babylonia 0.1.1 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: e5e07171440e9ebac6b51d3f768b68471dcbd5cd
4
- data.tar.gz: 7c0141cd5353cfe4e8e4fa10abdad68675388466
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YzYzMTcwNjBhNThmMTUxYzVkZWE3ZTcwMzM4ZjhmM2MxZWMxMmVlNg==
5
+ data.tar.gz: !binary |-
6
+ YzkxZTg3YTc2YmY2NTFjMzdjMDIwYjg0OWQ3N2M0ZDA3OGE2MTkyMw==
5
7
  SHA512:
6
- metadata.gz: bc939cba85b5aadb2bf909dcccafff796137489ee22956aaf91c000f347e21b3fc3db967f2736c871b78848f56b8f4b77ec65af1cc2c172da6548a056952b30d
7
- data.tar.gz: df443e957bc998fb312d3f483f9fb38c68e8bfd817abf897db36f200ea7804811268cf1655a2b38a8f6508aefb76b836caa1e384c1d873120f3ec266bddab4e9
8
+ metadata.gz: !binary |-
9
+ ZTUxYjJhYTJjY2Q4Nzg3NmIzMGY1YzYxZjJjYTA0NTJjNWM5ZjAwODUxMWUx
10
+ NzE4YjdlN2RjZGRlYWMzNjlhN2Q1ZjJiZGEyZDhmMGU2NTlhMzQyODk2YjQ3
11
+ ZWI5M2UwYmQwNDI5YzIxY2I1MzE0NGNjMGFkYWU1YzIzMWEwZWE=
12
+ data.tar.gz: !binary |-
13
+ NTZmMzRhYzIwYjg0MTA3YTAyOWY3NWIwNjgzYTY1Y2UxOWY1MmUzNTY2YTdj
14
+ ZmNiODU0NmY5MTNkNzU2ZDFmZTQxNzA5MmY5MGIzNjY1N2RiNDk0ZmM3ZDg1
15
+ MzA3YmI1NTM2MWFlMTllYWIyMTFjMDYxNzMxNzFlMTQ4ZTY4MDM=
@@ -3,164 +3,203 @@ require 'i18n'
3
3
 
4
4
  # Let your users translate their content into their languages without additional tables or columns in your tables
5
5
  # @author Beat Richartz
6
- # @version 0.0.2
6
+ # @version 0.2.0
7
7
  # @since 0.0.1
8
8
  #
9
9
  module Babylonia
10
10
 
11
- # Class methods to extend a class with in order to make it able to handle translatable attributes
11
+ # Helper Methods for locales
12
+ # @author Beat Richartz
13
+ # @version 0.0.2
14
+ # @since 0.0.1
12
15
  #
13
- module ClassMethods
14
- # Main class method ob Babylonia. Use to make attributes translatable
15
- # @param [Symbol] fields the attributes to translate
16
- # @param [Hash] options The options for translation
17
- # @option [Symbol, Proc, String] locale The current locale - can be either a symbol that will be sent to the instance, a locale symbol that is included in available_locales or a proc that will get called with the instance. Defaults to I18n.locale at the time of use
18
- # @option [Symbol, Proc, String] default_locale The fallback / default locale - can be either a symbol that will be sent to the instance, a locale symbol that is included in available_locales, a proc that will get called with the instance
19
- # @option [Symbol, Proc, Array] available_locales The available locales - can be either a symbol that will be sent to the instance, a proc that will get called with the instance, or an Array of symbols of available locales. Defaults to I18n.available_locales at the time of use.
20
- # @option [Boolean] fallback Wheter to fallback to the default locale or not
21
- # @option [String] placeholder The placeholder to use for missing translations
16
+ module HelperMethods
17
+ # Return the currently active locale for the object
18
+ # @return [Symbol] The currently active locale
22
19
  #
