yaml-validator 0.0.1 → 0.1.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.
- data/.travis.yml +3 -0
- data/Gemfile.lock +3 -1
- data/README.md +2 -0
- data/Rakefile +2 -0
- data/bin/yaml-validator +16 -3
- data/lib/helpers.rb +24 -0
- data/lib/yaml-validator.rb +67 -3
- data/lib/yaml-validator/version.rb +1 -1
- data/pkg/yaml-validator-0.0.1.gem +0 -0
- data/spec/fixtures/invalid_yml/en.yml +2 -0
- data/spec/fixtures/missing_translations/en.yml +12 -0
- data/spec/fixtures/missing_translations/he.yml +7 -0
- data/spec/helpers_spec.rb +53 -0
- data/spec/yaml-validator_spec.rb +69 -1
- data/yaml-validator.gemspec +2 -1
- metadata +32 -5
data/.travis.yml
ADDED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
data/Rakefile
CHANGED
data/bin/yaml-validator
CHANGED
@@ -1,15 +1,28 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require_relative '../lib/yaml-validator'
|
4
|
+
require 'colorize'
|
4
5
|
|
5
6
|
def main
|
7
|
+
show_missing = true
|
8
|
+
if ARGV.include? '--no-missing'
|
9
|
+
show_missing = false
|
10
|
+
ARGV.delete '--no-missing'
|
11
|
+
end
|
12
|
+
|
6
13
|
root_path = '.'
|
7
14
|
root_path = ARGV[0] if ARGV.length > 0
|
8
15
|
|
9
|
-
puts "Validating #{root_path}"
|
10
|
-
|
16
|
+
puts "Validating #{root_path}...\n\n".colorize(:blue).underline
|
17
|
+
validator = YamlValidator.new(root_path, :show_missing => show_missing)
|
18
|
+
errors = validator.validate()
|
11
19
|
puts errors
|
12
|
-
|
20
|
+
|
21
|
+
if errors.length > 0
|
22
|
+
puts "\nfound #{errors.length} error(s)".colorize(:red).underline
|
23
|
+
else
|
24
|
+
puts "no errors".colorize(:green).underline
|
25
|
+
end
|
13
26
|
end
|
14
27
|
|
15
28
|
main()
|
data/lib/helpers.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Helpers
|
2
|
+
|
3
|
+
def self.normalize_yaml(yaml)
|
4
|
+
return '' if yaml.nil?
|
5
|
+
return yaml if yaml.is_a? String
|
6
|
+
return yaml.to_s if yaml.is_a? Numeric
|
7
|
+
return yaml.to_s if !!yaml == yaml # if boolean
|
8
|
+
return ":#{yaml.to_s}" if yaml.is_a? Symbol
|
9
|
+
yaml = array_to_hash(yaml) if yaml.is_a? Array
|
10
|
+
|
11
|
+
normalized = {}
|
12
|
+
yaml.each do |key, value|
|
13
|
+
normalized[key] = normalize_yaml(value)
|
14
|
+
end
|
15
|
+
normalized
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.array_to_hash(array)
|
19
|
+
hash = {}
|
20
|
+
array.each_with_index { |val, i| hash[i.to_s] = val }
|
21
|
+
hash
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/yaml-validator.rb
CHANGED
@@ -1,21 +1,38 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'yaml-validator/version'
|
3
|
+
require_relative './helpers'
|
3
4
|
|
4
5
|
class YamlValidator
|
5
6
|
|
6
|
-
def initialize(root_path)
|
7
|
+
def initialize(root_path, options = {})
|
8
|
+
@options = options
|
9
|
+
@options[:show_missing] ||= true
|
7
10
|
@root_path = root_path
|
8
11
|
end
|
9
12
|
|
13
|
+
def en
|
14
|
+
return @en unless @en.nil?
|
15
|
+
|
16
|
+
fullpath = File.join(@root_path, 'en.yml')
|
17
|
+
return nil unless File.exists?(fullpath)
|
18
|
+
|
19
|
+
@en = YAML.load_file(fullpath)['en']
|
20
|
+
@en = Helpers.normalize_yaml(@en)
|
21
|
+
end
|
22
|
+
|
10
23
|
def en_with_vars
|
11
|
-
|
12
|
-
@en_with_vars ||= get_all_variables(
|
24
|
+
return nil if en.nil?
|
25
|
+
@en_with_vars ||= get_all_variables(en)
|
13
26
|
end
|
14
27
|
|
15
28
|
def validate()
|
29
|
+
if en_with_vars.nil?
|
30
|
+
return ["no en.yml file in the directory (an en.yml file is required as reference)"]
|
31
|
+
end
|
16
32
|
yml_files = File.join(@root_path, '*.yml')
|
17
33
|
errors = []
|
18
34
|
Dir[yml_files].each do |filename|
|
35
|
+
next if File.basename(filename) == 'en.yml'
|
19
36
|
errors.concat validate_yaml(filename)
|
20
37
|
end
|
21
38
|
errors
|
@@ -29,14 +46,21 @@ class YamlValidator
|
|
29
46
|
rescue Psych::SyntaxError => e
|
30
47
|
return [e.message.sub(/^\([^)]+\)/, filename)]
|
31
48
|
end
|
49
|
+
|
32
50
|
yaml_object = yaml_object[yaml_object.keys[0]]
|
51
|
+
yaml_object = Helpers.normalize_yaml(yaml_object)
|
33
52
|
errors = validate_yaml_object('', yaml_object)
|
53
|
+
if @options[:show_missing]
|
54
|
+
errors.concat find_missing_translations(yaml_object)
|
55
|
+
end
|
34
56
|
|
35
57
|
errors.map { |err| "#{filename}: #{err}" }
|
36
58
|
end
|
37
59
|
|
38
60
|
def validate_yaml_object(full_key, yaml_object)
|
61
|
+
return [] if yaml_object.nil?
|
39
62
|
errors = []
|
63
|
+
|
40
64
|
yaml_object.each do |key, value|
|
41
65
|
full_subkey = (full_key.empty?) ? key : "#{full_key}.#{key}"
|
42
66
|
if value.is_a? String
|
@@ -48,6 +72,41 @@ class YamlValidator
|
|
48
72
|
errors
|
49
73
|
end
|
50
74
|
|
75
|
+
def find_missing_translations(yaml_object)
|
76
|
+
find_missing_translations_in_en_object('', en, yaml_object)
|
77
|
+
end
|
78
|
+
|
79
|
+
def find_missing_translations_in_en_object(full_key, en_yaml_object, yaml_object)
|
80
|
+
return [] if en_yaml_object.nil?
|
81
|
+
errors = []
|
82
|
+
|
83
|
+
en_yaml_object.each do |key, value|
|
84
|
+
full_subkey = (full_key.empty?) ? key : "#{full_key}.#{key}"
|
85
|
+
if value.is_a? String or value.is_a? Symbol
|
86
|
+
if self.class.find_key_in_yaml_object(full_subkey, yaml_object).nil?
|
87
|
+
errors << "missing translation for #{full_subkey} ('#{value}')"
|
88
|
+
end
|
89
|
+
else
|
90
|
+
errors.concat find_missing_translations_in_en_object(full_subkey, value, yaml_object)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
errors
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.find_key_in_yaml_object(full_key, yaml_object)
|
97
|
+
position = yaml_object
|
98
|
+
full_key.split('.').each do |key|
|
99
|
+
return nil unless position.is_a? Hash
|
100
|
+
position = position[key]
|
101
|
+
end
|
102
|
+
|
103
|
+
if position.is_a? String or position.is_a? Symbol
|
104
|
+
position
|
105
|
+
else
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
51
110
|
def validate_item(full_key, value)
|
52
111
|
real_vars = get_key_en_vars(full_key)
|
53
112
|
if real_vars.nil?
|
@@ -80,10 +139,14 @@ class YamlValidator
|
|
80
139
|
end
|
81
140
|
|
82
141
|
def get_all_variables(yaml_object)
|
142
|
+
return {} if yaml_object.nil?
|
83
143
|
with_vars = {}
|
144
|
+
|
84
145
|
yaml_object.each do |key, value|
|
85
146
|
if value.is_a? String
|
86
147
|
with_vars[key] = identify_variables(value)
|
148
|
+
elsif value.is_a? Symbol
|
149
|
+
with_vars[key] = {}
|
87
150
|
else
|
88
151
|
with_vars[key] = get_all_variables(value)
|
89
152
|
end
|
@@ -94,5 +157,6 @@ class YamlValidator
|
|
94
157
|
def identify_variables(string)
|
95
158
|
string.scan(/%{([^}]+)}/).map { |v| v[0] }
|
96
159
|
end
|
160
|
+
|
97
161
|
end
|
98
162
|
|
Binary file
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative '../lib/helpers'
|
2
|
+
|
3
|
+
describe Helpers do
|
4
|
+
describe "#normalize_yaml" do
|
5
|
+
it "converts symbols to strings (with ':' prefix)" do
|
6
|
+
yaml = { 'key3' => :bob }
|
7
|
+
|
8
|
+
Helpers.normalize_yaml(yaml).should == {
|
9
|
+
'key3' => ':bob'
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
it "converts nil to ''" do
|
14
|
+
yaml = { 'key3' => nil }
|
15
|
+
Helpers.normalize_yaml(yaml).should == {
|
16
|
+
'key3' => ''
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
it "converts numbers to string" do
|
21
|
+
yaml = { 'key3' => 123 }
|
22
|
+
Helpers.normalize_yaml(yaml).should == {
|
23
|
+
'key3' => '123'
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "converts booleans to string" do
|
28
|
+
yaml = { 'key3' => true }
|
29
|
+
Helpers.normalize_yaml(yaml).should == {
|
30
|
+
'key3' => 'true'
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
it "converts arrays to hashes" do
|
35
|
+
yaml = { 'key1' => 'value1',
|
36
|
+
'key2' => [ 'value2', nil, :bla ],
|
37
|
+
'parent1' => { 'key3' => [ :bob ] } }
|
38
|
+
|
39
|
+
Helpers.normalize_yaml(yaml).should == {
|
40
|
+
'key1' => 'value1',
|
41
|
+
'key2' => { '0' => 'value2', '1' => '', '2' => ':bla' },
|
42
|
+
'parent1' => { 'key3' => { '0' => ':bob' } }
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#array_to_hash" do
|
48
|
+
it "returns hash with numeric indexes" do
|
49
|
+
Helpers.array_to_hash(['a','b']).should == { '0' => 'a', '1' => 'b' }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/spec/yaml-validator_spec.rb
CHANGED
@@ -6,6 +6,15 @@ describe YamlValidator do
|
|
6
6
|
|
7
7
|
describe "#validate" do
|
8
8
|
|
9
|
+
describe "no en.yml file" do
|
10
|
+
it "returns 'no en.yml' error" do
|
11
|
+
validator = YamlValidator.new('spec/fixtures')
|
12
|
+
errors = validator.validate()
|
13
|
+
errors.should ==
|
14
|
+
['no en.yml file in the directory (an en.yml file is required as reference)']
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
9
18
|
describe "wrong_variables scenario" do
|
10
19
|
it "returns two errors" do
|
11
20
|
validator = YamlValidator.new('spec/fixtures/wrong_variables')
|
@@ -25,7 +34,9 @@ describe YamlValidator do
|
|
25
34
|
"he.yml: parent1.key1.subkey1 doesn't exist in en.yml",
|
26
35
|
"he.yml: parent2.key2 doesn't exist in en.yml",
|
27
36
|
"he.yml: key3 doesn't exist in en.yml",
|
28
|
-
"he.yml: parent3.key4 doesn't exist in en.yml"
|
37
|
+
"he.yml: parent3.key4 doesn't exist in en.yml",
|
38
|
+
"he.yml: missing translation for parent1.key1 ('Hello, %{name}, this is %{day_of_week}')",
|
39
|
+
"he.yml: missing translation for parent2.key2.subkey ('bla bla')"
|
29
40
|
]
|
30
41
|
end
|
31
42
|
end
|
@@ -40,6 +51,19 @@ describe YamlValidator do
|
|
40
51
|
]
|
41
52
|
end
|
42
53
|
end
|
54
|
+
|
55
|
+
describe "missing translations" do
|
56
|
+
it "returns invalid yaml error" do
|
57
|
+
validator = YamlValidator.new('spec/fixtures/missing_translations')
|
58
|
+
errors = validator.validate()
|
59
|
+
errors.should == [
|
60
|
+
"he.yml: missing translation for key2 ('value2')",
|
61
|
+
"he.yml: missing translation for parent2.key3 ('value3')",
|
62
|
+
"he.yml: missing translation for parent3.2 ('three')",
|
63
|
+
"he.yml: missing translation for parent3.3 ('')",
|
64
|
+
]
|
65
|
+
end
|
66
|
+
end
|
43
67
|
|
44
68
|
end
|
45
69
|
|
@@ -134,5 +158,49 @@ describe YamlValidator do
|
|
134
158
|
end
|
135
159
|
end
|
136
160
|
end
|
161
|
+
|
162
|
+
describe "#find_missing_translations" do
|
163
|
+
it "returns the missing translation keys" do
|
164
|
+
validator = YamlValidator.new('spec/fixtures/missing_translations')
|
165
|
+
|
166
|
+
yaml_object = YAML.load_file('spec/fixtures/missing_translations/he.yml')['he']
|
167
|
+
yaml_object = Helpers.normalize_yaml(yaml_object)
|
168
|
+
|
169
|
+
errors = validator.find_missing_translations(yaml_object)
|
170
|
+
errors.should == [
|
171
|
+
"missing translation for key2 ('value2')",
|
172
|
+
"missing translation for parent2.key3 ('value3')",
|
173
|
+
"missing translation for parent3.2 ('three')",
|
174
|
+
"missing translation for parent3.3 ('')"
|
175
|
+
]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "#find_key_in_yaml_object" do
|
180
|
+
it "handles subkeys" do
|
181
|
+
yaml_object = { 'parent1' => { 'key1' => 'value1' } }
|
182
|
+
YamlValidator.find_key_in_yaml_object('parent1.key1', yaml_object).should == 'value1'
|
183
|
+
end
|
184
|
+
|
185
|
+
it "handles root keys" do
|
186
|
+
yaml_object = { "key2" => 'value2' }
|
187
|
+
YamlValidator.find_key_in_yaml_object('key2', yaml_object).should == 'value2'
|
188
|
+
end
|
189
|
+
|
190
|
+
it "returns nil when a root key doesn't exist" do
|
191
|
+
yaml_object = { "key2" => 'value2' }
|
192
|
+
YamlValidator.find_key_in_yaml_object('key1', yaml_object).should be_nil
|
193
|
+
end
|
194
|
+
|
195
|
+
it "returns nil when a subkey doesn't exist" do
|
196
|
+
yaml_object = { "parent1" => { "key2" => 'value2' } }
|
197
|
+
YamlValidator.find_key_in_yaml_object('parent1.key1', yaml_object).should be_nil
|
198
|
+
end
|
199
|
+
|
200
|
+
it "returns nil when a subkey is an object" do
|
201
|
+
yaml_object = { "parent1" => { "parent2" => { "key1" => 'value1' } } }
|
202
|
+
YamlValidator.find_key_in_yaml_object('parent1.key2', yaml_object).should be_nil
|
203
|
+
end
|
137
204
|
|
205
|
+
end
|
138
206
|
end
|
data/yaml-validator.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |gem|
|
|
10
10
|
gem.email = ["3david@gmail.com"]
|
11
11
|
gem.description = %q{YAML locales validator}
|
12
12
|
gem.summary = %q{Validates .yml locale files for Ruby on Rails projects}
|
13
|
-
gem.homepage = ""
|
13
|
+
gem.homepage = "http://github.com/wazeHQ/yaml-validator"
|
14
14
|
|
15
15
|
gem.files = `git ls-files`.split($/)
|
16
16
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
@@ -19,4 +19,5 @@ Gem::Specification.new do |gem|
|
|
19
19
|
|
20
20
|
gem.add_dependency('rake')
|
21
21
|
gem.add_dependency('rspec')
|
22
|
+
gem.add_dependency('colorize')
|
22
23
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yaml-validator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: colorize
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
46
62
|
description: YAML locales validator
|
47
63
|
email:
|
48
64
|
- 3david@gmail.com
|
@@ -52,21 +68,28 @@ extensions: []
|
|
52
68
|
extra_rdoc_files: []
|
53
69
|
files:
|
54
70
|
- .rspec
|
71
|
+
- .travis.yml
|
55
72
|
- Gemfile
|
56
73
|
- Gemfile.lock
|
57
74
|
- README.md
|
58
75
|
- Rakefile
|
59
76
|
- bin/yaml-validator
|
77
|
+
- lib/helpers.rb
|
60
78
|
- lib/yaml-validator.rb
|
61
79
|
- lib/yaml-validator/version.rb
|
80
|
+
- pkg/yaml-validator-0.0.1.gem
|
62
81
|
- spec/fixtures/inconsistent_types/en.yml
|
63
82
|
- spec/fixtures/inconsistent_types/he.yml
|
83
|
+
- spec/fixtures/invalid_yml/en.yml
|
64
84
|
- spec/fixtures/invalid_yml/invalid.yml
|
85
|
+
- spec/fixtures/missing_translations/en.yml
|
86
|
+
- spec/fixtures/missing_translations/he.yml
|
65
87
|
- spec/fixtures/wrong_variables/en.yml
|
66
88
|
- spec/fixtures/wrong_variables/he.yml
|
89
|
+
- spec/helpers_spec.rb
|
67
90
|
- spec/yaml-validator_spec.rb
|
68
91
|
- yaml-validator.gemspec
|
69
|
-
homepage:
|
92
|
+
homepage: http://github.com/wazeHQ/yaml-validator
|
70
93
|
licenses: []
|
71
94
|
post_install_message:
|
72
95
|
rdoc_options: []
|
@@ -80,7 +103,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
80
103
|
version: '0'
|
81
104
|
segments:
|
82
105
|
- 0
|
83
|
-
hash:
|
106
|
+
hash: 1734535970002030944
|
84
107
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
108
|
none: false
|
86
109
|
requirements:
|
@@ -89,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
112
|
version: '0'
|
90
113
|
segments:
|
91
114
|
- 0
|
92
|
-
hash:
|
115
|
+
hash: 1734535970002030944
|
93
116
|
requirements: []
|
94
117
|
rubyforge_project:
|
95
118
|
rubygems_version: 1.8.24
|
@@ -99,7 +122,11 @@ summary: Validates .yml locale files for Ruby on Rails projects
|
|
99
122
|
test_files:
|
100
123
|
- spec/fixtures/inconsistent_types/en.yml
|
101
124
|
- spec/fixtures/inconsistent_types/he.yml
|
125
|
+
- spec/fixtures/invalid_yml/en.yml
|
102
126
|
- spec/fixtures/invalid_yml/invalid.yml
|
127
|
+
- spec/fixtures/missing_translations/en.yml
|
128
|
+
- spec/fixtures/missing_translations/he.yml
|
103
129
|
- spec/fixtures/wrong_variables/en.yml
|
104
130
|
- spec/fixtures/wrong_variables/he.yml
|
131
|
+
- spec/helpers_spec.rb
|
105
132
|
- spec/yaml-validator_spec.rb
|