active_data 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/.travis.yml +1 -1
- data/Gemfile +5 -7
- data/Guardfile +8 -3
- data/active_data.gemspec +2 -2
- data/lib/active_data/attributes/base.rb +10 -5
- data/lib/active_data/attributes/localized.rb +1 -1
- data/lib/active_data/model/associations/{many.rb → association.rb} +9 -3
- data/lib/active_data/model/associations/embeds_many.rb +33 -0
- data/lib/active_data/model/associations/embeds_one.rb +30 -0
- data/lib/active_data/model/associations.rb +19 -22
- data/lib/active_data/model/attributable.rb +35 -29
- data/lib/active_data/model/collectionizable.rb +13 -12
- data/lib/active_data/model/extensions/array.rb +3 -3
- data/lib/active_data/model/extensions/big_decimal.rb +2 -2
- data/lib/active_data/model/extensions/date.rb +1 -8
- data/lib/active_data/model/extensions/date_time.rb +17 -0
- data/lib/active_data/model/extensions/float.rb +1 -1
- data/lib/active_data/model/extensions/hash.rb +1 -1
- data/lib/active_data/model/extensions/integer.rb +1 -1
- data/lib/active_data/model/extensions/localized.rb +2 -2
- data/lib/active_data/model/extensions/object.rb +17 -0
- data/lib/active_data/model/extensions/time.rb +17 -0
- data/lib/active_data/model/localizable.rb +3 -3
- data/lib/active_data/model/nested_attributes.rb +10 -4
- data/lib/active_data/model.rb +17 -11
- data/lib/active_data/validations/associated.rb +17 -0
- data/lib/active_data/validations.rb +7 -0
- data/lib/active_data/version.rb +1 -1
- data/lib/active_data.rb +1 -1
- data/spec/lib/active_data/model/associations/embeds_many_spec.rb +93 -0
- data/spec/lib/active_data/model/associations/embeds_one_spec.rb +57 -0
- data/spec/lib/active_data/model/attributable_spec.rb +118 -2
- data/spec/lib/active_data/model/attributes/localized_spec.rb +1 -0
- data/spec/lib/active_data/model/collectionizable_spec.rb +41 -15
- data/spec/lib/active_data/model/nested_attributes_spec.rb +47 -26
- data/spec/lib/active_data/model/type_cast_spec.rb +31 -3
- data/spec/lib/active_data/model_spec.rb +26 -7
- data/spec/lib/active_data/validations/associated_spec.rb +88 -0
- metadata +27 -16
- data/spec/lib/active_data/model/associations_spec.rb +0 -35
data/lib/active_data/model.rb
CHANGED
@@ -18,12 +18,9 @@ module ActiveData
|
|
18
18
|
|
19
19
|
included do
|
20
20
|
include ActiveModel::Conversion
|
21
|
-
include ActiveModel::Dirty
|
22
21
|
include ActiveModel::Validations
|
23
|
-
include ActiveModel::MassAssignmentSecurity
|
24
22
|
include ActiveModel::Serialization
|
25
23
|
include ActiveModel::Serializers::JSON
|
26
|
-
include ActiveModel::Serializers::Xml
|
27
24
|
|
28
25
|
include Attributable
|
29
26
|
include Localizable
|
@@ -31,7 +28,6 @@ module ActiveData
|
|
31
28
|
include Associations
|
32
29
|
include NestedAttributes
|
33
30
|
include Parameterizable
|
34
|
-
extend ActiveModel::Callbacks
|
35
31
|
extend ActiveModel::Naming
|
36
32
|
extend ActiveModel::Translation
|
37
33
|
|
@@ -46,17 +42,28 @@ module ActiveData
|
|
46
42
|
def self.i18n_scope
|
47
43
|
:active_data
|
48
44
|
end
|
45
|
+
|
46
|
+
def serializable_hash *args
|
47
|
+
super(*args).stringify_keys!
|
48
|
+
end
|
49
49
|
end
|
50
50
|
|
51
51
|
module ClassMethods
|
52
|
-
def instantiate
|
53
|
-
return
|
52
|
+
def instantiate data
|
53
|
+
return data if data.class.include? ActiveData::Model
|
54
54
|
|
55
|
+
data = data.symbolize_keys
|
55
56
|
instance = allocate
|
56
57
|
|
57
|
-
|
58
|
+
attributes = initialize_attributes
|
59
|
+
attributes.merge!(data.slice(*attributes.keys))
|
60
|
+
|
61
|
+
data.slice(*association_names.map(&:to_sym)).each do |association, data|
|
62
|
+
instance.send(:"#{association}=", data)
|
63
|
+
end
|
64
|
+
|
65
|
+
instance.instance_variable_set(:@attributes, attributes)
|
58
66
|
instance.instance_variable_set(:@new_record, false)
|
59
|
-
instance.attributes = attributes
|
60
67
|
|
61
68
|
instance
|
62
69
|
end
|
@@ -74,9 +81,8 @@ module ActiveData
|
|
74
81
|
other.instance_of?(self.class) && other.attributes == attributes
|
75
82
|
end
|
76
83
|
|
77
|
-
def
|
78
|
-
|
84
|
+
def inspect
|
85
|
+
"#<#{self.class} #{attributes.map { |name, value| "#{name}: #{value.inspect}" }.join(' ')}>"
|
79
86
|
end
|
80
|
-
|
81
87
|
end
|
82
88
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveData
|
2
|
+
module Validations
|
3
|
+
class AssociatedValidator < ActiveModel::EachValidator #:nodoc:
|
4
|
+
def validate_each(record, attribute, value)
|
5
|
+
if Array.wrap(value).reject { |r| r.respond_to?(:valid?) && r.valid?(record.validation_context) }.any?
|
6
|
+
record.errors.add(attribute, :invalid, options.merge(:value => value))
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def validates_associated(*attr_names)
|
13
|
+
validates_with AssociatedValidator, _merge_attributes(attr_names)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/active_data/version.rb
CHANGED
data/lib/active_data.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'active_support/concern'
|
2
2
|
require 'active_support/core_ext'
|
3
|
-
require 'active_support/hash_with_indifferent_access'
|
4
3
|
require 'active_model'
|
5
4
|
require 'active_data/version'
|
6
5
|
require 'active_data/model'
|
6
|
+
require 'active_data/validations'
|
7
7
|
|
8
8
|
module ActiveData
|
9
9
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe ActiveData::Model::Associations::EmbedsMany do
|
5
|
+
|
6
|
+
class ManyAssoc
|
7
|
+
include ActiveData::Model
|
8
|
+
|
9
|
+
attribute :name
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:noassoc) do
|
13
|
+
Class.new do
|
14
|
+
include ActiveData::Model
|
15
|
+
|
16
|
+
attribute :name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:klass) do
|
21
|
+
Class.new(noassoc) do
|
22
|
+
embeds_many :many_assocs
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:inherited1) do
|
27
|
+
Class.new(klass) do
|
28
|
+
embeds_many :many_assocs_inherited1, class_name: ManyAssoc
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:inherited2) do
|
33
|
+
Class.new(noassoc) do
|
34
|
+
embeds_many :many_assocs_inherited2, class_name: ManyAssoc
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
subject { klass.new(name: 'world') }
|
39
|
+
|
40
|
+
context do
|
41
|
+
specify { subject.many_assocs.should be_empty }
|
42
|
+
specify { subject.many_assocs.should be_instance_of ManyAssoc.collection_class }
|
43
|
+
specify { subject.many_assocs.count.should == 0 }
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'accessor with objects' do
|
47
|
+
before { subject.many_assocs = [ManyAssoc.new(name: 'foo'), ManyAssoc.new(name: 'bar')] }
|
48
|
+
specify { subject.many_assocs.count.should == 2 }
|
49
|
+
specify { subject.many_assocs[0].name.should == 'foo' }
|
50
|
+
specify { subject.many_assocs[1].name.should == 'bar' }
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'accessor with attributes' do
|
54
|
+
before { subject.many_assocs = [{ name: 'foo' }, { name: 'bar' }] }
|
55
|
+
specify { subject.many_assocs.count.should == 2 }
|
56
|
+
specify { subject.many_assocs[0].name.should == 'foo' }
|
57
|
+
specify { subject.many_assocs[1].name.should == 'bar' }
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'inheritance' do
|
61
|
+
specify { noassoc.association_names.should == [] }
|
62
|
+
specify { klass.association_names.should == %w(many_assocs) }
|
63
|
+
specify { inherited1.association_names.should == %w(many_assocs many_assocs_inherited1) }
|
64
|
+
specify { inherited2.association_names.should == %w(many_assocs_inherited2) }
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#instantiate' do
|
68
|
+
subject { klass.instantiate name: 'Root', many_assocs: [{ name: 'foo' }, { name: 'bar' }] }
|
69
|
+
|
70
|
+
its('many_assocs.count') { should == 2 }
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#==' do
|
74
|
+
let(:instance) { klass.new(name: 'world') }
|
75
|
+
before { subject.many_assocs = [ManyAssoc.new(name: 'foo'), ManyAssoc.new(name: 'bar')] }
|
76
|
+
specify { subject.should_not == instance }
|
77
|
+
|
78
|
+
context do
|
79
|
+
before { instance.many_assocs = [ManyAssoc.new(name: 'foo')] }
|
80
|
+
specify { subject.should_not == instance }
|
81
|
+
end
|
82
|
+
|
83
|
+
context do
|
84
|
+
before { instance.many_assocs = [ManyAssoc.new(name: 'foo1'), ManyAssoc.new(name: 'bar')] }
|
85
|
+
specify { subject.should_not == instance }
|
86
|
+
end
|
87
|
+
|
88
|
+
context do
|
89
|
+
before { instance.many_assocs = [ManyAssoc.new(name: 'foo'), ManyAssoc.new(name: 'bar')] }
|
90
|
+
specify { subject.should == instance }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe ActiveData::Model::Associations::EmbedsMany do
|
5
|
+
|
6
|
+
class OneAssoc
|
7
|
+
include ActiveData::Model
|
8
|
+
|
9
|
+
attribute :name
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:klass) do
|
13
|
+
Class.new do
|
14
|
+
include ActiveData::Model
|
15
|
+
|
16
|
+
attribute :name
|
17
|
+
embeds_one :one_assoc
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
subject { klass.new(name: 'world') }
|
22
|
+
|
23
|
+
its(:one_assoc) { should be_nil }
|
24
|
+
|
25
|
+
context 'accessor with objects' do
|
26
|
+
before { subject.one_assoc = OneAssoc.new(name: 'foo') }
|
27
|
+
specify { subject.one_assoc.should be_instance_of OneAssoc }
|
28
|
+
specify { subject.one_assoc.name.should == 'foo' }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'accessor with attributes' do
|
32
|
+
before { subject.one_assoc = { name: 'foo' } }
|
33
|
+
specify { subject.one_assoc.should be_instance_of OneAssoc }
|
34
|
+
specify { subject.one_assoc.name.should == 'foo' }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'accessor with nothing' do
|
38
|
+
before { subject.one_assoc = nil }
|
39
|
+
specify { subject.one_assoc.should be_nil }
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#==' do
|
43
|
+
let(:instance) { klass.new(name: 'world') }
|
44
|
+
before { subject.one_assoc = { name: 'foo' } }
|
45
|
+
specify { subject.should_not == instance }
|
46
|
+
|
47
|
+
context do
|
48
|
+
before { instance.one_assoc = { name: 'foo1' } }
|
49
|
+
specify { subject.should_not == instance }
|
50
|
+
end
|
51
|
+
|
52
|
+
context do
|
53
|
+
before { instance.one_assoc = { name: 'foo' } }
|
54
|
+
specify { subject.should == instance }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -9,6 +9,7 @@ describe ActiveData::Model::Attributable do
|
|
9
9
|
attr_reader :name
|
10
10
|
|
11
11
|
attribute :hello
|
12
|
+
attribute :string, type: String, default_blank: true, default: ->(record){ record.name }
|
12
13
|
attribute :count, type: Integer, default: 10
|
13
14
|
attribute(:calc, type: Integer) { 2 + 3 }
|
14
15
|
attribute :enum, type: Integer, in: [1, 2, 3]
|
@@ -23,8 +24,8 @@ describe ActiveData::Model::Attributable do
|
|
23
24
|
context do
|
24
25
|
subject { klass.new('world') }
|
25
26
|
specify { klass.enum_values == [1, 2, 3] }
|
26
|
-
its(:attributes) { should == {
|
27
|
-
its(:present_attributes) { should == {
|
27
|
+
its(:attributes) { should == { hello: nil, count: 10, calc: 5, enum: nil, string: 'world' } }
|
28
|
+
its(:present_attributes) { should == { count: 10, calc: 5, string: 'world' } }
|
28
29
|
its(:name) { should == 'world' }
|
29
30
|
its(:hello) { should be_nil }
|
30
31
|
its(:count) { should == 10 }
|
@@ -34,4 +35,119 @@ describe ActiveData::Model::Attributable do
|
|
34
35
|
specify { expect { subject.calc = 15 } .to change { subject.calc } .from(5).to(15) }
|
35
36
|
end
|
36
37
|
|
38
|
+
context 'calculating default values' do
|
39
|
+
let(:klass) do
|
40
|
+
Class.new do
|
41
|
+
include ActiveData::Model::Attributable
|
42
|
+
|
43
|
+
attribute(:rand, type: String) { SecureRandom.uuid }
|
44
|
+
|
45
|
+
def initialize
|
46
|
+
@attributes = self.class.initialize_attributes
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
subject { klass.new }
|
52
|
+
specify { subject.rand.should == subject.rand }
|
53
|
+
specify { subject.rand.should_not == klass.new.rand }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'default_blank' do
|
57
|
+
let(:klass) do
|
58
|
+
Class.new do
|
59
|
+
include ActiveData::Model::Attributable
|
60
|
+
|
61
|
+
attribute :string1, type: String, default_blank: true, default: 'default'
|
62
|
+
attribute :string2, type: String, default: 'default'
|
63
|
+
|
64
|
+
def initialize attributes = {}
|
65
|
+
@attributes = self.class.initialize_attributes
|
66
|
+
self.attributes = attributes
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
specify { klass.new.string1.should == 'default' }
|
72
|
+
specify { klass.new.string2.should == 'default' }
|
73
|
+
specify { klass.new(string1: '').string1.should == 'default' }
|
74
|
+
specify { klass.new(string2: '').string2.should == '' }
|
75
|
+
specify { klass.new(string1: 'hello').string1.should == 'hello' }
|
76
|
+
specify { klass.new(string2: 'hello').string2.should == 'hello' }
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'attribute caching' do
|
80
|
+
subject { klass.new('world') }
|
81
|
+
|
82
|
+
context do
|
83
|
+
before do
|
84
|
+
subject.send(:attributes_cache).should_not_receive(:[])
|
85
|
+
end
|
86
|
+
|
87
|
+
specify { subject.hello }
|
88
|
+
end
|
89
|
+
|
90
|
+
context do
|
91
|
+
before do
|
92
|
+
subject.hello
|
93
|
+
subject.send(:attributes_cache).should_receive(:[]).with(:hello).once
|
94
|
+
end
|
95
|
+
|
96
|
+
specify { subject.hello }
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'attribute cache reset' do
|
100
|
+
before do
|
101
|
+
subject.hello = 'blabla'
|
102
|
+
subject.hello
|
103
|
+
subject.hello = 'newnewnew'
|
104
|
+
end
|
105
|
+
|
106
|
+
specify { subject.hello.should == 'newnewnew' }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'inheritance' do
|
111
|
+
let!(:ancestor) do
|
112
|
+
Class.new do
|
113
|
+
include ActiveData::Model::Attributable
|
114
|
+
attribute :foo
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
let!(:descendant1) do
|
119
|
+
Class.new ancestor do
|
120
|
+
attribute :bar
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
let!(:descendant2) do
|
125
|
+
Class.new ancestor do
|
126
|
+
attribute :baz
|
127
|
+
attribute :moo
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
specify { ancestor._attributes.keys.should == [:foo] }
|
132
|
+
specify { ancestor.instance_methods.should include :foo, :foo= }
|
133
|
+
specify { ancestor.instance_methods.should_not include :bar, :bar=, :baz, :baz= }
|
134
|
+
specify { descendant1._attributes.keys.should == [:foo, :bar] }
|
135
|
+
specify { descendant1.instance_methods.should include :foo, :foo=, :bar, :bar= }
|
136
|
+
specify { descendant1.instance_methods.should_not include :baz, :baz= }
|
137
|
+
specify { descendant2._attributes.keys.should == [:foo, :baz, :moo] }
|
138
|
+
specify { descendant2.instance_methods.should include :foo, :foo=, :baz, :baz=, :moo, :moo= }
|
139
|
+
specify { descendant2.instance_methods.should_not include :bar, :bar= }
|
140
|
+
end
|
141
|
+
|
142
|
+
context '#write_attributes' do
|
143
|
+
subject { klass.new('world') }
|
144
|
+
|
145
|
+
specify { expect { subject.write_attributes(strange: 'value') }.to raise_error NoMethodError }
|
146
|
+
|
147
|
+
context do
|
148
|
+
before { subject.write_attributes('hello' => 'blabla', count: 20) }
|
149
|
+
specify { subject.attributes.should == { hello: 'blabla', count: 20, calc: 5, enum: nil, string: 'world' } }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
37
153
|
end
|
@@ -13,22 +13,48 @@ describe ActiveData::Model::Collectionizable do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.no_mars
|
16
|
-
delete_if{|i| i.name == 'Mars'}
|
16
|
+
delete_if { |i| i.name == 'Mars' }
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
specify{
|
28
|
-
specify{
|
29
|
-
specify{
|
30
|
-
specify{
|
31
|
-
|
32
|
-
specify{collection.
|
33
|
-
specify{collection.
|
20
|
+
|
21
|
+
class CollectionizableTest
|
22
|
+
include ActiveData::Model
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:collection) { klass.collection([{ name: 'Hello' }, { name: 'World' }, { name: 'Mars' }]) }
|
26
|
+
|
27
|
+
specify { klass.collection_class.should_not be_nil }
|
28
|
+
specify { klass.collection_class.collectible.should == klass }
|
29
|
+
specify { klass.collection_class.new.should be_empty }
|
30
|
+
specify { CollectionizableTest.collection_class.should < Array }
|
31
|
+
|
32
|
+
specify { collection.should be_instance_of klass.collection_class }
|
33
|
+
specify { collection.except_first.should be_instance_of klass.collection_class }
|
34
|
+
specify { collection.no_mars.should be_instance_of klass.collection_class }
|
35
|
+
specify { collection.except_first.should == klass.collection([{ name: 'World' }, { name: 'Mars' }]) }
|
36
|
+
specify { collection.no_mars.should == klass.collection([{ name: 'Hello' }, { name: 'World' }]) }
|
37
|
+
specify { collection.except_first.no_mars.should == klass.collection([{ name: 'World' }]) }
|
38
|
+
specify { collection.no_mars.except_first.should == klass.collection([{ name: 'World' }]) }
|
39
|
+
|
40
|
+
context do
|
41
|
+
let!(:ancestor) do
|
42
|
+
Class.new do
|
43
|
+
include ActiveData::Model
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
let!(:descendant1) do
|
48
|
+
Class.new ancestor
|
49
|
+
end
|
50
|
+
|
51
|
+
let!(:descendant2) do
|
52
|
+
Class.new ancestor
|
53
|
+
end
|
54
|
+
|
55
|
+
specify { descendant1.collection_class.should < Array }
|
56
|
+
specify { descendant2.collection_class.should < Array }
|
57
|
+
specify { ancestor.collection_class.should_not == descendant1.collection_class }
|
58
|
+
specify { descendant1.collection_class.should_not == descendant2.collection_class }
|
59
|
+
end
|
34
60
|
end
|
@@ -3,44 +3,65 @@ require 'spec_helper'
|
|
3
3
|
|
4
4
|
describe ActiveData::Model::Associations do
|
5
5
|
|
6
|
-
class
|
6
|
+
class NestedAssoc
|
7
7
|
include ActiveData::Model
|
8
8
|
|
9
9
|
attribute :name
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
context do
|
13
|
+
let(:klass) do
|
14
|
+
Class.new do
|
15
|
+
include ActiveData::Model
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
attribute :name
|
18
|
+
embeds_one :assoc, class_name: NestedAssoc
|
18
19
|
|
19
|
-
|
20
|
+
accepts_nested_attributes_for :assoc
|
21
|
+
end
|
20
22
|
end
|
21
|
-
|
23
|
+
let(:instance) { klass.new( name: 'world') }
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
specify { instance.assocs.first.name.should == 'foo' }
|
29
|
-
specify { instance.assocs.last.name.should == 'bar' }
|
25
|
+
context do
|
26
|
+
before { instance.assoc_attributes = { name: 'foo'} }
|
27
|
+
specify { instance.assoc.should be_instance_of NestedAssoc }
|
28
|
+
specify { instance.assoc.name.should == 'foo' }
|
29
|
+
end
|
30
30
|
end
|
31
31
|
|
32
32
|
context do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
specify { instance.assocs.last.name.should == 'foo' }
|
37
|
-
end
|
33
|
+
let(:klass) do
|
34
|
+
Class.new do
|
35
|
+
include ActiveData::Model
|
38
36
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
37
|
+
attribute :name
|
38
|
+
embeds_many :assocs, class_name: NestedAssoc
|
39
|
+
|
40
|
+
accepts_nested_attributes_for :assocs
|
41
|
+
end
|
42
|
+
end
|
43
|
+
let(:instance) { klass.new(name: 'world') }
|
44
|
+
|
45
|
+
context do
|
46
|
+
before { instance.assocs_attributes = [{ name: 'foo' }, { name: 'bar' }] }
|
47
|
+
specify { instance.assocs.count.should == 2 }
|
48
|
+
specify { instance.assocs.first.name.should == 'foo' }
|
49
|
+
specify { instance.assocs.last.name.should == 'bar' }
|
50
|
+
end
|
51
|
+
|
52
|
+
context do
|
53
|
+
before { instance.assocs_attributes = {1 => { name: 'baz' }, 2 => { name: 'foo' }} }
|
54
|
+
specify { instance.assocs.count.should == 2 }
|
55
|
+
specify { instance.assocs.first.name.should == 'baz' }
|
56
|
+
specify { instance.assocs.last.name.should == 'foo' }
|
57
|
+
end
|
58
|
+
|
59
|
+
context do
|
60
|
+
before { instance.assocs_attributes = {1 => { name: 'baz' }, 2 => { name: 'foo' }} }
|
61
|
+
specify { instance.to_params.should == {
|
62
|
+
"name" => "world",
|
63
|
+
"assocs_attributes" => {'0' => {"name" => "baz"}, '1' => {"name" => "foo"}}
|
64
|
+
} }
|
65
|
+
end
|
45
66
|
end
|
46
67
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
4
|
describe 'typecasting' do
|
5
|
-
|
6
5
|
let(:klass) do
|
7
6
|
Class.new do
|
8
7
|
include ActiveData::Model::Attributable
|
@@ -14,6 +13,9 @@ describe 'typecasting' do
|
|
14
13
|
attribute :big_decimal, type: BigDecimal
|
15
14
|
attribute :boolean, type: Boolean
|
16
15
|
attribute :array, type: Array
|
16
|
+
attribute :date, type: Date
|
17
|
+
attribute :datetime, type: DateTime
|
18
|
+
attribute :time, type: Time
|
17
19
|
|
18
20
|
def initialize name = nil
|
19
21
|
@attributes = self.class.initialize_attributes
|
@@ -45,7 +47,7 @@ describe 'typecasting' do
|
|
45
47
|
specify{subject.tap{|s| s.float = 'hello'}.float.should == nil}
|
46
48
|
specify{subject.tap{|s| s.float = '123hello'}.float.should == nil}
|
47
49
|
specify{subject.tap{|s| s.float = '123'}.float.should == 123.0}
|
48
|
-
specify{subject.tap{|s| s.float = '123.'}.float.should ==
|
50
|
+
specify{subject.tap{|s| s.float = '123.'}.float.should == nil}
|
49
51
|
specify{subject.tap{|s| s.float = '123.5'}.float.should == 123.5}
|
50
52
|
specify{subject.tap{|s| s.float = 123}.float.should == 123.0}
|
51
53
|
specify{subject.tap{|s| s.float = 123.5}.float.should == 123.5}
|
@@ -57,7 +59,7 @@ describe 'typecasting' do
|
|
57
59
|
specify{subject.tap{|s| s.big_decimal = 'hello'}.big_decimal.should == nil}
|
58
60
|
specify{subject.tap{|s| s.big_decimal = '123hello'}.big_decimal.should == nil}
|
59
61
|
specify{subject.tap{|s| s.big_decimal = '123'}.big_decimal.should == BigDecimal.new('123.0')}
|
60
|
-
specify{subject.tap{|s| s.big_decimal = '123.'}.big_decimal.should ==
|
62
|
+
specify{subject.tap{|s| s.big_decimal = '123.'}.big_decimal.should == nil}
|
61
63
|
specify{subject.tap{|s| s.big_decimal = '123.5'}.big_decimal.should == BigDecimal.new('123.5')}
|
62
64
|
specify{subject.tap{|s| s.big_decimal = 123}.big_decimal.should == BigDecimal.new('123.0')}
|
63
65
|
specify{subject.tap{|s| s.big_decimal = 123.5}.big_decimal.should == BigDecimal.new('123.5')}
|
@@ -85,4 +87,30 @@ describe 'typecasting' do
|
|
85
87
|
specify{subject.tap{|s| s.array = 10}.array.should == nil}
|
86
88
|
end
|
87
89
|
|
90
|
+
context 'date' do
|
91
|
+
let(:date) { Date.new(2013, 6, 13) }
|
92
|
+
specify{subject.tap{|s| s.date = nil}.date.should == nil}
|
93
|
+
specify{subject.tap{|s| s.date = '2013-06-13'}.date.should == date}
|
94
|
+
specify{subject.tap{|s| s.date = '2013-55-55'}.date.should == nil}
|
95
|
+
specify{subject.tap{|s| s.date = DateTime.new(2013, 6, 13, 23, 13)}.date.should == date}
|
96
|
+
specify{subject.tap{|s| s.date = Time.new(2013, 6, 13, 23, 13)}.date.should == date}
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'datetime' do
|
100
|
+
let(:datetime) { DateTime.new(2013, 6, 13, 23, 13) }
|
101
|
+
specify{subject.tap{|s| s.datetime = nil}.datetime.should == nil}
|
102
|
+
specify{subject.tap{|s| s.datetime = '2013-06-13 23:13'}.datetime.should == datetime}
|
103
|
+
specify{subject.tap{|s| s.datetime = '2013-55-55 55:55'}.datetime.should == nil}
|
104
|
+
specify{subject.tap{|s| s.datetime = Date.new(2013, 6, 13)}.datetime.should == DateTime.new(2013, 6, 13, 0, 0)}
|
105
|
+
specify{subject.tap{|s| s.datetime = Time.utc_time(2013, 6, 13, 23, 13).utc}.datetime.should == DateTime.new(2013, 6, 13, 23, 13)}
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'time' do
|
109
|
+
let(:time) { Time.utc_time(2013, 6, 13, 23, 13) }
|
110
|
+
specify{subject.tap{|s| s.time = nil}.time.should == nil}
|
111
|
+
specify{subject.tap{|s| s.time = '2013-06-13 23:13'}.time.should == time}
|
112
|
+
specify{subject.tap{|s| s.time = '2013-55-55 55:55'}.time.should == nil}
|
113
|
+
specify{subject.tap{|s| s.time = Date.new(2013, 6, 13)}.time.should == Time.new(2013, 6, 13, 0, 0)}
|
114
|
+
specify{subject.tap{|s| s.time = DateTime.new(2013, 6, 13, 23, 13)}.time.should == time}
|
115
|
+
end
|
88
116
|
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
4
|
describe ActiveData::Model do
|
5
|
-
|
6
5
|
let(:model) do
|
7
6
|
Class.new do
|
8
7
|
include ActiveData::Model
|
@@ -12,12 +11,32 @@ describe ActiveData::Model do
|
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
|
-
specify{model.
|
16
|
-
specify{model.
|
17
|
-
specify{model.
|
18
|
-
specify{model.instantiate({}).should
|
14
|
+
specify { expect { model.blablabla }.to raise_error NoMethodError }
|
15
|
+
specify { model.i18n_scope.should == :active_data }
|
16
|
+
specify { model.new.should_not be_persisted }
|
17
|
+
specify { model.instantiate({}).should be_an_instance_of model }
|
18
|
+
specify { model.instantiate({}).should be_persisted }
|
19
19
|
|
20
20
|
context 'Fault tolerance' do
|
21
|
-
specify{ expect { model.new(:
|
21
|
+
specify{ expect { model.new(foo: 'bar') }.not_to raise_error }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#instantiate' do
|
25
|
+
context do
|
26
|
+
subject(:instance) { model.instantiate(name: 'Hello', foo: 'Bar') }
|
27
|
+
|
28
|
+
specify { subject.instance_variable_get(:@attributes).should == { name: 'Hello', count: nil } }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#==' do
|
33
|
+
subject { model.new name: 'hello', count: 42 }
|
34
|
+
it { should_not == nil }
|
35
|
+
it { should_not == 'hello' }
|
36
|
+
it { should_not == Object.new }
|
37
|
+
it { should_not == model.new }
|
38
|
+
it { should_not == model.new(name: 'hello1', count: 42) }
|
39
|
+
it { should_not == model.new(name: 'hello', count: 42.1) }
|
40
|
+
it { should == model.new(name: 'hello', count: 42) }
|
22
41
|
end
|
23
|
-
end
|
42
|
+
end
|