23
- def build_babylonian_tower_on(*fields)
24
- options = fields.last.is_a?(Hash) ? fields.pop : {}
25
- options[:locale] ||= lambda { |r| I18n.locale }
26
- options[:default_locale] ||= lambda { |r| I18n.default_locale }
27
- options[:available_locales] ||= lambda { |r| I18n.available_locales }
28
- options[:fallback] = true if options[:fallback].nil?
29
-
30
- fields.each do |field|
31
- # Alias method chain the field to a translated value
32
- # @param [Symbol] locale Pass a locale to get the field translation in this specific locale
33
- # @param [Boolean] fallback Whether a fallback should be used, defaults to true
34
- # @return [String, NilClass] Either the string with the translation, the fallback, the placeholder or nil
35
- # @example Call a field in italian
36
- # your_instance.field(:it) #=> "Translation"
37
- #
38
- define_method :"#{field}_translated" do |l=nil, options={fallback: true}|
39
- field_hash = send(:"#{field}_hash")
40
- translation = field_hash[l || locale]
41
- translation = field_hash[default_locale] if translation.nil? or translation.empty? and options[:fallback] and locale_fallback?
42
- (translation.nil? or translation.empty?) ? missing_translation_placeholder(field) : translation
43
- end
44
- alias_method :"#{field}_raw", field
45
- alias_method field, :"#{field}_translated"
46
-
47
- # Return the translated values as a hash
48
- # @return [Hash] The hash with all the translations stored in the field
49
- #
50
- define_method :"#{field}_hash" do
51
- field_content = send(:"#{field}_raw")
52
- field_content.is_a?(String) ? YAML.load(field_content) : {}
53
- end
54
-
55
- # Set the field to a value. This either takes a string or a hash
56
- # If given a String, the current locale is set to this value
57
- # If given a Hash, the hash is merged into the current translation hash, and empty values are purged
58
- # @param [String, Hash] data The data to set either the current language translation or all translations to
59
- # @example Set the translation for the current locale
60
- # your_object.field = "TRANSLATION"
61
- # @example Set the translation and delete italian
62
- # your_object.field = {de: 'DEUTSCH', it: ''}
63
- #
64
- define_method :"#{field}_translated=" do |data|
65
- current_hash = send(:"#{field}_hash")
66
-
67
- if data.is_a?(String)
68
- current_hash.merge! locale => data
69
- elsif data.is_a?(Hash)
70
- data.delete_if{|k,v| !has_available_locale?(k) }
71
- current_hash.merge! data
72
- end
73
-
74
- send(:"#{field}_raw=", YAML.dump(current_hash.delete_if{|k,v| v.nil? or v.empty? }))
75
- end
76
- alias_method :"#{field}_raw=", :"#{field}="
77
- alias_method :"#{field}=", :"#{field}_translated="
78
- end
79
-
80
- # Return the currently active locale for the object
81
- # @return [Symbol] The currently active locale
82
- #
83
- define_method :locale do
84
- evaluate_localization_option!(:locale)
85
- end
86
-
87
- # Return the default locale for the object
88
- # @return [Symbol] The currently active locale
89
- #
90
- define_method :default_locale do
91
- evaluate_localization_option!(:default_locale)
20
+ def locale
21
+ evaluate_localization_option!(:locale)
22
+ end
23
+
24
+ # Return the default locale for the object
25
+ # @return [Symbol] The currently active locale
26
+ #
27
+ def default_locale
28
+ evaluate_localization_option!(:default_locale)
29
+ end
30
+
31
+ # Return if the object falls back on translations
32
+ # @return [Boolean] if the translations fall back to the default locale
33
+ #
34
+ def locale_fallback?
35
+ evaluate_localization_option!(:fallback)
36
+ end
37
+
38
+ # Return the missing translation placeholder
39
+ # @return [String] The missing translation placeholder
40
+ #
41
+ def missing_translation_placeholder field
42
+ evaluate_localization_option!(:placeholder, field)
43
+ end
44
+
45
+ # Return if a translation in the language is stored in all translated fields
46
+ # @return [Boolean] True if a translation is stored
47
+ #
48
+ def has_locale? locale
49
+ locales.include?(locale.to_sym)
50
+ end
51
+
52
+ # Return all the available locales
53
+ # @return [Array] An array of symbols of all available locales
54
+ #
55
+ def available_locales
56
+ evaluate_localization_option!(:available_locales)
57
+ end
58
+
59
+ # Return if a locale is theoretically available in all translated fields
60
+ # @return [Boolean] True if the language is available
61
+ #
62
+ def has_available_locale? locale
63
+ available_locales.include?(locale.to_sym)
64
+ end
65
+
66
+ protected
67
+
68
+ def translation_nil_or_empty? translation
69
+ translation.nil? or translation.empty?
70
+ end
71
+
72
+ def dump_translation_locale_hash hash
73
+ YAML.dump(hash.delete_if{|k,v| translation_nil_or_empty?(v) })
74
+ end
75
+
76
+ def fallback_to_default_locale!(hash, translation, options)
77
+ if translation_nil_or_empty?(translation) and options[:fallback] and locale_fallback?
78
+ hash[default_locale]
79
+ else
80
+ translation
92
81
  end
