Festoon
What is it?
This project aspires to better enable object composition by offering a set of
super classes and modules akin to the standard library's SimpleDelegator
.
Why is it?
Personally I've felt the delegation tools in the standard library to be lacking in functionality, often difficult to use in practice and sometimes misleading.
The following are issues I have encountered (not comprehensive)
- Delegation of
#inspect
causing theSimpleDelegator
to masquerade as the object it decorates. - Comparison of decorated objects only works for coercible primitives.
- Fluid interfaces, where the decorated object returns self, are not supported and cause your composed objects to unravel.
- Difficulty debugging multiple layers of decoration
Examples
Equality
my_object = Object.new
Festoon::Dynamic.new(my_object) == Festoon::Dynamic.new(my_object)
=> true
Fluid interfaces, return of self
class MyClass
def returns_self
self
end
end
my_object = MyClass.new
Festoon::Dynamic.new(my_object).returns_self.class
=> Festoon::Dynamic
Inspection
Festoon::Dynamic.new(my_object).inspect
=> #<Festoon::Dynamic:0x0000010108af28 @thing=#<Object:0x0000010108af50>>
Compose and __decompose__
#__decompose__
returns an array, each element containing a layer of the
composed object, outermost first. This is most easily demonstrable by mapping
each layer to its class.
This mainly exists for debugging and allow you to inspect, interact with, and bypass arbitrary layers of the composition.
class DecoratorA < Festoon::Dynamic; end
class DecoratorB < Festoon::Dynamic; end
composed_object = DecoratorB.new(DecoratorA.new(MyClass.new))
composed_object.__decompose__.map { |o| o.class }
=> [DecoratorB, DecoratorA, MyClass]
composed_object.__decompose__
=> [
#<DecoratorB:0x00000102003770 @thing=#<DecoratorA:0x00000102003798 @thing=#<MyClass:0x00000102003e28>>>,
#<DecoratorA:0x00000102003798 @thing=#<MyClass:0x00000102003e28>>,
#<MyClass:0x00000102003e28>
]
TODO
- Method reflection methods such as
#public_methods
etc - Consider delegation of
#trust
,#untrust
,#taint
,#untaint
,#freeze
-
#inspect
method which has readable output and does not attempt to hide the object's composed nature. Potentially offer a set of strategies for this - Recursive
#dup
? - Hash equality
- Rename
@thing
Installation
Add this line to your application's Gemfile:
gem "festoon"
And then execute:
$ bundle
Or install it yourself as:
$ gem install festoon
Usage
TODO: Write usage instructions here
Contributing
- Fork it ( https://github.com/[my-github-username]/festoon/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request