ardm 0.0.1 → 0.1.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 (93) hide show
  1. checksums.yaml +5 -13
  2. data/Gemfile +1 -2
  3. data/LICENSE +2 -2
  4. data/README.md +72 -16
  5. data/ardm.gemspec +1 -0
  6. data/lib/ardm.rb +2 -1
  7. data/lib/ardm/active_record.rb +8 -1
  8. data/lib/ardm/active_record/associations.rb +33 -4
  9. data/lib/ardm/active_record/base.rb +2 -0
  10. data/lib/ardm/active_record/collection.rb +5 -0
  11. data/lib/ardm/active_record/data_mapper_constant.rb +1 -0
  12. data/lib/ardm/active_record/data_mapper_constant_proxy.rb +24 -0
  13. data/lib/ardm/active_record/finalize.rb +18 -0
  14. data/lib/ardm/active_record/predicate_builder/array_handler.rb +10 -16
  15. data/lib/ardm/active_record/predicate_builder/rails3.rb +42 -15
  16. data/lib/ardm/active_record/predicate_builder/rails4.rb +39 -13
  17. data/lib/ardm/active_record/property.rb +24 -12
  18. data/lib/ardm/active_record/query.rb +9 -18
  19. data/lib/ardm/active_record/record.rb +54 -11
  20. data/lib/ardm/active_record/relation.rb +36 -6
  21. data/lib/ardm/active_record/repository.rb +6 -2
  22. data/lib/ardm/data_mapper.rb +2 -0
  23. data/lib/ardm/data_mapper/record.rb +3 -9
  24. data/lib/ardm/version.rb +1 -1
  25. data/spec/ardm/datamapper_constants_spec.rb +31 -0
  26. data/spec/fixtures/article.rb +2 -0
  27. data/spec/integration/api_key_spec.rb +3 -3
  28. data/spec/integration/bcrypt_hash_spec.rb +7 -7
  29. data/spec/integration/comma_separated_list_spec.rb +11 -11
  30. data/spec/integration/dirty_minder_spec.rb +23 -39
  31. data/spec/integration/enum_spec.rb +11 -11
  32. data/spec/integration/epoch_time_spec.rb +6 -6
  33. data/spec/integration/file_path_spec.rb +23 -23
  34. data/spec/integration/flag_spec.rb +11 -13
  35. data/spec/integration/ip_address_spec.rb +15 -15
  36. data/spec/integration/json_spec.rb +7 -7
  37. data/spec/integration/slug_spec.rb +6 -6
  38. data/spec/integration/uri_spec.rb +11 -11
  39. data/spec/integration/uuid_spec.rb +16 -16
  40. data/spec/integration/yaml_spec.rb +8 -8
  41. data/spec/public/model_spec.rb +193 -0
  42. data/spec/public/property/binary_spec.rb +4 -4
  43. data/spec/public/property/boolean_spec.rb +3 -3
  44. data/spec/public/property/class_spec.rb +2 -2
  45. data/spec/public/property/date_spec.rb +2 -2
  46. data/spec/public/property/date_time_spec.rb +2 -2
  47. data/spec/public/property/decimal_spec.rb +2 -2
  48. data/spec/public/property/discriminator_spec.rb +21 -20
  49. data/spec/public/property/float_spec.rb +2 -2
  50. data/spec/public/property/integer_spec.rb +2 -2
  51. data/spec/public/property/object_spec.rb +14 -13
  52. data/spec/public/property/serial_spec.rb +2 -2
  53. data/spec/public/property/string_spec.rb +2 -2
  54. data/spec/public/property/text_spec.rb +2 -2
  55. data/spec/public/property/time_spec.rb +2 -2
  56. data/spec/public/property_spec.rb +44 -48
  57. data/spec/public/resource_spec.rb +278 -0
  58. data/spec/schema.rb +33 -4
  59. data/spec/semipublic/property/boolean_spec.rb +5 -5
  60. data/spec/semipublic/property/class_spec.rb +3 -3
  61. data/spec/semipublic/property/date_spec.rb +8 -8
  62. data/spec/semipublic/property/date_time_spec.rb +9 -9
  63. data/spec/semipublic/property/decimal_spec.rb +16 -16
  64. data/spec/semipublic/property/float_spec.rb +16 -16
  65. data/spec/semipublic/property/integer_spec.rb +16 -16
  66. data/spec/semipublic/property/lookup_spec.rb +4 -4
  67. data/spec/semipublic/property/text_spec.rb +2 -2
  68. data/spec/semipublic/property/time_spec.rb +10 -10
  69. data/spec/semipublic/property_spec.rb +4 -4
  70. data/spec/shared/finder_shared_spec.rb +1151 -0
  71. data/spec/shared/flags_shared_spec.rb +6 -6
  72. data/spec/shared/identity_function_group.rb +1 -1
  73. data/spec/shared/public_property_spec.rb +26 -25
  74. data/spec/shared/resource_spec.rb +1218 -0
  75. data/spec/shared/semipublic_property_spec.rb +23 -22
  76. data/spec/spec_helper.rb +17 -0
  77. data/spec/unit/bcrypt_hash_spec.rb +15 -15
  78. data/spec/unit/csv_spec.rb +11 -11
  79. data/spec/unit/dirty_minder_spec.rb +3 -5
  80. data/spec/unit/enum_spec.rb +17 -17
  81. data/spec/unit/epoch_time_spec.rb +8 -8
  82. data/spec/unit/file_path_spec.rb +9 -9
  83. data/spec/unit/flag_spec.rb +9 -9
  84. data/spec/unit/ip_address_spec.rb +9 -9
  85. data/spec/unit/json_spec.rb +11 -11
  86. data/spec/unit/paranoid_boolean_spec.rb +19 -17
  87. data/spec/unit/paranoid_datetime_spec.rb +21 -19
  88. data/spec/unit/regexp_spec.rb +4 -4
  89. data/spec/unit/uri_spec.rb +8 -8
  90. data/spec/unit/yaml_spec.rb +9 -9
  91. metadata +35 -27
  92. data/lib/ardm/active_record/not_found.rb +0 -7
  93. data/lib/ardm/data_mapper/not_found.rb +0 -5