93
-
94
- # Return if the object falls back on translations
95
- # @return [Boolean] if the translations fall back to the default locale
96
- #
97
- define_method :locale_fallback? do
98
- evaluate_localization_option!(:fallback)
82
+ end
83
+ end
84
+
85
+ # Method missing implementation for virtual attributes
86
+ # @author Beat Richartz
87
+ # @version 0.0.2
88
+ # @since 0.0.1
89
+ #
90
+ module VirtualAttributes
91
+ # Define method missing to be able to access a language directly
92
+ # Enables to call a language virtual attribute directly
93
+ # @note Since the virtual attribute is called directly, there is no fallback on this unless you set it to true
94
+ # @example Call a getter directly
95
+ # object.field_de #=> 'DEUTSCH'
96
+ # @example Call a setter directly
97
+ # object.field_de = 'DEUTSCH'
98
+ # @example Call an untranslated field
99
+ # object.field_it #=> nil
100
+ #
101
+ # @example Call a field with fallback
102
+ # object.field_it(fallback: true)
103
+ def method_missing meth, *args, &block
104
+ if parts = extract_locale_method_parts(meth)
105
+ parts[2] ? send(parts[0] + parts[2].to_s, { parts[1].to_sym => args.first }) : send(parts[0], parts[1].to_sym, args.first || {})
106
+ else
107
+ super(meth, *args, &block)
99
108
  end
100
-
101
- # Return the missing translation placeholder
102
- # @return [String] The missing translation placeholder
103
- #
104
- define_method :missing_translation_placeholder do |field|
105
- evaluate_localization_option!(:placeholder, field)
109
+ end
110
+
111
+ private
112
+
113
+ def extract_locale_method_parts meth
114
+ if (parts = meth.to_s.match(/\A([^_]+)_(\w+)(=)?\z/).to_a[1..3]) && localized?(parts[0]) && has_available_locale?(parts[1])
115
+ parts
106
116
  end
107
-
108
- # Return languages stored in all translated fields
109
- # @return [Array] An array containing all languages stored
117
+ end
118
+ end
119
+
120
+ # Class methods to extend a class with in order to make it able to handle translatable attributes
121
+ #
122
+ module ClassMethods
123
+ private
124
+
125
+ def install_locale_field_getter_for(field)
126
+ # Alias method chain the field to a translated value
127
+ # @param [Symbol] locale Pass a locale to get the field translation in this specific locale
128
+ # @param [Boolean] fallback Whether a fallback should be used, defaults to true
129
+ # @return [String, NilClass] Either the string with the translation, the fallback, the placeholder or nil
130
+ # @example Call a field in italian
131
+ # your_instance.field(:it) #=> "Translation"
110
132
  #
111
- define_method :locales do
112
- first_field_locales = send(:"#{fields.first}_hash").keys
113
- fields.inject(first_field_locales){|o, f| o & send(:"#{f}_hash").keys }
133
+ define_method :"#{field}_translated" do |l=nil, options={fallback: true}|
134
+ field_hash = send(:"#{field}_hash")
135
+ translation = field_hash[l || locale]
136
+ translation = fallback_to_default_locale!(field_hash, translation, options)
137
+ translation_nil_or_empty?(translation) ? missing_translation_placeholder(field) : translation
114
138
  end
