object_attorney 2.10.12 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +5 -13
  2. data/.gitignore +48 -17
  3. data/.rubocop.yml +19 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +4 -0
  6. data/Gemfile +0 -13
  7. data/Gemfile.lock +83 -0
  8. data/README.md +25 -18
  9. data/Rakefile +7 -16
  10. data/lib/object_attorney.rb +57 -44
  11. data/lib/object_attorney/accusation.rb +46 -0
  12. data/lib/object_attorney/allegation.rb +20 -0
  13. data/lib/object_attorney/base.rb +17 -0
  14. data/lib/object_attorney/class_methods.rb +50 -0
  15. data/lib/object_attorney/errors.rb +32 -0
  16. data/lib/object_attorney/helpers.rb +22 -21
  17. data/lib/object_attorney/validations/custom.rb +23 -0
  18. data/lib/object_attorney/version.rb +3 -1
  19. data/object_attorney.gemspec +24 -17
  20. data/spec/object_attorney/base_spec.rb +21 -0
  21. data/spec/object_attorney/custom_validation_spec.rb +60 -0
  22. data/spec/object_attorney/object_attorney_spec.rb +64 -0
  23. data/spec/spec_helper.rb +17 -56
  24. data/spec/support/post.rb +7 -0
  25. data/spec/support/user.rb +5 -0
  26. metadata +102 -127
  27. data/.rvmrc +0 -1
  28. data/Guardfile +0 -5
  29. data/console.rb +0 -36
  30. data/db/migrate/20131205114000_create_users.rb +0 -13
  31. data/db/migrate/20131205114900_create_posts.rb +0 -14
  32. data/db/migrate/20131205114901_create_comments.rb +0 -13
  33. data/db/migrate/20131205114902_create_addresses.rb +0 -14
  34. data/db/schema.rb +0 -22
  35. data/lib/object_attorney/association_reflection.rb +0 -72
  36. data/lib/object_attorney/attribute_assignment.rb +0 -69
  37. data/lib/object_attorney/delegation.rb +0 -48
  38. data/lib/object_attorney/naming.rb +0 -16
  39. data/lib/object_attorney/nested_objects.rb +0 -311
  40. data/lib/object_attorney/orm_handlers/smooth_operator.rb +0 -69
  41. data/lib/object_attorney/record.rb +0 -117
  42. data/lib/object_attorney/reflection.rb +0 -40
  43. data/lib/object_attorney/representation.rb +0 -93
  44. data/lib/object_attorney/serialization.rb +0 -43
  45. data/lib/object_attorney/translation.rb +0 -25
  46. data/lib/object_attorney/validations.rb +0 -46
  47. data/not_used/nested_uniqueness_validator.rb +0 -33
  48. data/spec/object_attorney/address_form_spec.rb +0 -45
  49. data/spec/object_attorney/bulk_post_form_spec.rb +0 -52
  50. data/spec/object_attorney/bulk_posts_allow_only_existing_form_spec.rb +0 -37
  51. data/spec/object_attorney/bulk_posts_allow_only_new_form_spec.rb +0 -39
  52. data/spec/object_attorney/bulk_posts_with_form_objects_form_spec.rb +0 -91
  53. data/spec/object_attorney/delegation_spec.rb +0 -142
  54. data/spec/object_attorney/nested_objects_spec.rb +0 -63
  55. data/spec/object_attorney/post_form_spec.rb +0 -154
  56. data/spec/object_attorney/post_validations_form_spec.rb +0 -46
  57. data/spec/object_attorney/post_with_comment_form_spec.rb +0 -123
  58. data/spec/object_attorney/post_with_comment_validations_form_spec.rb +0 -46
  59. data/spec/object_attorney/post_with_comments_and_address_form_spec.rb +0 -54
  60. data/spec/object_attorney/post_with_only_existing_comments_form_spec.rb +0 -38
  61. data/spec/object_attorney/post_with_only_new_comments_form_spec.rb +0 -42
  62. data/spec/object_attorney/serialization_spec.rb +0 -40
  63. data/spec/object_attorney/test_spec.rb +0 -23
  64. data/spec/object_attorney/user_and_comments_form_spec.rb +0 -56
  65. data/spec/object_attorney/user_form_spec.rb +0 -70
  66. data/spec/require_helper.rb +0 -32
  67. data/spec/support/active_model/validations.rb +0 -21
  68. data/spec/support/database_setup.rb +0 -14
  69. data/spec/support/form_objects/address_form.rb +0 -9
  70. data/spec/support/form_objects/bulk_posts_allow_only_existing_form.rb +0 -19
  71. data/spec/support/form_objects/bulk_posts_allow_only_new_form.rb +0 -19
  72. data/spec/support/form_objects/bulk_posts_form.rb +0 -27
  73. data/spec/support/form_objects/bulk_posts_with_form_objects_form.rb +0 -27
  74. data/spec/support/form_objects/comment_form.rb +0 -11
  75. data/spec/support/form_objects/post_form.rb +0 -120
  76. data/spec/support/form_objects/post_validations_form.rb +0 -17
  77. data/spec/support/form_objects/post_with_comment_form.rb +0 -21
  78. data/spec/support/form_objects/post_with_comment_validations_form.rb +0 -17
  79. data/spec/support/form_objects/post_with_comments_and_address_form.rb +0 -13
  80. data/spec/support/form_objects/post_with_only_existing_comments_form.rb +0 -9
  81. data/spec/support/form_objects/post_with_only_new_comments_form.rb +0 -9
  82. data/spec/support/form_objects/user_and_comments_form.rb +0 -11
  83. data/spec/support/form_objects/user_form.rb +0 -11
  84. data/spec/support/models/address.rb +0 -5
  85. data/spec/support/models/comment.rb +0 -5
  86. data/spec/support/models/post.rb +0 -9
  87. data/spec/support/models/user.rb +0 -7
@@ -1,72 +0,0 @@
1
- module ObjectAttorney
2
-
3
- class AssociationReflection < Reflection
4
- attr_reader :related_reflection, :macro
5
-
6
- def initialize(association, related_reflection, options)
7
- super(association, options)
8
- @macro = options[:macro] || macro_default(association)
9
- @related_reflection = related_reflection
10
- end
11
-
12
- def primary_key
13
- @primary_key ||= options[:primary_key] || :id
14
- end
15
-
16
- def foreign_key
17
- @foreign_key ||= options[:foreign_key] || foreign_key_default
18
- end
19
-
20
- def set_relational_keys(origin, destination)
21
- return nil if options[:standalone] == true
22
-
23
- if has_many? || has_one?
24
- set_foreign_key(destination, primary_key_of(origin))
25
- elsif belongs_to?
26
- set_foreign_key(origin, primary_key_of(destination))
27
- end
28
- end
29
-
30
- def set_foreign_key(object, id)
31
- setter = "#{foreign_key}="
32
-
33
- if object.respond_to?(setter)
34
- object.send(setter, id)
35
- elsif object.respond_to?("send_to_representative")
36
- object.send_to_representative(setter, id)
37
- end
38
- end
39
-
40
- def primary_key_of(object)
41
- object.send(primary_key)
42
- end
43
-
44
- def has_many?
45
- macro == :has_many
46
- end
47
-
48
- def has_one?
49
- macro == :has_one
50
- end
51
-
52
- def belongs_to?
53
- macro == :belongs_to
54
- end
55
-
56
- private ################################# private
57
-
58
- def macro_default(association)
59
- Helpers.plural?(association) ? :has_many : :belongs_to
60
- end
61
-
62
- def foreign_key_default
63
- if has_many? || has_one?
64
- "#{related_reflection.single_name}_id"
65
- elsif belongs_to?
66
- "#{single_name}_id"
67
- end.to_sym
68
- end
69
-
70
- end
71
-
72
- end
@@ -1,69 +0,0 @@
1
- module ObjectAttorney
2
-
3
- module AttributeAssignment
4
-
5
- def assign_attributes(attributes = {})
6
- return if attributes.blank?
7
-
8
- attributes.each do |name, value|
9
- name, value = check_for_hidden_nested_attributes(name, value)
10
- send("#{name}=", value) if allowed_attribute(name)
11
- end
12
-
13
- mark_for_destruction_if_necessary(self, attributes)
14
- end
15
-
16
- protected #################### PROTECTED METHODS DOWN BELOW ######################
17
-
18
- def check_for_hidden_nested_attributes(name, value)
19
- name_sym = name.to_sym
20
-
21
- reflection = self.class.reflect_on_association(name_sym)
22
-
23
- if reflection
24
- if reflection.has_many? && value.is_a?(Array)
25
- hash = {}
26
- value.each_with_index do |_value, index|
27
- hash[index.to_s] = _value
28
- end
29
- value = hash
30
- end
31
- name = "#{name}_attributes"
32
- end
33
-
34
- [name, value]
35
- end
36
-
37
- def parsing_arguments(attributes, object)
38
- if !attributes.is_a?(Hash) && object.blank?
39
- object = attributes
40
- attributes = nil
41
- end
42
-
43
- attributes = {} if attributes.blank?
44
-
45
- [attributes.symbolize_keys, object]
46
- end
47
-
48
- def allowed_attribute(attribute)
49
- respond_to?("#{attribute}=")
50
- end
51
-
52
- def attributes_without_destroy(attributes)
53
- return nil unless attributes.is_a?(Hash)
54
-
55
- _attributes = attributes.dup
56
- _attributes.delete("_destroy")
57
- _attributes.delete(:_destroy)
58
-
59
- _attributes.symbolize_keys
60
- end
61
-
62
- def attributes_order_destruction?(attributes)
63
- _destroy = attributes["_destroy"] || attributes[:_destroy]
64
- ["true", "1", true].include?(_destroy)
65
- end
66
-
67
- end
68
-
69
- end
@@ -1,48 +0,0 @@
1
- module ObjectAttorney
2
-
3
- module Delegation
4
-
5
- module MissingMethods
6
-
7
- def method_missing(method, *args, &block)
8
- represented_object.send(method, *args, &block)
9
- end
10
-
11
- end
12
-
13
- def zuper_method(method_name, *args)
14
- self.superclass.send(method_name, *args) if self.superclass.respond_to?(method_name)
15
- end
16
-
17
- def properties(*_properties)
18
- _properties.each { |property| delegate_property(property) }
19
- end
20
-
21
- def getters(*_getters)
22
- _getters.each { |getter| delegate_getter(getter) }
23
- end
24
-
25
- def setters(*_setters)
26
- _setters.each { |getter| delegate_setter(getter) }
27
- end
28
-
29
-
30
- protected ##################### PROTECTED #####################
31
-
32
- def delegate_property(property)
33
- delegate_getter(property)
34
- delegate_setter(property)
35
- end
36
-
37
- def delegate_getter(getter)
38
- delegate getter, to: :represented_object
39
- add_attribute_key getter
40
- end
41
-
42
- def delegate_setter(setter)
43
- delegate "#{setter}=", to: :represented_object
44
- end
45
-
46
- end
47
-
48
- end
@@ -1,16 +0,0 @@
1
- module ObjectAttorney
2
-
3
- module Naming
4
-
5
- def model_name
6
- @_model_name ||= begin
7
- namespace = self.parents.detect do |n|
8
- n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
9
- end
10
- ActiveModel::Name.new(represented_object_class || self, namespace)
11
- end
12
- end
13
-
14
- end
15
-
16
- end
@@ -1,311 +0,0 @@
1
- require "object_attorney/association_reflection"
2
-
3
- module ObjectAttorney
4
- module NestedObjects
5
-
6
- def initialize_nested_attributes
7
- self.class.reflect_on_all_associations.each do |reflection|
8
- self.instance_variable_set("@#{reflection.name}_attributes", {})
9
- end
10
- end
11
-
12
- def mark_for_destruction
13
- represented_object.respond_to?(:mark_for_destruction) && represented_object.mark_for_destruction
14
-
15
- @marked_for_destruction = true
16
- end
17
-
18
- def marked_for_destruction?
19
- if represented_object.respond_to?(:marked_for_destruction?) && represented_object.marked_for_destruction?
20
- @marked_for_destruction = true
21
- end
22
-
23
- @marked_for_destruction
24
- end
25
-
26
- def mark_for_destruction_if_necessary(object, attributes)
27
- return nil unless attributes.is_a?(Hash)
28
-
29
- object.mark_for_destruction if attributes_order_destruction? attributes
30
- end
31
-
32
- def nested_objects(macro = nil)
33
- nested_objects_list = []
34
-
35
- self.class.reflect_on_all_associations(macro).each do |reflection|
36
- [*self.send(reflection.name)].each do |nested_object|
37
- nested_objects_list << [reflection, nested_object]
38
- end
39
- end
40
-
41
- nested_objects_list
42
- end
43
-
44
- def reset_nested_objects(reflection_name = nil)
45
- self.class.reflect_on_all_associations.each do |reflection|
46
- next if !reflection_name.nil? && reflection_name != reflection.name
47
-
48
- self.instance_variable_set("@#{reflection.name}_attributes", {})
49
- self.instance_variable_set("@#{reflection.name}", nil)
50
- end
51
- end
52
-
53
- protected #################### PROTECTED METHODS DOWN BELOW ######################
54
-
55
- def save_or_destroy_nested_objects(save_method, association_macro)
56
- nested_objects(association_macro).map do |reflection, nested_object|
57
-
58
- populate_foreign_key(self, nested_object, reflection, :has_many)
59
- populate_foreign_key(self, nested_object, reflection, :has_one)
60
-
61
- saving_result = call_save_or_destroy(nested_object, save_method)
62
-
63
- populate_foreign_key(self, nested_object, reflection, :belongs_to)
64
-
65
- saving_result
66
-
67
- end.all?
68
- end
69
-
70
- def validate_nested_objects
71
- nested_objects.map { |reflection, nested_object| nested_object.valid? }.all?
72
- end
73
-
74
- def import_nested_objects_errors
75
- nested_objects.each do |reflection, nested_object|
76
- nested_object.errors.full_messages.each { |message| self.errors.add(reflection.name, message) }
77
- end
78
- end
79
-
80
- def get_attributes_for_existing(nested_object_name, existing_nested_object)
81
- attributes = send("#{nested_object_name}_attributes")
82
-
83
- if attributes.present?
84
- (attributes.values.select { |x| x[:id].to_i == existing_nested_object.id }.first || {}).symbolize_keys
85
- else
86
- {}
87
- end
88
- end
89
-
90
- private #################### PRIVATE METHODS DOWN BELOW ######################
91
-
92
- def populate_foreign_key(origin, destination, reflection, macro)
93
- return nil if represented_object.blank? || Helpers.marked_for_destruction?(destination) || reflection.macro != macro
94
-
95
- reflection.set_relational_keys(origin, destination)
96
- end
97
-
98
- def self.included(base)
99
- base.extend(ClassMethods)
100
-
101
- base.class_eval do
102
- validate :validate_nested_objects
103
- end
104
- end
105
-
106
- def nested_getter(nested_object_name)
107
- nested_instance_variable = self.instance_variable_get("@#{nested_object_name}")
108
-
109
- if nested_instance_variable.nil?
110
- reflection = self.class.reflect_on_association(nested_object_name)
111
-
112
- nested_instance_variable = reflection.has_many? ? get_existing_and_new_nested_objects(nested_object_name) : get_existing_or_new_nested_object(nested_object_name)
113
-
114
- [*nested_instance_variable].each do |nested_object|
115
- nested_object.extend(Validations) unless nested_object.respond_to?(:represented_object)
116
- end
117
-
118
- self.instance_variable_set("@#{nested_object_name}", nested_instance_variable)
119
- end
120
-
121
- nested_instance_variable
122
- end
123
-
124
- def get_existing_or_new_nested_object(nested_object_name)
125
- nested_object = send("existing_#{nested_object_name}")
126
- attributes = send("#{nested_object_name}_attributes")
127
-
128
- if nested_object.present?
129
- #return nested_object if (attributes["id"] || attributes[:id]).to_s != nested_object.id.to_s
130
-
131
- nested_object.assign_attributes(attributes_without_destroy(attributes))
132
- mark_for_destruction_if_necessary(nested_object, attributes)
133
- elsif attributes.keys.present? && !attributes_order_destruction?(attributes)
134
- nested_object = send("build_#{Helpers.singularize(nested_object_name)}", attributes_without_destroy(attributes))
135
- mark_for_destruction_if_necessary(nested_object, attributes)
136
- end
137
-
138
- nested_object
139
- end
140
-
141
- def get_existing_and_new_nested_objects(nested_object_name)
142
- existing_and_new_nested_objects = []
143
-
144
- update_existing_nested_objects(existing_and_new_nested_objects, nested_object_name)
145
- build_new_nested_objects(existing_and_new_nested_objects, nested_object_name)
146
-
147
- existing_and_new_nested_objects
148
- end
149
-
150
- def update_existing_nested_objects(existing_and_new_nested_objects, nested_object_name)
151
- send("existing_#{nested_object_name}").each do |existing_nested_object|
152
- attributes = get_attributes_for_existing(nested_object_name, existing_nested_object)
153
-
154
- mark_for_destruction_if_necessary(existing_nested_object, attributes)
155
- existing_nested_object.assign_attributes(attributes_without_destroy(attributes))
156
-
157
- existing_and_new_nested_objects << existing_nested_object
158
- end
159
- end
160
-
161
- def build_new_nested_objects(existing_and_new_nested_objects, nested_object_name)
162
- (send("#{nested_object_name}_attributes") || {}).values.each do |attributes|
163
- next if attributes["id"].present? || attributes[:id].present? || attributes_order_destruction?(attributes)
164
-
165
- new_nested_object = send("build_#{Helpers.singularize(nested_object_name)}", attributes_without_destroy(attributes))
166
- next unless new_nested_object
167
-
168
- mark_for_destruction_if_necessary(new_nested_object, attributes)
169
- existing_and_new_nested_objects << new_nested_object
170
- end
171
- end
172
-
173
- def build_nested_object(nested_object_name, attributes = {}, new_nested_object = nil)
174
- attributes = attributes.symbolize_keys
175
- reflection = self.class.reflect_on_association(nested_object_name)
176
-
177
- return nil if reflection.options[:new_records] == false
178
-
179
- if new_nested_object.present?
180
- new_nested_object = assign_attributes_or_build_nested_object(reflection, attributes, new_nested_object)
181
-
182
- elsif reflection.options[:standalone] == true || !can_represented_object_build_nested?(reflection, nested_object_name)
183
- new_nested_object = reflection.klass.new(attributes)
184
-
185
- else
186
- new_nested_object = build_from_represented_object(reflection, nested_object_name)
187
-
188
- new_nested_object = assign_attributes_or_build_nested_object(reflection, attributes, new_nested_object)
189
- end
190
-
191
- populate_foreign_key(self, new_nested_object, reflection, :has_many)
192
- new_nested_object.extend(Validations) unless new_nested_object.respond_to?(:represented_object)
193
-
194
- new_nested_object
195
- end
196
-
197
- def assign_attributes_or_build_nested_object(reflection, attributes, new_nested_object)
198
- real_reflection_class = self.class.represented_object_reflect_on_association(reflection.name).try(:klass)
199
-
200
- if reflection.klass == real_reflection_class
201
- new_nested_object.assign_attributes(attributes)
202
- new_nested_object
203
- else
204
- reflection.klass.respond_to?(:represents) ? reflection.klass.new(attributes, new_nested_object) : reflection.klass.new(attributes)
205
- end
206
- end
207
-
208
- def can_represented_object_build_nested?(reflection, nested_object_name)
209
- return false if represented_object.blank?
210
-
211
- represented_object.respond_to?("build_#{nested_object_name}") || represented_object.send(nested_object_name).respond_to?(:build)
212
- end
213
-
214
- def build_from_represented_object(reflection, nested_object_name)
215
- build_method = "build_#{nested_object_name}"
216
-
217
- if represented_object.respond_to?(build_method)
218
- represented_object.send(build_method)
219
- else
220
- represented_object.send(nested_object_name).build
221
- end
222
- end
223
-
224
- def existing_nested_objects(nested_object_name)
225
- nested_relection = self.class.reflect_on_association(nested_object_name)
226
-
227
- return [] if nested_relection.options[:existing_records] == false
228
-
229
- if nested_relection.options[:standalone] == true
230
- return nested_relection.has_many? ? (nested_relection.klass.try(:all) || []) : nil
231
- end
232
-
233
- existing = represented_object.nil? ? (nested_relection.klass.try(:all) || []) : (represented_object.send(nested_object_name) || (nested_relection.has_many? ? [] : nil))
234
-
235
- if represented_object.present?
236
- if self.class.represented_object_class.respond_to?(:reflect_on_association)
237
- existing = _existing_in_form_objects(existing, nested_relection) if nested_relection.klass != self.class.represented_object_class.reflect_on_association(nested_object_name).try(:klass)
238
- else
239
- existing = _existing_in_form_objects(existing, nested_relection)
240
- end
241
- end
242
-
243
- existing
244
- end
245
-
246
- def _existing_in_form_objects(existing, nested_relection)
247
- if existing.respond_to?(:map)
248
- existing.map { |existing_nested_object| nested_relection.klass.new({}, existing_nested_object) }
249
- elsif existing.present?
250
- nested_relection.klass.new({}, existing)
251
- else
252
- nil
253
- end
254
- end
255
-
256
- module ClassMethods
257
-
258
- def has_many(nested_object_name, options = {})
259
- accepts_nested_objects_overwrite_macro(nested_object_name, options, :has_many)
260
- end
261
-
262
- def has_one(nested_object_name, options = {})
263
- accepts_nested_objects_overwrite_macro(nested_object_name, options, :has_one)
264
- end
265
-
266
- def belongs_to(nested_object_name, options = {})
267
- accepts_nested_objects_overwrite_macro(nested_object_name, options, :belongs_to)
268
- end
269
-
270
- def accepts_nested_objects(nested_object_name, options = {})
271
- options.symbolize_keys!
272
- reflection = AssociationReflection.new(nested_object_name, represented_object_reflection, options)
273
-
274
- self.instance_variable_set("@#{nested_object_name}_reflection", reflection)
275
- self.instance_variable_set("@association_reflections", association_reflections.merge(nested_object_name => reflection))
276
-
277
- self.send(:attr_accessor, "#{nested_object_name}_attributes".to_sym)
278
-
279
- define_method(nested_object_name) { nested_getter(nested_object_name) }
280
- define_method("build_#{reflection.single_name}") { |attributes = {}, nested_object = nil| build_nested_object(nested_object_name, attributes, nested_object) }
281
- define_method("existing_#{nested_object_name}") { existing_nested_objects(nested_object_name) }
282
- end
283
-
284
- def association_reflections
285
- self.instance_variable_get("@association_reflections") || zuper_method('association_reflections') || {}
286
- end
287
-
288
- def reflect_on_association(association)
289
- self.instance_variable_get("@#{association}_reflection") || zuper_method('reflect_on_association', association)
290
- end
291
-
292
- def reflect_on_all_associations(macro = nil)
293
- macro ? association_reflections.values.select { |reflection| reflection.macro == macro } : association_reflections.values
294
- end
295
-
296
- def reflections
297
- association_reflections
298
- end
299
-
300
- private ############################### PRIVATE METHODS ###########################
301
-
302
- def accepts_nested_objects_overwrite_macro(nested_object_name, options, macro)
303
- default_options = { macro: macro }
304
- options = options.is_a?(Hash) ? options.merge(default_options) : default_options
305
- accepts_nested_objects(nested_object_name, options)
306
- end
307
-
308
- end
309
-
310
- end
311
- end