sleeping_king_studios-tools 0.7.1 → 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.
Files changed (27) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +32 -3
  3. data/DEVELOPMENT.md +5 -7
  4. data/README.md +3 -64
  5. data/lib/sleeping_king_studios/tools.rb +12 -6
  6. data/lib/sleeping_king_studios/tools/all.rb +8 -3
  7. data/lib/sleeping_king_studios/tools/array_tools.rb +83 -58
  8. data/lib/sleeping_king_studios/tools/base.rb +18 -0
  9. data/lib/sleeping_king_studios/tools/core_tools.rb +68 -22
  10. data/lib/sleeping_king_studios/tools/enumerable_tools.rb +6 -3
  11. data/lib/sleeping_king_studios/tools/hash_tools.rb +59 -47
  12. data/lib/sleeping_king_studios/tools/integer_tools.rb +97 -55
  13. data/lib/sleeping_king_studios/tools/object_tools.rb +67 -50
  14. data/lib/sleeping_king_studios/tools/string_tools.rb +81 -63
  15. data/lib/sleeping_king_studios/tools/toolbelt.rb +46 -22
  16. data/lib/sleeping_king_studios/tools/toolbox.rb +2 -2
  17. data/lib/sleeping_king_studios/tools/toolbox/configuration.rb +197 -122
  18. data/lib/sleeping_king_studios/tools/toolbox/constant_map.rb +24 -51
  19. data/lib/sleeping_king_studios/tools/toolbox/delegator.rb +50 -29
  20. data/lib/sleeping_king_studios/tools/toolbox/inflector.rb +130 -0
  21. data/lib/sleeping_king_studios/tools/toolbox/inflector/rules.rb +171 -0
  22. data/lib/sleeping_king_studios/tools/toolbox/mixin.rb +10 -10
  23. data/lib/sleeping_king_studios/tools/toolbox/semantic_version.rb +15 -14
  24. data/lib/sleeping_king_studios/tools/version.rb +6 -8
  25. metadata +84 -26
  26. data/lib/sleeping_king_studios/tools/semantic_version.rb +0 -15
  27. 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
- # lib/sleeping_king_studios/tools/core_tools.rb
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
- module CoreTools
8
- extend self
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,16 +37,14 @@ 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 *args, format: nil, message: nil
26
- format ||= "[WARNING] %s has been deprecated."
27
-
28
- str = format % args
29
- str << ' ' << message if message
30
-
31
- str << "\n called from #{caller[1]}"
32
-
33
- Kernel.warn str
34
- end # method deprecate
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
35
48
 
36
49
  # Generates an empty Binding object with a BasicObject as the receiver.
37
50
  #
@@ -41,24 +54,57 @@ module SleepingKingStudios::Tools
41
54
 
42
55
  def context.binding
43
56
  Kernel.instance_method(:binding).bind(self).call
44
- end # singleton method binding
57
+ end
45
58
 
46
59
  context.binding
47
- end # method empty_binding
60
+ end
48
61
 
49
62
  # Expands each file pattern and requires each file.
50
63
  #
51
64
  # @param file_patterns [Array] The files to require.
52
- def require_each *file_patterns
65
+ def require_each(*file_patterns)
53
66
  file_patterns.each do |file_pattern|
54
67
  if file_pattern.include?('*')
55
68
  Dir[file_pattern].each do |file_name|
56
69
  Kernel.require file_name
57
- end # each
70
+ end
58
71
  else
59
72
  Kernel.require file_pattern
60
- end # unless
61
- end # each
62
- end # method require_each
63
- end # module
64
- end # module
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
- # lib/sleeping_king_studios/tools/enumerable_tools.rb
1
+ # frozen_string_literal: true
2
2
 
3
- require 'sleeping_king_studios/tools/array_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 # module
11
+ end
@@ -1,48 +1,58 @@
1
- # lib/sleeping_king_studios/tools/hash_tools.rb
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/core_tools'
6
- require 'sleeping_king_studios/tools/object_tools'
7
4
 
8
5
  module SleepingKingStudios::Tools
9
6
  # Tools for working with hash-like enumerable objects.
10
- module HashTools
11
- extend self
12
-
13
- HASH_METHODS = [:[], :count, :each, :each_key, :each_pair].freeze
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
14
24
 
15
25
  # Returns a copy of the hash with the keys converted to strings.