115
-
116
- # Return if a translation in the language is stored in all translated fields
117
- # @return [Boolean] True if a translation is stored
139
+ alias_method :"#{field}_raw", field
140
+ alias_method field, :"#{field}_translated"
141
+ end
142
+
143
+ def install_locale_field_hash_for(field)
144
+ # Return the translated values as a hash
145
+ # @return [Hash] The hash with all the translations stored in the field
118
146
  #
119
- define_method :has_locale? do |locale|
120
- locales.include?(locale.to_sym)
121
- end
122
-
123
- # Return all the available locales
124
- # @return [Array] An array of symbols of all available locales
125
- #
126
- define_method :available_locales do
127
- evaluate_localization_option!(:available_locales)
147
+ define_method :"#{field}_hash" do
148
+ field_content = send(:"#{field}_raw")
149
+ field_content.is_a?(String) ? YAML.load(field_content) : {}
128
150
  end
129
-
130
- # Return if a locale is theoretically available in all translated fields
131
- # @return [Boolean] True if the language is available
151
+ end
152
+
153
+ def install_locale_field_setter_for(field)
154
+ # Set the field to a value. This either takes a string or a hash
155
+ # If given a String, the current locale is set to this value
156
+ # If given a Hash, the hash is merged into the current translation hash, and empty values are purged
157
+ # @param [String, Hash] data The data to set either the current language translation or all translations to
158
+ # @example Set the translation for the current locale
159
+ # your_object.field = "TRANSLATION"
160
+ # @example Set the translation and delete italian
161
+ # your_object.field = {de: 'DEUTSCH', it: ''}
132
162
  #
133
- define_method :has_available_locale? do |locale|
134
- available_locales.include?(locale.to_sym)
163
+ define_method :"#{field}_translated=" do |data|
164
+ current_hash = send(:"#{field}_hash")
165
+
166
+ if data.is_a?(String)
167
+ current_hash.merge! locale => data
168
+ elsif data.is_a?(Hash)
169
+ data.delete_if{|k,v| !has_available_locale?(k) }
170
+ current_hash.merge! data
171
+ end
172
+
173
+ send(:"#{field}_raw=", dump_translation_locale_hash(current_hash))
135
174
  end
136
-
175
+ alias_method :"#{field}_raw=", :"#{field}="
176
+ alias_method :"#{field}=", :"#{field}_translated="
177
+ end
178
+
179
+ def install_virtual_locale_attributes_via_method_missing
180
+
181
+ end
182
+
183
+ def install_localized_helper_for(fields)
137
184
  # Return if an attribute is localized
138
185
  # @return [Boolean] True if the attribute is localized
139
186
  #
140
187
  define_method :localized? do |attr|
141
188
  fields.include?(attr.to_sym)
142
189
  end
143
-
144
- # Define method missing to be able to access a language directly
145
- # Enables to call a language virtual attribute directly
146
- # @note Since the virtual attribute is called directly, there is no fallback on this unless you set it to true
147
- # @example Call a getter directly
148
- # object.field_de #=> 'DEUTSCH'
149
- # @example Call a setter directly
150
- # object.field_de = 'DEUTSCH'
151
- # @example Call an untranslated field
152
- # object.field_it #=> nil
190
+ end
191
+
192
+ def install_locales_helper_for(fields)
193
+ # Return languages stored in all translated fields
194
+ # @return [Array] An array containing all languages stored
153
195
  #
