Closed fgarcia closed 9 years ago
Nope, sorry this will never work. Model is being extended with behavior based on attribute definitions, after they are initialized they should not be changed. In virtus 2.0 they will be frozen (frankly I'm surprised they are not already)
I am still playing around with dynamically defined attributes but it did not took to much more to understand why non frozen attributes is an awful idea.
The title of this issue and my initial approach is flawed. Certainly a module with Virtus attributes should be frozen, however I am still considering an easy way to reuse current definitions to define new objects.
Normally I have a clean cut of my domain objects:
Hence I am very interested in exploring how to make multiple definitions from a central one. So far I am using instance_variable_get(:@attribute_set)
to get the attribute_set of Virtus.model
and define new ones inside another class
Should that be safe and viable on the long term?
Why not just use inheritance?
Normally I reserve inheritance to restrict the nature/type of a class. In my case I have the "Behaviour Domain Object" species and the "Simple State Holder Model" species. The "class species" is something where I tend to use inheritance over mixins
That both of them can share a similar subset of attributes is just an orthogonal concept, where I do prefer to use mixins.
In my current case the inheritance slot is already reserved, but will reevaluate. Also I was concerned about inherited attributes being frozen...
...or maybe I just took the long road of introspection for the fun of exploring Virtus. It is a long time I thought about a custom DSL to copy/redefine/imitate Virtus objects that "mostly" resemble an existing one ... which might overlap with your work with ROM
actually a custom DSL extension was the way I thought the Adapter objects where going to be implemented ;-)
like:
class PersonAdapter
include Virtus.adapter( Person )
map from('/age'), to('/current_age', &:to_i)
# inherit / skip rest of attributes?
end
And that would be an whole extra gem, like https://github.com/ismasan/hash_mapper but with some extra knowledge assuming Virtus is being used.
Integration could also lead to things like Person.adapters
. Almost useless in production code, but very nice to have with introspection / repl
@solnic Regarding not using inheritance, I am facing that issue in my current code:
I have a common set of attributes (for one concept) spread across many classes: events, commands, form objects, query results, widget model ... Normally I tend to add one generic model attribute, but as code evolves there are "slight" variations. Still not sure if having multiple adapters for each of those objects is really worth it or totally insane.
Maybe you could use Virtus.module
to share common attributes
That is what I am doing right now, and it is almost my solution.
As mentioned earlier, the repeated set of attributes tend to have slight variations. However I wonder now about your comment in the chat about extracting data structure mapping out of Rom into an independent gem (without memory adapter).
Did you have in mind something like the hash_mapper gem syntax I wrote above? To me seems like something very useful and easy to add as an extra independent gem, but I believe you are solving already the same problem from another angle.
Since you have much more experience than me, I am curious about your point of view on my approach.
ROM mapper is standalone, it'll be probably extracted into a separate gem at some point. For repeated set of attributes you can also use inheritance and override some attributes if you want (frankly I don't recall how that would work with virtus models)
I am trying to modify on runtime already defined attributes. However the modified options are ignored.
See gist https://gist.github.com/fgarcia/80449b6d2754e66f557d
Is this supposed to be possible? I also played with
Virtus.finalize
without much success.