@@ -15,8 +15,8 @@ describe Ardm::Property::Serial do
15
15
  describe '.options' do
16
16
  subject { described_class.options }
17
17
 
18
- it { should be_kind_of(Hash) }
18
+ it { is_expected.to be_kind_of(Hash) }
19
19
 
20
- it { should eql(:load_as => @load_as, :dump_as => @load_as, :coercion_method => :to_integer, :min => 1, :serial => true) }
20
+ it { is_expected.to eql(:load_as => @load_as, :dump_as => @load_as, :coercion_method => :to_integer, :min => 1, :serial => true) }
21
21
  end
22
22
  end
@@ -15,8 +15,8 @@ describe Ardm::Property::String do
15
15
  describe '.options' do
16
16
  subject { described_class.options }
17
17
 
18
- it { should be_kind_of(Hash) }
18
+ it { is_expected.to be_kind_of(Hash) }
19
19
 
20
- it { should eql(:load_as => @load_as, :dump_as => @load_as, :coercion_method => :to_string, :length => 50) }
20
+ it { is_expected.to eql(:load_as => @load_as, :dump_as => @load_as, :coercion_method => :to_string, :length => 50) }
21
21
  end
22
22
  end
@@ -15,9 +15,9 @@ describe Ardm::Property::Text do
15
15
  describe '.options' do
16
16
  subject { described_class.options }
17
17
 
18
- it { should be_kind_of(Hash) }
18
+ it { is_expected.to be_kind_of(Hash) }
19
19
 
20
- it { should eql(:load_as => @load_as, :dump_as => @load_as, :coercion_method => :to_string, :length => 65535, :lazy => true) }
20
+ it { is_expected.to eql(:load_as => @load_as, :dump_as => @load_as, :coercion_method => :to_string, :length => 65535, :lazy => true) }
21
21
  end
22
22
 
23
23
  end
@@ -15,8 +15,8 @@ describe Ardm::Property::Time do
15
15
  describe '.options' do
