hash_attributes 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +26 -0
  4. data/Rakefile +20 -0
  5. data/lib/core_ext/active_record_relation_extend.rb +23 -0
  6. data/lib/hash_attributes.rb +4 -0
  7. data/lib/hash_attributes/date_time_serializer.rb +30 -0
  8. data/lib/hash_attributes/hash_attributes.rb +357 -0
  9. data/lib/hash_attributes/version.rb +3 -0
  10. data/spec/concerns/hash_attributes_spec.rb +645 -0
  11. data/spec/dummy/Rakefile +6 -0
  12. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  13. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  14. data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
  15. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  16. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  17. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  18. data/spec/dummy/bin/bundle +3 -0
  19. data/spec/dummy/bin/rails +4 -0
  20. data/spec/dummy/bin/rake +4 -0
  21. data/spec/dummy/config.ru +4 -0
  22. data/spec/dummy/config/application.rb +30 -0
  23. data/spec/dummy/config/boot.rb +5 -0
  24. data/spec/dummy/config/database.yml +25 -0
  25. data/spec/dummy/config/environment.rb +5 -0
  26. data/spec/dummy/config/environments/development.rb +29 -0
  27. data/spec/dummy/config/environments/production.rb +80 -0
  28. data/spec/dummy/config/environments/test.rb +36 -0
  29. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  30. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  31. data/spec/dummy/config/initializers/inflections.rb +16 -0
  32. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  33. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  34. data/spec/dummy/config/initializers/session_store.rb +3 -0
  35. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  36. data/spec/dummy/config/locales/en.yml +23 -0
  37. data/spec/dummy/config/routes.rb +56 -0
  38. data/spec/dummy/db/test.sqlite3 +0 -0
  39. data/spec/dummy/public/404.html +58 -0
  40. data/spec/dummy/public/422.html +58 -0
  41. data/spec/dummy/public/500.html +57 -0
  42. data/spec/dummy/public/favicon.ico +0 -0
  43. data/spec/spec_helper.rb +52 -0
  44. metadata +145 -0
@@ -0,0 +1,3 @@
1
+ module HashAttributes
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,645 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Hash Attributes" do
4
+ before(:each) do
5
+ # path = File.dirname(__FILE__) + "/test.sqlite3"
6
+ # File.delete(path) if File.exist?(path)
7
+ # ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: path)
8
+
9
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
10
+ ActiveRecord::Base.connection.create_table :models do |table|
11
+ table.text :__hash_column
12
+ table.integer :length
13
+ end
14
+ end
15
+
16
+ let(:model) do
17
+ model = Class.new(ActiveRecord::Base) do
18
+ include HashAttributes
19
+ serialize :__hash_column, Hash
20
+ self.table_name = "models"
21
+ end
22
+ Object.const_set("Model" + SecureRandom.uuid.gsub('-', ''), model)
23
+ end
24
+
25
+ context "class methods", :focus do
26
+ subject { model }
27
+
28
+ its(:hash_column) { should == "__hash_column" }
29
+
30
+ context "change hash_column" do
31
+ let(:alternative_name) { "__alternative_hash_column" }
32
+ before do
33
+ model.hash_column = alternative_name
34
+ end
35
+
36
+ its(:hash_column) { should == alternative_name}
37
+
38
+ it "should not accept blank" do
39
+ expect { subject.hash_column = "" }.to raise_error(ArgumentError)
40
+ end
41
+ end
42
+
43
+ context "extract_attribute_name" do
44
+ it { subject.extract_attribute_name("id").should == "id" }
45
+ it { subject.extract_attribute_name("#").should be_nil }
46
+ it { subject.extract_attribute_name("name").should == "name" }
47
+ it { subject.extract_attribute_name("name=").should == "name" }
48
+ it { subject.extract_attribute_name("name_before_type_cast").should == "name" }
49
+ it { subject.extract_attribute_name("name?").should == "name" }
50
+ it { subject.extract_attribute_name("name_changed?").should == "name" }
51
+ it { subject.extract_attribute_name("name_was").should == "name" }
52
+ it { subject.extract_attribute_name("name_change").should == "name" }
53
+ it { subject.extract_attribute_name("name_will_change!").should == "name" }
54
+ it { subject.extract_attribute_name("name_unknown").should == "name_unknown" }
55
+ end
56
+
57
+ context "is_valid_attribute_name?" do
58
+ it { subject.is_valid_attribute_name?("id").should be_true }
59
+ it { subject.is_valid_attribute_name?("#").should be_false }
60
+ it { subject.is_valid_attribute_name?("name").should be_true }
61
+ it { subject.is_valid_attribute_name?("name=").should be_false }
62
+ it { subject.is_valid_attribute_name?("name_before_type_cast").should be_false }
63
+ it { subject.is_valid_attribute_name?("name?").should be_false }
64
+ it { subject.is_valid_attribute_name?("name_changed?").should be_false }
65
+ it { subject.is_valid_attribute_name?("name_was").should be_false }
66
+ it { subject.is_valid_attribute_name?("name_change").should be_false }
67
+ it { subject.is_valid_attribute_name?("name_will_change!").should be_false }
68
+ end
69
+
70
+ context "serialize_hash_column_attribute" do
71
+ let(:datetime_str) { DateTime.now.in_time_zone.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
72
+ let(:datetime) { DateTime.parse(datetime_str) }
73
+ let(:time_str) { datetime.to_time.in_time_zone.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
74
+ let(:time) { datetime.to_time }
75
+ let(:date_str) { datetime.to_date.in_time_zone.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
76
+ let(:date) { datetime.to_date }
77
+
78
+ it { subject.serialize_hash_column_attribute("attr", datetime).should == datetime_str }
79
+ it { subject.serialize_hash_column_attribute("attr", {datetime: datetime}).should == {"datetime" => datetime_str} }
80
+ it { subject.serialize_hash_column_attribute("attr", {datetime: {datetime: datetime}}).should == {"datetime" => {"datetime" => datetime_str}} }
81
+ it { subject.serialize_hash_column_attribute("attr", [datetime]).should == [datetime_str] }
82
+ it { subject.serialize_hash_column_attribute("attr", [[datetime]]).should == [[datetime_str]] }
83
+ it { subject.serialize_hash_column_attribute("attr", [{datetime: datetime}]).should == [{"datetime" => datetime_str}] }
84
+ it { subject.serialize_hash_column_attribute("attr", time).should == time_str }
85
+ it { subject.serialize_hash_column_attribute("attr", {time: time}).should == {"time" => time_str} }
86
+ it { subject.serialize_hash_column_attribute("attr", {time: {time: time}}).should == {"time" => {"time" => time_str}} }
87
+ it { subject.serialize_hash_column_attribute("attr", [time]).should == [time_str] }
88
+ it { subject.serialize_hash_column_attribute("attr", [[time]]).should == [[time_str]] }
89
+ it { subject.serialize_hash_column_attribute("attr", [{time: time}]).should == [{"time" => time_str}] }
90
+ it { subject.serialize_hash_column_attribute("attr", date).should == date_str }
91
+ it { subject.serialize_hash_column_attribute("attr", {date: date}).should == {"date" => date_str} }
92
+ it { subject.serialize_hash_column_attribute("attr", {date: {date: date}}).should == {"date" => {"date" => date_str}} }
93
+ it { subject.serialize_hash_column_attribute("attr", [date]).should == [date_str] }
94
+ it { subject.serialize_hash_column_attribute("attr", [[date]]).should == [[date_str]] }
95
+ it { subject.serialize_hash_column_attribute("attr", [{date: date}]).should == [{"date" => date_str}] }
96
+ end
97
+
98
+ context "deserialize_hash_column_attribute" do
99
+ let(:datetime_str) { DateTime.now.in_time_zone.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
100
+ let(:datetime) { DateTime.parse(datetime_str) }
101
+ let(:time_str) { datetime.to_time.in_time_zone.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
102
+ let(:time) { datetime.to_time }
103
+ let(:date_str) { datetime.to_date.in_time_zone.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
104
+ let(:date) { datetime.to_date }
105
+
106
+ it { subject.deserialize_hash_column_attribute("attr", datetime_str).should == datetime }
107
+ it { subject.deserialize_hash_column_attribute("attr", {datetime: datetime_str}).should == {"datetime" => datetime} }
108
+ it { subject.deserialize_hash_column_attribute("attr", {datetime: {datetime: datetime_str}}).should == {"datetime" => {"datetime" => datetime}} }
109
+ it { subject.deserialize_hash_column_attribute("attr", [datetime_str]).should == [datetime] }
110
+ it { subject.deserialize_hash_column_attribute("attr", [[datetime_str]]).should == [[datetime]] }
111
+ it { subject.deserialize_hash_column_attribute("attr", [{datetime: datetime_str}]).should == [{"datetime" => datetime}] }
112
+ it { subject.deserialize_hash_column_attribute("attr", time_str).should == time }
113
+ it { subject.deserialize_hash_column_attribute("attr", {time: time_str}).should == {"time" => time} }
114
+ it { subject.deserialize_hash_column_attribute("attr", {time: {time: time_str}}).should == {"time" => {"time" => time}} }
115
+ it { subject.deserialize_hash_column_attribute("attr", [time_str]).should == [time] }
116
+ it { subject.deserialize_hash_column_attribute("attr", [[time_str]]).should == [[time]] }
117
+ it { subject.deserialize_hash_column_attribute("attr", [{time: time_str}]).should == [{"time" => time}] }
118
+ it { subject.deserialize_hash_column_attribute("attr", date_str).should == date }
119
+ it { subject.deserialize_hash_column_attribute("attr", {date: date_str}).should == {"date" => date} }
120
+ it { subject.deserialize_hash_column_attribute("attr", {date: {date: date_str}}).should == {"date" => {"date" => date}} }
121
+ it { subject.deserialize_hash_column_attribute("attr", [date_str]).should == [date] }
122
+ it { subject.deserialize_hash_column_attribute("attr", [[date_str]]).should == [[date]] }
123
+ it { subject.deserialize_hash_column_attribute("attr", [{date: date_str}]).should == [{"date" => date}] }
124
+ end
125
+
126
+ context "define_hash_column_attribute" do
127
+ before do
128
+ subject.define_hash_column_attribute("name")
129
+ end
130
+
131
+ it { expect { subject.define_hash_column_attribute("#") }.to raise_error(ArgumentError) }
132
+ it { subject.method_defined?("name").should be_true }
133
+ it { subject.method_defined?("name=").should be_true }
134
+ it { subject.method_defined?("name_before_type_cast").should be_true }
135
+ it { subject.method_defined?("name?").should be_true }
136
+ it { subject.method_defined?("name_changed?").should be_true }
137
+ it { subject.method_defined?("name_was").should be_true }
138
+ it { subject.method_defined?("name_change").should be_true }
139
+ it { subject.method_defined?("name_will_change!").should be_true }
140
+
141
+ context "undefine_attribute_method" do
142
+ before do
143
+ subject.undefine_attribute_method("name")
144
+ end
145
+
146
+ it { subject.method_defined?("name").should be_false }
147
+ it { subject.method_defined?("name=").should be_false }
148
+ it { subject.method_defined?("name_before_type_cast").should be_false }
149
+ it { subject.method_defined?("name?").should be_false }
150
+ it { subject.method_defined?("name_changed?").should be_false }
151
+ it { subject.method_defined?("name_was").should be_false }
152
+ it { subject.method_defined?("name_change").should be_false }
153
+ it { subject.method_defined?("name_will_change!").should be_false }
154
+ end
155
+
156
+ context "attribute setter and getter already exist" do
157
+ before do
158
+ subject.class_eval <<-RUBY
159
+ def name
160
+ nil
161
+ end
162
+
163
+ def name=(value)
164
+ value
165
+ end
166
+ RUBY
167
+ subject.define_hash_column_attribute("name")
168
+ end
169
+
170
+ it { subject.method_defined?("name").should be_true }
171
+ it { subject.method_defined?("name=").should be_true }
172
+ it { subject.method_defined?("name_before_type_cast").should be_true }
173
+ it { subject.method_defined?("name?").should be_true }
174
+ it { subject.method_defined?("name_changed?").should be_true }
175
+ it { subject.method_defined?("name_was").should be_true }
176
+ it { subject.method_defined?("name_change").should be_true }
177
+ it { subject.method_defined?("name_will_change!").should be_true }
178
+ end
179
+ end
180
+ end
181
+
182
+ context "initialize", :focus do
183
+ context "ordinary attribute" do
184
+ context "and with no argument" do
185
+ subject do
186
+ record = model.create
187
+ record.length = 123
188
+ record
189
+ end
190
+ its(:length) { should == 123 }
191
+ end
192
+
193
+ context "and with argument" do
194
+ subject do
195
+ record = model.create(length: 123)
196
+ record.length = 456
197
+ record.save
198
+ record
199
+ end
200
+ its(:length) { should == 456 }
201
+ end
202
+ end
203
+
204
+ context "with block" do
205
+ context "and no arguments" do
206
+ subject do
207
+ model.create do |record|
208
+ record.length = 123
209
+ record.name = "Jacob"
210
+ end
211
+ end
212
+
213
+ its(:length) { should == 123 }
214
+ its(:name) { should == "Jacob" }
215
+ end
216
+
217
+ context "and arguments" do
218
+ subject do
219
+ model.create(length: 123) do |record|
220
+ record.name = "Jacob"
221
+ end
222
+ end
223
+
224
+ its(:length) { should == 123 }
225
+ its(:name) { should == "Jacob" }
226
+ end
227
+
228
+ context "and overwrite arguments" do
229
+ subject do
230
+ model.create(length: 123) do |record|
231
+ record.length = 456
232
+ record.name = "Jacob"
233
+ end
234
+ end
235
+
236
+ its(:length) { should == 456 }
237
+ its(:name) { should == "Jacob" }
238
+ end
239
+ end
240
+ end
241
+
242
+ context "is_valid_hash_column_attribute_name?", :focus do
243
+ subject { model.create({"name" => "Jacob"}) }
244
+ it { subject.is_valid_hash_column_attribute_name?(model.primary_key).should be_false }
245
+ it { subject.is_valid_hash_column_attribute_name?(model.hash_column).should be_false }
246
+ it { subject.is_valid_hash_column_attribute_name?(:length).should be_false }
247
+ it { subject.is_valid_hash_column_attribute_name?("#").should be_false }
248
+ it { subject.is_valid_hash_column_attribute_name?(:name).should be_true }
249
+ it { subject.is_valid_hash_column_attribute_name?(:name=).should be_false }
250
+ it { subject.is_valid_hash_column_attribute_name?(:name_before_type_cast).should be_false }
251
+ it { subject.is_valid_hash_column_attribute_name?(:name?).should be_false }
252
+ it { subject.is_valid_hash_column_attribute_name?(:name_changed?).should be_false }
253
+ it { subject.is_valid_hash_column_attribute_name?(:name_was).should be_false }
254
+ it { subject.is_valid_hash_column_attribute_name?(:name_change).should be_false }
255
+ it { subject.is_valid_hash_column_attribute_name?(:name_will_change!).should be_false }
256
+ it { subject.is_valid_hash_column_attribute_name?(:lucky_number).should be_true }
257
+ it { subject.is_valid_hash_column_attribute_name?(:lucky_number=).should be_false }
258
+ it { subject.is_valid_hash_column_attribute_name?(:lucky_number_before_type_cast).should be_false }
259
+ it { subject.is_valid_hash_column_attribute_name?(:lucky_number?).should be_false }
260
+ it { subject.is_valid_hash_column_attribute_name?(:lucky_number_changed?).should be_false }
261
+ it { subject.is_valid_hash_column_attribute_name?(:lucky_number_was).should be_false }
262
+ it { subject.is_valid_hash_column_attribute_name?(:lucky_number_change).should be_false }
263
+ it { subject.is_valid_hash_column_attribute_name?(:lucky_number_will_change!).should be_false }
264
+ end
265
+
266
+ context "read_attribute", :focus do
267
+ subject { model.create({name: "Jacob", length: 123}) }
268
+
269
+ it { subject.read_attribute(:name).should == "Jacob" }
270
+ it { subject.read_attribute(:__hash_column).should == {"name" => "Jacob"} }
271
+ it { subject.read_attribute(:__hash_column).should be_a(ActiveSupport::HashWithIndifferentAccess) }
272
+ it { subject.read_attribute(:length).should == 123 }
273
+ it { subject.read_attribute(:lucky_number).should be_nil }
274
+ its(:name) { should == "Jacob" }
275
+ its(:__hash_column) { should == {"name" => "Jacob"} }
276
+ its(:__hash_column) { should be_a(ActiveSupport::HashWithIndifferentAccess) }
277
+ its(:length) { should == 123 }
278
+ its(:lucky_number) { should be_nil }
279
+ its([:name]) { should == "Jacob" }
280
+ its([:__hash_column]) { should == {"name" => "Jacob"} }
281
+ its([:__hash_column]) { should be_a(ActiveSupport::HashWithIndifferentAccess) }
282
+ its([:length]) { should == 123 }
283
+ its([:lucky_number]) { should be_nil }
284
+ its(["name"]) { should == "Jacob" }
285
+ its(["__hash_column"]) { should == {"name" => "Jacob"} }
286
+ its(["__hash_column"]) { should be_a(ActiveSupport::HashWithIndifferentAccess) }
287
+ its(["length"]) { should == 123 }
288
+ its(["lucky_number"]) { should be_nil }
289
+ end
290
+
291
+ context "read_hash_column_attribute", :focus do
292
+ subject { model.create({name: "Jacob", length: 123}) }
293
+
294
+ it { subject.read_hash_column_attribute(:name).should == "Jacob" }
295
+ it { subject.read_hash_column_attribute(:__hash_column).should be_nil }
296
+ it { subject.read_hash_column_attribute(:length).should be_nil }
297
+ it { subject.read_hash_column_attribute(:lucky_number).should be_nil }
298
+ end
299
+
300
+ context "write_attribute", :focus do
301
+ subject { model.create({name: "Jacob", length: 123}) }
302
+
303
+ it { subject.write_attribute(:name, "Martin").should == "Martin" }
304
+ it { subject.write_attribute(model.hash_column, {name: "Martin"}).should == {"name" => "Martin"} }
305
+ it { subject.write_attribute(model.hash_column, {name: "Martin"}).should be_a(ActiveSupport::HashWithIndifferentAccess) }
306
+ it { subject.write_attribute(model.hash_column, {lucky_number: 123}).should == {"lucky_number" => 123} }
307
+ it { subject.write_attribute(model.hash_column, {lucky_number: 123}).should be_a(ActiveSupport::HashWithIndifferentAccess) }
308
+ it { subject.write_attribute(:length, 456).should == 456 }
309
+ it { subject.write_attribute(:name, nil).should be_nil }
310
+ it { (subject[:name] = "Martin").should == "Martin" }
311
+ it { (subject[:__hash_column] = {name: "Martin"}).should == {name: "Martin"} }
312
+ it { (subject[:__hash_column] = {name: "Martin"}).should be_a(Hash) }
313
+ it { (subject[:__hash_column] = {lucky_number: 123}).should == {lucky_number: 123} }
314
+ it { (subject[:__hash_column] = {lucky_number: 123}).should be_a(Hash) }
315
+ it { (subject[:length] = 456).should == 456 }
316
+ it { (subject[:name] = nil).should be_nil }
317
+ end
318
+
319
+ context "write_hash_column_attribute", :focus do
320
+ subject { model.create({name: "Jacob", length: 123}) }
321
+
322
+ it { subject.write_hash_column_attribute(:name, "Martin").should == "Martin" }
323
+ it { subject.write_hash_column_attribute(model.hash_column, {name: "Martin"}).should == {name: "Martin"} }
324
+ it { subject.write_hash_column_attribute(model.hash_column, {lucky_number: 123}).should == {lucky_number: 123} }
325
+ it { subject.write_hash_column_attribute(:length, 456).should == 456 }
326
+ it { subject.write_hash_column_attribute(:name, nil).should be_nil }
327
+ end
328
+
329
+ context "read_attribute_before_type_cast", :focus do
330
+ let(:datetime_str) { DateTime.now.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
331
+ let(:datetime) { DateTime.parse(datetime_str) }
332
+
333
+ subject { model.create({datetime_str: datetime_str, datetime: datetime}) }
334
+
335
+ its(:datetime_str) { should == datetime }
336
+ its(:datetime) { should == datetime }
337
+ its(:datetime_str_before_type_cast) { should == datetime_str }
338
+ its(:datetime_before_type_cast) { should == datetime_str }
339
+
340
+ it { subject.read_attribute(:datetime_str).should == datetime }
341
+ it { subject.read_attribute(:datetime).should == datetime }
342
+ it { subject.read_hash_column_attribute(:datetime_str).should == datetime }
343
+ it { subject.read_hash_column_attribute(:datetime).should == datetime }
344
+ it { subject.read_attribute_before_type_cast(:datetime_str).should == datetime_str }
345
+ it { subject.read_attribute_before_type_cast(:datetime).should == datetime_str }
346
+ end
347
+
348
+ context "attributes_before_type_cast", :focus do
349
+ let(:datetime_str) { DateTime.now.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
350
+ let(:datetime) { DateTime.parse(datetime_str) }
351
+
352
+ subject { model.create({datetime_str: datetime_str, datetime: datetime}) }
353
+
354
+ its(:attributes_before_type_cast) { should == {"id"=>subject.id, "datetime_str"=>datetime_str, "datetime"=>datetime_str, "length"=>subject.length} }
355
+ end
356
+
357
+ context "query_attribute", :focus do
358
+ subject { model.create({name: "Jacob", length: 123}) }
359
+
360
+ its(:id?) { should be_true }
361
+ its(:name?) { should be_true }
362
+ its(:length?) { should be_true }
363
+ its(:__hash_column?) { should be_true }
364
+ its(:lucky_number?) { should be_true }
365
+ end
366
+
367
+ context "hash_column_attributes", :focus do
368
+ let(:datetime_str) { DateTime.now.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
369
+ let(:datetime) { DateTime.parse(datetime_str) }
370
+
371
+ subject { model.create({dates: {datetime_str: datetime_str, datetime: datetime}}) }
372
+
373
+ its(:hash_column_attributes) { should == {"dates" => {"datetime_str" => datetime, "datetime" => datetime}} }
374
+ end
375
+
376
+ context "hash_column_attribute_names", :focus do
377
+ let(:datetime_str) { DateTime.now.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
378
+ let(:datetime) { DateTime.parse(datetime_str) }
379
+
380
+ subject { model.create({name: "Jacob", lucky_number: 14}) }
381
+
382
+ its(:hash_column_attribute_names) { should == ["lucky_number", "name"] }
383
+ end
384
+
385
+ context "attribute_names", :focus do
386
+ subject { model.create({name: "Jacob", lucky_number: 14}) }
387
+
388
+ its(:attribute_names) { should == ["id", "length", "lucky_number", "name"] }
389
+ end
390
+
391
+ context "attributes", :focus do
392
+ subject { model.create({name: "Jacob", lucky_number: 14}) }
393
+
394
+ its(:attributes) { should == {"id"=>subject.id, "length"=>subject.length, "lucky_number"=>14, "name"=>"Jacob"} }
395
+ end
396
+
397
+ context "column_for_attribute", :focus do
398
+ subject { model.create({name: "Jacob"}) }
399
+
400
+ it { subject.column_for_attribute(:id).should be_a(ActiveRecord::ConnectionAdapters::Column) }
401
+ it { subject.column_for_attribute(:length).should be_a(ActiveRecord::ConnectionAdapters::Column) }
402
+ it { subject.column_for_attribute(:name).should be_nil }
403
+ it { subject.column_for_attribute(:lucky_number).should be_nil }
404
+ end
405
+
406
+ context "has_attribute?", :focus do
407
+ subject { model.create({name: "Jacob"}) }
408
+
409
+ it { subject.has_attribute?(:id).should be_true }
410
+ it { subject.has_attribute?(:length).should be_true }
411
+ it { subject.has_attribute?(:name).should be_true }
412
+ it { subject.has_attribute?(:lucky_number).should be_false }
413
+ end
414
+
415
+ context "assign_attributes", :focus do
416
+ subject do
417
+ record = model.create
418
+ record.reload
419
+ record.attributes = {name: "Jacob", length: 123}
420
+ record.save!
421
+ record
422
+ end
423
+
424
+ its(:name) { should == "Jacob" }
425
+ its(:length) { should == 123 }
426
+ end
427
+
428
+ context "to_h", :focus do
429
+ subject { model.create({"name" => "Jacob", "length" => 123}) }
430
+ its(:to_h) { should == {"id"=>subject.id, "name"=>"Jacob", "length"=>123} }
431
+ its(:to_h) { should be_a(ActiveSupport::HashWithIndifferentAccess) }
432
+ end
433
+
434
+ context "cache_key", :focus do
435
+ subject { model.create({"name" => "Jacob", "length" => 123}) }
436
+ its(:cache_key) { should == "#{model.name.underscore.dasherize}-#{subject.id}-version-#{Digest::MD5.hexdigest(subject.attributes.inspect)}" }
437
+ end
438
+
439
+ context "inspect", :focus do
440
+ subject { model.create({"name" => "Jacob", "length" => 123}) }
441
+ its(:inspect) { should == "#<#{subject.class.name} #{subject.attributes.map{ |k, v| "#{k}: #{v.inspect}" }.join(", ")}>" }
442
+ end
443
+
444
+ context "delete hash column attribute", :focus do
445
+ subject { model.create({"name" => "Jacob"}) }
446
+ it { subject.delete_hash_column_attribute(:name).should == "Jacob" }
447
+ it { subject.delete_hash_column_attribute(:lucky_number).should be_nil }
448
+
449
+ context "already deleted" do
450
+ before do
451
+ subject.delete_hash_column_attribute(:name)
452
+ end
453
+
454
+ it { subject.read_attribute(model.hash_column).should == {} }
455
+ it { subject.delete_hash_column_attribute(:name).should be_nil }
456
+ end
457
+ end
458
+
459
+ context "reload", :focus do
460
+ subject do
461
+ record = model.create({name: "Jacob"})
462
+ record.name = "Frida"
463
+ record.reload
464
+ record
465
+ end
466
+
467
+ its(:name) { should == "Jacob" }
468
+ its(:name_was) { should == "Jacob" }
469
+ its(:name_changed?) { should be_false }
470
+ end
471
+
472
+ context "dirty", :focus do
473
+ subject do
474
+ id = model.create({name: "Jacob"}).id
475
+ record = model.uncached { model.find(id) }
476
+ record.name = "Frida"
477
+ record
478
+ end
479
+
480
+ its(:name) { should == "Frida" }
481
+ its(:name_was) { should == "Jacob" }
482
+ its(:name_changed?) { should be_true }
483
+ end
484
+
485
+ context "attribute methods", :focus do
486
+ subject { model.create({"name" => "Jacob", "lucky_number" => 14}) }
487
+
488
+ its(:name) { should == "Jacob" }
489
+ its([:name]) { should == "Jacob" }
490
+ its(["name"]) { should == "Jacob" }
491
+ its(:lucky_number) { should == 14 }
492
+ its([:lucky_number]) { should == 14 }
493
+ its(["lucky_number"]) { should == 14 }
494
+ its(:name_changed?) { should be_false }
495
+ its(:lucky_number_changed?) { should be_false }
496
+ its(:name_was) { should == "Jacob" }
497
+ its(:lucky_number_was) { should == 14 }
498
+ its(:focusname_change) { should be_nil }
499
+ its(:lucky_number_change) { should be_nil }
500
+ its(:__hash_column) { should == {"name" => "Jacob", "lucky_number" => 14} }
501
+ its(:__hash_column_changed?) { should be_false }
502
+ its(:__hash_column_was) { should == {"name" => "Jacob", "lucky_number" => 14} }
503
+ its(:__hash_column_change) { should be_nil }
504
+
505
+ context "with changed value" do
506
+ before do
507
+ subject.name = "Martin"
508
+ end
509
+
510
+ its(:name) { should == "Martin" }
511
+ its([:name]) { should == "Martin" }
512
+ its(["name"]) { should == "Martin" }
513
+ its(:name_changed?) { should be_true }
514
+ its(:lucky_number_changed?) { should be_false }
515
+ its(:name_was) { should == "Jacob" }
516
+ its(:lucky_number_was) { should == 14 }
517
+ its(:name_change) { should == ["Jacob", "Martin"] }
518
+ its(:lucky_number_change) { should be_nil }
519
+ its(:__hash_column) { should == {"name" => "Martin", "lucky_number" => 14} }
520
+ its(:__hash_column_changed?) { should be_true }
521
+ its(:__hash_column_was) { should == {"name" => "Jacob", "lucky_number" => 14} }
522
+ its(:__hash_column_change) { should == [{"name" => "Jacob", "lucky_number" => 14}, {"name" => "Martin", "lucky_number" => 14}] }
523
+
524
+ context "saved" do
525
+ before do
526
+ subject.save
527
+ end
528
+
529
+ its(:name) { should == "Martin" }
530
+ its([:name]) { should == "Martin" }
531
+ its(["name"]) { should == "Martin" }
532
+ its(:lucky_number) { should == 14 }
533
+ its([:lucky_number]) { should == 14 }
534
+ its(["lucky_number"]) { should == 14 }
535
+ its(:name_changed?) { should be_false }
536
+ its(:lucky_number_changed?) { should be_false }
537
+ its(:name_was) { should == "Martin" }
538
+ its(:lucky_number_was) { should == 14 }
539
+ its(:name_change) { should be_nil }
540
+ its(:lucky_number_change) { should be_nil }
541
+ its(:__hash_column) { should == {"name" => "Martin", "lucky_number" => 14} }
542
+ its(:__hash_column_changed?) { should be_false }
543
+ its(:__hash_column_was) { should == {"name" => "Martin", "lucky_number" => 14} }
544
+ its(:__hash_column_change) { should be_nil }
545
+ end
546
+ end
547
+ end
548
+
549
+ context "time, date and datetime attributes", :focus do
550
+ let(:datetime_str) { DateTime.now.in_time_zone.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
551
+ let(:datetime) { DateTime.parse(datetime_str) }
552
+ let(:time_str) { datetime.to_time.in_time_zone.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
553
+ let(:time) { datetime.to_time }
554
+ let(:date_str) { datetime.to_date.in_time_zone.strftime('%Y-%m-%dT%H:%M:%S.%LZ') }
555
+ let(:date) { datetime.to_date }
556
+
557
+ subject do
558
+ record = model.create(datetime: datetime, time: time, date: date)
559
+ record.reload
560
+ record
561
+ end
562
+
563
+ its(:datetime) { should == datetime }
564
+ its(:time) { should == time }
565
+ its(:date) { should == date }
566
+
567
+ it { subject.__hash_column[:datetime].should == datetime_str }
568
+ it { subject.__hash_column[:time].should == time_str }
569
+ it { subject.__hash_column[:date].should == date_str }
570
+ end
571
+
572
+ context "respond_to?", :focus do
573
+ subject { model.create(name: "Jacob") }
574
+
575
+ it { subject.respond_to?("length").should be_true }
576
+ it { subject.respond_to?("length=").should be_true }
577
+ it { subject.respond_to?("length_before_type_cast").should be_true }
578
+ it { subject.respond_to?("length?").should be_true }
579
+ it { subject.respond_to?("length_changed?").should be_true }
580
+ it { subject.respond_to?("length_was").should be_true }
581
+ it { subject.respond_to?("length_change").should be_true }
582
+ it { subject.respond_to?("length_will_change!").should be_true }
583
+
584
+
585
+ it { subject.respond_to?("name").should be_true }
586
+ it { subject.respond_to?("name=").should be_true }
587
+ it { subject.respond_to?("name_before_type_cast").should be_true }
588
+ it { subject.respond_to?("name?").should be_true }
589
+ it { subject.respond_to?("name_changed?").should be_true }
590
+ it { subject.respond_to?("name_was").should be_true }
591
+ it { subject.respond_to?("name_change").should be_true }
592
+ it { subject.respond_to?("name_will_change!").should be_true }
593
+
594
+ it { subject.respond_to?("age").should be_false }
595
+ it { subject.respond_to?("age=").should be_false }
596
+ it { subject.respond_to?("age_before_type_cast").should be_false }
597
+ it { subject.respond_to?("age?").should be_false }
598
+ it { subject.respond_to?("age_changed?").should be_false }
599
+ it { subject.respond_to?("age_was").should be_false }
600
+ it { subject.respond_to?("age_change").should be_false }
601
+ it { subject.respond_to?("age_will_change!").should be_false }
602
+ end
603
+
604
+ context "update_attributes", :focus do
605
+ subject do
606
+ record = model.create
607
+ record.update_attributes(name: "Jacob", lucky_number: 14)
608
+ record
609
+ end
610
+
611
+ its(:name) { should == "Jacob" }
612
+ its(:lucky_number) { should == 14 }
613
+ end
614
+
615
+ context "update_attribute", :focus do
616
+ subject do
617
+ record = model.create
618
+ record.update_attribute(:name, "Jacob")
619
+ record
620
+ end
621
+
622
+ its(:name) { should == "Jacob" }
623
+ end
624
+
625
+ context "update_column", :focus do
626
+ subject do
627
+ record = model.create(id: 1)
628
+ record.reload
629
+ record.update_column(:name, "Jacob")
630
+ record
631
+ end
632
+
633
+ its(:name) { should == "Jacob" }
634
+ end
635
+
636
+ context "update_column", :focus do
637
+ subject do
638
+ id = model.create.id
639
+ model.update_all(name: "Jacob")
640
+ model.uncached { model.find(id) }
641
+ end
642
+
643
+ its(:name) { should == "Jacob" }
644
+ end
645
+ end