Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
require "test/unit"
class CountryMatcherTest < Test::Unit::TestCase
def test_valid_case
result = CountryMatcher.call("DE") do |match|
match.us { "US" }
match.de { "DE" }
match.gb { "GB" }
end
assert_equal result, "DE"
end
def test_valid_case_with_nil_result
result = CountryMatcher.call("DE") do |match|
match.us { "US" }
match.de {}
match.gb { "GB" }
end
assert_equal result, nil
end
def test_multiple_definitions
result = proc do
CountryMatcher.call("DE") do |match|
match.us { "US" }
match.de { "DE" }
match.de { "DE" }
match.gb { "GB" }
end
end
assert_raise(CountryMatcher::MultipleDefinitionError) { result.call }
end
def test_missing_definition
result = proc do
CountryMatcher.call("DE") do |match|
match.de { "DE" }
match.gb { "GB" }
end
end
assert_raise(CountryMatcher::MissingDefinitionError) { result.call }
end
def test_unknown_country
result = proc do
CountryMatcher.call("XX") do |match|
match.de { "DE" }
match.us { "US" }
match.gb { "GB" }
end
end
assert_raise(CountryMatcher::UnknownValueError) { result.call }
end
def test_unknown_case
result = proc do
CountryMatcher.call("DE") do |match|
match.xx { "XX" }
match.de { "DE" }
match.us { "US" }
match.gb { "GB" }
end
end
assert_raise(NoMethodError) { result.call }
end
end
class CountryMatcher
COUNTRIES = ["DE", "GB", "US"]
class MultipleDefinitionError < StandardError; end
class MissingDefinitionError < StandardError; end
class UnknownValueError < StandardError; end
class Match
def initialize(country)
@country = country
@calls = []
end
COUNTRIES.each do |country|
define_method country.downcase do |&block|
if @calls.include?(country)
raise MultipleDefinitionError, country.inspect
end
@calls << country
@result = block.call if @country == country
end
end
def verify_and_return
difference.then do |missing|
if missing.any?
raise MissingDefinitionError, missing.inspect
end
end
if !COUNTRIES.include?(@country)
raise UnknownValueError, @country.inspect
end
@result
end
private
def difference
COUNTRIES.difference(@calls) +
@calls.difference(COUNTRIES)
end
end
def self.call(*args, **kwargs, &block)
new(*args, **kwargs).call(&block)
end
def initialize(value)
@value = value
end
def call
Match.new(@value).then do |match|
yield match
match.verify_and_return
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment