resource_model 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e75b1686bd2c25fbe1ed8b41081a3653e7d7f4ec
4
+ data.tar.gz: 6e43b8d87d5057e7b5365b35f1c24470ed7517f9
5
+ SHA512:
6
+ metadata.gz: b843e35b9a1430728e86ae09f221450b797b924cf2f9260675404494e1b46ca6e36167210a28a47e5e57109ac3c86c6c57de35b8d67c41ae8eee41b2adcb3598
7
+ data.tar.gz: 1b65fba097a4bf5b3919fed6127b9250b2e1a54b879d9b66734b246998d3ae6657ed6aef9f86a69b7d4454a04e578b54c38cea71d1ab88808f00561c72f1b464
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in resource_model.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 James Coleman
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # ResourceModel
2
+
3
+ This code was extracted from a real-world project. While you may browse and use the code contained here, there isn't currently good documentation, example code, or any tests. All of these should follow at some point.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'resource_model'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install resource_model
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/resource_model/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,7 @@
1
+ require "resource_model/version"
2
+
3
+ module ResourceModel
4
+ # Your code goes here...
5
+ end
6
+
7
+ require "resource_model/base"
@@ -0,0 +1,550 @@
1
+ class ResourceModel::Base
2
+
3
+ extend ActiveModel::Callbacks
4
+ extend ActiveModel::Naming
5
+ include ActiveModel::Validations
6
+ include ActiveModel::Validations::Callbacks
7
+ include ActiveModel::Conversion
8
+
9
+ def self.model_name
10
+ ActiveModel::Name.new(self, nil, self.name)
11
+ end
12
+
13
+ def self.view_template
14
+ raise NotImplementedError
15
+ end
16
+
17
+ def persisted?
18
+ self.respond_to?(:id) && self.id.present?
19
+ end
20
+
21
+ @associated_resource_model_attributes = []
22
+ class << self; attr_reader :associated_resource_model_attributes; end
23
+
24
+ def self.has_associated_resource_model(attribute_name, options={})
25
+ raise ArgumentError, "Expected `#{attribute_name}` to be an instance of Symbol" unless attribute_name.is_a?(Symbol)
26
+ if self.associated_resource_model_attributes.include?(attribute_name)
27
+ raise ArgumentError, "Already contains associated resource model named `#{attribute_name}`"
28
+ else
29
+ @associated_resource_model_attributes << attribute_name
30
+ class_name = options[:class_name] || "::#{attribute_name.to_s.camelcase}"
31
+ self.class_eval <<-eos
32
+ attr_reader :#{attribute_name}
33
+ def #{attribute_name}=(model)
34
+ raise ArgumentError, 'Expected instance of `#{class_name}`' unless model.nil? || model.is_a?(#{class_name})
35
+ @#{attribute_name}_attributes = nil
36
+ @#{attribute_name} = model
37
+ end
38
+
39
+ def #{attribute_name}_attributes=(attributes)
40
+ if attributes
41
+ model = #{class_name}.new(attributes)
42
+ self.#{attribute_name} = model
43
+ else
44
+ self.#{attribute_name} = nil
45
+ end
46
+ @#{attribute_name}_attributes = attributes
47
+ end
48
+
49
+ validate do
50
+ if self.#{attribute_name} && !self.#{attribute_name}.valid?
51
+ self.errors.add(:#{attribute_name}, :invalid)
52
+ end
53
+ end
54
+ eos
55
+ end
56
+ end
57
+
58
+ @associated_resource_model_collection_attributes = []
59
+ class << self; attr_reader :associated_resource_model_collection_attributes; end
60
+
61
+ def self.has_associated_resource_model_collection(attribute_name, options={})
62
+ raise ArgumentError, "Expected `#{attribute_name}` to be an instance of Symbol" unless attribute_name.is_a?(Symbol)
63
+ if self.associated_resource_model_collection_attributes.include?(attribute_name)
64
+ raise ArgumentError, "Already contains associated resource model collection named `#{attribute_name}`"
65
+ else
66
+ @associated_resource_model_collection_attributes << attribute_name
67
+ class_name = options[:class_name] || "::#{attribute_name.to_s.singularize.camelcase}"
68
+ self.class_eval <<-eos
69
+ attr_reader :#{attribute_name}
70
+ def #{attribute_name}=(models)
71
+ case models
72
+ when nil
73
+ @#{attribute_name} = []
74
+ when Array
75
+ models.each do |model|
76
+ unless model.is_a?(#{class_name})
77
+ raise ArgumentError, "Assignment of collection to #{attribute_name} contained invalid type \#{model.class.name}; expected only instances of #{class_name}"
78
+ end
79
+ end
80
+ @#{attribute_name} = models
81
+ else
82
+ if models.respond_to?(:to_a)
83
+ self.#{attribute_name} = models.to_a
84
+ else
85
+ raise ArgumentError, 'Expected instance of array'
86
+ end
87
+ end
88
+ end
89
+
90
+ def #{attribute_name}_attributes=(attributes={})
91
+ if attributes
92
+ self.#{attribute_name} = attributes.collect do |(k, model_attributes)|
93
+ #{class_name}.new(model_attributes)
94
+ end
95
+ else
96
+ self.#{attribute_name} = []
97
+ end
98
+ end
99
+
100
+ validate do
101
+ if !self.#{attribute_name}.inject(true) { |valid, model| model.valid? && valid }
102
+ self.errors.add(:#{attribute_name}, :invalid)
103
+ end
104
+ end
105
+ eos
106
+ end
107
+ end
108
+
109
+ @associated_model_attributes = []
110
+ class << self; attr_reader :associated_model_attributes; end
111
+
112
+ def self.has_associated_model(attribute_name, options={}) # accepts_nested_attributes: nil
113
+ raise ArgumentError, "Expected `#{attribute_name}` to be an instance of Symbol" unless attribute_name.is_a?(Symbol)
114
+ if self.associated_model_attributes.include?(attribute_name)
115
+ raise ArgumentError, "Already contains associated model named `#{attribute_name}`"
116
+ else
117
+ @associated_model_attributes << attribute_name
118
+ class_name = options[:class_name] || "::#{attribute_name.to_s.camelcase}"
119
+ self.class_eval <<-eos
120
+ attr_reader :#{attribute_name}, :#{attribute_name}_id
121
+ def #{attribute_name}=(model)
122
+ raise ArgumentError, 'Expected instance of `#{class_name}`' unless model.nil? || model.is_a?(#{class_name})
123
+ @#{attribute_name}_id = model.present? ? model.id : nil
124
+ @#{attribute_name} = model
125
+ end
126
+
127
+ def #{attribute_name}_id=(id)
128
+ if id.present?
129
+ scope = #{class_name}.where(id: id)
130
+ eager_loads = #{options[:eager_load].inspect}
131
+ if eager_loads
132
+ scope = scope.eager_load(eager_loads)
133
+ end
134
+ self.#{attribute_name} = scope.first!
135
+ else
136
+ self.#{attribute_name} = nil
137
+ end
138
+ end
139
+ eos
140
+ end
141
+ end
142
+
143
+ @associated_model_collection_attributes = []
144
+ class << self; attr_reader :associated_model_collection_attributes; end
145
+
146
+ def self.has_associated_model_collection(attribute_name, class_name: nil, unique: true)
147
+ raise ArgumentError, "Expected `#{attribute_name}` to be an instance of Symbol" unless attribute_name.is_a?(Symbol)
148
+ if self.associated_model_collection_attributes.include?(attribute_name)
149
+ raise ArgumentError, "Already contains associated model collection named `#{attribute_name}`"
150
+ else
151
+ @associated_model_collection_attributes << attribute_name
152
+ class_name ||= "::#{attribute_name.to_s.singularize.camelcase}"
153
+ self.class_eval <<-eos
154
+ attr_reader :#{attribute_name}
155
+ def #{attribute_name}_ids
156
+ self.#{attribute_name}.collect { |model| model.id }
157
+ end
158
+
159
+ def #{attribute_name}=(models)
160
+ case models
161
+ when nil
162
+ @#{attribute_name} = []
163
+ when Array
164
+ models.each do |model|
165
+ unless model.is_a?(#{class_name})
166
+ raise ArgumentError, "Assignment of collection to #{attribute_name} contained invalid type \#{model.class.name}; expected only instances of #{class_name}"
167
+ end
168
+ end
169
+ @#{attribute_name} = models
170
+ else
171
+ if models.respond_to?(:to_a)
172
+ self.#{attribute_name} = models.to_a
173
+ else
174
+ raise ArgumentError, 'Expected instance of array'
175
+ end
176
+ end
177
+ end
178
+
179
+ def #{attribute_name}_ids=(ids)
180
+ if ids.present?
181
+ ids = ids.collect do |i|
182
+ unless i.is_a?(Integer) || (i.is_a?(String) && i =~ /\\A\\s*\\d+\\s*\\Z/)
183
+ raise ArgumentError, "Assignment of collection to #{attribute_name}_ids contained value (\#{i}) not an integer or stringified integer"
184
+ end
185
+ i.to_i
186
+ end#{unique ? '.uniq' : ''}
187
+ self.#{attribute_name} = #{class_name}.where(id: ids).to_a
188
+ else
189
+ self.#{attribute_name} = []
190
+ end
191
+ end
192
+ eos
193
+ end
194
+ end
195
+
196
+ @boolean_attributes = []
197
+ class << self; attr_reader :boolean_attributes; end
198
+
199
+ def self.boolean_accessor(attribute_name)
200
+ raise ArgumentError, "Expected `#{attribute_name}` to be an instance of Symbol" unless attribute_name.is_a?(Symbol)
201
+ if self.boolean_attributes.include?(attribute_name)
202
+ raise ArgumentError, "Already contains a boolean accessor named `#{attribute_name}`"
203
+ else
204
+ @boolean_attributes << attribute_name
205
+ self.class_eval <<-eos
206
+ attr_reader :#{attribute_name}
207
+ def #{attribute_name}=(value)
208
+ case value
209
+ when nil
210
+ @#{attribute_name} = nil
211
+ when TrueClass, FalseClass
212
+ @#{attribute_name} = value
213
+ else
214
+ @#{attribute_name} = value.present? ? ['1', 1, 'true', 't'].include?(value) : nil
215
+ end
216
+ end
217
+ eos
218
+ end
219
+ end
220
+
221
+ @integer_attributes = []
222
+ class << self; attr_reader :integer_attributes; end
223
+
224
+ def self.integer_accessor(attribute_name)
225
+ raise ArgumentError, "Expected `#{attribute_name}` to be an instance of Symbol" unless attribute_name.is_a?(Symbol)
226
+ if self.integer_attributes.include?(attribute_name)
227
+ raise ArgumentError, "Already contains a integer accessor named `#{attribute_name}`"
228
+ else
229
+ @integer_attributes << attribute_name
230
+ self.class_eval <<-eos
231
+ attr_reader :#{attribute_name}
232
+ attr_reader :#{attribute_name}_unconverted_value
233
+ def #{attribute_name}=(value)
234
+ @#{attribute_name}_unconverted_value = value
235
+ @#{attribute_name} = value.present? && value.to_s =~ /\\A\\s*\\-?\\d+\\s*\\Z/ ? value.to_i : nil
236
+ end
237
+ validate do
238
+ if self.#{attribute_name}_unconverted_value.present? != self.#{attribute_name}.present?
239
+ self.errors.add(:#{attribute_name}, :not_an_integer)
240
+ end
241
+ end
242
+ eos
243
+ end
244
+ end
245
+
246
+ @decimal_attributes = []
247
+ class << self; attr_reader :decimal_attributes; end
248
+
249
+ def self.decimal_accessor(attribute_name, options={})
250
+ raise ArgumentError, "Expected `#{attribute_name}` to be an instance of Symbol" unless attribute_name.is_a?(Symbol)
251
+ if self.decimal_attributes.include?(attribute_name)
252
+ raise ArgumentError, "Already contains a decimal accessor named `#{attribute_name}`"
253
+ else
254
+ decimal_regex = /\A\s*[+-]?\s*\d*(\d,\d)*\d*\.?\d*\s*\Z/
255
+ @decimal_attributes << attribute_name
256
+ self.class_eval <<-eos
257
+ attr_reader :#{attribute_name}
258
+ attr_reader :#{attribute_name}_unconverted_value
259
+ def #{attribute_name}=(value)
260
+ @#{attribute_name}_unconverted_value = value
261
+ @#{attribute_name} = value.present? && value.to_s =~ #{decimal_regex.inspect} ? BigDecimal.new(value.to_s.gsub(/\\s|[,]/, '')) : nil
262
+ end
263
+ validate do
264
+ if self.#{attribute_name}_unconverted_value.present? != self.#{attribute_name}.present?
265
+ self.errors.add(:#{attribute_name}, :not_a_number)
266
+ end
267
+ end
268
+ eos
269
+ end
270
+ end
271
+
272
+ @usd_attributes = []
273
+ class << self; attr_reader :usd_attributes; end
274
+
275
+ def self.usd_accessor(attribute_name, options={})
276
+ raise ArgumentError, "Expected `#{attribute_name}` to be an instance of Symbol" unless attribute_name.is_a?(Symbol)
277
+ if self.usd_attributes.include?(attribute_name)
278
+ raise ArgumentError, "Already contains a usd accessor named `#{attribute_name}`"
279
+ else
280
+ usd_regex = /\A\s*[+-]?\s*\$?\s*\d*(\d,\d)*\d*\.?\d*\s*\Z/
281
+ @usd_attributes << attribute_name
282
+ self.class_eval <<-eos
283
+ attr_reader :#{attribute_name}
284
+ attr_reader :#{attribute_name}_unconverted_value
285
+ def #{attribute_name}=(value)
286
+ @#{attribute_name}_unconverted_value = value
287
+ @#{attribute_name} = value.present? && value.to_s =~ #{usd_regex.inspect} ? BigDecimal.new(value.to_s.gsub(/[\$,]|\\s/, '')) : nil
288
+ end
289
+ validate do
290
+ if self.#{attribute_name}_unconverted_value.present? != self.#{attribute_name}.present?
291
+ self.errors.add(:#{attribute_name}, :invalid)
292
+ end
293
+ end
294
+ eos
295
+ end
296
+ end
297
+
298
+ @date_attributes = []
299
+ class << self; attr_reader :date_attributes; end
300
+
301
+ def self.date_accessor(attribute_name, options={})
302
+ raise ArgumentError, "Expected `#{attribute_name}` to be an instance of Symbol" unless attribute_name.is_a?(Symbol)
303
+ raise ArgumentError, "Expected options[:timezone]=`#{options[:timezone]}` to be an instance of Symbol, String, or Nil" unless options[:timezone].nil? || options[:timezone].is_a?(String) || options[:timezone].is_a?(Symbol)
304
+ if self.date_attributes.include?(attribute_name)
305
+ raise ArgumentError, "Already contains a date accessor named `#{attribute_name}`"
306
+ else
307
+ @date_attributes << attribute_name
308
+ self.class_eval <<-eos
309
+ attr_reader :#{attribute_name}
310
+ attr_reader :#{attribute_name}_unconverted_value
311
+ def #{attribute_name}=(value)
312
+ case value
313
+ when nil
314
+ @#{attribute_name}_unconverted_value = nil
315
+ @#{attribute_name} = nil
316
+ when Time, DateTime
317
+ @#{attribute_name}_unconverted_value = value
318
+ timezone = #{case options[:timezone]; when Symbol; "self.send(#{options[:timezone].inspect})"; when String; "ActiveSupport::TimeZone[#{options[:timezone].inspect}]"; else; "ActiveSupport::TimeZone['UTC']"; end}
319
+ @#{attribute_name} = ActiveSupport::TimeWithZone.new(nil, timezone, (value.is_a?(ActiveSupport::TimeWithZone) ? value.time : value))
320
+ when String
321
+ @#{attribute_name}_unconverted_value = value
322
+ parsed_date = DateTime.parse(value) rescue nil
323
+ timezone = #{case options[:timezone]; when Symbol; "self.send(#{options[:timezone].inspect})"; when String; "ActiveSupport::TimeZone[#{options[:timezone].inspect}]"; else; "ActiveSupport::TimeZone['UTC']"; end}
324
+ @#{attribute_name} = parsed_date ? ActiveSupport::TimeWithZone.new(nil, timezone, parsed_date) : nil
325
+ else
326
+ raise ArgumentError, 'Unexpected value passed to date_accessor #{attribute_name}; expected Time, String, or nil.'
327
+ end
328
+ end
329
+ validate do
330
+ if self.#{attribute_name}_unconverted_value.present? != self.#{attribute_name}.present?
331
+ self.errors.add(:#{attribute_name}, :invalid)
332
+ end
333
+ end
334
+ eos
335
+ end
336
+ end
337
+
338
+ @string_attributes = []
339
+ class << self; attr_reader :string_attributes; end
340
+
341
+ def self.string_accessor(attribute_name, options={})
342
+ raise ArgumentError, "Expected `#{attribute_name}` to be an instance of Symbol" unless attribute_name.is_a?(Symbol)
343
+ if self.string_attributes.include?(attribute_name)
344
+ raise ArgumentError, "Already contains a string accessor named `#{attribute_name}`"
345
+ else
346
+ @string_attributes << attribute_name
347
+ self.class_eval <<-eos
348
+ attr_reader :#{attribute_name}
349
+ def #{attribute_name}=(value)
350
+ if #{options[:strip] == true} && value
351
+ value = value.strip
352
+ end
353
+ value = nil unless value.present?
354
+ @#{attribute_name} = value
355
+ end
356
+ eos
357
+ end
358
+ end
359
+
360
+ @enum_attributes = []
361
+ class << self; attr_reader :enum_attributes; end
362
+
363
+ def self.enum_accessor(attribute_name, enums:, raise_error_on_set: false, allow_nil: true)
364
+ raise ArgumentError, "Expected `#{attribute_name}` to be an instance of Symbol" unless attribute_name.is_a?(Symbol)
365
+ raise ArgumentError, "Expected `enums`: `#{enums}` to be an instance of Array containing only instances of String" unless enums.is_a?(Array) && enums.all? { |e| e.is_a?(String) }
366
+ raise ArgumentError, "Expected `raise_error_on_set`: `#{raise_error_on_set}` to be an instance of TrueClass or FalseClass" unless raise_error_on_set.is_a?(TrueClass) || raise_error_on_set.is_a?(FalseClass)
367
+ raise ArgumentError, "Expected `allow_nil`: `#{allow_nil}` to be an instance of TrueClass or FalseClass" unless allow_nil.is_a?(TrueClass) || allow_nil.is_a?(FalseClass)
368
+
369
+ if self.enum_attributes.include?(attribute_name)
370
+ raise ArgumentError, "Already contains a enum accessor named `#{attribute_name}`"
371
+ else
372
+ @enum_attributes << attribute_name
373
+ self.class_eval <<-eos
374
+ attr_reader :#{attribute_name}
375
+ validates :#{attribute_name}, inclusion: {in: #{(enums + (allow_nil ? [nil] : [])).inspect}}
376
+ def #{attribute_name}=(value)
377
+ value = nil unless value.present?
378
+ if #{raise_error_on_set} && !((#{allow_nil} && value.nil?) || #{enums.inspect}.include?(value))
379
+ raise ArgumentError, 'Expected to receive valid enum string or nil.'
380
+ end
381
+ @#{attribute_name} = value
382
+ end
383
+ def #{attribute_name}_enums
384
+ #{enums.inspect}
385
+ end
386
+ eos
387
+ end
388
+ end
389
+
390
+ def self.inherited(klass)
391
+ klass.class_eval <<-eos
392
+ @associated_model_attributes = []
393
+ @associated_model_collection_attributes = []
394
+ @associated_resource_model_attributes = []
395
+ @associated_resource_model_collection_attributes = []
396
+ @boolean_attributes = []
397
+ @integer_attributes = []
398
+ @decimal_attributes = []
399
+ @usd_attributes = []
400
+ @date_attributes = []
401
+ @string_attributes = []
402
+ @enum_attributes = []
403
+ eos
404
+ class << klass
405
+ def associated_model_attributes
406
+ self.superclass.associated_model_attributes + @associated_model_attributes
407
+ end
408
+ def associated_model_collection_attributes
409
+ self.superclass.associated_model_collection_attributes + @associated_model_collection_attributes
410
+ end
411
+ def associated_resource_model_attributes
412
+ self.superclass.associated_resource_model_attributes + @associated_resource_model_attributes
413
+ end
414
+ def associated_resource_model_collection_attributes
415
+ self.superclass.associated_resource_model_collection_attributes + @associated_resource_model_collection_attributes
416
+ end
417
+ def boolean_attributes
418
+ self.superclass.boolean_attributes + @boolean_attributes
419
+ end
420
+ def integer_attributes
421
+ self.superclass.integer_attributes + @integer_attributes
422
+ end
423
+ def decimal_attributes
424
+ self.superclass.decimal_attributes + @decimal_attributes
425
+ end
426
+ def usd_attributes
427
+ self.superclass.usd_attributes + @usd_attributes
428
+ end
429
+ def date_attributes
430
+ self.superclass.date_attributes + @date_attributes
431
+ end
432
+ def string_attributes
433
+ self.superclass.date_attributes + @string_attributes
434
+ end
435
+ def enum_attributes
436
+ self.superclass.date_attributes + @enum_attributes
437
+ end
438
+ end
439
+ end
440
+
441
+ def initialize(attributes={})
442
+ self.attributes = attributes
443
+ end
444
+
445
+ def attributes=(attributes)
446
+ (
447
+ self.class.associated_resource_model_collection_attributes +
448
+ self.class.associated_model_collection_attributes
449
+ ).each do |attribute|
450
+ unless (value = self.send(attribute)).is_a?(Array) && value.present?
451
+ self.send("#{attribute}=", [])
452
+ end
453
+ end
454
+
455
+ if attributes.present?
456
+ attributes = attributes.dup
457
+
458
+ (
459
+ self.class.associated_resource_model_attributes +
460
+ self.class.associated_resource_model_collection_attributes
461
+ ).each do |attribute|
462
+ attribute_attributes_key = "#{attribute}_attributes".to_sym
463
+ if attributes.key?(attribute)
464
+ self.send("#{attribute}=", attributes.delete(attribute))
465
+ end
466
+ if attributes.key?(attribute_attributes_key)
467
+ self.send("#{attribute_attributes_key}=", attributes.delete(attribute_attributes_key))
468
+ end
469
+ end
470
+
471
+ self.class.associated_model_attributes.each do |attribute|
472
+ id_attribute = "#{attribute}_id".to_sym
473
+ if attributes.key?(attribute)
474
+ self.send("#{attribute}=", attributes.delete(attribute))
475
+ attributes.delete(id_attribute)
476
+ elsif attributes.key?(id_attribute)
477
+ self.send("#{id_attribute}=", attributes.delete(id_attribute))
478
+ end
479
+ end
480
+
481
+ self.class.associated_model_collection_attributes.each do |attribute|
482
+ ids_attribute = "#{attribute}_ids"
483
+ if attributes.key?(attribute)
484
+ self.send("#{attribute}=", attributes.delete(attribute))
485
+ attributes.delete(ids_attribute)
486
+ elsif attributes.key?(ids_attribute)
487
+ self.send("#{ids_attribute}=", attributes.delete(ids_attribute))
488
+ end
489
+ end
490
+
491
+ attributes.each do |name, value|
492
+ send("#{name}=", value)
493
+ end
494
+ end
495
+ end
496
+
497
+ def to_json_attributes
498
+ hash = {}
499
+ self.class.boolean_attributes.each do |attribute_name|
500
+ hash[attribute_name] = self.send(attribute_name)
501
+ end
502
+ self.class.integer_attributes.each do |attribute_name|
503
+ hash[attribute_name] = self.send(attribute_name)
504
+ end
505
+ self.class.decimal_attributes.each do |attribute_name|
506
+ hash[attribute_name] = self.send(attribute_name).andand.to_s
507
+ end
508
+ self.class.usd_attributes.each do |attribute_name|
509
+ hash[attribute_name] = self.send(attribute_name).andand.to_s
510
+ end
511
+ self.class.date_attributes.each do |attribute_name|
512
+ hash[attribute_name] = self.send(attribute_name).andand.iso8601
513
+ end
514
+ self.class.string_attributes.each do |attribute_name|
515
+ hash[attribute_name] = self.send(attribute_name)
516
+ end
517
+ self.class.enum_attributes.each do |attribute_name|
518
+ hash[attribute_name] = self.send(attribute_name)
519
+ end
520
+ self.class.associated_model_attributes.each do |attribute_name|
521
+ id_attribute_name = "#{attribute_name}_id"
522
+ value = self.send(id_attribute_name)
523
+ if value
524
+ hash[id_attribute_name.to_sym] = value
525
+ end
526
+ end
527
+ self.class.associated_model_collection_attributes.each do |attribute_name|
528
+ ids_attribute_name = "#{attribute_name}_ids"
529
+ value = self.send(ids_attribute_name)
530
+ if value
531
+ hash[ids_attribute_name] = value
532
+ end
533
+ end
534
+ self.class.associated_resource_model_attributes.each do |attribute_name|
535
+ value = self.send(attribute_name)
536
+ if value
537
+ hash["#{attribute_name}_attributes".to_sym] = value.to_json_attributes
538
+ end
539
+ end
540
+ self.class.associated_resource_model_collection_attributes.each do |attribute_name|
541
+ hash["#{attribute_name}_attributes".to_sym] = self.send(attribute_name).inject({}) do |sub_hash, item|
542
+ sub_hash[sub_hash.size] = item.to_json_attributes
543
+ sub_hash
544
+ end
545
+ end
546
+
547
+ hash
548
+ end
549
+
550
+ end
@@ -0,0 +1,3 @@
1
+ module ResourceModel
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'resource_model/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "resource_model"
8
+ spec.version = ResourceModel::VERSION
9
+ spec.authors = ["James Coleman"]
10
+ spec.email = ["jtc331@gmail.com"]
11
+ spec.summary = %q{Smart models to back your resources actions.}
12
+ spec.description = %q{All of the goodness of ActiveModel (validations, callbacks, etc.) along with declarative typed accessors, JSON serialization, and more.}
13
+ spec.homepage = "https://github.com/jcoleman/resource_model"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.add_dependency "activerecord", "~> 4.0"
25
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resource_model
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - James Coleman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: activerecord
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '4.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '4.0'
55
+ description: All of the goodness of ActiveModel (validations, callbacks, etc.) along
56
+ with declarative typed accessors, JSON serialization, and more.
57
+ email:
58
+ - jtc331@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/resource_model.rb
69
+ - lib/resource_model/base.rb
70
+ - lib/resource_model/version.rb
71
+ - resource_model.gemspec
72
+ homepage: https://github.com/jcoleman/resource_model
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.4.5
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Smart models to back your resources actions.
96
+ test_files: []