Created
December 3, 2012 20:12
-
-
Save simonkro/4197654 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'number_converter' | |
ARGV.each do |input_number| | |
result = NumberConverter.new(input_number).convert | |
puts "#{input_number} = #{result}" | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class NumberConverter | |
attr_accessor :number, :type | |
ROMAN_NUMERALS_VALUES = { | |
'I' => 1, | |
'V' => 5, | |
'X' => 10, | |
'L' => 50, | |
'C' => 100, | |
'D' => 500, | |
'M' => 1000 | |
} | |
SUBTRACTION_RULES = { | |
'I' => ['V', 'X'], | |
'X' => ['L', 'C'], | |
'C' => ['D', 'M'] | |
} | |
ARABIAN_REGEX = /\d+/ | |
ROMAN_REGEX = /[MDCLXVI]+/ | |
def initialize(input_number) | |
@number = input_number.to_s | |
if number.match(ARABIAN_REGEX) | |
@type = :arabian | |
elsif number.match(ROMAN_REGEX) | |
@type = :roman | |
else | |
raise 'Incorrect input number' | |
end | |
end | |
def convert | |
case type | |
when :arabian | |
to_roman | |
when :roman | |
to_arabic | |
end | |
end | |
def roman_numerals_extension | |
@roman_numerals_extension ||= {}.tap do |extension_hash| | |
SUBTRACTION_RULES.each do |subtrahend, rule| | |
rule.each do |minuend| | |
min = ROMAN_NUMERALS_VALUES[minuend] | |
sub = ROMAN_NUMERALS_VALUES[subtrahend] | |
extension_hash[subtrahend + minuend] = min - sub | |
end | |
end | |
end | |
end | |
def to_arabic | |
tmp_number = number.dup | |
roman_numerals_extension.each do |extension, value| | |
tmp_number.gsub!(extension, '+' + value.to_s) | |
end | |
ROMAN_NUMERALS_VALUES.each do |numeral, value| | |
tmp_number.gsub!(numeral, '+' + value.to_s) | |
end | |
eval tmp_number | |
end | |
def to_roman | |
decimal_number = number.to_i | |
roman_numerals_extended = ROMAN_NUMERALS_VALUES.merge(roman_numerals_extension) | |
sorted_numerals = roman_numerals_extended.keys.sort{ | |
|a,b| roman_numerals_extended[b] <=> roman_numerals_extended[a] | |
} | |
sorted_numerals.inject("") do |roman_number, numeral| | |
value = roman_numerals_extended[numeral] | |
while decimal_number - value >= 0 | |
roman_number << numeral | |
decimal_number -= value | |
end | |
roman_number | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'test/unit' | |
require 'number_converter' | |
class NumberConverterTest < Test::Unit::TestCase | |
def test_should_convert_to_roman | |
assert_equal 'III', NumberConverter.new(3).convert | |
assert_equal 'IV', NumberConverter.new(4).convert | |
assert_equal 'VIII', NumberConverter.new(8).convert | |
assert_equal 'XXIX', NumberConverter.new(29).convert | |
assert_equal 'XXXVIII', NumberConverter.new(38).convert | |
assert_equal 'MCMXCIX', NumberConverter.new(1999).convert | |
assert_equal 'CCXCI', NumberConverter.new(291).convert | |
assert_equal 'XXXI', NumberConverter.new(31).convert | |
assert_equal 'CM', NumberConverter.new(900).convert | |
assert_equal 'MCMLIV', NumberConverter.new(1954).convert | |
assert_equal 'MMVI', NumberConverter.new(2006).convert | |
end | |
def test_should_convert_to_arabic | |
assert_equal 3, NumberConverter.new('III').convert | |
assert_equal 4, NumberConverter.new('IV').convert | |
assert_equal 8, NumberConverter.new('VIII').convert | |
assert_equal 29, NumberConverter.new('XXIX').convert | |
assert_equal 38, NumberConverter.new('XXXVIII').convert | |
assert_equal 1999, NumberConverter.new('MCMXCIX').convert | |
assert_equal 291, NumberConverter.new('CCXCI').convert | |
assert_equal 31, NumberConverter.new('XXXI').convert | |
assert_equal 900, NumberConverter.new('CM').convert | |
assert_equal 1954, NumberConverter.new('MCMLIV').convert | |
assert_equal 2006, NumberConverter.new('MMVI').convert | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment