sleeping_king_studios-tools 0.7.0.beta.0 → 0.8.0
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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +37 -5
- data/DEVELOPMENT.md +5 -7
- data/README.md +27 -64
- data/lib/sleeping_king_studios/tools.rb +12 -6
- data/lib/sleeping_king_studios/tools/all.rb +8 -3
- data/lib/sleeping_king_studios/tools/array_tools.rb +83 -58
- data/lib/sleeping_king_studios/tools/base.rb +18 -0
- data/lib/sleeping_king_studios/tools/core_tools.rb +76 -17
- data/lib/sleeping_king_studios/tools/enumerable_tools.rb +6 -3
- data/lib/sleeping_king_studios/tools/hash_tools.rb +65 -42
- data/lib/sleeping_king_studios/tools/integer_tools.rb +97 -55
- data/lib/sleeping_king_studios/tools/object_tools.rb +67 -50
- data/lib/sleeping_king_studios/tools/string_tools.rb +81 -63
- data/lib/sleeping_king_studios/tools/toolbelt.rb +46 -22
- data/lib/sleeping_king_studios/tools/toolbox.rb +2 -2
- data/lib/sleeping_king_studios/tools/toolbox/configuration.rb +206 -118
- data/lib/sleeping_king_studios/tools/toolbox/constant_map.rb +24 -51
- data/lib/sleeping_king_studios/tools/toolbox/delegator.rb +50 -29
- data/lib/sleeping_king_studios/tools/toolbox/inflector.rb +130 -0
- data/lib/sleeping_king_studios/tools/toolbox/inflector/rules.rb +171 -0
- data/lib/sleeping_king_studios/tools/toolbox/mixin.rb +10 -10
- data/lib/sleeping_king_studios/tools/toolbox/semantic_version.rb +15 -14
- data/lib/sleeping_king_studios/tools/version.rb +7 -9
- metadata +86 -28
- data/lib/sleeping_king_studios/tools/semantic_version.rb +0 -15
- data/lib/sleeping_king_studios/tools/string_tools/plural_inflector.rb +0 -185
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
|
|
5
|
+
require 'sleeping_king_studios/tools'
|
|
6
|
+
|
|
7
|
+
module SleepingKingStudios::Tools
|
|
8
|
+
# Abstract base class for Tools classes.
|
|
9
|
+
class Base
|
|
10
|
+
class << self
|
|
11
|
+
extend Forwardable
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.instance
|
|
15
|
+
@instance ||= new
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -1,11 +1,26 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'sleeping_king_studios/tools'
|
|
4
4
|
|
|
5
5
|
module SleepingKingStudios::Tools
|
|
6
6
|
# Tools for working with an application or working environment.
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
class CoreTools < Base
|
|
8
|
+
class DeprecationError < StandardError; end
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
def_delegators :instance,
|
|
12
|
+
:deprecate,
|
|
13
|
+
:empty_binding,
|
|
14
|
+
:require_each
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def initialize(deprecation_strategy: nil)
|
|
18
|
+
@deprecation_strategy =
|
|
19
|
+
deprecation_strategy || ENV.fetch('DEPRECATION_STRATEGY', 'warn')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [String] The current deprecation strategy.
|
|
23
|
+
attr_reader :deprecation_strategy
|
|
9
24
|
|
|
10
25
|
# @overload deprecate(name, message: nil)
|
|
11
26
|
# Prints a deprecation warning.
|
|
@@ -22,30 +37,74 @@ module SleepingKingStudios::Tools
|
|
|
22
37
|
# @param format [String] The format string.
|
|
23
38
|
# @param message [String] An optional message to print after the formatted
|
|
24
39
|
# string. Defaults to nil.
|
|
25
|
-
def deprecate
|
|
26
|
-
|
|
40
|
+
def deprecate(*args, format: nil, message: nil)
|
|
41
|
+
send(
|
|
42
|
+
:"deprecate_as_#{deprecation_strategy}",
|
|
43
|
+
*args,
|
|
44
|
+
format: format,
|
|
45
|
+
message: message
|
|
46
|
+
)
|
|
47
|
+
end
|
|
27
48
|
|
|
28
|
-
|
|
29
|
-
|
|
49
|
+
# Generates an empty Binding object with a BasicObject as the receiver.
|
|
50
|
+
#
|
|
51
|
+
# @return [Binding] The empty binding object.
|
|
52
|
+
def empty_binding
|
|
53
|
+
context = Object.new
|
|
30
54
|
|
|
31
|
-
|
|
55
|
+
def context.binding
|
|
56
|
+
Kernel.instance_method(:binding).bind(self).call
|
|
57
|
+
end
|
|
32
58
|
|
|
33
|
-
|
|
34
|
-
end
|
|
59
|
+
context.binding
|
|
60
|
+
end
|
|
35
61
|
|
|
36
62
|
# Expands each file pattern and requires each file.
|
|
37
63
|
#
|
|
38
64
|
# @param file_patterns [Array] The files to require.
|
|
39
|
-
def require_each
|
|
65
|
+
def require_each(*file_patterns)
|
|
40
66
|
file_patterns.each do |file_pattern|
|
|
41
67
|
if file_pattern.include?('*')
|
|
42
68
|
Dir[file_pattern].each do |file_name|
|
|
43
69
|
Kernel.require file_name
|
|
44
|
-
end
|
|
70
|
+
end
|
|
45
71
|
else
|
|
46
72
|
Kernel.require file_pattern
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def deprecate_as_ignore(*_args, **_kwargs); end
|
|
80
|
+
|
|
81
|
+
def deprecate_as_raise(*args, format: nil, message: nil)
|
|
82
|
+
format ||= '%s has been deprecated.'
|
|
83
|
+
|
|
84
|
+
str = format % args
|
|
85
|
+
str << ' ' << message if message
|
|
86
|
+
|
|
87
|
+
raise DeprecationError, str, caller(2..-1)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def deprecate_as_warn(*args, format: nil, message: nil)
|
|
91
|
+
format ||= '[WARNING] %s has been deprecated.'
|
|
92
|
+
|
|
93
|
+
str = format % args
|
|
94
|
+
str << ' ' << message if message
|
|
95
|
+
|
|
96
|
+
str << "\n called from #{external_caller}"
|
|
97
|
+
|
|
98
|
+
Kernel.warn str
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def external_caller
|
|
102
|
+
caller.find do |line|
|
|
103
|
+
!(
|
|
104
|
+
line.include?('forwardable.rb') ||
|
|
105
|
+
line.include?('sleeping_king_studios-tools')
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'sleeping_king_studios/tools
|
|
3
|
+
require 'sleeping_king_studios/tools'
|
|
4
|
+
|
|
5
|
+
SleepingKingStudios::Tools::CoreTools
|
|
6
|
+
.deprecate('SleepingKingStudios::Tools::EnumerableTools')
|
|
4
7
|
|
|
5
8
|
module SleepingKingStudios::Tools
|
|
6
9
|
# Alias for ArrayTools to ensure backward compatibility.
|
|
7
10
|
EnumerableTools = ArrayTools
|
|
8
|
-
end
|
|
11
|
+
end
|
|
@@ -1,47 +1,58 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'sleeping_king_studios/tools'
|
|
4
|
-
require 'sleeping_king_studios/tools/array_tools'
|
|
5
|
-
require 'sleeping_king_studios/tools/object_tools'
|
|
6
4
|
|
|
7
5
|
module SleepingKingStudios::Tools
|
|
8
6
|
# Tools for working with hash-like enumerable objects.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
class HashTools < SleepingKingStudios::Tools::Base
|
|
8
|
+
HASH_METHODS = %i[[] count each each_key each_pair].freeze
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
def_delegators :instance,
|
|
12
|
+
:convert_keys_to_strings,
|
|
13
|
+
:convert_keys_to_symbols,
|
|
14
|
+
:deep_dup,
|
|
15
|
+
:deep_freeze,
|
|
16
|
+
:generate_binding,
|
|
17
|
+
:hash?,
|
|
18
|
+
:immutable?,
|
|
19
|
+
:mutable?
|
|
20
|
+
|
|
21
|
+
alias stringify_keys convert_keys_to_strings
|
|
22
|
+
alias symbolize_keys convert_keys_to_symbols
|
|
23
|
+
end
|
|
13
24
|
|
|
14
25
|
# Returns a copy of the hash with the keys converted to strings.
|
|
15
26
|
#
|
|
16
27
|
# @param [Hash] hsh The hash to convert.
|
|
17
28
|
#
|
|
18
29
|
# @return [Hash] The converted copy of the hash.
|
|
19
|
-
def convert_keys_to_strings
|
|
30
|
+
def convert_keys_to_strings(hsh)
|
|
20
31
|
require_hash! hsh
|
|
21
32
|
|
|
22
33
|
hsh.each.with_object({}) do |(key, value), cpy|
|
|
23
34
|
sym = key.to_s
|
|
24
35
|
|
|
25
36
|
cpy[sym] = convert_value_to_stringified_hash(value)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
alias stringify_keys convert_keys_to_strings
|
|
29
40
|
|
|
30
41
|
# Returns a copy of the hash with the keys converted to symbols.
|
|
31
42
|
#
|
|
32
43
|
# @param [Hash] hsh The hash to convert.
|
|
33
44
|
#
|
|
34
45
|
# @return [Hash] The converted copy of the hash.
|
|
35
|
-
def convert_keys_to_symbols
|
|
46
|
+
def convert_keys_to_symbols(hsh)
|
|
36
47
|
require_hash! hsh
|
|
37
48
|
|
|
38
49
|
hsh.each.with_object({}) do |(key, value), cpy|
|
|
39
50
|
sym = key.to_s.intern
|
|
40
51
|
|
|
41
52
|
cpy[sym] = convert_value_to_symbolic_hash(value)
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
alias symbolize_keys convert_keys_to_symbols
|
|
45
56
|
|
|
46
57
|
# Creates a deep copy of the object by returning a new Hash with deep
|
|
47
58
|
# copies of each key and value.
|
|
@@ -49,19 +60,19 @@ module SleepingKingStudios::Tools
|
|
|
49
60
|
# @param [Hash<Object>] hsh The hash to copy.
|
|
50
61
|
#
|
|
51
62
|
# @return [Hash] The copy of the hash.
|
|
52
|
-
def deep_dup
|
|
63
|
+
def deep_dup(hsh)
|
|
53
64
|
require_hash! hsh
|
|
54
65
|
|
|
55
|
-
hsh.each.with_object(
|
|
66
|
+
hsh.each.with_object({}) do |(key, value), copy|
|
|
56
67
|
copy[ObjectTools.deep_dup key] = ObjectTools.deep_dup(value)
|
|
57
|
-
end
|
|
58
|
-
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
59
70
|
|
|
60
71
|
# Freezes the hash and performs a deep freeze on each hash key and
|
|
61
72
|
# value.
|
|
62
73
|
#
|
|
63
74
|
# @param [Hash] hsh The object to freeze.
|
|
64
|
-
def deep_freeze
|
|
75
|
+
def deep_freeze(hsh)
|
|
65
76
|
require_hash! hsh
|
|
66
77
|
|
|
67
78
|
hsh.freeze
|
|
@@ -69,23 +80,33 @@ module SleepingKingStudios::Tools
|
|
|
69
80
|
hsh.each do |key, value|
|
|
70
81
|
ObjectTools.deep_freeze key
|
|
71
82
|
ObjectTools.deep_freeze value
|
|
72
|
-
end
|
|
73
|
-
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def generate_binding(hsh)
|
|
87
|
+
require_hash! hsh
|
|
88
|
+
|
|
89
|
+
CoreTools.empty_binding.tap do |binding|
|
|
90
|
+
hsh.each do |key, value|
|
|
91
|
+
binding.local_variable_set key, value
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
74
95
|
|
|
75
96
|
# Returns true if the object is or appears to be a Hash.
|
|
76
97
|
#
|
|
77
98
|
# @param hsh [Object] The object to test.
|
|
78
99
|
#
|
|
79
100
|
# @return [Boolean] True if the object is a Hash, otherwise false.
|
|
80
|
-
def hash?
|
|
81
|
-
return true if Hash
|
|
101
|
+
def hash?(hsh)
|
|
102
|
+
return true if hsh.is_a?(Hash)
|
|
82
103
|
|
|
83
104
|
HASH_METHODS.each do |method_name|
|
|
84
105
|
return false unless hsh.respond_to?(method_name)
|
|
85
|
-
end
|
|
106
|
+
end
|
|
86
107
|
|
|
87
108
|
true
|
|
88
|
-
end
|
|
109
|
+
end
|
|
89
110
|
|
|
90
111
|
# Returns true if the hash is immutable, i.e. if the hash is frozen and each
|
|
91
112
|
# hash key and hash value are immutable.
|
|
@@ -93,17 +114,19 @@ module SleepingKingStudios::Tools
|
|
|
93
114
|
# @param hsh [Hash] The hash to test.
|
|
94
115
|
#
|
|
95
116
|
# @return [Boolean] True if the hash is immutable, otherwise false.
|
|
96
|
-
def immutable?
|
|
117
|
+
def immutable?(hsh)
|
|
97
118
|
require_hash! hsh
|
|
98
119
|
|
|
99
120
|
return false unless hsh.frozen?
|
|
100
121
|
|
|
101
122
|
hsh.each do |key, value|
|
|
102
|
-
|
|
103
|
-
|
|
123
|
+
unless ObjectTools.immutable?(key) && ObjectTools.immutable?(value)
|
|
124
|
+
return false
|
|
125
|
+
end
|
|
126
|
+
end
|
|
104
127
|
|
|
105
128
|
true
|
|
106
|
-
end
|
|
129
|
+
end
|
|
107
130
|
|
|
108
131
|
# Returns true if the hash is mutable.
|
|
109
132
|
#
|
|
@@ -112,36 +135,36 @@ module SleepingKingStudios::Tools
|
|
|
112
135
|
# @return [Boolean] True if the hash is mutable, otherwise false.
|
|
113
136
|
#
|
|
114
137
|
# @see #immutable?
|
|
115
|
-
def mutable?
|
|
138
|
+
def mutable?(hsh)
|
|
116
139
|
!immutable?(hsh)
|
|
117
|
-
end
|
|
140
|
+
end
|
|
118
141
|
|
|
119
142
|
private
|
|
120
143
|
|
|
121
|
-
def convert_value_to_stringified_hash
|
|
144
|
+
def convert_value_to_stringified_hash(value)
|
|
122
145
|
if hash?(value)
|
|
123
146
|
convert_keys_to_strings(value)
|
|
124
147
|
elsif ArrayTools.array?(value)
|
|
125
148
|
value.map { |item| convert_value_to_stringified_hash(item) }
|
|
126
149
|
else
|
|
127
150
|
value
|
|
128
|
-
end
|
|
129
|
-
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
130
153
|
|
|
131
|
-
def convert_value_to_symbolic_hash
|
|
154
|
+
def convert_value_to_symbolic_hash(value)
|
|
132
155
|
if hash?(value)
|
|
133
156
|
convert_keys_to_symbols(value)
|
|
134
157
|
elsif ArrayTools.array?(value)
|
|
135
158
|
value.map { |item| convert_value_to_symbolic_hash(item) }
|
|
136
159
|
else
|
|
137
160
|
value
|
|
138
|
-
end
|
|
139
|
-
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
140
163
|
|
|
141
|
-
def require_hash!
|
|
164
|
+
def require_hash!(value)
|
|
142
165
|
return if hash?(value)
|
|
143
166
|
|
|
144
167
|
raise ArgumentError, 'argument must be a hash', caller[1..-1]
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
|
-
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -1,19 +1,63 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'sleeping_king_studios/tools'
|
|
4
|
-
require 'sleeping_king_studios/tools/string_tools'
|
|
5
4
|
|
|
6
5
|
module SleepingKingStudios::Tools
|
|
7
6
|
# Tools for working with integers.
|
|
8
|
-
|
|
9
|
-
extend self
|
|
10
|
-
|
|
7
|
+
class IntegerTools < SleepingKingStudios::Tools::Base
|
|
11
8
|
# Minimum integer value that can be converted to a roman numeral.
|
|
12
9
|
ROMANIZE_MIN = 1
|
|
13
10
|
|
|
14
11
|
# Maximum integer value that can be converted to a roman numeral.
|
|
15
12
|
ROMANIZE_MAX = 4999
|
|
16
13
|
|
|
14
|
+
ROMANIZE_NUMERALS = [
|
|
15
|
+
%w[I V X].freeze,
|
|
16
|
+
%w[X L C].freeze,
|
|
17
|
+
%w[C D M].freeze,
|
|
18
|
+
['M', 'MMM', ''].freeze
|
|
19
|
+
].freeze
|
|
20
|
+
private_constant :ROMANIZE_NUMERALS
|
|
21
|
+
|
|
22
|
+
ROMANIZE_RULES = [
|
|
23
|
+
'',
|
|
24
|
+
'1',
|
|
25
|
+
'11',
|
|
26
|
+
'111',
|
|
27
|
+
'15',
|
|
28
|
+
'5',
|
|
29
|
+
'51',
|
|
30
|
+
'511',
|
|
31
|
+
'5111',
|
|
32
|
+
'1a',
|
|
33
|
+
'a'
|
|
34
|
+
].freeze
|
|
35
|
+
private_constant :ROMANIZE_RULES
|
|
36
|
+
|
|
37
|
+
ROMANIZE_RULES_ADDITIVE = [
|
|
38
|
+
'',
|
|
39
|
+
'1',
|
|
40
|
+
'11',
|
|
41
|
+
'111',
|
|
42
|
+
'1111',
|
|
43
|
+
'5',
|
|
44
|
+
'51',
|
|
45
|
+
'511',
|
|
46
|
+
'5111',
|
|
47
|
+
'51111',
|
|
48
|
+
'a'
|
|
49
|
+
].freeze
|
|
50
|
+
private_constant :ROMANIZE_RULES_ADDITIVE
|
|
51
|
+
|
|
52
|
+
class << self
|
|
53
|
+
def_delegators :instance,
|
|
54
|
+
:count_digits,
|
|
55
|
+
:digits,
|
|
56
|
+
:integer?,
|
|
57
|
+
:pluralize,
|
|
58
|
+
:romanize
|
|
59
|
+
end
|
|
60
|
+
|
|
17
61
|
# Returns the number of digits in the given integer when represented in the
|
|
18
62
|
# specified base. Ignores minus sign for negative numbers.
|
|
19
63
|
#
|
|
@@ -38,9 +82,9 @@ module SleepingKingStudios::Tools
|
|
|
38
82
|
# Defaults to 10.
|
|
39
83
|
#
|
|
40
84
|
# @return [Integer] The number of digits.
|
|
41
|
-
def count_digits
|
|
42
|
-
digits(integer.abs, :
|
|
43
|
-
end
|
|
85
|
+
def count_digits(integer, base: 10)
|
|
86
|
+
digits(integer.abs, base: base).count
|
|
87
|
+
end
|
|
44
88
|
|
|
45
89
|
# Decomposes the given integer into its digits when represented in the
|
|
46
90
|
# given base.
|
|
@@ -63,18 +107,18 @@ module SleepingKingStudios::Tools
|
|
|
63
107
|
#
|
|
64
108
|
# @return [Array<String>] The digits of the decomposed integer,
|
|
65
109
|
# represented as a bigendian array of strings.
|
|
66
|
-
def digits
|
|
110
|
+
def digits(integer, base: 10)
|
|
67
111
|
integer.to_s(base).split('')
|
|
68
|
-
end
|
|
112
|
+
end
|
|
69
113
|
|
|
70
114
|
# Returns true if the object is an Integer.
|
|
71
115
|
#
|
|
72
116
|
# @param int [Object] The object to test.
|
|
73
117
|
#
|
|
74
118
|
# @return [Boolean] True if the object is an Integer, otherwise false.
|
|
75
|
-
def integer?
|
|
76
|
-
Integer
|
|
77
|
-
end
|
|
119
|
+
def integer?(int)
|
|
120
|
+
int.is_a?(Integer)
|
|
121
|
+
end
|
|
78
122
|
|
|
79
123
|
# Returns the singular or the plural value, depending on the provided
|
|
80
124
|
# item count.
|
|
@@ -89,11 +133,11 @@ module SleepingKingStudios::Tools
|
|
|
89
133
|
#
|
|
90
134
|
# @return [String] The single form if count == 1; otherwise the plural
|
|
91
135
|
# form.
|
|
92
|
-
def pluralize
|
|
136
|
+
def pluralize(count, single, plural = nil)
|
|
93
137
|
plural ||= StringTools.pluralize(single)
|
|
94
138
|
|
|
95
|
-
|
|
96
|
-
end
|
|
139
|
+
count == 1 ? single : plural
|
|
140
|
+
end
|
|
97
141
|
|
|
98
142
|
# Represents an integer between 1 and 4999 (inclusive) as a Roman numeral.
|
|
99
143
|
#
|
|
@@ -114,42 +158,40 @@ module SleepingKingStudios::Tools
|
|
|
114
158
|
# @return [String] The representation of the integer as a Roman numeral.
|
|
115
159
|
#
|
|
116
160
|
# @raise [RangeError] If the integer is less than 1 or greater than 4999.
|
|
117
|
-
def romanize
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
'
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
]
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
end # module
|
|
155
|
-
end # module
|
|
161
|
+
def romanize(integer, additive: false)
|
|
162
|
+
check_romanize_range(integer)
|
|
163
|
+
|
|
164
|
+
digits(integer)
|
|
165
|
+
.reverse
|
|
166
|
+
.map
|
|
167
|
+
.with_index do |digit, index|
|
|
168
|
+
romanize_digit(additive: additive, digit: digit.to_i, tens: index)
|
|
169
|
+
end
|
|
170
|
+
.reverse
|
|
171
|
+
.join ''
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
private
|
|
175
|
+
|
|
176
|
+
def check_romanize_range(integer)
|
|
177
|
+
return if (ROMANIZE_MIN..ROMANIZE_MAX).include?(integer)
|
|
178
|
+
|
|
179
|
+
error_message =
|
|
180
|
+
"integer to romanize must be within range #{ROMANIZE_MIN} to" \
|
|
181
|
+
" #{ROMANIZE_MAX}"
|
|
182
|
+
|
|
183
|
+
raise RangeError, error_message, caller(1..-1)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def romanize_digit(additive:, digit:, tens:)
|
|
187
|
+
rules = (additive ? ROMANIZE_RULES_ADDITIVE : ROMANIZE_RULES)
|
|
188
|
+
rule = rules[digit]
|
|
189
|
+
numerals = ROMANIZE_NUMERALS[tens]
|
|
190
|
+
|
|
191
|
+
rule
|
|
192
|
+
.gsub('1', numerals[0])
|
|
193
|
+
.gsub('5', numerals[1])
|
|
194
|
+
.gsub('a', numerals[2])
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|