custom_fields 1.1.0.rc1 → 2.0.0.rc1

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 (41) hide show
  1. data/MIT-LICENSE +1 -1
  2. data/README.textile +14 -6
  3. data/config/locales/fr.yml +5 -1
  4. data/lib/custom_fields.rb +11 -37
  5. data/lib/custom_fields/extensions/carrierwave.rb +25 -0
  6. data/lib/custom_fields/extensions/mongoid/document.rb +12 -50
  7. data/lib/custom_fields/extensions/mongoid/factory.rb +20 -0
  8. data/lib/custom_fields/extensions/mongoid/fields.rb +29 -0
  9. data/lib/custom_fields/extensions/mongoid/fields/i18n.rb +53 -0
  10. data/lib/custom_fields/extensions/mongoid/fields/internal/localized.rb +84 -0
  11. data/lib/custom_fields/extensions/mongoid/relations/referenced/many.rb +29 -0
  12. data/lib/custom_fields/field.rb +44 -175
  13. data/lib/custom_fields/source.rb +333 -0
  14. data/lib/custom_fields/target.rb +90 -0
  15. data/lib/custom_fields/types/boolean.rb +26 -3
  16. data/lib/custom_fields/types/date.rb +36 -24
  17. data/lib/custom_fields/types/default.rb +44 -24
  18. data/lib/custom_fields/types/file.rb +35 -17
  19. data/lib/custom_fields/types/select.rb +184 -0
  20. data/lib/custom_fields/types/string.rb +25 -6
  21. data/lib/custom_fields/types/text.rb +35 -8
  22. data/lib/custom_fields/types_old/boolean.rb +13 -0
  23. data/lib/custom_fields/{types → types_old}/category.rb +0 -0
  24. data/lib/custom_fields/types_old/date.rb +49 -0
  25. data/lib/custom_fields/types_old/default.rb +44 -0
  26. data/lib/custom_fields/types_old/file.rb +27 -0
  27. data/lib/custom_fields/{types → types_old}/has_many.rb +0 -0
  28. data/lib/custom_fields/{types → types_old}/has_many/proxy_collection.rb +0 -0
  29. data/lib/custom_fields/{types → types_old}/has_many/reverse_lookup_proxy_collection.rb +0 -0
  30. data/lib/custom_fields/{types → types_old}/has_one.rb +0 -0
  31. data/lib/custom_fields/types_old/string.rb +13 -0
  32. data/lib/custom_fields/types_old/text.rb +15 -0
  33. data/lib/custom_fields/version.rb +1 -1
  34. metadata +115 -91
  35. data/lib/custom_fields/custom_fields_for.rb +0 -350
  36. data/lib/custom_fields/extensions/mongoid/relations/accessors.rb +0 -31
  37. data/lib/custom_fields/extensions/mongoid/relations/builders.rb +0 -30
  38. data/lib/custom_fields/proxy_class/base.rb +0 -112
  39. data/lib/custom_fields/proxy_class/builder.rb +0 -60
  40. data/lib/custom_fields/proxy_class/helper.rb +0 -57
  41. data/lib/custom_fields/self_metadata.rb +0 -30
