class RomanNumbers::RomanNumber
Constants
- MAX_ALLOWED_REPETITION
based on above non_repeatable units, allowed repetition is 3
- ROMAN_DOUBLE_UNITS
- ROMAN_NON_REPEATABLE_UNITS
- ROMAN_NON_REPEATABLE_UNITS_1
- ROMAN_NON_REPEATABLE_UNITS_2
- ROMAN_REPEATABLE_UNITS
- ROMAN_SINGLE_UNITS
- ROMAN_UNITS
Attributes
input_integer[RW]
input_string[RW]
output_integer[RW]
output_roman[RW]
staged_roman_hash[RW]
Public Class Methods
new(input)
click to toggle source
initializing element
# File lib/roman_numbers/roman_number.rb, line 37 def initialize(input) # checking input type and setting instance variables case input when Integer @input_integer = input @staged_roman_hash = Array.new @output_roman = String.new when String @input_string = input.upcase @output_integer = 0 end end
Public Instance Methods
convert_decimal_to_roman(passed_integer=input_integer)
click to toggle source
converts arabic to roman
# File lib/roman_numbers/roman_number.rb, line 53 def convert_decimal_to_roman(passed_integer=input_integer) # validating input unless (1..3999).include? passed_integer raise InvalidInputError, "Invalid Input: #{passed_integer}" end # getting staged roman hash calculate_staged_roman_hash(passed_integer) # extracting hash from staged roman hash staged_roman_hash.each do |element| output_roman << (element[:largest_element][:unit].to_s)*(element[:times]) end output_roman end
convert_roman_to_decimal(passed_roman=input_string.clone)
click to toggle source
converts given arabic number (in string form) to corresponding integer
# File lib/roman_numbers/roman_number.rb, line 68 def convert_roman_to_decimal(passed_roman=input_string.clone) # generating regex expressions double_units_array = ROMAN_NON_REPEATABLE_UNITS_2.map { |element| ('^' + element[:unit].to_s) } single_units_array = (ROMAN_REPEATABLE_UNITS + ROMAN_NON_REPEATABLE_UNITS_1).map { |element| ('^' + element[:unit].to_s) } double_units_regex = Regexp.new(double_units_array.join('|')) single_units_regex = Regexp.new(single_units_array.join('|')) # validation # TODO: to add more validations if passed_roman =~ /(.)\1{#{MAX_ALLOWED_REPETITION},}/ raise InvalidInputError, "Invalid Input: #{passed_roman}" end # processing if passed_roman.length > 0 if unit = passed_roman.slice!(double_units_regex) self.output_integer += ROMAN_DOUBLE_UNITS.find { |element| element[:unit] == unit.to_sym }[:value] convert_roman_to_decimal(passed_roman) elsif unit = passed_roman.slice!(single_units_regex) self.output_integer += ROMAN_SINGLE_UNITS.find { |element| element[:unit] == unit.to_sym }[:value] convert_roman_to_decimal(passed_roman) else # invalid input raise InvalidInputError, "Invalid Input: #{passed_roman}" end else # process is complete self.output_integer end end
Private Instance Methods
calculate_staged_roman_hash(passed_input_integer)
click to toggle source
returns an array of hashed containing info on desired output roman
# File lib/roman_numbers/roman_number.rb, line 102 def calculate_staged_roman_hash(passed_input_integer) begin temp_hash = largest_repeatable_element(passed_input_integer) rescue StartsWithNonRepeatableRomanUnitError => ex temp_hash = largest_non_repeatable_element(passed_input_integer) end if temp_hash staged_roman_hash << temp_hash passed_input_integer = temp_hash[:reduced_integer] calculate_staged_roman_hash(passed_input_integer) else # processing done staged_roman_hash end end
largest_non_repeatable_element(passed_input_integer)
click to toggle source
returns largest non-repeatable element
# File lib/roman_numbers/roman_number.rb, line 147 def largest_non_repeatable_element(passed_input_integer) if passed_input_integer > 0 largest_element = ROMAN_NON_REPEATABLE_UNITS.find { |element| passed_input_integer >= element[:value] } # TODO: make it efficient by removing elements before largest_element # TODO: to use binary search instead if largest_element reduced_integer = passed_input_integer%largest_element[:value] {:reduced_integer => reduced_integer, :largest_element => largest_element, :times => 1} else # no non_repeatable element preset, but process is not complete yet {:reduced_integer => passed_input_integer, :largest_element => nil, :times => 0} end elsif passed_input_integer == 0 # process completed nil else # non-reachable code # passed_input_integer has to be >=0 raise NonReachableCodeError, 'ReceivedNegativeInteger' end end
largest_repeatable_element(passed_input_integer)
click to toggle source
returns reduced_integer, largest repeatable element, and number of times it can be repeated
# File lib/roman_numbers/roman_number.rb, line 119 def largest_repeatable_element(passed_input_integer) if passed_input_integer > 0 largest_element = ROMAN_REPEATABLE_UNITS.find { |element| passed_input_integer >= element[:value] } # TODO: make it efficient by removing elements before largest_element # TODO: to use binary search instead if largest_element times = passed_input_integer/largest_element[:value] reduced_integer = passed_input_integer%largest_element[:value] if times > MAX_ALLOWED_REPETITION # given integer starts with non_repeatable roman unit raise StartsWithNonRepeatableRomanUnitError end {:reduced_integer => reduced_integer, :largest_element => largest_element, :times => times} else # non-reachable code raise NonReachableCodeError, 'LargestElementIsNil' end elsif passed_input_integer == 0 # process completed nil else # non-reachable code # passed_input_integer has to be >=0 raise NonReachableCodeError, 'ReceivedNegativeInteger' end end