16
26
  #
17
27
  # @param [Hash] hsh The hash to convert.
18
28
  #
19
29
  # @return [Hash] The converted copy of the hash.
20
- def convert_keys_to_strings hsh
30
+ def convert_keys_to_strings(hsh)
21
31
  require_hash! hsh
22
32
 
23
33
  hsh.each.with_object({}) do |(key, value), cpy|
24
34
  sym = key.to_s
25
35
 
26
36
  cpy[sym] = convert_value_to_stringified_hash(value)
27
- end # each
28
- end # method convert_keys_to_strings
29
- alias_method :stringify_keys, :convert_keys_to_strings
37
+ end
38
+ end
39
+ alias stringify_keys convert_keys_to_strings
30
40
 
31
41
  # Returns a copy of the hash with the keys converted to symbols.
32
42
  #
33
43
  # @param [Hash] hsh The hash to convert.
34
44
  #
35
45
  # @return [Hash] The converted copy of the hash.
36
- def convert_keys_to_symbols hsh
46
+ def convert_keys_to_symbols(hsh)
37
47
  require_hash! hsh
38
48
 
39
49
  hsh.each.with_object({}) do |(key, value), cpy|
40
50
  sym = key.to_s.intern
41
51
 
42
52
  cpy[sym] = convert_value_to_symbolic_hash(value)
43
- end # each
44
- end # method convert_keys_to_symbols
45
- alias_method :symbolize_keys, :convert_keys_to_symbols
53
+ end
54
+ end
55
+ alias symbolize_keys convert_keys_to_symbols
46
56
 
47
57
  # Creates a deep copy of the object by returning a new Hash with deep
48
58
  # copies of each key and value.
@@ -50,19 +60,19 @@ module SleepingKingStudios::Tools
50
60
  # @param [Hash<Object>] hsh The hash to copy.
51
61
  #
52
62
  # @return [Hash] The copy of the hash.
53
- def deep_dup hsh
63
+ def deep_dup(hsh)
54
64
  require_hash! hsh
55
65
 
56
- hsh.each.with_object(Hash.new) do |(key, value), copy|
66
+ hsh.each.with_object({}) do |(key, value), copy|
57
67
  copy[ObjectTools.deep_dup key] = ObjectTools.deep_dup(value)
58
- end # each
59
- end # method deep_dup
68
+ end
69
+ end
60
70
 
61
71
  # Freezes the hash and performs a deep freeze on each hash key and
62
72
  # value.
63
73
  #
64
74
  # @param [Hash] hsh The object to freeze.
65
- def deep_freeze hsh
75
+ def deep_freeze(hsh)
66
76
  require_hash! hsh
67
77
 
68
78
  hsh.freeze
@@ -70,33 +80,33 @@ module SleepingKingStudios::Tools
70
80
  hsh.each do |key, value|
71
81
  ObjectTools.deep_freeze key
72
82
  ObjectTools.deep_freeze value
73
- end # each
74
- end # method deep_freeze
83
+ end
84
+ end
75
85
 
76
- def generate_binding hsh
86
+ def generate_binding(hsh)
77
87
  require_hash! hsh
78
88
 
79
89
  CoreTools.empty_binding.tap do |binding|
80
90
  hsh.each do |key, value|
81
91
  binding.local_variable_set key, value
82
- end # each
83
- end # tap
84
- end # method generate_binding
92
+ end
93
+ end
94
+ end
85
95
 
86
96
  # Returns true if the object is or appears to be a Hash.
87
97
  #
88
98
  # @param hsh [Object] The object to test.
89
99
  #
90
100
  # @return [Boolean] True if the object is a Hash, otherwise false.
91
- def hash? hsh
92
- return true if Hash === hsh
101
+ def hash?(hsh)
102
+ return true if hsh.is_a?(Hash)
93
103
 
94
104
  HASH_METHODS.each do |method_name|
95
105
  return false unless hsh.respond_to?(method_name)
96
- end # each
106
+ end
97
107
 
98
108
  true
99
- end # method hash?
109
+ end
100
110
 
101
111
  # Returns true if the hash is immutable, i.e. if the hash is frozen and each
102
112
  # hash key and hash value are immutable.
@@ -104,17 +114,19 @@ module SleepingKingStudios::Tools
104
114
  # @param hsh [Hash] The hash to test.
105
115
  #
106
116
  # @return [Boolean] True if the hash is immutable, otherwise false.
107
- def immutable? hsh
117
+ def immutable?(hsh)
108
118
  require_hash! hsh
109
119
 
110
120
  return false unless hsh.frozen?
111
121
 
112
122
  hsh.each do |key, value|
113
- return false unless ObjectTools.immutable?(key) && ObjectTools.immutable?(value)
114
- end # each
123
+ unless ObjectTools.immutable?(key) && ObjectTools.immutable?(value)
124
+ return false
125
+ end
126
+ end
115
127
 
116
128
  true
117
- end # method immutable
129
+ end
118
130
 
119
131
  # Returns true if the hash is mutable.
120
132
  #
@@ -123,36 +135,36 @@ module SleepingKingStudios::Tools
123
135
  # @return [Boolean] True if the hash is mutable, otherwise false.
124
136
  #
125
137
  # @see #immutable?
126
- def mutable? hsh
138
+ def mutable?(hsh)
127
139
  !immutable?(hsh)
128
- end # method mutable?
140
+ end
129
141
 
130
142
  private
131
143
 
132
- def convert_value_to_stringified_hash value
144
+ def convert_value_to_stringified_hash(value)
133
145
  if hash?(value)
134
146
  convert_keys_to_strings(value)
135
147
  elsif ArrayTools.array?(value)
136
148
  value.map { |item| convert_value_to_stringified_hash(item) }
137
149
  else
138
150
  value
139
- end # if-else
140
- end # method convert_value_to_stringified_hash
151
+ end
152
+ end
141
153
 
142
- def convert_value_to_symbolic_hash value
154
+ def convert_value_to_symbolic_hash(value)
143
155
  if hash?(value)
144
156
  convert_keys_to_symbols(value)
145
157
  elsif ArrayTools.array?(value)
146
158
  value.map { |item| convert_value_to_symbolic_hash(item) }
147
159
  else
148
160
  value
149
- end # if-else
150
- end # method convert_value_to_symbolic_hash
161
+ end
162
+ end
151
163
 
152
- def require_hash! value
164
+ def require_hash!(value)
153
165
  return if hash?(value)
154
166
 
155
167
  raise ArgumentError, 'argument must be a hash', caller[1..-1]
156
- end # method require_array
157
- end # module
158
- end # module
168
+ end
169
+ end
170
+ end
@@ -1,19 +1,63 @@
1
- # lib/sleeping_king_studios/tools/integer_tools.rb
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
- module IntegerTools
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 integer, base: 10
42
- digits(integer.abs, :base => base).count
43
- end # method count_digits
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 integer, base: 10
110
+ def digits(integer, base: 10)
67
111
  integer.to_s(base).split('')
68
- end # method digits
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? int
76
- Integer === int
77
- end # method integer?
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 count, single, plural = nil
136
+ def pluralize(count, single, plural = nil)
93
137
  plural ||= StringTools.pluralize(single)
94
138
 
95
- 1 == count ? single : plural
96
- end # method pluralize
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 integer, additive: false
118
- # Validate input value.
119
- unless (ROMANIZE_MIN..ROMANIZE_MAX).include? integer
120
- raise RangeError.new "integer to romanize must be within range #{ROMANIZE_MIN} to #{ROMANIZE_MAX}"
121
- end # unless
122
-
123
- # Define conversion rules.
124
- rules = [
125
- '',
126
- '%one',
127
- '%one%one',
128
- '%one%one%one',
129
- additive ? '%one%one%one%one' : '%one%five',
130
- '%five',
131
- '%five%one',
132
- '%five%one%one',
133
- '%five%one%one%one',
134
- additive ? '%five%one%one%one%one' : '%one%ten',
135
- '%ten'
136
- ] # end array
137
-
138
- # Define numeral values.
139
- numerals = [
140
- %w(I V X),
141
- %w(X L C),
142
- %w(C D M),
143
- ['M', 'MMM', '']
144
- ] # end array numerals
145
-
146
- # Generate string representation.
147
- digits(integer).reverse.map.with_index do |digit, index|
148
- rules[digit.to_i]
149
- .gsub('%one', numerals[index][0])
150
- .gsub('%five', numerals[index][1])
151
- .gsub('%ten', numerals[index][2])
152
- end.reverse.join ''
153
- end # method romanize
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