facets 2.8.2 → 2.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +13 -11
- data/HISTORY.rdoc +58 -0
- data/lib/core/facets/array/recursive.rb +91 -0
- data/lib/core/facets/array/recursively.rb +2 -2
- data/lib/core/facets/array/traverse.rb +23 -6
- data/lib/core/facets/enumerable/collisions.rb +1 -0
- data/lib/core/facets/enumerable/commonality.rb +4 -2
- data/lib/core/facets/enumerable/graph.rb +37 -1
- data/lib/core/facets/enumerable/mash.rb +1 -39
- data/lib/core/facets/enumerable/recursive.rb +75 -0
- data/lib/core/facets/enumerable/visit.rb +30 -0
- data/lib/core/facets/file/ext.rb +36 -0
- data/lib/core/facets/hash/graph.rb +18 -0
- data/lib/core/facets/hash/mash.rb +1 -18
- data/lib/core/facets/hash/recursive.rb +180 -0
- data/lib/core/facets/hash/recursive_merge.rb +6 -0
- data/lib/core/facets/hash/recursively.rb +2 -2
- data/lib/core/facets/hash/to_module.rb +26 -0
- data/lib/core/facets/hash/to_proc.rb +2 -2
- data/lib/core/facets/hash/traverse.rb +19 -13
- data/lib/core/facets/kernel/assign.rb +63 -0
- data/lib/core/facets/kernel/assign_from.rb +45 -0
- data/lib/core/facets/kernel/dup.rb +63 -0
- data/lib/core/facets/kernel/instance.rb +156 -0
- data/lib/core/facets/kernel/instance_assign.rb +1 -22
- data/lib/core/facets/kernel/meta_def.rb +4 -0
- data/lib/core/facets/kernel/populate.rb +1 -74
- data/lib/core/facets/kernel/set_from.rb +2 -0
- data/lib/core/facets/kernel/try_dup.rb +1 -0
- data/lib/core/facets/module/set.rb +36 -0
- data/lib/core/facets/objectspace/reflect.rb +45 -0
- data/lib/core/facets/struct/attributes.rb +6 -2
- data/lib/core/facets/symbol/op_div.rb +19 -0
- data/lib/core/facets/to_hash.rb +12 -0
- data/lib/more/facets/casting_hash.rb +172 -0
- data/lib/more/facets/pathname.rb +36 -0
- data/lib/more/facets/prepend.rb +57 -0
- data/lib/more/facets/random.rb +19 -3
- data/lib/more/facets/roman.rb +46 -153
- data/lib/more/facets/stash.rb +148 -33
- data/meta/released +1 -1
- data/meta/version +1 -1
- data/test/core/array/test_recursive.rb +18 -0
- data/test/core/enumerable/test_recursive.rb +18 -0
- data/test/core/file/test_ext.rb +31 -0
- data/test/core/hash/test_recursive.rb +23 -0
- data/test/core/hash/test_to_module.rb +21 -0
- data/test/core/kernel/test_assign.rb +57 -0
- data/test/core/kernel/test_assign_from.rb +20 -0
- data/test/more/test_prepend.rb +28 -0
- data/test/more/test_random.rb +40 -4
- metadata +39 -10
- data/lib/core/facets/kernel/instance_variables.rb +0 -97
- data/lib/more/facets/instance_eval.rb +0 -50
- data/lib/more/facets/ioredirect.rb +0 -77
- data/lib/more/facets/plugin_manager.rb +0 -50
- data/test/core/kernel/test_populate.rb +0 -46
@@ -1,11 +1,15 @@
|
|
1
1
|
class Struct
|
2
2
|
|
3
|
-
# Returns a hash containing the names and values
|
3
|
+
# Returns a hash containing the names and values
|
4
|
+
# for all instance settings in the Struct.
|
5
|
+
#
|
6
|
+
# This will eventually be deprecated in favor of #to_h.
|
7
|
+
|
4
8
|
def attributes
|
5
9
|
h = {}
|
6
10
|
each_pair { |k,v| h[k] = v }
|
7
11
|
h
|
8
12
|
end
|
9
13
|
|
10
|
-
end
|
14
|
+
end
|
11
15
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Symbol
|
2
|
+
|
3
|
+
# Join with _path_ as a file path.
|
4
|
+
#
|
5
|
+
# :merb / "core_ext" #=> "merb/core_ext"
|
6
|
+
# :merb / :core_ext / :string #=> "merb/core_ext/string"
|
7
|
+
#
|
8
|
+
# @param [#to_s] path The path component(s) to append.
|
9
|
+
#
|
10
|
+
# @return [String] The receiver (as path string), concatenated with _path_.
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
|
14
|
+
def /(path)
|
15
|
+
File.join(to_s, path.to_s)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
data/lib/core/facets/to_hash.rb
CHANGED
@@ -0,0 +1,172 @@
|
|
1
|
+
# CastingHash is just like Hash, except that all keys and values
|
2
|
+
# are passed through casting procedures.
|
3
|
+
#--
|
4
|
+
# TODO: Handle default_proc.
|
5
|
+
#++
|
6
|
+
class CastingHash < Hash
|
7
|
+
|
8
|
+
# Default key conversion procedure.
|
9
|
+
KEY_PROC = lambda{ |x| x } #.to_s }
|
10
|
+
|
11
|
+
# Default value conversion procedure.
|
12
|
+
VAL_PROC = lambda{ |x| x }
|
13
|
+
|
14
|
+
#
|
15
|
+
def self.[](hash)
|
16
|
+
s = new
|
17
|
+
hash.each{ |k,v| s[k] = v }
|
18
|
+
s
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
def initialize(hash, value_cast=nil, &key_cast)
|
23
|
+
@key_proc = key_cast || KEY_PROC
|
24
|
+
@value_proc = value_cast.to_proc || VAL_PROC
|
25
|
+
hash.each{ |k,v| self[k] = v }
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
def key_proc
|
30
|
+
@key_proc
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
def key_proc=(proc)
|
35
|
+
@key_proc = proc.to_proc
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
def value_proc
|
40
|
+
@value_proc
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
def value_proc=(proc)
|
45
|
+
@value_proc = proc.to_proc
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
def [](k)
|
50
|
+
super(key_proc[k])
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
def []=(k,v)
|
55
|
+
super(key_proc[k], value_proc[v])
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
def <<(other)
|
60
|
+
case other
|
61
|
+
when Hash
|
62
|
+
super(cast(other))
|
63
|
+
when Array
|
64
|
+
self[other[0]] = other[1]
|
65
|
+
else
|
66
|
+
raise ArgumentError
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def fetch(k)
|
71
|
+
super(key_proc[k])
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
def store(k, v)
|
76
|
+
super(key_proc[k], value_proc[v])
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
def key?(k)
|
81
|
+
super(key_proc[k])
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
def has_key?(k)
|
86
|
+
super(key_proc[k])
|
87
|
+
end
|
88
|
+
|
89
|
+
# Synonym for Hash#rekey, but modifies the receiver in place (and returns it).
|
90
|
+
#
|
91
|
+
# foo = { :name=>'Gavin', :wife=>:Lisa }.to_stash
|
92
|
+
# foo.rekey!{ |k| k.upcase } #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
|
93
|
+
# foo.inspect #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
|
94
|
+
#
|
95
|
+
def rekey!(*args, &block)
|
96
|
+
# for backward comptability (DEPRECATE?).
|
97
|
+
block = args.pop.to_sym.to_proc if args.size == 1
|
98
|
+
if args.empty?
|
99
|
+
block = lambda{|k| k} unless block
|
100
|
+
keys.each do |k|
|
101
|
+
nk = block[k]
|
102
|
+
self[nk] = delete(k) #if nk
|
103
|
+
end
|
104
|
+
else
|
105
|
+
raise ArgumentError, "3 for 2" if block
|
106
|
+
to, from = *args
|
107
|
+
self[to] = delete(from) if has_key?(from)
|
108
|
+
end
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
def rekey(*args, &block)
|
114
|
+
dup.rekey!(*args, &block)
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
def delete(k)
|
119
|
+
super(key_proc[k])
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
def update(other)
|
124
|
+
super(cast(other))
|
125
|
+
end
|
126
|
+
|
127
|
+
# Same as #update.
|
128
|
+
def merge!(other)
|
129
|
+
super(cast(other))
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
def replace(other)
|
134
|
+
super(cast(other))
|
135
|
+
end
|
136
|
+
|
137
|
+
#
|
138
|
+
def values_at(*keys)
|
139
|
+
super(keys.map(&key_proc))
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
def to_hash
|
144
|
+
h = {}; each{ |k,v| h[k] = v }; h
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
alias_method :to_h, :to_hash
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
#
|
153
|
+
def cast(hash)
|
154
|
+
h
|
155
|
+
hash.each do |k,v|
|
156
|
+
h[key_proc[k]] = value_proc[v]
|
157
|
+
end
|
158
|
+
h
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
class Hash
|
165
|
+
|
166
|
+
# Convert a Hash to a Stash object.
|
167
|
+
def to_casting_hash(value_cast=nil, &key_cast)
|
168
|
+
CastingHash.new(self, value_cast, &key_cast)
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
data/lib/more/facets/pathname.rb
CHANGED
@@ -25,6 +25,10 @@ require 'facets/file/rootname'
|
|
25
25
|
|
26
26
|
class Pathname
|
27
27
|
|
28
|
+
# Alias #to_s to #to_str when #to_str is not defined.
|
29
|
+
#
|
30
|
+
alias_method(:to_str, :to_s) unless method_defined?(:to_str)
|
31
|
+
|
28
32
|
# Alternate to Pathname#new.
|
29
33
|
#
|
30
34
|
# Pathname['/usr/share']
|
@@ -148,6 +152,38 @@ class Pathname
|
|
148
152
|
::FileUtils.outofdate?(to_s, sources.flatten)
|
149
153
|
end
|
150
154
|
|
155
|
+
# Recursively visit a directory located by its path, yielding each resource
|
156
|
+
# as its full matching pathname object. If called on a file, yield the file.
|
157
|
+
#
|
158
|
+
# call-seq:
|
159
|
+
# visit => yield each file
|
160
|
+
# visit(all: true) => yield visited directories as well
|
161
|
+
# visit(hidden: true) => yield hidden files and directories as well
|
162
|
+
#
|
163
|
+
# Example use case:
|
164
|
+
#
|
165
|
+
# # get rid of any file but *.haml within app/**/*
|
166
|
+
# Pathname.new("app").visit do |f|
|
167
|
+
# FileUtils.rm_f(f) unless f.to_s =~ /\.haml$/
|
168
|
+
# puts "!!! deleting #{f}"
|
169
|
+
# end
|
170
|
+
#
|
171
|
+
# CREDIT: Jean-Denis Vauguet
|
172
|
+
def visit(options = {:all => false, :hidden => false})
|
173
|
+
if self.directory?
|
174
|
+
children.each do |entry|
|
175
|
+
next if entry.basename.to_s[0] == "." && !options[:hidden]
|
176
|
+
yield(entry) unless entry.directory? && !options[:all]
|
177
|
+
#entry.visit(:all => options[:all]) { |sub_entry| yield sub_entry } if entry.directory?
|
178
|
+
entry.visit(:all => options[:all], :hidden => options[:hidden]) do |sub_entry|
|
179
|
+
yield(sub_entry)
|
180
|
+
end if entry.directory?
|
181
|
+
end
|
182
|
+
else
|
183
|
+
yield self
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
151
187
|
# # Already included in 1.8.4+ version of Ruby (except for inclusion flag)
|
152
188
|
# if not instance_methods.include?(:ascend)
|
153
189
|
#
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# :title: Prepend
|
2
|
+
# :copyright: Copyright (c) 2005 Thomas Sawyer
|
3
|
+
# :license: Ruby License
|
4
|
+
# :description: Prepend a module to another module, or to a class.
|
5
|
+
|
6
|
+
# = Prepend
|
7
|
+
#
|
8
|
+
# This is a module prepend system, which provides an elegant
|
9
|
+
# way to prepend code to the class hierarchy rather then append
|
10
|
+
# it (a la #include).
|
11
|
+
#
|
12
|
+
# class C
|
13
|
+
# def f
|
14
|
+
# "f"
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# module M
|
19
|
+
# def f
|
20
|
+
# '{' + super + '}'
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# class C
|
25
|
+
# prepend M
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# c = C.new
|
29
|
+
# c.f #=> "{f}"
|
30
|
+
#
|
31
|
+
# This works by overriding Class#new so that all prepended modules
|
32
|
+
# extend new instances of the class upon instantiation.
|
33
|
+
#
|
34
|
+
# If needed the original #new method has been aliased as #init.
|
35
|
+
|
36
|
+
class Class
|
37
|
+
|
38
|
+
#
|
39
|
+
def prepend(*mods)
|
40
|
+
@prepend ||= []
|
41
|
+
@prepend.concat(mods)
|
42
|
+
@prepend
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method :init, :new
|
46
|
+
|
47
|
+
def new(*args, &blk)
|
48
|
+
o = allocate
|
49
|
+
prepend.each do |mod|
|
50
|
+
o.extend(mod)
|
51
|
+
end
|
52
|
+
o.__send__(:initialize, *args, &blk) #if private_method_defined?(:initialize)
|
53
|
+
o
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
data/lib/more/facets/random.rb
CHANGED
@@ -53,7 +53,7 @@ require 'facets/string/shatter'
|
|
53
53
|
module Random
|
54
54
|
|
55
55
|
class << self
|
56
|
-
#
|
56
|
+
# Alias for Kernel#rand.
|
57
57
|
alias_method :number, :rand
|
58
58
|
public :number
|
59
59
|
end
|
@@ -79,6 +79,8 @@ module Random
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
+
#
|
83
|
+
|
82
84
|
module Object
|
83
85
|
|
84
86
|
# Random generator that returns true or false.
|
@@ -106,9 +108,23 @@ module Random
|
|
106
108
|
# (1..4).at_rand #=> 2
|
107
109
|
# (1..4).at_rand #=> 4
|
108
110
|
#
|
111
|
+
# (1.5..2.5).at_rand #=> 2.06309842754533
|
112
|
+
# (1.5..2.5).at_rand #=> 1.74976944931541
|
113
|
+
#
|
114
|
+
# ('a'..'z').at_rand #=> 'q'
|
115
|
+
# ('a'..'z').at_rand #=> 'f'
|
116
|
+
#
|
117
|
+
# CREDIT: Lavir the Whiolet
|
118
|
+
|
109
119
|
def at_rand
|
110
|
-
|
111
|
-
|
120
|
+
if first.respond_to?(:succ)
|
121
|
+
to_a.at_rand
|
122
|
+
elsif Numeric===first && Numeric===last
|
123
|
+
number = (last - first) * Random.number + first
|
124
|
+
(number == last && exclude_end?) ? first : number
|
125
|
+
else
|
126
|
+
nil
|
127
|
+
end
|
112
128
|
end
|
113
129
|
|
114
130
|
end
|
data/lib/more/facets/roman.rb
CHANGED
@@ -1,174 +1,67 @@
|
|
1
|
-
|
2
|
-
# Roman Numerals
|
3
|
-
#
|
4
|
-
# = SYNOPSIS:
|
5
|
-
# Generates roman numerals from integers and vice-versa.
|
6
|
-
#
|
7
|
-
# = NOTES:
|
8
|
-
# A response to Ruby Quiz of the Week #22 - Roman Numerals [ruby-talk:132925]
|
9
|
-
#
|
10
|
-
# = AUTHORS:
|
11
|
-
# - Dave Burt <dave at burt.id.au>
|
12
|
-
# - Trans
|
13
|
-
|
14
|
-
module English #:nodoc:
|
15
|
-
|
16
|
-
# Contains methods to convert integers to roman numeral strings and vice-versa.
|
17
|
-
|
18
|
-
module RomanNumerals
|
19
|
-
|
20
|
-
# The largest integer representable as a roman
|
21
|
-
# numerable by this module.
|
22
|
-
|
23
|
-
MAX = 3999
|
24
|
-
|
25
|
-
# Stolen from O'Reilly's Perl Cookbook 6.23. Regular Expression Grabbag.
|
26
|
-
|
27
|
-
REGEXP = /^M*(D?C{0,3}|C[DM])(L?X{0,3}|X[LC])(V?I{0,3}|I[VX])$/i
|
28
|
-
|
29
|
-
#
|
30
|
-
|
31
|
-
SYMBOLS = [ "M", "D", "C", "L", "X", "V", "I" ]
|
32
|
-
NUMBERS = [ 1000, 500, 100, 50, 10, 5, 1 ]
|
33
|
-
|
34
|
-
|
35
|
-
# Maps roman numeral digits to their integer values.
|
36
|
-
# {
|
37
|
-
# 'I' => 1,
|
38
|
-
# 'V' => 5,
|
39
|
-
# 'X' => 10,
|
40
|
-
# 'L' => 50,
|
41
|
-
# 'C' => 100,
|
42
|
-
# 'D' => 500,
|
43
|
-
# 'M' => 1000,
|
44
|
-
# }
|
45
|
-
|
46
|
-
TABLE = Hash[*SYMBOLS.zip(NUMBERS).flatten]
|
1
|
+
class Integer
|
47
2
|
|
48
3
|
#
|
49
|
-
|
50
|
-
PAIR_SYMBOLS = [ "CM", "CD", "XC", "XL", "IX", "IV", "I" ]
|
51
|
-
PAIR_NUMBERS = [ 900, 400, 90, 40, 9, 4, 1 ]
|
52
|
-
|
53
|
-
# {
|
54
|
-
# 'CM' => 900,
|
55
|
-
# 'CD' => 400,
|
56
|
-
# 'XC' => 90,
|
57
|
-
# 'XL' => 40,
|
58
|
-
# 'IX' => 9,
|
59
|
-
# 'IV' => 4
|
60
|
-
# }
|
61
|
-
|
62
|
-
PAIR_TABLE = Hash[*PAIR_SYMBOLS.zip(PAIR_NUMBERS).flatten]
|
4
|
+
ROMAN_MAX = 3999
|
63
5
|
|
64
6
|
#
|
7
|
+
ROMAN_VALUES = [
|
8
|
+
["M", 1000],
|
9
|
+
["CM", 900],
|
10
|
+
["D", 500],
|
11
|
+
["CD", 400],
|
12
|
+
["C", 100],
|
13
|
+
["XC", 90],
|
14
|
+
["L", 50],
|
15
|
+
["XL", 40],
|
16
|
+
["X", 10],
|
17
|
+
["IX", 9],
|
18
|
+
["V", 5],
|
19
|
+
["IV", 4],
|
20
|
+
["I", 1]
|
21
|
+
]
|
65
22
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
return nil if integer < 0 || integer > MAX
|
75
|
-
|
76
|
-
r = integer # remainder
|
77
|
-
y = '' # result
|
78
|
-
|
79
|
-
NUMBERS.each do |n|
|
80
|
-
while r >= n
|
81
|
-
r -= n
|
82
|
-
y += LOOKUP[n]
|
83
|
-
end
|
84
|
-
break if r <= 0
|
85
|
-
end
|
86
|
-
|
87
|
-
return y
|
88
|
-
end
|
89
|
-
|
90
|
-
alias_method :roman, :from_integer
|
91
|
-
|
92
|
-
# Converts +roman_string+, a roman numeral, to an integer
|
93
|
-
|
94
|
-
def to_integer(roman_string)
|
95
|
-
return nil unless roman_string.is_roman_numeral?
|
96
|
-
|
97
|
-
l = nil # last
|
98
|
-
i = 0 # integer result
|
99
|
-
|
100
|
-
c = roman_string.to_s.upcase.split(//).reverse
|
101
|
-
|
102
|
-
c.each do |d|
|
103
|
-
if v = TABLE[d]
|
104
|
-
if l && l > v
|
105
|
-
i -= v
|
106
|
-
else
|
107
|
-
i += v
|
108
|
-
end
|
109
|
-
l = v
|
110
|
-
end
|
23
|
+
# Converts this integer to a roman numeral.
|
24
|
+
def roman
|
25
|
+
int = self
|
26
|
+
#return nil if integer > ROMAN_MAX
|
27
|
+
return "-#{(-int).roman}" if int < 0
|
28
|
+
return "" if int == 0
|
29
|
+
ROMAN_VALUES.each do |(i, v)|
|
30
|
+
return(i + (int-v).roman) if v <= int
|
111
31
|
end
|
112
|
-
|
113
|
-
return i
|
114
|
-
end
|
115
|
-
|
116
|
-
alias_method :arabic, :to_integer
|
117
|
-
|
118
|
-
# Returns true iif +string+ is a roman numeral.
|
119
|
-
|
120
|
-
def is_roman_numeral?(string)
|
121
|
-
REGEXP =~ string
|
122
|
-
end
|
123
|
-
|
124
32
|
end
|
125
33
|
|
126
34
|
end
|
127
35
|
|
128
|
-
end # module English
|
129
|
-
|
130
36
|
|
131
|
-
class
|
132
|
-
|
133
|
-
def roman
|
134
|
-
English::RomanNumerals.roman(self) || ''
|
135
|
-
end
|
136
|
-
|
137
|
-
# Converts this integer to a roman numeral.
|
138
|
-
|
139
|
-
def to_s_roman
|
140
|
-
English::RomanNumerals.from_integer(self) || ''
|
141
|
-
end
|
142
|
-
|
143
|
-
end
|
37
|
+
class String
|
144
38
|
|
39
|
+
# Taken from O'Reilly's Perl Cookbook 6.23. Regular Expression Grabbag.
|
40
|
+
ROMAN = /^M*(D?C{0,3}|C[DM])(L?X{0,3}|X[LC])(V?I{0,3}|I[VX])$/i
|
145
41
|
|
146
|
-
|
42
|
+
#
|
43
|
+
ROMAN_VALUES = Integer::ROMAN_VALUES.inject({}){ |h,(r,a)| h[r] = a; h }
|
147
44
|
|
148
|
-
# Considers string a
|
45
|
+
# Considers string a Roman numeral numeral,
|
149
46
|
# and converts it to the corresponding integer.
|
150
|
-
|
151
|
-
|
152
|
-
|
47
|
+
def roman
|
48
|
+
roman = self
|
49
|
+
raise unless roman?
|
50
|
+
last = roman[-1,1]
|
51
|
+
roman.reverse.split('').inject(0) do |result, c|
|
52
|
+
if ROMAN_VALUES[c] < ROMAN_VALUES[last]
|
53
|
+
result -= ROMAN_VALUES[c]
|
54
|
+
else
|
55
|
+
last = c
|
56
|
+
result += ROMAN_VALUES[c]
|
57
|
+
end
|
58
|
+
end
|
153
59
|
end
|
154
60
|
|
155
|
-
# Returns true iif the subject is a
|
156
|
-
|
157
|
-
|
158
|
-
English::RomanNumerals.is_roman_numeral?(self)
|
61
|
+
# Returns true iif the subject is a valid Roman numeral.
|
62
|
+
def roman?
|
63
|
+
ROMAN =~ self
|
159
64
|
end
|
160
65
|
|
161
66
|
end
|
162
67
|
|
163
|
-
|
164
|
-
# # Quiz solution: filter that swaps roman and arabic numbers
|
165
|
-
# if __FILE__ == $0
|
166
|
-
# ARGF.each do |line|
|
167
|
-
# line.chomp!
|
168
|
-
# if line.is_roman_numeral?
|
169
|
-
# puts line.to_i_roman
|
170
|
-
# else
|
171
|
-
# puts line.to_i.to_s_roman
|
172
|
-
# end
|
173
|
-
# end
|
174
|
-
# end
|