Skip to content

Commit

Permalink
added missing translations test
Browse files Browse the repository at this point in the history
  • Loading branch information
elentok committed Feb 7, 2013
1 parent b2dbe91 commit 010c6cc
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 4 deletions.
24 changes: 24 additions & 0 deletions lib/helpers.rb
@@ -0,0 +1,24 @@
module Helpers

def self.normalize_yaml(yaml)
return '' if yaml.nil?
return yaml if yaml.is_a? String
return yaml.to_s if yaml.is_a? Numeric
return yaml.to_s if !!yaml == yaml # if boolean
return ":#{yaml.to_s}" if yaml.is_a? Symbol
yaml = array_to_hash(yaml) if yaml.is_a? Array

normalized = {}
yaml.each do |key, value|
normalized[key] = normalize_yaml(value)
end
normalized
end

def self.array_to_hash(array)
hash = {}
array.each_with_index { |val, i| hash[i.to_s] = val }
hash
end

end
64 changes: 61 additions & 3 deletions lib/yaml-validator.rb
@@ -1,18 +1,26 @@
require 'yaml'
require 'yaml-validator/version'
require_relative './helpers'

class YamlValidator

def initialize(root_path)
@root_path = root_path
end

def en_with_vars
def en
return @en unless @en.nil?

fullpath = File.join(@root_path, 'en.yml')
return nil unless File.exists?(fullpath)

@en ||= YAML.load_file(fullpath)['en']
@en_with_vars ||= get_all_variables(@en)
@en = YAML.load_file(fullpath)['en']
@en = Helpers.normalize_yaml(@en)
end

def en_with_vars
return nil if en.nil?
@en_with_vars ||= get_all_variables(en)
end

def validate()
Expand All @@ -22,27 +30,37 @@ def validate()
yml_files = File.join(@root_path, '*.yml')
errors = []
Dir[yml_files].each do |filename|
next if File.basename(filename) == 'en.yml'
errors.concat validate_yaml(filename)
end
errors
end

def validate_yaml(filepath)
filename = File.basename(filepath)
puts "Validating #{filepath}"

begin
yaml_object = YAML.load_file(filepath)
rescue Psych::SyntaxError => e
return [e.message.sub(/^\([^)]+\)/, filename)]
end

yaml_object = yaml_object[yaml_object.keys[0]]
yaml_object = Helpers.normalize_yaml(yaml_object)
errors = validate_yaml_object('', yaml_object)
errors.concat find_missing_translations(yaml_object)

errors.map { |err| "#{filename}: #{err}" }
end

def validate_yaml_object(full_key, yaml_object)
return [] if yaml_object.nil?
errors = []

puts "full_key = #{full_key}"
puts "yaml_object = #{yaml_object}"

yaml_object.each do |key, value|
full_subkey = (full_key.empty?) ? key : "#{full_key}.#{key}"
if value.is_a? String
Expand All @@ -54,6 +72,41 @@ def validate_yaml_object(full_key, yaml_object)
errors
end

def find_missing_translations(yaml_object)
find_missing_translations_in_en_object('', en, yaml_object)
end

def find_missing_translations_in_en_object(full_key, en_yaml_object, yaml_object)
return [] if en_yaml_object.nil?
errors = []

en_yaml_object.each do |key, value|
full_subkey = (full_key.empty?) ? key : "#{full_key}.#{key}"
if value.is_a? String or value.is_a? Symbol
if self.class.find_key_in_yaml_object(full_subkey, yaml_object).nil?
errors << "missing translation for #{full_subkey} ('#{value}')"
end
else
errors.concat find_missing_translations_in_en_object(full_subkey, value, yaml_object)
end
end
errors
end

def self.find_key_in_yaml_object(full_key, yaml_object)
position = yaml_object
full_key.split('.').each do |key|
return nil unless position.is_a? Hash
position = position[key]
end

if position.is_a? String or position.is_a? Symbol
position
else
nil
end
end

def validate_item(full_key, value)
real_vars = get_key_en_vars(full_key)
if real_vars.nil?
Expand Down Expand Up @@ -86,10 +139,14 @@ def get_key_en_vars(full_key)
end

def get_all_variables(yaml_object)
return {} if yaml_object.nil?
with_vars = {}

yaml_object.each do |key, value|
if value.is_a? String
with_vars[key] = identify_variables(value)
elsif value.is_a? Symbol
with_vars[key] = {}
else
with_vars[key] = get_all_variables(value)
end
Expand All @@ -100,5 +157,6 @@ def get_all_variables(yaml_object)
def identify_variables(string)
string.scan(/%{([^}]+)}/).map { |v| v[0] }
end

end

