i18n-js 3.0.0.rc8 → 3.0.0.rc9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,14 +1,12 @@
1
1
  <%# encoding: utf-8 %>
2
2
 
3
3
  ;(function(factory) {
4
- if (typeof module !== 'undefined') {
4
+ if (typeof module !== 'undefined' && module.exports) {
5
5
  // Node/CommonJS
6
6
  factory(require('i18n'));
7
-
8
7
  } else if (typeof define === 'function' && define.amd) {
9
8
  // AMD
10
9
  define(['i18n'], factory);
11
-
12
10
  } else {
13
11
  // Browser globals
14
12
  factory(this.I18n);
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "i18n", "0.7.0"
6
+
7
+ gemspec :path => "../"
@@ -23,7 +23,6 @@ Gem::Specification.new do |s|
23
23
  s.add_development_dependency "activesupport", ">= 3"
24
24
  s.add_development_dependency "rspec", "~> 3.0"
25
25
  s.add_development_dependency "rake"
26
- s.add_development_dependency "pry-meta"
27
26
  s.add_development_dependency "gem-release", ">= 0.7"
28
27
 
29
28
  s.required_ruby_version = ">= 1.9.3"
@@ -1,12 +1,13 @@
1
+ require "yaml"
1
2
  require "i18n"
2
3
  require "fileutils"
3
-
4
4
  require "i18n/js/utils"
5
5
 
6
6
  module I18n
7
7
  module JS
8
8
  require "i18n/js/dependencies"
9
9
  require "i18n/js/fallback_locales"
10
+ require "i18n/js/segment"
10
11
  if JS::Dependencies.rails?
11
12
  require "i18n/js/middleware"
12
13
  require "i18n/js/engine"
@@ -20,6 +21,7 @@ module I18n
20
21
  def self.config_file_path
21
22
  @config_file_path ||= DEFAULT_CONFIG_PATH
22
23
  end
24
+
23
25
  def self.config_file_path=(new_path)
24
26
  @config_file_path = new_path
25
27
  end
@@ -29,48 +31,51 @@ module I18n
29
31
  def self.export
30
32
  export_i18n_js
31
33
 
32
- translation_segments.each do |filename, translations|
33
- save(translations, filename)
34
- end
34
+ translation_segments.each(&:save!)
35
35
  end
36
36
 
37
- def self.segments_per_locale(pattern, scope)
38
- I18n.available_locales.each_with_object({}) do |locale, segments|
37
+ def self.segments_per_locale(pattern, scope, exceptions, options)
38
+ I18n.available_locales.each_with_object([]) do |locale, segments|
39
39
  scope = [scope] unless scope.respond_to?(:each)
40
- result = scoped_translations(scope.collect{|s| "#{locale}.#{s}"})
41
- merge_with_fallbacks!(result, locale, scope) if use_fallbacks?
40
+ result = scoped_translations(scope.collect{|s| "#{locale}.#{s}"}, exceptions)
41
+ merge_with_fallbacks!(result, locale, scope, exceptions) if use_fallbacks?
42
42
 
43
43
  next if result.empty?
44
-
45
- segment_name = ::I18n.interpolate(pattern,{:locale => locale})
46
- segments[segment_name] = result
44
+ segments << Segment.new(::I18n.interpolate(pattern, {:locale => locale}), result, options)
47
45
  end
48
46
  end
49
47
 
50
- def self.segment_for_scope(scope)
48
+ def self.segment_for_scope(scope, exceptions)
51
49
  if scope == "*"
52
- translations
50
+ exclude(translations, exceptions)
53
51
  else
54
- scoped_translations(scope)
52
+ scoped_translations(scope, exceptions)
55
53
  end
56
54
  end
57
55
 
58
56
  def self.configured_segments
59
- config[:translations].each_with_object({}) do |options, segments|
60
- options.reverse_merge!(:only => "*")
61
- if options[:file] =~ ::I18n::INTERPOLATION_PATTERN
62
- segments.merge!(segments_per_locale(options[:file], options[:only]))
57
+ config[:translations].inject([]) do |segments, options|
58
+ file = options[:file]
59
+ only = options[:only] || '*'
60
+ exceptions = [options[:except] || []].flatten
61
+
62
+ segment_options = options.slice(:namespace, :pretty_print)
63
+
64
+ if file =~ ::I18n::INTERPOLATION_PATTERN
65
+ segments += segments_per_locale(file, only, exceptions, segment_options)
63
66
  else
64
- result = segment_for_scope(options[:only])
65
- segments[options[:file]] = result unless result.empty?
67
+ result = segment_for_scope(only, exceptions)
68
+ segments << Segment.new(file, result, segment_options) unless result.empty?
66
69
  end
70
+
71
+ segments
67
72
  end
68
73
  end
69
74
 
70
75
  def self.filtered_translations
71
76
  {}.tap do |result|
72
- translation_segments.each do |filename, translations|
73
- Utils.deep_merge!(result, translations)
77
+ translation_segments.each do |segment|
78
+ Utils.deep_merge!(result, segment.translations)
74
79
  end
75
80
  end
76
81
  end
@@ -79,7 +84,7 @@ module I18n
79
84
  if config? && config[:translations]
80
85
  configured_segments
81
86
  else
82
- {"#{DEFAULT_EXPORT_DIR_PATH}/translations.js" => translations}
87
+ [Segment.new("#{DEFAULT_EXPORT_DIR_PATH}/translations.js", translations)]
83
88
  end
84
89
  end
85
90
 
@@ -99,28 +104,30 @@ module I18n
99
104
  File.file? config_file_path
100
105
  end
101
106
 
102
- # Convert translations to JSON string and save file.
103
- def self.save(translations, file)
104
- FileUtils.mkdir_p File.dirname(file)
105
-
106
- File.open(file, "w+") do |f|
107
- f << %(I18n.translations || (I18n.translations = {});\n)
108
- Utils.strip_keys_with_nil_values(translations).each do |locale, translations_for_locale|
109
- f << %(I18n.translations["#{locale}"] = #{translations_for_locale.to_json};\n);
110
- end
111
- end
112
- end
113
-
114
- def self.scoped_translations(scopes) # :nodoc:
107
+ def self.scoped_translations(scopes, exceptions = []) # :nodoc:
115
108
  result = {}
116
109
 
117
110
  [scopes].flatten.each do |scope|
118
- Utils.deep_merge! result, filter(translations, scope)
111
+ translations_without_exceptions = exclude(translations, exceptions)
112
+ filtered_translations = filter(translations_without_exceptions, scope)
113
+
114
+ Utils.deep_merge! result, filtered_translations
119
115
  end
120
116
 
121
117
  result
122
118
  end
123
119
 
120
+ # Exclude keys from translations listed in the `except:` section in the config file
121
+ def self.exclude(translations, exceptions)
122
+ return translations if exceptions.empty?
123
+
124
+ exceptions.inject(translations) do |memo, exception|
125
+ Utils.deep_reject(memo) do |key, value|
126
+ key.to_s == exception.to_s
127
+ end
128
+ end
129
+ end
130
+
124
131
  # Filter translations according to the specified scope.
125
132
  def self.filter(translations, scopes)
126
133
  scopes = scopes.split(".") if scopes.is_a?(String)
@@ -160,35 +167,38 @@ module I18n
160
167
  end
161
168
 
162
169
  # deep_merge! given result with result for fallback locale
163
- def self.merge_with_fallbacks!(result, locale, scope)
170
+ def self.merge_with_fallbacks!(result, locale, scope, exceptions)
164
171
  result[locale] ||= {}
165
172
  fallback_locales = FallbackLocales.new(fallbacks, locale)
166
173
 
167
174
  fallback_locales.each do |fallback_locale|
168
- fallback_result = scoped_translations(scope.collect{|s| "#{fallback_locale}.#{s}"}) # NOTE: Duplicated code here
175
+ fallback_result = scoped_translations(scope.collect{|s| "#{fallback_locale}.#{s}"}, exceptions) # NOTE: Duplicated code here
169
176
  result[locale] = Utils.deep_merge(fallback_result[fallback_locale], result[locale])
170
177
  end
171
178
  end
172
179
 
173
-
174
180
  ### Export i18n.js
175
181
  begin
182
+
176
183
  # Copy i18n.js
177
184
  def self.export_i18n_js
178
- return if export_i18n_js_dir_path.nil?
185
+ return unless export_i18n_js_dir_path.is_a? String
179
186
 
180
187
  FileUtils.mkdir_p(export_i18n_js_dir_path)
181
188
 
182
189
  i18n_js_path = File.expand_path('../../../app/assets/javascripts/i18n.js', __FILE__)
183
190
  FileUtils.cp(i18n_js_path, export_i18n_js_dir_path)
184
191
  end
185
- def self.export_i18n_js_dir_path
186
- return @export_i18n_js_dir_path if defined?(@export_i18n_js_dir_path)
187
192
 
188
- @export_i18n_js_dir_path = DEFAULT_EXPORT_DIR_PATH
193
+ def self.export_i18n_js_dir_path
194
+ @export_i18n_js_dir_path ||= (config[:export_i18n_js] || :none) if config.has_key?(:export_i18n_js)
195
+ @export_i18n_js_dir_path ||= DEFAULT_EXPORT_DIR_PATH
196
+ @export_i18n_js_dir_path
189
197
  end
198
+
190
199
  # Setting this to nil would disable i18n.js exporting
191
200
  def self.export_i18n_js_dir_path=(new_path)
201
+ new_path = :none unless new_path.is_a? String
192
202
  @export_i18n_js_dir_path = new_path
193
203
  end
194
204
  end
@@ -1,13 +1,15 @@
1
1
  module I18n
2
2
  module JS
3
+ # When using `safe_gem_check` to check for a pre-release version of gem,
4
+ # we need to specify pre-release version suffix in version constraint
3
5
  module Dependencies
4
6
  class << self
5
7
  def rails3?
6
- safe_gem_check("rails", "~> 3") && running_rails3?
8
+ safe_gem_check("rails", "~> 3.0") && running_rails3?
7
9
  end
8
10
 
9
11
  def rails4?
10
- safe_gem_check("rails", "~> 4") && running_rails4?
12
+ safe_gem_check("rails", "~> 4.0", ">= 4.0.0.beta1") && running_rails4?
11
13
  end
12
14
 
13
15
  def sprockets_supports_register_preprocessor?
@@ -19,7 +21,7 @@ module I18n
19
21
  end
20
22
 
21
23
  def rails_available?
22
- safe_gem_check("rails", '>= 3')
24
+ safe_gem_check("rails", '>= 3.0.0.beta')
23
25
  end
24
26
 
25
27
  def using_asset_pipeline?
@@ -49,11 +51,11 @@ module I18n
49
51
  defined?(Rails) && Rails.respond_to?(:version)
50
52
  end
51
53
 
52
- def safe_gem_check(gem_name, version_string)
54
+ def safe_gem_check(*args)
53
55
  if Gem::Specification.respond_to?(:find_by_name)
54
- Gem::Specification.find_by_name(gem_name, version_string)
56
+ Gem::Specification.find_by_name(*args)
55
57
  elsif Gem.respond_to?(:available?)
56
- Gem.available?(gem_name, version_string)
58
+ Gem.available?(*args)
57
59
  end
58
60
  rescue Gem::LoadError
59
61
  false
@@ -0,0 +1,39 @@
1
+ module I18n
2
+ module JS
3
+
4
+ # Class which enscapulates a translations hash and outputs a single JSON translation file
5
+ class Segment
6
+ attr_accessor :file, :translations, :namespace, :pretty_print
7
+
8
+ def initialize(file, translations, options = {})
9
+ @file = file
10
+ @translations = translations
11
+ @namespace = options[:namespace] || 'I18n'
12
+ @pretty_print = !!options[:pretty_print]
13
+ end
14
+
15
+ # Saves JSON file containing translations
16
+ def save!
17
+ FileUtils.mkdir_p File.dirname(self.file)
18
+
19
+ File.open(self.file, "w+") do |f|
20
+ f << %(#{self.namespace}.translations || (#{self.namespace}.translations = {});\n)
21
+ self.translations.each do |locale, translations|
22
+ f << %(#{self.namespace}.translations["#{locale}"] = #{print_json(translations)};\n);
23
+ end
24
+ end
25
+ end
26
+
27
+ protected
28
+
29
+ # Outputs pretty or ugly JSON depending on :pretty_print option
30
+ def print_json(translations)
31
+ if pretty_print
32
+ JSON.pretty_generate(translations)
33
+ else
34
+ translations.to_json
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -5,11 +5,11 @@ module I18n
5
5
  MERGER = proc do |key, v1, v2|
6
6
  Hash === v1 && Hash === v2 ? v1.merge(v2, &MERGER) : v2
7
7
  end
8
+
8
9
  HASH_NIL_VALUE_CLEANER_PROC = proc do |k, v|
9
- v.kind_of?(Hash) ? (v.delete_if(&HASH_NIL_VALUE_CLEANER_PROC); false) : v.nil?
10
+ v.kind_of?(Hash) ? (v.delete_if(&HASH_NIL_VALUE_CLEANER_PROC); false) : v.nil?
10
11
  end
11
12
 
12
-
13
13
  def self.strip_keys_with_nil_values(hash)
14
14
  hash.dup.delete_if(&HASH_NIL_VALUE_CLEANER_PROC)
15
15
  end
@@ -21,6 +21,14 @@ module I18n
21
21
  def self.deep_merge!(target_hash, hash) # :nodoc:
22
22
  target_hash.merge!(hash, &MERGER)
23
23
  end
24
+
25
+ def self.deep_reject(hash, &block)
26
+ hash.each_with_object({}) do |(k, v), memo|
27
+ unless block.call(k, v)
28
+ memo[k] = v.kind_of?(Hash) ? deep_reject(v, &block) : v
29
+ end
30
+ end
31
+ end
24
32
  end
25
33
  end
26
34
  end
@@ -4,7 +4,7 @@ module I18n
4
4
  MAJOR = 3
5
5
  MINOR = 0
6
6
  PATCH = 0
7
- STRING = "#{MAJOR}.#{MINOR}.#{PATCH}.rc8"
7
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}.rc9"
8
8
  end
9
9
  end
10
10
  end
@@ -7,5 +7,9 @@
7
7
  "main": "app/assets/javascripts/i18n.js",
8
8
  "scripts": {
9
9
  "test": "./node_modules/.bin/jasmine-node spec/js"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/fnando/i18n-js.git"
10
14
  }
11
15
  }
@@ -0,0 +1,5 @@
1
+ translations:
2
+ - file: "tmp/i18n-js/trimmed.js"
3
+ except:
4
+ - "active_admin"
5
+ - "mailers"
@@ -0,0 +1,6 @@
1
+
2
+ export_i18n_js: 'tmp/i18n-js/foo'
3
+
4
+ translations:
5
+ - file: "tmp/i18n-js/%{locale}.js"
6
+ only: '*'
@@ -0,0 +1,6 @@
1
+
2
+ export_i18n_js: false
3
+
4
+ translations:
5
+ - file: "tmp/i18n-js/%{locale}.js"
6
+ only: '*'
@@ -0,0 +1,5 @@
1
+ translations:
2
+ - file: "tmp/i18n-js/%{locale}.js"
3
+ only: '*'
4
+ namespace: "Foo"
5
+ pretty_print: true
@@ -29,13 +29,15 @@ describe I18n::JS do
29
29
 
30
30
  it "exports messages using custom output path" do
31
31
  set_config "custom_path.yml"
32
- I18n::JS.should_receive(:save).with(translations, "tmp/i18n-js/all.js")
32
+ I18n::JS::Segment.should_receive(:new).with("tmp/i18n-js/all.js", translations, {}).and_call_original
33
+ I18n::JS::Segment.any_instance.should_receive(:save!).with(no_args)
33
34
  I18n::JS.export
34
35
  end
35
36
 
36
37
  it "sets default scope to * when not specified" do
37
38
  set_config "no_scope.yml"
38
- I18n::JS.should_receive(:save).with(translations, "tmp/i18n-js/no_scope.js")
39
+ I18n::JS::Segment.should_receive(:new).with("tmp/i18n-js/no_scope.js", translations, {}).and_call_original
40
+ I18n::JS::Segment.any_instance.should_receive(:save!).with(no_args)
39
41
  I18n::JS.export
40
42
  end
41
43
 
@@ -59,6 +61,7 @@ describe I18n::JS do
59
61
  I18n::JS.export
60
62
 
61
63
  file_should_exist "en.js"
64
+ file_should_exist "fr.js"
62
65
  end
63
66
 
64
67
  it "exports with multiple conditions" do
@@ -73,18 +76,23 @@ describe I18n::JS do
73
76
 
74
77
  set_config "multiple_conditions_per_locale.yml"
75
78
 
76
- expected_locales = %w(en fr)
77
-
78
79
  result = I18n::JS.translation_segments
79
- expected_files = expected_locales.map { |locale| "tmp/i18n-js/bits.#{locale}.js" }
80
- result.keys.should eql(expected_files)
80
+ result.map(&:file).should eql(["tmp/i18n-js/bits.en.js", "tmp/i18n-js/bits.fr.js"])
81
81
 
82
- expected_locales.each do |lang|
83
- result["tmp/i18n-js/bits.#{lang}.js"].keys.should eql([lang.to_sym])
84
- result["tmp/i18n-js/bits.#{lang}.js"][lang.to_sym].keys.sort.should eql([:date, :number])
82
+ %w(en fr).each do |lang|
83
+ segment = result.select{|s| s.file == "tmp/i18n-js/bits.#{lang}.js"}.first
84
+ segment.translations.keys.should eql([lang.to_sym])
85
+ segment.translations[lang.to_sym].keys.sort.should eql([:date, :number])
85
86
  end
86
87
  end
87
88
 
89
+ it "exports with :except condition" do
90
+ set_config "except_condition.yml"
91
+ I18n::JS.export
92
+
93
+ file_should_exist "trimmed.js"
94
+ end
95
+
88
96
  it "calls .export_i18n_js" do
89
97
  allow(described_class).to receive(:export_i18n_js)
90
98
  I18n::JS.export
@@ -132,33 +140,67 @@ describe I18n::JS do
132
140
  end
133
141
  end
134
142
 
143
+ context "exceptions" do
144
+ it "does not include a key listed in the exceptions list" do
145
+ result = I18n::JS.scoped_translations("*", ['admin'])
146
+
147
+ result[:en][:admin].should be_nil
148
+ result[:fr][:admin].should be_nil
149
+ end
150
+
151
+ it "does not include multiple keys listed in the exceptions list" do
152
+ result = I18n::JS.scoped_translations("*", ['title', 'note'])
153
+
154
+ result[:en][:admin][:show].should be_empty
155
+ result[:en][:admin][:edit].should be_empty
156
+
157
+ result[:fr][:admin][:show].should be_empty
158
+ result[:fr][:admin][:show].should be_empty
159
+ result[:fr][:admin][:edit].should be_empty
160
+ end
161
+
162
+ it "does not include a key listed in the exceptions list and respecs the 'only' option" do
163
+ result = I18n::JS.scoped_translations("fr.*", ['date', 'time', 'number', 'show'])
164
+
165
+ result[:en].should be_nil
166
+ result[:de].should be_nil
167
+ result[:ja].should be_nil
168
+
169
+ result[:fr][:date].should be_nil
170
+ result[:fr][:time].should be_nil
171
+ result[:fr][:number].should be_nil
172
+ result[:fr][:admin][:show].should be_nil
173
+
174
+ result[:fr][:admin][:edit][:title].should be_a(String)
175
+ end
176
+ end
177
+
135
178
  context "fallbacks" do
179
+ subject do
180
+ I18n::JS.translation_segments.inject({}) do |hash, segment|
181
+ hash[segment.file] = segment.translations
182
+ hash
183
+ end
184
+ end
185
+
136
186
  it "exports without fallback when disabled" do
137
187
  set_config "js_file_per_locale_without_fallbacks.yml"
138
-
139
- result = I18n::JS.translation_segments
140
- result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql(nil)
188
+ subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql(nil)
141
189
  end
142
190
 
143
191
  it "exports with default_locale as fallback when enabled" do
144
192
  set_config "js_file_per_locale_with_fallbacks_enabled.yml"
145
-
146
- result = I18n::JS.translation_segments
147
- result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
193
+ subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
148
194
  end
149
195
 
150
196
  it "exports with default_locale as fallback when enabled with :default_locale" do
151
197
  set_config "js_file_per_locale_with_fallbacks_as_default_locale_symbol.yml"
152
-
153
- result = I18n::JS.translation_segments
154
- result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
198
+ subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
155
199
  end
156
200
 
157
201
  it "exports with given locale as fallback" do
158
202
  set_config "js_file_per_locale_with_fallbacks_as_locale.yml"
159
-
160
- result = I18n::JS.translation_segments
161
- result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
203
+ subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
162
204
  end
163
205
 
164
206
  context "with I18n::Fallbacks enabled" do
@@ -173,27 +215,53 @@ describe I18n::JS do
173
215
 
174
216
  it "exports with defined locale as fallback when enabled" do
175
217
  set_config "js_file_per_locale_with_fallbacks_enabled.yml"
176
-
177
- result = I18n::JS.translation_segments
178
- result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
218
+ subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
179
219
  end
180
220
 
181
221
  it "exports with defined locale as fallback when enabled with :default_locale" do
182
222
  set_config "js_file_per_locale_with_fallbacks_as_default_locale_symbol.yml"
183
-
184
- result = I18n::JS.translation_segments
185
- result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
223
+ subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
186
224
  end
187
225
 
188
226
  it "exports with Fallbacks as Hash" do
189
227
  set_config "js_file_per_locale_with_fallbacks_as_hash.yml"
190
-
191
- result = I18n::JS.translation_segments
192
- result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
228
+ subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
193
229
  end
194
230
  end
195
231
  end
196
232
 
233
+ context "namespace and pretty_print options" do
234
+
235
+ before do
236
+ stub_const('I18n::JS::DEFAULT_EXPORT_DIR_PATH', temp_path)
237
+ set_config "js_file_with_namespace_and_pretty_print.yml"
238
+ end
239
+
240
+ it "exports with defined locale as fallback when enabled" do
241
+ I18n::JS.export
242
+ file_should_exist "en.js"
243
+ output = File.read(File.join(I18n::JS.export_i18n_js_dir_path, "en.js"))
244
+ expect(output).to match(/^#{
245
+ <<EOS
246
+ Foo.translations || (Foo.translations = {});
247
+ Foo.translations["en"] = {
248
+ "number": {
249
+ "format": {
250
+ EOS
251
+ }.+#{
252
+ <<EOS
253
+ "edit": {
254
+ "title": "Edit"
255
+ }
256
+ },
257
+ "foo": "Foo",
258
+ "fallback_test": "Success"
259
+ };
260
+ EOS
261
+ }$/)
262
+ end
263
+ end
264
+
197
265
  context "I18n.available_locales" do
198
266
  context "when I18n.available_locales is not set" do
199
267
  it "should allow all locales" do
@@ -236,9 +304,10 @@ describe I18n::JS do
236
304
  end
237
305
  end
238
306
 
239
-
240
307
  describe "i18n.js exporting" do
241
- describe ".export_i18n_js" do
308
+ after { begin described_class.send(:remove_instance_variable, :@export_i18n_js_dir_path); rescue; end }
309
+
310
+ describe ".export_i18n_js with global variable" do
242
311
  before do
243
312
  allow(FileUtils).to receive(:mkdir_p).and_call_original
244
313
  allow(FileUtils).to receive(:cp).and_call_original
@@ -273,11 +342,47 @@ describe I18n::JS do
273
342
  end
274
343
  end
275
344
 
345
+ describe ".export_i18n_js with config" do
346
+
347
+ let(:export_action) do
348
+ allow(FileUtils).to receive(:mkdir_p).and_call_original
349
+ allow(FileUtils).to receive(:cp).and_call_original
350
+ I18n::JS.export_i18n_js
351
+ end
352
+
353
+ context 'when :export_i18n_js set in config' do
354
+ before { set_config "js_export_dir_custom.yml"; export_action }
355
+ let(:export_i18n_js_dir_path) { temp_path }
356
+ let(:config_export_path) { "tmp/i18n-js/foo" }
357
+
358
+ it "does create the folder before copying" do
359
+ expect(FileUtils).to have_received(:mkdir_p).with(config_export_path).once
360
+ end
361
+ it "does copy the file with FileUtils.cp" do
362
+ expect(FileUtils).to have_received(:cp).once
363
+ end
364
+ it "exports the file" do
365
+ File.should be_file(File.join(config_export_path, "i18n.js"))
366
+ end
367
+ end
368
+
369
+ context 'when .export_i18n_js_dir_path is set to false' do
370
+ before { set_config "js_export_dir_none.yml"; export_action }
371
+
372
+ it "does NOT create the folder before copying" do
373
+ expect(FileUtils).to_not have_received(:mkdir_p)
374
+ end
375
+
376
+ it "does NOT copy the file with FileUtils.cp" do
377
+ expect(FileUtils).to_not have_received(:cp)
378
+ end
379
+ end
380
+ end
276
381
 
277
382
  describe '.export_i18n_js_dir_path' do
278
383
  let(:default_path) { I18n::JS::DEFAULT_EXPORT_DIR_PATH }
279
384
  let(:new_path) { File.join("tmp", default_path) }
280
- before { described_class.send(:remove_instance_variable, :@export_i18n_js_dir_path) }
385
+ after { described_class.send(:remove_instance_variable, :@export_i18n_js_dir_path) }
281
386
 
282
387
  subject { described_class.export_i18n_js_dir_path }
283
388
 
@@ -292,92 +397,8 @@ describe I18n::JS do
292
397
  context "when it is set to nil already" do
293
398
  before { described_class.export_i18n_js_dir_path = nil }
294
399
 
295
- it { should be_nil }
296
- end
297
- end
298
- end
299
- end
300
-
301
- describe I18n::JS::Dependencies, ".sprockets_supports_register_preprocessor?" do
302
-
303
- subject { described_class.sprockets_supports_register_preprocessor? }
304
-
305
- context 'when Sprockets is available to register preprocessors' do
306
- let!(:sprockets_double) do
307
- class_double('Sprockets').as_stubbed_const(register_processor: true).tap do |double|
308
- allow(double).to receive(:respond_to?).with(:register_preprocessor).and_return(true)
400
+ it { should eq :none }
309
401
  end
310
402
  end
311
-
312
- it { is_expected.to be_truthy }
313
- it 'calls respond_to? with register_preprocessor on Sprockets' do
314
- expect(sprockets_double).to receive(:respond_to?).with(:register_preprocessor).and_return(true)
315
- subject
316
- end
317
403
  end
318
-
319
- context 'when Sprockets is NOT available to register preprocessors' do
320
- let!(:sprockets_double) do
321
- class_double('Sprockets').as_stubbed_const(register_processor: true).tap do |double|
322
- allow(double).to receive(:respond_to?).with(:register_preprocessor).and_return(false)
323
- end
324
- end
325
-
326
- it { is_expected.to be_falsy }
327
- it 'calls respond_to? with register_preprocessor on Sprockets' do
328
- expect(sprockets_double).to receive(:respond_to?).with(:register_preprocessor).and_return(false)
329
- subject
330
- end
331
- end
332
-
333
- context 'when Sprockets is missing' do
334
- before do
335
- hide_const('Sprockets')
336
- expect { Sprockets }.to raise_error(NameError)
337
- end
338
-
339
- it { is_expected.to be_falsy }
340
- end
341
-
342
- end
343
-
344
- describe I18n::JS::Utils do
345
-
346
- describe ".strip_keys_with_nil_values" do
347
- subject { described_class.strip_keys_with_nil_values(input_hash) }
348
-
349
- context 'when input_hash does NOT contain nil value' do
350
- let(:input_hash) { {a: 1, b: { c: 2 }} }
351
- let(:expected_hash) { input_hash }
352
-
353
- it 'returns the original input' do
354
- is_expected.to eq expected_hash
355
- end
356
- end
357
- context 'when input_hash does contain nil value' do
358
- let(:input_hash) { {a: 1, b: { c: 2, d: nil }, e: { f: nil }} }
359
- let(:expected_hash) { {a: 1, b: { c: 2 }, e: {}} }
360
-
361
- it 'returns the original input with nil values removed' do
362
- is_expected.to eq expected_hash
363
- end
364
- end
365
- end
366
-
367
- context "hash merging" do
368
- it "performs a deep merge" do
369
- target = {:a => {:b => 1}}
370
- result = described_class.deep_merge(target, {:a => {:c => 2}})
371
-
372
- result[:a].should eql({:b => 1, :c => 2})
373
- end
374
-
375
- it "performs a banged deep merge" do
376
- target = {:a => {:b => 1}}
377
- described_class.deep_merge!(target, {:a => {:c => 2}})
378
-
379
- target[:a].should eql({:b => 1, :c => 2})
380
- end
381
- end
382
-
383
404
  end