sleeping_king_studios-tools 0.4.0 → 0.5.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f296e034d67c6ae33d69e7e40ccbdb62eaa65cdf
4
- data.tar.gz: 694ed1dc928edc084e9aa54453c8944ab25f8937
3
+ metadata.gz: 2cae6265d25b7d2972d938909435e59949c77b23
4
+ data.tar.gz: 3471511cbcdd63bfed0a61eb5681a8b8c0328f71
5
5
  SHA512:
6
- metadata.gz: 521bc036894b1f5eaaf08a512875f7d4adac55abfc63166a36be39ef3ade2d827fdc48c454fff4385ffda5ae32ed4128cdc86e85ce9496ce727c7c3f6b426f28
7
- data.tar.gz: bdec4ed0afeae762c0402507910a80a1e7572c8ee19389a69938393ff935f3c66fa5c7d6ea78ec8aa6d273b03f002a9ef702f82074a62aba1404485d22736304
6
+ metadata.gz: 4860968042c42af8a2309a5c178fe0885e69efc645fb87880f8fb2266607a14b0b312d71c4993a392f516c1a155acd044d1c23b2344238b9c3b73c0455409a9a
7
+ data.tar.gz: dc6074d5dac36aeebb47fccd5e904e1e6deac3aa48c07c95217b1f601d2cf4ac83681b0e5b107ea4fa17d36a2e92183cd091479ef3cadc11920aefc248f68707
data/CHANGELOG.md CHANGED
@@ -2,6 +2,29 @@
2
2
 
3
3
  ## Pre-release Versions
4
4
 
5
+ ### 0.5.0
6
+
7
+ - Implement CoreTools#require_each.
8
+ - Implement StringTools#camelize.
9
+ - Add an optional block argument to ArrayTools#humanize_list.
10
+
11
+ #### Toolbox
12
+
13
+ - Implement Delegator#delegate, Delegator#wrap_delegate.
14
+ - Refactor SemanticVersion to the Toolbox namespace. Accessing SemanticVersion as Tools::SemanticVersion is now deprecated, use Tools::Toolbox::SemanticVersion.
15
+
16
+ #### Identity Methods
17
+
18
+ - Implement a set of methods to classify objects by type: ArrayTools#array?, HashTools#hash?, IntegerTools#integer?, ObjectTools#object?, and StringTools#string?.
19
+
20
+ #### Mutability Methods
21
+
22
+ Implement #immutable? and #mutable? for ObjectTools, ArrayTools, and HashTools, which indicate whether or not a given object is mutable.
23
+
24
+ Implement #deep_freeze for ObjectTools, ArrayTools, and HashTools which recursively freezes the object and any children (array items, hash keys, and hash values).
25
+
26
+ ## Current Release
27
+
5
28
  ### 0.4.0
6
29
 
7
30
  #### CoreTools
@@ -16,8 +39,6 @@ Implement #pluralize.
16
39
 
17
40
  Implement #pluralize and #singularize. The previous behavior of #pluralize is deprecated; use IntegerTools#pluralize.
18
41
 
19
- ## Current Release
20
-
21
42
  ### 0.3.0
22
43
 
23
44
  Implement ArrayTools#bisect and ArrayTools#splice.
data/DEVELOPMENT.md CHANGED
@@ -1,30 +1,5 @@
1
1
  # Development Notes
2
2
 
3
- ## Version 0.5.0 - The Cold Update
4
-
5
- - ObjectTools#immutable? - delegates to specific toolset implementations.
6
- - Values of `nil`, `false`, and `true` are always immutable, as are instances of `Numeric` and `Symbol`.
7
- - Arrays are immutable if the array is frozen and all items are immutable.
8
- - Hashes are immutable if the hash is frozen and all keys and values are immutable.
9
- - All other objects are only immutable if the object is frozen.
10
- - ObjectTools#freeze - delegates to specific toolset implementation
11
- - Arrays freeze the collection and each item
12
- - Hashes freeze the collection and each key and value
13
- - ObjectTools#frozen_copy
14
-
15
- ## Version 0.6.0 - The Identity Update
16
-
17
- ### Features
18
-
19
- - Identity Methods
20
- - ArrayTools#array? - true if object is array-like
21
- - HashTools#hash? - true if object is hash-like
22
- - IntegerTools#integer? - true if object is integer
23
- - ObjectTools#object? - true if object is object-like (not BasicObject!)
24
- - StringTools#string? - true if object is string
25
- - s/is/is or claims to be a/ - see http://guides.rubyonrails.org/active_support_core_extensions.html#acts-like-questionmark-duck
26
- - StringTools#humanize_list - accept a block. If block given, yield each item and join the results.
27
-
28
3
  ## Future Tasks
29
4
 
30
5
  - Remove 'extend self' from Tools modules.
@@ -33,6 +8,11 @@
33
8
 
34
9
  #### Tools
35
10
 
11
+ - StringTools#chain |
12
+
13
+ tools.chain(str, :underscore, :pluralize)
14
+ #=> shorthand for tools.pluralize(tools.underscore str)
15
+
36
16
  - ObjectTools#pretty - returns user-friendly string representation. :multiline option? Delegates to specific toolset implementations.
37
17
  - RegexpTools#matching_string - generates a string that matches the regular expression. Does not support advanced Regexp features.
38
18
  - RegexpTools#nonmatching_strings - generates a set of strings that do not match the regular expression.
data/README.md CHANGED
@@ -35,6 +35,17 @@ The tools can be accessed in a convenient form using the Toolbelt class.
35
35
 
36
36
  Tools for working with array-like enumerable objects.
37
37
 
38
+ #### `#array?`
39
+
40
+ Returns true if the object is or appears to be an Array.
41
+
42
+ ArrayTools.array?(nil)
43
+ #=> false
44
+ ArrayTools.array?([])
45
+ #=> true
46
+ ArrayTools.array?({})
47
+ #=> false
48
+
38
49
  #### `#bisect`
39
50
 
40
51
  Separates the array into two arrays, the first containing all items in the original array that matches the provided block, and the second containing all items in the original array that do not match the provided block.
@@ -76,6 +87,18 @@ Creates a deep copy of the object by returning a new Array with deep copies of e
76
87
  ary
77
88
  #=> ['one', 'two', 'three']
78
89
 
90
+ #### `#deep_freeze`
91
+
92
+ Freezes the array and performs a deep freeze on each array item. See also ObjectTools#deep_freeze[#label-Object+Tools].
93
+
94
+ ary = ['one', 'two', 'three']
95
+ ArrayTools.deep_freeze ary
96
+
97
+ ary.frozen?
98
+ #=> true
99
+ ary.first.frozen?
100
+ #=> true
101
+
79
102
  #### `#humanize_list`