Binary file added pkg/yaml-validator-0.0.1.gem
Binary file not shown.
12 changes: 12 additions & 0 deletions spec/fixtures/missing_translations/en.yml
@@ -0,0 +1,12 @@
en:
key1: 'value1'
parent1:
subkey1: 'value1'
key2: 'value2'
parent2:
key3: 'value3'
parent3:
- one
- :two
- three
-
7 changes: 7 additions & 0 deletions spec/fixtures/missing_translations/he.yml
@@ -0,0 +1,7 @@
he:
key1: 'value1'
parent1:
subkey1: 'value1'
parent3:
- 1
- heb two
53 changes: 53 additions & 0 deletions spec/helpers_spec.rb
@@ -0,0 +1,53 @@
require_relative '../lib/helpers'

describe Helpers do
describe "#normalize_yaml" do
it "converts symbols to strings (with ':' prefix)" do
yaml = { 'key3' => :bob }

Helpers.normalize_yaml(yaml).should == {
'key3' => ':bob'
}
end

it "converts nil to ''" do
yaml = { 'key3' => nil }
Helpers.normalize_yaml(yaml).should == {
'key3' => ''
}
end

it "converts numbers to string" do
yaml = { 'key3' => 123 }
Helpers.normalize_yaml(yaml).should == {
'key3' => '123'
}
end

it "converts booleans to string" do
yaml = { 'key3' => true }
Helpers.normalize_yaml(yaml).should == {
'key3' => 'true'
}
end

it "converts arrays to hashes" do
yaml = { 'key1' => 'value1',
'key2' => [ 'value2', nil, :bla ],
'parent1' => { 'key3' => [ :bob ] } }

Helpers.normalize_yaml(yaml).should == {
'key1' => 'value1',
'key2' => { '0' => 'value2', '1' => '', '2' => ':bla' },
'parent1' => { 'key3' => { '0' => ':bob' } }
}
end
end

describe "#array_to_hash" do
it "returns hash with numeric indexes" do
Helpers.array_to_hash(['a','b']).should == { '0' => 'a', '1' => 'b' }
end
end

end
61 changes: 60 additions & 1 deletion spec/yaml-validator_spec.rb
Expand Up @@ -34,7 +34,9 @@
"he.yml: parent1.key1.subkey1 doesn't exist in en.yml",
"he.yml: parent2.key2 doesn't exist in en.yml",
"he.yml: key3 doesn't exist in en.yml",
"he.yml: parent3.key4 doesn't exist in en.yml"
"he.yml: parent3.key4 doesn't exist in en.yml",
"he.yml: missing translation for parent1.key1 ('Hello, %{name}, this is %{day_of_week}')",
"he.yml: missing translation for parent2.key2.subkey ('bla bla')"
]
end
end
Expand All @@ -49,6 +51,19 @@
]
end
end

describe "missing translations" do
it "returns invalid yaml error" do
validator = YamlValidator.new('spec/fixtures/missing_translations')
errors = validator.validate()
errors.should == [
"he.yml: missing translation for key2 ('value2')",
"he.yml: missing translation for parent2.key3 ('value3')",
"he.yml: missing translation for parent3.2 ('three')",
"he.yml: missing translation for parent3.3 ('')",
]
end
end

end

Expand Down Expand Up @@ -143,5 +158,49 @@
end
end
end

describe "#find_missing_translations" do
it "returns the missing translation keys" do
validator = YamlValidator.new('spec/fixtures/missing_translations')

yaml_object = YAML.load_file('spec/fixtures/missing_translations/he.yml')['he']
yaml_object = Helpers.normalize_yaml(yaml_object)

errors = validator.find_missing_translations(yaml_object)
errors.should == [
"missing translation for key2 ('value2')",
"missing translation for parent2.key3 ('value3')",
"missing translation for parent3.2 ('three')",
"missing translation for parent3.3 ('')"
]
end
end

describe "#find_key_in_yaml_object" do
it "handles subkeys" do
yaml_object = { 'parent1' => { 'key1' => 'value1' } }
YamlValidator.find_key_in_yaml_object('parent1.key1', yaml_object).should == 'value1'
end

it "handles root keys" do
yaml_object = { "key2" => 'value2' }
YamlValidator.find_key_in_yaml_object('key2', yaml_object).should == 'value2'
end

it "returns nil when a root key doesn't exist" do
yaml_object = { "key2" => 'value2' }
YamlValidator.find_key_in_yaml_object('key1', yaml_object).should be_nil
end

it "returns nil when a subkey doesn't exist" do
yaml_object = { "parent1" => { "key2" => 'value2' } }
YamlValidator.find_key_in_yaml_object('parent1.key1', yaml_object).should be_nil
end

it "returns nil when a subkey is an object" do
yaml_object = { "parent1" => { "parent2" => { "key1" => 'value1' } } }
YamlValidator.find_key_in_yaml_object('parent1.key2', yaml_object).should be_nil
end

end
end

0 comments on commit 010c6cc

Please sign in to comment.