custom_fields 1.0.0.beta.4 → 1.0.0.beta.5
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.
- data/config/locales/de.yml +9 -0
- data/config/locales/en.yml +9 -0
- data/config/locales/fr.yml +12 -0
- data/config/locales/pt-BR.yml +9 -0
- data/init.rb +1 -1
- data/lib/custom_fields.rb +15 -1
- data/lib/custom_fields/custom_fields_for.rb +35 -5
- data/lib/custom_fields/extensions/mongoid/relations/accessors.rb +5 -3
- data/lib/custom_fields/field.rb +33 -13
- data/lib/custom_fields/proxy_class_enabler.rb +19 -5
- data/lib/custom_fields/types/date.rb +12 -11
- data/lib/custom_fields/types/default.rb +14 -9
- data/lib/custom_fields/version.rb +1 -1
- metadata +23 -19
data/init.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
#
|
1
|
+
# Init
|
2
2
|
require File.dirname(__FILE__) + '/lib/custom_fields'
|
data/lib/custom_fields.rb
CHANGED
@@ -28,5 +28,19 @@ module Mongoid
|
|
28
28
|
end
|
29
29
|
|
30
30
|
ActiveSupport::Inflector.inflections do |inflect|
|
31
|
-
inflect.
|
31
|
+
inflect.irregular 'metadata', 'metadata'
|
32
32
|
end
|
33
|
+
|
34
|
+
# Load all the translation files
|
35
|
+
I18n.load_path += Dir[File.join(File.dirname(__FILE__), '..', 'config', 'locales', '*.yml')]
|
36
|
+
|
37
|
+
module MyBenchmark
|
38
|
+
|
39
|
+
def self.measure(caption, &block)
|
40
|
+
t1 = Time.now
|
41
|
+
returned_value = block.call
|
42
|
+
puts "[MyBenchmark] #{caption} took #{((Time.now - t1) * 1000).to_i} ms"
|
43
|
+
returned_value
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -37,31 +37,61 @@ module CustomFields
|
|
37
37
|
def custom_fields_for(collection_name)
|
38
38
|
singular_name = collection_name.to_s.singularize
|
39
39
|
|
40
|
+
# generate the custom field for the couple defined by the class and the collection name
|
41
|
+
dynamic_custom_field_class_name = "#{self.name}#{singular_name.camelize}Field"
|
42
|
+
|
43
|
+
unless Object.const_defined?(dynamic_custom_field_class_name)
|
44
|
+
(klass = Class.new(::CustomFields::Field)).class_eval <<-EOF
|
45
|
+
embedded_in :#{self.name.underscore}, :inverse_of => :#{singular_name}_custom_fields
|
46
|
+
EOF
|
47
|
+
|
48
|
+
Object.const_set(dynamic_custom_field_class_name, klass)
|
49
|
+
end
|
50
|
+
|
51
|
+
# enhance the class itself
|
40
52
|
if (itself = %w(itself self).include?(collection_name.to_s))
|
41
|
-
singular_name = '_metadata'
|
53
|
+
collection_name, singular_name = '_metadata', 'metadata'
|
42
54
|
|
43
55
|
class_eval <<-EOV
|
44
|
-
embeds_one :#{
|
56
|
+
embeds_one :#{collection_name}, :class_name => '::CustomFields::Metadata'
|
45
57
|
|
46
|
-
def
|
47
|
-
self.#{
|
58
|
+
def #{singular_name}
|
59
|
+
self.#{collection_name} || self.build_#{collection_name}
|
48
60
|
end
|
49
61
|
|
50
62
|
EOV
|
51
63
|
end
|
52
64
|
|
65
|
+
# common part
|
53
66
|
class_eval <<-EOV
|
54
67
|
field :#{singular_name}_custom_fields_counter, :type => Integer, :default => 0
|
55
68
|
|
56
|
-
embeds_many :#{singular_name}_custom_fields, :class_name => '
|
69
|
+
embeds_many :#{singular_name}_custom_fields, :class_name => '#{dynamic_custom_field_class_name}'
|
57
70
|
|
58
71
|
validates_associated :#{singular_name}_custom_fields
|
59
72
|
|
73
|
+
after_validation do |record|
|
74
|
+
if record.errors.empty?
|
75
|
+
record.invalidate_#{singular_name}_klass
|
76
|
+
end
|
77
|
+
end
|
78
|
+
after_destroy :invalidate_#{singular_name}_klass
|
79
|
+
|
60
80
|
accepts_nested_attributes_for :#{singular_name}_custom_fields, :allow_destroy => true
|
61
81
|
|
62
82
|
def ordered_#{singular_name}_custom_fields
|
63
83
|
self.#{singular_name}_custom_fields.sort { |a, b| (a.position || 0) <=> (b.position || 0) }
|
64
84
|
end
|
85
|
+
|
86
|
+
def fetch_#{singular_name}_klass
|
87
|
+
metadata = self.relations['#{collection_name.to_s}']
|
88
|
+
metadata.klass.to_klass_with_custom_fields(self.ordered_#{singular_name}_custom_fields, self, metadata.name)
|
89
|
+
end
|
90
|
+
|
91
|
+
def invalidate_#{singular_name}_klass
|
92
|
+
metadata = self.relations['#{collection_name.to_s}']
|
93
|
+
metadata.klass.invalidate_proxy_class_with_custom_fields(self, metadata.name)
|
94
|
+
end
|
65
95
|
EOV
|
66
96
|
|
67
97
|
if itself
|
@@ -16,12 +16,14 @@ module Mongoid # :nodoc:
|
|
16
16
|
#
|
17
17
|
# @since 2.0.0.rc.1
|
18
18
|
def create_relation_with_custom_fields(object, metadata)
|
19
|
-
|
19
|
+
association_name = metadata.name.to_s.gsub(/^_/, '')
|
20
|
+
|
21
|
+
if custom_fields?(self, association_name)
|
20
22
|
metadata = metadata.clone # 2 parent instances should not share the exact same option instance
|
21
23
|
|
22
|
-
custom_fields = self.send(:"ordered_#{custom_fields_association_name(
|
24
|
+
custom_fields = self.send(:"ordered_#{custom_fields_association_name(association_name)}")
|
23
25
|
|
24
|
-
klass = metadata.klass.to_klass_with_custom_fields(custom_fields, self,
|
26
|
+
klass = metadata.klass.to_klass_with_custom_fields(custom_fields, self, association_name)
|
25
27
|
|
26
28
|
metadata.instance_variable_set(:@klass, klass)
|
27
29
|
end
|
data/lib/custom_fields/field.rb
CHANGED
@@ -20,6 +20,7 @@ module CustomFields
|
|
20
20
|
field :kind
|
21
21
|
field :hint
|
22
22
|
field :position, :type => Integer, :default => 0
|
23
|
+
field :required, :type => Boolean, :default => false
|
23
24
|
|
24
25
|
## validations ##
|
25
26
|
validates_presence_of :label, :kind
|
@@ -27,28 +28,29 @@ module CustomFields
|
|
27
28
|
validate :uniqueness_of_label_and_alias
|
28
29
|
|
29
30
|
## other accessors ##
|
30
|
-
attr_accessor :association_name # missing in 2.0.0 rc
|
31
|
+
attr_accessor :association_name # missing in 2.0.0 rc 7
|
32
|
+
|
33
|
+
attr_accessor :parentized_done # for performance purpose
|
34
|
+
|
35
|
+
## callbacks ##
|
36
|
+
before_validation :set_alias
|
31
37
|
|
32
38
|
## methods ##
|
33
39
|
|
34
40
|
def field_type
|
35
|
-
self.class.field_types[self.
|
41
|
+
self.class.field_types[self.safe_kind.to_sym]
|
36
42
|
end
|
37
43
|
|
38
44
|
def apply(klass)
|
39
|
-
return false unless self.valid?
|
40
|
-
|
41
45
|
klass.field self._name, :type => self.field_type if self.field_type
|
42
46
|
|
43
|
-
apply_method_name = :"apply_#{self.
|
47
|
+
apply_method_name = :"apply_#{self.safe_kind}_type"
|
44
48
|
|
45
49
|
if self.respond_to?(apply_method_name)
|
46
50
|
self.send(apply_method_name, klass)
|
47
51
|
else
|
48
52
|
apply_default_type(klass)
|
49
53
|
end
|
50
|
-
|
51
|
-
true
|
52
54
|
end
|
53
55
|
|
54
56
|
def safe_alias
|
@@ -56,6 +58,10 @@ module CustomFields
|
|
56
58
|
self._alias
|
57
59
|
end
|
58
60
|
|
61
|
+
def safe_kind
|
62
|
+
self.kind.downcase # for compatibility purpose: prior version of CustomFields used to have the value of kind in uppercase.
|
63
|
+
end
|
64
|
+
|
59
65
|
def write_attributes_with_invalidation(attrs = nil)
|
60
66
|
if self.association_name.to_s == '_metadata_custom_fields'
|
61
67
|
target_name = 'metadata'
|
@@ -63,7 +69,7 @@ module CustomFields
|
|
63
69
|
target_name = self.association_name.to_s.gsub('_custom_fields', '').pluralize
|
64
70
|
end
|
65
71
|
|
66
|
-
klass = self._parent.send(target_name)
|
72
|
+
klass = self._parent.send(:"fetch_#{target_name.singularize}_klass")
|
67
73
|
|
68
74
|
write_attributes_without_invalidation(attrs)
|
69
75
|
|
@@ -72,6 +78,21 @@ module CustomFields
|
|
72
78
|
|
73
79
|
alias_method_chain :write_attributes, :invalidation
|
74
80
|
|
81
|
+
def to_hash(more = {})
|
82
|
+
self.fields.keys.inject({}) do |memo, meth|
|
83
|
+
memo[meth] = self.send(meth.to_sym); memo
|
84
|
+
end.merge({
|
85
|
+
'id' => self._id,
|
86
|
+
'new_record' => self.new_record?,
|
87
|
+
'errors' => self.errors,
|
88
|
+
'kind_name' => I18n.t("custom_fields.kind.#{self.safe_kind}")
|
89
|
+
}).merge(more)
|
90
|
+
end
|
91
|
+
|
92
|
+
def to_json
|
93
|
+
self.to_hash.to_json
|
94
|
+
end
|
95
|
+
|
75
96
|
protected
|
76
97
|
|
77
98
|
def uniqueness_of_label_and_alias
|
@@ -104,18 +125,17 @@ module CustomFields
|
|
104
125
|
end
|
105
126
|
|
106
127
|
def parentize_with_custom_fields(object)
|
128
|
+
return if self.parentized_done
|
129
|
+
|
107
130
|
object_name = object.class.to_s.underscore
|
108
131
|
|
109
132
|
self.association_name = self.metadata ? self.metadata.name : self.relations[object_name].inverse_of
|
110
133
|
|
111
|
-
if !self.relations.key?(object_name)
|
112
|
-
self.singleton_class.embedded_in object_name.to_sym, :inverse_of => self.association_name
|
113
|
-
end
|
114
|
-
|
115
134
|
parentize_without_custom_fields(object)
|
116
135
|
|
117
136
|
self.send(:set_unique_name!)
|
118
|
-
|
137
|
+
|
138
|
+
self.parentized_done = true
|
119
139
|
end
|
120
140
|
|
121
141
|
alias_method_chain :parentize, :custom_fields
|
@@ -6,19 +6,31 @@ module CustomFields
|
|
6
6
|
included do
|
7
7
|
|
8
8
|
def self.to_klass_with_custom_fields(fields, parent, association_name)
|
9
|
-
|
9
|
+
klass_name = self.klass_name_with_custom_fields(parent, association_name)
|
10
10
|
|
11
|
-
klass =
|
11
|
+
klass = Object.const_defined?(klass_name) ? Object.const_get(klass_name): nil
|
12
12
|
|
13
13
|
if klass.nil?
|
14
14
|
klass = self.build_proxy_class_with_custom_fields(fields, parent, association_name)
|
15
15
|
|
16
|
-
|
16
|
+
Object.const_set(klass_name, klass)
|
17
17
|
end
|
18
18
|
|
19
19
|
klass
|
20
20
|
end
|
21
21
|
|
22
|
+
def self.invalidate_proxy_class_with_custom_fields(parent, association_name)
|
23
|
+
klass_name = self.klass_name_with_custom_fields(parent, association_name)
|
24
|
+
|
25
|
+
if Object.const_defined?(klass_name)
|
26
|
+
Object.send(:remove_const, klass_name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.klass_name_with_custom_fields(parent, association_name)
|
31
|
+
"#{association_name.to_s.gsub(/^_/, '').singularize.camelize}#{parent.class.name.camelize}#{parent._id}"
|
32
|
+
end
|
33
|
+
|
22
34
|
def self.build_proxy_class_with_custom_fields(fields, parent, association_name)
|
23
35
|
(klass = Class.new(self)).class_eval <<-EOF
|
24
36
|
|
@@ -29,7 +41,9 @@ module CustomFields
|
|
29
41
|
end
|
30
42
|
|
31
43
|
def self.apply_custom_field(field)
|
32
|
-
|
44
|
+
unless field.persisted?
|
45
|
+
return unless field.valid?
|
46
|
+
end
|
33
47
|
|
34
48
|
(self.custom_fields ||= []) << field
|
35
49
|
|
@@ -66,7 +80,7 @@ module CustomFields
|
|
66
80
|
# copy scopes from the parent class
|
67
81
|
klass.write_inheritable_attribute(:scopes, self.scopes)
|
68
82
|
|
69
|
-
klass.association_name = association_name
|
83
|
+
klass.association_name = association_name.to_sym
|
70
84
|
klass._parent = parent
|
71
85
|
|
72
86
|
[*fields].each { |field| klass.apply_custom_field(field) }
|
@@ -1,35 +1,36 @@
|
|
1
1
|
module CustomFields
|
2
2
|
module Types
|
3
3
|
module Date
|
4
|
-
|
4
|
+
|
5
5
|
extend ActiveSupport::Concern
|
6
|
-
|
6
|
+
|
7
7
|
included do
|
8
8
|
register_type :date, ::Date
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
module InstanceMethods
|
12
|
-
|
12
|
+
|
13
13
|
def apply_date_type(klass)
|
14
|
-
|
14
|
+
|
15
15
|
klass.class_eval <<-EOF
|
16
16
|
def #{self.safe_alias}
|
17
17
|
self.#{self._name}.strftime(I18n.t('date.formats.default')) rescue nil
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def #{self.safe_alias}=(value)
|
21
|
-
if value.is_a?(String)
|
21
|
+
if value.is_a?(::String)
|
22
22
|
date = ::Date._strptime(value, I18n.t('date.formats.default'))
|
23
|
-
value = Date.new(date[:year], date[:mon], date[:mday])
|
23
|
+
value = ::Date.new(date[:year], date[:mon], date[:mday])
|
24
24
|
end
|
25
|
+
|
25
26
|
self.#{self._name} = value
|
26
27
|
end
|
27
28
|
EOF
|
28
|
-
|
29
|
+
|
29
30
|
end
|
30
|
-
|
31
|
+
|
31
32
|
end
|
32
|
-
|
33
|
+
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
@@ -1,36 +1,41 @@
|
|
1
1
|
module CustomFields
|
2
|
-
module Types
|
2
|
+
module Types
|
3
3
|
module Default
|
4
4
|
extend ActiveSupport::Concern
|
5
|
-
|
5
|
+
|
6
6
|
included do
|
7
7
|
cattr_accessor :field_types
|
8
|
-
end
|
9
|
-
|
8
|
+
end
|
9
|
+
|
10
10
|
module InstanceMethods
|
11
|
-
|
11
|
+
|
12
12
|
def apply_default_type(klass)
|
13
13
|
klass.class_eval <<-EOF
|
14
14
|
alias :#{self.safe_alias} :#{self._name}
|
15
15
|
alias :#{self.safe_alias}= :#{self._name}=
|
16
16
|
EOF
|
17
|
+
|
18
|
+
# add validation if required field
|
19
|
+
if self.required?
|
20
|
+
klass.validates_presence_of self.safe_alias.to_sym
|
21
|
+
end
|
17
22
|
end
|
18
|
-
|
23
|
+
|
19
24
|
end
|
20
|
-
|
25
|
+
|
21
26
|
module ClassMethods
|
22
27
|
|
23
28
|
def register_type(kind, klass = ::String)
|
24
29
|
self.field_types ||= {}
|
25
30
|
self.field_types[kind.to_sym] = klass unless klass.nil?
|
26
|
-
|
31
|
+
|
27
32
|
self.class_eval <<-EOF
|
28
33
|
def #{kind.to_s}?
|
29
34
|
self.kind.downcase == '#{kind}' rescue false
|
30
35
|
end
|
31
36
|
EOF
|
32
37
|
end
|
33
|
-
|
38
|
+
|
34
39
|
end
|
35
40
|
end
|
36
41
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: custom_fields
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 62196361
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
9
|
- 0
|
10
10
|
- beta
|
11
|
-
-
|
12
|
-
version: 1.0.0.beta.
|
11
|
+
- 5
|
12
|
+
version: 1.0.0.beta.5
|
13
13
|
platform: ruby
|
14
14
|
authors:
|
15
15
|
- Didier Lafforgue
|
@@ -17,47 +17,46 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2011-
|
20
|
+
date: 2011-03-06 00:00:00 +01:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|
24
|
-
name: mongoid
|
25
24
|
prerelease: false
|
26
|
-
|
25
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
27
26
|
none: false
|
28
27
|
requirements:
|
29
28
|
- - ~>
|
30
29
|
- !ruby/object:Gem::Version
|
31
|
-
hash:
|
30
|
+
hash: 15424091
|
32
31
|
segments:
|
33
32
|
- 2
|
34
33
|
- 0
|
35
34
|
- 0
|
36
35
|
- rc
|
37
|
-
-
|
38
|
-
version: 2.0.0.rc.
|
36
|
+
- 7
|
37
|
+
version: 2.0.0.rc.7
|
39
38
|
type: :runtime
|
40
|
-
|
39
|
+
requirement: *id001
|
40
|
+
name: mongoid
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name: activesupport
|
43
42
|
prerelease: false
|
44
|
-
|
43
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
45
44
|
none: false
|
46
45
|
requirements:
|
47
46
|
- - ">="
|
48
47
|
- !ruby/object:Gem::Version
|
49
|
-
hash:
|
48
|
+
hash: 15
|
50
49
|
segments:
|
51
50
|
- 3
|
52
51
|
- 0
|
53
|
-
-
|
54
|
-
version: 3.0.
|
52
|
+
- 4
|
53
|
+
version: 3.0.4
|
55
54
|
type: :runtime
|
56
|
-
|
55
|
+
requirement: *id002
|
56
|
+
name: activesupport
|
57
57
|
- !ruby/object:Gem::Dependency
|
58
|
-
name: locomotive_carrierwave
|
59
58
|
prerelease: false
|
60
|
-
|
59
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
61
60
|
none: false
|
62
61
|
requirements:
|
63
62
|
- - ">="
|
@@ -67,7 +66,8 @@ dependencies:
|
|
67
66
|
- 0
|
68
67
|
version: "0"
|
69
68
|
type: :runtime
|
70
|
-
|
69
|
+
requirement: *id003
|
70
|
+
name: locomotive_carrierwave
|
71
71
|
description: Manage custom fields to a mongoid document or a collection. This module is one of the core features we implemented in our custom cms named Locomotive.
|
72
72
|
email:
|
73
73
|
- didier@nocoffee.fr
|
@@ -97,6 +97,10 @@ files:
|
|
97
97
|
- lib/custom_fields/types/text.rb
|
98
98
|
- lib/custom_fields/version.rb
|
99
99
|
- lib/custom_fields.rb
|
100
|
+
- config/locales/de.yml
|
101
|
+
- config/locales/en.yml
|
102
|
+
- config/locales/fr.yml
|
103
|
+
- config/locales/pt-BR.yml
|
100
104
|
has_rdoc: true
|
101
105
|
homepage: http://github.com/locomotivecms/custom_fields
|
102
106
|
licenses: []
|