154
- # @example Call a field with fallback
155
- # object.field_it(fallback: true)
156
- define_method :method_missing do |meth, *args, &block|
157
- if (m = meth.to_s.match(/\A([^_]+)_(\w+)(=)?\z/).to_a[1..3]) && localized?(m[0]) && has_available_locale?(m[1])
158
- m[2] ? send(m[0] + m[2].to_s, {m[1].to_sym => args.first}) : send(m[0], m[1].to_sym, args.first || {})
159
- else
160
- super(meth, *args, &block)
161
- end
196
+ define_method :locales do
197
+ first_field_locales = send(:"#{fields.first}_hash").keys
198
+ fields.inject(first_field_locales){|o, f| o & send(:"#{f}_hash").keys }
162
199
  end
163
-
200
+ end
201
+
202
+ def install_locale_options_evaluation(options)
164
203
  # Evaluate a localization option
165
204
  #
166
205
  define_method :evaluate_localization_option! do |option, field=nil, recursion=false|
@@ -176,5 +215,42 @@ module Babylonia
176
215
  end
177
216
  end
178
217
  end
218
+
219
+ def evaluate_locale_options_for(fields)
220
+ options = fields.last.is_a?(Hash) ? fields.pop : {}
221
+ options[:locale] ||= lambda { |r| I18n.locale }
222
+ options[:default_locale] ||= lambda { |r| I18n.default_locale }
223
+ options[:available_locales] ||= lambda { |r| I18n.available_locales }
224
+ options[:fallback] = true if options[:fallback].nil?
225
+ options
226
+ end
227
+
228
+ # Main class method ob Babylonia. Use to make attributes translatable
229
+ # @param [Symbol] fields the attributes to translate
230
+ # @param [Hash] options The options for translation
231
+ # @option [Symbol, Proc, String] locale The current locale - can be either a symbol that will be sent to the instance, a locale symbol that is included in available_locales or a proc that will get called with the instance. Defaults to I18n.locale at the time of use
232
+ # @option [Symbol, Proc, String] default_locale The fallback / default locale - can be either a symbol that will be sent to the instance, a locale symbol that is included in available_locales, a proc that will get called with the instance
233
+ # @option [Symbol, Proc, Array] available_locales The available locales - can be either a symbol that will be sent to the instance, a proc that will get called with the instance, or an Array of symbols of available locales. Defaults to I18n.available_locales at the time of use.
234
+ # @option [Boolean] fallback Wheter to fallback to the default locale or not
235
+ # @option [String] placeholder The placeholder to use for missing translations
236
+ #
237
+ public
238
+
239
+ def build_babylonian_tower_on(*fields)
240
+ options = evaluate_locale_options_for(fields)
241
+
242
+ fields.each do |field|
243
+ install_locale_field_getter_for(field)
244
+ install_locale_field_setter_for(field)
245
+ install_locale_field_hash_for(field)
246
+ end
247
+
248
+ include HelperMethods
249
+ install_localized_helper_for(fields)
250
+ install_locales_helper_for(fields)
251
+
252
+ include VirtualAttributes
253
+ install_locale_options_evaluation(options)
254
+ end
179
255
  end
180
256
  end
@@ -1,5 +1,5 @@
1
1
  module Babylonia
2
2
  # The current gem version
3
3
  #
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
metadata CHANGED
@@ -1,41 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: babylonia
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Beat Richartz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-20 00:00:00.000000000 Z
11
+ date: 2013-11-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ! '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.5.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ! '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.5.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ! '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: 1.0.0
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ! '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.0.0
41
41
  description: Let your users translate their content into their languages without additional
@@ -70,21 +70,20 @@ require_paths:
70
70
  - lib
71
71
  required_ruby_version: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ! '>='
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  required_rubygems_version: !ruby/object:Gem::Requirement
77
77
  requirements:
78
- - - '>='
78
+ - - ! '>='
79
79
  - !ruby/object:Gem::Version
80
80
  version: '0'
81
81
  requirements: []
82
82
  rubyforge_project:
83
- rubygems_version: 2.0.7
83
+ rubygems_version: 2.1.11
84
84
  signing_key:
85
85
  specification_version: 4
86
86
  summary: Let there be languages!
87
87
  test_files:
88
88
  - spec/babylonia/class_methods_spec.rb
89
89
  - spec/spec_helper.rb
90
- has_rdoc: