sleeping_king_studios-tools 1.0.0 → 1.1.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 +4 -4
- data/CHANGELOG.md +63 -30
- data/README.md +394 -20
- data/lib/sleeping_king_studios/tools/array_tools.rb +1 -1
- data/lib/sleeping_king_studios/tools/assertions.rb +322 -0
- data/lib/sleeping_king_studios/tools/core_tools.rb +24 -10
- data/lib/sleeping_king_studios/tools/hash_tools.rb +1 -1
- data/lib/sleeping_king_studios/tools/integer_tools.rb +3 -3
- data/lib/sleeping_king_studios/tools/string_tools.rb +1 -1
- data/lib/sleeping_king_studios/tools/toolbelt.rb +3 -0
- data/lib/sleeping_king_studios/tools/toolbox/inflector/rules.rb +2 -0
- data/lib/sleeping_king_studios/tools/toolbox/inflector.rb +1 -1
- data/lib/sleeping_king_studios/tools/toolbox/subclass.rb +54 -0
- data/lib/sleeping_king_studios/tools/toolbox.rb +12 -1
- data/lib/sleeping_king_studios/tools/version.rb +1 -1
- data/lib/sleeping_king_studios/tools.rb +2 -0
- metadata +17 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e0283e289b39463cacc292d923861867d3692aa582c11ea52e093d4a669db47
|
4
|
+
data.tar.gz: 6974c66896e0f0a0b9b464326529e8d093f1842d5242a289d559b6508b08f3b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 207672541e0507cdb35887ef670cc300157c204ddf937ca21a7c1b0243cdde20d212c7daf76f2cd2c70d734f8676ef2e6c646d30f9304933be1db36126c9d2cb
|
7
|
+
data.tar.gz: 5177a4f97ffd28c60b8249f9a4c8a6eafea08dd5c8fe7833273b4274e1fbb59d48e12bcda042a40d2e7d91afb850ed9e583aeeb8f728eea64feeb30c7c9da95a
|
data/CHANGELOG.md
CHANGED
@@ -1,15 +1,50 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
|
3
|
+
## 1.1.0
|
4
4
|
|
5
|
-
|
5
|
+
Files in the `Toolbox` are now autoloaded.
|
6
6
|
|
7
|
-
|
7
|
+
### Tools
|
8
|
+
|
9
|
+
Implemented `SleepingKingStudios::Tools::Assertions` with the following methods:
|
10
|
+
|
11
|
+
- `#assert`
|
12
|
+
- `#assert_boolean`
|
13
|
+
- `#assert_class`
|
14
|
+
- `#assert_instance_of`
|
15
|
+
- `#assert_matches`
|
16
|
+
- `#assert_name`
|
17
|
+
|
18
|
+
Each method raises an exception if its condition is not met. `Assertions` also defines equivalent `#validate` methods, which always raise an `ArgumentError`.
|
19
|
+
|
20
|
+
Added :deprecation_caller_depth option to CoreTools. When calling #deprecate with the default strategy of 'warn', will print the specified number of lines from the caller. The default value is 3.
|
21
|
+
|
22
|
+
### Toolbelt
|
23
|
+
|
24
|
+
- Added `#assertions` to Toolbelt.
|
25
|
+
|
26
|
+
### Toolbox
|
27
|
+
|
28
|
+
Implemented `SleepingKingStudios::Tools::Toolbox::Subclass`, which implements partial application for constructor parameters.
|
29
|
+
|
30
|
+
## 1.0.2
|
31
|
+
|
32
|
+
Updated gem metadata.
|
33
|
+
|
34
|
+
## 1.0.1
|
35
|
+
|
36
|
+
Added a missing `require 'set'` to Toolbox::Inflector::Rules.
|
37
|
+
|
38
|
+
## 1.0.0
|
39
|
+
|
40
|
+
Removed all deprecated code from pre-1.0 releases.
|
41
|
+
|
42
|
+
### Toolbox
|
8
43
|
|
9
44
|
Added some Hash-like methods to ConstantMap - `#each_key`, `#each_value`,
|
10
45
|
`#keys`, `#to_h`, and `#values`.
|
11
46
|
|
12
|
-
|
47
|
+
## 0.8.0
|
13
48
|
|
14
49
|
Last minor release before 1.0.0.
|
15
50
|
|
@@ -20,14 +55,14 @@ in version 1.0.0. Update dependent code accordingly.
|
|
20
55
|
functionality is still available as
|
21
56
|
SleepingKingStudios::Tools::Toolbox::SemanticVersion.
|
22
57
|
|
23
|
-
|
58
|
+
### Tools
|
24
59
|
|
25
60
|
- Refactored all Tools modules to classes.
|
26
61
|
- Removed StringTools::PluralInflector. It's functionality is now handled by
|
27
62
|
Toolbox::Inflector.
|
28
63
|
- Added support for deprecation strategy to CoreTools#deprecate.
|
29
64
|
|
30
|
-
|
65
|
+
### Toolbelt
|
31
66
|
|
32
67
|
- Refactored Toolbelt to reference Tools instances rather than classes.
|
33
68
|
- Defined new abbreviated helpers #ary, #hsh, #int, #obj, #str.
|
@@ -36,36 +71,36 @@ in version 1.0.0. Update dependent code accordingly.
|
|
36
71
|
- Deprecated old abbreviated helpers #array, #core, #hash, #integer, #object,
|
37
72
|
#string.
|
38
73
|
|
39
|
-
|
74
|
+
### Toolbox
|
40
75
|
|
41
76
|
- Deprecate Toolbox::Configuration. Use a struct instead.
|
42
77
|
- Deprecate Toolbox::Delegator. Use the stdlib Forwardable module instead.
|
43
78
|
- Implement Toolbox::Inflector, which serves as a delegate for StringTools.
|
44
79
|
|
45
|
-
|
80
|
+
## 0.7.1
|
46
81
|
|
47
82
|
- Implement CoreTools#empty_binding.
|
48
83
|
- Implement HashTools#generate_binding.
|
49
84
|
|
50
|
-
|
85
|
+
## 0.7.0
|
51
86
|
|
52
|
-
|
87
|
+
### Tools
|
53
88
|
|
54
89
|
- Support symbol arguments to StringTools methods.
|
55
90
|
- Implement StringTools#chain.
|
56
91
|
- Implement StringTools#indent.
|
57
92
|
- Implement StringTools#map_lines.
|
58
93
|
|
59
|
-
|
94
|
+
### Toolbox
|
60
95
|
|
61
96
|
- Implement Toolbox::Configuration.
|
62
97
|
|
63
|
-
|
98
|
+
### Misc.
|
64
99
|
|
65
100
|
- IntegerTools#pluralize now accepts 2..3 arguments, and will automatically generate the plural string using StringTools#pluralize if an explicit plural is not given.
|
66
101
|
- SleepingKingStudios::Tools::Toolbelt is now autoloaded from SleepingKingStudios::Tools.
|
67
102
|
|
68
|
-
|
103
|
+
## 0.6.0
|
69
104
|
|
70
105
|
- Implement HashTools#convert_keys_to_strings and #convert_keys_to_symbols.
|
71
106
|
- Implement ObjectTools#dig.
|
@@ -75,69 +110,67 @@ in version 1.0.0. Update dependent code accordingly.
|
|
75
110
|
- Implement Toolbox::Mixin.
|
76
111
|
- Add support for Ruby 2.4.0.
|
77
112
|
|
78
|
-
|
113
|
+
## 0.5.0
|
79
114
|
|
80
115
|
- Implement CoreTools#require_each.
|
81
116
|
- Implement StringTools#camelize.
|
82
117
|
- Add an optional block argument to ArrayTools#humanize_list.
|
83
118
|
|
84
|
-
|
119
|
+
### Toolbox
|
85
120
|
|
86
121
|
- Implement Delegator#delegate, Delegator#wrap_delegate.
|
87
122
|
- Refactor SemanticVersion to the Toolbox namespace. Accessing SemanticVersion as Tools::SemanticVersion is now deprecated, use Tools::Toolbox::SemanticVersion.
|
88
123
|
|
89
|
-
|
124
|
+
### Identity Methods
|
90
125
|
|
91
126
|
- Implement a set of methods to classify objects by type: ArrayTools#array?, HashTools#hash?, IntegerTools#integer?, ObjectTools#object?, and StringTools#string?.
|
92
127
|
|
93
|
-
|
128
|
+
### Mutability Methods
|
94
129
|
|
95
130
|
Implement #immutable? and #mutable? for ObjectTools, ArrayTools, and HashTools, which indicate whether or not a given object is mutable.
|
96
131
|
|
97
132
|
Implement #deep_freeze for ObjectTools, ArrayTools, and HashTools which recursively freezes the object and any children (array items, hash keys, and hash values).
|
98
133
|
|
99
|
-
##
|
100
|
-
|
101
|
-
### 0.4.0
|
134
|
+
## 0.4.0
|
102
135
|
|
103
|
-
|
136
|
+
### CoreTools
|
104
137
|
|
105
138
|
Implement CoreTools#deprecate.
|
106
139
|
|
107
|
-
|
140
|
+
### IntegerTools
|
108
141
|
|
109
142
|
Implement #pluralize.
|
110
143
|
|
111
|
-
|
144
|
+
### StringTools
|
112
145
|
|
113
146
|
Implement #pluralize and #singularize. The previous behavior of #pluralize is deprecated; use IntegerTools#pluralize.
|
114
147
|
|
115
|
-
|
148
|
+
## 0.3.0
|
116
149
|
|
117
150
|
Implement ArrayTools#bisect and ArrayTools#splice.
|
118
151
|
|
119
|
-
|
152
|
+
### StringTools
|
120
153
|
|
121
154
|
Implement #underscore.
|
122
155
|
|
123
|
-
|
156
|
+
## 0.2.0
|
124
157
|
|
125
158
|
Split EnumerableTools into ArrayTools and HashTools.
|
126
159
|
|
127
160
|
Implement ArrayTools#deep_dup, HashTools#deep_dup and ObjectTools#deep_dup.
|
128
161
|
|
129
|
-
|
162
|
+
## 0.1.3
|
130
163
|
|
131
164
|
Properly support both keywords and optional arguments in ObjectTools#apply.
|
132
165
|
|
133
|
-
|
166
|
+
## 0.1.2
|
134
167
|
|
135
168
|
Fix loading order issues when loading SemanticVersion in isolation.
|
136
169
|
|
137
|
-
|
170
|
+
## 0.1.1
|
138
171
|
|
139
172
|
Add configuration options to EnumerableTools#humanize_list.
|
140
173
|
|
141
|
-
|
174
|
+
## 0.1.0
|
142
175
|
|
143
176
|
Initial release.
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ A library of utility services and concerns to expand the functionality of core c
|
|
4
4
|
|
5
5
|
## About
|
6
6
|
|
7
|
-
SleepingKingStudios::Tools is tested against MRI Ruby 2.
|
7
|
+
SleepingKingStudios::Tools is tested against MRI Ruby 2.6 through 3.1.
|
8
8
|
|
9
9
|
### Documentation
|
10
10
|
|
@@ -30,18 +30,20 @@ Please note that the `SleepingKingStudios::Tools` project is released with a [Co
|
|
30
30
|
|
31
31
|
The tools can be accessed in a convenient form using the Toolbelt class.
|
32
32
|
|
33
|
-
|
33
|
+
```ruby
|
34
|
+
require 'sleeping_king_studios/tools'
|
34
35
|
|
35
|
-
|
36
|
+
tools = ::SleepingKingStudios::Tools::Toolbelt.instance
|
36
37
|
|
37
|
-
|
38
|
-
|
38
|
+
tools.ary.humanize_list 'one', 'two', 'three'
|
39
|
+
#=> calls ArrayTools#humanize_list
|
39
40
|
|
40
|
-
|
41
|
-
|
41
|
+
tools.core.deprecate 'my_method'
|
42
|
+
#=> calls CoreTools#deprecate
|
42
43
|
|
43
|
-
|
44
|
-
|
44
|
+
tools.str.underscore 'MyModuleName'
|
45
|
+
#=> calls StringTools#underscore
|
46
|
+
```
|
45
47
|
|
46
48
|
### Array Tools
|
47
49
|
|
@@ -181,6 +183,256 @@ Accepts an array, a start value, a number of items to delete, and zero or more i
|
|
181
183
|
values
|
182
184
|
#=> ['shortbow', 'longbow', 'arbalest', 'chu-ko-nu']
|
183
185
|
|
186
|
+
### Assertions
|
187
|
+
|
188
|
+
Tools for validating the current application state.
|
189
|
+
|
190
|
+
#### `#assert`
|
191
|
+
|
192
|
+
Raises an exception unless the given block returns a truthy value.
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
Assertions.assert { true == false }
|
196
|
+
#=> raises an AssertionError with message 'block returned a falsy value'
|
197
|
+
|
198
|
+
Assertions.assert { true == true }
|
199
|
+
#=> does not raise an exception
|
200
|
+
```
|
201
|
+
|
202
|
+
It accepts the following options:
|
203
|
+
|
204
|
+
- `error_class:` The class of exception to raise. Defaults to `SleepingKingStudios::Tools::Assertions::AssertionError`.
|
205
|
+
- `message`: The error message to display.
|
206
|
+
|
207
|
+
#### `#assert_boolean`
|
208
|
+
|
209
|
+
Raises an exception unless the given value is either `true` or `false`.
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
Assertions.assert_boolean(nil)
|
213
|
+
#=> raises an AssertionError with message 'value must be true or false'
|
214
|
+
|
215
|
+
Assertions.assert_boolean(Object.new)
|
216
|
+
#=> raises an AssertionError with message 'value must be true or false'
|
217
|
+
|
218
|
+
Assertions.assert_boolean(false)
|
219
|
+
#=> does not raise an exception
|
220
|
+
|
221
|
+
Assertions.assert_boolean(true)
|
222
|
+
#=> does not raise an exception
|
223
|
+
```
|
224
|
+
|
225
|
+
It accepts the following options:
|
226
|
+
|
227
|
+
- `as:` A short descriptor of the given value. Defaults to `"value"`.
|
228
|
+
- `error_class:` The class of exception to raise. Defaults to `SleepingKingStudios::Tools::Assertions::AssertionError`.
|
229
|
+
- `message`: The error message to display.
|
230
|
+
|
231
|
+
#### `#assert_class`
|
232
|
+
|
233
|
+
Raises an exception unless the given value is a Class.
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
Assertions.assert_class(Object.new)
|
237
|
+
#=> raises an AssertionError with message 'value is not a class'
|
238
|
+
|
239
|
+
Assertions.assert_class(String)
|
240
|
+
#=> does not raise an exception
|
241
|
+
```
|
242
|
+
|
243
|
+
It accepts the following options:
|
244
|
+
|
245
|
+
- `as:` A short descriptor of the given value. Defaults to `"value"`.
|
246
|
+
- `error_class:` The class of exception to raise. Defaults to `SleepingKingStudios::Tools::Assertions::AssertionError`.
|
247
|
+
- `message`: The error message to display.
|
248
|
+
|
249
|
+
#### `#assert_instance_of`
|
250
|
+
|
251
|
+
Raises an exception unless the given value is an instance of the expected Class or Module.
|
252
|
+
|
253
|
+
```ruby
|
254
|
+
Assertions.assert_instance_of(:foo, expected: String)
|
255
|
+
#=> raises an AssertionError with message 'value is not an instance of String'
|
256
|
+
|
257
|
+
Assertions.assert_instance_of('foo', expected: String)
|
258
|
+
#=> does not raise an exception
|
259
|
+
```
|
260
|
+
|
261
|
+
It accepts the following options:
|
262
|
+
|
263
|
+
- `as:` A short descriptor of the given value. Defaults to `"value"`.
|
264
|
+
- `error_class:` The class of exception to raise. Defaults to `SleepingKingStudios::Tools::Assertions::AssertionError`.
|
265
|
+
- `message`: The error message to display.
|
266
|
+
- `optional`: If true, accepts `nil` values as well as instances of the Class or Module.
|
267
|
+
|
268
|
+
#### `#assert_matches`
|
269
|
+
|
270
|
+
Raises an exception unless the given value matches the expected value using case equality (`#===`).
|
271
|
+
|
272
|
+
|
273
|
+
```ruby
|
274
|
+
Assertions.assert_matches('bar', expected: /foo/)
|
275
|
+
#=> raises an AssertionError with message 'value does not match the pattern /foo/'
|
276
|
+
|
277
|
+
Assertions.assert_matches('foo', expected: /foo/)
|
278
|
+
#=> does not raise an exception
|
279
|
+
```
|
280
|
+
|
281
|
+
It accepts the following options:
|
282
|
+
|
283
|
+
- `as:` A short descriptor of the given value. Defaults to `"value"`.
|
284
|
+
- `error_class:` The class of exception to raise. Defaults to `SleepingKingStudios::Tools::Assertions::AssertionError`.
|
285
|
+
- `message`: The error message to display.
|
286
|
+
- `optional`: If true, accepts `nil` values as well as matching values.
|
287
|
+
|
288
|
+
#### `#assert_name`
|
289
|
+
|
290
|
+
Raises an exception unless the given value is non-empty a String or Symbol.
|
291
|
+
|
292
|
+
```ruby
|
293
|
+
Assertions.assert_name(nil)
|
294
|
+
#=> raises an AssertionError with message "value can't be blank"
|
295
|
+
|
296
|
+
Assertions.assert_name(Object.new)
|
297
|
+
#=> raises an AssertionError with message 'value is not a String or a Symbol'
|
298
|
+
|
299
|
+
Assertions.assert_name('')
|
300
|
+
#=> raises an AssertionError with message "value can't be blank"
|
301
|
+
|
302
|
+
Assertions.assert_name('foo')
|
303
|
+
#=> does not raise an exception
|
304
|
+
|
305
|
+
Assertions.assert_name(:bar)
|
306
|
+
#=> does not raise an exception
|
307
|
+
```
|
308
|
+
|
309
|
+
It accepts the following options:
|
310
|
+
|
311
|
+
- `as:` A short descriptor of the given value. Defaults to `"value"`.
|
312
|
+
- `error_class:` The class of exception to raise. Defaults to `SleepingKingStudios::Tools::Assertions::AssertionError`.
|
313
|
+
- `message`: The error message to display.
|
314
|
+
- `optional`: If true, accepts `nil` values as well as valid Symbols and Strings.
|
315
|
+
|
316
|
+
#### `#validate`
|
317
|
+
|
318
|
+
Raises an `ArgumentError` unless the given block returns a truthy value.
|
319
|
+
|
320
|
+
```ruby
|
321
|
+
Assertions.validate { true == false }
|
322
|
+
#=> raises an ArgumentError with message 'block returned a falsy value'
|
323
|
+
|
324
|
+
Assertions.validate { true == true }
|
325
|
+
#=> does not raise an exception
|
326
|
+
```
|
327
|
+
|
328
|
+
It accepts the following options:
|
329
|
+
|
330
|
+
- `message`: The error message to display.
|
331
|
+
|
332
|
+
#### `#validate_boolean`
|
333
|
+
|
334
|
+
Raises an exception unless the given value is either `true` or `false`.
|
335
|
+
|
336
|
+
```ruby
|
337
|
+
Assertions.validate_boolean(nil)
|
338
|
+
#=> raises an ArgumentError with message 'value must be true or false'
|
339
|
+
|
340
|
+
Assertions.validate_boolean(Object.new)
|
341
|
+
#=> raises an ArgumentError with message 'value must be true or false'
|
342
|
+
|
343
|
+
Assertions.validate_boolean(false)
|
344
|
+
#=> does not raise an exception
|
345
|
+
|
346
|
+
Assertions.validate_boolean(true)
|
347
|
+
#=> does not raise an exception
|
348
|
+
```
|
349
|
+
|
350
|
+
It accepts the following options:
|
351
|
+
|
352
|
+
- `as:` A short descriptor of the given value. Defaults to `"value"`.
|
353
|
+
- `message`: The error message to display.
|
354
|
+
|
355
|
+
#### `#validate_class`
|
356
|
+
|
357
|
+
Raises an `ArgumentError` unless the given value is a Class.
|
358
|
+
|
359
|
+
```ruby
|
360
|
+
Assertions.validate_class(Object.new)
|
361
|
+
#=> raises an ArgumentError with message 'value is not a class'
|
362
|
+
|
363
|
+
Assertions.validate_class(String)
|
364
|
+
#=> does not raise an exception
|
365
|
+
```
|
366
|
+
|
367
|
+
It accepts the following options:
|
368
|
+
|
369
|
+
- `as:` A short descriptor of the given value. Defaults to `"value"`.
|
370
|
+
- `message`: The error message to display.
|
371
|
+
|
372
|
+
#### `#validate_instance_of`
|
373
|
+
|
374
|
+
Raises an `ArgumentError` unless the given value is an instance of the expected Class or Module.
|
375
|
+
|
376
|
+
```ruby
|
377
|
+
Assertions.validate_instance_of(:foo, expected: String)
|
378
|
+
#=> raises an AssertionError with message 'value is not an instance of String'
|
379
|
+
|
380
|
+
Assertions.validate_instance_of('foo', expected: String)
|
381
|
+
#=> does not raise an exception
|
382
|
+
```
|
383
|
+
|
384
|
+
It accepts the following options:
|
385
|
+
|
386
|
+
- `as:` A short descriptor of the given value. Defaults to `"value"`.
|
387
|
+
- `message`: The error message to display.
|
388
|
+
- `optional`: If true, accepts `nil` values as well as instances of the Class or Module.
|
389
|
+
|
390
|
+
#### `#validate_matches`
|
391
|
+
|
392
|
+
Raises an `ArgumentError` unless the given value matches the expected value using case equality (`#===`).
|
393
|
+
|
394
|
+
|
395
|
+
```ruby
|
396
|
+
Assertions.validate_matches('bar', expected: /foo/)
|
397
|
+
#=> raises an ArgumentError with message 'value does not match the pattern /foo/'
|
398
|
+
|
399
|
+
Assertions.validate_matches('foo', expected: /foo/)
|
400
|
+
#=> does not raise an exception
|
401
|
+
```
|
402
|
+
|
403
|
+
It accepts the following options:
|
404
|
+
|
405
|
+
- `as:` A short descriptor of the given value. Defaults to `"value"`.
|
406
|
+
- `message`: The error message to display.
|
407
|
+
- `optional`: If true, accepts `nil` values as well as matching values.
|
408
|
+
|
409
|
+
#### `#validate_name`
|
410
|
+
|
411
|
+
Raises an `ArgumentError` unless the given value is non-empty a String or Symbol.
|
412
|
+
|
413
|
+
```ruby
|
414
|
+
Assertions.validate_name(nil)
|
415
|
+
#=> raises an ArgumentError with message "value can't be blank"
|
416
|
+
|
417
|
+
Assertions.validate_name(Object.new)
|
418
|
+
#=> raises an AssertionError with message 'value is not a String or a Symbol'
|
419
|
+
|
420
|
+
Assertions.validate_name('')
|
421
|
+
#=> raises an ArgumentError with message "value can't be blank"
|
422
|
+
|
423
|
+
Assertions.validate_name('foo')
|
424
|
+
#=> does not raise an exception
|
425
|
+
|
426
|
+
Assertions.validate_name(:bar)
|
427
|
+
#=> does not raise an exception
|
428
|
+
```
|
429
|
+
|
430
|
+
It accepts the following options:
|
431
|
+
|
432
|
+
- `as:` A short descriptor of the given value. Defaults to `"value"`.
|
433
|
+
- `message`: The error message to display.
|
434
|
+
- `optional`: If true, accepts `nil` values as well as valid Symbols and Strings.
|
435
|
+
|
184
436
|
### Core Tools
|
185
437
|
|
186
438
|
Tools for working with an application or working environment.
|
@@ -189,17 +441,40 @@ Tools for working with an application or working environment.
|
|
189
441
|
|
190
442
|
Prints a deprecation warning.
|
191
443
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
444
|
+
```ruby
|
445
|
+
CoreTools.deprecate 'ObjectTools#old_method'
|
446
|
+
#=> prints to stderr:
|
447
|
+
#
|
448
|
+
# [WARNING] ObjectTools#old_method is deprecated.
|
449
|
+
# called from /path/to/file.rb:4: in something_or_other
|
450
|
+
```
|
451
|
+
|
452
|
+
You can also specify an additional message to display:
|
453
|
+
|
454
|
+
```ruby
|
455
|
+
CoreTools.deprecate 'ObjectTools#old_method',
|
456
|
+
'Use #new_method instead.'
|
457
|
+
#=> prints to stderr:
|
458
|
+
#
|
459
|
+
# [WARNING] ObjectTools#old_method is deprecated. Use #new_method instead.
|
460
|
+
# called from /path/to/file.rb:4: in something_or_other
|
461
|
+
```
|
462
|
+
|
463
|
+
You can specify a custom format for the deprecation message:
|
464
|
+
|
465
|
+
```ruby
|
466
|
+
CoreTools.deprecate 'ObjectTools#old_method',
|
467
|
+
'0.1.0',
|
468
|
+
format: '%s was deprecated in version %s.'
|
469
|
+
#=> prints to stderr:
|
470
|
+
#
|
471
|
+
# ObjectTools#old_method was deprecated in version 0.1.0.
|
472
|
+
# called from /path/to/file.rb:4: in something_or_other
|
473
|
+
```
|
474
|
+
|
475
|
+
By default, `#deprecate` will print the last 3 lines of the caller, excluding
|
476
|
+
any lines from `Forwardable` and from `SleepingKingStudios::Tools` itself. To
|
477
|
+
print a different number of lines, pass a custom `deprecation_caller_depth` parameter to `CoreTools.new` or set the `DEPRECATION_CALLER_DEPTH` environment variable.
|
203
478
|
|
204
479
|
#### `#empty_binding`
|
205
480
|
|
@@ -825,3 +1100,102 @@ Concatenates the MAJOR, MINOR, and PATCH constant values with PRERELEASE and BUI
|
|
825
1100
|
#### `#to_version`
|
826
1101
|
|
827
1102
|
Concatenates the MAJOR, MINOR, and PATCH constant values with PRERELEASE and BUILD (if available) to generate a semantic version string. The major, minor, and patch values are separated by dots `.`, then the prerelease (if available) preceded by a hyphen `-`, and the build (if available) preceded by a plus sign `+`.
|
1103
|
+
|
1104
|
+
### Subclass
|
1105
|
+
|
1106
|
+
```ruby
|
1107
|
+
require 'sleeping_king_studios/tools/toolbox/subclass'
|
1108
|
+
```
|
1109
|
+
|
1110
|
+
The `Subclass` module provides a mechanism for performing partial application (or "currying") of constructor parameters. This is useful for defining subclasses that inject pre-defined values into the constructor.
|
1111
|
+
|
1112
|
+
Let's consider an example. We'll start by defining a base class.
|
1113
|
+
|
1114
|
+
```ruby
|
1115
|
+
class Query
|
1116
|
+
extend SleepingKingStudios::Tools::Toolbox::Subclass
|
1117
|
+
|
1118
|
+
def initialize(entity_class, **options)
|
1119
|
+
@entity_class = entity_class
|
1120
|
+
@options = options
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
attr_reader :entity_class
|
1124
|
+
|
1125
|
+
attr_reader :options
|
1126
|
+
|
1127
|
+
def call
|
1128
|
+
# Querying logic here.
|
1129
|
+
end
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
query = Query.new(Book, limit: 10)
|
1133
|
+
query.entity_class
|
1134
|
+
#=> Book
|
1135
|
+
query.options
|
1136
|
+
#=> { limit: 10 }
|
1137
|
+
```
|
1138
|
+
|
1139
|
+
Our `Query` class is used to perform queries on some data source - a relational table, an API, or some in-memory data structure. To perform a query, we need to know what data to request. This is represented by the `:entity_class` argument. Additionally, we can pass arbitrary `:options` as keywords.
|
1140
|
+
|
1141
|
+
```ruby
|
1142
|
+
BooksQuery = Query.subclass(Book)
|
1143
|
+
|
1144
|
+
query = BooksQuery.new(order: :title)
|
1145
|
+
query.entity_class
|
1146
|
+
#=> Book
|
1147
|
+
query.options
|
1148
|
+
#=> { order: :title }
|
1149
|
+
```
|
1150
|
+
|
1151
|
+
By calling `.subclass` on our `Query` class, we are defining a new subclass of `Query` that injects the given parameters and partially applies them to the constructor. In this case, we are injecting the `Book` class into our query.
|
1152
|
+
|
1153
|
+
We can also use `.subclass` to partially apply keywords or a block.
|
1154
|
+
|
1155
|
+
```ruby
|
1156
|
+
RecentItemsQuery = Query.subclass(order: { created_at: :desc })
|
1157
|
+
|
1158
|
+
query = RecentItemsQuery.new(Book)
|
1159
|
+
query.entity_class
|
1160
|
+
#=> Book
|
1161
|
+
query.options
|
1162
|
+
#=> { order: { created_at: :desc } }
|
1163
|
+
```
|
1164
|
+
|
1165
|
+
When you call the subclass's constructor with additional parameters, they are applied in addition to the configured values (if any).
|
1166
|
+
|
1167
|
+
- Any arguments passed to `.new` are added *after* the configured arguments.
|
1168
|
+
- Any keywords passed to `.new` are merged into the configured keywords, with the values passed to `.new` taking precedence.
|
1169
|
+
- A block passed to `.new` will take precedence over a configured block.
|
1170
|
+
|
1171
|
+
```ruby
|
1172
|
+
class Character
|
1173
|
+
extend SleepingKingStudios::Tools::Toolbox::Subclass
|
1174
|
+
|
1175
|
+
def initialize(*traits, **stats, &special)
|
1176
|
+
@traits = traits
|
1177
|
+
@stats = stats
|
1178
|
+
@special = special
|
1179
|
+
end
|
1180
|
+
|
1181
|
+
attr_reader :special
|
1182
|
+
|
1183
|
+
attr_reader :stats
|
1184
|
+
|
1185
|
+
attr_reader :traits
|
1186
|
+
end
|
1187
|
+
|
1188
|
+
Bard = Character.subclass(:musical, performance: 5, persuasion: 10) do
|
1189
|
+
'The bard sings a cheerful tune.'
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
aoife = Bard.new(:sorcerous, magic: 5, performance: 10) do
|
1193
|
+
'Aoife drops her lute!'
|
1194
|
+
end
|
1195
|
+
aoife.traits
|
1196
|
+
#=> [:musical, :sorcerous]
|
1197
|
+
aoife.stats
|
1198
|
+
#=> { magic: 5, performance: 10, persuasion: 10 }
|
1199
|
+
aoife.special.call
|
1200
|
+
#=> 'Aoife drops her lute!'
|
1201
|
+
```
|
@@ -302,7 +302,7 @@ module SleepingKingStudios::Tools
|
|
302
302
|
def require_array!(value)
|
303
303
|
return if array?(value)
|
304
304
|
|
305
|
-
raise ArgumentError, 'argument must be an array', caller[1
|
305
|
+
raise ArgumentError, 'argument must be an array', caller[1..]
|
306
306
|
end
|
307
307
|
end
|
308
308
|
end
|
@@ -0,0 +1,322 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tools'
|
4
|
+
|
5
|
+
module SleepingKingStudios::Tools
|
6
|
+
# Methods for asserting on the state of a function or application.
|
7
|
+
class Assertions < Base # rubocop:disable Metrics/ClassLength
|
8
|
+
# Error class for handling a failed assertion.
|
9
|
+
class AssertionError < StandardError; end
|
10
|
+
|
11
|
+
# Asserts that the block returns a truthy value.
|
12
|
+
#
|
13
|
+
# @param error_class [Class] The exception class to raise on a failure.
|
14
|
+
# @param message [String] The exception message to raise on a failure.
|
15
|
+
#
|
16
|
+
# @yield The block to evaluate.
|
17
|
+
# @yieldreturn [Object] The returned value of the block.
|
18
|
+
#
|
19
|
+
# @raise AssertionError if the block does not return a truthy value.
|
20
|
+
def assert(error_class: AssertionError, message: nil, &block)
|
21
|
+
return if block.call
|
22
|
+
|
23
|
+
raise error_class,
|
24
|
+
message || 'block returned a falsy value',
|
25
|
+
caller(1..-1)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Asserts that the value is either true or false.
|
29
|
+
#
|
30
|
+
# @param value [Object] The value to assert on.
|
31
|
+
# @param as [String] The name of the asserted value.
|
32
|
+
# @param error_class [Class] The exception class to raise on a failure.
|
33
|
+
# @param message [String] The exception message to raise on a failure.
|
34
|
+
#
|
35
|
+
# @raise AssertionError if the value is not a Class.
|
36
|
+
def assert_boolean(
|
37
|
+
value,
|
38
|
+
as: 'value',
|
39
|
+
error_class: AssertionError,
|
40
|
+
message: nil
|
41
|
+
)
|
42
|
+
return if value.equal?(true) || value.equal?(false)
|
43
|
+
|
44
|
+
raise error_class,
|
45
|
+
message || "#{as} must be true or false",
|
46
|
+
caller(1..-1)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Asserts that the value is a Class.
|
50
|
+
#
|
51
|
+
# @param value [Object] The value to assert on.
|
52
|
+
# @param as [String] The name of the asserted value.
|
53
|
+
# @param error_class [Class] The exception class to raise on a failure.
|
54
|
+
# @param message [String] The exception message to raise on a failure.
|
55
|
+
#
|
56
|
+
# @raise AssertionError if the value is not a Class.
|
57
|
+
def assert_class(
|
58
|
+
value,
|
59
|
+
as: 'value',
|
60
|
+
error_class: AssertionError,
|
61
|
+
message: nil
|
62
|
+
)
|
63
|
+
return if value.is_a?(Class)
|
64
|
+
|
65
|
+
raise error_class,
|
66
|
+
message || "#{as} is not a Class",
|
67
|
+
caller(1..-1)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Asserts that the value is an example of the given Class.
|
71
|
+
#
|
72
|
+
# @param value [Object] The value to assert on.
|
73
|
+
# @param as [String] The name of the asserted value.
|
74
|
+
# @param error_class [Class] The exception class to raise on a failure.
|
75
|
+
# @param expected [Class] The expected class.
|
76
|
+
# @param message [String] The exception message to raise on a failure.
|
77
|
+
# @param optional [true, false] If true, allows nil values.
|
78
|
+
#
|
79
|
+
# @raise ArgumentError if the expected class is not a Class.
|
80
|
+
# @raise AssertionError if the value is not an instance of the expected
|
81
|
+
# class.
|
82
|
+
def assert_instance_of( # rubocop:disable Metrics/ParameterLists
|
83
|
+
value,
|
84
|
+
expected:,
|
85
|
+
as: 'value',
|
86
|
+
error_class: AssertionError,
|
87
|
+
message: nil,
|
88
|
+
optional: false
|
89
|
+
)
|
90
|
+
unless expected.is_a?(Class)
|
91
|
+
raise ArgumentError, 'expected must be a Class'
|
92
|
+
end
|
93
|
+
|
94
|
+
return if optional && value.nil?
|
95
|
+
return if value.is_a?(expected)
|
96
|
+
|
97
|
+
raise error_class,
|
98
|
+
message || "#{as} is not an instance of #{class_name(expected)}",
|
99
|
+
caller(1..-1)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Asserts that the value matches the expected object using #===.
|
103
|
+
#
|
104
|
+
# @param value [Object] The value to assert on.
|
105
|
+
# @param as [String] The name of the asserted value.
|
106
|
+
# @param error_class [Class] The exception class to raise on a failure.
|
107
|
+
# @param expected [#===] The expected object.
|
108
|
+
# @param message [String] The exception message to raise on a failure.
|
109
|
+
# @param optional [true, false] If true, allows nil values.
|
110
|
+
#
|
111
|
+
# @raise AssertionError if the value does not match the expected object.
|
112
|
+
def assert_matches( # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/ParameterLists
|
113
|
+
value,
|
114
|
+
expected:,
|
115
|
+
as: 'value',
|
116
|
+
error_class: AssertionError,
|
117
|
+
message: nil,
|
118
|
+
optional: false
|
119
|
+
)
|
120
|
+
return if optional && value.nil?
|
121
|
+
return if expected === value # rubocop:disable Style/CaseEquality
|
122
|
+
|
123
|
+
message ||=
|
124
|
+
case expected
|
125
|
+
when Module
|
126
|
+
"#{as} is not an instance of #{class_name(expected)}"
|
127
|
+
when Proc
|
128
|
+
"#{as} does not match the Proc"
|
129
|
+
when Regexp
|
130
|
+
"#{as} does not match the pattern #{expected.inspect}"
|
131
|
+
else
|
132
|
+
"#{as} does not match the expected value"
|
133
|
+
end
|
134
|
+
|
135
|
+
raise error_class, message, caller(1..-1)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Asserts that the value is a non-empty String or Symbol.
|
139
|
+
#
|
140
|
+
# @param value [Object] The value to assert on.
|
141
|
+
# @param as [String] The name of the asserted value.
|
142
|
+
# @param error_class [Class] The exception class to raise on a failure.
|
143
|
+
# @param message [String] The exception message to raise on a failure.
|
144
|
+
# @param optional [true, false] If true, allows nil values.
|
145
|
+
#
|
146
|
+
# @raise AssertionError if the value is not a String or a Symbol, or if the
|
147
|
+
# value is empty.
|
148
|
+
def assert_name( # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
149
|
+
value,
|
150
|
+
as: 'value',
|
151
|
+
error_class: AssertionError,
|
152
|
+
message: nil,
|
153
|
+
optional: false
|
154
|
+
)
|
155
|
+
if value.nil?
|
156
|
+
return if optional
|
157
|
+
|
158
|
+
raise error_class, message || "#{as} can't be blank", caller(1..-1)
|
159
|
+
end
|
160
|
+
|
161
|
+
unless value.is_a?(String) || value.is_a?(Symbol)
|
162
|
+
raise error_class,
|
163
|
+
message || "#{as} is not a String or a Symbol",
|
164
|
+
caller(1..-1)
|
165
|
+
end
|
166
|
+
|
167
|
+
return unless value.empty?
|
168
|
+
|
169
|
+
raise error_class, message || "#{as} can't be blank", caller(1..-1)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Asserts that the block returns a truthy value.
|
173
|
+
#
|
174
|
+
# @param message [String] The exception message to raise on a failure.
|
175
|
+
#
|
176
|
+
# @yield The block to evaluate.
|
177
|
+
# @yieldreturn [Object] The returned value of the block.
|
178
|
+
#
|
179
|
+
# @raise ArgumentError if the block does not return a truthy value.
|
180
|
+
def validate(message: nil, &block)
|
181
|
+
return if block.call
|
182
|
+
|
183
|
+
raise ArgumentError,
|
184
|
+
message || 'block returned a falsy value',
|
185
|
+
caller(1..-1)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Asserts that the value is either true or false.
|
189
|
+
#
|
190
|
+
# @param value [Object] The value to assert on.
|
191
|
+
# @param as [String] The name of the asserted value.
|
192
|
+
# @param message [String] The exception message to raise on a failure.
|
193
|
+
#
|
194
|
+
# @raise AssertionError if the value is not a Class.
|
195
|
+
def validate_boolean(value, as: 'value', message: nil)
|
196
|
+
return if value.equal?(true) || value.equal?(false)
|
197
|
+
|
198
|
+
raise ArgumentError,
|
199
|
+
message || "#{as} must be true or false",
|
200
|
+
caller(1..-1)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Asserts that the value is a Class.
|
204
|
+
#
|
205
|
+
# @param value [Object] The value to assert on.
|
206
|
+
# @param as [String] The name of the asserted value.
|
207
|
+
# @param message [String] The exception message to raise on a failure.
|
208
|
+
#
|
209
|
+
# @raise ArgumentError if the value is not a Class.
|
210
|
+
def validate_class(value, as: 'value', message: nil)
|
211
|
+
return if value.is_a?(Class)
|
212
|
+
|
213
|
+
raise ArgumentError,
|
214
|
+
message || "#{as} is not a Class",
|
215
|
+
caller(1..-1)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Asserts that the value is an example of the given Class.
|
219
|
+
#
|
220
|
+
# @param value [Object] The value to assert on.
|
221
|
+
# @param as [String] The name of the asserted value.
|
222
|
+
# @param expected [Class] The expected class.
|
223
|
+
# @param message [String] The exception message to raise on a failure.
|
224
|
+
# @param optional [true, false] If true, allows nil values.
|
225
|
+
#
|
226
|
+
# @raise ArgumentError if the expected class is not a Class.
|
227
|
+
# @raise AssertionError if the value is not an instance of the expected
|
228
|
+
# class.
|
229
|
+
def validate_instance_of(
|
230
|
+
value,
|
231
|
+
expected:,
|
232
|
+
as: 'value',
|
233
|
+
message: nil,
|
234
|
+
optional: false
|
235
|
+
)
|
236
|
+
unless expected.is_a?(Class)
|
237
|
+
raise ArgumentError, 'expected must be a Class'
|
238
|
+
end
|
239
|
+
|
240
|
+
return if optional && value.nil?
|
241
|
+
return if value.is_a?(expected)
|
242
|
+
|
243
|
+
raise ArgumentError,
|
244
|
+
message || "#{as} is not an instance of #{class_name(expected)}",
|
245
|
+
caller(1..-1)
|
246
|
+
end
|
247
|
+
|
248
|
+
# Asserts that the value matches the expected object using #===.
|
249
|
+
#
|
250
|
+
# @param value [Object] The value to assert on.
|
251
|
+
# @param as [String] The name of the asserted value.
|
252
|
+
# @param expected [#===] The expected object.
|
253
|
+
# @param message [String] The exception message to raise on a failure.
|
254
|
+
# @param optional [true, false] If true, allows nil values.
|
255
|
+
#
|
256
|
+
# @raise ArgumentError if the value does not match the expected object.
|
257
|
+
def validate_matches( # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
258
|
+
value,
|
259
|
+
expected:,
|
260
|
+
as: 'value',
|
261
|
+
message: nil,
|
262
|
+
optional: false
|
263
|
+
)
|
264
|
+
return if optional && value.nil?
|
265
|
+
return if expected === value # rubocop:disable Style/CaseEquality
|
266
|
+
|
267
|
+
message ||=
|
268
|
+
case expected
|
269
|
+
when Module
|
270
|
+
"#{as} is not an instance of #{class_name(expected)}"
|
271
|
+
when Proc
|
272
|
+
"#{as} does not match the Proc"
|
273
|
+
when Regexp
|
274
|
+
"#{as} does not match the pattern #{expected.inspect}"
|
275
|
+
else
|
276
|
+
"#{as} does not match the expected value"
|
277
|
+
end
|
278
|
+
|
279
|
+
raise ArgumentError, message, caller(1..-1)
|
280
|
+
end
|
281
|
+
|
282
|
+
# Asserts that the value is a non-empty String or Symbol.
|
283
|
+
#
|
284
|
+
# @param value [Object] The value to assert on.
|
285
|
+
# @param as [String] The name of the asserted value.
|
286
|
+
# @param message [String] The exception message to raise on a failure.
|
287
|
+
# @param optional [true, false] If true, allows nil values.
|
288
|
+
#
|
289
|
+
# @raise ArgumentError if the value is not a String or a Symbol, or if the
|
290
|
+
# value is empty.
|
291
|
+
def validate_name( # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
292
|
+
value,
|
293
|
+
as: 'value',
|
294
|
+
message: nil,
|
295
|
+
optional: false
|
296
|
+
)
|
297
|
+
if value.nil?
|
298
|
+
return if optional
|
299
|
+
|
300
|
+
raise ArgumentError, message || "#{as} can't be blank", caller(1..-1)
|
301
|
+
end
|
302
|
+
|
303
|
+
unless value.is_a?(String) || value.is_a?(Symbol)
|
304
|
+
raise ArgumentError,
|
305
|
+
message || "#{as} is not a String or a Symbol",
|
306
|
+
caller(1..-1)
|
307
|
+
end
|
308
|
+
|
309
|
+
return unless value.empty?
|
310
|
+
|
311
|
+
raise ArgumentError, message || "#{as} can't be blank", caller(1..-1)
|
312
|
+
end
|
313
|
+
|
314
|
+
private
|
315
|
+
|
316
|
+
def class_name(expected)
|
317
|
+
return expected.name if expected.name
|
318
|
+
|
319
|
+
"#{expected.inspect} (#{expected.ancestors.find(&:name).name})"
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
@@ -16,16 +16,28 @@ module SleepingKingStudios::Tools
|
|
16
16
|
:require_each
|
17
17
|
end
|
18
18
|
|
19
|
+
# @param deprecation_caller_depth [Integer] The number of backtrace lines to
|
20
|
+
# display when outputting a deprecation warning.
|
19
21
|
# @param deprecation_strategy [String] The name of the strategy used when
|
20
22
|
# deprecated code is called. Must be 'ignore', 'raise', or 'warn'.
|
21
|
-
def initialize(
|
23
|
+
def initialize(
|
24
|
+
deprecation_caller_depth: nil,
|
25
|
+
deprecation_strategy: nil
|
26
|
+
)
|
22
27
|
super()
|
23
28
|
|
29
|
+
@deprecation_caller_depth =
|
30
|
+
deprecation_caller_depth ||
|
31
|
+
ENV.fetch('DEPRECATION_CALLER_DEPTH', '3').to_i
|
24
32
|
@deprecation_strategy =
|
25
33
|
deprecation_strategy || ENV.fetch('DEPRECATION_STRATEGY', 'warn')
|
26
34
|
end
|
27
35
|
|
28
|
-
# @return [
|
36
|
+
# @return [Integer] the number of backtrace lines to display when outputting
|
37
|
+
# a deprecation warning.
|
38
|
+
attr_reader :deprecation_caller_depth
|
39
|
+
|
40
|
+
# @return [String] the current deprecation strategy.
|
29
41
|
attr_reader :deprecation_strategy
|
30
42
|
|
31
43
|
# @overload deprecate(name, message: nil)
|
@@ -92,19 +104,21 @@ module SleepingKingStudios::Tools
|
|
92
104
|
|
93
105
|
str = format % args
|
94
106
|
str << ' ' << message if message
|
95
|
-
|
96
|
-
str << "\n called from #{external_caller}"
|
107
|
+
str << format_caller
|
97
108
|
|
98
109
|
Kernel.warn str
|
99
110
|
end
|
100
111
|
|
101
|
-
def
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
line.include?('sleeping_king_studios-tools')
|
106
|
-
)
|
112
|
+
def format_caller
|
113
|
+
lines = caller
|
114
|
+
start = lines.find_index do |line|
|
115
|
+
!line.include?('forwardable.rb') &&
|
116
|
+
!line.include?('sleeping_king_studios-tools')
|
107
117
|
end
|
118
|
+
|
119
|
+
lines[start...(start + deprecation_caller_depth)]
|
120
|
+
.map { |line| "\n called from #{line}" }
|
121
|
+
.join
|
108
122
|
end
|
109
123
|
end
|
110
124
|
end
|
@@ -108,7 +108,7 @@ module SleepingKingStudios::Tools
|
|
108
108
|
# @return [Array<String>] The digits of the decomposed integer,
|
109
109
|
# represented as a bigendian array of strings.
|
110
110
|
def digits(integer, base: 10)
|
111
|
-
integer.to_s(base).
|
111
|
+
integer.to_s(base).chars
|
112
112
|
end
|
113
113
|
|
114
114
|
# Returns true if the object is an Integer.
|
@@ -177,8 +177,8 @@ module SleepingKingStudios::Tools
|
|
177
177
|
return if (ROMANIZE_MIN..ROMANIZE_MAX).include?(integer)
|
178
178
|
|
179
179
|
error_message =
|
180
|
-
"integer to romanize must be within range #{ROMANIZE_MIN} to" \
|
181
|
-
"
|
180
|
+
"integer to romanize must be within range #{ROMANIZE_MIN} to " \
|
181
|
+
"#{ROMANIZE_MAX}"
|
182
182
|
|
183
183
|
raise RangeError, error_message, caller(1..-1)
|
184
184
|
end
|
@@ -18,6 +18,7 @@ module SleepingKingStudios::Tools
|
|
18
18
|
# ActiveSupport::Inflector .
|
19
19
|
def initialize(deprecation_strategy: nil, inflector: nil)
|
20
20
|
@array_tools = ::SleepingKingStudios::Tools::ArrayTools.new
|
21
|
+
@assertions = ::SleepingKingStudios::Tools::Assertions.new
|
21
22
|
@core_tools = ::SleepingKingStudios::Tools::CoreTools.new(
|
22
23
|
deprecation_strategy: deprecation_strategy
|
23
24
|
)
|
@@ -30,6 +31,8 @@ module SleepingKingStudios::Tools
|
|
30
31
|
|
31
32
|
attr_reader :array_tools
|
32
33
|
|
34
|
+
attr_reader :assertions
|
35
|
+
|
33
36
|
attr_reader :core_tools
|
34
37
|
|
35
38
|
attr_reader :hash_tools
|
@@ -47,7 +47,7 @@ module SleepingKingStudios::Tools::Toolbox
|
|
47
47
|
|
48
48
|
word = word.to_s.gsub(/(\b|[_-])([a-z])/) { Regexp.last_match(2).upcase }
|
49
49
|
|
50
|
-
(uppercase_first_letter ? word[0].upcase : word[0].downcase) + word[1
|
50
|
+
(uppercase_first_letter ? word[0].upcase : word[0].downcase) + word[1..]
|
51
51
|
end
|
52
52
|
|
53
53
|
# rubocop:disable Metrics/AbcSize
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tools/toolbox'
|
4
|
+
|
5
|
+
module SleepingKingStudios::Tools::Toolbox
|
6
|
+
# Mixin for partially applying constructor parameters.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class Character
|
10
|
+
# extend SleepingKingStudios::Tools::Toolbox::Subclass
|
11
|
+
#
|
12
|
+
# def initialize(*traits)
|
13
|
+
# @traits = traits
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# attr_reader :traits
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# Bard = Character.subclass(:charismatic, :musical)
|
20
|
+
#
|
21
|
+
# aoife = Bard.new(:sorcerous)
|
22
|
+
# aoife.traits
|
23
|
+
# #=> [:charismatic, :musical, :sorcerous]
|
24
|
+
module Subclass
|
25
|
+
# Creates a subclass with partially applied constructor parameters.
|
26
|
+
#
|
27
|
+
# @param class_arguments [Array] The arguments, if any, to apply to the
|
28
|
+
# constructor. These arguments will be added before any args passed
|
29
|
+
# directly to the constructor.
|
30
|
+
# @param class_keywords [Hash] The keywords, if any, to apply to the
|
31
|
+
# constructor. These keywords will be added before any kwargs passed
|
32
|
+
# directly to the constructor.
|
33
|
+
#
|
34
|
+
# @yield The block, if any, to pass to the constructor. This will be
|
35
|
+
# overriden by a block passed directly to the constructor.
|
36
|
+
#
|
37
|
+
# @return [Class] the generated subclass.
|
38
|
+
def subclass(*class_arguments, **class_keywords, &class_block) # rubocop:disable Metrics/MethodLength
|
39
|
+
subclass = Class.new(self)
|
40
|
+
|
41
|
+
subclass.define_method :initialize do |*args, **kwargs, &block|
|
42
|
+
super(
|
43
|
+
*class_arguments,
|
44
|
+
*args,
|
45
|
+
**class_keywords,
|
46
|
+
**kwargs,
|
47
|
+
&(block || class_block)
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
subclass
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -6,5 +6,16 @@ module SleepingKingStudios::Tools
|
|
6
6
|
# Namespace for common objects or patterns that are useful across projects but
|
7
7
|
# are larger than or do not fit the functional paradigm of the tools.*
|
8
8
|
# pattern.
|
9
|
-
module Toolbox
|
9
|
+
module Toolbox
|
10
|
+
autoload :ConstantMap,
|
11
|
+
'sleeping_king_studios/tools/toolbox/constant_map'
|
12
|
+
autoload :Inflector,
|
13
|
+
'sleeping_king_studios/tools/toolbox/inflector'
|
14
|
+
autoload :Mixin,
|
15
|
+
'sleeping_king_studios/tools/toolbox/mixin'
|
16
|
+
autoload :SemanticVersion,
|
17
|
+
'sleeping_king_studios/tools/toolbox/semantic_version'
|
18
|
+
autoload :Subclass,
|
19
|
+
'sleeping_king_studios/tools/toolbox/subclass'
|
20
|
+
end
|
10
21
|
end
|
@@ -7,12 +7,14 @@ module SleepingKingStudios
|
|
7
7
|
module Tools
|
8
8
|
autoload :Base, 'sleeping_king_studios/tools/base'
|
9
9
|
autoload :ArrayTools, 'sleeping_king_studios/tools/array_tools'
|
10
|
+
autoload :Assertions, 'sleeping_king_studios/tools/assertions'
|
10
11
|
autoload :CoreTools, 'sleeping_king_studios/tools/core_tools'
|
11
12
|
autoload :HashTools, 'sleeping_king_studios/tools/hash_tools'
|
12
13
|
autoload :IntegerTools, 'sleeping_king_studios/tools/integer_tools'
|
13
14
|
autoload :ObjectTools, 'sleeping_king_studios/tools/object_tools'
|
14
15
|
autoload :StringTools, 'sleeping_king_studios/tools/string_tools'
|
15
16
|
autoload :Toolbelt, 'sleeping_king_studios/tools/toolbelt'
|
17
|
+
autoload :Toolbox, 'sleeping_king_studios/tools/toolbox'
|
16
18
|
autoload :Version, 'sleeping_king_studios/tools/version'
|
17
19
|
end
|
18
20
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sleeping_king_studios-tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob "Merlin" Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: byebug
|
@@ -58,42 +58,42 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '1.
|
61
|
+
version: '1.35'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '1.
|
68
|
+
version: '1.35'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rubocop-rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0.
|
75
|
+
version: '0.6'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0.
|
82
|
+
version: '0.6'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rubocop-rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '2.
|
89
|
+
version: '2.12'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '2.
|
96
|
+
version: '2.12'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: simplecov
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,28 +128,14 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '2.
|
131
|
+
version: '2.7'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '2.
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: sleeping_king_studios-tasks
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - "~>"
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: '0.4'
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - "~>"
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: '0.4'
|
138
|
+
version: '2.7'
|
153
139
|
description: |
|
154
140
|
A library of utility services and concerns to expand the functionality of
|
155
141
|
core classes without polluting the global namespace.
|
@@ -166,6 +152,7 @@ files:
|
|
166
152
|
- README.md
|
167
153
|
- lib/sleeping_king_studios/tools.rb
|
168
154
|
- lib/sleeping_king_studios/tools/array_tools.rb
|
155
|
+
- lib/sleeping_king_studios/tools/assertions.rb
|
169
156
|
- lib/sleeping_king_studios/tools/base.rb
|
170
157
|
- lib/sleeping_king_studios/tools/core_tools.rb
|
171
158
|
- lib/sleeping_king_studios/tools/hash_tools.rb
|
@@ -179,11 +166,15 @@ files:
|
|
179
166
|
- lib/sleeping_king_studios/tools/toolbox/inflector/rules.rb
|
180
167
|
- lib/sleeping_king_studios/tools/toolbox/mixin.rb
|
181
168
|
- lib/sleeping_king_studios/tools/toolbox/semantic_version.rb
|
169
|
+
- lib/sleeping_king_studios/tools/toolbox/subclass.rb
|
182
170
|
- lib/sleeping_king_studios/tools/version.rb
|
183
171
|
homepage: http://sleepingkingstudios.com
|
184
172
|
licenses:
|
185
173
|
- MIT
|
186
|
-
metadata:
|
174
|
+
metadata:
|
175
|
+
bug_tracker_uri: https://github.com/sleepingkingstudios/sleeping_king_studios-tools/issues
|
176
|
+
source_code_uri: https://github.com/sleepingkingstudios/sleeping_king_studios-tools
|
177
|
+
rubygems_mfa_required: 'true'
|
187
178
|
post_install_message:
|
188
179
|
rdoc_options: []
|
189
180
|
require_paths:
|
@@ -192,7 +183,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
192
183
|
requirements:
|
193
184
|
- - ">="
|
194
185
|
- !ruby/object:Gem::Version
|
195
|
-
version: 2.
|
186
|
+
version: 2.7.0
|
196
187
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
197
188
|
requirements:
|
198
189
|
- - ">="
|