Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- namespace PersonTraits
- import System
- import Boo.Lang
- import Boo.Lang.Compiler
- import Boo.Lang.Compiler.Ast
- class Builder(AbstractAstAttribute):
- entries as Hash
- public def constructor(initString as StringLiteralExpression):
- entries = Hash()
- parts = /;/.Split(initString.Value)
- for part in parts:
- elements = /=/.Split(part)
- props = /,/.Split(elements[1])
- entries[elements[0]] = props
- public override def Apply(node as Node):
- AddBuilderClass(node)
- AddFactoryMethod(node)
- private def fieldName(propName as string) as string:
- return char.ToLower(propName[0]) + propName.Substring(1)
- private def AddBuilderClass(node as ClassDefinition):
- classRef = ReferenceExpression(node.Name)
- fieldRef = ReferenceExpression(fieldName(node.Name))
- builderRef = ReferenceExpression(node.Name + "Builder")
- c = [|
- class $(builderRef):
- $(fieldRef) as $(classRef)
- public def constructor($(fieldRef) as $(classRef)):
- self.$(fieldRef) = $(fieldRef)
- static def op_Implicit(o as $(builderRef)):
- return o.$(fieldRef)
- |]
- AddIndividualFluentMethods(c, node)
- AddCombinationFluentMethods(c, node)
- AddInternalBuilders(c, node)
- (node.ParentNode as Module).Members.Add(c)
- private def AddInternalBuilders(builder as ClassDefinition, source as ClassDefinition):
- // iterate over each set
- for entry in entries:
- // create and a stub class
- classRef = ReferenceExpression(source.Name + entry.Key + "Builder")
- targetRef = ReferenceExpression(source.Name)
- outerFieldRef = ReferenceExpression(fieldName(source.Name))
- innerClass = [|
- class $classRef:
- $outerFieldRef as $targetRef
- public def constructor($(outerFieldRef) as $targetRef):
- self.$(outerFieldRef) = $(outerFieldRef)
- static def op_Implicit(o as $builder):
- return o.$(outerFieldRef)
- |]
- // spawn each setter for this class
- for prop in entry.Value:
- for sp in source.Members:
- p2 = sp as Property
- if p2 != null and prop == p2.Name:
- methodRef = ReferenceExpression("With" + prop)
- fieldRef = ReferenceExpression(fieldName(prop))
- propRef = ReferenceExpression(prop as string)
- // let's do it
- setter = [|
- public def $methodRef($fieldRef as $(p2.Type)) as $classRef:
- $outerFieldRef.$propRef = $fieldRef
- return self
- |]
- innerClass.Members.Add(setter)
- // ensure a property exists for this class in the root builder
- prop = [|
- public $(ReferenceExpression(entry.Key as string)):
- get:
- return $classRef($(ReferenceExpression(fieldName(source.Name))))
- |]
- builder.Members.Add(prop)
- // ensure inner builders expose divergent properties
- for entry2 in entries:
- if entry.Key != entry2.Key:
- otherClassRef = ReferenceExpression(source.Name + entry2.Key + "Builder")
- prop = [|
- public $(ReferenceExpression(entry2.Key as string)):
- get:
- return $otherClassRef($outerFieldRef)
- |]
- innerClass.Members.Add(prop)
- // add it all
- builder.Members.Add(innerClass)
- private def AddCombinationFluentMethods(builder as ClassDefinition, source as ClassDefinition):
- for entry in entries:
- m = Method("With" + entry.Key)
- for p in entry.Value as (string):
- // look for this param in the class
- for sp in source.Members:
- prop = sp as Property
- if prop != null and p == prop.Name:
- mp = ParameterDeclaration(fieldName(prop.Name), prop.Type)
- m.Parameters.Add(mp)
- sourceRef = ReferenceExpression(fieldName(source.Name))
- propRef = ReferenceExpression(prop.Name)
- a = [|
- $sourceRef.$propRef = $mp
- |]
- m.Body.Add(a)
- m.Body.Statements.Add([| return self |])
- builder.Members.Add(m)
- private def AddIndividualFluentMethods(builder as ClassDefinition, source as ClassDefinition):
- builderRef = ReferenceExpression(builder.Name)
- for prop in source.Members:
- p = prop as Property
- if p != null:
- methodName = ReferenceExpression("With" + p.Name)
- propRef = ReferenceExpression(p.Name)
- paramRef = ReferenceExpression(fieldName(p.Name))
- m = [|
- public def $(methodName)($paramRef as $(p.Type)) as $(builderRef):
- person.$(propRef) = $paramRef
- return self
- |]
- builder.Members.Add(m)
- private def AddFactoryMethod(node as ClassDefinition):
- builderRef = ReferenceExpression(node.Name + "Builder")
- classRef = ReferenceExpression(node.Name)
- m = [|
- def Create() as $(builderRef):
- return $(builderRef)($(classRef)())
- |]
- node.Members.Add(m)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement