hash_attributes 1.0.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 (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