custom_fields 1.0.0.beta.4 → 1.0.0.beta.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []