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.
Files changed (27) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +32 -3
  3. data/DEVELOPMENT.md +5 -7
  4. data/README.md +3 -64
  5. data/lib/sleeping_king_studios/tools.rb +12 -6
  6. data/lib/sleeping_king_studios/tools/all.rb +8 -3
  7. data/lib/sleeping_king_studios/tools/array_tools.rb +83 -58
  8. data/lib/sleeping_king_studios/tools/base.rb +18 -0
  9. data/lib/sleeping_king_studios/tools/core_tools.rb +68 -22
  10. data/lib/sleeping_king_studios/tools/enumerable_tools.rb +6 -3
  11. data/lib/sleeping_king_studios/tools/hash_tools.rb +59 -47
  12. data/lib/sleeping_king_studios/tools/integer_tools.rb +97 -55
  13. data/lib/sleeping_king_studios/tools/object_tools.rb +67 -50
  14. data/lib/sleeping_king_studios/tools/string_tools.rb +81 -63
  15. data/lib/sleeping_king_studios/tools/toolbelt.rb +46 -22
  16. data/lib/sleeping_king_studios/tools/toolbox.rb +2 -2
  17. data/lib/sleeping_king_studios/tools/toolbox/configuration.rb +197 -122
  18. data/lib/sleeping_king_studios/tools/toolbox/constant_map.rb +24 -51
  19. data/lib/sleeping_king_studios/tools/toolbox/delegator.rb +50 -29
  20. data/lib/sleeping_king_studios/tools/toolbox/inflector.rb +130 -0
  21. data/lib/sleeping_king_studios/tools/toolbox/inflector/rules.rb +171 -0
  22. data/lib/sleeping_king_studios/tools/toolbox/mixin.rb +10 -10
  23. data/lib/sleeping_king_studios/tools/toolbox/semantic_version.rb +15 -14
  24. data/lib/sleeping_king_studios/tools/version.rb +6 -8
  25. metadata +84 -26
  26. data/lib/sleeping_king_studios/tools/semantic_version.rb +0 -15
  27. data/lib/sleeping_king_studios/tools/string_tools/plural_inflector.rb +0 -185
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 694e8a5ab01a8bbe5c689954d0c00a70045f13cd
4
- data.tar.gz: e6421ef4c5f581125590ef984c3b0f1281e45a36
2
+ SHA256:
3
+ metadata.gz: ec480f3a22706bc58097d0d85632d800ea2ec49994a6f1f0694e2f33ff0b3809
4
+ data.tar.gz: b4422c9ec69b876a987e78f84d13c89701704ab0ed7a61737812287595a72759
5
5
  SHA512:
6
- metadata.gz: 113e19e8b5e5f37906c3bd6dfa05e3bd7f400f3159d13b335128d40acaae22f6426bcd414bed58891661a21914962b98bcc5c9c4cf14d6819f5e4cd62e1c46d7
7
- data.tar.gz: 58b378e8326afd2ed60ad1487301c9e4e117bc6709c61543ff50a36b4805e432cd90f948eed78c0a710d11476115d4c31d51d4365ec5a9affc135ab2bbe70b81
6
+ metadata.gz: 054a259336cde5f020e7fa67e2370c3ecef621f1ca2ebdd4c0e28703887e23dbcc8178844b2b415e0fdde0ad2e60ed72040a436f009eadb4d059a5f27fafac35
7
+ data.tar.gz: 4b093d9a4c59900422d0b3851b04bccefc2aa5ee2b6dbed68a083aa8b511b47e84957c6d4dc71c997b24ede623584d07293161cfa5588fbe20e27ee6897aebd7
@@ -1,6 +1,37 @@
1
1
  # Changelog
2
2
 
3
- ## Current Release
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.
@@ -1,10 +1,12 @@
1
1
  # Development Notes
2
2
 
3
- ## 0.7.0
3
+ ## 1.0.0
4
4
 
5
- ## Future Tasks
5
+ - Remove sleeping_king_studios/tools/all
6
+ - Remove all deprecated methods and references.
7
+ - Documentation pass.
6
8
 
7
- - Remove 'extend self' from Tools modules.
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
- Module for extending classes with basic delegation.
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
- # lib/sleeping_king_studios/tools.rb
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 :Toolbelt, 'sleeping_king_studios/tools/toolbelt'
9
- end # module
10
- end # module
11
-
12
- require 'sleeping_king_studios/tools/version'
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
- # lib/sleeping_king_studios/tools/all.rb
1
+ # frozen_string_literal: true
2
2
 
3
- Dir[File.join File.dirname(__FILE__), '*_tools.rb'].each do |file|
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 # end each
10
+ end
@@ -1,34 +1,45 @@
1
- # lib/sleeping_king_studios/tools/array_tools.rb
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
- module ArrayTools
9
- extend self
10
-
11
- ARRAY_METHODS = [:[], :count, :each].freeze
12
- OTHER_METHODS = [:each_key, :each_pair].freeze
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? ary
20
- return true if Array === ary
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 # each
35
+ end
25
36
 
26
37
  OTHER_METHODS.each do |method_name|
27
38
  return false if ary.respond_to?(method_name)
28
- end # each
39
+ end
29
40
 
30
41
  true
31
- end # method array?
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 ary, &block
66
+ def bisect(ary)
56
67
  require_array! ary
57
68
 
58
- raise ArgumentError.new('no block given') unless block_given?
69
+ raise ArgumentError, 'no block given' unless block_given?
59
70
 
60
- selected, rejected = [], []
71
+ selected = []
72
+ rejected = []
61
73
 
62
74
  ary.each do |item|
63
75
  (yield(item) ? selected : rejected) << item
64
- end # each
76
+ end
65
77
 
66
78
  [selected, rejected]
67
- end # method bisect
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 ary, &block
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 # each
107
- end # method count_values
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 ary
128
+ def deep_dup(ary)
116
129
  require_array! ary
117
130
 
118
131
  ary.map { |obj| ObjectTools.deep_dup obj }
119
- end # method deep_dup
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 ary
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 # method deep_freeze
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(['spam', 'eggs', 'bacon', 'spam'], :last_separator => ' or ')
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 ary, options = {}, &block
185
+ def humanize_list(ary, **options, &block) # rubocop:disable Metrics/AbcSize
170
186
  require_array! ary
171
187
 
172
- ary = ary.map(&block) if block_given?
188
+ return '' if ary.empty?
173
189
 
174
- separator = options.fetch(:separator, ', ')
175
- last_separator = options.fetch(:last_separator, ' and ')
190
+ size = ary.size
191
+ ary = ary.map(&block) if block_given?
176
192
 
177
- case ary.count
178
- when 0
179
- ''
180
- when 1
181
- ary.first.to_s
182
- when 2
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
- "#{ary[0...-1].join(separator)}#{last_separator}#{ary.last}"
192
- end # case
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? ary
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 # method immutable?
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? ary
228
+ def mutable?(ary)
221
229
  !immutable?(ary)
222
- end # method mutable?
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, 'zweihänder'
246
+ # ArrayTools.splice values, 1, 0, 'zweihander'
239
247
  # #=> []
240
248
  # values
241
- # #=> ['longsword', 'zweihänder', 'broadsword', 'claymore']
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 ary, start, delete_count, *insert
268
+ def splice(ary, start, delete_count, *insert)
261
269
  require_array! ary
262
270
 
263
- start = start < 0 ? start + ary.count : 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 # method splice
278
+ end
271
279
 
272
280
  private
273
281
 
274
- def require_array! value
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 # method require_array
279
- end # module
280
- end # module
303
+ end
304
+ end
305
+ end