i18n-tasks 0.5.4 → 0.6.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 +4 -4
- data/CHANGES.md +9 -0
- data/README.md +46 -36
- data/Rakefile +2 -2
- data/lib/i18n/tasks/base_task.rb +2 -0
- data/lib/i18n/tasks/commands.rb +55 -35
- data/lib/i18n/tasks/commands_base.rb +36 -9
- data/lib/i18n/tasks/configuration.rb +14 -13
- data/lib/i18n/tasks/console_context.rb +0 -1
- data/lib/i18n/tasks/data.rb +2 -2
- data/lib/i18n/tasks/data/adapter/json_adapter.rb +6 -2
- data/lib/i18n/tasks/data/file_formats.rb +19 -4
- data/lib/i18n/tasks/data/file_system_base.rb +1 -1
- data/lib/i18n/tasks/data/tree/node.rb +11 -37
- data/lib/i18n/tasks/data/tree/nodes.rb +6 -2
- data/lib/i18n/tasks/data/tree/siblings.rb +53 -29
- data/lib/i18n/tasks/data/tree/traversal.rb +4 -2
- data/lib/i18n/tasks/fill_tasks.rb +5 -2
- data/lib/i18n/tasks/ignore_keys.rb +1 -1
- data/lib/i18n/tasks/locale_pathname.rb +1 -1
- data/lib/i18n/tasks/logging.rb +2 -0
- data/lib/i18n/tasks/missing_keys.rb +74 -31
- data/lib/i18n/tasks/plural_keys.rb +4 -3
- data/lib/i18n/tasks/reports/base.rb +8 -5
- data/lib/i18n/tasks/reports/spreadsheet.rb +15 -3
- data/lib/i18n/tasks/reports/terminal.rb +62 -23
- data/lib/i18n/tasks/scanners/base_scanner.rb +4 -2
- data/lib/i18n/tasks/scanners/relative_keys.rb +21 -0
- data/lib/i18n/tasks/split_key.rb +39 -0
- data/lib/i18n/tasks/used_keys.rb +1 -1
- data/lib/i18n/tasks/version.rb +1 -1
- data/spec/fixtures/app/views/index.html.slim +2 -0
- data/spec/i18n_tasks_spec.rb +19 -5
- data/spec/locale_pathname_spec.rb +24 -0
- data/spec/locale_tree/siblings_spec.rb +41 -4
- data/spec/split_key_spec.rb +27 -0
- data/spec/support/i18n_tasks_output_matcher.rb +7 -13
- data/spec/support/trees.rb +4 -0
- data/templates/config/i18n-tasks.yml +82 -0
- data/templates/rspec/i18n_spec.rb +18 -0
- metadata +10 -3
- data/lib/i18n/tasks/relative_keys.rb +0 -19
@@ -1,4 +1,5 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
require 'set'
|
2
3
|
module I18n::Tasks::PluralKeys
|
3
4
|
PLURAL_KEY_SUFFIXES = Set.new %w(zero one two few many other)
|
4
5
|
PLURAL_KEY_RE = /\.(?:#{PLURAL_KEY_SUFFIXES.to_a * '|'})$/
|
@@ -20,10 +21,10 @@ module I18n::Tasks::PluralKeys
|
|
20
21
|
# @return the base form if the key is a specific plural form (e.g. apple for apple.many), and the key as passed otherwise
|
21
22
|
def depluralize_key(key, locale = base_locale)
|
22
23
|
return key if key !~ PLURAL_KEY_RE
|
23
|
-
|
24
|
-
nodes =
|
24
|
+
parent_key = split_key(key)[0..-2] * '.'
|
25
|
+
nodes = tree("#{locale}.#{parent_key}").presence || (locale != base_locale && tree("#{base_locale}.#{parent_key}"))
|
25
26
|
if nodes && nodes.all? { |x| x.leaf? && ".#{x.key}" =~ PLURAL_KEY_RE }
|
26
|
-
|
27
|
+
parent_key
|
27
28
|
else
|
28
29
|
key
|
29
30
|
end
|
@@ -13,9 +13,8 @@ module I18n::Tasks::Reports
|
|
13
13
|
protected
|
14
14
|
|
15
15
|
MISSING_TYPES = {
|
16
|
-
|
17
|
-
|
18
|
-
eq_base: {glyph: '=', summary: 'value equals base value'}
|
16
|
+
missing_used: {glyph: '✗', summary: 'used in code but missing from base locale'},
|
17
|
+
missing_diff: {glyph: '∅', summary: 'translated in one locale but not in the other'}
|
19
18
|
}
|
20
19
|
|
21
20
|
def missing_types
|
@@ -30,11 +29,15 @@ module I18n::Tasks::Reports
|
|
30
29
|
"Unused keys (#{key_values.count || '∅'})"
|
31
30
|
end
|
32
31
|
|
32
|
+
def eq_base_title(key_values, locale = base_locale)
|
33
|
+
"Same value as #{locale} (#{key_values.count || '∅'})"
|
34
|
+
end
|
35
|
+
|
33
36
|
def used_title(used_tree)
|
34
37
|
leaves = used_tree.leaves.to_a
|
35
38
|
filter = used_tree.first.root.data[:key_filter]
|
36
39
|
used_n = leaves.map { |node| node.data[:source_locations].size }.reduce(:+).to_i
|
37
|
-
"#{leaves.length} key#{'s' if leaves.size != 1}#{"
|
40
|
+
"#{leaves.length} key#{'s' if leaves.size != 1}#{" matching '#{filter}'" if filter}#{" (#{used_n} usage#{'s' if used_n != 1})" if used_n > 0}"
|
38
41
|
end
|
39
42
|
|
40
43
|
# Sort keys by their attributes in order
|
@@ -50,7 +53,7 @@ module I18n::Tasks::Reports
|
|
50
53
|
|
51
54
|
def forest_to_attr(forest)
|
52
55
|
forest.keys(root: false).map { |key, node|
|
53
|
-
{key: key, type: node.data[:type], locale: node.root.key}
|
56
|
+
{key: key, value: node.value, type: node.data[:type], locale: node.root.key, data: node.data}
|
54
57
|
}
|
55
58
|
end
|
56
59
|
end
|
@@ -10,6 +10,7 @@ module I18n::Tasks::Reports
|
|
10
10
|
p = Axlsx::Package.new
|
11
11
|
add_missing_sheet p.workbook
|
12
12
|
add_unused_sheet p.workbook
|
13
|
+
add_eq_base_sheet p.workbook
|
13
14
|
p.use_shared_strings = true
|
14
15
|
FileUtils.mkpath(File.dirname(path))
|
15
16
|
p.serialize(path)
|
@@ -37,9 +38,20 @@ module I18n::Tasks::Reports
|
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
41
|
+
def add_eq_base_sheet(wb)
|
42
|
+
keys = task.eq_base_keys.root_key_values(true)
|
43
|
+
add_locale_key_value_table wb, keys, name: eq_base_title(keys)
|
44
|
+
end
|
45
|
+
|
40
46
|
def add_unused_sheet(wb)
|
41
|
-
keys = task.unused_keys.root_key_values
|
42
|
-
wb
|
47
|
+
keys = task.unused_keys.root_key_values(true)
|
48
|
+
add_locale_key_value_table wb, keys, name: unused_title(keys)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def add_locale_key_value_table(wb, keys, worksheet_opts = {})
|
54
|
+
wb.add_worksheet worksheet_opts do |sheet|
|
43
55
|
sheet.add_row ['Locale', 'Key', 'Value']
|
44
56
|
style_header sheet
|
45
57
|
keys.each do |locale_k_v|
|
@@ -48,7 +60,7 @@ module I18n::Tasks::Reports
|
|
48
60
|
end
|
49
61
|
end
|
50
62
|
|
51
|
-
|
63
|
+
|
52
64
|
def style_header(sheet)
|
53
65
|
border_bottom = sheet.workbook.styles.add_style(border: {style: :thin, color: '000000', edges: [:bottom]})
|
54
66
|
sheet.rows.first.style = border_bottom
|
@@ -11,26 +11,21 @@ module I18n
|
|
11
11
|
print_title missing_title(forest)
|
12
12
|
|
13
13
|
if forest.present?
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
if type == :missing_from_base
|
24
|
-
locale = magenta locale
|
25
|
-
base_value = ''
|
14
|
+
keys_attr = sort_by_attr! forest_to_attr(forest), {locale: :asc, type: :desc, key: :asc}
|
15
|
+
print_table headings: [cyan(bold('Locale')), cyan(bold 'Key'), 'Details'] do |t|
|
16
|
+
t.rows = keys_attr.map do |a|
|
17
|
+
locale, key = a[:locale], a[:key], a[:type]
|
18
|
+
if a[:type] == :missing_used
|
19
|
+
occ = a[:data][:source_locations]
|
20
|
+
first = occ.first
|
21
|
+
info = [green("#{first[:src_path]}:#{first[:line_num]}"),
|
22
|
+
("(#{occ.length - 1} more)" if occ.length > 1)].compact.join(' ')
|
26
23
|
else
|
27
|
-
|
28
|
-
base_value = task.t(key, base_locale).to_s.strip
|
24
|
+
info = a[:value].to_s.strip
|
29
25
|
end
|
30
|
-
[{value: locale, alignment: :center},
|
31
|
-
|
32
|
-
|
33
|
-
cyan(base_value)]
|
26
|
+
[{value: cyan(locale), alignment: :center},
|
27
|
+
cyan(key),
|
28
|
+
wrap_string(info, 60)]
|
34
29
|
end
|
35
30
|
end
|
36
31
|
else
|
@@ -38,6 +33,11 @@ module I18n
|
|
38
33
|
end
|
39
34
|
end
|
40
35
|
|
36
|
+
def icon(type)
|
37
|
+
glyph = missing_types[type][:glyph]
|
38
|
+
{missing_used: red(glyph), missing_diff: yellow(glyph)}[type]
|
39
|
+
end
|
40
|
+
|
41
41
|
def used_keys(used_tree = task.used_tree(source_locations: true))
|
42
42
|
print_title used_title(used_tree)
|
43
43
|
keys_nodes = used_tree.keys.to_a
|
@@ -60,21 +60,43 @@ module I18n
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def unused_keys(tree = task.unused_keys)
|
63
|
-
keys = tree.root_key_values
|
63
|
+
keys = tree.root_key_values(true)
|
64
64
|
print_title unused_title(keys)
|
65
65
|
if keys.present?
|
66
|
-
|
67
|
-
t.rows = keys.map { |(locale, k, v)| [magenta(locale), magenta(k), cyan(v.to_s)] }
|
68
|
-
end
|
66
|
+
print_locale_key_value_table keys
|
69
67
|
else
|
70
68
|
print_success 'Every translation is used!'
|
71
69
|
end
|
72
70
|
end
|
73
71
|
|
72
|
+
def eq_base_keys(tree = task.eq_base_keys)
|
73
|
+
keys = tree.root_key_values(true)
|
74
|
+
print_title eq_base_title(keys)
|
75
|
+
if keys.present?
|
76
|
+
print_locale_key_value_table keys
|
77
|
+
else
|
78
|
+
print_info cyan('No translations are the same as base value')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def show_tree(tree)
|
83
|
+
print_locale_key_value_table tree.root_key_values(true)
|
84
|
+
end
|
85
|
+
|
74
86
|
private
|
75
87
|
|
88
|
+
def print_locale_key_value_table(locale_key_values)
|
89
|
+
if locale_key_values.present?
|
90
|
+
print_table headings: [bold(cyan('Locale')), bold(cyan('Key')), 'Value'] do |t|
|
91
|
+
t.rows = locale_key_values.map { |(locale, k, v)| [{value: cyan(locale), alignment: :center}, cyan(k), v.to_s] }
|
92
|
+
end
|
93
|
+
else
|
94
|
+
puts 'ø'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
76
98
|
def print_title(title)
|
77
|
-
log_stderr "#{bold
|
99
|
+
log_stderr "#{bold title.strip} #{dark "|"} #{"i18n-tasks v#{I18n::Tasks::VERSION}"}"
|
78
100
|
end
|
79
101
|
|
80
102
|
def print_success(message)
|
@@ -97,6 +119,23 @@ module I18n
|
|
97
119
|
def print_table(opts, &block)
|
98
120
|
puts ::Terminal::Table.new(opts, &block)
|
99
121
|
end
|
122
|
+
|
123
|
+
def wrap_string(s, max)
|
124
|
+
chars = []
|
125
|
+
dist = 0
|
126
|
+
s.chars.each do |c|
|
127
|
+
chars << c
|
128
|
+
dist += 1
|
129
|
+
if c == "\n"
|
130
|
+
dist = 0
|
131
|
+
elsif dist == max
|
132
|
+
dist = 0
|
133
|
+
chars << "\n"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
chars = chars[0..-2] if chars.last == "\n"
|
137
|
+
chars.join
|
138
|
+
end
|
100
139
|
end
|
101
140
|
end
|
102
141
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
require 'i18n/tasks/key_pattern_matching'
|
3
|
-
require 'i18n/tasks/relative_keys'
|
3
|
+
require 'i18n/tasks/scanners/relative_keys'
|
4
|
+
|
4
5
|
module I18n::Tasks::Scanners
|
5
6
|
class BaseScanner
|
6
|
-
include
|
7
|
+
include RelativeKeys
|
7
8
|
include ::I18n::Tasks::KeyPatternMatching
|
8
9
|
include ::I18n::Tasks::Logging
|
9
10
|
|
@@ -11,6 +12,7 @@ module I18n::Tasks::Scanners
|
|
11
12
|
|
12
13
|
def initialize(config = {})
|
13
14
|
@config = config.dup.with_indifferent_access.tap do |conf|
|
15
|
+
conf[:relative_roots] = %w(app/views) if conf[:relative_roots].blank?
|
14
16
|
conf[:paths] = %w(app/) if conf[:paths].blank?
|
15
17
|
conf[:include] = Array(conf[:include]) if conf[:include].present?
|
16
18
|
if conf.key?(:exclude)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module I18n
|
3
|
+
module Tasks
|
4
|
+
module Scanners
|
5
|
+
module RelativeKeys
|
6
|
+
# @param key [String] relative i18n key (starts with a .)
|
7
|
+
# @param path [String] path to the file containing the key
|
8
|
+
# @return [String] absolute version of the key
|
9
|
+
def absolutize_key(key, path, roots = relative_roots)
|
10
|
+
# normalized path
|
11
|
+
path = File.expand_path path
|
12
|
+
(path_root = roots.map { |path| File.expand_path path }.sort.reverse.detect { |root| path.start_with?(root + '/') }) or
|
13
|
+
raise CommandError.new("Error scanning #{path}: cannot resolve relative key \"#{key}\".\nSet relative_roots in config/i18n-tasks.yml (currently #{relative_roots.inspect})")
|
14
|
+
# key prefix based on path
|
15
|
+
prefix = path.gsub(%r(#{path_root}/|(\.[^/]+)*$), '').tr('/', '.').gsub(%r(\._), '.')
|
16
|
+
"#{prefix}#{key}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module SplitKey
|
2
|
+
extend self
|
3
|
+
|
4
|
+
# split a key taking parenthesis into account
|
5
|
+
# split_key 'a.b' # => ['a', 'b']
|
6
|
+
# split_key 'a.#{b.c}' # => ['a', '#{b.c}']
|
7
|
+
# split_key 'a.b.c', 2 # => ['a', 'b.c']
|
8
|
+
def split_key(key, max = Float::INFINITY)
|
9
|
+
parts = []
|
10
|
+
nesting = NESTING_CHARS
|
11
|
+
counts = Array.new(NESTING_CHARS.size, 0)
|
12
|
+
delim = '.'.freeze
|
13
|
+
buf = []
|
14
|
+
key.to_s.chars.each do |char|
|
15
|
+
nest_i, nest_inc = nesting[char]
|
16
|
+
if nest_i
|
17
|
+
counts[nest_i] += nest_inc
|
18
|
+
buf << char
|
19
|
+
elsif char == delim && parts.length + 1 < max && counts.all?(&:zero?)
|
20
|
+
part = buf.join
|
21
|
+
buf.clear
|
22
|
+
parts << part
|
23
|
+
yield part if block_given?
|
24
|
+
else
|
25
|
+
buf << char
|
26
|
+
end
|
27
|
+
end
|
28
|
+
parts << buf.join unless buf.empty?
|
29
|
+
parts
|
30
|
+
end
|
31
|
+
|
32
|
+
NESTING_CHARS = %w({} [] ()).inject({}) { |h, s|
|
33
|
+
i = h.size / 2
|
34
|
+
h[s[0].freeze] = [i, 1].freeze
|
35
|
+
h[s[1].freeze] = [i, -1].freeze
|
36
|
+
h
|
37
|
+
}.freeze
|
38
|
+
private_constant :NESTING_CHARS
|
39
|
+
end
|
data/lib/i18n/tasks/used_keys.rb
CHANGED
@@ -22,7 +22,7 @@ module I18n::Tasks
|
|
22
22
|
@scanner ||= begin
|
23
23
|
search_config = (config[:search] || {}).with_indifferent_access
|
24
24
|
class_name = search_config[:scanner] || '::I18n::Tasks::Scanners::PatternWithScopeScanner'
|
25
|
-
class_name.constantize.new search_config
|
25
|
+
class_name.constantize.new search_config
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
data/lib/i18n/tasks/version.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
| x-t :fp_dash_before
|
3
3
|
/ t(:fp_comment)
|
4
4
|
/ i18n-tasks-use t(:fn_comment)
|
5
|
+
= t 'only_in_es'
|
5
6
|
p #{t('ca.a')} #{t 'ca.b'} #{t "ca.c"}
|
6
7
|
p #{t 'ca.d'} #{t 'ca.f', i: 'world'} #{t 'ca.e', i: 'world'}
|
7
8
|
p #{t 'missing_in_es.a'} #{t 'same_in_es.a'} #{t 'blank_in_es.a'}
|
@@ -22,3 +23,4 @@ p = t 'missing_in_es_plural_2.a', count: 2
|
|
22
23
|
p = t 'devise.a'
|
23
24
|
p = t :missing_symbol_key
|
24
25
|
p #{t :"missing_symbol.key_two"} #{t :'missing_symbol.key_three'}
|
26
|
+
= t 'present_in_es_but_not_en.a'
|
data/spec/i18n_tasks_spec.rb
CHANGED
@@ -9,15 +9,16 @@ describe 'i18n-tasks' do
|
|
9
9
|
describe 'missing' do
|
10
10
|
let (:expected_missing_keys) {
|
11
11
|
%w( en.used_but_missing.key en.relative.index.missing
|
12
|
-
es.missing_in_es.a
|
12
|
+
es.missing_in_es.a
|
13
|
+
en.present_in_es_but_not_en.a
|
13
14
|
en.hash.pattern_missing.a en.hash.pattern_missing.b
|
14
15
|
en.missing_symbol_key en.missing_symbol.key_two en.missing_symbol.key_three
|
15
16
|
es.missing_in_es_plural_1.a es.missing_in_es_plural_2.a
|
16
17
|
en.missing-key-with-a-dash.key
|
17
|
-
en.fn_comment
|
18
|
+
en.fn_comment en.only_in_es
|
18
19
|
)
|
19
20
|
}
|
20
|
-
it 'detects missing
|
21
|
+
it 'detects missing' do
|
21
22
|
capture_stderr do
|
22
23
|
expect(run_cmd :missing).to be_i18n_keys expected_missing_keys
|
23
24
|
es_keys = expected_missing_keys.grep(/^es\./)
|
@@ -28,6 +29,14 @@ describe 'i18n-tasks' do
|
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
32
|
+
describe 'eq_base' do
|
33
|
+
it 'detects eq_base' do
|
34
|
+
capture_stderr do
|
35
|
+
expect(run_cmd :eq_base).to be_i18n_keys %w(es.same_in_es.a)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
31
40
|
let(:expected_unused_keys) { %w(unused.a unused.numeric unused.plural).map { |k| %w(en es).map { |l| "#{l}.#{k}" } }.reduce(:+) }
|
32
41
|
describe 'unused' do
|
33
42
|
it 'detects unused' do
|
@@ -41,7 +50,7 @@ describe 'i18n-tasks' do
|
|
41
50
|
it 'removes unused' do
|
42
51
|
in_test_app_dir do
|
43
52
|
t = i18n_task
|
44
|
-
unused = expected_unused_keys.map { |k|
|
53
|
+
unused = expected_unused_keys.map { |k| SplitKey.split_key(k, 2)[1] }
|
45
54
|
unused.each do |key|
|
46
55
|
expect(t.key_value?(key, :en)).to be true
|
47
56
|
expect(t.key_value?(key, :es)).to be true
|
@@ -88,6 +97,7 @@ describe 'i18n-tasks' do
|
|
88
97
|
run_cmd :add_missing, locales: 'base'
|
89
98
|
in_test_app_dir {
|
90
99
|
expect(YAML.load_file('config/locales/en.yml')['en']['used_but_missing']['key']).to eq 'Key'
|
100
|
+
expect(YAML.load_file('config/locales/en.yml')['en']['present_in_es_but_not_en']['a']).to eq 'A'
|
91
101
|
}
|
92
102
|
end
|
93
103
|
|
@@ -111,6 +121,7 @@ describe 'i18n-tasks' do
|
|
111
121
|
in_test_app_dir {
|
112
122
|
expect(YAML.load_file('config/locales/es.yml')['es']['missing_in_es']['a']).to eq 'TRME'
|
113
123
|
expect(YAML.load_file('config/locales/devise.es.yml')['es']['devise']['a']).to eq 'ES_TEXT'
|
124
|
+
expect(YAML.load_file('config/locales/en.yml')['en']['present_in_es_but_not_en']['a']).to eq 'TRME'
|
114
125
|
}
|
115
126
|
end
|
116
127
|
|
@@ -121,6 +132,7 @@ describe 'i18n-tasks' do
|
|
121
132
|
run_cmd :add_missing, locales: 'all', placeholder: 'TRME %{base_value}'
|
122
133
|
in_test_app_dir {
|
123
134
|
expect(YAML.load_file('config/locales/es.yml')['es']['missing_in_es']['a']).to eq 'TRME EN_TEXT'
|
135
|
+
expect(YAML.load_file('config/locales/en.yml')['en']['present_in_es_but_not_en']['a']).to eq 'TRME ES_TEXT'
|
124
136
|
}
|
125
137
|
end
|
126
138
|
end
|
@@ -148,7 +160,7 @@ used.a 2
|
|
148
160
|
|
149
161
|
|
150
162
|
# --- setup ---
|
151
|
-
BENCH_KEYS =
|
163
|
+
BENCH_KEYS = 10
|
152
164
|
before(:each) do
|
153
165
|
gen_data = ->(v) {
|
154
166
|
v_num = v.chars.map(&:ord).join('').to_i
|
@@ -194,6 +206,8 @@ used.a 2
|
|
194
206
|
es_data['blank_in_es']['a'] = ''
|
195
207
|
es_data['ignore_eq_base_all']['a'] = 'EN_TEXT'
|
196
208
|
es_data['ignore_eq_base_es']['a'] = 'EN_TEXT'
|
209
|
+
es_data['only_in_es'] = 1
|
210
|
+
es_data['present_in_es_but_not_en'] = {'a' => 'ES_TEXT'}
|
197
211
|
|
198
212
|
fs = fixtures_contents.merge(
|
199
213
|
'config/locales/en.yml' => {'en' => en_data}.to_yaml,
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'LocalePathname' do
|
4
|
+
include ::I18n::Tasks::LocalePathname
|
5
|
+
context '#replace_locale' do
|
6
|
+
|
7
|
+
it 'es.yml' do
|
8
|
+
expect(replace_locale 'es.yml', 'es', 'fr').to eq 'fr.yml'
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'scope.es.yml' do
|
12
|
+
expect(replace_locale 'scope.es.yml', 'es', 'fr').to eq 'scope.fr.yml'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'path/es.yml' do
|
16
|
+
expect(replace_locale 'path/es.yml', 'es', 'fr').to eq 'path/fr.yml'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'path/scope.es.yml' do
|
20
|
+
expect(replace_locale 'path/scope.es.yml', 'es', 'fr').to eq 'path/scope.fr.yml'
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -10,12 +10,12 @@ describe 'Tree siblings / forest' do
|
|
10
10
|
key: 'fr',
|
11
11
|
children: children
|
12
12
|
)
|
13
|
-
expect(node.to_siblings.first.children.
|
13
|
+
expect(node.to_siblings.first.children.parent.key).to eq 'fr'
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
17
|
context 'a tree' do
|
18
|
-
let(:a_hash) { {a
|
18
|
+
let(:a_hash) { {'a' => 1, 'b' => {'ba' => 1, 'bb' => 2}} }
|
19
19
|
|
20
20
|
it '::from_nested_hash' do
|
21
21
|
a = build_tree(a_hash)
|
@@ -34,14 +34,34 @@ describe 'Tree siblings / forest' do
|
|
34
34
|
|
35
35
|
it '#merge' do
|
36
36
|
a = build_tree(a_hash)
|
37
|
-
b_hash = {b
|
37
|
+
b_hash = {'b' => {'bc' => 1}, 'c' => 1}
|
38
38
|
expect(a.merge(build_tree(b_hash)).to_hash).to eq(a_hash.deep_merge(b_hash))
|
39
39
|
end
|
40
40
|
|
41
|
+
it '#merge does not modify self' do
|
42
|
+
a = build_tree(a: 1)
|
43
|
+
b = build_tree(a: 2)
|
44
|
+
c = a.merge b
|
45
|
+
expect(a['a'].value).to eq 1
|
46
|
+
expect(c['a'].value).to eq 2
|
47
|
+
expect(b['a'].value).to eq 2
|
48
|
+
end
|
49
|
+
|
50
|
+
it '#merge conflict value <- scope' do
|
51
|
+
a = build_tree(a: 1)
|
52
|
+
b = build_tree(a: {b: 1})
|
53
|
+
expect { silence_stderr { a.merge(b) } }.to_not raise_error
|
54
|
+
end
|
55
|
+
|
56
|
+
it '#set conflict value <- scope' do
|
57
|
+
a = build_tree(a: 1)
|
58
|
+
expect { silence_stderr { a.set('a.b', build_node(key: 'b', value: 1)) } }.to_not raise_error
|
59
|
+
end
|
60
|
+
|
41
61
|
it '#intersect' do
|
42
62
|
x = {a: 1, b: {ba: 1, bb: 2}}
|
43
63
|
y = {b: {ba: 1, bc: 3}, c: 1}
|
44
|
-
intersection = {b
|
64
|
+
intersection = {'b' => {'ba' => 1}}
|
45
65
|
a = build_tree(x)
|
46
66
|
b = build_tree(y)
|
47
67
|
expect(a.intersect_keys(b, root: true).to_hash).to eq(intersection)
|
@@ -50,5 +70,22 @@ describe 'Tree siblings / forest' do
|
|
50
70
|
it '#select_keys' do
|
51
71
|
expect(build_tree(a: 1, b: 1).select_keys {|k, node| k == 'b'}.to_hash).to eq({'b' => 1})
|
52
72
|
end
|
73
|
+
|
74
|
+
it '#append!' do
|
75
|
+
expect(build_tree({'a' => 1}).append!(build_node(key: 'b', value: 2)).to_hash).to eq('a' => 1, 'b' => 2)
|
76
|
+
end
|
77
|
+
|
78
|
+
it '#set replace value' do
|
79
|
+
expect(build_tree(a: {b: 1}).tap {|t| t['a.b'] = build_node(key: 'b', value: 2) }.to_hash).to(
|
80
|
+
eq('a' => {'b' => 2})
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
it '#set get' do
|
85
|
+
t = build_tree(a: {x: 1})
|
86
|
+
node = build_node(key: 'd', value: 'e')
|
87
|
+
t['a.b.c.' + node.key] = node
|
88
|
+
expect(t['a.b.c.d'].value).to eq('e')
|
89
|
+
end
|
53
90
|
end
|
54
91
|
end
|