Closed kerinin closed 10 years ago
Third way is to override the attr_reader
s that Assembler gives you with the casting in there:
def number
@number.to_i
end
That's horrible, of course, because converting to Numerics might be OK, but to Strings or Arrays will cause it to create a bunch of objects all the time and... yuck.
This seems like a legit use case... but I'm not at all sure about the API. I love how simple the API currently is. If we want to maintain the same feature set we have and add this, we end up with something like...
class Foo
extend Assembler
assemble_with number: :to_i, enumerable: { convert: :to_ary, default: [] }
end
Or something abominable.
You got an API proposal?
OK, after some thought, here's the best option I came up with. We provide two initializer functions, one for batch declaration (the one that's already implemented) and another one for declaring a single argument with options. Not sure what the names should be - I'll just use assemble_with_options
for the sake of discussion:
class Foo
extend Assembler
# No change here
assemble_with :required, optional: 'default'
# This gives us flexibility going forward, because we can always add
# more keys for additional metadata
assemble_with_options :number, default: 'default', initializer: :to_i
assemble_with_options :timestamp, initializer: ->(arg) { Time.at(arg) if arg.kind_of?(Integer) }
# This might solve the lazy initialization problem too, if we passed self to
# the initializer block
assemble_with_options :host, initializer: ->(arg, foo) { arg || foo.redis.host }
end
This lets us keep the existing API whose simplicity I also like, but declare more complex initialization logic on-demand as needed.
See #11 for broader discussion about this.
I'll sometimes do type casting on inputs to ensure they're in the shape I expect:
To get the same effect with assembler, we'd need to either remember to always do conversion when we construct instances or remember to always do the conversion inside the class when accessing the variables, neither of which is ideal.
Do you think we should work on a way to duplicate this functionality?