16
16
  subject { described_class.options }
17
17
 
18
- it { should be_kind_of(Hash) }
18
+ it { is_expected.to be_kind_of(Hash) }
19
19
 
20
- it { should eql(:load_as => @load_as, :dump_as => @load_as, :coercion_method => :to_time) }
20
+ it { is_expected.to eql(:load_as => @load_as, :dump_as => @load_as, :coercion_method => :to_time) }
21
21
  end
22
22
  end
@@ -30,37 +30,37 @@ describe Ardm::Property do
30
30
 
31
31
  describe '#field' do
32
32
  it 'returns @field value if it is present' do
33
- Track.properties[:title].field.should eql('name')
33
+ expect(Track.properties[:title].field).to eql('name')
34
34
  end
35
35
  end
36
36
 
37
37
  describe '#default_for' do
38
38
  it 'returns default value for non-callables' do
39
- Image.properties[:format].default_for(Image.new).should == 'jpeg'
39
+ expect(Image.properties[:format].default_for(Image.new)).to eq('jpeg')
40
40
  end
41
41
 
42
42
  it 'returns result of a call for callable values' do
43
- Image.properties[:taken_at].default_for(Image.new).year.should == Time.now.year
43
+ expect(Image.properties[:taken_at].default_for(Image.new).year).to eq(Time.now.year)
44
44
  end
45
45
 
46
46
  it "sets the default when the record is created" do
47
47
  img = Image.create!(title: 'My Picture')
48
- img.format.should == 'jpeg'
48
+ expect(img.format).to eq('jpeg')
49
49
  end
50
50
  end
51
51
 
52
52
  describe '#eql?' do
53
53
  it 'is true for properties with the same model and name' do
54
- Track.properties[:title].should eql(Track.properties[:title])
54
+ expect(Track.properties[:title]).to eql(Track.properties[:title])
55
55
  end
56
56
 
57
57
 
58
58
  it 'is false for properties of different models' do
59
- Track.properties[:title].should_not eql(Image.properties[:title])
59
+ expect(Track.properties[:title]).not_to eql(Image.properties[:title])
60
60
  end
61
61
 
62
62
  it 'is false for properties with different names' do
63
- Track.properties[:title].should_not eql(Track.properties[:id])
63
+ expect(Track.properties[:title]).not_to eql(Track.properties[:id])
64
64
  end
65
65
  end
66
66
 
@@ -72,26 +72,24 @@ describe Ardm::Property do
72
72
  @image.instance_variable_set(:@description, 'Is set by magic')
73
73
  end
74
74
 
75
- it 'gets instance variable value from the resource directly' do
76
- pending "support for this in ActiveRecord is questionable" do
77
- # if you know a better way to test direct instance variable access,
78
- # go ahead and make changes to this example
79
- Image.properties[:description].get!(@image).should == 'Is set by magic'
80
- end
75
+ it 'gets instance variable value from the resource directly', pending: true do
76
+ # if you know a better way to test direct instance variable access,
77
+ # go ahead and make changes to this example
78
+ expect(Image.properties[:description].get!(@image)).to eq('Is set by magic')
81
79
  end
82
80
  end
83
81
 
84
82
  describe '#index' do
85
83
  it 'returns true when property has an index' do
86
- Track.properties[:title].index.should be(true)
84
+ expect(Track.properties[:title].index).to be(true)
87
85
  end
88
86
 
89
87
  it 'returns index name when property has a named index' do
90
- Track.properties[:album].index.should eql(:artist_album)
88
+ expect(Track.properties[:album].index).to eql(:artist_album)
91
89
  end
92
90
 
93
91
  it 'returns false when property has no index' do
94
- Track.properties[:musicbrainz_hash].index.should be(false)
92
+ expect(Track.properties[:musicbrainz_hash].index).to be(false)
95
93
  end
96
94
  end
97
95
 
@@ -107,48 +105,48 @@ describe Ardm::Property do
107
105
  end
108
106
 
109
107
  it 'features model name' do
110
- @str.should =~ /@model=Track/
108
+ expect(@str).to match(/@model=Track/)
111
109
  end
