active_data 0.1.0 → 0.2.0
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/.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
|