80
103
 
81
104
  Accepts a list of values and returns a human-readable string of the values, with the format based on the number of items.
@@ -92,6 +115,33 @@ Accepts a list of values and returns a human-readable string of the values, with
92
115
  ArrayTools.humanize_list(['spam', 'eggs', 'bacon', 'spam'])
93
116
  #=> 'spam, eggs, bacon, and spam'
94
117
 
118
+ # With A Block
119
+ ArrayTools.humanize_list(['bronze', 'silver', 'gold'], { |str| str.capitalize })
120
+ #=> 'Bronze, Silver, and Gold'
121
+
122
+ #### `#immutable?`
123
+
124
+ Returns true if the array is immutable, i.e. the array is frozen and each array item is immutable.
125
+
126
+ ArrayTools.immutable?([1, 2, 3])
127
+ #=> false
128
+
129
+ ArrayTools.immutable?([1, 2, 3].freeze)
130
+ #=> true
131
+
132
+ ArrayTools.immutable?(['ichi', 'ni', 'san'])
133
+ #=> false
134
+
135
+ ArrayTools.immutable?(['ichi', 'ni', 'san'].freeze)
136
+ #=> false
137
+
138
+ ArrayTools.immutable?(['ichi'.freeze, 'ni'.freeze, 'san'.freeze].freeze)
139
+ #=> true
140
+
141
+ #### `#mutable?`
142
+
143
+ Returns true if the array is mutable (see `#immutable?`, above).
144
+
95
145
  #### `#splice`
96
146
 
97
147
  Accepts an array, a start value, a number of items to delete, and zero or more items to insert at that index. Deletes the specified number of items, then inserts the given items at the index and returns the array of deleted items.
@@ -121,7 +171,7 @@ Accepts an array, a start value, a number of items to delete, and zero or more i
121
171
 
122
172
  Tools for working with an application or working environment.
123
173
 
124
- #### '#deprecate'
174
+ #### `#deprecate`
125
175
 
126
176
  Prints a deprecation warning.
127
177
 
@@ -137,6 +187,16 @@ Prints a deprecation warning.
137
187
  ObjectTools#old_method was deprecated in version 0.1.0.
138
188
  called from /path/to/file.rb:4: in something_or_other
139
189
 
190
+ #### `#require_each`
191
+
192
+ Takes a file pattern or a list of file names and requires each file.
193
+
194
+ CoreTools.require_each '/path/to/one', '/path/to/two', '/path/to/three'
195
+ #=> Requires each file.
196
+
197
+ CoreTools.require_each '/path/to/directory/**/*.rb'
198
+ #=> Requires each file matching the pattern.
199
+
140
200
  ### Hash Tools
141
201
 
142
202
  Tools for working with array-like enumerable objects.
@@ -158,6 +218,46 @@ Creates a deep copy of the object by returning a new Hash with deep copies of ea
158
218
  hsh
159
219
  #=> { :one => 'one', :two => 'two', :three => 'three' }
160
220
 
221
+ #### `#deep_freeze`
222
+
223
+ Freezes the hash and performs a deep freeze on each hash key and value.
224
+
225
+ hsh = { :one => 'one', :two => 'two', :three => 'three' }
226
+ HashTools.deep_freeze hsh
227
+
228
+ hsh.frozen?
229
+ #=> true
230
+ hsh[:one].frozen?
231
+ #=> true
232
+
233
+ #### `#hash?`
234
+
235
+ Returns true if the object is or appears to be a Hash.
236
+
237
+ HashTools.hash?(nil)
238
+ #=> false
239
+ HashTools.hash?([])
240
+ #=> false
241
+ HashTools.hash?({})
242
+ #=> true
243
+
244
+ #### `#immutable?`
245
+
246
+ Returns true if the hash is immutable, i.e. if the hash is frozen and each hash key and hash value are immutable.
247
+
248
+ HashTools.immutable?({ :id => 0, :title => 'The Ramayana' })
249
+ #=> false
250
+
251
+ HashTools.immutable?({ :id => 0, :title => 'The Ramayana' }.freeze)
252
+ #=> false
253
+
254
+ HashTools.immutable?({ :id => 0, :title => 'The Ramayana'.freeze }.freeze)
255
+ #=> true
256
+
257
+ #### `#mutable?`
258
+
259
+ Returns true if the hash is mutable (see `#immutable?`, above).
260
+
161
261
  ### Integer Tools
162
262
 
163
263
  Tools for working with integers and fixnums.
@@ -198,6 +298,19 @@ Decomposes the given integer into its digits when represented in the given base.
198
298
  IntegerTools.digits(16724838)
199
299
  #=> ['f', 'f', '3', '3', '6', '6']
200
300
 
301
+ #### `#integer?`
302
+
303
+ Returns true if the object is an Integer.
304
+
305
+ IntegerTools.integer?(nil)
306
+ #=> false
307
+ IntegerTools.integer?([])
308
+ #=> false
309
+ IntegerTools.integer?({})
310
+ #=> false
311
+ IntegerTools.integer?(1)
312
+ #=> true
313
+
201
314
  #### `#pluralize`
202
315
 
203
316
  Returns the singular or the plural value, depending on the provided item count.
@@ -262,6 +375,40 @@ Creates a deep copy of the object. If the object is an Array, returns a new Arra
262
375
  data[:songs][1]
263
376
  #=> { :name => 'Hells Bells', :artist => 'AC/DC', :album => 'Back in Black' }
264
377
 
