Permalink
Browse files

Initial work on Virtus modules

  • Loading branch information...
1 parent b97afea commit 5600671f28ee28cf95496fe4b36cd25a2556521b @solnic committed May 18, 2012
Showing with 61 additions and 0 deletions.
  1. +2 −0 lib/virtus.rb
  2. +29 −0 lib/virtus/module.rb
  3. +30 −0 spec/integration/using_modules_spec.rb
View
@@ -42,6 +42,8 @@ def self.included(descendant)
require 'virtus/class_methods'
require 'virtus/instance_methods'
+require 'virtus/module'
+
require 'virtus/value_object'
require 'virtus/attribute_set'
View
@@ -0,0 +1,29 @@
+module Virtus
+
+ # Virtus module class that can define attributes for later inclusion
+ #
+ module Module
+
+ def included(model)
+ model.send(:include, Virtus)
@apotonick
apotonick May 18, 2012 Contributor

Problem here is that Virtus still wants to be included in the class, which leads to problems when you extend an object with the coercion module! Here's how I do it in representable: https://github.com/apotonick/representable/blob/master/lib/representable.rb#L40

@solnic
solnic May 18, 2012 Owner

OK now I'm lost :)

I think I don't understand what's your expectation from this feature. From my pov I wanted to be able to define attributes on a module, then include it in a class so that it's extended with Virtus and it gets all the attributes that were defined in the module.

@apotonick
apotonick May 18, 2012 Contributor

Here's how roar/representable works:

module SongRepresenter
  include Roar::Representer::JSON

  property :title
end

This module can be used in classes and instances.

Song.include(SongRepresenter).new.from_json ..

or

Song.new.extend(SongRepresenter).from_json

Oki?

@dkubb
dkubb May 18, 2012 Collaborator

@apotonick yeah, that's kind of how I expected this to work too. A module with attributes that can be mixed into other modules, classes and instances.

@solnic
solnic May 18, 2012 Owner

so that's what I was missing. OK I'll work on that.

+ define_attributes(model)
+ end
+
+ def attribute(*args)
+ attribute_definitions << args
+ end
+
+ private
+
+ def attribute_definitions
+ @_attribute_definitions ||= []
+ end
+
+ def define_attributes(model)
+ attribute_definitions.reverse.each do |attribute_args|
@apotonick
apotonick May 18, 2012 Contributor

Awesome, that's exactly how we do it in roar! Leeeeeeeet me see

@solnic
solnic May 18, 2012 Owner

@apotonick ok great. I'll push 0.5.0 soon, probably during the weekend.

@dkubb
dkubb May 18, 2012 Collaborator

@solnic why reverse here? Also reverse_each creates one less intermediate array.

+ model.attribute(*attribute_args)
+ end
+ end
+
+ end # class Module
+end # module Virtus
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+describe 'I can define attributes within a module' do
+ specify 'including a module with attributes' do
+ module Examples
+ module Base
+ extend Virtus::Module
+
+ attribute :name, String
+ attribute :age, Integer
+ end
+
+ class User
+ include Base
+ end
+
+ class Admin < User; end
+ end
+
+ Examples::User.attributes[:name].should be_instance_of(Virtus::Attribute::String)
+ Examples::User.attributes[:age].should be_instance_of(Virtus::Attribute::Integer)
+
+ Examples::Admin.attributes[:name].should be_instance_of(Virtus::Attribute::String)
+ Examples::Admin.attributes[:age].should be_instance_of(Virtus::Attribute::Integer)
+
+ user = Examples::User.new(:name => 'Piotr', :age => 29)
+ user.name.should eql('Piotr')
+ user.age.should eql(29)
+ end
+end

0 comments on commit 5600671

Please sign in to comment.