virtus 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +11 -15
- data/History.txt +10 -0
- data/TODO +4 -0
- data/VERSION +1 -1
- data/config/flay.yml +1 -1
- data/config/flog.yml +1 -1
- data/config/roodi.yml +6 -6
- data/config/site.reek +5 -5
- data/lib/virtus.rb +21 -11
- data/lib/virtus/attribute.rb +92 -59
- data/lib/virtus/attribute/array.rb +4 -3
- data/lib/virtus/attribute/boolean.rb +21 -9
- data/lib/virtus/attribute/date.rb +5 -3
- data/lib/virtus/attribute/date_time.rb +5 -3
- data/lib/virtus/attribute/decimal.rb +5 -3
- data/lib/virtus/attribute/float.rb +5 -3
- data/lib/virtus/attribute/hash.rb +4 -3
- data/lib/virtus/attribute/integer.rb +5 -3
- data/lib/virtus/attribute/numeric.rb +5 -3
- data/lib/virtus/attribute/object.rb +4 -4
- data/lib/virtus/attribute/string.rb +7 -9
- data/lib/virtus/attribute/time.rb +5 -3
- data/lib/virtus/attribute_set.rb +151 -0
- data/lib/virtus/class_methods.rb +19 -10
- data/lib/virtus/instance_methods.rb +51 -27
- data/lib/virtus/support/descendants_tracker.rb +30 -0
- data/lib/virtus/typecast/boolean.rb +7 -5
- data/lib/virtus/typecast/numeric.rb +13 -8
- data/lib/virtus/typecast/string.rb +24 -0
- data/lib/virtus/typecast/time.rb +7 -5
- data/spec/integration/virtus/class_methods/attribute_spec.rb +17 -5
- data/spec/integration/virtus/class_methods/attributes_spec.rb +2 -5
- data/spec/shared/idempotent_method_behaviour.rb +5 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/unit/shared/attribute.rb +6 -155
- data/spec/unit/shared/attribute/accept_options.rb +55 -0
- data/spec/unit/shared/attribute/accepted_options.rb +11 -0
- data/spec/unit/shared/attribute/complex.rb +15 -0
- data/spec/unit/shared/attribute/get.rb +29 -0
- data/spec/unit/shared/attribute/options.rb +7 -0
- data/spec/unit/shared/attribute/set.rb +42 -0
- data/spec/unit/virtus/attribute/boolean_spec.rb +1 -2
- data/spec/unit/virtus/attribute/date_spec.rb +1 -2
- data/spec/unit/virtus/attribute/date_time_spec.rb +1 -2
- data/spec/unit/virtus/attribute/decimal_spec.rb +1 -2
- data/spec/unit/virtus/attribute/float_spec.rb +1 -2
- data/spec/unit/virtus/attribute/integer_spec.rb +1 -2
- data/spec/unit/virtus/attribute/numeric/class_methods/descendants_spec.rb +2 -2
- data/spec/unit/virtus/attribute/object/class_methods/descendants_spec.rb +6 -4
- data/spec/unit/virtus/attribute/string_spec.rb +1 -2
- data/spec/unit/virtus/attribute/time_spec.rb +1 -2
- data/spec/unit/virtus/attribute_set/append_spec.rb +35 -0
- data/spec/unit/virtus/attribute_set/each_spec.rb +60 -0
- data/spec/unit/virtus/attribute_set/element_reference_spec.rb +13 -0
- data/spec/unit/virtus/attribute_set/element_set_spec.rb +35 -0
- data/spec/unit/virtus/attribute_set/merge_spec.rb +36 -0
- data/spec/unit/virtus/attribute_set/parent_spec.rb +11 -0
- data/spec/unit/virtus/attribute_set/reset_spec.rb +60 -0
- data/spec/unit/virtus/class_methods/attribute_spec.rb +11 -0
- data/spec/unit/virtus/descendants_tracker/descendants_spec.rb +22 -0
- data/spec/unit/virtus/descendants_tracker/inherited_spec.rb +24 -0
- data/spec/unit/virtus/determine_type_spec.rb +21 -9
- data/spec/unit/virtus/instance_methods/{attribute_get_spec.rb → element_reference_spec.rb} +4 -2
- data/spec/unit/virtus/instance_methods/{attribute_set_spec.rb → element_set_spec.rb} +5 -7
- data/virtus.gemspec +35 -13
- metadata +96 -14
- data/lib/virtus/support/chainable.rb +0 -13
@@ -1,9 +1,11 @@
|
|
1
1
|
module Virtus
|
2
|
+
|
2
3
|
# Instance methods that are added when you include Virtus
|
3
4
|
module InstanceMethods
|
5
|
+
|
4
6
|
# Set attributes during initialization of an object
|
5
7
|
#
|
6
|
-
# @param [
|
8
|
+
# @param [#to_hash] attributes
|
7
9
|
# the attributes hash to be set
|
8
10
|
#
|
9
11
|
# @return [Object]
|
@@ -23,7 +25,7 @@ module Virtus
|
|
23
25
|
# end
|
24
26
|
#
|
25
27
|
# user = User.new(:name => 'John')
|
26
|
-
# user
|
28
|
+
# user[:name] # => "john"
|
27
29
|
#
|
28
30
|
# @param [Symbol] name
|
29
31
|
# a name of an attribute
|
@@ -32,8 +34,8 @@ module Virtus
|
|
32
34
|
# a value of an attribute
|
33
35
|
#
|
34
36
|
# @api public
|
35
|
-
def
|
36
|
-
|
37
|
+
def [](name)
|
38
|
+
attribute_get(name)
|
37
39
|
end
|
38
40
|
|
39
41
|
# Sets a value of the attribute with the given name
|
@@ -46,7 +48,7 @@ module Virtus
|
|
46
48
|
# end
|
47
49
|
#
|
48
50
|
# user = User.new
|
49
|
-
# user
|
51
|
+
# user[:name] = "john" # => "john"
|
50
52
|
# user.name # => "john"
|
51
53
|
#
|
52
54
|
# @param [Symbol] name
|
@@ -59,11 +61,11 @@ module Virtus
|
|
59
61
|
# the value set on an object
|
60
62
|
#
|
61
63
|
# @api public
|
62
|
-
def
|
63
|
-
|
64
|
+
def []=(name, value)
|
65
|
+
attribute_set(name, value)
|
64
66
|
end
|
65
67
|
|
66
|
-
#
|
68
|
+
# Returns a hash of all publicly accessible attributes
|
67
69
|
#
|
68
70
|
# @example
|
69
71
|
# class User
|
@@ -73,23 +75,25 @@ module Virtus
|
|
73
75
|
# attribute :age, Integer
|
74
76
|
# end
|
75
77
|
#
|
76
|
-
# user = User.new
|
77
|
-
# user.attributes
|
78
|
-
#
|
79
|
-
# @param [Hash] attributes
|
80
|
-
# a hash of attribute values to be set on an object
|
78
|
+
# user = User.new(:name => 'John', :age => 28)
|
79
|
+
# user.attributes # => { :name => 'John', :age => 28 }
|
81
80
|
#
|
82
81
|
# @return [Hash]
|
83
82
|
# the attributes
|
84
83
|
#
|
85
84
|
# @api public
|
86
|
-
def attributes
|
87
|
-
attributes
|
88
|
-
|
85
|
+
def attributes
|
86
|
+
attributes = {}
|
87
|
+
|
88
|
+
self.class.attributes.each do |attribute|
|
89
|
+
name = attribute.name
|
90
|
+
attributes[name] = attribute_get(name) if respond_to?(name)
|
89
91
|
end
|
92
|
+
|
93
|
+
attributes
|
90
94
|
end
|
91
95
|
|
92
|
-
#
|
96
|
+
# Mass-assign of attribute values
|
93
97
|
#
|
94
98
|
# @example
|
95
99
|
# class User
|
@@ -99,21 +103,41 @@ module Virtus
|
|
99
103
|
# attribute :age, Integer
|
100
104
|
# end
|
101
105
|
#
|
102
|
-
# user = User.new
|
103
|
-
# user.attributes
|
106
|
+
# user = User.new
|
107
|
+
# user.attributes = { :name => 'John', :age => 28 }
|
108
|
+
#
|
109
|
+
# @param [#to_hash] attributes
|
110
|
+
# a hash of attribute values to be set on an object
|
104
111
|
#
|
105
112
|
# @return [Hash]
|
106
113
|
# the attributes
|
107
114
|
#
|
108
115
|
# @api public
|
109
|
-
def attributes
|
110
|
-
attributes
|
111
|
-
|
112
|
-
self.class.attributes.each_key do |name|
|
113
|
-
attributes[name] = attribute_get(name) if respond_to?(name)
|
116
|
+
def attributes=(attributes)
|
117
|
+
attributes.to_hash.each do |name, value|
|
118
|
+
attribute_set(name, value) if respond_to?("#{name}=")
|
114
119
|
end
|
120
|
+
end
|
115
121
|
|
116
|
-
|
122
|
+
private
|
123
|
+
|
124
|
+
# Returns a value of the attribute with the given name
|
125
|
+
#
|
126
|
+
# @see Virtus::InstanceMethods#[]
|
127
|
+
#
|
128
|
+
# @api private
|
129
|
+
def attribute_get(name)
|
130
|
+
__send__(name)
|
117
131
|
end
|
118
|
-
|
119
|
-
|
132
|
+
|
133
|
+
# Sets a value of the attribute with the given name
|
134
|
+
#
|
135
|
+
# @see Virtus::InstanceMethods#[]=
|
136
|
+
#
|
137
|
+
# @api private
|
138
|
+
def attribute_set(name, value)
|
139
|
+
__send__("#{name}=", value)
|
140
|
+
end
|
141
|
+
|
142
|
+
end # module InstanceMethods
|
143
|
+
end # module Virtus
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Virtus
|
2
|
+
|
3
|
+
# A module that adds descendant tracking to a class
|
4
|
+
module DescendantsTracker
|
5
|
+
|
6
|
+
# Hook called when class is inherited
|
7
|
+
#
|
8
|
+
# @param [Class] descendant
|
9
|
+
#
|
10
|
+
# @return [self]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
def inherited(descendant)
|
14
|
+
superclass = self.superclass
|
15
|
+
superclass.inherited(descendant) if superclass.respond_to?(:descendants)
|
16
|
+
descendants.unshift(descendant)
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return the descendants of this class
|
21
|
+
#
|
22
|
+
# @return [Array<Class>]
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
def descendants
|
26
|
+
@descendants ||= []
|
27
|
+
end
|
28
|
+
|
29
|
+
end # module DescendantsTracker
|
30
|
+
end # module Virtus
|
@@ -1,12 +1,13 @@
|
|
1
1
|
module Virtus
|
2
2
|
module Typecast
|
3
|
+
|
3
4
|
# Typecast defined values into true or false.
|
4
5
|
# See TRUE_VALUES and FALSE_VALUES constants for a reference.
|
5
6
|
class Boolean
|
7
|
+
|
6
8
|
TRUE_VALUES = [ 1, '1', 't', 'T', 'true', 'TRUE' ].freeze
|
7
9
|
FALSE_VALUES = [ 0, '0', 'f', 'F', 'false', 'FALSE' ].freeze
|
8
|
-
|
9
|
-
BOOLEAN_MAP = Hash[TRUE_VALUES.product([ true ]) + FALSE_VALUES.product([ false ]) ].freeze
|
10
|
+
BOOLEAN_MAP = Hash[ TRUE_VALUES.product([ true ]) + FALSE_VALUES.product([ false ]) ].freeze
|
10
11
|
|
11
12
|
# Typecast value to TrueClass or FalseClass
|
12
13
|
#
|
@@ -22,6 +23,7 @@ module Virtus
|
|
22
23
|
def self.call(value)
|
23
24
|
BOOLEAN_MAP.fetch(value, value)
|
24
25
|
end
|
25
|
-
|
26
|
-
|
27
|
-
end #
|
26
|
+
|
27
|
+
end # class Boolean
|
28
|
+
end # module Typecast
|
29
|
+
end # module Virtus
|
@@ -1,14 +1,18 @@
|
|
1
1
|
module Virtus
|
2
2
|
module Typecast
|
3
|
+
|
3
4
|
# Typecast numeric values. Supports Integer, Float and BigDecimal
|
4
5
|
class Numeric
|
6
|
+
|
7
|
+
REGEXP = /\A(-?(?:0|[1-9]\d*)(?:\.\d+)?|(?:\.\d+))\z/.freeze
|
8
|
+
|
5
9
|
# Typecast value to integer
|
6
10
|
#
|
7
11
|
# @example
|
8
12
|
# Virtus::Typecast::Numeric.to_i('1') # => 1
|
9
13
|
# Virtus::Typecast::Numeric.to_i(1.2) # => 1
|
10
14
|
#
|
11
|
-
# @param [Object]
|
15
|
+
# @param [Object] value
|
12
16
|
#
|
13
17
|
# @return [Integer]
|
14
18
|
#
|
@@ -23,7 +27,7 @@ module Virtus
|
|
23
27
|
# Virtus::Typecast::Numeric.to_f('1.2') # => 1.2
|
24
28
|
# Virtus::Typecast::Numeric.to_f(1) # => 1.0
|
25
29
|
#
|
26
|
-
# @param [Object]
|
30
|
+
# @param [Object] value
|
27
31
|
#
|
28
32
|
# @return [Float]
|
29
33
|
#
|
@@ -38,7 +42,7 @@ module Virtus
|
|
38
42
|
# Virtus::Typecast::Numeric.to_d('1.2') # => #<BigDecimal:b72157d4,'0.12E1',8(8)>
|
39
43
|
# Virtus::Typecast::Numeric.to_d(1) # => #<BigDecimal:b7212e08,'0.1E1',4(8)>
|
40
44
|
#
|
41
|
-
# @param [Object]
|
45
|
+
# @param [Object] value
|
42
46
|
#
|
43
47
|
# @return [BigDecimal]
|
44
48
|
#
|
@@ -51,7 +55,7 @@ module Virtus
|
|
51
55
|
end
|
52
56
|
end
|
53
57
|
|
54
|
-
|
58
|
+
private
|
55
59
|
|
56
60
|
# Match numeric string
|
57
61
|
#
|
@@ -66,7 +70,7 @@ module Virtus
|
|
66
70
|
# @api private
|
67
71
|
def self.call(value, method)
|
68
72
|
if value.respond_to?(:to_str)
|
69
|
-
if value.to_str =~
|
73
|
+
if value.to_str =~ REGEXP
|
70
74
|
$1.send(method)
|
71
75
|
else
|
72
76
|
value
|
@@ -77,6 +81,7 @@ module Virtus
|
|
77
81
|
value
|
78
82
|
end
|
79
83
|
end
|
80
|
-
|
81
|
-
|
82
|
-
end #
|
84
|
+
|
85
|
+
end # class Numeric
|
86
|
+
end # module Typecast
|
87
|
+
end # module Virtus
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Virtus
|
2
|
+
module Typecast
|
3
|
+
|
4
|
+
# Typecast any object to a string
|
5
|
+
class String
|
6
|
+
|
7
|
+
# Typecast value to a string
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# Virtus::Typecast::String.call(1) # => '1'
|
11
|
+
# Virtus::Typecast::String.call([]) # => '[]'
|
12
|
+
#
|
13
|
+
# @param [Object] value
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
def self.call(value)
|
19
|
+
value.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
end # class String
|
23
|
+
end # module Typecast
|
24
|
+
end # module Virtus
|
data/lib/virtus/typecast/time.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module Virtus
|
2
2
|
module Typecast
|
3
|
+
|
3
4
|
# Typecast various values into Date, DateTime or Time
|
4
5
|
class Time
|
5
6
|
SEGMENTS = [ :year, :month, :day, :hour, :min, :sec ].freeze
|
@@ -67,14 +68,14 @@ module Virtus
|
|
67
68
|
call(value, :to_datetime)
|
68
69
|
end
|
69
70
|
|
70
|
-
|
71
|
+
private
|
71
72
|
|
72
73
|
# @api private
|
73
74
|
def self.call(value, method)
|
74
75
|
return value.send(method) if value.respond_to?(method)
|
75
76
|
|
76
77
|
begin
|
77
|
-
if value.
|
78
|
+
if value.kind_of?(::Hash)
|
78
79
|
from_hash(value, method)
|
79
80
|
else
|
80
81
|
from_string(value.to_s, method)
|
@@ -157,6 +158,7 @@ module Virtus
|
|
157
158
|
Numeric.to_i(value.fetch(segment, now.send(segment)))
|
158
159
|
end
|
159
160
|
end
|
160
|
-
|
161
|
-
|
162
|
-
end #
|
161
|
+
|
162
|
+
end # class Time
|
163
|
+
end # module Typecast
|
164
|
+
end # module Virtus
|
@@ -5,9 +5,9 @@ describe Virtus::ClassMethods, '.attribute' do
|
|
5
5
|
Class.new { include Virtus }
|
6
6
|
end
|
7
7
|
|
8
|
-
|
8
|
+
specify { described_class.should respond_to(:attribute) }
|
9
9
|
|
10
|
-
|
10
|
+
context "in the class" do
|
11
11
|
before do
|
12
12
|
described_class.attribute(:name, String)
|
13
13
|
described_class.attribute(:email, String, :accessor => :private)
|
@@ -20,11 +20,11 @@ describe Virtus::ClassMethods, '.attribute' do
|
|
20
20
|
let(:protected_instance_methods) { described_class.protected_instance_methods.map { |method| method.to_s } }
|
21
21
|
let(:private_instance_methods) { described_class.private_instance_methods.map { |method| method.to_s } }
|
22
22
|
|
23
|
-
it "
|
24
|
-
described_class.
|
23
|
+
it "returns self" do
|
24
|
+
described_class.attribute(:name, String).should be(described_class)
|
25
25
|
end
|
26
26
|
|
27
|
-
it "
|
27
|
+
it "creates an attribute of a correct type" do
|
28
28
|
described_class.attributes[:name].should be_instance_of(Virtus::Attribute::String)
|
29
29
|
end
|
30
30
|
|
@@ -60,4 +60,16 @@ describe Virtus::ClassMethods, '.attribute' do
|
|
60
60
|
protected_instance_methods.should include('bday=')
|
61
61
|
end
|
62
62
|
end
|
63
|
+
|
64
|
+
context "in the descendants" do
|
65
|
+
subject { described_class.attribute(:name, String).attributes[:name] }
|
66
|
+
|
67
|
+
let(:descendant) { Class.new(described_class) }
|
68
|
+
|
69
|
+
it 'updates the descendant attributes' do
|
70
|
+
descendant.attributes.to_a.should be_empty
|
71
|
+
@attribute = subject
|
72
|
+
descendant.attributes.to_a.should eql([ @attribute ])
|
73
|
+
end
|
74
|
+
end
|
63
75
|
end
|
@@ -15,11 +15,8 @@ describe Virtus::ClassMethods, '.attributes' do
|
|
15
15
|
|
16
16
|
subject { described_class.attributes }
|
17
17
|
|
18
|
-
it "returns
|
19
|
-
subject.should
|
20
|
-
:name => described_class.attributes[:name],
|
21
|
-
:age => described_class.attributes[:age]
|
22
|
-
)
|
18
|
+
it "returns a set of attributes" do
|
19
|
+
subject.should be_kind_of(Virtus::AttributeSet)
|
23
20
|
end
|
24
21
|
end
|
25
22
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -9,3 +9,18 @@ ENV['TZ'] = 'UTC'
|
|
9
9
|
SPEC_ROOT = Pathname(__FILE__).dirname.expand_path
|
10
10
|
|
11
11
|
Pathname.glob((SPEC_ROOT + '**/shared/**/*.rb').to_s).each { |file| require file }
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
|
15
|
+
# Remove anonymous Attribute classes from Attribute descendants
|
16
|
+
config.after :all do
|
17
|
+
stack = [ Virtus::Attribute ]
|
18
|
+
while klass = stack.pop
|
19
|
+
klass.descendants.delete_if do |descendant|
|
20
|
+
descendant.name.nil? || descendant.name.empty?
|
21
|
+
end
|
22
|
+
stack.concat(klass.descendants)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -1,157 +1,8 @@
|
|
1
|
-
# TODO: split this into separate files
|
2
|
-
|
3
1
|
shared_examples_for "Attribute" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
Object.send(:remove_const, :User) if Object.const_defined?(:User)
|
11
|
-
end
|
12
|
-
|
13
|
-
let(:sub_attribute) { class SubAttribute < described_class; end; SubAttribute }
|
14
|
-
|
15
|
-
let(:model) do
|
16
|
-
Class.new { include Virtus }
|
17
|
-
end
|
18
|
-
|
19
|
-
describe ".options" do
|
20
|
-
subject { described_class.options }
|
21
|
-
it { should be_instance_of(Hash) }
|
22
|
-
end
|
23
|
-
|
24
|
-
describe ".accepted_options" do
|
25
|
-
it "returns an array of accepted options" do
|
26
|
-
described_class.accepted_options.should be_instance_of(Array)
|
27
|
-
end
|
28
|
-
|
29
|
-
it "accepts base options" do
|
30
|
-
described_class.accepted_options.should include(*Virtus::Attribute::OPTIONS)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
describe ".accept_options" do
|
35
|
-
let(:new_option) { :width }
|
36
|
-
|
37
|
-
before :all do
|
38
|
-
described_class.accepted_options.should_not include(new_option)
|
39
|
-
described_class.accept_options(new_option)
|
40
|
-
end
|
41
|
-
|
42
|
-
it "sets new accepted options on itself" do
|
43
|
-
described_class.accepted_options.should include(new_option)
|
44
|
-
end
|
45
|
-
|
46
|
-
it "sets new accepted option on its descendants" do
|
47
|
-
sub_attribute.accepted_options.should include(new_option)
|
48
|
-
end
|
49
|
-
|
50
|
-
it "creates option accessors" do
|
51
|
-
described_class.should respond_to(new_option)
|
52
|
-
end
|
53
|
-
|
54
|
-
it "creates option accessors on descendants" do
|
55
|
-
sub_attribute.should respond_to(new_option)
|
56
|
-
end
|
57
|
-
|
58
|
-
context 'with default option value' do
|
59
|
-
let(:option) { :height }
|
60
|
-
let(:value) { 10 }
|
61
|
-
|
62
|
-
before :all do
|
63
|
-
sub_attribute.accept_options(option)
|
64
|
-
sub_attribute.height(value)
|
65
|
-
end
|
66
|
-
|
67
|
-
context "when new attribute is created" do
|
68
|
-
subject { sub_attribute.new(attribute_name) }
|
69
|
-
|
70
|
-
it "sets the default value" do
|
71
|
-
subject.options[option].should eql(value)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
context "when new attribute is created and overrides option's default value" do
|
76
|
-
let(:new_value) { 11 }
|
77
|
-
|
78
|
-
subject { sub_attribute.new(attribute_name, option => new_value) }
|
79
|
-
|
80
|
-
it "sets the new value" do
|
81
|
-
subject.options[option].should eql(new_value)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
describe "#set" do
|
88
|
-
let(:attribute) { model.attribute(attribute_name, described_class) }
|
89
|
-
let(:object) { model.new }
|
90
|
-
|
91
|
-
context "with nil" do
|
92
|
-
subject { attribute.set(object, nil) }
|
93
|
-
|
94
|
-
it "doesn't set the ivar" do
|
95
|
-
subject
|
96
|
-
object.instance_variable_defined?(attribute.instance_variable_name).should be(false)
|
97
|
-
end
|
98
|
-
|
99
|
-
it "returns nil" do
|
100
|
-
subject.should be(nil)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
context "with a primitive value" do
|
105
|
-
before { attribute.set(object, attribute_value) }
|
106
|
-
|
107
|
-
it "sets the value in an ivar" do
|
108
|
-
object.instance_variable_get(attribute.instance_variable_name).should eql(attribute_value)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
context "with a non-primitive value" do
|
113
|
-
before { attribute.set(object, attribute_value_other) }
|
114
|
-
|
115
|
-
it "sets the value in an ivar converted to the primitive type" do
|
116
|
-
object.instance_variable_get(attribute.instance_variable_name).should be_kind_of(described_class.primitive)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
describe "#get" do
|
122
|
-
let(:attribute) { model.attribute(attribute_name, described_class) }
|
123
|
-
let(:object) { model.new }
|
124
|
-
|
125
|
-
context "when a non-nil value is set" do
|
126
|
-
before { attribute.set(object, attribute_value) }
|
127
|
-
|
128
|
-
subject { attribute.get(object) }
|
129
|
-
|
130
|
-
it { should eql(attribute_value) }
|
131
|
-
end
|
132
|
-
|
133
|
-
context "when nil is set" do
|
134
|
-
before { attribute.set(object, nil) }
|
135
|
-
|
136
|
-
subject { attribute.get(object) }
|
137
|
-
|
138
|
-
it { should be(nil) }
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
describe "#complex?" do
|
143
|
-
let(:attribute) { model.attribute(attribute_name, described_class, :complex => complex) }
|
144
|
-
|
145
|
-
subject { attribute.complex? }
|
146
|
-
|
147
|
-
context "when set to true" do
|
148
|
-
let(:complex) { true }
|
149
|
-
it { should be(true) }
|
150
|
-
end
|
151
|
-
|
152
|
-
context "when set to false" do
|
153
|
-
let(:complex) { false }
|
154
|
-
it { should be(false) }
|
155
|
-
end
|
156
|
-
end
|
2
|
+
it_behaves_like 'Attribute.options'
|
3
|
+
it_behaves_like 'Attribute.accept_options'
|
4
|
+
it_behaves_like 'Attribute.accepted_options'
|
5
|
+
it_behaves_like 'Attribute#set'
|
6
|
+
it_behaves_like 'Attribute#get'
|
7
|
+
it_behaves_like 'Attribute#complex?'
|
157
8
|
end
|