378
+ #### `#deep_freeze`
379
+
380
+ Performs a deep freeze of the object. If the object is an Array, freezes the array and performs a deep freeze on each array item (see ArrayTools#deep_dup[#label-Array+Tools]). If the object is a hash, freezes the hash and performs a deep freeze on each hash key and value (see HashTools#deep_dup[#label-Hash+Tools]). Otherwise, calls Object#freeze unless the object is already immutable.
381
+
382
+ data = {
383
+ :songs = [
384
+ {
385
+ :name => 'Welcome to the Jungle',
386
+ :artist => "Guns N' Roses",
387
+ :album => 'Appetite for Destruction'
388
+ }, # end hash
389
+ {
390
+ :name => 'Hells Bells',
391
+ :artist => 'AC/DC',
392
+ :album => 'Back in Black'
393
+ }, # end hash
394
+ {
395
+ :name => "Knockin' on Heaven's Door",
396
+ :artist => 'Bob Dylan',
397
+ :album => 'Pat Garrett & Billy The Kid'
398
+ } # end hash
399
+ ] # end array
400
+ } # end hash
401
+ ObjectTools.deep_freeze(data)
402
+
403
+ data.frozen?
404
+ #=> true
405
+ data[:songs].frozen?
406
+ #=> true
407
+ data[:songs][0].frozen?
408
+ #=> true
409
+ data[:songs][0].name.frozen?
410
+ #=> true
411
+
265
412
  #### `#eigenclass`, `#metaclass`
266
413
 
267
414
  Returns the object's eigenclass.
@@ -269,12 +416,75 @@ Returns the object's eigenclass.
269
416
  ObjectTools.eigenclass my_object
270
417
  #=> Shortcut for class << self; self; end.
271
418
 
419
+ #### `#immutable?`
420
+
421
+ Returns true if the object is immutable. Values of nil, false, and true are always immutable, as are instances of Numeric and Symbol. Arrays are immutable if the array is frozen and each array item is immutable. Hashes are immutable if the hash is frozen and each hash key and hash value are immutable. Otherwise, objects are immutable if they are frozen.
422
+
423
+ ObjectTools.immutable?(nil)
424
+ #=> true
425
+
426
+ ObjectTools.immutable?(false)
427
+ #=> true
428
+
429
+ ObjectTools.immutable?(0)
430
+ #=> true
431
+
432
+ ObjectTools.immutable?(:hello)
433
+ #=> true
434
+
435
+ ObjectTools.immutable?("Greetings, programs!")
436
+ #=> false
437
+
438
+ ObjectTools.immutable?([1, 2, 3])
439
+ #=> false
440
+
441
+ ObjectTools.immutable?([1, 2, 3].freeze)
442
+ #=> false
443
+
444
+ #### `#mutable?`
445
+
446
+ Returns true if the object is mutable (see `#immutable?`, above).
447
+
448
+ #### `#object?`
449
+
450
+ Returns true if the object is an Object.
451
+
452
+ ObjectTools.object?(nil)
453
+ #=> true
454
+ ObjectTools.object?([])
455
+ #=> true
456
+ ObjectTools.object?({})
457
+ #=> true
458
+ ObjectTools.object?(1)
459
+ #=> true
460
+ ObjectTools.object?(BasicObject.new)
461
+ #=> false
462
+
463
+ #### `#try`
464
+
465
+ As #send, but returns nil if the object does not respond to the method.
466
+
467
+ ObjectTools.try(%w(ichi ni san), :count)
468
+ #=> 3
469
+ ObjectTools.try(nil, :count)
470
+ #=> nil
471
+
272
472
  ### String Tools
273
473
 
274
474
  require 'sleeping_king_studios/tools/string_tools'
275
475
 
276
476
  Tools for working with strings.
277
477
 
478
+ #### `#camelize`
479
+
480
+ Converts a lowercase, underscore separated string to a mixed-case string expression, as per ActiveSupport::Inflector#camelize.
481
+
482
+ StringTools#camelize 'valhalla'
483
+ #=> 'Valhalla'
484
+
485
+ StringTools#camelize 'muspelheimr_and_niflheimr'
486
+ #=> 'MuspelheimrAndNiflheimr'
487
+
278
488
  #### `#pluralize`
279
489
 
280
490
  Takes a word in singular form and returns the plural form, based on the defined rules and known irregular/uncountable words.
@@ -316,20 +526,113 @@ Takes a word in plural form and returns the singular form, based on the defined
316
526
  StringTools.singularize 'elves'
317
527
  #=> 'elf'
318
528
 
529
+ #### `#string?`
530
+
531
+ Returns true if the object is a String.
532
+
533
+ StringTools.string?(nil)
534
+ #=> false
535
+ StringTools.string?([])
536
+ #=> false
537
+ StringTools.string?('Greetings, programs!')
538
+ #=> true
539
+ StringTools.string?(:greetings_starfighter)
540
+ #=> false
541
+
319
542
  #### `#underscore`
320
543
 
321
544
  Converts a mixed-case string expression to a lowercase, underscore separated string, as per ActiveSupport::Inflector#underscore.
322
545
 
323
- ## Additional Features
546
+ StringTools#underscore 'Bifrost'
547
+ #=> 'bifrost'
548
+
549
+ StringTools#underscore 'FenrisWolf'
550
+ #=> 'fenris_wolf'
551
+
552
+ ## Toolbox
553
+
554
+ Common objects or patterns that are useful across projects but are larger than or do not fit the functional paradigm of the tools.* pattern.
555
+
556
+ ### Delegator
557
+
558
+ require 'sleeping_king_studios/tools/delegator'
559
+
560
+ require 'sleeping_king_studios/tools/toolbox/delegator'
561
+
562
+ class MyClass
563
+ extend SleepingKingStudios::Tools::Delegator
564
+
565
+ delegate :my_method, :to => MyService
566
+ end # class
567
+
568
+ Module for extending classes with basic delegation.
569
+
570
+ #### `::delegate`
571
+
572
+ 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.
573
+
574
+ # Delegate to an object
575
+ class MyModule
576
+ extend SleepingKingStudios::Tools::Delegator
577
+
578
+ delegate :my_method, :to => MyService
579
+ end class
580
+
581
+ # Delegate to a method
582
+ class MyModule
583
+ extend SleepingKingStudios::Tools::Delegator
584
+
585
+ def my_service
586
+ MyService.new
587
+ end method my_service
588
+
589
+ delegate :my_method, :to => :my_service
590
+ end class
591
+
592
+ # Delegate to an instance variable
593
+ class MyModule
594
+ extend SleepingKingStudios::Tools::Delegator
595
+
596
+ def initialize
597
+ @my_service = MyService.new
598
+ end constructor
599
+
600
+ delegate :my_method, :to => :@my_service
601
+ end class
602
+
603
+ 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.
604
+
605
+ #### `::wrap_delegate`
606
+
607
+ Wraps a delegate object by automatically delegating each method that is defined on the delegate class from the instance to the delegate. The
608
+ delegate can be specified with an object literal or with the name of an instance method or instance variable.
609
+
610
+ 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.
611
+
612
+ # Create a class that wraps a Hash
613
+ class Errors
614
+ extend SleepingKingStudios::Tools::Delegator
615
+
616
+ wrap_delegate Hash.new { |hsh, key| hsh[key] = Errors.new }, :klass => Hash
617
+
618
+ def messages
619
+ @messages ||= []
620
+ end # method messages
621
+ end # class
622
+
623
+ errors = Errors.new
624
+ errors[:post].messages << "title can't be blank"
625
+
626
+ 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).
324
627
 
325
628
  ### Semantic Version
326
629
 
327
- require 'sleeping_king_studios/tools/semantic_version'
630
+ require 'sleeping_king_studios/tools/toolbox/semantic_version'
328
631
 
329
632
  Module mixin for using semantic versioning (see http://semver.org) with helper methods for generating strict and gem-compatible version strings.
330
633
 
331
634
  module Version
332
- extend SleepingKingStudios::Tools::SemanticVersion
635
+ extend SleepingKingStudios::Tools::Toolbox::SemanticVersion
333
636
 
334
637
  MAJOR = 3
335
638
  MINOR = 1
@@ -8,6 +8,28 @@ module SleepingKingStudios::Tools
8
8
  module ArrayTools
9
9
  extend self
10
10
 
11
+ ARRAY_METHODS = [:[], :count, :each].freeze
12
+ OTHER_METHODS = [:each_key, :each_pair].freeze
13
+
14
+ # Returns true if the object is or appears to be an Array.
15
+ #
16
+ # @param ary [Object] The object to test.
17
+ #
18
+ # @return [Boolean] True if the object is an Array, otherwise false.
19
+ def array? ary
20
+ return true if Array === ary
21
+
22
+ ARRAY_METHODS.each do |method_name|
23
+ return false unless ary.respond_to?(method_name)
24
+ end # each
25
+
26
+ OTHER_METHODS.each do |method_name|
27
+ return false if ary.respond_to?(method_name)
28
+ end # each
29
+
30
+ true
31
+ end # method array?
32
+
11
33
  # Separates the array into two arrays, the first containing all items in the
12
34
  # original array that matches the provided block, and the second containing
13
35
  # all items in the original array that do not match the provided block.
@@ -96,6 +118,17 @@ module SleepingKingStudios::Tools
96
118
  ary.map { |obj| ObjectTools.deep_dup obj }
97
119
  end # method deep_dup
98
120
 
121
+ # Freezes the array and performs a deep freeze on each array item.
122
+ #
123
+ # @param [Array] ary The object to freeze.
124
+ def deep_freeze ary
125
+ require_array! ary
126
+
127
+ ary.freeze
128
+
129
+ ary.each { |obj| ObjectTools.deep_freeze obj }
130
+ end # method deep_freeze
131
+
99
132
  # Accepts a list of values and returns a human-readable string of the
100
133
  # values, with the format based on the number of items.
101
134
  #
@@ -133,9 +166,11 @@ module SleepingKingStudios::Tools
133
166
  # @raise ArgumentError If the first argument is not an Array-like object.
134
167
  #
135
168
  # @return [String] The formatted string.
136
- def humanize_list ary, options = {}
169
+ def humanize_list ary, options = {}, &block
137
170
  require_array! ary
138
171
 
172
+ ary = ary.map(&block) if block_given?
173
+
139
174
  separator = options.fetch(:separator, ', ')
140
175
  last_separator = options.fetch(:last_separator, ' and ')
141
176
 
@@ -157,6 +192,35 @@ module SleepingKingStudios::Tools
157
192
  end # case
158
193
  end # method humanize_list
159
194
 
195
+ # Returns true if the array is immutable, i.e. the array is frozen and each
196
+ # array item is immutable.
197
+ #
198
+ # @param ary [Array] The array to test.
199
+ #
200
+ # @return [Boolean] True if the array is immutable, otherwise false.
201
+ #
202
+ # @see ObjectTools#immutable?
203
+ def immutable? ary
204
+ require_array! ary
205
+
206
+ return false unless ary.frozen?
207
+
208
+ ary.each { |item| return false unless ObjectTools.immutable?(item) }
209
+
210
+ true
211
+ end # method immutable?
212
+
213
+ # Returns true if the array is mutable.
214
+ #
215
+ # @param ary [Array] The array to test.
216
+ #
217
+ # @return [Boolean] True if the array is mutable, otherwise false.
218
+ #
219
+ # @see #immutable?
220
+ def mutable? ary
221
+ !immutable?(ary)
222
+ end # method mutable?
223
+
160
224
  # Accepts an array, a start value, a number of items to delete, and zero or
161
225
  # more items to insert at that index. Deletes the specified number of items,
162
226
  # then inserts the given items at the index and returns the array of deleted
@@ -208,9 +272,9 @@ module SleepingKingStudios::Tools
208
272
  private
209
273
 
210
274
  def require_array! value
211
- methods = %i([] count each)
275
+ return if array?(value)
212
276
 
213
- raise ArgumentError.new('argument must be an array') unless methods.reduce(true) { |memo, method_name| memo && value.respond_to?(method_name) }
277
+ raise ArgumentError, 'argument must be an array', caller[1..-1]
214
278
  end # method require_array
215
279
  end # module
216
280
  end # module
@@ -32,5 +32,18 @@ module SleepingKingStudios::Tools
32
32
 
33
33
  Kernel.warn str
34
34
  end # method deprecate
35
+
36
+ # Expands each file pattern and requires each file.
37
+ def require_each *file_patterns
38
+ file_patterns.each do |file_pattern|
39
+ if file_pattern.include?('*')
40
+ Dir[file_pattern].each do |file_name|
41
+ Kernel.require file_name
42
+ end # each
43
+ else
44
+ Kernel.require file_pattern
45
+ end # unless
46
+ end # each
47
+ end # method require_each
35
48
  end # module
36
49
  end # module
@@ -8,6 +8,8 @@ module SleepingKingStudios::Tools
8
8
  module HashTools
9
9
  extend self
10
10
 
11
+ HASH_METHODS = [:[], :count, :each, :each_key, :each_pair].freeze
12
+
11
13
  # Creates a deep copy of the object by returning a new Hash with deep
12
14
  # copies of each key and value.
13
15
  #
@@ -19,5 +21,60 @@ module SleepingKingStudios::Tools
19
21
  copy[ObjectTools.deep_dup key] = ObjectTools.deep_dup(value)
20
22
  end # each
21
23
  end # method deep_dup
24
+
25
+ # Freezes the hash and performs a deep freeze on each hash key and
26
+ # value.
27
+ #
28
+ # @param [Hash] hsh The object to freeze.
29
+ def deep_freeze hsh
30
+ hsh.freeze
31
+
32
+ hsh.each do |key, value|
33
+ ObjectTools.deep_freeze key
34
+ ObjectTools.deep_freeze value
35
+ end # each
36
+ end # method deep_freeze
37
+
38
+ # Returns true if the object is or appears to be a Hash.
39
+ #
40
+ # @param hsh [Object] The object to test.
41
+ #
42
+ # @return [Boolean] True if the object is a Hash, otherwise false.
43
+ def hash? hsh
44
+ return true if Hash === hsh
45
+
46
+ HASH_METHODS.each do |method_name|
47
+ return false unless hsh.respond_to?(method_name)
48
+ end # each
49
+
50
+ true
51
+ end # method hash?
52
+
53
+ # Returns true if the hash is immutable, i.e. if the hash is frozen and each
54
+ # hash key and hash value are immutable.
55
+ #
56
+ # @param hsh [Hash] The hash to test.
57
+ #
58
+ # @return [Boolean] True if the hash is immutable, otherwise false.
59
+ def immutable? hsh
60
+ return false unless hsh.frozen?
61
+
62
+ hsh.each do |key, value|
63
+ return false unless ObjectTools.immutable?(key) && ObjectTools.immutable?(value)
64
+ end # each
65
+
66
+ true
67
+ end # method immutable
68
+
69
+ # Returns true if the hash is mutable.
70
+ #
71
+ # @param hsh [Array] The hash to test.
72
+ #
73
+ # @return [Boolean] True if the hash is mutable, otherwise false.
74
+ #
75
+ # @see #immutable?
76
+ def mutable? hsh
77
+ !immutable?(hsh)
78
+ end # method mutable?
22
79
  end # module
23
80
  end # module
@@ -66,6 +66,15 @@ module SleepingKingStudios::Tools
66
66
  integer.to_s(base).split('')
67
67
  end # method digits
68
68
 
69
+ # Returns true if the object is an Integer.
70
+ #
71
+ # @param int [Object] The object to test.
72
+ #
73
+ # @return [Boolean] True if the object is an Integer, otherwise false.
74
+ def integer? int
75
+ Integer === int
76
+ end # method integer?
77
+
69
78
  # Returns the singular or the plural value, depending on the provided
70
79
  # item count.
71
80
  #
@@ -21,6 +21,14 @@ module SleepingKingStudios::Tools
21
21
  # @return The result of calling the proc or lambda with the given
22
22
  # receiver and any additional arguments or block.
23
23
  def apply base, proc, *args, **kwargs, &block
24
+ unless block_given?
25
+ if kwargs.empty?
26
+ return base.instance_exec *args, &proc
27
+ else
28
+ return base.instance_exec *args, **kwargs, &proc
29
+ end # if-else
30
+ end # unless
31
+
24
32
  temporary_method_name = :__sleeping_king_studios_tools_object_tools_temporary_method_for_applying_proc__
25
33
 
26
34
  metaclass = class << base; self; end
@@ -49,15 +57,34 @@ module SleepingKingStudios::Tools
49
57
  case obj
50
58
  when FalseClass, Fixnum, Float, NilClass, Symbol, TrueClass
51
59
  obj
52
- when Array
60
+ when ->(_) { ArrayTools.array?(obj) }
53
61
  ArrayTools.deep_dup obj
54
- when Hash
62
+ when ->(_) { HashTools.hash?(obj) }
55
63
  HashTools.deep_dup obj
56
64
  else
57
65
  obj.respond_to?(:deep_dup) ? obj.deep_dup : obj.dup
58
66
  end # case
59
67
  end # method deep_dup
60
68
 
69
+ # Performs a deep freeze of the object. If the object is an Array, freezes
70
+ # the array and performs a deep freeze on each array item. If the object is
71
+ # a hash, freezes the hash and performs a deep freeze on each hash key and
72
+ # value. Otherwise, calls Object#freeze.
73
+ #
74
+ # @param [Object] obj The object to freeze.
75
+ def deep_freeze obj
76
+ case obj
77
+ when FalseClass, Fixnum, Float, NilClass, Symbol, TrueClass
78
+ # Object is inherently immutable; do nothing here.
79
+ when ->(_) { ArrayTools.array?(obj) }
80
+ ArrayTools.deep_freeze(obj)
81
+ when ->(_) { HashTools.hash?(obj) }
82
+ HashTools.deep_freeze obj
83
+ else
84
+ obj.respond_to?(:deep_freeze) ? obj.deep_freeze : obj.freeze
85
+ end # case
86
+ end # method deep_freeze
87
+
61
88
  # Returns the object's eigenclass.
62
89
  #
63
90
  # @param [Object] object The object for which an eigenclass is required.
@@ -68,6 +95,50 @@ module SleepingKingStudios::Tools
68
95
  end # method eigenclass
69
96
  alias_method :metaclass, :eigenclass
70
97
 
98
+ # Returns true if the object is immutable. Values of nil, false, and true
99
+ # are always immutable, as are instances of Numeric and Symbol. Arrays are
100
+ # immutable if the array is frozen and each array item is immutable. Hashes
101
+ # are immutable if the hash is frozen and each hash key and hash value are
102
+ # immutable. Otherwise, objects are immutable if they are frozen.
103
+ #
104
+ # @param obj [Object] The object to test.
105
+ #
106
+ # @return [Boolean] True if the object is immutable, otherwise false.
107
+ def immutable? obj
108
+ case obj
109
+ when NilClass, FalseClass, TrueClass, Numeric, Symbol
110
+ true
111
+ when ->(_) { ArrayTools.array?(obj) }
112
+ ArrayTools.immutable? obj
113
+ when ->(_) { HashTools.hash?(obj) }
114
+ HashTools.immutable? obj
115
+ else
116
+ obj.frozen?
117
+ end # case
118
+ end # method immutable?
119
+
120
+ # Returns true if the object is mutable.
121
+ #
122
+ # @param obj [Object] The object to test.
123
+ #
124
+ # @return [Boolean] True if the object is mutable, otherwise false.
125
+ #
126
+ # @see #immutable?
127
+ def mutable? obj
128
+ !immutable?(obj)
129
+ end # method mutable?
130
+
131
+ # Returns true if the object is an Object. This should return true only for
132
+ # objects that have an alternate inheritance chain from BasicObject, such as
133
+ # a Proxy.
134
+ #
135
+ # @param obj [Object] The object to test.
136
+ #
137
+ # @return [Boolean] True if the object is an Object, otherwise false.
138
+ def object? obj
139
+ Object === obj
140
+ end # method object?
141
+
71
142
  # As #send, but returns nil if the object does not respond to the method.
72
143
  #
73
144
  # @param [Object] object The receiver of the message.
@@ -1,108 +1,15 @@
1
1
  # lib/sleeping_king_studios/tools/semantic_version.rb
2
2
 
3
- module SleepingKingStudios
4
- module Tools
5
- # Helper for generating semantic version strings with optional prerelease and
6
- # build parameters.
7
- #
8
- # @example
9
- # module Version
10
- # extend SleepingKingStudios::Tools::SemanticVersion
11
- #
12
- # MAJOR = 3
13
- # MINOR = 1
14
- # PATCH = 4
15
- # PRERELEASE = 'beta'
16
- # BUILD = 1
17
- # end # module
18
- #
19
- # VERSION = Version.to_gem_version
20
- #
21
- # @see http://semver.org
22
- module SemanticVersion
23
- # Error class for handling missing constants in a version definition.
24
- class InvalidVersionError < StandardError; end
3
+ require 'sleeping_king_studios/tools/core_tools'
25
4
 
26
- # Concatenates the MAJOR, MINOR, and PATCH constant values with PRERELEASE
27
- # and BUILD (if available) to generate a modified semantic version string
28
- # compatible with Rubygems. The major, minor, patch, prerelease, and build
29
- # values (if available) are separated by dots (.).
30
- #
31
- # @example
32
- # module Version
33
- # extend SleepingKingStudios::Tools::SemanticVersion
34
- #
35
- # MAJOR = 3
36
- # MINOR = 1
37
- # PATCH = 4
38
- # PRERELEASE = 'beta'
39
- # BUILD = 1
40
- # end # module
41
- #
42
- # VERSION = Version.to_gem_version
43
- # #=> '3.1.4.beta.1'
44
- #
45
- # @return [String] The modified semantic version string.
46
- #
47
- # @raise InvalidVersionError If MAJOR, MINOR, or PATCH is undefined.
48
- def to_gem_version
49
- str = "#{const_fetch :MAJOR}.#{const_fetch :MINOR}.#{const_fetch :PATCH}"
5
+ SleepingKingStudios::Tools::CoreTools.deprecate(
6
+ 'SleepingKingStudios::Tools::SemanticVersion',
7
+ :message => 'Use SleepingKingStudios::Tools::Toolbox::SemanticVersion instead.'
8
+ ) # end deprecate
50
9
 
51
- prerelease = const_fetch(:PRERELEASE, nil)
52
- str << ".#{prerelease}" unless prerelease.nil? || prerelease.empty?
10
+ require 'sleeping_king_studios/tools/toolbox/semantic_version'
53
11
 
54
- build = const_fetch(:BUILD, nil)
55
- str << ".#{build}" unless build.nil? || build.empty?
56
-
57
- str
58
- end # method to_version
59
-
60
- # Concatenates the MAJOR, MINOR, and PATCH constant values with PRERELEASE
61
- # and BUILD (if available) to generate a semantic version string. The
62
- # major, minor, and patch values are separated by dots (.), then the
63
- # prerelease (if available) preceded by a hyphen (-), and the build (if
64
- # available) preceded by a plus (+).
65
- #
66
- # @example
67
- # module Version
68
- # extend SleepingKingStudios::Tools::SemanticVersion
69
- #
70
- # MAJOR = 3
71
- # MINOR = 1
72
- # PATCH = 4
73
- # PRERELEASE = 'beta'
74
- # BUILD = 1
75
- # end # module
76
- #
77
- # VERSION = Version.to_version
78
- # #=> '3.1.4-beta+1'
79
- #
80
- # @return [String] The semantic version string.
81
- #
82
- # @raise InvalidVersionError If MAJOR, MINOR, or PATCH is undefined.
83
- def to_version
84
- str = "#{const_fetch :MAJOR}.#{const_fetch :MINOR}.#{const_fetch :PATCH}"
85
-
86
- prerelease = const_fetch(:PRERELEASE, nil)
87
- str << "-#{prerelease}" unless prerelease.nil? || prerelease.empty?
88
-
89
- build = const_fetch(:BUILD, nil)
90
- str << "+#{build}" unless build.nil? || build.empty?
91
-
92
- str
93
- end # method to_version
94
-
95
- private
96
-
97
- FETCH_DEFAULT = Object.new.freeze
98
-
99
- def const_fetch name, default = FETCH_DEFAULT
100
- if self.const_defined?(name)
101
- return self.const_get(name).to_s
102
- elsif default == FETCH_DEFAULT
103
- raise InvalidVersionError.new "undefined constant for #{name.downcase} version"
104
- end # if-else
105
- end # method const_fetch
106
- end # module
107
- end # module
12
+ module SleepingKingStudios::Tools
13
+ # (see SleepingKingStudios::Tools::Toolbox::SemanticVersion)
14
+ SemanticVersion = Toolbox::SemanticVersion
108
15
  end # module
@@ -10,6 +10,21 @@ module SleepingKingStudios::Tools
10
10
 
11
11
  autoload :PluralInflector, 'sleeping_king_studios/tools/string_tools/plural_inflector'
12
12
 
13
+ # Converts a lowercase, underscore-separated string to CamelCase.
14
+ #
15
+ # @param str [String] The string to convert.
16
+ #
17
+ # @return [String] The converted string.
18
+ #
19
+ # @see ActiveSupport::Inflector#camelize.
20
+ def camelize str
21
+ require_string! str
22
+
23
+ str = str.dup
24
+ str.gsub!(/(\b|[_-])([a-z])/) { |match| $2.upcase }
25
+ str
26
+ end # method camelize
27
+
13
28
  # (see PluralInflector#define_irregular_word)
14
29
  def define_irregular_word singular, plural
15
30
  plural_inflector.define_irregular_word singular, plural
@@ -76,6 +91,15 @@ module SleepingKingStudios::Tools
76
91
  plural_inflector.singularize str
77
92
  end # method singularize
78
93
 
94
+ # Returns true if the object is a String.
95
+ #
96
+ # @param str [Object] The object to test.
97
+ #
98
+ # @return [Boolean] True if the object is a String, otherwise false.
99
+ def string? str
100
+ String === str
101
+ end # method string?
102
+
79
103
  # Converts a mixed-case string expression to a lowercase, underscore
80
104
  # separated string.
81
105
  #
@@ -102,7 +126,9 @@ module SleepingKingStudios::Tools
102
126
  end # method plural_inflector
103
127
 
104
128
  def require_string! value
105
- raise ArgumentError.new('argument must be a string') unless value.is_a?(String)
129
+ return if string?(value)
130
+
131
+ raise ArgumentError, 'argument must be a string', caller[1..-1]
106
132
  end # method require_array
107
133
  end # module
108
134
  end # module
@@ -0,0 +1,175 @@
1
+ # lib/sleeping_king_studios/tools/toolbox/delegator.rb
2
+
3
+ require 'sleeping_king_studios/tools/toolbox'
4
+
5
+ module SleepingKingStudios::Tools::Toolbox
6
+ # Module for extending classes with basic delegation. Supports passing
7
+ # arguments, keywords, and blocks to the delegated method.
8
+ #
9
+ # @example
10
+ # class MyClass
11
+ # extend SleepingKingStudios::Tools::Delegator
12
+ #
13
+ # delegate :my_method, :to => MyService
14
+ # end # class
15
+ module Delegator
16
+ # Defines a wrapper method to delegate implementation of the specified
17
+ # method or methods to an object, to the object at another specified method,
18
+ # or to the object at a specified instance variable.
19
+ #
20
+ # @example Delegate to an object
21
+ # class MyModule
22
+ # extend SleepingKingStudios::Tools::Delegator
23
+ #
24
+ # delegate :my_method, :to => MyService
25
+ # end # class
26
+ #
27
+ # @example Delegate to a method
28
+ # class MyModule
29
+ # extend SleepingKingStudios::Tools::Delegator
30
+ #
31
+ # def my_service
32
+ # MyService.new
33
+ # end # method my_service
34
+ #
35
+ # delegate :my_method, :to => :my_service
36
+ # end # class
37
+ #
38
+ # @example Delegate to an instance variable
39
+ # class MyModule
40
+ # extend SleepingKingStudios::Tools::Delegator
41
+ #
42
+ # def initialize
43
+ # @my_service = MyService.new
44
+ # end # constructor
45
+ #
46
+ # delegate :my_method, :to => :@my_service
47
+ # end # class
48
+ #
49
+ # @param method_names [Array<String, Symbol>] The names of the methods to
50
+ # delegate.
51
+ # @param to [Object, String, Symbol] The object, method, or instance
52
+ # variable to delegate to. If the object is not a string or symbol, the
53
+ # generated method will call `method_name` on the object. If the object is
54
+ # a string or symbol, but does not start with an `@`, the generated method
55
+ # will call the method of that name on the instance, and then call
56
+ # `method_name` on the result. If the object is a string or symbol and
57
+ # does start with an `@`, the generated method will get the instance
58
+ # variable of that name and call `method_name` on the result.
59
+ #
60
+ # @raise ArgumentError if no delegate is specified.
61
+ def delegate *method_names, to: nil, allow_nil: false
62
+ raise ArgumentError.new('must specify a delegate') if to.nil? && !allow_nil
63
+
64
+ method_names.each do |method_name|
65
+ delegate_method method_name, to, { :allow_nil => !!allow_nil }
66
+ end # each
67
+ end # method delegate
68
+
69
+ # Wraps a delegate object by automatically delegating each method that is
70
+ # defined on the delegate class from the instance to the delegate. The
71
+ # delegate can be specified with an object literal or with the name of an
72
+ # instance method or instance variable.
73
+ #
74
+ # Only methods that are defined at the time #wrap_delegate is called will be
75
+ # delegated, so make sure to call #wrap_delegate after loading any gems or
76
+ # libraries that extend your delegate class, such as ActiveSupport.
77
+ #
78
+ # @example Create a class that wraps a Hash
79
+ # class Errors
80
+ # extend SleepingKingStudios::Tools::Delegator
81
+ #
82
+ # wrap_delegate Hash.new { |hsh, key| hsh[key] = Errors.new }, :klass => Hash
83
+ #
84
+ # def messages
85
+ # @messages ||= []
86
+ # end # method messages
87
+ # end # class
88
+ #
89
+ # errors = Errors.new
90
+ # errors[:post].messages << "title can't be blank"
91
+ #
92
+ # @param target [Object, String, Symbol] The object, method, or instance
93
+ # variable to delegate to. If the object is not a string or symbol, the
94
+ # generated method will call each method on the object. If the object is
95
+ # a string or symbol, but does not start with an `@`, the generated method
96
+ # will call the method of that name on the instance, and then call
97
+ # each method on the result. If the object is a string or symbol and
98
+ # does start with an `@`, the generated method will get the instance
99
+ # variable of that name and call each method on the result.
100
+ # @param klass [Module] The class or module whose methods are delegated to
101
+ # the target. If target is the name of an instance variable or an instance
102
+ # method, the klass must be specified. If target is an object literal, the
103
+ # klass is optional, in which case all methods from the target will be
104
+ # delegated to the target.
105
+ # @param except [Array<String, Symbol>] An optional list of method names.
106
+ # Any names on the list will not be delegated, even if the method is
107
+ # defined by the klass or defined on the target literal.
108
+ # @param only [Array<String, Symbol>] An optional list of method names.
109
+ # Only names on the list will be delegated, and only if the method is
110
+ # defined by the klass or defined on the target literal.
111
+ #
112
+ # @raise ArgumentError if no delegate is specified.
113
+ # @raise ArgumentError if the target is the name of an instance method or an
114
+ # instance variable and no klass is specified.
115
+ # @raise ArgumentError if the target is an object literal that does not
116
+ # belong to the specified klass.
117
+ #
118
+ # @see #delegate
119
+ def wrap_delegate target, klass: nil, except: [], only: []
120
+ if klass.is_a?(Module)
121
+ unless target.is_a?(String) || target.is_a?(Symbol) || target.is_a?(klass)
122
+ raise ArgumentError.new "expected delegate to be a #{klass.name}"
123
+ end # unless
124
+
125
+ method_names = klass.instance_methods - Object.instance_methods
126
+ elsif target.is_a?(String) || target.is_a?(Symbol)
127
+ raise ArgumentError.new 'must specify a delegate class'
128
+ else
129
+ method_names = target.methods - Object.new.methods
130
+ end # if-elsif-else
131
+
132
+ if except.is_a?(Array) && !except.empty?
133
+ method_names = method_names - except.map(&:intern)
134
+ end # if
135
+
136
+ if only.is_a?(Array) && !only.empty?
137
+ method_names = method_names & only.map(&:intern)
138
+ end # if
139
+
140
+ delegate *method_names, :to => target
141
+ end # method wrap_delegate
142
+
143
+ private
144
+
145
+ def delegate_method method_name, target, options = {}
146
+ if target.is_a?(String) || target.is_a?(Symbol)
147
+ target = target.intern
148
+
149
+ if target.to_s =~ /\A@/
150
+ define_method method_name do |*args, &block|
151
+ receiver = instance_variable_get(target)
152
+
153
+ return nil if receiver.nil? && options[:allow_nil]
154
+
155
+ receiver.send(method_name, *args, &block)
156
+ end # define_method
157
+ else
158
+ define_method method_name do |*args, &block|
159
+ receiver = send(target)
160
+
161
+ return nil if receiver.nil? && options[:allow_nil]
162
+
163
+ receiver.send(method_name, *args, &block)
164
+ end # define_method
165
+ end # if-else
166
+ else
167
+ define_method method_name do |*args, &block|
168
+ return nil if target.nil? && options[:allow_nil]
169
+
170
+ target.send(method_name, *args, &block)
171
+ end # define_method
172
+ end # if
173
+ end # method delegate_method
174
+ end # module
175
+ end # module
@@ -0,0 +1,108 @@
1
+ # lib/sleeping_king_studios/tools/toolbox/semantic_version.rb
2
+
3
+ require 'sleeping_king_studios/tools/toolbox'
4
+
5
+ module SleepingKingStudios::Tools::Toolbox
6
+ # Helper for generating semantic version strings with optional prerelease and
7
+ # build parameters.
8
+ #
9
+ # @example
10
+ # module Version
11
+ # extend SleepingKingStudios::Tools::SemanticVersion
12
+ #
13
+ # MAJOR = 3
14
+ # MINOR = 1
15
+ # PATCH = 4
16
+ # PRERELEASE = 'beta'
17
+ # BUILD = 1
18
+ # end # module
19
+ #
20
+ # VERSION = Version.to_gem_version
21
+ #
22
+ # @see http://semver.org
23
+ module SemanticVersion
24
+ # Error class for handling missing constants in a version definition.
25
+ class InvalidVersionError < StandardError; end
26
+
27
+ # Concatenates the MAJOR, MINOR, and PATCH constant values with PRERELEASE
28
+ # and BUILD (if available) to generate a modified semantic version string
29
+ # compatible with Rubygems. The major, minor, patch, prerelease, and build
30
+ # values (if available) are separated by dots (.).
31
+ #
32
+ # @example
33
+ # module Version
34
+ # extend SleepingKingStudios::Tools::SemanticVersion
35
+ #
36
+ # MAJOR = 3
37
+ # MINOR = 1
38
+ # PATCH = 4
39
+ # PRERELEASE = 'beta'
40
+ # BUILD = 1
41
+ # end # module
42
+ #
43
+ # VERSION = Version.to_gem_version
44
+ # #=> '3.1.4.beta.1'
45
+ #
46
+ # @return [String] The modified semantic version string.
47
+ #
48
+ # @raise InvalidVersionError If MAJOR, MINOR, or PATCH is undefined.
49
+ def to_gem_version
50
+ str = "#{const_fetch :MAJOR}.#{const_fetch :MINOR}.#{const_fetch :PATCH}"
51
+
52
+ prerelease = const_fetch(:PRERELEASE, nil)
53
+ str << ".#{prerelease}" unless prerelease.nil? || prerelease.empty?
54
+
55
+ build = const_fetch(:BUILD, nil)
56
+ str << ".#{build}" unless build.nil? || build.empty?
57
+
58
+ str
59
+ end # method to_version
60
+
61
+ # Concatenates the MAJOR, MINOR, and PATCH constant values with PRERELEASE
62
+ # and BUILD (if available) to generate a semantic version string. The
63
+ # major, minor, and patch values are separated by dots (.), then the
64
+ # prerelease (if available) preceded by a hyphen (-), and the build (if
65
+ # available) preceded by a plus (+).
66
+ #
67
+ # @example
68
+ # module Version
69
+ # extend SleepingKingStudios::Tools::SemanticVersion
70
+ #
71
+ # MAJOR = 3
72
+ # MINOR = 1
73
+ # PATCH = 4
74
+ # PRERELEASE = 'beta'
75
+ # BUILD = 1
76
+ # end # module
77
+ #
78
+ # VERSION = Version.to_version
79
+ # #=> '3.1.4-beta+1'
80
+ #
81
+ # @return [String] The semantic version string.
82
+ #
83
+ # @raise InvalidVersionError If MAJOR, MINOR, or PATCH is undefined.
84
+ def to_version
85
+ str = "#{const_fetch :MAJOR}.#{const_fetch :MINOR}.#{const_fetch :PATCH}"
86
+
87
+ prerelease = const_fetch(:PRERELEASE, nil)
88
+ str << "-#{prerelease}" unless prerelease.nil? || prerelease.empty?
89
+
90
+ build = const_fetch(:BUILD, nil)
91
+ str << "+#{build}" unless build.nil? || build.empty?
92
+
93
+ str
94
+ end # method to_version
95
+
96
+ private
97
+
98
+ FETCH_DEFAULT = Object.new.freeze
99
+
100
+ def const_fetch name, default = FETCH_DEFAULT
101
+ if self.const_defined?(name)
102
+ return self.const_get(name).to_s
103
+ elsif default == FETCH_DEFAULT
104
+ raise InvalidVersionError.new "undefined constant for #{name.downcase} version"
105
+ end # if-else
106
+ end # method const_fetch
107
+ end # module
108
+ end # module
@@ -0,0 +1,10 @@
1
+ # lib/sleeping_king_studios/tools/toolbox.rb
2
+
3
+ require 'sleeping_king_studios/tools'
4
+
5
+ module SleepingKingStudios::Tools
6
+ # Namespace for common objects or patterns that are useful across projects but
7
+ # are larger than or do not fit the functional paradigm of the tools.*
8
+ # pattern.
9
+ module Toolbox; end
10
+ end # module
@@ -1,6 +1,6 @@
1
1
  # lib/sleeping_king_studios/tools/version.rb
2
2
 
3
- require 'sleeping_king_studios/tools/semantic_version'
3
+ require 'sleeping_king_studios/tools/toolbox/semantic_version'
4
4
 
5
5
  module SleepingKingStudios
6
6
  module Tools
@@ -8,15 +8,15 @@ module SleepingKingStudios
8
8
  #
9
9
  # @see http://semver.org
10
10
  module Version
11
- extend SleepingKingStudios::Tools::SemanticVersion
11
+ extend SleepingKingStudios::Tools::Toolbox::SemanticVersion
12
12
 
13
13
  private
14
14
 
15
15
  MAJOR = 0
16
- MINOR = 4
16
+ MINOR = 5
17
17
  PATCH = 0
18
- PRERELEASE = nil
19
- BUILD = nil
18
+ PRERELEASE = :rc
19
+ BUILD = 0
20
20
  end # module
21
21
 
22
22
  VERSION = Version.to_gem_version
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: 0.4.0
4
+ version: 0.5.0.rc.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: 2016-08-22 00:00:00.000000000 Z
11
+ date: 2016-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -103,6 +103,9 @@ files:
103
103
  - lib/sleeping_king_studios/tools/string_tools.rb
104
104
  - lib/sleeping_king_studios/tools/string_tools/plural_inflector.rb
105
105
  - lib/sleeping_king_studios/tools/toolbelt.rb
106
+ - lib/sleeping_king_studios/tools/toolbox.rb
107
+ - lib/sleeping_king_studios/tools/toolbox/delegator.rb
108
+ - lib/sleeping_king_studios/tools/toolbox/semantic_version.rb
106
109
  - lib/sleeping_king_studios/tools/version.rb
107
110
  homepage: http://sleepingkingstudios.com
108
111
  licenses:
@@ -119,9 +122,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
119
122
  version: '0'
120
123
  required_rubygems_version: !ruby/object:Gem::Requirement
121
124
  requirements:
122
- - - ">="
125
+ - - ">"
123
126
  - !ruby/object:Gem::Version
124
- version: '0'
127
+ version: 1.3.1
125
128
  requirements: []
126
129
  rubyforge_project:
127
130
  rubygems_version: 2.5.1