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.
Files changed (41) hide show
  1. data/.rspec +1 -0
  2. data/.travis.yml +1 -1
  3. data/Gemfile +5 -7
  4. data/Guardfile +8 -3
  5. data/active_data.gemspec +2 -2
  6. data/lib/active_data/attributes/base.rb +10 -5
  7. data/lib/active_data/attributes/localized.rb +1 -1
  8. data/lib/active_data/model/associations/{many.rb → association.rb} +9 -3
  9. data/lib/active_data/model/associations/embeds_many.rb +33 -0
  10. data/lib/active_data/model/associations/embeds_one.rb +30 -0
  11. data/lib/active_data/model/associations.rb +19 -22
  12. data/lib/active_data/model/attributable.rb +35 -29
  13. data/lib/active_data/model/collectionizable.rb +13 -12
  14. data/lib/active_data/model/extensions/array.rb +3 -3
  15. data/lib/active_data/model/extensions/big_decimal.rb +2 -2
  16. data/lib/active_data/model/extensions/date.rb +1 -8
  17. data/lib/active_data/model/extensions/date_time.rb +17 -0
  18. data/lib/active_data/model/extensions/float.rb +1 -1
  19. data/lib/active_data/model/extensions/hash.rb +1 -1
  20. data/lib/active_data/model/extensions/integer.rb +1 -1
  21. data/lib/active_data/model/extensions/localized.rb +2 -2
  22. data/lib/active_data/model/extensions/object.rb +17 -0
  23. data/lib/active_data/model/extensions/time.rb +17 -0
  24. data/lib/active_data/model/localizable.rb +3 -3
  25. data/lib/active_data/model/nested_attributes.rb +10 -4
  26. data/lib/active_data/model.rb +17 -11
  27. data/lib/active_data/validations/associated.rb +17 -0
  28. data/lib/active_data/validations.rb +7 -0
  29. data/lib/active_data/version.rb +1 -1
  30. data/lib/active_data.rb +1 -1
  31. data/spec/lib/active_data/model/associations/embeds_many_spec.rb +93 -0
  32. data/spec/lib/active_data/model/associations/embeds_one_spec.rb +57 -0
  33. data/spec/lib/active_data/model/attributable_spec.rb +118 -2
  34. data/spec/lib/active_data/model/attributes/localized_spec.rb +1 -0
  35. data/spec/lib/active_data/model/collectionizable_spec.rb +41 -15
  36. data/spec/lib/active_data/model/nested_attributes_spec.rb +47 -26
  37. data/spec/lib/active_data/model/type_cast_spec.rb +31 -3
  38. data/spec/lib/active_data/model_spec.rb +26 -7
  39. data/spec/lib/active_data/validations/associated_spec.rb +88 -0
  40. metadata +27 -16
  41. data/spec/lib/active_data/model/associations_spec.rb +0 -35
@@ -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 attributes
53
- return attributes if attributes.instance_of? self
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
- instance.instance_variable_set(:@attributes, initialize_attributes)
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 assign_attributes(attributes, options = {})
78
- super(sanitize_for_mass_assignment((attributes.presence || {}), options[:as]))
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
@@ -0,0 +1,7 @@
1
+ require 'active_data/validations/associated'
2
+
3
+ module ActiveData
4
+ module Validations
5
+ extend ActiveSupport::Concern
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveData
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
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 == { "hello"=>nil, "count"=>10, "calc"=>5, "enum" => nil } }
27
- its(:present_attributes) { should == { "count"=>10, "calc"=>5 } }
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
@@ -42,6 +42,7 @@ describe Localized do
42
42
  I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
43
43
  I18n.fallbacks.map(en: :ru)
44
44
  end
45
+ after { I18n.fallbacks = false }
45
46
  its(:name) { should == 'Привет' }
46
47
  end
47
48
  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
- let(:collection){klass.collection([{:name => 'Hello'}, {:name => 'World'}, {:name => 'Mars'}])}
21
-
22
- specify{klass.const_defined?('Collection').should be_true}
23
- specify{klass.collection_class.should == klass.const_get(:Collection)}
24
- specify{klass.collection_class.collectible.should == klass}
25
- specify{klass.collection_class.new.should be_empty}
26
-
27
- specify{collection.should be_instance_of klass.collection_class}
28
- specify{collection.except_first.should be_instance_of klass.collection_class}
29
- specify{collection.no_mars.should be_instance_of klass.collection_class}
30
- specify{collection.except_first.should == klass.collection([{:name => 'World'}, {:name => 'Mars'}])}
31
- specify{collection.no_mars.should == klass.collection([{:name => 'Hello'}, {:name => 'World'}])}
32
- specify{collection.except_first.no_mars.should == klass.collection([{:name => 'World'}])}
33
- specify{collection.no_mars.except_first.should == klass.collection([{:name => 'World'}])}
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 Assoc
6
+ class NestedAssoc
7
7
  include ActiveData::Model
8
8
 
9
9
  attribute :name
10
10
  end
11
11
 
12
- let(:klass) do
13
- Class.new do
14
- include ActiveData::Model
12
+ context do
13
+ let(:klass) do
14
+ Class.new do
15
+ include ActiveData::Model
15
16
 
16
- attribute :name
17
- embeds_many :assocs
17
+ attribute :name
18
+ embeds_one :assoc, class_name: NestedAssoc
18
19
 
19
- accepts_nested_attributes_for :assocs
20
+ accepts_nested_attributes_for :assoc
21
+ end
20
22
  end
21
- end
23
+ let(:instance) { klass.new( name: 'world') }
22
24
 
23
- let(:instance){klass.new(:name => 'world')}
24
-
25
- context do
26
- before { instance.assocs_attributes = [{:name => 'foo'}, {:name => 'bar'}] }
27
- specify { instance.assocs.count.should == 2 }
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
- before { instance.assocs_attributes = {1 => {:name => 'baz'}, 2 => {:name => 'foo'}} }
34
- specify { instance.assocs.count.should == 2 }
35
- specify { instance.assocs.first.name.should == 'baz' }
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
- context do
40
- before { instance.assocs_attributes = {1 => {:name => 'baz'}, 2 => {:name => 'foo'}} }
41
- specify { instance.to_params.should == {
42
- "name" => "world",
43
- "assocs_attributes" => {'0' => {"name" => "baz"}, '1' => {"name" => "foo"}}
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 == 123.0}
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 == BigDecimal.new('123.0')}
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.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}
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(:foo => 'bar') }.not_to raise_error }
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