solnic / virtus Goto Github PK
View Code? Open in Web Editor NEW[DISCONTINUED ] Attributes on Steroids for Plain Old Ruby Objects
License: MIT License
[DISCONTINUED ] Attributes on Steroids for Plain Old Ruby Objects
License: MIT License
Hey folks, we are trying to upgrade virtus from 0.0.9 to 0.2.0 and because of the changes made to mass assignment it actually broke some of our specs as we didn't have some of our attributes declared as a virtus attribute, we have our own logic on getters and setters that we think would not fit into an attribute type kinda thing.
To give you some context, we are using virtus for dealing with API resources and we use attributes= to build the object from a JSON response. The reason we believe those accessors wouldn't fit into a attribute type / class is that they are like "virtual properties", used to extract and reconstruct values based on the API data.
The code would be something like this:
class Movie
# ... a bunch of virtus attributes ...
attribute :main_category, String
attribute :subcategory, String
def categories
[self.main_category, self.subcategory]
end
def categories=(all_categories)
self.main_category = all_categories.first
self.subcategory = all_categories.last
end
end
With that we can get extract the "composite" attribute when fetching from the API and simplify our use on the context of our application and rebuild the values when sending data back to the API.
Does it make sense to you guys? If it does, what do you think about it?
Keep up with the good work!
Cheers!
This would allow
VirtusModel.new(virtus_model_insance)
This could probably be an alias for #attributes
Is it possible to get virtus to do something like:
require 'virtus'
class Address
include Virtus
attribute :street, String
attribute :city, String
end
class User
include Virtus
attribute :name, String
attribute :address, Address
end
u = User.new
fail unless "" == u.name
fail unless "" == u.address.city
I'm building a form handling library based on virtus, and not having to deal with nil's would make this a lot easier.
In Ruby 1.9.3 (and I assume others, although I haven't checked), Module defines const_missing
to be a public method. Virtus::ClassMethods
however, redefines const_missing
to be private. Ultimately, there are cases when the following exception occurs:
NoMethodError in MyController#show
private method `const_missing' called for My::Klass:Class
As a test, I simply moved the method definition until the public space of ClassMethods and everything works as expected.
The discussion in #61 brought up, that ValueObjects should not be duped or cloned.
the current Virtus behavior is to create a new object. See the following irb session for an example:
ruby-1.9.2-p290 :004 > class Example
ruby-1.9.2-p290 :005?> include Virtus::ValueObject
ruby-1.9.2-p290 :006?> end
=> Example
ruby-1.9.2-p290 :007 > e = Example.new
=> #<Example:0x007fdc24081dc8>
ruby-1.9.2-p290 :008 > e.object_id
=> 70291737022180
ruby-1.9.2-p290 :009 > e.dup.object_id
=> 70291736987800
It'd be great if an attribute of type Array could be automatically converted to an array.
Example use case:
In a Sinatra app, an URL formatted like ?key=value
results in params['key'] = 'value'
, while ?key[]=value1&key[]=value2
results in params['key'] = ['value1', 'value2']
.
I'd like to deal with an array all the time. i.e. VirtusObject.new(:key => 1).key # => [1]
.
On #datamapper, Solnic suggested something like:
class Virtus::Coercion::Object; def self.to_array(value); Array(value); end; end
Best,
Vivien.
module Mixin include Virtus end module Mixin2 include Mixin attribute :foo, String end
NoMethodError: undefined method `superclass' for Mixin2:Module from /home/hal/.rvm/gems/ruby-1.9.3-p194/gems/virtus-0.5.0/lib/virtus/class_methods.rb:43:in `attribute_set' from /home/hal/.rvm/gems/ruby-1.9.3-p194/gems/virtus-0.5.0/lib/virtus/extensions.rb:89:in `virtus_add_attribute' from /home/hal/.rvm/gems/ruby-1.9.3-p194/gems/virtus-0.5.0/lib/virtus/class_methods.rb:110:in `virtus_add_attribute' from /home/hal/.rvm/gems/ruby-1.9.3-p194/gems/virtus-0.5.0/lib/virtus/extensions.rb:53:in `attribute' from (irb):7:in `' from (irb):5 from /home/hal/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `'
When I use virtus against 1.8.7, it's running into problem related to singleton_class (https://github.com/solnic/virtus/blob/master/lib/virtus/support/type_lookup.rb#L25). The error is
undefined local variable or method
singleton_class' for Virtus::Attribute:Class`
I wanted to try replacing parameters with Virtus. One of the features that Parameters has is being able to be used in Mixin modules, so that when the Mixin is included the parameters are added to the class. Virtus appears to only work with Classes.
module Test include Virtus attribute :name, String end
NoMethodError: undefined method `superclass' for Test:Module /home/hal/.rvm/gems/ruby-1.9.3-p0/gems/virtus-0.0.9/lib/virtus/class_methods.rb:71:in `attributes' /home/hal/.rvm/gems/ruby-1.9.3-p0/gems/virtus-0.0.9/lib/virtus/class_methods.rb:115:in `virtus_add_attribute' /home/hal/.rvm/gems/ruby-1.9.3-p0/gems/virtus-0.0.9/lib/virtus/class_methods.rb:48:in `attribute' (ripl):7:in `'
Virtus should support deep coercion of Hash attributes.
attribute :settings, Hash[Symbol => Float]
# ...
user.settings = params[:settings]
I was just playing around with the gem and stumbled on this:
require 'virtus'
class Book
include Virtus
attribute :page_numbers, Array[Integer]
end
book = Book.new(:page_numbers => %w[dummy 2 3])
book.page_numbers # => ["dummy", 2, 3]
I would expect [0, 2, 3] or maybe [nil, 2, 3] or even an error.
Is it the wanted behavior ?
Just updated from 0.0.3 to 0.0.4 and getting this error when my app starts up. I'll take a closer look tomorrow as I'm doing something else now and it's nearly 3am ;)
/home/chris/.rvm/gems/ruby-1.9.2-p180@flippa/gems/virtus-0.0.4/lib/virtus/support/descendants_tracker.rb:15:in `inherited': private method `inherited' called for Object:Class (NoMethodError)
from /home/chris/.rvm/gems/ruby-1.9.2-p180@flippa/gems/virtus-0.0.4/lib/virtus/attribute.rb:118:in `inherited'
from /home/chris/.rvm/gems/ruby-1.9.2-p180@flippa/gems/virtus-0.0.4/lib/virtus/attribute/object.rb:5:in `<class:Attribute>'
from /home/chris/.rvm/gems/ruby-1.9.2-p180@flippa/gems/virtus-0.0.4/lib/virtus/attribute/object.rb:2:in `<module:Virtus>'
from /home/chris/.rvm/gems/ruby-1.9.2-p180@flippa/gems/virtus-0.0.4/lib/virtus/attribute/object.rb:1:in `<top (required)>'
from /home/chris/.rvm/gems/ruby-1.9.2-p180@flippa/gems/virtus-0.0.4/lib/virtus.rb:66:in `require'
from /home/chris/.rvm/gems/ruby-1.9.2-p180@flippa/gems/virtus-0.0.4/lib/virtus.rb:66:in `<top (required)>'
I was trying to replace Parameters with Virtus. One of the features of Parameters, is being able to define parameters on Objects as well as Classes. Virtus does not want to be extended into an Object.
class Test
end
obj = Test.new
obj.extend Virtus::ClassMethods
NoMethodError: undefined method `const_set' for #<Test:0x00000002aeb878>
/home/hal/.rvm/gems/ruby-1.9.3-p0/gems/virtus-0.0.9/lib/virtus/class_methods.rb:16:in `extended'
Just updated to 0.0.6 and starting getting this error on classes where I'm using Object
as an attribute type.
class Example
include Virtus
attribute :foo, Object
end
KeyError: key not found: :coercion_method
from /home/chris/.rvm/gems/ruby-1.9.2-p290@flippa/gems/virtus-0.0.6/lib/virtus/attribute.rb:98:in `fetch'
from /home/chris/.rvm/gems/ruby-1.9.2-p290@flippa/gems/virtus-0.0.6/lib/virtus/attribute.rb:98:in `initialize'
from /home/chris/.rvm/gems/ruby-1.9.2-p290@flippa/gems/virtus-0.0.6/lib/virtus/class_methods.rb:46:in `new'
from /home/chris/.rvm/gems/ruby-1.9.2-p290@flippa/gems/virtus-0.0.6/lib/virtus/class_methods.rb:46:in `attribute'
from (irb):4:in `<class:Example>'
from (irb):2
from /home/chris/.rvm/rubies/ruby-1.9.2-p180/bin/irb:16:in `<main>'
I think I'll just use attr_accessor for these attributes for now, but it's nice to be consistent when there are a list of related attributes and some of those are just Object types.
Hi there,
I'm facing a use case where @virtus@ may be suitable. I need to generate test data (user with id and password) which needs to be stored in YAML files. The passwords have to be store encrypted within that YAML file. When reading it, it needs to be decrypted. I hope the use case is clear. Now to my question:
Hi guys,
Thanks again for an awesome helping tool. It really does save a ton of time, and works perfectly fine.
I'm still uncertain about the issues I reported before. I decided to keep developing mongo repository, and have opensourced a smallish proof of concept, but it's still to raw, and has only integration tests so far. But, hopefully, it will get moving.
I'm trying to understand, what's the best way to update an existing record? I can see attributes=
method, but I'm not sure if it's a promoted way to do so. It works perfectly fine, and as I see from here: https://github.com/solnic/virtus/blob/master/lib/virtus/instance_methods.rb#L14 it seems to be exactly same mechanism to record creation.
Is it safe to use it? Is there any need to secure myself and use something else?
Hi,
I run into a minor issue with Virtus when trying to write some specs of a Virtus Object.
Here is a spec that describe the problem.
require 'spec_helper'
class Poro
include Virtus
attribute :id, Integer
attribute :name, String
end
describe Poro do
subject { Poro.new }
# This spec fails
it 'accepts RSpec String doubles' do
name = double
subject.name = name
subject.name.should == name
end
# Those pass
it 'accepts RSpec Integer doubles' do
id = double
subject.id = id
subject.id.should == id
end
it 'accepts integer attributes' do
subject.id = 1
subject.id.should == 1
end
it 'accepts string attributes' do
subject.name = 'foo bar'
subject.name.should == 'foo bar'
end
end
The first spec failed with this message
Failures:
1) Poro accepts RSpec String doubles
Failure/Error: subject.name.should == name
expected: #<RSpec::Mocks::Mock:0x3fe5188fb58c @name=nil>
got: "#[RSpec::Mocks::Mock:0x3fe5188fb58c @name=nil]" (using ==)
Diff:
@@ -1,2 +1,2 @@
-#<RSpec::Mocks::Mock:0x3fe5188fb58c @name=nil>
+"#[RSpec::Mocks::Mock:0x3fe5188fb58c @name=nil]"
# ./spec/integration/bug_spec.rb:25:in `block (2 levels) in <top (required)>'
Finished in 0.00176 seconds
1 example, 1 failure
It is pretty clear that the double
is converted into a String
but that is not what I expect.
To fix this issue, I add a custom coercion object.
module Virtus
class Coercion
class Mock < Virtus::Coercion::Object
primitive ::RSpec::Mocks::Mock
def self.to_string(value)
value
end
end
end
end
But, I'm pretty sure that it is not the right way to fix the problem.
What do you think of this issue ?
EDIT : BTW, this happend only in virtus 0.3 and not 0.2.
I don't know if this is seen as just syntactic sugar, but it could be quite nice to have Hash style read/write for Virtus objects. I used Virtus in a project today, just as an intermediate for creating a Hash (from an XML document from Quova.com) with each element cast to the correct type. I just defined a Virtus class with the respective properties, then parsed the XML, calling #attribute_set
for each element I was interested it, before finally exporting #attributes
to get a plain Hash back out. I was thinking the whole time, it would be nice if Virtus added []
and []=
so the object could behave somewhat like a Hash.
DM does this already.
What about using Virtus::Attribute::Object
as a default type if it is not specified in attribute, for example these would be equivalent:
attribute :obj, Object
attribute :obj
This would also have to handle cases where options are passed in, which shouldn't be too difficult to implement.
Folks, another feature I just remembered that would be good to have for the project I'm currently working on is a way to reject hash values that comes from a form before they get assigned / coerced to the main object, something along the lines of ActiveRecord's accepts_nested_attributes_for :reject_if parameter and I wanted to know your thoughts on this.
Where do you guys think would be the best place to have that? Is it something that Virtus should take care of?
Cheers!
In DataMapper one thing I had wished to do with the DataMapper::Resource API is allow the property and relationship DSL to be used within modules, rather than just in classes.
This would allow the user to specify attributes within modules and then compose objects from those modules without having to do anything special with the included hooks. I think it would make for an improved experience since it might encourage people to break things down into smaller components rather than trying to do everything in a single classs.
@solnic what do you think?
I am finding that a very common use-case for me is that I want to use a virtus object to wrap another object or objects.
I'd like to be able to do this:
class PersonPage
attribute :person, Person, accessor: private
def age
"#{person.age} years old"
end
end
I make the person
attribute private because I don't want it to be part of the public interface of this object, but I do want to be able pass it to the PersonPage's constructor as a named argument. However I've found that when I pass the Person instance that I want to wrap into the PersonPage constructor, it isn't set. I think this is because the accessor is private.
I could use the options to set the writer to public, but I don't want to expose a setter as part of the public interface - I just want to be able to set it from the constructor.
Am I using the library wrongly, or should we change it so that even attributes with private setters can be set from the constructor?
Today I found out about this method and by doing a git grep "value_coerced?"
I couldn't spot any use of it. Is it for some future feature or has it been forgotten?
On top of that, using the Custom Attributes example from README, is this code really expected to raise an error?
user = MyAppClass::User.new
user.info = {"email" => "[email protected]"}
TypeError: can't convert Hash into String
from /home/fabio/.rvm/gems/ruby-1.8.7-p334@virtus/gems/json-1.6.5/lib/json/common.rb:148:in `initialize'
from /home/fabio/.rvm/gems/ruby-1.8.7-p334@virtus/gems/json-1.6.5/lib/json/common.rb:148:in `new'
from /home/fabio/.rvm/gems/ruby-1.8.7-p334@virtus/gems/json-1.6.5/lib/json/common.rb:148:in `parse'
from (irb):11:in `coerce'
from ./virtus/attribute.rb:191:in `set'
from ./virtus/attributes_accessor.rb:60:in `info='
from (irb):25
I mean, should we check if the value is an instance of the target class on custom attributes #coerce
method (MyAppClass::Attributes::JSON in this case) or should Virtus bypass value coercion and just set the value? If the check is needed, the example should probably be updated to something like:
module MyAppClass
module Attributes
class JSON < Virtus::Attribute::Object
primitive Hash
def coerce(value)
if value.is_a? Hash
value
else
::JSON.parse value
end
end
end
end
end
I'm asking this because I noticed that on my current project we have some custom attributes that have that kind of checking on #coerce
method in order to use the coerced value right away on specs.
Example: https://gist.github.com/2994514
At the moment, if you have a Virtus object acting as an Embedded Value, you can't do any kind of custom coercion. Or even invoke the constructor, unless you pass in a hash. For example:
require 'virtus'
class Ability
include Virtus
attribute :rating, Integer, :default => 0
attribute :favoured, Boolean, :default => false
def initialize(rating_or_hash)
if Integer === rating_or_hash
self.rating = rating_or_hash
else
super
end
end
end
p Ability.new(1)
#=> #<Ability:0x1f01760 @rating=1>
p Ability.new(:rating => 1, :favoured => true)
#=> #<Ability:0x1f09380 @rating=1, @favoured=true>
class Character
include Virtus
attribute :driving, Ability
end
c = Character.new(:driving => 1)
p c
#=> #<Character:0x1c8c540 @driving=1>
c = Character.new(:driving => {:rating => 1})
p c
#=> #<Character:0x1c8b2b0 @driving=#<Ability:0x1c8b190 @rating=1>>
It would be helpful if in the Character.new(:driving => 1)
case, the one could still be cast to an Ability. Perhaps via a custom coercion method? I'm not immediately sure how the best way to go about this would be.
I noticed that the current implementation of default values passes in self to give the Proc access to it's attributes. Since it is possible to have private attributes, how would you make defaults based on these attributes without having to reach out to send
?
It would be an option to evaluate the Block in the context of the record to get direct access to the attributes.
Add #to_array
and #to_hash
methods to Virtus::Coercion::Object
so that they coerce any value that responds to #to_ary
(and #to_a
), or #to_hash
respectively. If the value does not respond to one of those methods then it should be returned directly as-is.
Consider similar coercions for objects into String using #to_str
and #to_s
, and Integers using #to_int
and #to_i
.
WDYT?
Why not make it link to docs, instead?
If I include Virtus
in my class, it adds a method initialize
to do it's magic. This is mostly a good thing, but it means that I cannot compute and set non-Virtus instance variables at object creation time. I'd like to be able to do this.
AttributeSet And Equalizer are subclass of Module I have looked online as much as I can; but I have no idea why you have done this; must be cool reason;
if its not too much trouble can tell why you use this approach and what it achieves in the library as a whole. as I have not seen this technique before; I am curious;
playing around; when you have a subclass of a module and you include the methods they are not available to the includer which is puzzling;
Cheers
Richard
Are there any plans to implement dirty tracking support in Virtus? I can do what I want without it, but it would be handy in some circumstances.
I believe the plan with DM2 is to manage dirty tracking in a UnitOfWork
/Session
object, but I'd like it for non-persistent objects.
Hi,
I really like this library but already got some cases where only the coercion part is needed, my problem is coming up with the shortest path to do this.
Currently I have this:
require 'virtus'
def coerce_value(type, ret)
converter = Virtus::Attribute.build(:a, type)
converter.coerce(ret)
end
p coerce_value(Array[String], [45, 56, "a", 4.56])
Is there a better way ?
See gist:
https://gist.github.com/1277089
In short, the following causes global breakage in Virtus:
class Whatever < Virtus::Attribute::Object; end
Class.new(Whatever)
From that point on, all virtus attributes are considered to be of the 'Whatever' type, due to the way TypeLookup works.
the current behaviour seems to just assign the set value. This could be dangerous when you expect the attributes to contain data of the right type.
class Example
include Virtus
attribute :my_date, Date
end
e = Example.new
e.my_date = 'test'
e.my_date # => 'test'
I've been working on Monger, Clojure Mongodb Driver. It's no surprise we've been always working with hashes there.
When you go down to the driver level, you always end up working with language primitives.
Right now I'm working on a prototype / proof of concept of Virtus + MongoDB driver, kind of DAO thing, which uses pretty much same API we expose in Monger.
Right now #to_hash is not recursive, therefore it won't handle embedded Mongodb models.
I realize that this is mostly applicable for the document databases, and way less applicable for Object Relational ones.
Do you think it would be useful for Virtus to have recursive implementation of #to_hash, and would consider making it a default implementation?
Thanks
The present :default
implementation doesn't allow for proc
/lamba
based defaults. This is important for (to give an example), Time based properties. Otherwise the default will be statically evaluated at class definition time.
class VirtusTime
include Virtus
attribute :time, DateTime, :default => DateTime.now
end
@old = VirtusTime.new
# many years pass
@new = VirtusTime.new
@old.time == @new.time
Hi there,
I'm facing a use case where virtus
may be suitable. I need to generate test data (user with id and password) which needs to be stored in YAML files. The passwords have to be store encrypted within that YAML file. When reading it, it needs to be decrypted.
Now comming to my question:
Can I use virtus for that use case? I think about building a custom attribute, which overwrites (coerce
or set
) and get
.
require 'encryptor'
module MyApp
# Defining the custom attribute(s)
module Attributes
class EncryptedString < Virtus::Attribute::Object
primitive String
def coerce(key, value)
Encryptor.encrypt key, value
end
def get(key)
[...]
Encryptor.decrypt key, value
end
end
end
class User
include Virtus
attribute :name, String
attribute :password, Attributes::EncryptedString
end
end
Thank you very much.
Cheers,
MaxMeyer
It would be nice if virtus had like a submodule for building ValueObjects. On top of my head this could look something like:
class GeoLocation
include Virtus::ValueObject
attribute :latitude, Float
attribute :longitude, Float
end
The Virtus::ValueObject
module would set some sane defaults for building ValueObjects like:
place = GeoLocation.new(:latitute => 40.73216945026674, :longitude => -74.091796875)
the_same_place = GeoLocation.new(:latitute => 40.73216945026674, :longitude => -74.091796875)
place == the_same_place # => true
hash = {palce => 1}
hash[the_same_palce] # => 1
place.latitude = -74.091796875 # => ERROR: Attempt to call private method
Using worker: ruby3.worker.travis-ci.org:worker-5
2
3$ git clone --depth=1000 --quiet git://github.com/solnic/virtus.git solnic/virtus
4$ git checkout -qf af6a7cd38294e40306ff1e09980b00f6ffa85803
5$ rvm use rbx
6Using /home/vagrant/.rvm/gems/rbx-head
7$ export BUNDLE_GEMFILE=/home/vagrant/builds/solnic/virtus/Gemfile
8$ export RBXOPT="-X19"
9$ bundle install --without guard metrics
10Fetching git://github.com/dkubb/reek.git
11remote: Counting objects: 7204, done.
12remote: Compressing objects: 100% (1811/1811), done.[K
13remote: Total 7204 (delta 5288), reused 7167 (delta 5255)[K
14Receiving objects: 100% (7204/7204), 1006.40 KiB | 564 KiB/s, done.
15Resolving deltas: 100% (5288/5288), done.
16Fetching source index for http://rubygems.org/
17Using rake (0.9.2.2)
18Installing backports (2.3.0)
19Installing diff-lcs (1.1.3)
20Installing rspec-core (2.6.4)
21Installing rspec-expectations (2.6.0)
22Installing rspec-mocks (2.6.0)
23Installing rspec (2.6.0)
24Using virtus (0.10.0) from source at /home/vagrant/builds/solnic/virtus
25Using bundler (1.0.21)
26Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
27$ bundle exec rake spec
28/home/vagrant/.rvm/rubies/rbx-head/bin/rbx -S bundle exec rspec ./spec/integration/virtus/class_methods/attributes_spec.rb ./spec/integration/virtus/class_methods/const_missing_spec.rb ./spec/integration/virtus/class_methods/attribute_spec.rb ./spec/integration/virtus/attributes/attribute/set_spec.rb ./spec/unit/virtus/attribute/decimal_spec.rb ./spec/unit/virtus/attribute/date_time_spec.rb ./spec/unit/virtus/attribute/time_spec.rb ./spec/unit/virtus/attribute/boolean_spec.rb ./spec/unit/virtus/attribute/float_spec.rb ./spec/unit/virtus/attribute/date_spec.rb ./spec/unit/virtus/attribute/class_spec.rb ./spec/unit/virtus/attribute/hash_spec.rb ./spec/unit/virtus/attribute/string_spec.rb ./spec/unit/virtus/attribute/array_spec.rb ./spec/unit/virtus/attribute/integer_spec.rb ./spec/unit/virtus/type_lookup/determine_type_spec.rb ./spec/unit/virtus/type_lookup/primitive_spec.rb ./spec/unit/virtus/class_methods/attributes_spec.rb ./spec/unit/virtus/class_methods/new_spec.rb ./spec/unit/virtus/class_methods/attribute_spec.rb ./spec/unit/virtus/descendants_tracker/add_descendant_spec.rb ./spec/unit/virtus/descendants_tracker/descendants_spec.rb ./spec/unit/virtus/attribute_set/each_spec.rb ./spec/unit/virtus/attribute_set/merge_spec.rb ./spec/unit/virtus/attribute_set/reset_spec.rb ./spec/unit/virtus/attribute_set/parent_spec.rb ./spec/unit/virtus/attribute_set/append_spec.rb ./spec/unit/virtus/attribute_set/element_set_spec.rb ./spec/unit/virtus/attribute_set/element_reference_spec.rb ./spec/unit/virtus/coercion/class_name_reference_spec.rb ./spec/unit/virtus/instance_methods/attributes_spec.rb ./spec/unit/virtus/instance_methods/element_set_spec.rb ./spec/unit/virtus/instance_methods/element_reference_spec.rb ./spec/unit/virtus/options/options_spec.rb ./spec/unit/virtus/options/accepted_options_spec.rb ./spec/unit/virtus/options/accept_options_spec.rb ./spec/unit/virtus/coercion/hash/class_methods/to_date_spec.rb ./spec/unit/virtus/coercion/hash/class_methods/to_datetime_spec.rb ./spec/unit/virtus/coercion/hash/class_methods/to_time_spec.rb ./spec/unit/virtus/coercion/hash/class_methods/to_array_spec.rb ./spec/unit/virtus/coercion/float/class_methods/to_decimal_spec.rb ./spec/unit/virtus/coercion/float/class_methods/to_integer_spec.rb ./spec/unit/virtus/coercion/float/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/object/class_methods/method_missing_spec.rb ./spec/unit/virtus/coercion/false_class/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/date/class_methods/to_datetime_spec.rb ./spec/unit/virtus/coercion/date/class_methods/to_time_spec.rb ./spec/unit/virtus/coercion/date/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/decimal/class_methods/to_float_spec.rb ./spec/unit/virtus/coercion/decimal/class_methods/to_integer_spec.rb ./spec/unit/virtus/coercion/decimal/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/integer/class_methods/to_decimal_spec.rb ./spec/unit/virtus/coercion/integer/class_methods/to_float_spec.rb ./spec/unit/virtus/coercion/integer/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/integer/class_methods/to_boolean_spec.rb ./spec/unit/virtus/coercion/symbol/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/true_class/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_date_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_decimal_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_datetime_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_time_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_float_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_integer_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_constant_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_boolean_spec.rb ./spec/unit/virtus/coercion/date_time/class_methods/to_date_spec.rb ./spec/unit/virtus/coercion/date_time/class_methods/to_time_spec.rb ./spec/unit/virtus/coercion/date_time/class_methods/to_string_spec.rb ./spec/unit/virtus/attribute/class_methods/determine_type_spec.rb ./spec/unit/virtus/attribute/default_value/class_methods/new_spec.rb ./spec/unit/virtus/attribute/default_value/instance_methods/evaluate_spec.rb ./spec/unit/virtus/attribute/object/class_methods/descendants_spec.rb ./spec/unit/virtus/attribute/numeric/class_methods/descendants_spec.rb
29An exception occurred running at_exit handlers
30undefined method `empty?' on nil:NilClass. (NoMethodError)
31
32Backtrace:
33 Kernel(NilClass)#empty? (method_missing) at kernel/delta/kernel.rb:79
34RSpec::Core::Configuration#configure_group at /home/vagrant/.rvm/gems
35/rbx-head/gems
36/rspec-core-2.6.4/lib
37/rspec/core
38/configuration.rb:403
39 Array#each at kernel/bootstrap/array.rb:59
40RSpec::Core::Configuration#configure_group at /home/vagrant/.rvm/gems/rbx-head
41/gems/rspec-core-2.6.4/lib/rspec
42/core/configuration.rb:402
43RSpec::Core::World#configure_group at /home/vagrant/.rvm/gems/rbx-head/gems
44/rspec-core-2.6.4/lib/rspec/core
45/world.rb:62
46RSpec::Core::ExampleGroup.set_it_up at /home/vagrant/.rvm/gems/rbx-head/gems
47/rspec-core-2.6.4/lib/rspec/core
48/example_group.rb:184
49RSpec::Core::ExampleGroup.subclass at /home/vagrant/.rvm/gems/rbx-head/gems
50/rspec-core-2.6.4/lib/rspec/core
51/example_group.rb:141
52RSpec::Core::ExampleGroup.describe at /home/vagrant/.rvm/gems/rbx-head/gems
53/rspec-core-2.6.4/lib/rspec/core
54/example_group.rb:129
55RSpec::Core::DSL(Object)#describe at /home/vagrant/.rvm/gems/rbx-head/gems
56/rspec-core-2.6.4/lib/rspec/core
57/dsl.rb:5
58Object#__script__ at spec/unit/virtus/attribute
59/integer_spec.rb:3
60 Kernel(RSpec::Core::Configuration)#load at kernel/common/kernel.rb:621
61{ } in RSpec::Core::Configuration#load_spec_files at /home/vagrant/.rvm/gems
62/rbx-head/gems
63/rspec-core-2.6.4/lib
64/rspec/core
65/configuration.rb:419
66 Array#map at kernel/bootstrap/array19.rb:16
67RSpec::Core::Configuration#load_spec_files at /home/vagrant/.rvm/gems/rbx-head
68/gems/rspec-core-2.6.4/lib/rspec
69/core/configuration.rb:419
70RSpec::Core::CommandLine#run at /home/vagrant/.rvm/gems/rbx-head/gems
71/rspec-core-2.6.4/lib/rspec/core
72/command_line.rb:18
73RSpec::Core::Runner.run_in_process at /home/vagrant/.rvm/gems/rbx-head/gems
74/rspec-core-2.6.4/lib/rspec/core
75/runner.rb:80
76RSpec::Core::Runner.run at /home/vagrant/.rvm/gems/rbx-head/gems
77/rspec-core-2.6.4/lib/rspec/core
78/runner.rb:69
79{ } in RSpec::Core::Runner.autorun at /home/vagrant/.rvm/gems/rbx-head/gems
80/rspec-core-2.6.4/lib/rspec/core
81/runner.rb:11
82 Rubinius::Loader#run_at_exits at kernel/loader.rb:659
83 Rubinius::Loader#epilogue at kernel/loader.rb:679
84 Rubinius::Loader#main at kernel/loader.rb:809
85rake aborted!
86ruby -S bundle exec rspec ./spec/integration/virtus/class_methods/attributes_spec.rb ./spec/integration/virtus/class_methods/const_missing_spec.rb ./spec/integration/virtus/class_methods/attribute_spec.rb ./spec/integration/virtus/attributes/attribute/set_spec.rb ./spec/unit/virtus/attribute/decimal_spec.rb ./spec/unit/virtus/attribute/date_time_spec.rb ./spec/unit/virtus/attribute/time_spec.rb ./spec/unit/virtus/attribute/boolean_spec.rb ./spec/unit/virtus/attribute/float_spec.rb ./spec/unit/virtus/attribute/date_spec.rb ./spec/unit/virtus/attribute/class_spec.rb ./spec/unit/virtus/attribute/hash_spec.rb ./spec/unit/virtus/attribute/string_spec.rb ./spec/unit/virtus/attribute/array_spec.rb ./spec/unit/virtus/attribute/integer_spec.rb ./spec/unit/virtus/type_lookup/determine_type_spec.rb ./spec/unit/virtus/type_lookup/primitive_spec.rb ./spec/unit/virtus/class_methods/attributes_spec.rb ./spec/unit/virtus/class_methods/new_spec.rb ./spec/unit/virtus/class_methods/attribute_spec.rb ./spec/unit/virtus/descendants_tracker/add_descendant_spec.rb ./spec/unit/virtus/descendants_tracker/descendants_spec.rb ./spec/unit/virtus/attribute_set/each_spec.rb ./spec/unit/virtus/attribute_set/merge_spec.rb ./spec/unit/virtus/attribute_set/reset_spec.rb ./spec/unit/virtus/attribute_set/parent_spec.rb ./spec/unit/virtus/attribute_set/append_spec.rb ./spec/unit/virtus/attribute_set/element_set_spec.rb ./spec/unit/virtus/attribute_set/element_reference_spec.rb ./spec/unit/virtus/coercion/class_name_reference_spec.rb ./spec/unit/virtus/instance_methods/attributes_spec.rb ./spec/unit/virtus/instance_methods/element_set_spec.rb ./spec/unit/virtus/instance_methods/element_reference_spec.rb ./spec/unit/virtus/options/options_spec.rb ./spec/unit/virtus/options/accepted_options_spec.rb ./spec/unit/virtus/options/accept_options_spec.rb ./spec/unit/virtus/coercion/hash/class_methods/to_date_spec.rb ./spec/unit/virtus/coercion/hash/class_methods/to_datetime_spec.rb ./spec/unit/virtus/coercion/hash/class_methods/to_time_spec.rb ./spec/unit/virtus/coercion/hash/class_methods/to_array_spec.rb ./spec/unit/virtus/coercion/float/class_methods/to_decimal_spec.rb ./spec/unit/virtus/coercion/float/class_methods/to_integer_spec.rb ./spec/unit/virtus/coercion/float/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/object/class_methods/method_missing_spec.rb ./spec/unit/virtus/coercion/false_class/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/date/class_methods/to_datetime_spec.rb ./spec/unit/virtus/coercion/date/class_methods/to_time_spec.rb ./spec/unit/virtus/coercion/date/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/decimal/class_methods/to_float_spec.rb ./spec/unit/virtus/coercion/decimal/class_methods/to_integer_spec.rb ./spec/unit/virtus/coercion/decimal/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/integer/class_methods/to_decimal_spec.rb ./spec/unit/virtus/coercion/integer/class_methods/to_float_spec.rb ./spec/unit/virtus/coercion/integer/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/integer/class_methods/to_boolean_spec.rb ./spec/unit/virtus/coercion/symbol/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/true_class/class_methods/to_string_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_date_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_decimal_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_datetime_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_time_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_float_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_integer_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_constant_spec.rb ./spec/unit/virtus/coercion/string/class_methods/to_boolean_spec.rb ./spec/unit/virtus/coercion/date_time/class_methods/to_date_spec.rb ./spec/unit/virtus/coercion/date_time/class_methods/to_time_spec.rb ./spec/unit/virtus/coercion/date_time/class_methods/to_string_spec.rb ./spec/unit/virtus/attribute/class_methods/determine_type_spec.rb ./spec/unit/virtus/attribute/default_value/class_methods/new_spec.rb ./spec/unit/virtus/attribute/default_value/instance_methods/evaluate_spec.rb ./spec/unit/virtus/attribute/object/class_methods/descendants_spec.rb ./spec/unit/virtus/attribute/numeric/class_methods/descendants_spec.rb failed
87
88Tasks: TOP => spec
89(See full trace by running task with --trace)
90
91Done. Build script exited with: 1
In default values example, #default_editor_title calls #published?, but as far as I can tell #published? isn't defined. I'm guessing its just a Readme error?
Would it make sense for virtus to track changed attributes so that the mapper can choose what fields to update?
u = User.new
u.name = 'foo'
u.changed_attributes # {:name => 'foo'}
recently I played around with virtus and de/serialization. since virtus already offers a to_hash method with a deep copy if the data things were pretty straight forward. I wonder if this something for virtus itself or for another gem like dm-serialization ? I could setup a project in case nothing is there already !!
I've noticed that there are multiple places where integration specs are placed:
I think it would be a good idea to unify these specs and group them together. Currently the example specs also differ in writing style from the spec/integration specs. I would also suggest to pursue one writing style for integration specs. I also think these specs are a good place to "document" the different features of virtus, which are not all visible in the README. I like projects which explanatory integration specs to demonstrate the features.
What do you think? Is there a reason for these specs to coexist? What style of writing do you prefere?
what I'd like to be able to do is something like
class Address
include Virtus
# include .... something else, too, to make it a property as well?
attribute :line1, String
# ... others
end
class Person
include Virtus
attribute :name, String
attribute :address, Address
end
Preferably without needing to manually set up a whole slew of property subclasses. This would be useful for using Virtus to back a system for interacting with e.g. CouchDB where embedded values are not uncommon and they sometimes need more complex behaviour than a hash provides
How does Virtus handle class inheritance? More specifically how are attribute options accessed/collated through the inheritance chain.
I have a model, Person that has a Company attrbiute:
class Person
include Virtus
attribute :company, Company, :default => nil
# rest omitted
end
Company also includes Virtus.
if I create a Person with
p = Person.new(:company => nil, :last_name => 'Confused')
and inspect p.attributes it has a Company instance. I don't think it should have a Company instance if I instantiate it with a nil. Of note: it did not exhibit this behavior in the previous version.
For instance, I have a Person model that has many Article entities related to it:
class Person
include Virtus
attribute :name, String
attribute :gender, String
attribute :articles, Array[Article]
end
On the other hand, I have an Article object that is related to Person:
class Article
include Virtus
attribute :title, String
attribute :text, String
attribute :person_id, BSON::ObjectId
attribute :person, Person
end
What is the suggested way to handle such things?
Usually, wrapping in lambda for lazy evaluation works fine for such cases (e.q.)
attribute :person, lambda { Person }
or turning Object to Symbol:
attribute :person, :Person
Maybe current example is not quite exhaustive, but there are many cases when two objects have an equal power, first may be initialized via attributes of second one or vice versa.
Both approaches allow following trivial instantiation.
I want to integrate virtus into our existing application as a replacement for ActiveModel
form backends. Since we use Rails it would be convenient to have a mass-assignment functionality backed into virtus. Is there anything planned in that direction?
I just tried to write an integration spec. Since I don't want to pollute the namespace I wanted to define the virtus classes like:
let(:person_class) do
Class.new do
include Virtus
attribute :name, String
attribute :age, Integer
attribute :doctor, Boolean
end
end
This results in the following error:
Failure/Error: attribute :age, Boolean
NameError:
uninitialized constant Class::Boolean
I investigated the error and found out, that the problem is the const_missing
definition in Virtus. In the block passed to Class.new constant lookup is performed on the top-level so it never reaches the const-missing
defined by virtus. Following an example to illustrate the problem:
class ThisWorks
def self.const_missing(*args)
p "yay!"
end
NonExistingConstant
end
this_does_not_work = Class.new do
def self.const_missing(*args)
p "yay!"
end
NonExistingConstant
end
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.