virtus 1.0.0.beta7 → 1.0.0.beta8
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +31 -2
- data/lib/virtus.rb +7 -0
- data/lib/virtus/attribute.rb +11 -4
- data/lib/virtus/attribute/builder.rb +111 -44
- data/lib/virtus/attribute/collection.rb +25 -6
- data/lib/virtus/attribute/embedded_value.rb +3 -2
- data/lib/virtus/attribute/hash.rb +23 -7
- data/lib/virtus/attribute_set.rb +9 -1
- data/lib/virtus/configuration.rb +4 -0
- data/lib/virtus/module_builder.rb +8 -0
- data/lib/virtus/version.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/virtus/attribute/collection/coerce_spec.rb +1 -0
- data/spec/unit/virtus/attribute/hash/coerce_spec.rb +2 -0
- data/spec/unit/virtus/class_methods/finalize_spec.rb +55 -0
- metadata +3 -2
data/README.md
CHANGED
@@ -476,6 +476,9 @@ class User
|
|
476
476
|
end
|
477
477
|
```
|
478
478
|
|
479
|
+
Please check out [Coercible README](https://github.com/solnic/coercible/blob/master/README.md)
|
480
|
+
for more information.
|
481
|
+
|
479
482
|
## Strict Coercion Mode
|
480
483
|
|
481
484
|
By default Virtus returns the input value even when it couldn't coerce it to the expected type.
|
@@ -519,8 +522,34 @@ class User
|
|
519
522
|
end
|
520
523
|
```
|
521
524
|
|
522
|
-
|
523
|
-
|
525
|
+
## Attribute Finalization and Circular Dependencies
|
526
|
+
|
527
|
+
If a type references another type which happens to not be available yet you need
|
528
|
+
to use lazy-finalization of attributes and finalize virtus manually after all
|
529
|
+
types have been already loaded:
|
530
|
+
|
531
|
+
``` ruby
|
532
|
+
# in blog.rb
|
533
|
+
class Blog
|
534
|
+
include Virtus.model(:finalize => false)
|
535
|
+
|
536
|
+
attribute :posts, Array['Post']
|
537
|
+
end
|
538
|
+
|
539
|
+
# in post.rb
|
540
|
+
class Post
|
541
|
+
include Virtus.model(:finalize => false)
|
542
|
+
|
543
|
+
attribute :blog, 'Blog'
|
544
|
+
end
|
545
|
+
|
546
|
+
# after loading both files just do:
|
547
|
+
Virtus.finalize
|
548
|
+
|
549
|
+
# constants will be resolved:
|
550
|
+
Blog.attribute_set[:posts].member_type.primitive # => Post
|
551
|
+
Post.attribute_set[:blog].type.primitive # => Blog
|
552
|
+
```
|
524
553
|
|
525
554
|
Credits
|
526
555
|
-------
|
data/lib/virtus.rb
CHANGED
@@ -150,6 +150,13 @@ module Virtus
|
|
150
150
|
@configuration ||= Configuration.new
|
151
151
|
end
|
152
152
|
|
153
|
+
# @api public
|
154
|
+
def self.finalize
|
155
|
+
ExtensionBuilder.pending.each do |klass|
|
156
|
+
klass.attribute_set.finalize
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
153
160
|
# @api private
|
154
161
|
def self.warn(msg)
|
155
162
|
Kernel.warn(msg)
|
data/lib/virtus/attribute.rb
CHANGED
@@ -5,11 +5,12 @@ module Virtus
|
|
5
5
|
|
6
6
|
include ::Equalizer.new(:type, :options)
|
7
7
|
|
8
|
-
accept_options :primitive, :accessor, :default, :lazy, :strict, :required
|
8
|
+
accept_options :primitive, :accessor, :default, :lazy, :strict, :required, :finalize
|
9
9
|
|
10
10
|
strict false
|
11
11
|
required true
|
12
12
|
accessor :public
|
13
|
+
finalize true
|
13
14
|
|
14
15
|
# @see Virtus.coerce
|
15
16
|
#
|
@@ -55,12 +56,12 @@ module Virtus
|
|
55
56
|
def self.new(*args)
|
56
57
|
attribute = super
|
57
58
|
yield(attribute)
|
58
|
-
attribute
|
59
|
+
attribute
|
59
60
|
end
|
60
61
|
|
61
62
|
# @api private
|
62
|
-
def self.build_type(
|
63
|
-
Axiom::Types.infer(
|
63
|
+
def self.build_type(definition)
|
64
|
+
Axiom::Types.infer(definition.primitive)
|
64
65
|
end
|
65
66
|
|
66
67
|
# @api private
|
@@ -126,6 +127,11 @@ module Virtus
|
|
126
127
|
options[:required]
|
127
128
|
end
|
128
129
|
|
130
|
+
# @api public
|
131
|
+
def finalized?
|
132
|
+
frozen?
|
133
|
+
end
|
134
|
+
|
129
135
|
# @api private
|
130
136
|
def define_accessor_methods(attribute_set)
|
131
137
|
attribute_set.define_reader_method(self, name, options[:reader])
|
@@ -135,6 +141,7 @@ module Virtus
|
|
135
141
|
# @api private
|
136
142
|
def finalize
|
137
143
|
freeze
|
144
|
+
self
|
138
145
|
end
|
139
146
|
|
140
147
|
end # class Attribute
|
@@ -1,4 +1,79 @@
|
|
1
1
|
module Virtus
|
2
|
+
|
3
|
+
# @private
|
4
|
+
class PendingAttribute
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
# @api private
|
8
|
+
def initialize(type, options)
|
9
|
+
@type = type
|
10
|
+
@options = options
|
11
|
+
@name = options[:name]
|
12
|
+
end
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
def finalize
|
16
|
+
Attribute::Builder.call(determine_type, @options).finalize
|
17
|
+
end
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def finalized?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
# @api private
|
25
|
+
def determine_type
|
26
|
+
if @type.include?('::')
|
27
|
+
# TODO: wrap it up in Virtus.constantize and use feature-detection to
|
28
|
+
# pick up either Inflecto or ActiveSupport, whateve is available
|
29
|
+
if defined?(Inflecto)
|
30
|
+
Inflecto.constantize(@type)
|
31
|
+
else
|
32
|
+
raise NotImplementedError, 'Virtus needs inflecto gem to constantize namespaced constant names'
|
33
|
+
end
|
34
|
+
else
|
35
|
+
Object.const_get(@type)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end # PendingAttribute
|
40
|
+
|
41
|
+
class TypeDefinition
|
42
|
+
attr_reader :type, :primitive
|
43
|
+
|
44
|
+
# @api private
|
45
|
+
def initialize(type)
|
46
|
+
@type = type
|
47
|
+
initialize_primitive
|
48
|
+
end
|
49
|
+
|
50
|
+
# @api private
|
51
|
+
def pending?
|
52
|
+
@pending
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# @api private
|
58
|
+
def initialize_primitive
|
59
|
+
@primitive =
|
60
|
+
if type.instance_of?(String) || type.instance_of?(Symbol)
|
61
|
+
if !type.to_s.include?('::') && Object.const_defined?(type)
|
62
|
+
Object.const_get(type)
|
63
|
+
elsif not Attribute::Builder.determine_type(type)
|
64
|
+
@pending = true
|
65
|
+
type
|
66
|
+
else
|
67
|
+
type
|
68
|
+
end
|
69
|
+
elsif not type.is_a?(Class)
|
70
|
+
type.class
|
71
|
+
else
|
72
|
+
type
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
2
77
|
class Attribute
|
3
78
|
|
4
79
|
# TODO: this is a huge class and it might be a good idea to split it into
|
@@ -10,8 +85,14 @@ module Virtus
|
|
10
85
|
attr_reader :attribute
|
11
86
|
|
12
87
|
# @api private
|
13
|
-
def self.call(
|
14
|
-
new(
|
88
|
+
def self.call(type, options = {})
|
89
|
+
type_definition = TypeDefinition.new(type)
|
90
|
+
|
91
|
+
if type_definition.pending?
|
92
|
+
PendingAttribute.new(type, options)
|
93
|
+
else
|
94
|
+
new(type_definition, options).attribute
|
95
|
+
end
|
15
96
|
end
|
16
97
|
|
17
98
|
# @api private
|
@@ -33,10 +114,11 @@ module Virtus
|
|
33
114
|
end
|
34
115
|
|
35
116
|
# @api private
|
36
|
-
def initialize(
|
37
|
-
|
117
|
+
def initialize(type_definition, options)
|
118
|
+
@type_definition = type_definition
|
119
|
+
|
38
120
|
initialize_class
|
39
|
-
initialize_type
|
121
|
+
initialize_type
|
40
122
|
initialize_options(options)
|
41
123
|
initialize_default_value
|
42
124
|
initialize_coercer
|
@@ -45,50 +127,14 @@ module Virtus
|
|
45
127
|
|
46
128
|
private
|
47
129
|
|
48
|
-
# @api private
|
49
|
-
def initialize_attribute
|
50
|
-
@attribute = @klass.new(@type, @options) do |attribute|
|
51
|
-
attribute.extend(Accessor) if @options[:name]
|
52
|
-
attribute.extend(Coercible) if @options[:coerce]
|
53
|
-
attribute.extend(Strict) if @options[:strict]
|
54
|
-
attribute.extend(LazyDefault) if @options[:lazy]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# @api private
|
59
|
-
def initialize_default_value
|
60
|
-
@options.update(:default_value => DefaultValue.build(@options[:default]))
|
61
|
-
end
|
62
|
-
|
63
|
-
# @api private
|
64
|
-
def initialize_coercer
|
65
|
-
@options.update(:coercer => @options.fetch(:coercer) { @klass.build_coercer(@type, @options) })
|
66
|
-
end
|
67
|
-
|
68
|
-
# @api private
|
69
|
-
def initialize_primitive(type)
|
70
|
-
@primitive =
|
71
|
-
if type.instance_of?(String) || type.instance_of?(Symbol)
|
72
|
-
begin
|
73
|
-
Object.const_get(type)
|
74
|
-
rescue
|
75
|
-
type
|
76
|
-
end
|
77
|
-
elsif not type.is_a?(Class)
|
78
|
-
type.class
|
79
|
-
else
|
80
|
-
type
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
130
|
# @api private
|
85
131
|
def initialize_class
|
86
|
-
@klass = self.class.determine_type(@primitive, Attribute)
|
132
|
+
@klass = self.class.determine_type(@type_definition.primitive, Attribute)
|
87
133
|
end
|
88
134
|
|
89
135
|
# @api private
|
90
|
-
def initialize_type
|
91
|
-
@type = @klass.build_type(
|
136
|
+
def initialize_type
|
137
|
+
@type = @klass.build_type(@type_definition)
|
92
138
|
end
|
93
139
|
|
94
140
|
# @api private
|
@@ -106,6 +152,27 @@ module Virtus
|
|
106
152
|
@options.update(:reader => reader_visibility, :writer => writer_visibility)
|
107
153
|
end
|
108
154
|
|
155
|
+
# @api private
|
156
|
+
def initialize_default_value
|
157
|
+
@options.update(:default_value => DefaultValue.build(@options[:default]))
|
158
|
+
end
|
159
|
+
|
160
|
+
# @api private
|
161
|
+
def initialize_coercer
|
162
|
+
@options.update(:coercer => @options.fetch(:coercer) { @klass.build_coercer(@type, @options) })
|
163
|
+
end
|
164
|
+
|
165
|
+
# @api private
|
166
|
+
def initialize_attribute
|
167
|
+
@attribute = @klass.new(@type, @options) do |attribute|
|
168
|
+
attribute.extend(Accessor) if @options[:name]
|
169
|
+
attribute.extend(Coercible) if @options[:coerce]
|
170
|
+
attribute.extend(Strict) if @options[:strict]
|
171
|
+
attribute.extend(LazyDefault) if @options[:lazy]
|
172
|
+
end
|
173
|
+
@attribute.finalize if @options[:finalize]
|
174
|
+
end
|
175
|
+
|
109
176
|
end # class Builder
|
110
177
|
|
111
178
|
end # class Attribute
|
@@ -9,15 +9,17 @@ module Virtus
|
|
9
9
|
class Collection < Attribute
|
10
10
|
default Proc.new { |_, attribute| attribute.type.primitive.new }
|
11
11
|
|
12
|
+
attr_reader :member_type
|
13
|
+
|
12
14
|
# FIXME: temporary hack, remove when Axiom::Type works with EV as member_type
|
13
15
|
Type = Struct.new(:primitive, :member_type) do
|
14
16
|
def self.infer(type, primitive)
|
15
|
-
return type if
|
17
|
+
return type if axiom_type?(type)
|
16
18
|
|
17
19
|
klass = Axiom::Types.infer(type)
|
18
20
|
member = infer_member_type(type) || Object
|
19
21
|
|
20
|
-
if EmbeddedValue.handles?(member)
|
22
|
+
if EmbeddedValue.handles?(member) || pending?(member)
|
21
23
|
Type.new(primitive, member)
|
22
24
|
else
|
23
25
|
klass.new {
|
@@ -27,6 +29,14 @@ module Virtus
|
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
32
|
+
def self.pending?(primitive)
|
33
|
+
primitive.is_a?(String) || primitive.is_a?(Symbol)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.axiom_type?(type)
|
37
|
+
type.is_a?(Class) && type < Axiom::Types::Type
|
38
|
+
end
|
39
|
+
|
30
40
|
def self.infer_member_type(type)
|
31
41
|
return unless type.respond_to?(:count)
|
32
42
|
|
@@ -43,8 +53,8 @@ module Virtus
|
|
43
53
|
end
|
44
54
|
|
45
55
|
# @api private
|
46
|
-
def self.build_type(
|
47
|
-
Type.infer(
|
56
|
+
def self.build_type(definition)
|
57
|
+
Type.infer(definition.type, definition.primitive)
|
48
58
|
end
|
49
59
|
|
50
60
|
# @api private
|
@@ -61,10 +71,19 @@ module Virtus
|
|
61
71
|
end
|
62
72
|
end
|
63
73
|
|
64
|
-
|
65
|
-
|
74
|
+
# @api private
|
75
|
+
def finalize
|
76
|
+
return self if finalized?
|
77
|
+
@member_type = @options[:member_type].finalize
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
# @api private
|
82
|
+
def finalized?
|
83
|
+
super && member_type.finalized?
|
66
84
|
end
|
67
85
|
|
68
86
|
end # class Collection
|
87
|
+
|
69
88
|
end # class Attribute
|
70
89
|
end # module Virtus
|
@@ -66,8 +66,9 @@ module Virtus
|
|
66
66
|
end
|
67
67
|
|
68
68
|
# @api private
|
69
|
-
def self.build_type(
|
70
|
-
|
69
|
+
def self.build_type(definition)
|
70
|
+
klass = definition.primitive.is_a?(Class) ? definition.primitive : definition.type
|
71
|
+
Axiom::Types::Object.new { primitive klass }
|
71
72
|
end
|
72
73
|
|
73
74
|
# @api private
|
@@ -16,10 +16,13 @@ module Virtus
|
|
16
16
|
primitive ::Hash
|
17
17
|
default primitive.new
|
18
18
|
|
19
|
+
attr_reader :key_type
|
20
|
+
attr_reader :value_type
|
21
|
+
|
19
22
|
# FIXME: remove this once axiom-types supports it
|
20
23
|
Type = Struct.new(:key_type, :value_type) do
|
21
24
|
def self.infer(type)
|
22
|
-
if
|
25
|
+
if axiom_type?(type)
|
23
26
|
new(type.key_type, type.value_type)
|
24
27
|
else
|
25
28
|
type_options = infer_key_and_value_types(type)
|
@@ -30,7 +33,17 @@ module Virtus
|
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
36
|
+
def self.pending?(primitive)
|
37
|
+
primitive.is_a?(String) || primitive.is_a?(Symbol)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.axiom_type?(type)
|
41
|
+
type.is_a?(Class) && type < Axiom::Types::Type
|
42
|
+
end
|
43
|
+
|
33
44
|
def self.determine_type(type)
|
45
|
+
return type if pending?(type)
|
46
|
+
|
34
47
|
if EmbeddedValue.handles?(type)
|
35
48
|
type
|
36
49
|
else
|
@@ -58,8 +71,8 @@ module Virtus
|
|
58
71
|
end
|
59
72
|
|
60
73
|
# @api private
|
61
|
-
def self.build_type(
|
62
|
-
Type.infer(
|
74
|
+
def self.build_type(definition)
|
75
|
+
Type.infer(definition.type)
|
63
76
|
end
|
64
77
|
|
65
78
|
# @api private
|
@@ -85,13 +98,16 @@ module Virtus
|
|
85
98
|
end
|
86
99
|
|
87
100
|
# @api private
|
88
|
-
def
|
89
|
-
|
101
|
+
def finalize
|
102
|
+
return self if finalized?
|
103
|
+
@key_type = options[:key_type].finalize
|
104
|
+
@value_type = options[:value_type].finalize
|
105
|
+
super
|
90
106
|
end
|
91
107
|
|
92
108
|
# @api private
|
93
|
-
def
|
94
|
-
|
109
|
+
def finalized?
|
110
|
+
super && key_type.finalized? && value_type.finalized?
|
95
111
|
end
|
96
112
|
|
97
113
|
end # class Hash
|
data/lib/virtus/attribute_set.rb
CHANGED
@@ -74,7 +74,8 @@ module Virtus
|
|
74
74
|
# @api public
|
75
75
|
def <<(attribute)
|
76
76
|
self[attribute.name] = attribute
|
77
|
-
attribute.define_accessor_methods(self)
|
77
|
+
attribute.define_accessor_methods(self) if attribute.finalized?
|
78
|
+
self
|
78
79
|
end
|
79
80
|
|
80
81
|
# Get an attribute by name
|
@@ -208,6 +209,13 @@ module Virtus
|
|
208
209
|
)
|
209
210
|
end
|
210
211
|
|
212
|
+
# @api private
|
213
|
+
def finalize
|
214
|
+
each do |attribute|
|
215
|
+
self << attribute.finalize unless attribute.finalized?
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
211
219
|
private
|
212
220
|
|
213
221
|
# @api private
|
data/lib/virtus/configuration.rb
CHANGED
@@ -3,6 +3,9 @@ module Virtus
|
|
3
3
|
# A Configuration instance
|
4
4
|
class Configuration
|
5
5
|
|
6
|
+
# Access the finalize setting for this instance
|
7
|
+
attr_accessor :finalize
|
8
|
+
|
6
9
|
# Access the coerce setting for this instance
|
7
10
|
attr_accessor :coerce
|
8
11
|
|
@@ -35,6 +38,7 @@ module Virtus
|
|
35
38
|
#
|
36
39
|
# @api private
|
37
40
|
def initialize
|
41
|
+
@finalize = true
|
38
42
|
@coerce = true
|
39
43
|
@strict = false
|
40
44
|
@constructor = true
|
@@ -44,6 +44,11 @@ module Virtus
|
|
44
44
|
builder.module
|
45
45
|
end
|
46
46
|
|
47
|
+
# @api private
|
48
|
+
def self.pending
|
49
|
+
@pending ||= []
|
50
|
+
end
|
51
|
+
|
47
52
|
# Initializes a new ModuleBuilder
|
48
53
|
#
|
49
54
|
# @param [Configuration] configuration
|
@@ -68,11 +73,13 @@ module Virtus
|
|
68
73
|
attribute_proc = attribute_method(configuration)
|
69
74
|
constructor = configuration.constructor
|
70
75
|
mass_assignment = configuration.mass_assignment
|
76
|
+
finalize = configuration.finalize
|
71
77
|
extensions = core_extensions
|
72
78
|
inclusions = core_inclusions
|
73
79
|
|
74
80
|
self.module.define_singleton_method :included do |object|
|
75
81
|
super(object)
|
82
|
+
ExtensionBuilder.pending << object unless finalize
|
76
83
|
extensions.each { |mod| object.extend(mod) }
|
77
84
|
inclusions.each { |mod| object.send(:include, mod) }
|
78
85
|
object.send(:include, Model::Constructor) if constructor
|
@@ -114,6 +121,7 @@ module Virtus
|
|
114
121
|
# @api private
|
115
122
|
def module_options
|
116
123
|
{ :coerce => configuration.coerce,
|
124
|
+
:finalize => configuration.finalize,
|
117
125
|
:strict => configuration.strict,
|
118
126
|
:configured_coercer => configuration.coercer }
|
119
127
|
end
|
data/lib/virtus/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -17,6 +17,7 @@ describe Virtus::Attribute::Collection, '#coerce' do
|
|
17
17
|
|
18
18
|
it 'uses coercer to coerce members' do
|
19
19
|
stub(coercer).call(input) { input }
|
20
|
+
stub(member_type).finalize { member_type }
|
20
21
|
stub(member_type).coerce('1') { 1 }
|
21
22
|
stub(member_type).coerce('2') { 2 }
|
22
23
|
|
@@ -41,9 +41,11 @@ describe Virtus::Attribute::Hash, '#coerce' do
|
|
41
41
|
it 'uses coercer to coerce key and value' do
|
42
42
|
stub(coercer).call(input) { input }
|
43
43
|
|
44
|
+
stub(key_type).finalize { key_type }
|
44
45
|
stub(key_type).coerce(1) { '1' }
|
45
46
|
stub(key_type).coerce(2) { '2' }
|
46
47
|
|
48
|
+
stub(value_type).finalize { value_type }
|
47
49
|
stub(value_type).coerce('1') { 1 }
|
48
50
|
stub(value_type).coerce('2') { 2 }
|
49
51
|
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Virtus, '.finalize' do
|
4
|
+
before do
|
5
|
+
module Examples
|
6
|
+
class Person
|
7
|
+
include Virtus.model(:finalize => false)
|
8
|
+
|
9
|
+
attribute :articles, Array['Examples::Article']
|
10
|
+
attribute :address, 'Examples::Address'
|
11
|
+
end
|
12
|
+
|
13
|
+
class Article
|
14
|
+
include Virtus.model(:finalize => false)
|
15
|
+
|
16
|
+
attribute :posts, Hash['Examples::Person' => 'Examples::Post']
|
17
|
+
attribute :person, 'Examples::Person'
|
18
|
+
end
|
19
|
+
|
20
|
+
class Post
|
21
|
+
include Virtus.model(:finalize => false)
|
22
|
+
|
23
|
+
attribute :title, String
|
24
|
+
end
|
25
|
+
|
26
|
+
class Address
|
27
|
+
include Virtus.model(:finalize => false)
|
28
|
+
|
29
|
+
attribute :street, String
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Virtus.finalize
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'it finalizes member type for a collection attribute' do
|
37
|
+
expect(Examples::Person.attribute_set[:address].primitive).to be(Examples::Address)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'it finalizes key type for a hash attribute' do
|
41
|
+
expect(Examples::Article.attribute_set[:posts].key_type.primitive).to be(Examples::Person)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'it finalizes value type for a hash attribute' do
|
45
|
+
expect(Examples::Article.attribute_set[:posts].value_type.primitive).to be(Examples::Post)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'it finalizes type for an EV attribute' do
|
49
|
+
expect(Examples::Article.attribute_set[:person].type.primitive).to be(Examples::Person)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'automatically resolves constant when it is already available' do
|
53
|
+
expect(Examples::Article.attribute_set[:person].type.primitive).to be(Examples::Person)
|
54
|
+
end
|
55
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: virtus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.beta8
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
12
|
+
date: 2013-09-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: descendants_tracker
|
@@ -189,6 +189,7 @@ files:
|
|
189
189
|
- spec/unit/virtus/attribute_spec.rb
|
190
190
|
- spec/unit/virtus/attributes_reader_spec.rb
|
191
191
|
- spec/unit/virtus/attributes_writer_spec.rb
|
192
|
+
- spec/unit/virtus/class_methods/finalize_spec.rb
|
192
193
|
- spec/unit/virtus/class_methods/new_spec.rb
|
193
194
|
- spec/unit/virtus/config_spec.rb
|
194
195
|
- spec/unit/virtus/element_reader_spec.rb
|