sleeping_king_studios-tools 0.7.0 → 1.0.2
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 +54 -3
- data/CODE_OF_CONDUCT.md +132 -0
- data/DEVELOPMENT.md +7 -16
- data/LICENSE +1 -1
- data/README.md +71 -145
- data/lib/sleeping_king_studios/tools.rb +12 -6
- data/lib/sleeping_king_studios/tools/array_tools.rb +86 -58
- data/lib/sleeping_king_studios/tools/base.rb +20 -0
- data/lib/sleeping_king_studios/tools/core_tools.rb +78 -19
- data/lib/sleeping_king_studios/tools/hash_tools.rb +69 -42
- data/lib/sleeping_king_studios/tools/integer_tools.rb +97 -55
- data/lib/sleeping_king_studios/tools/object_tools.rb +75 -52
- data/lib/sleeping_king_studios/tools/string_tools.rb +69 -96
- data/lib/sleeping_king_studios/tools/toolbelt.rb +44 -23
- data/lib/sleeping_king_studios/tools/toolbox.rb +2 -2
- data/lib/sleeping_king_studios/tools/toolbox/constant_map.rb +75 -74
- data/lib/sleeping_king_studios/tools/toolbox/inflector.rb +124 -0
- data/lib/sleeping_king_studios/tools/toolbox/inflector/rules.rb +173 -0
- data/lib/sleeping_king_studios/tools/toolbox/mixin.rb +11 -11
- data/lib/sleeping_king_studios/tools/toolbox/semantic_version.rb +15 -14
- data/lib/sleeping_king_studios/tools/version.rb +14 -10
- metadata +106 -35
- data/lib/sleeping_king_studios/tools/all.rb +0 -5
- data/lib/sleeping_king_studios/tools/enumerable_tools.rb +0 -8
- data/lib/sleeping_king_studios/tools/semantic_version.rb +0 -15
- data/lib/sleeping_king_studios/tools/string_tools/plural_inflector.rb +0 -185
- data/lib/sleeping_king_studios/tools/toolbox/configuration.rb +0 -207
- data/lib/sleeping_king_studios/tools/toolbox/delegator.rb +0 -175
@@ -1,12 +1,18 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Hic iacet Arthurus, rex quondam, rexque futurus.
|
4
4
|
module SleepingKingStudios
|
5
5
|
# A library of utility services and concerns to expand the functionality of
|
6
6
|
# core classes without polluting the global namespace.
|
7
7
|
module Tools
|
8
|
-
autoload :
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
autoload :Base, 'sleeping_king_studios/tools/base'
|
9
|
+
autoload :ArrayTools, 'sleeping_king_studios/tools/array_tools'
|
10
|
+
autoload :CoreTools, 'sleeping_king_studios/tools/core_tools'
|
11
|
+
autoload :HashTools, 'sleeping_king_studios/tools/hash_tools'
|
12
|
+
autoload :IntegerTools, 'sleeping_king_studios/tools/integer_tools'
|
13
|
+
autoload :ObjectTools, 'sleeping_king_studios/tools/object_tools'
|
14
|
+
autoload :StringTools, 'sleeping_king_studios/tools/string_tools'
|
15
|
+
autoload :Toolbelt, 'sleeping_king_studios/tools/toolbelt'
|
16
|
+
autoload :Version, 'sleeping_king_studios/tools/version'
|
17
|
+
end
|
18
|
+
end
|
@@ -1,34 +1,48 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'sleeping_king_studios/tools'
|
4
|
-
require 'sleeping_king_studios/tools/object_tools'
|
5
4
|
|
6
5
|
module SleepingKingStudios::Tools
|
7
6
|
# Tools for working with array-like enumerable objects.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
class ArrayTools < SleepingKingStudios::Tools::Base
|
8
|
+
# Expected methods that an Array-like object should implement.
|
9
|
+
ARRAY_METHODS = %i[[] count each].freeze
|
10
|
+
|
11
|
+
# Methods that an Array-like object should *not* implement.
|
12
|
+
OTHER_METHODS = %i[each_key each_pair].freeze
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def_delegators :instance,
|
16
|
+
:array?,
|
17
|
+
:bisect,
|
18
|
+
:count_values,
|
19
|
+
:deep_dup,
|
20
|
+
:deep_freeze,
|
21
|
+
:humanize_list,
|
22
|
+
:immutable?,
|
23
|
+
:mutable?,
|
24
|
+
:splice,
|
25
|
+
:tally
|
26
|
+
end
|
13
27
|
|
14
28
|
# Returns true if the object is or appears to be an Array.
|
15
29
|
#
|
16
30
|
# @param ary [Object] The object to test.
|
17
31
|
#
|
18
32
|
# @return [Boolean] True if the object is an Array, otherwise false.
|
19
|
-
def array?
|
20
|
-
return true if Array
|
33
|
+
def array?(ary)
|
34
|
+
return true if ary.is_a?(Array)
|
21
35
|
|
22
36
|
ARRAY_METHODS.each do |method_name|
|
23
37
|
return false unless ary.respond_to?(method_name)
|
24
|
-
end
|
38
|
+
end
|
25
39
|
|
26
40
|
OTHER_METHODS.each do |method_name|
|
27
41
|
return false if ary.respond_to?(method_name)
|
28
|
-
end
|
42
|
+
end
|
29
43
|
|
30
44
|
true
|
31
|
-
end
|
45
|
+
end
|
32
46
|
|
33
47
|
# Separates the array into two arrays, the first containing all items in the
|
34
48
|
# original array that matches the provided block, and the second containing
|
@@ -52,19 +66,20 @@ module SleepingKingStudios::Tools
|
|
52
66
|
# if no block is given.
|
53
67
|
#
|
54
68
|
# @return [Array<Array<Object>>] An array containing two arrays.
|
55
|
-
def bisect
|
69
|
+
def bisect(ary)
|
56
70
|
require_array! ary
|
57
71
|
|
58
|
-
raise ArgumentError
|
72
|
+
raise ArgumentError, 'no block given' unless block_given?
|
59
73
|
|
60
|
-
selected
|
74
|
+
selected = []
|
75
|
+
rejected = []
|
61
76
|
|
62
77
|
ary.each do |item|
|
63
78
|
(yield(item) ? selected : rejected) << item
|
64
|
-
end
|
79
|
+
end
|
65
80
|
|
66
81
|
[selected, rejected]
|
67
|
-
end
|
82
|
+
end
|
68
83
|
|
69
84
|
# @overload count_values(ary)
|
70
85
|
# Counts the number of times each value appears in the enumerable object.
|
@@ -96,15 +111,16 @@ module SleepingKingStudios::Tools
|
|
96
111
|
#
|
97
112
|
# @return [Hash{Object, Integer}] The number of times each result
|
98
113
|
# appears.
|
99
|
-
def count_values
|
114
|
+
def count_values(ary, &block)
|
100
115
|
require_array! ary
|
101
116
|
|
102
117
|
ary.each.with_object({}) do |item, hsh|
|
103
118
|
value = block_given? ? block.call(item) : item
|
104
119
|
|
105
120
|
hsh[value] = hsh.fetch(value, 0) + 1
|
106
|
-
end
|
107
|
-
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
alias tally count_values
|
108
124
|
|
109
125
|
# Creates a deep copy of the object by returning a new Array with deep
|
110
126
|
# copies of each array item.
|
@@ -112,22 +128,22 @@ module SleepingKingStudios::Tools
|
|
112
128
|
# @param [Array<Object>] ary The array to copy.
|
113
129
|
#
|
114
130
|
# @return [Array] The copy of the array.
|
115
|
-
def deep_dup
|
131
|
+
def deep_dup(ary)
|
116
132
|
require_array! ary
|
117
133
|
|
118
134
|
ary.map { |obj| ObjectTools.deep_dup obj }
|
119
|
-
end
|
135
|
+
end
|
120
136
|
|
121
137
|
# Freezes the array and performs a deep freeze on each array item.
|
122
138
|
#
|
123
139
|
# @param [Array] ary The object to freeze.
|
124
|
-
def deep_freeze
|
140
|
+
def deep_freeze(ary)
|
125
141
|
require_array! ary
|
126
142
|
|
127
143
|
ary.freeze
|
128
144
|
|
129
145
|
ary.each { |obj| ObjectTools.deep_freeze obj }
|
130
|
-
end
|
146
|
+
end
|
131
147
|
|
132
148
|
# Accepts a list of values and returns a human-readable string of the
|
133
149
|
# values, with the format based on the number of items.
|
@@ -149,7 +165,10 @@ module SleepingKingStudios::Tools
|
|
149
165
|
# #=> 'spam, eggs, bacon, and spam'
|
150
166
|
#
|
151
167
|
# @example With Three Or More Items And Options
|
152
|
-
# ArrayTools.humanize_list(
|
168
|
+
# ArrayTools.humanize_list(
|
169
|
+
# ['spam', 'eggs', 'bacon', 'spam'],
|
170
|
+
# :last_separator => ' or '
|
171
|
+
# )
|
153
172
|
# #=> 'spam, eggs, bacon, or spam'
|
154
173
|
#
|
155
174
|
# @param [Array<String>] ary The list of values to format. Will be
|
@@ -166,31 +185,23 @@ module SleepingKingStudios::Tools
|
|
166
185
|
# @raise ArgumentError If the first argument is not an Array-like object.
|
167
186
|
#
|
168
187
|
# @return [String] The formatted string.
|
169
|
-
def humanize_list
|
188
|
+
def humanize_list(ary, **options, &block)
|
170
189
|
require_array! ary
|
171
190
|
|
172
|
-
|
191
|
+
return '' if ary.empty?
|
173
192
|
|
174
|
-
|
175
|
-
|
193
|
+
size = ary.size
|
194
|
+
ary = ary.map(&block) if block_given?
|
176
195
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
"#{ary[0]}#{last_separator}#{ary[1]}"
|
184
|
-
else
|
185
|
-
if last_separator =~ /\A,?\s*/
|
186
|
-
last_separator = last_separator.sub /\A,?\s*/, separator
|
187
|
-
else
|
188
|
-
last_separator = "#{separator}#{last_separator}"
|
189
|
-
end # if-else
|
196
|
+
return ary[0].to_s if size == 1
|
197
|
+
|
198
|
+
separator, last_separator =
|
199
|
+
options_for_humanize_list(size: size, **options)
|
200
|
+
|
201
|
+
return "#{ary[0]}#{last_separator}#{ary[1]}" if size == 2
|
190
202
|
|
191
|
-
|
192
|
-
|
193
|
-
end # method humanize_list
|
203
|
+
"#{ary[0...-1].join(separator)}#{last_separator}#{ary.last}"
|
204
|
+
end
|
194
205
|
|
195
206
|
# Returns true if the array is immutable, i.e. the array is frozen and each
|
196
207
|
# array item is immutable.
|
@@ -200,7 +211,7 @@ module SleepingKingStudios::Tools
|
|
200
211
|
# @return [Boolean] True if the array is immutable, otherwise false.
|
201
212
|
#
|
202
213
|
# @see ObjectTools#immutable?
|
203
|
-
def immutable?
|
214
|
+
def immutable?(ary)
|
204
215
|
require_array! ary
|
205
216
|
|
206
217
|
return false unless ary.frozen?
|
@@ -208,7 +219,7 @@ module SleepingKingStudios::Tools
|
|
208
219
|
ary.each { |item| return false unless ObjectTools.immutable?(item) }
|
209
220
|
|
210
221
|
true
|
211
|
-
end
|
222
|
+
end
|
212
223
|
|
213
224
|
# Returns true if the array is mutable.
|
214
225
|
#
|
@@ -217,9 +228,9 @@ module SleepingKingStudios::Tools
|
|
217
228
|
# @return [Boolean] True if the array is mutable, otherwise false.
|
218
229
|
#
|
219
230
|
# @see #immutable?
|
220
|
-
def mutable?
|
231
|
+
def mutable?(ary)
|
221
232
|
!immutable?(ary)
|
222
|
-
end
|
233
|
+
end
|
223
234
|
|
224
235
|
# Accepts an array, a start value, a number of items to delete, and zero or
|
225
236
|
# more items to insert at that index. Deletes the specified number of items,
|
@@ -235,10 +246,10 @@ module SleepingKingStudios::Tools
|
|
235
246
|
#
|
236
247
|
# @example Inserting items into an Array
|
237
248
|
# values = %w(longsword broadsword claymore)
|
238
|
-
# ArrayTools.splice values, 1, 0, '
|
249
|
+
# ArrayTools.splice values, 1, 0, 'zweihander'
|
239
250
|
# #=> []
|
240
251
|
# values
|
241
|
-
# #=> ['longsword', '
|
252
|
+
# #=> ['longsword', 'zweihander', 'broadsword', 'claymore']
|
242
253
|
#
|
243
254
|
# @example Inserting and deleting items
|
244
255
|
# values = %w(shortbow longbow crossbow)
|
@@ -257,24 +268,41 @@ module SleepingKingStudios::Tools
|
|
257
268
|
#
|
258
269
|
# @return [Array<Object>] The deleted items, or an empty array if no items
|
259
270
|
# were deleted.
|
260
|
-
def splice
|
271
|
+
def splice(ary, start, delete_count, *insert)
|
261
272
|
require_array! ary
|
262
273
|
|
263
|
-
start = start
|
274
|
+
start = start.negative? ? start + ary.count : start
|
264
275
|
range = start...(start + delete_count)
|
265
276
|
deleted = ary[range]
|
266
277
|
|
267
278
|
ary[range] = insert
|
268
279
|
|
269
280
|
deleted
|
270
|
-
end
|
281
|
+
end
|
271
282
|
|
272
283
|
private
|
273
284
|
|
274
|
-
def
|
285
|
+
def options_for_humanize_list(
|
286
|
+
size:,
|
287
|
+
last_separator: ' and ',
|
288
|
+
separator: ', '
|
289
|
+
)
|
290
|
+
return [separator, last_separator] if size < 3
|
291
|
+
|
292
|
+
last_separator =
|
293
|
+
if last_separator =~ /\A,?\s*/
|
294
|
+
last_separator.sub(/\A,?\s*/, separator)
|
295
|
+
else
|
296
|
+
"#{separator}#{last_separator}"
|
297
|
+
end
|
298
|
+
|
299
|
+
[separator, last_separator]
|
300
|
+
end
|
301
|
+
|
302
|
+
def require_array!(value)
|
275
303
|
return if array?(value)
|
276
304
|
|
277
305
|
raise ArgumentError, 'argument must be an array', caller[1..-1]
|
278
|
-
end
|
279
|
-
end
|
280
|
-
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
@@ -0,0 +1,20 @@
|
|
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
|
+
# @return [SleepingKingStudios::Tools::Base] a memoized instance of the
|
15
|
+
# tools class.
|
16
|
+
def self.instance
|
17
|
+
@instance ||= new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,11 +1,32 @@
|
|
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
|
+
# Exception class used when deprecated code is called and the deprecation
|
9
|
+
# strategy is 'raise'.
|
10
|
+
class DeprecationError < StandardError; end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def_delegators :instance,
|
14
|
+
:deprecate,
|
15
|
+
:empty_binding,
|
16
|
+
:require_each
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param deprecation_strategy [String] The name of the strategy used when
|
20
|
+
# deprecated code is called. Must be 'ignore', 'raise', or 'warn'.
|
21
|
+
def initialize(deprecation_strategy: nil)
|
22
|
+
super()
|
23
|
+
|
24
|
+
@deprecation_strategy =
|
25
|
+
deprecation_strategy || ENV.fetch('DEPRECATION_STRATEGY', 'warn')
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [String] The current deprecation strategy.
|
29
|
+
attr_reader :deprecation_strategy
|
9
30
|
|
10
31
|
# @overload deprecate(name, message: nil)
|
11
32
|
# Prints a deprecation warning.
|
@@ -22,30 +43,68 @@ module SleepingKingStudios::Tools
|
|
22
43
|
# @param format [String] The format string.
|
23
44
|
# @param message [String] An optional message to print after the formatted
|
24
45
|
# string. Defaults to nil.
|
25
|
-
def deprecate
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
46
|
+
def deprecate(*args, format: nil, message: nil)
|
47
|
+
send(
|
48
|
+
:"deprecate_as_#{deprecation_strategy}",
|
49
|
+
*args,
|
50
|
+
format: format,
|
51
|
+
message: message
|
52
|
+
)
|
53
|
+
end
|
30
54
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
55
|
+
# Generates an empty Binding object with an Object as the receiver.
|
56
|
+
#
|
57
|
+
# @return [Binding] The empty binding object.
|
58
|
+
def empty_binding
|
59
|
+
Object.new.instance_exec { 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,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
|
+
# Expected methods that a Hash-like object should implement.
|
9
|
+
HASH_METHODS = %i[[] count each each_key each_pair].freeze
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def_delegators :instance,
|
13
|
+
:convert_keys_to_strings,
|
14
|
+
:convert_keys_to_symbols,
|
15
|
+
:deep_dup,
|
16
|
+
:deep_freeze,
|
17
|
+
:generate_binding,
|
18
|
+
:hash?,
|
19
|
+
:immutable?,
|
20
|
+
:mutable?,
|
21
|
+
:stringify_keys,
|
22
|
+
:symbolize_keys
|
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,37 @@ 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
|
+
# Generates a Binding object with an Object as the receiver and the hash
|
87
|
+
# key-value pairs set as local variables.
|
88
|
+
#
|
89
|
+
# @return [Binding] The binding object.
|
90
|
+
def generate_binding(hsh)
|
91
|
+
require_hash! hsh
|
92
|
+
|
93
|
+
CoreTools.empty_binding.tap do |binding|
|
94
|
+
hsh.each do |key, value|
|
95
|
+
binding.local_variable_set key, value
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
74
99
|
|
75
100
|
# Returns true if the object is or appears to be a Hash.
|
76
101
|
#
|
77
102
|
# @param hsh [Object] The object to test.
|
78
103
|
#
|
79
104
|
# @return [Boolean] True if the object is a Hash, otherwise false.
|
80
|
-
def hash?
|
81
|
-
return true if Hash
|
105
|
+
def hash?(hsh)
|
106
|
+
return true if hsh.is_a?(Hash)
|
82
107
|
|
83
108
|
HASH_METHODS.each do |method_name|
|
84
109
|
return false unless hsh.respond_to?(method_name)
|
85
|
-
end
|
110
|
+
end
|
86
111
|
|
87
112
|
true
|
88
|
-
end
|
113
|
+
end
|
89
114
|
|
90
115
|
# Returns true if the hash is immutable, i.e. if the hash is frozen and each
|
91
116
|
# hash key and hash value are immutable.
|
@@ -93,17 +118,19 @@ module SleepingKingStudios::Tools
|
|
93
118
|
# @param hsh [Hash] The hash to test.
|
94
119
|
#
|
95
120
|
# @return [Boolean] True if the hash is immutable, otherwise false.
|
96
|
-
def immutable?
|
121
|
+
def immutable?(hsh)
|
97
122
|
require_hash! hsh
|
98
123
|
|
99
124
|
return false unless hsh.frozen?
|
100
125
|
|
101
126
|
hsh.each do |key, value|
|
102
|
-
|
103
|
-
|
127
|
+
unless ObjectTools.immutable?(key) && ObjectTools.immutable?(value)
|
128
|
+
return false
|
129
|
+
end
|
130
|
+
end
|
104
131
|
|
105
132
|
true
|
106
|
-
end
|
133
|
+
end
|
107
134
|
|
108
135
|
# Returns true if the hash is mutable.
|
109
136
|
#
|
@@ -112,36 +139,36 @@ module SleepingKingStudios::Tools
|
|
112
139
|
# @return [Boolean] True if the hash is mutable, otherwise false.
|
113
140
|
#
|
114
141
|
# @see #immutable?
|
115
|
-
def mutable?
|
142
|
+
def mutable?(hsh)
|
116
143
|
!immutable?(hsh)
|
117
|
-
end
|
144
|
+
end
|
118
145
|
|
119
146
|
private
|
120
147
|
|
121
|
-
def convert_value_to_stringified_hash
|
148
|
+
def convert_value_to_stringified_hash(value)
|
122
149
|
if hash?(value)
|
123
150
|
convert_keys_to_strings(value)
|
124
151
|
elsif ArrayTools.array?(value)
|
125
152
|
value.map { |item| convert_value_to_stringified_hash(item) }
|
126
153
|
else
|
127
154
|
value
|
128
|
-
end
|
129
|
-
end
|
155
|
+
end
|
156
|
+
end
|
130
157
|
|
131
|
-
def convert_value_to_symbolic_hash
|
158
|
+
def convert_value_to_symbolic_hash(value)
|
132
159
|
if hash?(value)
|
133
160
|
convert_keys_to_symbols(value)
|
134
161
|
elsif ArrayTools.array?(value)
|
135
162
|
value.map { |item| convert_value_to_symbolic_hash(item) }
|
136
163
|
else
|
137
164
|
value
|
138
|
-
end
|
139
|
-
end
|
165
|
+
end
|
166
|
+
end
|
140
167
|
|
141
|
-
def require_hash!
|
168
|
+
def require_hash!(value)
|
142
169
|
return if hash?(value)
|
143
170
|
|
144
171
|
raise ArgumentError, 'argument must be a hash', caller[1..-1]
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|