-
-
Save avdi/6123055 to your computer and use it in GitHub Desktop.
| class SomeORM | |
| def self.attributes(*names) | |
| if const_defined?(:DynamicAttributes, false) | |
| mod = const_get(:DynamicAttributes) | |
| else | |
| mod = const_set(:DynamicAttributes, Module.new) | |
| include mod | |
| end | |
| mod.module_eval do | |
| names.each do |name| | |
| define_method(name) do | |
| # Stuff | |
| end | |
| end | |
| end | |
| end | |
| end |
One thing I dislike slightly about this compared to my original solution is that Post::DynamicAttributes perhaps gives less of a clue where the module comes from than SomeORM::DynamicAttributes123. But I suppose "where it comes from" is kind of hard to decide anyway – SomeORM generates it, but you declared the attributes in Post, which is-a SomeORM anyway.
I suppose you could call it Post::SomeORMDynamicAttributes if you want to be very clear.
I also like to define a custom #to_s on these modules so that when listed with #ancestors you see e.g. DynamicAttributes(attr1, attr2, attr3). I think I showed that in one of the RubyTapas episodes I mentioned on Twitter.
I checked out episode 28, it's in there. Clever!
For my own future reference, the above could be achieved with something along the lines of (after line 15):
def mod.to_s
"DynamicAttributes(#{instance_methods(false).join(', ')})"
end
Thanks for the feedback!
I like how this solution uses plain constants to keep down the number of modules (one per class in an inheritance hierarchy), unique-enough names (no need for object ids as it's again one per class), and of course for naming.