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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +32 -3
- data/DEVELOPMENT.md +5 -7
- data/README.md +3 -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 +68 -22
- data/lib/sleeping_king_studios/tools/enumerable_tools.rb +6 -3
- data/lib/sleeping_king_studios/tools/hash_tools.rb +59 -47
- 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 +197 -122
- 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 +6 -8
- metadata +84 -26
- data/lib/sleeping_king_studios/tools/semantic_version.rb +0 -15
- data/lib/sleeping_king_studios/tools/string_tools/plural_inflector.rb +0 -185
@@ -1,16 +1,33 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'sleeping_king_studios/tools'
|
4
4
|
|
5
5
|
module SleepingKingStudios::Tools
|
6
6
|
# Low-level tools for working with objects.
|
7
|
-
|
8
|
-
|
7
|
+
class ObjectTools < SleepingKingStudios::Tools::Base
|
8
|
+
TEMPORARY_METHOD_NAME =
|
9
|
+
'__sleeping_king_studios_tools_apply_%i__'
|
10
|
+
private_constant :TEMPORARY_METHOD_NAME
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def_delegators :instance,
|
14
|
+
:apply,
|
15
|
+
:deep_dup,
|
16
|
+
:deep_freeze,
|
17
|
+
:dig,
|
18
|
+
:eigenclass,
|
19
|
+
:immutable?,
|
20
|
+
:mutable?,
|
21
|
+
:object?,
|
22
|
+
:try
|
23
|
+
|
24
|
+
alias metaclass eigenclass
|
25
|
+
end
|
9
26
|
|
10
27
|
# Takes a proc or lambda and invokes it with the given object as
|
11
28
|
# receiver, with any additional arguments or block provided.
|
12
29
|
#
|
13
|
-
# @param [Object]
|
30
|
+
# @param [Object] receiver The receiver. The proc will be called in the
|
14
31
|
# context of this object.
|
15
32
|
# @param [Proc] proc The proc or lambda to call.
|
16
33
|
# @param [Array] args Optional. Additional arguments to pass in to the
|
@@ -20,20 +37,16 @@ module SleepingKingStudios::Tools
|
|
20
37
|
#
|
21
38
|
# @return The result of calling the proc or lambda with the given
|
22
39
|
# receiver and any additional arguments or block.
|
23
|
-
def apply
|
24
|
-
return
|
40
|
+
def apply(receiver, proc, *args, &block)
|
41
|
+
return receiver.instance_exec(*args, &proc) unless block_given?
|
25
42
|
|
26
|
-
|
43
|
+
method_name =
|
44
|
+
Kernel.format(TEMPORARY_METHOD_NAME, Thread.current.object_id)
|
27
45
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
begin
|
32
|
-
base.send temporary_method_name, *args, &block
|
33
|
-
ensure
|
34
|
-
metaclass.send :remove_method, temporary_method_name if temporary_method_name && defined?(temporary_method_name)
|
46
|
+
with_temporary_method(receiver, method_name, proc) do
|
47
|
+
receiver.send(method_name, *args, &block)
|
35
48
|
end
|
36
|
-
end
|
49
|
+
end
|
37
50
|
|
38
51
|
# Creates a deep copy of the object. If the object is an Array, returns a
|
39
52
|
# new Array with deep copies of each array item. If the object is a Hash,
|
@@ -43,7 +56,7 @@ module SleepingKingStudios::Tools
|
|
43
56
|
# @param [Object] obj The object to copy.
|
44
57
|
#
|
45
58
|
# @return The copy of the object.
|
46
|
-
def deep_dup
|
59
|
+
def deep_dup(obj)
|
47
60
|
case obj
|
48
61
|
when FalseClass, Integer, Float, NilClass, Symbol, TrueClass
|
49
62
|
obj
|
@@ -53,8 +66,8 @@ module SleepingKingStudios::Tools
|
|
53
66
|
HashTools.deep_dup obj
|
54
67
|
else
|
55
68
|
obj.respond_to?(:deep_dup) ? obj.deep_dup : obj.dup
|
56
|
-
end
|
57
|
-
end
|
69
|
+
end
|
70
|
+
end
|
58
71
|
|
59
72
|
# Performs a deep freeze of the object. If the object is an Array, freezes
|
60
73
|
# the array and performs a deep freeze on each array item. If the object is
|
@@ -62,7 +75,7 @@ module SleepingKingStudios::Tools
|
|
62
75
|
# value. Otherwise, calls Object#freeze.
|
63
76
|
#
|
64
77
|
# @param [Object] obj The object to freeze.
|
65
|
-
def deep_freeze
|
78
|
+
def deep_freeze(obj)
|
66
79
|
case obj
|
67
80
|
when FalseClass, Integer, Float, NilClass, Symbol, TrueClass
|
68
81
|
# Object is inherently immutable; do nothing here.
|
@@ -72,8 +85,8 @@ module SleepingKingStudios::Tools
|
|
72
85
|
HashTools.deep_freeze obj
|
73
86
|
else
|
74
87
|
obj.respond_to?(:deep_freeze) ? obj.deep_freeze : obj.freeze
|
75
|
-
end
|
76
|
-
end
|
88
|
+
end
|
89
|
+
end
|
77
90
|
|
78
91
|
# Accesses deeply nested attributes by calling the first named method on the
|
79
92
|
# given object, and each subsequent method on the result of the previous
|
@@ -85,21 +98,21 @@ module SleepingKingStudios::Tools
|
|
85
98
|
#
|
86
99
|
# @return [Object] The result of the last method call, or nil if the last
|
87
100
|
# object does not respond to the last method.
|
88
|
-
def dig
|
101
|
+
def dig(object, *method_names)
|
89
102
|
method_names.reduce(object) do |memo, method_name|
|
90
103
|
memo.respond_to?(method_name) ? memo.send(method_name) : nil
|
91
|
-
end
|
92
|
-
end
|
104
|
+
end
|
105
|
+
end
|
93
106
|
|
94
107
|
# Returns the object's eigenclass.
|
95
108
|
#
|
96
109
|
# @param [Object] object The object for which an eigenclass is required.
|
97
110
|
#
|
98
111
|
# @return [Class] The object's eigenclass.
|
99
|
-
def eigenclass
|
100
|
-
|
101
|
-
end
|
102
|
-
|
112
|
+
def eigenclass(object)
|
113
|
+
object.singleton_class
|
114
|
+
end
|
115
|
+
alias metaclass eigenclass
|
103
116
|
|
104
117
|
# Returns true if the object is immutable. Values of nil, false, and true
|
105
118
|
# are always immutable, as are instances of Numeric and Symbol. Arrays are
|
@@ -110,7 +123,7 @@ module SleepingKingStudios::Tools
|
|
110
123
|
# @param obj [Object] The object to test.
|
111
124
|
#
|
112
125
|
# @return [Boolean] True if the object is immutable, otherwise false.
|
113
|
-
def immutable?
|
126
|
+
def immutable?(obj)
|
114
127
|
case obj
|
115
128
|
when NilClass, FalseClass, TrueClass, Numeric, Symbol
|
116
129
|
true
|
@@ -120,8 +133,8 @@ module SleepingKingStudios::Tools
|
|
120
133
|
HashTools.immutable? obj
|
121
134
|
else
|
122
135
|
obj.frozen?
|
123
|
-
end
|
124
|
-
end
|
136
|
+
end
|
137
|
+
end
|
125
138
|
|
126
139
|
# Returns true if the object is mutable.
|
127
140
|
#
|
@@ -130,9 +143,9 @@ module SleepingKingStudios::Tools
|
|
130
143
|
# @return [Boolean] True if the object is mutable, otherwise false.
|
131
144
|
#
|
132
145
|
# @see #immutable?
|
133
|
-
def mutable?
|
146
|
+
def mutable?(obj)
|
134
147
|
!immutable?(obj)
|
135
|
-
end
|
148
|
+
end
|
136
149
|
|
137
150
|
# Returns true if the object is an Object. This should return true only for
|
138
151
|
# objects that have an alternate inheritance chain from BasicObject, such as
|
@@ -141,9 +154,9 @@ module SleepingKingStudios::Tools
|
|
141
154
|
# @param obj [Object] The object to test.
|
142
155
|
#
|
143
156
|
# @return [Boolean] True if the object is an Object, otherwise false.
|
144
|
-
def object?
|
145
|
-
Object
|
146
|
-
end
|
157
|
+
def object?(obj)
|
158
|
+
Object.instance_method(:is_a?).bind(obj).call(Object)
|
159
|
+
end
|
147
160
|
|
148
161
|
# As #send, but returns nil if the object does not respond to the method.
|
149
162
|
#
|
@@ -151,23 +164,27 @@ module SleepingKingStudios::Tools
|
|
151
164
|
# @param [String, Symbol] method_name The name of the method to call.
|
152
165
|
# @param [Array] args The arguments to the message.
|
153
166
|
#
|
154
|
-
# @see
|
155
|
-
def try
|
156
|
-
if object.nil?
|
157
|
-
return object.respond_to?(method_name) ?
|
158
|
-
object.send(method_name, *args) :
|
159
|
-
nil
|
160
|
-
end # if
|
161
|
-
|
162
|
-
# Delegate to ActiveSupport::CoreExt::Object#try.
|
167
|
+
# @see ActiveSupport::CoreExt::Object#try.
|
168
|
+
def try(object, method_name, *args)
|
163
169
|
return object.try(method_name, *args) if object.respond_to?(:try)
|
164
170
|
|
171
|
+
return nil unless object.respond_to?(method_name)
|
172
|
+
|
165
173
|
object.send method_name, *args
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
def with_temporary_method(receiver, method_name, proc)
|
179
|
+
metaclass = class << receiver; self; end
|
180
|
+
metaclass.send :define_method, method_name, &proc
|
181
|
+
|
182
|
+
yield
|
183
|
+
ensure
|
184
|
+
metaclass.send :remove_method, method_name
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
171
188
|
|
172
189
|
require 'sleeping_king_studios/tools/array_tools'
|
173
190
|
require 'sleeping_king_studios/tools/hash_tools'
|
@@ -1,14 +1,35 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'sleeping_king_studios/tools'
|
4
|
-
require 'sleeping_king_studios/tools/
|
4
|
+
require 'sleeping_king_studios/tools/toolbox/inflector'
|
5
5
|
|
6
6
|
module SleepingKingStudios::Tools
|
7
7
|
# Tools for working with strings.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
class StringTools < SleepingKingStudios::Tools::Base
|
9
|
+
class << self
|
10
|
+
def_delegators :instance,
|
11
|
+
:camelize,
|
12
|
+
:chain,
|
13
|
+
:define_irregular_word,
|
14
|
+
:define_plural_rule,
|
15
|
+
:define_singular_rule,
|
16
|
+
:define_uncountable_word,
|
17
|
+
:indent,
|
18
|
+
:map_lines,
|
19
|
+
:plural?,
|
20
|
+
:pluralize,
|
21
|
+
:singular?,
|
22
|
+
:singularize,
|
23
|
+
:string?,
|
24
|
+
:underscore
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(inflector: nil)
|
28
|
+
@inflector =
|
29
|
+
inflector || SleepingKingStudios::Tools::Toolbox::Inflector.new
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :inflector
|
12
33
|
|
13
34
|
# Converts a lowercase, underscore-separated string to CamelCase.
|
14
35
|
#
|
@@ -17,13 +38,11 @@ module SleepingKingStudios::Tools
|
|
17
38
|
# @return [String] The converted string.
|
18
39
|
#
|
19
40
|
# @see ActiveSupport::Inflector#camelize.
|
20
|
-
def camelize
|
41
|
+
def camelize(str)
|
21
42
|
str = require_string! str
|
22
43
|
|
23
|
-
str
|
24
|
-
|
25
|
-
str
|
26
|
-
end # method camelize
|
44
|
+
inflector.camelize(str)
|
45
|
+
end
|
27
46
|
|
28
47
|
# Performs multiple string tools operations in sequence, starting with the
|
29
48
|
# given string and passing the result of each operation to the next.
|
@@ -32,31 +51,39 @@ module SleepingKingStudios::Tools
|
|
32
51
|
# @param commands [Array<String, Symbol>] The string operations to apply.
|
33
52
|
#
|
34
53
|
# @return [String] The processed string.
|
35
|
-
def chain
|
54
|
+
def chain(str, *commands)
|
36
55
|
str = require_string! str
|
37
56
|
|
38
57
|
commands.reduce(str) { |memo, command| send(command, memo) }
|
39
|
-
end
|
58
|
+
end
|
40
59
|
|
41
60
|
# (see PluralInflector#define_irregular_word)
|
42
|
-
def define_irregular_word
|
43
|
-
|
44
|
-
|
61
|
+
def define_irregular_word(singular, plural)
|
62
|
+
CoreTools.deprecate 'StringTools#define_irregular_word'
|
63
|
+
|
64
|
+
inflector.rules.define_irregular_word singular, plural
|
65
|
+
end
|
45
66
|
|
46
67
|
# (see PluralInflector#define_plural_rule)
|
47
|
-
def define_plural_rule
|
48
|
-
|
49
|
-
|
68
|
+
def define_plural_rule(match, replace)
|
69
|
+
CoreTools.deprecate 'StringTools#define_plural_rule'
|
70
|
+
|
71
|
+
inflector.rules.define_plural_rule match, replace
|
72
|
+
end
|
50
73
|
|
51
74
|
# (see PluralInflector#define_singular_rule)
|
52
|
-
def define_singular_rule
|
53
|
-
|
54
|
-
|
75
|
+
def define_singular_rule(match, replace)
|
76
|
+
CoreTools.deprecate 'StringTools#define_singular_rule'
|
77
|
+
|
78
|
+
inflector.rules.define_singular_rule match, replace
|
79
|
+
end
|
55
80
|
|
56
81
|
# (see PluralInflector#define_uncountable_word)
|
57
|
-
def define_uncountable_word
|
58
|
-
|
59
|
-
|
82
|
+
def define_uncountable_word(word)
|
83
|
+
CoreTools.deprecate 'StringTools#define_uncountable_word'
|
84
|
+
|
85
|
+
inflector.rules.define_uncountable_word word
|
86
|
+
end
|
60
87
|
|
61
88
|
# Adds the specified number of spaces to the start of each line of the
|
62
89
|
# string. Defaults to 2 spaces.
|
@@ -65,12 +92,12 @@ module SleepingKingStudios::Tools
|
|
65
92
|
# @param count [Integer] The number of spaces to add.
|
66
93
|
#
|
67
94
|
# @return [String] The indented string.
|
68
|
-
def indent
|
95
|
+
def indent(str, count = 2)
|
69
96
|
str = require_string! str
|
70
|
-
pre =
|
97
|
+
pre = ' ' * count
|
71
98
|
|
72
99
|
map_lines(str) { |line| "#{pre}#{line}" }
|
73
|
-
end
|
100
|
+
end
|
74
101
|
|
75
102
|
# Yields each line of the string to the provided block and combines the
|
76
103
|
# results into a new multiline string.
|
@@ -81,23 +108,23 @@ module SleepingKingStudios::Tools
|
|
81
108
|
# @yieldparam index [Integer] The index of the current line.
|
82
109
|
#
|
83
110
|
# @return [String] The mapped string.
|
84
|
-
def map_lines
|
111
|
+
def map_lines(str)
|
85
112
|
str = require_string! str
|
86
113
|
|
87
|
-
str.each_line.with_index.reduce('') do |memo, (line, index)|
|
114
|
+
str.each_line.with_index.reduce(+'') do |memo, (line, index)|
|
88
115
|
memo << yield(line, index)
|
89
|
-
end
|
90
|
-
end
|
116
|
+
end
|
117
|
+
end
|
91
118
|
|
92
119
|
# Determines whether or not the given word is in plural form. If calling
|
93
120
|
# #pluralize(word) is equal to word, the word is considered plural.
|
94
121
|
#
|
95
122
|
# @return [Boolean] True if the word is in plural form, otherwise false.
|
96
|
-
def plural?
|
123
|
+
def plural?(word)
|
97
124
|
word = require_string!(word)
|
98
125
|
|
99
126
|
word == pluralize(word)
|
100
|
-
end
|
127
|
+
end
|
101
128
|
|
102
129
|
# @overload pluralize(str)
|
103
130
|
# Takes a word in singular form and returns the plural form, based on the
|
@@ -125,44 +152,44 @@ module SleepingKingStudios::Tools
|
|
125
152
|
#
|
126
153
|
# @return [String] The single form if count == 1; otherwise the plural
|
127
154
|
# form.
|
128
|
-
def pluralize
|
155
|
+
def pluralize(*args)
|
129
156
|
if args.count == 3
|
130
157
|
CoreTools.deprecate 'StringTools#pluralize with 3 arguments',
|
131
|
-
:
|
158
|
+
message: 'Use IntegerTools#pluralize instead.'
|
132
159
|
|
133
160
|
return IntegerTools.pluralize(*args)
|
134
|
-
end
|
161
|
+
end
|
135
162
|
|
136
163
|
str = require_string! args.first
|
137
164
|
|
138
|
-
|
139
|
-
end
|
165
|
+
inflector.pluralize str
|
166
|
+
end
|
140
167
|
|
141
168
|
# Determines whether or not the given word is in singular form. If calling
|
142
169
|
# #singularize(word) is equal to word, the word is considered singular.
|
143
170
|
#
|
144
171
|
# @return [Boolean] True if the word is in singular form, otherwise false.
|
145
|
-
def singular?
|
172
|
+
def singular?(word)
|
146
173
|
word = require_string!(word)
|
147
174
|
|
148
175
|
word == singularize(word)
|
149
|
-
end
|
176
|
+
end
|
150
177
|
|
151
178
|
# (see PluralInflector#singularize)
|
152
|
-
def singularize
|
179
|
+
def singularize(str)
|
153
180
|
require_string! str
|
154
181
|
|
155
|
-
|
156
|
-
end
|
182
|
+
inflector.singularize str
|
183
|
+
end
|
157
184
|
|
158
185
|
# Returns true if the object is a String.
|
159
186
|
#
|
160
187
|
# @param str [Object] The object to test.
|
161
188
|
#
|
162
189
|
# @return [Boolean] True if the object is a String, otherwise false.
|
163
|
-
def string?
|
164
|
-
String
|
165
|
-
end
|
190
|
+
def string?(str)
|
191
|
+
str.is_a?(String)
|
192
|
+
end
|
166
193
|
|
167
194
|
# Converts a mixed-case string expression to a lowercase, underscore
|
168
195
|
# separated string.
|
@@ -172,29 +199,20 @@ module SleepingKingStudios::Tools
|
|
172
199
|
# @return [String] The converted string.
|
173
200
|
#
|
174
201
|
# @see ActiveSupport::Inflector#underscore.
|
175
|
-
def underscore
|
202
|
+
def underscore(str)
|
176
203
|
str = require_string! str
|
177
204
|
|
178
|
-
str
|
179
|
-
|
180
|
-
str.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
181
|
-
str.tr!("-", "_")
|
182
|
-
str.downcase!
|
183
|
-
str
|
184
|
-
end # method underscore
|
205
|
+
inflector.underscore(str)
|
206
|
+
end
|
185
207
|
|
186
208
|
private
|
187
209
|
|
188
|
-
def
|
189
|
-
@plural_inflector ||= PluralInflector.new
|
190
|
-
end # method plural_inflector
|
191
|
-
|
192
|
-
def require_string! value
|
210
|
+
def require_string!(value)
|
193
211
|
return value if string?(value)
|
194
212
|
|
195
213
|
return value.to_s if value.is_a?(Symbol)
|
196
214
|
|
197
215
|
raise ArgumentError, 'argument must be a string', caller[1..-1]
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|