dm-core 0.10.2 → 1.0.0.rc1
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/.gitignore +10 -1
- data/Gemfile +143 -0
- data/Rakefile +9 -5
- data/VERSION +1 -1
- data/dm-core.gemspec +160 -57
- data/lib/dm-core.rb +131 -56
- data/lib/dm-core/adapters.rb +98 -14
- data/lib/dm-core/adapters/abstract_adapter.rb +24 -4
- data/lib/dm-core/adapters/in_memory_adapter.rb +7 -2
- data/lib/dm-core/associations/many_to_many.rb +19 -30
- data/lib/dm-core/associations/many_to_one.rb +58 -42
- data/lib/dm-core/associations/one_to_many.rb +33 -23
- data/lib/dm-core/associations/one_to_one.rb +27 -11
- data/lib/dm-core/associations/relationship.rb +4 -4
- data/lib/dm-core/collection.rb +23 -16
- data/lib/dm-core/core_ext/array.rb +36 -0
- data/lib/dm-core/core_ext/hash.rb +30 -0
- data/lib/dm-core/core_ext/module.rb +46 -0
- data/lib/dm-core/core_ext/object.rb +31 -0
- data/lib/dm-core/core_ext/pathname.rb +20 -0
- data/lib/dm-core/core_ext/string.rb +22 -0
- data/lib/dm-core/core_ext/try_dup.rb +44 -0
- data/lib/dm-core/model.rb +88 -27
- data/lib/dm-core/model/hook.rb +75 -18
- data/lib/dm-core/model/property.rb +50 -9
- data/lib/dm-core/model/relationship.rb +31 -31
- data/lib/dm-core/model/scope.rb +3 -3
- data/lib/dm-core/property.rb +196 -516
- data/lib/dm-core/property/binary.rb +7 -0
- data/lib/dm-core/property/boolean.rb +35 -0
- data/lib/dm-core/property/class.rb +24 -0
- data/lib/dm-core/property/date.rb +47 -0
- data/lib/dm-core/property/date_time.rb +48 -0
- data/lib/dm-core/property/decimal.rb +43 -0
- data/lib/dm-core/property/discriminator.rb +48 -0
- data/lib/dm-core/property/float.rb +24 -0
- data/lib/dm-core/property/integer.rb +32 -0
- data/lib/dm-core/property/numeric.rb +43 -0
- data/lib/dm-core/property/object.rb +32 -0
- data/lib/dm-core/property/serial.rb +8 -0
- data/lib/dm-core/property/string.rb +49 -0
- data/lib/dm-core/property/text.rb +12 -0
- data/lib/dm-core/property/time.rb +48 -0
- data/lib/dm-core/property/typecast/numeric.rb +32 -0
- data/lib/dm-core/property/typecast/time.rb +28 -0
- data/lib/dm-core/property_set.rb +10 -4
- data/lib/dm-core/query.rb +14 -37
- data/lib/dm-core/query/conditions/comparison.rb +8 -6
- data/lib/dm-core/query/conditions/operation.rb +33 -2
- data/lib/dm-core/query/operator.rb +2 -5
- data/lib/dm-core/query/path.rb +4 -6
- data/lib/dm-core/repository.rb +21 -6
- data/lib/dm-core/resource.rb +316 -133
- data/lib/dm-core/resource/state.rb +79 -0
- data/lib/dm-core/resource/state/clean.rb +40 -0
- data/lib/dm-core/resource/state/deleted.rb +30 -0
- data/lib/dm-core/resource/state/dirty.rb +86 -0
- data/lib/dm-core/resource/state/immutable.rb +34 -0
- data/lib/dm-core/resource/state/persisted.rb +29 -0
- data/lib/dm-core/resource/state/transient.rb +70 -0
- data/lib/dm-core/spec/lib/adapter_helpers.rb +52 -0
- data/lib/dm-core/spec/lib/collection_helpers.rb +20 -0
- data/{spec → lib/dm-core/spec}/lib/counter_adapter.rb +5 -1
- data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
- data/lib/dm-core/spec/lib/spec_helper.rb +68 -0
- data/lib/dm-core/spec/setup.rb +165 -0
- data/lib/dm-core/spec/{adapter_shared_spec.rb → shared/adapter_spec.rb} +21 -7
- data/{spec/public/shared/resource_shared_spec.rb → lib/dm-core/spec/shared/resource_spec.rb} +120 -83
- data/{spec/public/shared/sel_shared_spec.rb → lib/dm-core/spec/shared/sel_spec.rb} +5 -6
- data/lib/dm-core/support/assertions.rb +8 -0
- data/lib/dm-core/support/equalizer.rb +1 -0
- data/lib/dm-core/support/hook.rb +420 -0
- data/lib/dm-core/support/lazy_array.rb +453 -0
- data/lib/dm-core/support/local_object_space.rb +12 -0
- data/lib/dm-core/support/logger.rb +193 -6
- data/lib/dm-core/support/naming_conventions.rb +8 -8
- data/lib/dm-core/support/subject.rb +33 -0
- data/lib/dm-core/type.rb +4 -0
- data/lib/dm-core/types/boolean.rb +2 -0
- data/lib/dm-core/types/decimal.rb +9 -0
- data/lib/dm-core/types/discriminator.rb +2 -0
- data/lib/dm-core/types/object.rb +3 -0
- data/lib/dm-core/types/serial.rb +2 -0
- data/lib/dm-core/types/text.rb +2 -0
- data/lib/dm-core/version.rb +1 -1
- data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +67 -0
- data/spec/public/model/hook_spec.rb +209 -0
- data/spec/public/model/property_spec.rb +35 -0
- data/spec/public/model/relationship_spec.rb +33 -20
- data/spec/public/model_spec.rb +142 -10
- data/spec/public/property/binary_spec.rb +14 -0
- data/spec/public/property/boolean_spec.rb +14 -0
- data/spec/public/property/class_spec.rb +20 -0
- data/spec/public/property/date_spec.rb +14 -0
- data/spec/public/property/date_time_spec.rb +14 -0
- data/spec/public/property/decimal_spec.rb +14 -0
- data/spec/public/{types → property}/discriminator_spec.rb +2 -12
- data/spec/public/property/float_spec.rb +14 -0
- data/spec/public/property/integer_spec.rb +14 -0
- data/spec/public/property/object_spec.rb +9 -17
- data/spec/public/property/serial_spec.rb +14 -0
- data/spec/public/property/string_spec.rb +14 -0
- data/spec/public/property/text_spec.rb +52 -0
- data/spec/public/property/time_spec.rb +14 -0
- data/spec/public/property_spec.rb +28 -87
- data/spec/public/resource_spec.rb +101 -0
- data/spec/public/sel_spec.rb +5 -15
- data/spec/public/shared/collection_shared_spec.rb +16 -30
- data/spec/public/shared/finder_shared_spec.rb +2 -4
- data/spec/public/shared/property_shared_spec.rb +176 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +1 -1
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +2 -2
- data/spec/semipublic/associations/many_to_many_spec.rb +89 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +24 -1
- data/spec/semipublic/associations/one_to_many_spec.rb +51 -0
- data/spec/semipublic/associations/one_to_one_spec.rb +49 -0
- data/spec/semipublic/associations/relationship_spec.rb +3 -3
- data/spec/semipublic/associations_spec.rb +1 -1
- data/spec/semipublic/property/binary_spec.rb +13 -0
- data/spec/semipublic/property/boolean_spec.rb +65 -0
- data/spec/semipublic/property/class_spec.rb +33 -0
- data/spec/semipublic/property/date_spec.rb +43 -0
- data/spec/semipublic/property/date_time_spec.rb +46 -0
- data/spec/semipublic/property/decimal_spec.rb +82 -0
- data/spec/semipublic/property/discriminator_spec.rb +19 -0
- data/spec/semipublic/property/float_spec.rb +82 -0
- data/spec/semipublic/property/integer_spec.rb +82 -0
- data/spec/semipublic/property/serial_spec.rb +13 -0
- data/spec/semipublic/property/string_spec.rb +13 -0
- data/spec/semipublic/property/text_spec.rb +31 -0
- data/spec/semipublic/property/time_spec.rb +50 -0
- data/spec/semipublic/property_spec.rb +2 -532
- data/spec/semipublic/query/conditions/comparison_spec.rb +171 -169
- data/spec/semipublic/query/conditions/operation_spec.rb +53 -51
- data/spec/semipublic/query/path_spec.rb +17 -17
- data/spec/semipublic/query_spec.rb +47 -78
- data/spec/semipublic/resource/state/clean_spec.rb +88 -0
- data/spec/semipublic/resource/state/deleted_spec.rb +78 -0
- data/spec/semipublic/resource/state/dirty_spec.rb +133 -0
- data/spec/semipublic/resource/state/immutable_spec.rb +99 -0
- data/spec/semipublic/resource/state/transient_spec.rb +128 -0
- data/spec/semipublic/resource/state_spec.rb +226 -0
- data/spec/semipublic/shared/property_shared_spec.rb +143 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +16 -15
- data/spec/semipublic/shared/resource_state_shared_spec.rb +78 -0
- data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
- data/spec/spec_helper.rb +21 -97
- data/spec/support/types/huge_integer.rb +17 -0
- data/spec/unit/array_spec.rb +48 -0
- data/spec/unit/hash_spec.rb +35 -0
- data/spec/unit/hook_spec.rb +1234 -0
- data/spec/unit/lazy_array_spec.rb +1959 -0
- data/spec/unit/module_spec.rb +70 -0
- data/spec/unit/object_spec.rb +37 -0
- data/spec/unit/try_dup_spec.rb +45 -0
- data/tasks/local_gemfile.rake +18 -0
- data/tasks/spec.rake +0 -3
- metadata +197 -71
- data/deps.rip +0 -2
- data/lib/dm-core/adapters/data_objects_adapter.rb +0 -712
- data/lib/dm-core/adapters/mysql_adapter.rb +0 -42
- data/lib/dm-core/adapters/oracle_adapter.rb +0 -229
- data/lib/dm-core/adapters/postgres_adapter.rb +0 -22
- data/lib/dm-core/adapters/sqlite3_adapter.rb +0 -17
- data/lib/dm-core/adapters/sqlserver_adapter.rb +0 -114
- data/lib/dm-core/adapters/yaml_adapter.rb +0 -111
- data/lib/dm-core/core_ext/enumerable.rb +0 -28
- data/lib/dm-core/migrations.rb +0 -1427
- data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +0 -366
- data/lib/dm-core/transaction.rb +0 -508
- data/lib/dm-core/types/paranoid_boolean.rb +0 -42
- data/lib/dm-core/types/paranoid_datetime.rb +0 -41
- data/spec/lib/adapter_helpers.rb +0 -105
- data/spec/lib/collection_helpers.rb +0 -18
- data/spec/lib/pending_helpers.rb +0 -46
- data/spec/public/migrations_spec.rb +0 -503
- data/spec/public/transaction_spec.rb +0 -153
- data/spec/semipublic/adapters/mysql_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/oracle_adapter_spec.rb +0 -194
- data/spec/semipublic/adapters/postgres_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/sqlserver_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/yaml_adapter_spec.rb +0 -12
@@ -0,0 +1,133 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe DataMapper::Resource::State::Dirty do
|
4
|
+
before :all do
|
5
|
+
class ::Author
|
6
|
+
include DataMapper::Resource
|
7
|
+
|
8
|
+
property :id, HugeInteger, :key => true, :default => 1
|
9
|
+
property :name, String
|
10
|
+
property :active, Boolean, :default => true
|
11
|
+
property :coding, Boolean, :default => true
|
12
|
+
|
13
|
+
belongs_to :parent, self, :required => false
|
14
|
+
has n, :children, self, :inverse => :parent
|
15
|
+
end
|
16
|
+
|
17
|
+
@model = Author
|
18
|
+
end
|
19
|
+
|
20
|
+
before do
|
21
|
+
@resource = @model.create(:name => 'Dan Kubb')
|
22
|
+
@resource.attributes = { :name => 'John Doe' }
|
23
|
+
|
24
|
+
@state = @resource.persisted_state
|
25
|
+
@state.should be_kind_of(DataMapper::Resource::State::Dirty)
|
26
|
+
end
|
27
|
+
|
28
|
+
after do
|
29
|
+
@resource.destroy
|
30
|
+
end
|
31
|
+
|
32
|
+
after do
|
33
|
+
@model.all.destroy!
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#commit' do
|
37
|
+
subject { @state.commit }
|
38
|
+
|
39
|
+
supported_by :all do
|
40
|
+
before do
|
41
|
+
@new_id = @resource.id = @resource.id.succ
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should return a Clean state' do
|
45
|
+
should eql(DataMapper::Resource::State::Clean.new(@resource))
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should update the resource' do
|
49
|
+
subject
|
50
|
+
@model.get!(*@resource.key).should == @resource
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should update the resource to the identity map if the key changed' do
|
54
|
+
identity_map = @resource.repository.identity_map(@model)
|
55
|
+
identity_map.should == { @resource.key => @resource }
|
56
|
+
subject
|
57
|
+
identity_map.should == { [ @new_id ] => @resource }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#delete' do
|
63
|
+
subject { @state.delete }
|
64
|
+
|
65
|
+
supported_by :all do
|
66
|
+
before do
|
67
|
+
@resource.children = [ @resource.parent = @resource ]
|
68
|
+
end
|
69
|
+
|
70
|
+
it_should_behave_like 'It resets resource state'
|
71
|
+
|
72
|
+
it 'should return a Deleted state' do
|
73
|
+
should eql(DataMapper::Resource::State::Deleted.new(@resource))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#get' do
|
79
|
+
before do
|
80
|
+
@loaded_value = 'John Doe'
|
81
|
+
end
|
82
|
+
|
83
|
+
it_should_behave_like 'Resource::State::Persisted#get'
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#rollback' do
|
87
|
+
subject { @state.rollback }
|
88
|
+
|
89
|
+
supported_by :all do
|
90
|
+
before do
|
91
|
+
@resource.children = [ @resource.parent = @resource ]
|
92
|
+
end
|
93
|
+
|
94
|
+
it_should_behave_like 'It resets resource state'
|
95
|
+
|
96
|
+
it 'should return a Clean state' do
|
97
|
+
should eql(DataMapper::Resource::State::Clean.new(@resource))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#set' do
|
103
|
+
subject { @state.set(@key, @value) }
|
104
|
+
|
105
|
+
supported_by :all do
|
106
|
+
describe 'with attributes that keep the resource dirty' do
|
107
|
+
before do
|
108
|
+
@key = @model.properties[:name]
|
109
|
+
@value = @key.get!(@resource)
|
110
|
+
end
|
111
|
+
|
112
|
+
it_should_behave_like 'A method that delegates to the superclass #set'
|
113
|
+
|
114
|
+
it 'should return a Dirty state' do
|
115
|
+
should equal(@state)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe 'with attributes that make the resource clean' do
|
120
|
+
before do
|
121
|
+
@key = @model.properties[:name]
|
122
|
+
@value = 'Dan Kubb'
|
123
|
+
end
|
124
|
+
|
125
|
+
it_should_behave_like 'A method that delegates to the superclass #set'
|
126
|
+
|
127
|
+
it 'should return a Clean state' do
|
128
|
+
should eql(DataMapper::Resource::State::Clean.new(@resource))
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe DataMapper::Resource::State::Immutable do
|
4
|
+
before :all do
|
5
|
+
class ::Author
|
6
|
+
include DataMapper::Resource
|
7
|
+
|
8
|
+
property :id, Serial
|
9
|
+
property :name, String
|
10
|
+
property :active, Boolean, :default => true
|
11
|
+
property :coding, Boolean, :default => true
|
12
|
+
|
13
|
+
belongs_to :parent, self, :required => false
|
14
|
+
end
|
15
|
+
|
16
|
+
@model = Author
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
@parent = @model.create(:name => 'John Doe')
|
21
|
+
|
22
|
+
@resource = @model.create(:name => 'Dan Kubb', :parent => @parent)
|
23
|
+
@resource = @model.first(@model.key.zip(@resource.key).to_hash.merge(:fields => [ :name, :parent_id ]))
|
24
|
+
|
25
|
+
@state = @resource.persisted_state
|
26
|
+
@state.should be_kind_of(DataMapper::Resource::State::Immutable)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#commit' do
|
30
|
+
subject { @state.commit }
|
31
|
+
|
32
|
+
supported_by :all do
|
33
|
+
it 'should be a no-op' do
|
34
|
+
should equal(@state)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#delete' do
|
40
|
+
subject { @state.delete }
|
41
|
+
|
42
|
+
supported_by :all do
|
43
|
+
it 'should raise an exception' do
|
44
|
+
method(:subject).should raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be deleted')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#get' do
|
50
|
+
subject { @state.get(@key) }
|
51
|
+
|
52
|
+
supported_by :all do
|
53
|
+
describe 'with an unloaded property' do
|
54
|
+
before do
|
55
|
+
@key = @model.properties[:id]
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should raise an exception' do
|
59
|
+
method(:subject).should raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be lazy loaded')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'with an unloaded relationship' do
|
64
|
+
before do
|
65
|
+
@key = @model.relationships[:parent]
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should return value' do
|
69
|
+
should == @parent
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'with a loaded subject' do
|
74
|
+
before do
|
75
|
+
@key = @model.properties[:name]
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should return value' do
|
79
|
+
should == 'Dan Kubb'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#set' do
|
86
|
+
before do
|
87
|
+
@key = @model.properties[:name]
|
88
|
+
@value = @key.get!(@resource)
|
89
|
+
end
|
90
|
+
|
91
|
+
subject { @state.set(@key, @value) }
|
92
|
+
|
93
|
+
supported_by :all do
|
94
|
+
it 'should raise an exception' do
|
95
|
+
method(:subject).should raise_error(DataMapper::ImmutableError, 'Immutable resource cannot be modified')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe DataMapper::Resource::State::Transient do
|
4
|
+
before :all do
|
5
|
+
class ::Author
|
6
|
+
include DataMapper::Resource
|
7
|
+
|
8
|
+
property :id, Serial
|
9
|
+
property :name, String
|
10
|
+
property :age, Integer
|
11
|
+
property :description, Text, :default => lambda { |resource, property| resource.name }
|
12
|
+
property :active, Boolean, :default => true
|
13
|
+
property :coding, Boolean, :default => true
|
14
|
+
end
|
15
|
+
|
16
|
+
@model = Author
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
@resource = @model.new(:name => 'Dan Kubb', :coding => false)
|
21
|
+
|
22
|
+
@state = @resource.persisted_state
|
23
|
+
@state.should be_kind_of(DataMapper::Resource::State::Transient)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#commit' do
|
27
|
+
subject { @state.commit }
|
28
|
+
|
29
|
+
supported_by :all do
|
30
|
+
it 'should return the expected Clean state' do
|
31
|
+
should eql(DataMapper::Resource::State::Clean.new(@resource))
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should set the serial property' do
|
35
|
+
method(:subject).should change(@resource, :id).from(nil)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should set default values' do
|
39
|
+
method(:subject).should change { @model.properties[:active].get!(@resource) }.from(nil).to(true)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should not set default values when they are already set' do
|
43
|
+
method(:subject).should_not change(@resource, :coding)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should create the resource' do
|
47
|
+
subject
|
48
|
+
@model.get(*@resource.key).should == @resource
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should reset original attributes' do
|
52
|
+
expect do
|
53
|
+
@resource.persisted_state = subject
|
54
|
+
end.should change { @resource.original_attributes.dup }.from(@model.properties[:name] => nil, @model.properties[:coding] => nil).to({})
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should add the resource to the identity map' do
|
58
|
+
DataMapper.repository do |repository|
|
59
|
+
identity_map = repository.identity_map(@model)
|
60
|
+
identity_map.should be_empty
|
61
|
+
subject
|
62
|
+
identity_map.should == { @resource.key => @resource }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
[ :delete, :rollback ].each do |method|
|
69
|
+
describe "##{method}" do
|
70
|
+
subject { @state.send(method) }
|
71
|
+
|
72
|
+
it 'should be a no-op' do
|
73
|
+
should equal(@state)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#get' do
|
79
|
+
subject { @state.get(@key) }
|
80
|
+
|
81
|
+
describe 'with a set value' do
|
82
|
+
before do
|
83
|
+
@key = @model.properties[:coding]
|
84
|
+
@key.should be_loaded(@resource)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should return value' do
|
88
|
+
should be(false)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should be idempotent' do
|
92
|
+
should equal(subject)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe 'with an unset value and no default value' do
|
97
|
+
before do
|
98
|
+
@key = @model.properties[:age]
|
99
|
+
@key.should_not be_loaded(@resource)
|
100
|
+
@key.should_not be_default
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should return nil' do
|
104
|
+
should be_nil
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should be idempotent' do
|
108
|
+
should equal(subject)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe 'with an unset value and a default value' do
|
113
|
+
before do
|
114
|
+
@key = @model.properties[:description]
|
115
|
+
@key.should_not be_loaded(@resource)
|
116
|
+
@key.should be_default
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should return the name' do
|
120
|
+
should == 'Dan Kubb'
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should be idempotent' do
|
124
|
+
should equal(subject)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
|
2
|
+
|
3
|
+
describe DataMapper::Resource::State do
|
4
|
+
before :all do
|
5
|
+
class ::Author
|
6
|
+
include DataMapper::Resource
|
7
|
+
|
8
|
+
property :id, Serial
|
9
|
+
property :name, String
|
10
|
+
property :private, Boolean, :accessor => :private
|
11
|
+
|
12
|
+
belongs_to :parent, self, :required => false
|
13
|
+
end
|
14
|
+
|
15
|
+
@model = Author
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
@resource = @model.new(:name => 'Dan Kubb')
|
20
|
+
|
21
|
+
@state = DataMapper::Resource::State.new(@resource)
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '.new' do
|
25
|
+
subject { DataMapper::Resource::State.new(@resource) }
|
26
|
+
|
27
|
+
it { should be_kind_of(DataMapper::Resource::State) }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#==' do
|
31
|
+
subject { @state == @other }
|
32
|
+
|
33
|
+
describe 'with the same class and resource' do
|
34
|
+
before do
|
35
|
+
@other = DataMapper::Resource::State.new(@resource)
|
36
|
+
end
|
37
|
+
|
38
|
+
it { should be(true) }
|
39
|
+
|
40
|
+
it 'should be symmetric' do
|
41
|
+
should == (@other == @state)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'with the same class and different resource' do
|
46
|
+
before do
|
47
|
+
@other = DataMapper::Resource::State.new(@model.new)
|
48
|
+
end
|
49
|
+
|
50
|
+
it { should be(false) }
|
51
|
+
|
52
|
+
it 'should be symmetric' do
|
53
|
+
should == (@other == @state)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'with a different class and the same resource' do
|
58
|
+
before do
|
59
|
+
@other = DataMapper::Resource::State::Clean.new(@resource)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should be true for a subclass' do
|
63
|
+
should be(true)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should be symmetric' do
|
67
|
+
should == (@other == @state)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'with a different class and different resource' do
|
72
|
+
before do
|
73
|
+
@other = DataMapper::Resource::State::Clean.new(@model.new)
|
74
|
+
end
|
75
|
+
|
76
|
+
it { should be(false) }
|
77
|
+
|
78
|
+
it 'should be symmetric' do
|
79
|
+
should == (@other == @state)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
[ :commit, :delete, :rollback ].each do |method|
|
85
|
+
describe "##{method}" do
|
86
|
+
subject { @state.send(method) }
|
87
|
+
|
88
|
+
it 'should raise an exception' do
|
89
|
+
method(:subject).should raise_error(NotImplementedError, "DataMapper::Resource::State##{method} should be implemented")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#eql?' do
|
95
|
+
subject { @state.eql?(@other) }
|
96
|
+
|
97
|
+
describe 'with the same class and resource' do
|
98
|
+
before do
|
99
|
+
@other = DataMapper::Resource::State.new(@resource)
|
100
|
+
end
|
101
|
+
|
102
|
+
it { should be(true) }
|
103
|
+
|
104
|
+
it 'should be symmetric' do
|
105
|
+
should == @other.eql?(@state)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe 'with the same class and different resource' do
|
110
|
+
before do
|
111
|
+
@other = DataMapper::Resource::State.new(@model.new)
|
112
|
+
end
|
113
|
+
|
114
|
+
it { should be(false) }
|
115
|
+
|
116
|
+
it 'should be symmetric' do
|
117
|
+
should == @other.eql?(@state)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe 'with a different class and the same resource' do
|
122
|
+
before do
|
123
|
+
@other = DataMapper::Resource::State::Clean.new(@resource)
|
124
|
+
end
|
125
|
+
|
126
|
+
it { should be(false) }
|
127
|
+
|
128
|
+
it 'should be symmetric' do
|
129
|
+
should == @other.eql?(@state)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe 'with a different class and different resource' do
|
134
|
+
before do
|
135
|
+
@other = DataMapper::Resource::State::Clean.new(@model.new)
|
136
|
+
end
|
137
|
+
|
138
|
+
it { should be(false) }
|
139
|
+
|
140
|
+
it 'should be symmetric' do
|
141
|
+
should == @other.eql?(@state)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '#get' do
|
147
|
+
subject { @state.get(@key) }
|
148
|
+
|
149
|
+
describe 'with a Property subject' do
|
150
|
+
before do
|
151
|
+
@key = @model.properties[:name]
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should return the value' do
|
155
|
+
should == 'Dan Kubb'
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe 'with a Relationship subject' do
|
160
|
+
supported_by :all do
|
161
|
+
before do
|
162
|
+
# set the association
|
163
|
+
@resource.parent = @resource
|
164
|
+
|
165
|
+
@key = @model.relationships[:parent]
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'should return the association' do
|
169
|
+
should == @resource
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe '#hash' do
|
176
|
+
subject { @state.hash }
|
177
|
+
|
178
|
+
it 'should be the object_id hash of the resource' do
|
179
|
+
should == @resource.object_id.hash
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe '#resource' do
|
184
|
+
subject { @state.resource }
|
185
|
+
|
186
|
+
it 'should return the resource' do
|
187
|
+
should equal(@resource)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe '#set' do
|
192
|
+
subject { @state.set(@key, @value) }
|
193
|
+
|
194
|
+
describe 'with a Property subject' do
|
195
|
+
before do
|
196
|
+
@key = @model.properties[:name]
|
197
|
+
@value = 'John Doe'
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'should return a state object' do
|
201
|
+
should be_kind_of(DataMapper::Resource::State)
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'should change the object attributes' do
|
205
|
+
method(:subject).should change(@resource, :attributes).from(:name => 'Dan Kubb').to(:name => 'John Doe')
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
describe 'with a Relationship subject' do
|
210
|
+
supported_by :all do
|
211
|
+
before do
|
212
|
+
@key = @model.relationships[:parent]
|
213
|
+
@value = @resource
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'should return a state object' do
|
217
|
+
should be_kind_of(DataMapper::Resource::State)
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'should change the object relationship' do
|
221
|
+
method(:subject).should change(@resource, :parent).from(nil).to(@resource)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|