Class: RomanNumeral

Inherits:
Numeric show all
Includes:
Comparable
Defined in:
lib/roman.rb

Overview

Work with Roman numerals just like normal Integers.

Constant Summary collapse

MAX =

The largest integer representable as a roman numerable by this module.

3999
REGEXP =

Taken from O’Reilly’s Perl Cookbook 6.23. Regular Expression Grabbag.

/^M*(D?C{0,3}|C[DM])(L?X{0,3}|X[LC])(V?I{0,3}|I[VX])$/i
ROMAN_VALUES_ASSOC =
[
  ["M", 1000],
  ["CM", 900],
  ["D",  500],
  ["CD", 400],
  ["C",  100],
  ["XC",  90],
  ["L",   50],
  ["XL",  40],
  ["X",   10],
  ["IX",   9],
  ["V",    5],
  ["IV",   4],
  ["I",    1]
]
ROMAN_VALUES =
ROMAN_VALUES_ASSOC.inject({}){ |h,(r,a)| h[r] = a; h }

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(val) ⇒ RomanNumeral

Create a new instance from an Integer, String or other RomanNumeral.



66
67
68
69
70
71
72
73
74
75
76
# File 'lib/roman.rb', line 66

def initialize(val)  
  case val
  when String
    @i = self.class.to_integer(val)  
    @s = val.frozen? ? val : val.dup.freeze  
  when Numeric  
    @i = val.to_i  
  else  
    raise ArgumentError, 'Cannot convert %p' % val  
  end  
end

Class Method Details

.from_integer(int) ⇒ Object



34
35
36
37
38
39
40
41
# File 'lib/roman.rb', line 34

def self.from_integer(int)
  #return nil if integer > MAX
  return "-#{(-int).roman}" if int < 0
  return "" if int == 0
  ROMAN_VALUES_ASSOC.each do |(i, v)|
    return(i + from_integer(int-v)) if v <= int 
  end
end

.is_roman_numeral?(string) ⇒ Boolean

Returns true if string is a roman numeral.

Returns:

  • (Boolean)


59
60
61
# File 'lib/roman.rb', line 59

def self.is_roman_numeral?(string)
  REGEXP =~ string
end

.to_integer(roman) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/roman.rb', line 44

def self.to_integer(roman)
  #return nil unless roman_string.is_roman_numeral?
  last = roman[-1,1].upcase
  roman.reverse.split('').inject(0) do |result, c|
    c = c.upcase
    if ROMAN_VALUES[c] < ROMAN_VALUES[last]
      result -= ROMAN_VALUES[c]
    else
      last = c
      result += ROMAN_VALUES[c]
    end
  end
end

Instance Method Details

#&(o) ⇒ Object

bit operators



229
230
231
# File 'lib/roman.rb', line 229

def &(o)
  self.class.new(@i & o.to_int)
end

#*(o) ⇒ Object



191
192
193
194
195
196
197
198
# File 'lib/roman.rb', line 191

def *(o)
  if Numeric === o
    self.class.new(@i * o.to_num)
  else
    a, b = o.coerce(self)
    a * b
  end
end

#**(o) ⇒ Object



210
211
212
213
214
215
216
217
# File 'lib/roman.rb', line 210

def **(o)
  if Numeric === o
    self.class.new(@i / o.to_num)
  else
    a, b = o.coerce(self)
    a / b
  end
end

#+(o) ⇒ Object



171
172
173
174
175
176
177
178
# File 'lib/roman.rb', line 171

def +(o)
  if Numeric === o
    self.class.new(@i + o.to_num)
  else
    a, b = o.coerce(self)
    a + b
  end
end

#+@Object



162
163
164
# File 'lib/roman.rb', line 162

def +@
  self
end

#-(o) ⇒ Object



181
182
183
184
185
186
187
188
# File 'lib/roman.rb', line 181

def -(o)
  if Numeric === o
    self.class.new(@i - o.to_num)
  else
    a, b = o.coerce(self)
    a - b
  end
end

#-@Object



166
167
168
# File 'lib/roman.rb', line 166

def -@
  self.class.new(-@i)
end

#/(o) ⇒ Object



201
202
203
204
205
206
207
208
# File 'lib/roman.rb', line 201

def /(o)
  if Numeric === o
    self.class.new(@i / o.to_num)
  else
    a, b = o.coerce(self)
    a / b
  end
end

#<<(o) ⇒ Object



219
220
221
# File 'lib/roman.rb', line 219

def <<(o)
  self.class.new(@i << o.to_int)
end

#<=>(o) ⇒ Object



122
123
124
125
126
127
128
129
130
# File 'lib/roman.rb', line 122

def <=>(o)  
  case o
  when Numeric
    @i <=> o.to_num
  else
    a, b = o.coerce(self)
    a <=> b
  end rescue nil  
end

#==(num) ⇒ Object



112
113
114
# File 'lib/roman.rb', line 112

def ==(num)
  @i == num.to_num  
end

#>>(o) ⇒ Object



223
224
225
# File 'lib/roman.rb', line 223

def >>(o)
  self.class.new(@i >> o.to_int)
end

#between?(a, b) ⇒ Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/roman.rb', line 150

def between?(a, b)
  @i.between? a, b
end

#coerce(o) ⇒ Object



117
118
119
# File 'lib/roman.rb', line 117

def coerce(o)  
  [self.class.new(o.to_int), self]  
end

#eql?(num) ⇒ Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/roman.rb', line 107

def eql?(num)
  self.class.equal?(num.class) && @i == num.to_i  
end

#even?Boolean

Returns:

  • (Boolean)


146
147
148
# File 'lib/roman.rb', line 146

def even?
  @i.even?
end

#freezeObject

Freeze



238
239
240
241
# File 'lib/roman.rb', line 238

def freeze
  to_s
  super
end

#hashObject

hash code calculation



80
81
82
# File 'lib/roman.rb', line 80

def hash
  @i.hash
end

#integer?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'lib/roman.rb', line 154

def integer?
  true
end

#nonzero?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/roman.rb', line 138

def nonzero?
  @i.nonzero?
end

#odd?Boolean

Returns:

  • (Boolean)


142
143
144
# File 'lib/roman.rb', line 142

def odd?
  @i.odd?
end

#real?Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/roman.rb', line 158

def real?
  true
end

#to_arabicObject



99
# File 'lib/roman.rb', line 99

def to_arabic ; @i ; end

#to_iObject



93
# File 'lib/roman.rb', line 93

def to_i ; @i ; end

#to_intObject



96
# File 'lib/roman.rb', line 96

def to_int ; @i ; end

#to_numObject



90
# File 'lib/roman.rb', line 90

def to_num ; @i ; end

#to_romanObject



102
103
104
# File 'lib/roman.rb', line 102

def to_roman
  self  
end

#to_sObject



85
86
87
# File 'lib/roman.rb', line 85

def to_s
  @s ||= self.class.from_integer(@i)
end

#zero?Boolean

various tests that Fixnum also has

Returns:

  • (Boolean)


134
135
136
# File 'lib/roman.rb', line 134

def zero?
  @i.zero?
end

#|(o) ⇒ Object



233
234
235
# File 'lib/roman.rb', line 233

def |(o)
  self.class.new(@i | o.to_int)
end