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.
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