solnic / virtus

[DISCONTINUED ] Attributes on Steroids for Plain Old Ruby Objects
MIT License
3.77k stars 229 forks source link

Support annotations/meta information for attribute #207

Open mirasrael opened 11 years ago

mirasrael commented 11 years ago

Hi. What you think about add support for attributes meta information? In some cases it may be very useful. I.e. we are generating xml by virtus models and have to wrap any array element into custom tag. So it will be handy to specify additional option for attribute and later access it in generator.

I.e. we have a class:

class Container
   include Virtus

   attribute :entries, Array[Entry], annotations: {wrap: 'entry'}
end

and somewhere in code:

Container.attribute_set[:entries].annotations[:wrap] #=> 'entry'

solnic commented 11 years ago

I think it's a good candidate for a virtus plugin

mirasrael commented 11 years ago

What is better point to extend Virtus with this kind of functionality? We can override attribute to catch annotations option, but it may be handy to obtain annotations direct from attribute and how to implement this without monkey patching?

niquola commented 11 years ago

:+1: I think virtus should pay attention to "reflection api" and meta information! It would be very useful in datamappers, serializers, etc (this is already used in java, .net) Attribute annotations is looking like core functionality. When you declare attribute, you already attach type meta information to it, why not just give container for any additional meta data (like attribute.meta || attribute.annotations)?

This feature also gives good extension point for plugins :)

solnic commented 11 years ago

I'm fine with a plugin and maybe merging it in later for virtus 2.0.0. Now it's not a good moment as the code base is already very complex due to keeping backward compatibility with 0.5.x.

I already have some initial work done for 'extension' interface so that you can attach additional behaviour to an attribute instance. This could be used to add 'annotation' feature.

All options passed to an attribute are saved and are accessible via Attribute#options so it's a matter of adding one method to Attribute that returns annotations:

module Virtus
  class Attribute
    module Annotated
       def annotations
          options[:annotations]
       end
    end
  end
end

attr = Virtus::Attribute.build(String, annotations: { wrap: 'entry' })
attr.extend(Virtus::Attribute::Annotated)
attr.annotations # => { wrap: 'entry' }
solnic commented 11 years ago

...I could introduce a new interface for registering custom extensions, something like that maybe:

Virtus::Attribute.register_extension(Virtus::Attribute::Annotated)

# it would require some method that would tell virtus when to use it, maybe something like this:

module Virtus::Attribute::Annotated
  def extend?(options)
    options.key?(:annotations)
  end
end

it's a simple addition that I could include in 1.0.0 final

mirasrael commented 11 years ago

Yes, it looks good. Thank you.

solnic commented 11 years ago

@mirasrael I wanted to introduce that interface anyway so it's cool to know people need that :)

mirasrael commented 11 years ago

@solnic I glad to be one of the first consumers of this interface ;)

dapi commented 9 years ago

+1 useful for auto generated documentation