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.
@@ -0,0 +1,9 @@
1
+ de:
2
+ custom_fields:
3
+ kind:
4
+ string: Einfache Texteingabe
5
+ text: Text
6
+ category: Auswahlbox
7
+ boolean: Checkbox
8
+ date: Datum
9
+ file: Datei
@@ -0,0 +1,9 @@
1
+ en:
2
+ custom_fields:
3
+ kind:
4
+ string: Simple Input
5
+ text: Text
6
+ category: Select
7
+ boolean: Checkbox
8
+ date: Date
9
+ file: File
@@ -0,0 +1,12 @@
1
+ fr:
2
+ custom_fields:
3
+ kind:
4
+ string: Texte
5
+ text: Zone de texte
6
+ category: Liste déroulante
7
+ boolean: Case à cocher
8
+ date: Date
9
+ file: Fichier
10
+ text_formatting:
11
+ none: Aucun
12
+ html: HTML
@@ -0,0 +1,9 @@
1
+ pt-BR:
2
+ custom_fields:
3
+ kind:
4
+ string: Texto Simples
5
+ text: Texto
6
+ category: Caixa de Seleção
7
+ boolean: Checkbox
8
+ date: Data
9
+ file: Arquivo
data/init.rb CHANGED
@@ -1,2 +1,2 @@
1
- # Include hook code here
1
+ # Init
2
2
  require File.dirname(__FILE__) + '/lib/custom_fields'
@@ -28,5 +28,19 @@ module Mongoid
28
28
  end
29
29
 
30
30
  ActiveSupport::Inflector.inflections do |inflect|
31
- inflect.uncountable 'metadata'
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 :#{singular_name}, :class_name => '::CustomFields::Metadata'
56
+ embeds_one :#{collection_name}, :class_name => '::CustomFields::Metadata'
45
57
 
46
- def metadata
47
- self.#{singular_name} || self.build_#{singular_name}
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 => '::CustomFields::Field'
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
- if custom_fields?(self, metadata.name)
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(metadata.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, metadata.name)
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
@@ -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.kind.downcase.to_sym]
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.kind.downcase}_type"
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).metadata.klass
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
- self.send(:set_alias)
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
- target_name = "#{association_name}_proxy_class"
9
+ klass_name = self.klass_name_with_custom_fields(parent, association_name)
10
10
 
11
- klass = parent.instance_variable_get(:"@#{target_name}")
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
- parent.instance_variable_set(:"@#{target_name}", klass)
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
- return unless field.valid?
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
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module CustomFields
3
- VERSION = "1.0.0.beta.4"
3
+ VERSION = "1.0.0.beta.5"
4
4
  end
5
5
  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: 62196363
4
+ hash: 62196361
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
9
  - 0
10
10
  - beta
11
- - 4
12
- version: 1.0.0.beta.4
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-01-27 00:00:00 +01:00
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
- requirement: &id001 !ruby/object:Gem::Requirement
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: 15424089
30
+ hash: 15424091
32
31
  segments:
33
32
  - 2
34
33
  - 0
35
34
  - 0
36
35
  - rc
37
- - 6
38
- version: 2.0.0.rc.6
36
+ - 7
37
+ version: 2.0.0.rc.7
39
38
  type: :runtime
40
- version_requirements: *id001
39
+ requirement: *id001
40
+ name: mongoid
41
41
  - !ruby/object:Gem::Dependency
42
- name: activesupport
43
42
  prerelease: false
44
- requirement: &id002 !ruby/object:Gem::Requirement
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: 7
48
+ hash: 15
50
49
  segments:
51
50
  - 3
52
51
  - 0
53
- - 0
54
- version: 3.0.0
52
+ - 4
53
+ version: 3.0.4
55
54
  type: :runtime
56
- version_requirements: *id002
55
+ requirement: *id002
56
+ name: activesupport
57
57
  - !ruby/object:Gem::Dependency
58
- name: locomotive_carrierwave
59
58
  prerelease: false
60
- requirement: &id003 !ruby/object:Gem::Requirement
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
- version_requirements: *id003
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: []