sleeping_king_studios-tools 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ec480f3a22706bc58097d0d85632d800ea2ec49994a6f1f0694e2f33ff0b3809
|
4
|
+
data.tar.gz: b4422c9ec69b876a987e78f84d13c89701704ab0ed7a61737812287595a72759
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 054a259336cde5f020e7fa67e2370c3ecef621f1ca2ebdd4c0e28703887e23dbcc8178844b2b415e0fdde0ad2e60ed72040a436f009eadb4d059a5f27fafac35
|
7
|
+
data.tar.gz: 4b093d9a4c59900422d0b3851b04bccefc2aa5ee2b6dbed68a083aa8b511b47e84957c6d4dc71c997b24ede623584d07293161cfa5588fbe20e27ee6897aebd7
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,37 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
|
3
|
+
### 0.8.0
|
4
|
+
|
5
|
+
Last minor release before 1.0.0.
|
6
|
+
|
7
|
+
This release adds a number of deprecations. All deprecated code will be removed
|
8
|
+
in version 1.0.0. Update dependent code accordingly.
|
9
|
+
|
10
|
+
- Removed deprecated SleepingKingStudios::Tools::SemanticVersion. This
|
11
|
+
functionality is still available as
|
12
|
+
SleepingKingStudios::Tools::Toolbox::SemanticVersion.
|
13
|
+
|
14
|
+
#### Tools
|
15
|
+
|
16
|
+
- Refactored all Tools modules to classes.
|
17
|
+
- Removed StringTools::PluralInflector. It's functionality is now handled by
|
18
|
+
Toolbox::Inflector.
|
19
|
+
- Added support for deprecation strategy to CoreTools#deprecate.
|
20
|
+
|
21
|
+
#### Toolbelt
|
22
|
+
|
23
|
+
- Refactored Toolbelt to reference Tools instances rather than classes.
|
24
|
+
- Defined new abbreviated helpers #ary, #hsh, #int, #obj, #str.
|
25
|
+
- Defined new helpers #array_tools, #core_tools, #hash_tools, #integer_tools,
|
26
|
+
#object_tools, #string_tools.
|
27
|
+
- Deprecated old abbreviated helpers #array, #core, #hash, #integer, #object,
|
28
|
+
#string.
|
29
|
+
|
30
|
+
#### Toolbox
|
31
|
+
|
32
|
+
- Deprecate Toolbox::Configuration. Use a struct instead.
|
33
|
+
- Deprecate Toolbox::Delegator. Use the stdlib Forwardable module instead.
|
34
|
+
- Implement Toolbox::Inflector, which serves as a delegate for StringTools.
|
4
35
|
|
5
36
|
### 0.7.1
|
6
37
|
|
@@ -25,8 +56,6 @@
|
|
25
56
|
- IntegerTools#pluralize now accepts 2..3 arguments, and will automatically generate the plural string using StringTools#pluralize if an explicit plural is not given.
|
26
57
|
- SleepingKingStudios::Tools::Toolbelt is now autoloaded from SleepingKingStudios::Tools.
|
27
58
|
|
28
|
-
## Previous Releases
|
29
|
-
|
30
59
|
### 0.6.0
|
31
60
|
|
32
61
|
- Implement HashTools#convert_keys_to_strings and #convert_keys_to_symbols.
|
data/DEVELOPMENT.md
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# Development Notes
|
2
2
|
|
3
|
-
## 0.
|
3
|
+
## 1.0.0
|
4
4
|
|
5
|
-
|
5
|
+
- Remove sleeping_king_studios/tools/all
|
6
|
+
- Remove all deprecated methods and references.
|
7
|
+
- Documentation pass.
|
6
8
|
|
7
|
-
|
9
|
+
## Future Tasks
|
8
10
|
|
9
11
|
### Features
|
10
12
|
|
@@ -20,7 +22,3 @@
|
|
20
22
|
- RegexpTools#nonmatching_strings - generates a set of strings that do not match the regular expression.
|
21
23
|
- Identity Methods
|
22
24
|
- RegexpTools#regexp? - true if object is regular expression, otherwise false.
|
23
|
-
|
24
|
-
### Maintenance
|
25
|
-
|
26
|
-
- Remove deprecated StringTools#pluralize(int, str, str) implementation.
|
data/README.md
CHANGED
@@ -695,6 +695,8 @@ Common objects or patterns that are useful across projects but are larger than o
|
|
695
695
|
|
696
696
|
require 'sleeping_king_studios/tools/toolbox/configuration'
|
697
697
|
|
698
|
+
This module is now deprecated. Use a struct instead.
|
699
|
+
|
698
700
|
Provides a simple DSL for defining configuration objects, which can be populated via hashes or data objects (such as a Rails configuration object).
|
699
701
|
|
700
702
|
class MyGemConfig < SleepingKingStudios::Tools::Toolbox::Configuration
|
@@ -783,70 +785,7 @@ Provides an enumerable interface for defining a group of constants.
|
|
783
785
|
|
784
786
|
require 'sleeping_king_studios/tools/toolbox/delegator'
|
785
787
|
|
786
|
-
|
787
|
-
|
788
|
-
class MyClass
|
789
|
-
extend SleepingKingStudios::Tools::Toolbox::Delegator
|
790
|
-
|
791
|
-
delegate :my_method, :to => MyService
|
792
|
-
end # class
|
793
|
-
|
794
|
-
#### `::delegate`
|
795
|
-
|
796
|
-
Defines a wrapper method to delegate implementation of the specified method or methods to an object, to the object at another specified method, or to the object at a specified instance variable.
|
797
|
-
|
798
|
-
# Delegate to an object
|
799
|
-
class MyModule
|
800
|
-
extend SleepingKingStudios::Tools::Toolbox::Delegator
|
801
|
-
|
802
|
-
delegate :my_method, :to => MyService
|
803
|
-
end class
|
804
|
-
|
805
|
-
# Delegate to a method
|
806
|
-
class MyModule
|
807
|
-
extend SleepingKingStudios::Tools::Toolbox::Delegator
|
808
|
-
|
809
|
-
def my_service
|
810
|
-
MyService.new
|
811
|
-
end method my_service
|
812
|
-
|
813
|
-
delegate :my_method, :to => :my_service
|
814
|
-
end class
|
815
|
-
|
816
|
-
# Delegate to an instance variable
|
817
|
-
class MyModule
|
818
|
-
extend SleepingKingStudios::Tools::Toolbox::Delegator
|
819
|
-
|
820
|
-
def initialize
|
821
|
-
@my_service = MyService.new
|
822
|
-
end constructor
|
823
|
-
|
824
|
-
delegate :my_method, :to => :@my_service
|
825
|
-
end class
|
826
|
-
|
827
|
-
Expects one or more method names and a delegation target, which can be an object literal, or the name of an method or instance variable as a String or Symbol. Defines a wrapper method to delegate implementation of the specified method or methods to an object, to the object at the another specified method, or to the object at the specified instance variable.
|
828
|
-
|
829
|
-
#### `::wrap_delegate`
|
830
|
-
|
831
|
-
Wraps a delegate object by automatically delegating each method that is defined on the delegate class from the instance to the delegate. The delegate can be specified with an object literal or with the name of an instance method or instance variable.
|
832
|
-
|
833
|
-
Only methods that are defined at the time #wrap_delegate is called will be delegated, so make sure to call #wrap_delegate after loading any gems or libraries that extend your delegate class, such as ActiveSupport.
|
834
|
-
|
835
|
-
# Create a class that wraps a Hash
|
836
|
-
class Errors
|
837
|
-
extend SleepingKingStudios::Tools::Toolbox::Delegator
|
838
|
-
|
839
|
-
wrap_delegate Hash.new { |hsh, key| hsh[key] = Errors.new }, :klass => Hash
|
840
|
-
|
841
|
-
def messages
|
842
|
-
@messages ||= []
|
843
|
-
end # method messages
|
844
|
-
end # class
|
845
|
-
|
846
|
-
errors = Errors.new
|
847
|
-
errors[:post].messages << "title can't be blank"
|
848
|
-
|
849
|
-
Expects a delegation target and optionally a class or module (to determine which methods to delegate), as well as optional :except and :only arrays to limit which methods are delegated. The delegation target can be an object literal, or the name of an method or instance variable as a String or Symbol (in which case a class or module must be specified in :klass or an ArgumentError will be raised).
|
788
|
+
This module is now deprecated. Use the stdlib `Forwardable` module instead.
|
850
789
|
|
851
790
|
### Mixin
|
852
791
|
|
@@ -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,5 +1,10 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'sleeping_king_studios/tools'
|
4
|
+
|
5
|
+
SleepingKingStudios::Tools::CoreTools
|
6
|
+
.deprecate('sleeping_king_studios/tools/all')
|
7
|
+
|
8
|
+
Dir[File.join File.dirname(__FILE__), '*_tools.rb'].sort.each do |file|
|
4
9
|
require file
|
5
|
-
end
|
10
|
+
end
|
@@ -1,34 +1,45 @@
|
|
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
|
+
ARRAY_METHODS = %i[[] count each].freeze
|
9
|
+
OTHER_METHODS = %i[each_key each_pair].freeze
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def_delegators :instance,
|
13
|
+
:array?,
|
14
|
+
:bisect,
|
15
|
+
:count_values,
|
16
|
+
:deep_dup,
|
17
|
+
:deep_freeze,
|
18
|
+
:humanize_list,
|
19
|
+
:immutable?,
|
20
|
+
:mutable?,
|
21
|
+
:splice,
|
22
|
+
:tally
|
23
|
+
end
|
13
24
|
|
14
25
|
# Returns true if the object is or appears to be an Array.
|
15
26
|
#
|
16
27
|
# @param ary [Object] The object to test.
|
17
28
|
#
|
18
29
|
# @return [Boolean] True if the object is an Array, otherwise false.
|
19
|
-
def array?
|
20
|
-
return true if Array
|
30
|
+
def array?(ary)
|
31
|
+
return true if ary.is_a?(Array)
|
21
32
|
|
22
33
|
ARRAY_METHODS.each do |method_name|
|
23
34
|
return false unless ary.respond_to?(method_name)
|
24
|
-
end
|
35
|
+
end
|
25
36
|
|
26
37
|
OTHER_METHODS.each do |method_name|
|
27
38
|
return false if ary.respond_to?(method_name)
|
28
|
-
end
|
39
|
+
end
|
29
40
|
|
30
41
|
true
|
31
|
-
end
|
42
|
+
end
|
32
43
|
|
33
44
|
# Separates the array into two arrays, the first containing all items in the
|
34
45
|
# original array that matches the provided block, and the second containing
|
@@ -52,19 +63,20 @@ module SleepingKingStudios::Tools
|
|
52
63
|
# if no block is given.
|
53
64
|
#
|
54
65
|
# @return [Array<Array<Object>>] An array containing two arrays.
|
55
|
-
def bisect
|
66
|
+
def bisect(ary)
|
56
67
|
require_array! ary
|
57
68
|
|
58
|
-
raise ArgumentError
|
69
|
+
raise ArgumentError, 'no block given' unless block_given?
|
59
70
|
|
60
|
-
selected
|
71
|
+
selected = []
|
72
|
+
rejected = []
|
61
73
|
|
62
74
|
ary.each do |item|
|
63
75
|
(yield(item) ? selected : rejected) << item
|
64
|
-
end
|
76
|
+
end
|
65
77
|
|
66
78
|
[selected, rejected]
|
67
|
-
end
|
79
|
+
end
|
68
80
|
|
69
81
|
# @overload count_values(ary)
|
70
82
|
# Counts the number of times each value appears in the enumerable object.
|
@@ -96,15 +108,16 @@ module SleepingKingStudios::Tools
|
|
96
108
|
#
|
97
109
|
# @return [Hash{Object, Integer}] The number of times each result
|
98
110
|
# appears.
|
99
|
-
def count_values
|
111
|
+
def count_values(ary, &block)
|
100
112
|
require_array! ary
|
101
113
|
|
102
114
|
ary.each.with_object({}) do |item, hsh|
|
103
115
|
value = block_given? ? block.call(item) : item
|
104
116
|
|
105
117
|
hsh[value] = hsh.fetch(value, 0) + 1
|
106
|
-
end
|
107
|
-
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
alias tally count_values
|
108
121
|
|
109
122
|
# Creates a deep copy of the object by returning a new Array with deep
|
110
123
|
# copies of each array item.
|
@@ -112,22 +125,22 @@ module SleepingKingStudios::Tools
|
|
112
125
|
# @param [Array<Object>] ary The array to copy.
|
113
126
|
#
|
114
127
|
# @return [Array] The copy of the array.
|
115
|
-
def deep_dup
|
128
|
+
def deep_dup(ary)
|
116
129
|
require_array! ary
|
117
130
|
|
118
131
|
ary.map { |obj| ObjectTools.deep_dup obj }
|
119
|
-
end
|
132
|
+
end
|
120
133
|
|
121
134
|
# Freezes the array and performs a deep freeze on each array item.
|
122
135
|
#
|
123
136
|
# @param [Array] ary The object to freeze.
|
124
|
-
def deep_freeze
|
137
|
+
def deep_freeze(ary)
|
125
138
|
require_array! ary
|
126
139
|
|
127
140
|
ary.freeze
|
128
141
|
|
129
142
|
ary.each { |obj| ObjectTools.deep_freeze obj }
|
130
|
-
end
|
143
|
+
end
|
131
144
|
|
132
145
|
# Accepts a list of values and returns a human-readable string of the
|
133
146
|
# values, with the format based on the number of items.
|
@@ -149,7 +162,10 @@ module SleepingKingStudios::Tools
|
|
149
162
|
# #=> 'spam, eggs, bacon, and spam'
|
150
163
|
#
|
151
164
|
# @example With Three Or More Items And Options
|
152
|
-
# ArrayTools.humanize_list(
|
165
|
+
# ArrayTools.humanize_list(
|
166
|
+
# ['spam', 'eggs', 'bacon', 'spam'],
|
167
|
+
# :last_separator => ' or '
|
168
|
+
# )
|
153
169
|
# #=> 'spam, eggs, bacon, or spam'
|
154
170
|
#
|
155
171
|
# @param [Array<String>] ary The list of values to format. Will be
|
@@ -166,31 +182,23 @@ module SleepingKingStudios::Tools
|
|
166
182
|
# @raise ArgumentError If the first argument is not an Array-like object.
|
167
183
|
#
|
168
184
|
# @return [String] The formatted string.
|
169
|
-
def humanize_list
|
185
|
+
def humanize_list(ary, **options, &block) # rubocop:disable Metrics/AbcSize
|
170
186
|
require_array! ary
|
171
187
|
|
172
|
-
|
188
|
+
return '' if ary.empty?
|
173
189
|
|
174
|
-
|
175
|
-
|
190
|
+
size = ary.size
|
191
|
+
ary = ary.map(&block) if block_given?
|
176
192
|
|
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
|
193
|
+
return ary[0].to_s if size == 1
|
194
|
+
|
195
|
+
separator, last_separator =
|
196
|
+
options_for_humanize_list(size: size, **options)
|
197
|
+
|
198
|
+
return "#{ary[0]}#{last_separator}#{ary[1]}" if size == 2
|
190
199
|
|
191
|
-
|
192
|
-
|
193
|
-
end # method humanize_list
|
200
|
+
"#{ary[0...-1].join(separator)}#{last_separator}#{ary.last}"
|
201
|
+
end
|
194
202
|
|
195
203
|
# Returns true if the array is immutable, i.e. the array is frozen and each
|
196
204
|
# array item is immutable.
|
@@ -200,7 +208,7 @@ module SleepingKingStudios::Tools
|
|
200
208
|
# @return [Boolean] True if the array is immutable, otherwise false.
|
201
209
|
#
|
202
210
|
# @see ObjectTools#immutable?
|
203
|
-
def immutable?
|
211
|
+
def immutable?(ary)
|
204
212
|
require_array! ary
|
205
213
|
|
206
214
|
return false unless ary.frozen?
|
@@ -208,7 +216,7 @@ module SleepingKingStudios::Tools
|
|
208
216
|
ary.each { |item| return false unless ObjectTools.immutable?(item) }
|
209
217
|
|
210
218
|
true
|
211
|
-
end
|
219
|
+
end
|
212
220
|
|
213
221
|
# Returns true if the array is mutable.
|
214
222
|
#
|
@@ -217,9 +225,9 @@ module SleepingKingStudios::Tools
|
|
217
225
|
# @return [Boolean] True if the array is mutable, otherwise false.
|
218
226
|
#
|
219
227
|
# @see #immutable?
|
220
|
-
def mutable?
|
228
|
+
def mutable?(ary)
|
221
229
|
!immutable?(ary)
|
222
|
-
end
|
230
|
+
end
|
223
231
|
|
224
232
|
# Accepts an array, a start value, a number of items to delete, and zero or
|
225
233
|
# more items to insert at that index. Deletes the specified number of items,
|
@@ -235,10 +243,10 @@ module SleepingKingStudios::Tools
|
|
235
243
|
#
|
236
244
|
# @example Inserting items into an Array
|
237
245
|
# values = %w(longsword broadsword claymore)
|
238
|
-
# ArrayTools.splice values, 1, 0, '
|
246
|
+
# ArrayTools.splice values, 1, 0, 'zweihander'
|
239
247
|
# #=> []
|
240
248
|
# values
|
241
|
-
# #=> ['longsword', '
|
249
|
+
# #=> ['longsword', 'zweihander', 'broadsword', 'claymore']
|
242
250
|
#
|
243
251
|
# @example Inserting and deleting items
|
244
252
|
# values = %w(shortbow longbow crossbow)
|
@@ -257,24 +265,41 @@ module SleepingKingStudios::Tools
|
|
257
265
|
#
|
258
266
|
# @return [Array<Object>] The deleted items, or an empty array if no items
|
259
267
|
# were deleted.
|
260
|
-
def splice
|
268
|
+
def splice(ary, start, delete_count, *insert)
|
261
269
|
require_array! ary
|
262
270
|
|
263
|
-
start = start
|
271
|
+
start = start.negative? ? start + ary.count : start
|
264
272
|
range = start...(start + delete_count)
|
265
273
|
deleted = ary[range]
|
266
274
|
|
267
275
|
ary[range] = insert
|
268
276
|
|
269
277
|
deleted
|
270
|
-
end
|
278
|
+
end
|
271
279
|
|
272
280
|
private
|
273
281
|
|
274
|
-
def
|
282
|
+
def options_for_humanize_list(
|
283
|
+
last_separator: ' and ',
|
284
|
+
separator: ', ',
|
285
|
+
size:
|
286
|
+
)
|
287
|
+
return [separator, last_separator] if size < 3
|
288
|
+
|
289
|
+
last_separator =
|
290
|
+
if last_separator =~ /\A,?\s*/
|
291
|
+
last_separator.sub(/\A,?\s*/, separator)
|
292
|
+
else
|
293
|
+
"#{separator}#{last_separator}"
|
294
|
+
end
|
295
|
+
|
296
|
+
[separator, last_separator]
|
297
|
+
end
|
298
|
+
|
299
|
+
def require_array!(value)
|
275
300
|
return if array?(value)
|
276
301
|
|
277
302
|
raise ArgumentError, 'argument must be an array', caller[1..-1]
|
278
|
-
end
|
279
|
-
end
|
280
|
-
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|