Add Locale class to enable easier matching of locales.

This commit is contained in:
Markus Reiter 2016-09-27 22:23:13 +02:00
parent bc143bb470
commit b5531e8ec1
2 changed files with 140 additions and 0 deletions

View File

@ -0,0 +1,72 @@
require "spec_helper"
require "locale"
describe Locale do
describe "::parse" do
it "parses a string in the correct format" do
expect(described_class.parse("zh")).to eql(described_class.new("zh", nil, nil))
expect(described_class.parse("zh-CN")).to eql(described_class.new("zh", "CN", nil))
expect(described_class.parse("zh-Hans")).to eql(described_class.new("zh", nil, "Hans"))
expect(described_class.parse("zh-CN-Hans")).to eql(described_class.new("zh", "CN", "Hans"))
end
context "raises a ParserError when given" do
it "an empty string" do
expect{ described_class.parse("") }.to raise_error(Locale::ParserError)
end
it "a string in a wrong format" do
expect { described_class.parse("zh_CN_Hans") }.to raise_error(Locale::ParserError)
expect { described_class.parse("zhCNHans") }.to raise_error(Locale::ParserError)
expect { described_class.parse("zh-CN_Hans") }.to raise_error(Locale::ParserError)
expect { described_class.parse("zhCN") }.to raise_error(Locale::ParserError)
expect { described_class.parse("zh_Hans") }.to raise_error(Locale::ParserError)
end
end
end
describe "::new" do
it "raises an ArgumentError when all arguments are nil" do
expect { described_class.new(nil, nil, nil) }.to raise_error(ArgumentError)
end
it "raises a ParserError when one of the arguments does not match the locale format" do
expect { described_class.new("ZH", nil, nil) }.to raise_error(Locale::ParserError)
expect { described_class.new(nil, "cn", nil) }.to raise_error(Locale::ParserError)
expect { described_class.new(nil, nil, "hans") }.to raise_error(Locale::ParserError)
end
end
subject { described_class.new("zh", "CN", "Hans") }
describe "#include?" do
it { is_expected.to include("zh") }
it { is_expected.to include("zh-CN") }
it { is_expected.to include("CN") }
it { is_expected.to include("CN-Hans") }
it { is_expected.to include("Hans") }
it { is_expected.to include("zh-CN-Hans") }
end
describe "#eql?" do
subject { described_class.new("zh", "CN", "Hans") }
context "all parts match" do
it { is_expected.to eql("zh-CN-Hans") }
it { is_expected.to eql(subject) }
end
context "only some parts match" do
it { is_expected.to_not eql("zh") }
it { is_expected.to_not eql("zh-CN") }
it { is_expected.to_not eql("CN") }
it { is_expected.to_not eql("CN-Hans") }
it { is_expected.to_not eql("Hans") }
end
it "does not raise if 'other' cannot be parsed" do
expect { subject.eql?("zh_CN_Hans") }.not_to raise_error
expect(subject.eql?("zh_CN_Hans")).to be false
end
end
end

View File

@ -0,0 +1,68 @@
class Locale
class ParserError < ::RuntimeError
end
LANGUAGE_REGEX = /(?:[a-z]{2})/
REGION_REGEX = /(?:[A-Z]{2})/
SCRIPT_REGEX = /(?:[A-Z][a-z]{3})/
LOCALE_REGEX = /^(#{LANGUAGE_REGEX})?(?:(?:^|-)(#{REGION_REGEX}))?(?:(?:^|-)(#{SCRIPT_REGEX}))?$/
def self.parse(string)
language, region, script = string.to_s.scan(LOCALE_REGEX)[0]
if language.nil? && region.nil? && script.nil?
raise ParserError, "'#{string}' cannot be parsed to a #{self.class}"
end
new(language, region, script)
end
attr_reader :language, :region, :script
def initialize(language, region, script)
if language.nil? && region.nil? && script.nil?
raise ArgumentError, "#{self.class} cannot be empty"
end
{
language: language,
region: region,
script: script,
}.each do |key, value|
next if value.nil?
regex = self.class.const_get("#{key.upcase}_REGEX")
raise ParserError, "'#{value}' does not match #{regex}" unless value =~ regex
instance_variable_set(:"@#{key}", value)
end
self
end
def include?(other)
other = self.class.parse(other) unless other.is_a?(self.class)
[:language, :region, :script].all? { |var|
if other.public_send(var).nil?
true
else
public_send(var) == other.public_send(var)
end
}
end
def eql?(other)
other = self.class.parse(other) unless other.is_a?(self.class)
[:language, :region, :script].all? { |var|
public_send(var) == other.public_send(var)
}
rescue ParserError
false
end
alias == eql?
def to_s
[@language, @region, @script].compact.join("-")
end
end