112
110
 
113
111
  it 'features property name' do
114
- @str.should =~ /@name=:title/
112
+ expect(@str).to match(/@name=:title/)
115
113
  end
116
114
  end
117
115
 
118
116
  describe '#key?' do
119
117
  describe 'returns true when property is a ' do
120
118
  it 'serial key' do
121
- Track.properties[:id].key?.should be(true)
119
+ expect(Track.properties[:id].key?).to be(true)
122
120
  end
123
121
  it 'natural key' do
124
- Image.properties[:md5hash].key?.should be(true)
122
+ expect(Image.properties[:md5hash].key?).to be(true)
125
123
  end
126
124
  end
127
125
 
128
126
  it 'returns true when property is a part of composite key'
129
127
 
130
128
  it 'returns false when property does not relate to a key' do
131
- Track.properties[:title].key?.should be(false)
129
+ expect(Track.properties[:title].key?).to be(false)
132
130
  end
133
131
  end
134
132
 
135
133
  describe '#lazy?' do
136
134
  it 'returns true when property is lazy loaded' do
137
- Image.properties[:description].lazy?.should be(true)
135
+ expect(Image.properties[:description].lazy?).to be(true)
138
136
  end
139
137
 
140
138
  it 'returns false when property is not lazy loaded' do
141
- Track.properties[:artist].lazy?.should be(false)
139
+ expect(Track.properties[:artist].lazy?).to be(false)
142
140
  end
143
141
  end
144
142
 
145
143
  describe '#length' do
146
144
  it 'returns upper bound for Range values' do
147
- Image.properties[:description].length.should eql(1024)
145
+ expect(Image.properties[:description].length).to eql(1024)
148
146
  end
149
147
 
150
148
  it 'returns value as is for integer values' do
151
- Image.properties[:md5hash].length.should eql(32)
149
+ expect(Image.properties[:md5hash].length).to eql(32)
152
150
  end
153
151
  end
154
152
 
@@ -159,7 +157,7 @@ describe Ardm::Property do
159
157
  end
160
158
 
161
159
  it 'should be nil' do
162
- @property.min.should be_nil
160
+ expect(@property.min).to be_nil
163
161
  end
164
162
  end
165
163
 
@@ -169,7 +167,7 @@ describe Ardm::Property do
169
167
  end
170
168
 
171
169
  it 'should be the default value' do
172
- @property.min.should == 0
170
+ expect(@property.min).to eq(0)
173
171
  end
174
172
  end
175
173
 
@@ -180,7 +178,7 @@ describe Ardm::Property do
180
178
  end
181
179
 
182
180
  it 'should be the expected value' do
183
- @property.min.should == @min
181
+ expect(@property.min).to eq(@min)
184
182
  end
185
183
  end
186
184
  end
@@ -192,7 +190,7 @@ describe Ardm::Property do
192
190
  end
193
191
 
194
192
  it 'should be nil' do
195
- @property.max.should be_nil
193
+ expect(@property.max).to be_nil
196
194
  end
197
195
  end
198
196
 
@@ -202,7 +200,7 @@ describe Ardm::Property do
202
200
  end
203
201
 
204
202
  it 'should be the default value' do
205
- @property.max.should == 2**31-1
203
+ expect(@property.max).to eq(2**31-1)
206
204
  end
207
205
  end
208
206
 
@@ -213,28 +211,28 @@ describe Ardm::Property do
213
211
  end
214
212
 
215
213
  it 'should be the expected value' do
216
- @property.max.should == @max
214
+ expect(@property.max).to eq(@max)
217
215
  end
218
216
  end
219
217
  end
220
218
 
221
219
  describe '#allow_nil?' do
222
220
  it 'returns true when property can accept nil as its value' do
223
- Track.properties[:artist].allow_nil?.should be(true)
221
+ expect(Track.properties[:artist].allow_nil?).to be(true)
224
222
  end
225
223
 
226
224
  it 'returns false when property nil value is prohibited for this property' do
227
- Image.properties[:title].allow_nil?.should be(false)
225
+ expect(Image.properties[:title].allow_nil?).to be(false)
228
226
  end
229
227
  end
230
228
 
231
229
  describe '#serial?' do
232
230
  it 'returns true when property is serial (auto incrementing)' do
233
- Track.properties[:id].serial?.should be(true)
231
+ expect(Track.properties[:id].serial?).to be(true)
234
232
  end
235
233
 
236
234
  it 'returns false when property is NOT serial (auto incrementing)' do
237
- Image.properties[:md5hash].serial?.should be(false)
235
+ expect(Image.properties[:md5hash].serial?).to be(false)
238
236
  end
239
237
  end
240
238
 
@@ -256,12 +254,12 @@ describe Ardm::Property do
256
254
  it 'type casts given value' do
257
255
  @property.set(@image, Addressable::URI.parse('http://test.example/'))
258
256
  # get a string that has been typecasted using #to_str
259
- @image.title.should == 'http://test.example/'
257
+ expect(@image.title).to eq('http://test.example/')
260
258
  end
261
259
 
262
260
  it 'sets new property value' do
263
261
  @property.set(@image, 'Updated value')
264
- @image.title.should == 'Updated value'
262
+ expect(@image.title).to eq('Updated value')
265
263
  end
266
264
  end
267
265
 
@@ -276,41 +274,39 @@ describe Ardm::Property do
276
274
 
277
275
  it 'directly sets instance variable on given resource' do
278
276
  @property.set!(@image, 'Set with dark Ruby magic')
279
- @image.title.should == 'Set with dark Ruby magic'
277
+ expect(@image.title).to eq('Set with dark Ruby magic')
280
278
  end
281
279
  end
282
280
 
283
281
  describe '#unique?' do
284
282
  it 'is true for fields that explicitly given uniq index' do
285
- Track.properties[:musicbrainz_hash].unique?.should be(true)
283
+ expect(Track.properties[:musicbrainz_hash].unique?).to be(true)
286
284
  end
287
285
 
288
- it 'is true for serial fields' do
289
- pending do
290
- Track.properties[:title].unique?.should be(true)
291
- end
286
+ it 'is true for serial fields', pending: true do
287
+ expect(Track.properties[:title].unique?).to be(true)
292
288
  end
293
289
 
294
290
  it 'is true for keys' do
295
- Image.properties[:md5hash].unique?.should be(true)
291
+ expect(Image.properties[:md5hash].unique?).to be(true)
296
292
  end
297
293
  end
298
294
 
299
295
  describe '#unique_index' do
300
296
  it 'returns true when property has unique index' do
301
- Track.properties[:musicbrainz_hash].unique_index.should be(true)
297
+ expect(Track.properties[:musicbrainz_hash].unique_index).to be(true)
302
298
  end
303
299
 
304
300
  it 'returns false when property has no unique index' do
305
- Track.properties[:title].unique_index.should be(false)
301
+ expect(Track.properties[:title].unique_index).to be(false)
306
302
  end
307
303
 
308
304
  it 'returns true when property is unique' do
309
- Image.properties[:title].unique_index.should be(true)
305
+ expect(Image.properties[:title].unique_index).to be(true)
310
306
  end
311
307
 
312
308
  it 'returns :key when property is a key' do
313
- Track.properties[:id].unique_index.should == :key
309
+ expect(Track.properties[:id].unique_index).to eq(:key)
314
310
  end
315
311
  end
316
312
  end
