ardm 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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