J
Jamis Buck
First, let me just say THANK-YOU to everyone who gave me feedback on my
presentation on Sunday. Rich Kilmer's suggestion that I serialize to
Ruby code, and various people (Austin, and various others that I can't
recall immediately) that suggested I ditch the YAML configuration file,
and Nathaniel Talbott who inadvertantly gave me some inspiration during
his test/unit presentation...
I've spent the last couple of days since my presentation thinking, and
thinking, and thinking. I'm going to do a brain dump here, and since I
know some of you have opinions on this matter, I hope you'll take a
moment to let me know if you think I'm on the right track to ruby-izing
Copland.
First of all, I realized that configuration points are just services
that implement a Hash-like or Array-like interface. Thus, there is no
really compelling need to treat them differently. In fact, implementing
them as service points allows you to use your own custom Hash-like or
Array-like class instead of Hash or Array.
Second, I think that Rich's suggestion of a Ruby-based domain-language
is very applicable, and ties in nicely with the inspiration I got from
Nathaniel's presentation. (Rich, any comments on the "domain language"
demonstrated below would be appreciated.)
Putting it all together, I'm thinking along the lines of the following
code snippet for defining service points:
registry = Copland::Registry.construct do
package "calc" do
service_point "Adder", Calc::Adder
service_point "Subtractor", Calc::Subtractor
service_point "Divider", Calc:ivider
service_point "Multiplier", Calc::Multiplier
service_point "Operations", Hash
service_point "Calculator" do
factory service { "copland.BuilderFactory" }
implementor do
klass Calc::Calculator
parameters [
service { "calc.Operations" }
]
end
end
with "calc.Operations" do |ops|
ops[:add] = service { "calc.Adder" }
ops[:subtract] = service { "calc.Subtractor" }
ops[:multiply] = service { "calc.Multiplier" }
ops[:divide] = service { "calc.Divider" }
end
end
end
calc = registry.service( "calc.Calculator" )
p calc.add( 8, 5 )
p calc.subtract( 8, 5 )
p calc.divide( 8, 5 )
p calc.multiply( 8, 5 )
It's still more verbose than I would like it, and there are problems
remaining that the above does not solve, but as a first pass, I think it
looks pretty nice. (Note that the "service {...}" syntax is necessary so
that the string is interpreted as a service reference, and not as a
string literal).
For those of you that were vocal in your opposition to the external
configuration file--how does the above strike you? What do you
like/dislike about it?
Other ideas:
* Allow "package" to be optional. If omitted, service points are added
to the global namespace.
* Allow true nesting of namespaces, for hierarchical package definitions.
Anyway, just getting my thoughts out. Comments would be greatly appreciated!
- Jamis
presentation on Sunday. Rich Kilmer's suggestion that I serialize to
Ruby code, and various people (Austin, and various others that I can't
recall immediately) that suggested I ditch the YAML configuration file,
and Nathaniel Talbott who inadvertantly gave me some inspiration during
his test/unit presentation...
I've spent the last couple of days since my presentation thinking, and
thinking, and thinking. I'm going to do a brain dump here, and since I
know some of you have opinions on this matter, I hope you'll take a
moment to let me know if you think I'm on the right track to ruby-izing
Copland.
First of all, I realized that configuration points are just services
that implement a Hash-like or Array-like interface. Thus, there is no
really compelling need to treat them differently. In fact, implementing
them as service points allows you to use your own custom Hash-like or
Array-like class instead of Hash or Array.
Second, I think that Rich's suggestion of a Ruby-based domain-language
is very applicable, and ties in nicely with the inspiration I got from
Nathaniel's presentation. (Rich, any comments on the "domain language"
demonstrated below would be appreciated.)
Putting it all together, I'm thinking along the lines of the following
code snippet for defining service points:
registry = Copland::Registry.construct do
package "calc" do
service_point "Adder", Calc::Adder
service_point "Subtractor", Calc::Subtractor
service_point "Divider", Calc:ivider
service_point "Multiplier", Calc::Multiplier
service_point "Operations", Hash
service_point "Calculator" do
factory service { "copland.BuilderFactory" }
implementor do
klass Calc::Calculator
parameters [
service { "calc.Operations" }
]
end
end
with "calc.Operations" do |ops|
ops[:add] = service { "calc.Adder" }
ops[:subtract] = service { "calc.Subtractor" }
ops[:multiply] = service { "calc.Multiplier" }
ops[:divide] = service { "calc.Divider" }
end
end
end
calc = registry.service( "calc.Calculator" )
p calc.add( 8, 5 )
p calc.subtract( 8, 5 )
p calc.divide( 8, 5 )
p calc.multiply( 8, 5 )
It's still more verbose than I would like it, and there are problems
remaining that the above does not solve, but as a first pass, I think it
looks pretty nice. (Note that the "service {...}" syntax is necessary so
that the string is interpreted as a service reference, and not as a
string literal).
For those of you that were vocal in your opposition to the external
configuration file--how does the above strike you? What do you
like/dislike about it?
Other ideas:
* Allow "package" to be optional. If omitted, service points are added
to the global namespace.
* Allow true nesting of namespaces, for hierarchical package definitions.
Anyway, just getting my thoughts out. Comments would be greatly appreciated!
- Jamis