Skip to content

Instantly share code, notes, and snippets.

@simonkro
Created December 3, 2012 20:12
Show Gist options
  • Save simonkro/4197654 to your computer and use it in GitHub Desktop.
Save simonkro/4197654 to your computer and use it in GitHub Desktop.
require 'number_converter'
ARGV.each do |input_number|
result = NumberConverter.new(input_number).convert
puts "#{input_number} = #{result}"
end
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
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