i18n-js 3.0.0.rc8 → 3.0.0.rc9

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.
@@ -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