@@ -0,0 +1,278 @@
1
+ require 'spec_helper'
2
+
3
+ module ::ResourceBlog
4
+ class User < Ardm::Record
5
+ self.table_name = "users"
6
+
7
+ property :name, String, :key => true
8
+ property :age, Integer
9
+ property :summary, Text
10
+ property :description, Text
11
+ property :admin, Boolean, :accessor => :private
12
+
13
+ belongs_to :parent, self, :required => false
14
+ has n, :children, self, :inverse => :parent
15
+
16
+ belongs_to :referrer, self, :required => false
17
+ has n, :comments
18
+
19
+ # FIXME: figure out a different approach than stubbing things out
20
+ def comment=(*)
21
+ # do nothing with comment
22
+ end
23
+ end
24
+
25
+ class Author < User; end
26
+
27
+ class Comment < Ardm::Record
28
+ self.table_name = "comments"
29
+
30
+ property :id, Serial
31
+ property :body, Text
32
+
33
+ belongs_to :user
34
+ end
35
+
36
+ class Article < Ardm::Record
37
+ self.table_name = "articles"
38
+
39
+ property :id, Serial
40
+ property :body, Text
41
+ timestamps :at
42
+
43
+ has n, :paragraphs
44
+ end
45
+
46
+ class Paragraph < Ardm::Record
47
+ self.table_name = "paragraphs"
48
+
49
+ property :id, Serial
50
+ property :text, String
51
+
52
+ belongs_to :article
53
+ end
54
+ end
55
+
56
+ Ardm::Record.finalize
57
+
58
+ # TODO: unused?
59
+ #class ::ResourceDefault < Ardm::Record
60
+ # property :name, String, :key => true, :default => 'a default value'
61
+ #end
62
+
63
+ describe Ardm::Record do
64
+ before do
65
+ @user_model = ResourceBlog::User
66
+ @author_model = ResourceBlog::Author
67
+ @comment_model = ResourceBlog::Comment
68
+ @article_model = ResourceBlog::Article
69
+ @paragraph_model = ResourceBlog::Paragraph
70
+
71
+ user = @user_model.create!(:name => 'dbussink', :age => 25, :description => 'Test')
72
+
73
+ @user = @user_model.get!(user.key)
74
+ end
75
+
76
+ # FIXME
77
+ #it_should_behave_like 'A public Resource'
78
+ #it_should_behave_like 'A Resource supporting Strategic Eager Loading'
79
+
80
+ it 'A resource should respond to raise_on_save_failure' do
81
+ expect(@user).to respond_to(:raise_on_save_failure)
82
+ end
83
+
84
+ describe '#raise_on_save_failure' do
85
+ after do
86
+ # reset to the default value
87
+ reset_raise_on_save_failure(@user_model)
88
+ reset_raise_on_save_failure(@user)
89
+ end
90
+
91
+ subject { @user.raise_on_save_failure }
92
+
93
+ describe 'when model.raise_on_save_failure has not been set' do
94
+ it { is_expected.to be false }
95
+ end
96
+
97
+ describe 'when model.raise_on_save_failure has been set to true' do
98
+ before do
99
+ @user_model.raise_on_save_failure = true
100
+ end
101
+
102
+ it { is_expected.to be true }
103
+ end
104
+
105
+ describe 'when resource.raise_on_save_failure has been set to true' do
106
+ before do
107
+ @user.raise_on_save_failure = true
108
+ end
109
+
110
+ it { is_expected.to be true }
111
+ end
112
+ end
113
+
114
+ it 'A model should respond to raise_on_save_failure=' do
115
+ expect(@user_model).to respond_to(:raise_on_save_failure=)
116
+ end
117
+
118
+ describe '#raise_on_save_failure=' do
119
+ after do
120
+ # reset to the default value
121
+ reset_raise_on_save_failure(@user_model)
122
+ end
123
+
124
+ describe 'with a true value' do
125
+ subject { @user_model.raise_on_save_failure = true }
126
+
127
+ it { is_expected.to be true }
128
+
129
+ it 'should set raise_on_save_failure' do
130
+ expect { subject }.to change {
131
+ @user_model.raise_on_save_failure
132
+ }.from(false).to(true)
133
+ end
134
+ end
135
+
136
+ describe 'with a false value' do
137
+ subject { @user_model.raise_on_save_failure = false }
138
+
139
+ it { is_expected.to be false }
140
+
141
+ it 'should set raise_on_save_failure' do
142
+ expect { subject }.to_not change {
143
+ @user_model.raise_on_save_failure
144
+ }
145
+ end
146
+ end
147
+ end
148
+
149
+ [ :save, :save! ].each do |method|
150
+ describe "##{method}" do
151
+ subject { @user.__send__(method) }
152
+
153
+ describe 'when raise_on_save_failure is true' do
154
+ before do
155
+ @user.raise_on_save_failure = true
156
+ end
157
+
158
+ describe 'and it is a savable resource' do
159
+ it { is_expected.to be true }
160
+ end
161
+
162
+ # FIXME: We cannot trigger a failing save with invalid properties anymore.
163
+ # Invalid properties will result in their own exception.
164
+ # So Im mocking here, but a better approach is needed.
165
+
166
+ describe 'and it is an invalid resource', pending: true do
167
+ before do
168
+ expect(@user).to receive(:save_self).and_return(false)
169
+ end
170
+
171
+ it 'should raise an exception' do
172
+ expect { subject }.to raise_error(Ardm::SaveFailureError, "Blog::User##{method} returned false, Blog::User was not saved")
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ [ :update, :update! ].each do |method|
180
+ describe 'with attributes where one is a foreign key' do
181
+ before do
182
+ @dkubb = @user_model.create(:name => 'dkubb', :age => 33)
183
+ @user.referrer = @dkubb
184
+ @user.save
185
+ @user = @user_model.get(@user.key)
186
+ expect(@user.referrer).to eq(@dkubb)
187
+
188
+ @solnic = @user_model.create(:name => 'solnic', :age => 28)
189
+
190
+ @attributes = {}
191
+
192
+ relationship = @user_model.relationships[:referrer]
193
+
194
+ # Original datamapper implementation:
195
+ #relationship.child_key.to_a.each_with_index do |k, i|
196
+ # @attributes[k.name] = relationship.parent_key.to_a[i].get(@solnic)
197
+ #end
198
+
199
+ # #key returns an array even though there's only one value.
200
+ @attributes[relationship.foreign_key] = @solnic.key.first
201
+
202
+ @return = @user.__send__(method, @attributes)
203
+ end
204
+
205
+ it 'should return true' do
206
+ expect(@return).to be true
207
+ end
208
+
209
+ it 'should update attributes of Resource' do
210
+ @attributes.each { |key, value| expect(@user.__send__(key)).to eq(value) }
211
+ end
212
+
213
+ it 'should persist the changes' do
214
+ resource = @user_model.get(@user.key)
215
+ @attributes.each { |key, value| expect(resource.__send__(key)).to eq(value) }
216
+ end
217
+
218
+ it 'should return correct parent' do
219
+ resource = @user_model.get(@user.key)
220
+ expect(resource.referrer).to eq(@solnic)
221
+ end
222
+ end
223
+ end
224
+
225
+ describe '#attribute_get' do
226
+ subject { object.attribute_get(name) }
227
+
228
+ let(:object) { @user }
229
+
230
+ context 'with a known property' do
231
+ let(:name) { :name }
232
+
233
+ it 'returns the attribute value' do
234
+ is_expected.to eq('dbussink')
235
+ end
236
+ end
237
+
238
+ context 'with an unknown property' do
239
+ let(:name) { :unknown }
240
+
241
+ it 'returns nil' do
242
+ is_expected.to be_nil
243
+ end
244
+ end
245
+ end
246
+
247
+ describe '#attribute_set' do
248
+ subject { object.attribute_set(name, value) }
249
+
250
+ let(:object) { @user }
251
+
252
+ context 'with a known property' do
253
+ let(:name) { :name }
254
+ let(:value) { 'dkubb' }
255
+
256
+ it 'sets the attribute' do
257
+ expect { subject }.to change { object.name }.from('dbussink').to('dkubb')
258
+ end
259
+
260
+ it 'makes the object dirty' do
261
+ expect { subject }.to change { object.dirty? }.from(false).to(true)
262
+ end
263
+ end
264
+
265
+ context 'with an unknown property' do
266
+ let(:name) { :unknown }
267
+ let(:value) { double('Unknown Value') }
268
+
269
+ it 'does not set the attribute' do
270
+ expect { subject }.to_not change { object.attributes.dup }
271
+ end
272
+
273
+ it 'does not make the object dirty' do
274
+ expect { subject }.to_not change { object.dirty? }
275
+ end
276
+ end
277
+ end
278
+ end