@@ -1,350 +0,0 @@
1
- module CustomFields
2
-
3
- module CustomFieldsFor
4
-
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- cattr_accessor :_custom_fields_for
9
-
10
- self._custom_fields_for = []
11
- end
12
-
13
- module InstanceMethods
14
-
15
- # Determines if the relation is enhanced by the custom fields
16
- #
17
- # @example the Person class has somewhere in its code this: "custom_fields_for :addresses"
18
- # person.custom_fields_for?(:addresses)
19
- #
20
- # @param [ String, Symbol ] name The name of the relation.
21
- #
22
- # @return [ true, false ] True if enhanced, false if not.
23
- #
24
- def custom_fields_for?(name)
25
- self.class.custom_fields_for?(name)
26
- end
27
-
28
- # Returns the class enhanced by the custom fields defined in the parent class.
29
- #
30
- # @param [ String, Symbol ] name The name of the relation.
31
- #
32
- # @return [ Class ] The modified class.
33
- #
34
- def klass_with_custom_fields(name)
35
- self.class.klass_with_custom_fields(name, self)
36
- end
37
-
38
- # Returns the ordered list of custom fields for a relation
39
- #
40
- # @example the Person class has somewhere in its code this: "custom_fields_for :addresses"
41
- # person.ordered_custom_fields(:addresses)
42
- #
43
- # @param [ String, Symbol ] name The name of the relation.
44
- #
45
- # @return [ Collection ] The ordered list.
46
- #
47
- def ordered_custom_fields(name)
48
- self.send(:"#{name}_custom_fields").sort { |a, b| (a.position || 0) <=> (b.position || 0) }
49
- end
50
-
51
- # Marks all the custom fields as persisted. Actually, this is a patch
52
- # for mongoid since for the update, it runs the reset_persisted_children method after
53
- # the callbacks unlike for the create.
54
- # We assume that all the fields have been validated in a previous step
55
- #
56
- # @param [ String, Symbol ] name The name of the relation.
57
- #
58
- def mark_custom_fields_as_persisted(name)
59
- self.send(:"#{name}_custom_fields").each do |field|
60
- field.instance_variable_set(:@new_record, false) unless field.persisted?
61
- end
62
- end
63
-
64
- # Builds the class enhanced by the custom fields defined in the parent class.
65
- # The new class inherits from the original one.
66
- #
67
- # @param [ String, Symbol ] name The name of the relation.
68
- # @param [ Metadata ] metadata The relation's metadata.
69
- #
70
- # @return [ Class ] The modified class.
71
- #
72
- def build_klass_with_custom_fields(name, metadata)
73
- custom_fields = self.ordered_custom_fields(name)
74
-
75
- metadata.klass.to_klass_with_custom_fields(name, self, custom_fields)
76
- end
77
-
78
- # Marks the class enhanced by the custom fields as invalidated
79
- #
80
- # @param [ String, Symbol ] name The name of the relation.
81
- #
82
- def mark_klass_with_custom_fields_as_invalidated(name)
83
- self.send(:"invalidate_#{name}_klass_flag=", true)
84
- end
85
-
86
- # Reset the flag telling if the class enhanced by the custom fields is invalidated
87
- #
88
- # @param [ String, Symbol ] name The name of the relation.
89
- #
90
- def reset_klass_with_custom_fields_invalidated_flag(name)
91
- # puts "* reset_klass_with_custom_fields_invalidated_flag #{name}"
92
- self.send(:"invalidate_#{name}_klass_flag=", false)
93
- end
94
-
95
- # Determines if the enhanced class has to be invalidated.
96
- #
97
- # @param [ String, Symbol ] name The name of the relation.
98
- #
99
- # @return [ true, false ] True if enhanced, false if not.
100
- #
101
- def invalidate_klass_with_custom_fields?(name)
102
- !!self.send(:"invalidate_#{name}_klass_flag")
103
- end
104
-
105
- # Destroy the class enhanced by the custom fields so that next time we need it,
106
- # we have a fresh new one.
107
- #
108
- # @param [ String, Symbol ] name The name of the relation.
109
- #
110
- def invalidate_klass_with_custom_fields(name)
111
- self.class.invalidate_klass_with_custom_fields(name, self)
112
- end
113
-
114
- # Duplicates a metadata and assigns the enhanced class to it.
115
- #
116
- # @param [ Metadata ] metadata The relation's old metadata.
117
- #
118
- # @return [ Metadata ] The relation's new metadata
119
- #
120
- def clone_metadata_for_custom_fields(metadata)
121
- # puts "-> clone_metadata_for_custom_fields #{metadata.name}"
122
-
123
- klass = self.build_klass_with_custom_fields(metadata.name, metadata)
124
-
125
- # we do not want that other instances of the parent class have the same metadata
126
- metadata.clone.tap do |metadata|
127
- metadata.instance_variable_set(:@klass, klass)
128
- end
129
- end
130
-
131
- # When the fields have been modified and before the object is saved,
132
- # we bump the version.
133
- #
134
- # @param [ String, Symbol ] name The name of the relation.
135
- #
136
- def bump_custom_fields_version(name)
137
- if self.invalidate_klass_with_custom_fields?(name)
138
- # puts "%%% bump_custom_fields_version #{name} #{self.send(:"#{name}_custom_fields_version").inspect}"
139
- version = self.send(:"#{name}_custom_fields_version") || 0
140
- self.send(:"#{name}_custom_fields_version=", version + 1)
141
- end
142
- end
143
-
144
- # Increments by 1 the counter couting the number of added custom fields
145
- # for a relation
146
- #
147
- # @param [ String, Symbol ] name The name of the relation.
148
- #
149
- # @return [ Integer ] The new value of the counter
150
- #
151
- def bump_custom_fields_counter(name)
152
- counter = self.send(:"#{name}_custom_fields_counter") || 0
153
- self.send(:"#{name}_custom_fields_counter=", counter + 1)
154
- end
155
-
156
- # Builds a new relation so that the builder takes the last version of
157
- # the enhanced class when creating new instances
158
- #
159
- # @param [ String, Symbol ] name The name of the relation.
160
- #
161
- def rebuild_custom_fields_relation(name)
162
- # metadata = self.clone_metadata_for_custom_fields(self.relations[name.to_s])
163
-
164
- # puts "rebuild_custom_fields_relation #{name}"
165
-
166
- metadata = self.relations[name.to_s]
167
- self.build(name, nil, metadata)
168
- end
169
-
170
- end
171
-
172
- module ClassMethods
173
-
174
- # Determines if the relation is enhanced by the custom fields
175
- #
176
- # @example the Person class has somewhere in its code this: "custom_fields_for :addresses"
177
- # Person.custom_fields_for?(:addresses)
178
- #
179
- # @param [ String, Symbol ] name The name of the relation.
180
- #
181
- # @return [ true, false ] True if enhanced, false if not.
182
- #
183
- def custom_fields_for?(name)
184
- self._custom_fields_for.include?(name.to_s)
185
- end
186
-
187
- # Enhance an embedded collection OR the instance itself (by passing self) by providing methods to manage custom fields.
188
- #
189
- # @param [ String, Symbol ] name The name of the relation.
190
- #
191
- # @example
192
- # class Company
193
- # embeds_many :employees
194
- # custom_fields_for :employees
195
- # end
196
- #
197
- # class Employee
198
- # embedded_in :company, :inverse_of => :employees
199
- # field :name, String
200
- # end
201
- #
202
- # company.employees_custom_fields.build :label => 'His/her position', :_alias => 'position', :kind => 'string'
203
- # company.employees.build :name => 'Michael Scott', :position => 'Regional manager'
204
- #
205
- def custom_fields_for(name)
206
- self.declare_embedded_in_definition_in_custom_field(name)
207
-
208
- # stores the relation name
209
- self._custom_fields_for << name.to_s
210
-
211
- self.extend_for_custom_fields(name)
212
- end
213
-
214
- # Enhances the class itself
215
- #
216
- # @example
217
- # class Company
218
- # custom_fields_for_itself
219
- # end
220
- #
221
- # company.self_metadata_custom_fields.build :label => 'Shipping Address', :_alias => 'address', :kind => 'text'
222
- # company.self_metadata.address = '700 S Laflin, 60607 Chicago'
223
- # other_company.self_metadata.address # returns a "not defined method" error
224
- #
225
- def custom_fields_for_itself
226
- self.embeds_one :self_metadata, :class_name => '::CustomFields::SelfMetadata'
227
-
228
- class_eval do
229
- def self_metadata_with_automatic_build
230
- object = self_metadata_without_automatic_build
231
- object || self.build_self_metadata
232
- end
233
- alias_method_chain :self_metadata, :automatic_build
234
- end
235
-
236
- self.custom_fields_for('self_metadata')
237
- end
238
-
239
- protected
240
-
241
- # Extends / Decorates the current class in order to be fully custom_fields compliant.
242
- # it declares news fields, adds new callbacks, ...etc
243
- #
244
- # @param [ String, Symbol ] name The name of the relation.
245
- #
246
- def extend_for_custom_fields(name)
247
- class_eval do
248
- field :"#{name}_custom_fields_counter", :type => Integer, :default => 0
249
- field :"#{name}_custom_fields_version", :type => Integer, :default => 0
250
-
251
- embeds_many :"#{name}_custom_fields", :class_name => self.dynamic_custom_field_class_name(name), :cascade_callbacks => true
252
-
253
- attr_accessor :"invalidate_#{name}_klass_flag" # flag for invalidating the custom class
254
-
255
- accepts_nested_attributes_for :"#{name}_custom_fields", :allow_destroy => true
256
- end
257
-
258
- class_eval <<-EOV
259
-
260
- before_save :bump_#{name}_custom_fields_version
261
- after_save :mark_#{name}_custom_fields_as_persisted
262
- after_save :rebuild_#{name}_relation
263
- after_save :reset_#{name}_klass_invalidated_flag
264
- after_destroy :invalidate_#{name}_klass
265
-
266
- def #{name}_klass
267
- self.klass_with_custom_fields('#{name}')
268
- end
269
-
270
- def #{name}_klass_name
271
- self.class.klass_name_with_custom_fields('#{name}', self)
272
- end
273
-
274
- def #{name}_klass_out_of_date?
275
- self.#{name}_klass.nil? || self.#{name}_klass.version != self.#{name}_custom_fields_version
276
- end
277
-
278
- def invalidate_#{name}_klass
279
- self.invalidate_klass_with_custom_fields('#{name}')
280
- end
281
-
282
- def invalidate_#{name}_klass?
283
- self.invalidate_klass_with_custom_fields?('#{name}')
284
- end
285
-
286
- def rebuild_#{name}_relation
287
- # puts "--> AFTER SAVE (#{name})"
288
- if self.#{name}_klass_out_of_date?
289
- # puts 'rebuild relation for #{name} after save'
290
- self.rebuild_custom_fields_relation('#{name}')
291
- end
292
- end
293
-
294
- protected
295
-
296
- def bump_#{name}_custom_fields_version
297
- # puts "--> BEFORE SAVE (#{name})"
298
- self.bump_custom_fields_version('#{name}')
299
- end
300
-
301
- def mark_#{name}_custom_fields_as_persisted
302
- self.mark_custom_fields_as_persisted('#{name}')
303
- end
304
-
305
- def reset_#{name}_klass_invalidated_flag
306
- self.reset_klass_with_custom_fields_invalidated_flag('#{name}')
307
- end
308
-
309
- EOV
310
- end
311
-
312
- # Returns the class name of the custom field which is based both on the parent class name
313
- # and the name of the relation in order to avoid name conflicts (with other classes)
314
- #
315
- # @param [ Metadata ] metadata The relation's old metadata.
316
- #
317
- # @return [ String ] The class name
318
- #
319
- def dynamic_custom_field_class_name(name)
320
- "#{self.name}#{name.to_s.singularize.camelize}Field"
321
- end
322
-
323
- # An embedded relationship has to be defined on both side in order for it
324
- # to work properly. But because custom_field can be embedded in different
325
- # models that it's not aware of, we have to declare manually the definition
326
- # once we know the target class.
327
- #
328
- # @param [ String, Symbol ] name The name of the relation.
329
- #
330
- # @return [ Field ] The new field class.
331
- #
332
- def declare_embedded_in_definition_in_custom_field(name)
333
- klass_name = self.dynamic_custom_field_class_name(name)
334
-
335
- unless Object.const_defined?(klass_name)
336
- (klass = Class.new(::CustomFields::Field)).class_eval <<-EOF
337
- embedded_in :#{self.name.underscore}, :inverse_of => :#{name}_custom_fields
338
- EOF
339
-
340
- Object.const_set(klass_name, klass)
341
- end
342
- end
343
-
344
- end
345
-
346
- end
347
-
348
- end
349
-
350
-
@@ -1,31 +0,0 @@
1
- # encoding: utf-8
2
- module Mongoid # :nodoc:
3
- module Relations #:nodoc:
4
-
5
- module Accessors
6
-
7
- # Builds the related document and creates the relation based on the class
8
- # enhanced by the custom_fields functionnality (if set up for the relation).
9
- #
10
- # @param [ String, Symbol ] name The name of the relation.
11
- # @param [ Hash, BSON::ObjectId ] object The id or attributes to use.
12
- # @param [ Metadata ] metadata The relation's metadata.
13
- # @param [ true, false ] building If we are in a build operation.
14
- #
15
- # @return [ Proxy ] The relation.
16
- #
17
- # @since 2.0.0.rc.1
18
- def build_with_custom_fields(name, object, metadata)
19
- if self.respond_to?(:custom_fields_for?) && self.custom_fields_for?(metadata.name)
20
- # puts "[Accessors] build_with_custom_fields #{name}"
21
- metadata = self.clone_metadata_for_custom_fields(metadata)
22
- end
23
-
24
- build_without_custom_fields(name, object, metadata)
25
- end
26
-
27
- alias_method_chain :build, :custom_fields
28
- end
29
-
30
- end
31
- end
@@ -1,30 +0,0 @@
1
- module Mongoid # :nodoc:
2
- module Relations #:nodoc:
3
-
4
- module Builders
5
-
6
- module ClassMethods #:nodoc:
7
-
8
- def builder_with_custom_fields(name, metadata)
9
- tap do
10
- define_method("build_#{name}") do |*args|
11
- if self.custom_fields_for?(metadata.name)
12
- metadata = self.clone_metadata_for_custom_fields(metadata)
13
- end
14
-
15
- attributes = args.first || {}
16
- options = args.size > 1 ? args[1] : {}
17
- document = Factory.build(metadata.klass, attributes, options)
18
- _building do
19
- send("#{name}=", document)
20
- end
21
- end
22
- end
23
- end
24
-
25
- alias_method_chain :builder, :custom_fields
26
-
27
- end
28
- end
29
- end
30
- end
@@ -1,112 +0,0 @@
1
- module CustomFields
2
- module ProxyClass
3
-
4
- module Base
5
-
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
- cattr_accessor :custom_fields, :_parent, :association_name, :built_at, :version
10
- end
11
-
12
- module InstanceMethods
13
-
14
- # Returns the list of the custom fields used to build this class
15
- #
16
- # @return [ List ] the list of custom fields
17
- #
18
- def custom_fields
19
- self.class.custom_fields
20
- end
21
-
22
- # Returns the fields specified by the custom fields and their values
23
- #
24
- # @return [ Hash ] the hash
25
- #
26
- def aliased_attributes
27
- hash = { :created_at => self.created_at, :updated_at => self.updated_at } rescue {}
28
-
29
- (self.custom_fields || []).each do |field|
30
- case field.kind
31
- when 'file' then hash[field._alias] = self.send(field._name.to_sym).url
32
- else
33
- hash[field._alias] = self.send(field._name.to_sym)
34
- end
35
- end
36
-
37
- hash
38
- end
39
-
40
- end
41
-
42
- module ClassMethods
43
-
44
- # Returns the fields specified by the custom fields and their values
45
- #
46
- def model_name
47
- @_model_name ||= ActiveModel::Name.new(self.superclass)
48
- end
49
-
50
- # Declares a field within the class based on the information given by the custom field
51
- #
52
- # @param [ Field ] field The custom field
53
- #
54
- def apply_custom_field(field)
55
- # puts "field #{field._name} persisted? #{field.persisted?} / valid ? #{field.quick_valid?}"
56
- return if !field.persisted? || !field.quick_valid?
57
-
58
- self.custom_fields ||= []
59
-
60
- if self.lookup_custom_field(field._name).nil?
61
- self.custom_fields << field
62
- field.apply(self)
63
- end
64
- end
65
-
66
- # Determines if the class has already declared the field
67
- #
68
- # @param [ String ] name The name of the custom field
69
- #
70
- # @return [ true, false ] True if found it, false if not.
71
- #
72
- def lookup_custom_field(name)
73
- self.custom_fields.detect { |f| f._name == name }
74
- end
75
-
76
- # Convenient method to get the name of a custom field from its alias
77
- #
78
- # @param [ String ] value The _alias value of the custom field
79
- #
80
- # @return [ String ] The name of the custom field.
81
- #
82
- def custom_field_alias_to_name(value)
83
- self.custom_fields.detect { |f| f._alias == value }._name
84
- end
85
-
86
- # Convenient method to get the _alias of a custom field from its name
87
- #
88
- # @param [ String ] value The name value of the custom field
89
- #
90
- # @return [ String ] The _alias of the custom field.
91
- #
92
- def custom_field_name_to_alias(value)
93
- self.custom_fields.detect { |f| f._name == value }._alias
94
- end
95
-
96
- # Tells Mongoid that this class is a child of a super class (even if it is no true)
97
- #
98
- def hereditary?
99
- false
100
- end
101
-
102
- end
103
-
104
- end
105
-
106
- end
107
- end
108
-
109
-
110
-
111
-
112
-