sleeping_king_studios-tools 0.5.0 → 0.6.0.rc.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/DEVELOPMENT.md +18 -20
- data/README.md +145 -14
- data/lib/sleeping_king_studios/tools/core_tools.rb +2 -0
- data/lib/sleeping_king_studios/tools/hash_tools.rb +67 -0
- data/lib/sleeping_king_studios/tools/integer_tools.rb +1 -1
- data/lib/sleeping_king_studios/tools/object_tools.rb +21 -15
- data/lib/sleeping_king_studios/tools/string_tools.rb +16 -0
- data/lib/sleeping_king_studios/tools/toolbelt.rb +14 -0
- data/lib/sleeping_king_studios/tools/toolbox/constant_map.rb +94 -0
- data/lib/sleeping_king_studios/tools/toolbox/delegator.rb +3 -3
- data/lib/sleeping_king_studios/tools/toolbox/mixin.rb +32 -0
- data/lib/sleeping_king_studios/tools/version.rb +3 -3
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7643481360065ffb89a2bd3e439caf8a6483edea
|
4
|
+
data.tar.gz: 3c956ccdcd390d4c3e3368210b6e7759f98bff96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e7fb8a49db7792f425f0b411a5fdbfc10436b4b3365a28d06bf119a5e76a673bc4f138454196a9ddf35a1826e4cddc34d46ddf933f2fa8812c2ad336bea3d73
|
7
|
+
data.tar.gz: 4a6ba7debe9880d7f6502eb8eea33dd60aa6dff3c942ad9df8423b4fc371bdb5a269d16f2d515afd0b97ab628d99fecd5d21bbd954391b6031d66bd06167e0b8
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,16 @@
|
|
2
2
|
|
3
3
|
## Current Release
|
4
4
|
|
5
|
+
### 0.6.0
|
6
|
+
|
7
|
+
- Implement HashTools#convert_keys_to_strings and #convert_keys_to_symbols.
|
8
|
+
- Implement ObjectTools#dig.
|
9
|
+
- Implement StringTools#singular? and #plural?.
|
10
|
+
- Implement Toolbelt::instance, #inspect, #to_s.
|
11
|
+
- Implement Toolbox::ConstantMap.
|
12
|
+
- Implement Toolbox::Mixin.
|
13
|
+
- Add support for Ruby 2.4.0.
|
14
|
+
|
5
15
|
### 0.5.0
|
6
16
|
|
7
17
|
- Implement CoreTools#require_each.
|
data/DEVELOPMENT.md
CHANGED
@@ -1,17 +1,31 @@
|
|
1
1
|
# Development Notes
|
2
2
|
|
3
|
+
## 0.7.0
|
4
|
+
|
5
|
+
- StringTools - support symbolic arguments
|
6
|
+
- StringTools#chain |
|
7
|
+
|
8
|
+
tools.chain(str, :underscore, :pluralize)
|
9
|
+
#=> shorthand for tools.pluralize(tools.underscore str)
|
10
|
+
|
11
|
+
- IntegerTools#pluralize - have third (plural string) parameter be optional and defer to StringTools#pluralize.
|
12
|
+
|
3
13
|
## Future Tasks
|
4
14
|
|
5
15
|
- Remove 'extend self' from Tools modules.
|
6
16
|
|
7
17
|
### Features
|
8
18
|
|
9
|
-
|
19
|
+
- HashTools::slice, ::bisect_keys
|
20
|
+
- ObjectTools::apply_with_arity
|
21
|
+
- ObjectTools::method_arity
|
22
|
+
- StringTools#map_lines |
|
10
23
|
|
11
|
-
|
24
|
+
tools.map_lines("10\n20 GOTO 10") { |str| " #{str}" }
|
25
|
+
#=> " 10\n 20 GOTO 10"
|
26
|
+
- Delegator#delegate, :prefix => prefix_name
|
12
27
|
|
13
|
-
|
14
|
-
#=> shorthand for tools.pluralize(tools.underscore str)
|
28
|
+
#### Tools
|
15
29
|
|
16
30
|
- ObjectTools#pretty - returns user-friendly string representation. :multiline option? Delegates to specific toolset implementations.
|
17
31
|
- RegexpTools#matching_string - generates a string that matches the regular expression. Does not support advanced Regexp features.
|
@@ -22,22 +36,6 @@
|
|
22
36
|
#### Toolkit
|
23
37
|
|
24
38
|
- Configuration
|
25
|
-
- ConstantEnumerator |
|
26
|
-
|
27
|
-
class MyClass
|
28
|
-
ROLES = ConstantEnumerator.new do
|
29
|
-
USER = 'user'
|
30
|
-
ADMIN = 'admin'
|
31
|
-
end
|
32
|
-
|
33
|
-
MyClass::ROLES::USER # 'user'
|
34
|
-
MyClass::ROLES.admin # 'admin'
|
35
|
-
MyClass::ROLES.all { 'USER' => 'user', 'ADMIN' => 'admin' }
|
36
|
-
end
|
37
|
-
- ImmutableConstantEnumerator
|
38
|
-
- Values cannot be added or removed after initial block
|
39
|
-
- Freezes individual values
|
40
|
-
- Equivalent to ConstantEnumerator.new do ... end.immutable!
|
41
39
|
|
42
40
|
### Maintenance
|
43
41
|
|
data/README.md
CHANGED
@@ -18,7 +18,7 @@ The tools can be accessed in a convenient form using the Toolbelt class.
|
|
18
18
|
|
19
19
|
require 'sleeping_king_studios/tools/toolbelt'
|
20
20
|
|
21
|
-
tools = ::SleepingKingStudios::Tools::Toolbelt.
|
21
|
+
tools = ::SleepingKingStudios::Tools::Toolbelt.instance
|
22
22
|
|
23
23
|
tools.array.humanize_list 'one', 'two', 'three'
|
24
24
|
#=> calls ArrayTools#humanize_list
|
@@ -201,6 +201,38 @@ Takes a file pattern or a list of file names and requires each file.
|
|
201
201
|
|
202
202
|
Tools for working with array-like enumerable objects.
|
203
203
|
|
204
|
+
#### `#convert_keys_to_strings`
|
205
|
+
|
206
|
+
Creates a copy of the hash with the keys converted to strings, including keys of nested hashes and hashes inside nested arrays.
|
207
|
+
|
208
|
+
hsh = { :one => 1, :two => 2, :three => 3 }
|
209
|
+
cpy = HashTools.convert_keys_to_strings(hsh)
|
210
|
+
#=> { 'one' => 1, 'two' => 2, 'three' => 3 }
|
211
|
+
hsh
|
212
|
+
#=> { :one => 1, :two => 2, :three => 3 }
|
213
|
+
|
214
|
+
hsh = { :odd => { :one => 1, :three => 3 }, :even => { :two => 2, :four => 4 } }
|
215
|
+
cpy = HashTools.convert_keys_to_strings(hsh)
|
216
|
+
#=> { 'odd' => { 'one' => 1, 'three' => 3 }, 'even' => { 'two' => 2, 'four' => 4 } }
|
217
|
+
hsh
|
218
|
+
#=> { :odd => { :one => 1, :three => 3 }, :even => { :two => 2, :four => 4 } }
|
219
|
+
|
220
|
+
#### `#convert_keys_to_symbols`
|
221
|
+
|
222
|
+
Creates a copy of the hash with the keys converted to symbols, including keys of nested hashes and hashes inside nested arrays.
|
223
|
+
|
224
|
+
hsh = { 'one' => 1, 'two' => 2, 'three' => 3 }
|
225
|
+
cpy = HashTools.convert_keys_to_strings(hsh)
|
226
|
+
#=> { :one => 1, :two => 2, :three => 3 }
|
227
|
+
hsh
|
228
|
+
#=> { 'one' => 1, 'two' => 2, 'three' => 3 }
|
229
|
+
|
230
|
+
hsh = { 'odd' => { 'one' => 1, 'three' => 3 }, 'even' => { 'two' => 2, 'four' => 4 } }
|
231
|
+
cpy = HashTools.convert_keys_to_strings(hsh)
|
232
|
+
#=> { :odd => { :one => 1, :three => 3 }, :even => { :two => 2, :four => 4 } }
|
233
|
+
hsh
|
234
|
+
#=> { 'odd' => { 'one' => 1, 'three' => 3 }, 'even' => { 'two' => 2, 'four' => 4 } }
|
235
|
+
|
204
236
|
#### `#deep_dup`
|
205
237
|
|
206
238
|
Creates a deep copy of the object by returning a new Hash with deep copies of each key and value. See also ObjectTools#deep_dup[#label-Object+Tools].
|
@@ -258,9 +290,17 @@ Returns true if the hash is immutable, i.e. if the hash is frozen and each hash
|
|
258
290
|
|
259
291
|
Returns true if the hash is mutable (see `#immutable?`, above).
|
260
292
|
|
293
|
+
#### `#stringify_keys`
|
294
|
+
|
295
|
+
See HashTools#convert_keys_to_strings[#label-Hash+Tools]
|
296
|
+
|
297
|
+
#### `#symbolize_keys`
|
298
|
+
|
299
|
+
See HashTools#convert_keys_to_symbols[#label-Hash+Tools]
|
300
|
+
|
261
301
|
### Integer Tools
|
262
302
|
|
263
|
-
Tools for working with integers
|
303
|
+
Tools for working with integers.
|
264
304
|
|
265
305
|
#### `#count_digits`
|
266
306
|
|
@@ -315,7 +355,7 @@ Returns true if the object is an Integer.
|
|
315
355
|
|
316
356
|
Returns the singular or the plural value, depending on the provided item count.
|
317
357
|
|
318
|
-
|
358
|
+
IntegerTools.pluralize 4, 'light', 'lights'
|
319
359
|
#=> 'lights'
|
320
360
|
|
321
361
|
#### `#romanize`
|
@@ -409,6 +449,13 @@ Performs a deep freeze of the object. If the object is an Array, freezes the arr
|
|
409
449
|
data[:songs][0].name.frozen?
|
410
450
|
#=> true
|
411
451
|
|
452
|
+
#### `#dig`
|
453
|
+
|
454
|
+
Accesses deeply nested attributes by calling the first named method on the given object, and each subsequent method on the result of the previous method call. If the object does not respond to the method name, nil is returned instead of calling the method.
|
455
|
+
|
456
|
+
ObjectTools.dig my_object, :first_method, :second_method, :third_method
|
457
|
+
#=> my_object.first_method.second_method.third_method
|
458
|
+
|
412
459
|
#### `#eigenclass`, `#metaclass`
|
413
460
|
|
414
461
|
Returns the object's eigenclass.
|
@@ -485,6 +532,16 @@ Converts a lowercase, underscore separated string to a mixed-case string express
|
|
485
532
|
StringTools#camelize 'muspelheimr_and_niflheimr'
|
486
533
|
#=> 'MuspelheimrAndNiflheimr'
|
487
534
|
|
535
|
+
#### `#plural?`
|
536
|
+
|
537
|
+
Returns true if the word is in plural form, and returns false otherwise. A word is in plural form if and only if calling `#pluralize` (see below) on the word returns the word without modification.
|
538
|
+
|
539
|
+
StringTools.plural? 'light'
|
540
|
+
#=> false
|
541
|
+
|
542
|
+
StringTools.plural? 'lights'
|
543
|
+
#=> true
|
544
|
+
|
488
545
|
#### `#pluralize`
|
489
546
|
|
490
547
|
Takes a word in singular form and returns the plural form, based on the defined rules and known irregular/uncountable words.
|
@@ -513,6 +570,16 @@ Additional rules can be defined using the following methods:
|
|
513
570
|
StringTools.pluralize 'series'
|
514
571
|
# => 'series'
|
515
572
|
|
573
|
+
#### `#singular?`
|
574
|
+
|
575
|
+
Returns true if the word is in singular form, and returns false otherwise. A word is in singular form if and only if calling `#singularize` (see below) on the word returns the word without modification.
|
576
|
+
|
577
|
+
StringTools.singular? 'light'
|
578
|
+
#=> true
|
579
|
+
|
580
|
+
StringTools.singular? 'lights'
|
581
|
+
#=> false
|
582
|
+
|
516
583
|
#### `#singularize`
|
517
584
|
|
518
585
|
Takes a word in plural form and returns the singular form, based on the defined rules and known irregular/uncountable words.
|
@@ -553,34 +620,53 @@ Converts a mixed-case string expression to a lowercase, underscore separated str
|
|
553
620
|
|
554
621
|
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
622
|
|
556
|
-
###
|
623
|
+
### ConstantMap
|
624
|
+
|
625
|
+
require 'sleeping_king_studios/tools/toolbox/constant_map'
|
626
|
+
|
627
|
+
Provides an enumerable interface for defining a group of constants.
|
628
|
+
|
629
|
+
UserRoles = ConstantMap.new(
|
630
|
+
:GUEST => 'guest',
|
631
|
+
:USER => 'user',
|
632
|
+
:ADMIN => 'admin'
|
633
|
+
) # end constants
|
557
634
|
|
558
|
-
|
635
|
+
UserRoles::GUEST
|
636
|
+
#=> 'guest'
|
637
|
+
|
638
|
+
UserRoles.user
|
639
|
+
#=> 'user'
|
640
|
+
|
641
|
+
UserRoles.all
|
642
|
+
#=> { :GUEST => 'guest', :USER => 'user', :ADMIN => 'admin' }
|
643
|
+
|
644
|
+
### Delegator
|
559
645
|
|
560
646
|
require 'sleeping_king_studios/tools/toolbox/delegator'
|
561
647
|
|
648
|
+
Module for extending classes with basic delegation.
|
649
|
+
|
562
650
|
class MyClass
|
563
|
-
extend SleepingKingStudios::Tools::Delegator
|
651
|
+
extend SleepingKingStudios::Tools::Toolbox::Delegator
|
564
652
|
|
565
653
|
delegate :my_method, :to => MyService
|
566
654
|
end # class
|
567
655
|
|
568
|
-
Module for extending classes with basic delegation.
|
569
|
-
|
570
656
|
#### `::delegate`
|
571
657
|
|
572
658
|
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
659
|
|
574
660
|
# Delegate to an object
|
575
661
|
class MyModule
|
576
|
-
extend SleepingKingStudios::Tools::Delegator
|
662
|
+
extend SleepingKingStudios::Tools::Toolbox::Delegator
|
577
663
|
|
578
664
|
delegate :my_method, :to => MyService
|
579
665
|
end class
|
580
666
|
|
581
667
|
# Delegate to a method
|
582
668
|
class MyModule
|
583
|
-
extend SleepingKingStudios::Tools::Delegator
|
669
|
+
extend SleepingKingStudios::Tools::Toolbox::Delegator
|
584
670
|
|
585
671
|
def my_service
|
586
672
|
MyService.new
|
@@ -591,7 +677,7 @@ Defines a wrapper method to delegate implementation of the specified method or m
|
|
591
677
|
|
592
678
|
# Delegate to an instance variable
|
593
679
|
class MyModule
|
594
|
-
extend SleepingKingStudios::Tools::Delegator
|
680
|
+
extend SleepingKingStudios::Tools::Toolbox::Delegator
|
595
681
|
|
596
682
|
def initialize
|
597
683
|
@my_service = MyService.new
|
@@ -604,14 +690,13 @@ Expects one or more method names and a delegation target, which can be an object
|
|
604
690
|
|
605
691
|
#### `::wrap_delegate`
|
606
692
|
|
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.
|
693
|
+
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.
|
609
694
|
|
610
695
|
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
696
|
|
612
697
|
# Create a class that wraps a Hash
|
613
698
|
class Errors
|
614
|
-
extend SleepingKingStudios::Tools::Delegator
|
699
|
+
extend SleepingKingStudios::Tools::Toolbox::Delegator
|
615
700
|
|
616
701
|
wrap_delegate Hash.new { |hsh, key| hsh[key] = Errors.new }, :klass => Hash
|
617
702
|
|
@@ -625,6 +710,52 @@ Only methods that are defined at the time #wrap_delegate is called will be deleg
|
|
625
710
|
|
626
711
|
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).
|
627
712
|
|
713
|
+
### Mixin
|
714
|
+
|
715
|
+
require 'sleeping_king_studios/tools/toolbox/mixin'
|
716
|
+
|
717
|
+
Implements module-based inheritance for both instance- and class-level methods, similar to the (in)famous ActiveSupport::Concern. When a Mixin is included into a class, the class will be extended with any methods defined in the special ClassMethods module, even if the Mixin is being included indirectly via one or more intermediary Mixins.
|
718
|
+
|
719
|
+
Widget = Struct.new(:widget_type)
|
720
|
+
|
721
|
+
module Widgets
|
722
|
+
extend SleepingKingStudios::Tools::Toolbox::Mixin
|
723
|
+
|
724
|
+
module ClassMethods
|
725
|
+
def widget_types
|
726
|
+
%w(gadget doohickey thingamabob)
|
727
|
+
end # class method widget_types
|
728
|
+
end # module
|
729
|
+
|
730
|
+
def widget? widget_type
|
731
|
+
self.class.widget_types.include?(widget_type)
|
732
|
+
end # method widget?
|
733
|
+
end # module
|
734
|
+
|
735
|
+
module WidgetBuilding
|
736
|
+
extend SleepingKingStudios::Tools::Toolbox::Mixin
|
737
|
+
|
738
|
+
include Widgets
|
739
|
+
|
740
|
+
def build_widget widget_type
|
741
|
+
raise ArgumentError, 'not a widget', caller unless widget?(widget_type)
|
742
|
+
|
743
|
+
Widget.new(widget_type)
|
744
|
+
end # method build_widget
|
745
|
+
end # module
|
746
|
+
|
747
|
+
class WidgetFactory
|
748
|
+
include WidgetBuilding
|
749
|
+
end # class
|
750
|
+
|
751
|
+
factory = WidgetFactory.new
|
752
|
+
|
753
|
+
factory.build_widget('gadget')
|
754
|
+
#=> Widget
|
755
|
+
|
756
|
+
WidgetFactory.widget_types
|
757
|
+
#=> ['gadget', 'doohickey', 'thingamabob']
|
758
|
+
|
628
759
|
### Semantic Version
|
629
760
|
|
630
761
|
require 'sleeping_king_studios/tools/toolbox/semantic_version'
|
@@ -34,6 +34,8 @@ module SleepingKingStudios::Tools
|
|
34
34
|
end # method deprecate
|
35
35
|
|
36
36
|
# Expands each file pattern and requires each file.
|
37
|
+
#
|
38
|
+
# @param file_patterns [Array] The files to require.
|
37
39
|
def require_each *file_patterns
|
38
40
|
file_patterns.each do |file_pattern|
|
39
41
|
if file_pattern.include?('*')
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# lib/sleeping_king_studios/tools/hash_tools.rb
|
2
2
|
|
3
3
|
require 'sleeping_king_studios/tools'
|
4
|
+
require 'sleeping_king_studios/tools/array_tools'
|
4
5
|
require 'sleeping_king_studios/tools/object_tools'
|
5
6
|
|
6
7
|
module SleepingKingStudios::Tools
|
@@ -10,6 +11,38 @@ module SleepingKingStudios::Tools
|
|
10
11
|
|
11
12
|
HASH_METHODS = [:[], :count, :each, :each_key, :each_pair].freeze
|
12
13
|
|
14
|
+
# Returns a copy of the hash with the keys converted to strings.
|
15
|
+
#
|
16
|
+
# @param [Hash] hsh The hash to convert.
|
17
|
+
#
|
18
|
+
# @return [Hash] The converted copy of the hash.
|
19
|
+
def convert_keys_to_strings hsh
|
20
|
+
require_hash! hsh
|
21
|
+
|
22
|
+
hsh.each.with_object({}) do |(key, value), cpy|
|
23
|
+
sym = key.to_s
|
24
|
+
|
25
|
+
cpy[sym] = convert_value_to_stringified_hash(value)
|
26
|
+
end # each
|
27
|
+
end # method convert_keys_to_strings
|
28
|
+
alias_method :stringify_keys, :convert_keys_to_strings
|
29
|
+
|
30
|
+
# Returns a copy of the hash with the keys converted to symbols.
|
31
|
+
#
|
32
|
+
# @param [Hash] hsh The hash to convert.
|
33
|
+
#
|
34
|
+
# @return [Hash] The converted copy of the hash.
|
35
|
+
def convert_keys_to_symbols hsh
|
36
|
+
require_hash! hsh
|
37
|
+
|
38
|
+
hsh.each.with_object({}) do |(key, value), cpy|
|
39
|
+
sym = key.to_s.intern
|
40
|
+
|
41
|
+
cpy[sym] = convert_value_to_symbolic_hash(value)
|
42
|
+
end # each
|
43
|
+
end # method convert_keys_to_symbols
|
44
|
+
alias_method :symbolize_keys, :convert_keys_to_symbols
|
45
|
+
|
13
46
|
# Creates a deep copy of the object by returning a new Hash with deep
|
14
47
|
# copies of each key and value.
|
15
48
|
#
|
@@ -17,6 +50,8 @@ module SleepingKingStudios::Tools
|
|
17
50
|
#
|
18
51
|
# @return [Hash] The copy of the hash.
|
19
52
|
def deep_dup hsh
|
53
|
+
require_hash! hsh
|
54
|
+
|
20
55
|
hsh.each.with_object(Hash.new) do |(key, value), copy|
|
21
56
|
copy[ObjectTools.deep_dup key] = ObjectTools.deep_dup(value)
|
22
57
|
end # each
|
@@ -27,6 +62,8 @@ module SleepingKingStudios::Tools
|
|
27
62
|
#
|
28
63
|
# @param [Hash] hsh The object to freeze.
|
29
64
|
def deep_freeze hsh
|
65
|
+
require_hash! hsh
|
66
|
+
|
30
67
|
hsh.freeze
|
31
68
|
|
32
69
|
hsh.each do |key, value|
|
@@ -57,6 +94,8 @@ module SleepingKingStudios::Tools
|
|
57
94
|
#
|
58
95
|
# @return [Boolean] True if the hash is immutable, otherwise false.
|
59
96
|
def immutable? hsh
|
97
|
+
require_hash! hsh
|
98
|
+
|
60
99
|
return false unless hsh.frozen?
|
61
100
|
|
62
101
|
hsh.each do |key, value|
|
@@ -76,5 +115,33 @@ module SleepingKingStudios::Tools
|
|
76
115
|
def mutable? hsh
|
77
116
|
!immutable?(hsh)
|
78
117
|
end # method mutable?
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def convert_value_to_stringified_hash value
|
122
|
+
if hash?(value)
|
123
|
+
convert_keys_to_strings(value)
|
124
|
+
elsif ArrayTools.array?(value)
|
125
|
+
value.map { |item| convert_value_to_stringified_hash(item) }
|
126
|
+
else
|
127
|
+
value
|
128
|
+
end # if-else
|
129
|
+
end # method convert_value_to_stringified_hash
|
130
|
+
|
131
|
+
def convert_value_to_symbolic_hash value
|
132
|
+
if hash?(value)
|
133
|
+
convert_keys_to_symbols(value)
|
134
|
+
elsif ArrayTools.array?(value)
|
135
|
+
value.map { |item| convert_value_to_symbolic_hash(item) }
|
136
|
+
else
|
137
|
+
value
|
138
|
+
end # if-else
|
139
|
+
end # method convert_value_to_symbolic_hash
|
140
|
+
|
141
|
+
def require_hash! value
|
142
|
+
return if hash?(value)
|
143
|
+
|
144
|
+
raise ArgumentError, 'argument must be a hash', caller[1..-1]
|
145
|
+
end # method require_array
|
79
146
|
end # module
|
80
147
|
end # module
|
@@ -20,14 +20,8 @@ module SleepingKingStudios::Tools
|
|
20
20
|
#
|
21
21
|
# @return The result of calling the proc or lambda with the given
|
22
22
|
# receiver and any additional arguments or block.
|
23
|
-
def apply base, proc, *args,
|
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
|
23
|
+
def apply base, proc, *args, &block
|
24
|
+
return base.instance_exec *args, &proc unless block_given?
|
31
25
|
|
32
26
|
temporary_method_name = :__sleeping_king_studios_tools_object_tools_temporary_method_for_applying_proc__
|
33
27
|
|
@@ -35,11 +29,7 @@ module SleepingKingStudios::Tools
|
|
35
29
|
metaclass.send :define_method, temporary_method_name, &proc
|
36
30
|
|
37
31
|
begin
|
38
|
-
|
39
|
-
base.send temporary_method_name, *args, &block
|
40
|
-
else
|
41
|
-
base.send temporary_method_name, *args, **kwargs, &block
|
42
|
-
end # if-else
|
32
|
+
base.send temporary_method_name, *args, &block
|
43
33
|
ensure
|
44
34
|
metaclass.send :remove_method, temporary_method_name if temporary_method_name && defined?(temporary_method_name)
|
45
35
|
end
|
@@ -55,7 +45,7 @@ module SleepingKingStudios::Tools
|
|
55
45
|
# @return The copy of the object.
|
56
46
|
def deep_dup obj
|
57
47
|
case obj
|
58
|
-
when FalseClass,
|
48
|
+
when FalseClass, Integer, Float, NilClass, Symbol, TrueClass
|
59
49
|
obj
|
60
50
|
when ->(_) { ArrayTools.array?(obj) }
|
61
51
|
ArrayTools.deep_dup obj
|
@@ -74,7 +64,7 @@ module SleepingKingStudios::Tools
|
|
74
64
|
# @param [Object] obj The object to freeze.
|
75
65
|
def deep_freeze obj
|
76
66
|
case obj
|
77
|
-
when FalseClass,
|
67
|
+
when FalseClass, Integer, Float, NilClass, Symbol, TrueClass
|
78
68
|
# Object is inherently immutable; do nothing here.
|
79
69
|
when ->(_) { ArrayTools.array?(obj) }
|
80
70
|
ArrayTools.deep_freeze(obj)
|
@@ -85,6 +75,22 @@ module SleepingKingStudios::Tools
|
|
85
75
|
end # case
|
86
76
|
end # method deep_freeze
|
87
77
|
|
78
|
+
# Accesses deeply nested attributes by calling the first named method on the
|
79
|
+
# given object, and each subsequent method on the result of the previous
|
80
|
+
# method call. If the object does not respond to the method name, nil is
|
81
|
+
# returned instead of calling the method.
|
82
|
+
#
|
83
|
+
# @param [Object] obj The object to dig.
|
84
|
+
# @param [Array] method_names The names of the methods to call.
|
85
|
+
#
|
86
|
+
# @return [Object] The result of the last method call, or nil if the last
|
87
|
+
# object does not respond to the last method.
|
88
|
+
def dig object, *method_names
|
89
|
+
method_names.reduce(object) do |memo, method_name|
|
90
|
+
memo.respond_to?(method_name) ? memo.send(method_name) : nil
|
91
|
+
end # reduce
|
92
|
+
end # method object
|
93
|
+
|
88
94
|
# Returns the object's eigenclass.
|
89
95
|
#
|
90
96
|
# @param [Object] object The object for which an eigenclass is required.
|
@@ -45,6 +45,14 @@ module SleepingKingStudios::Tools
|
|
45
45
|
plural_inflector.define_uncountable_word word
|
46
46
|
end # method define_uncountable_word
|
47
47
|
|
48
|
+
# Determines whether or not the given word is in plural form. If calling
|
49
|
+
# #pluralize(word) is equal to word, the word is considered plural.
|
50
|
+
#
|
51
|
+
# @return [Boolean] True if the word is in plural form, otherwise false.
|
52
|
+
def plural? word
|
53
|
+
word == pluralize(word)
|
54
|
+
end # method plural?
|
55
|
+
|
48
56
|
# @overload pluralize(str)
|
49
57
|
# Takes a word in singular form and returns the plural form, based on the
|
50
58
|
# defined rules and known irregular/uncountable words.
|
@@ -84,6 +92,14 @@ module SleepingKingStudios::Tools
|
|
84
92
|
plural_inflector.pluralize args.first
|
85
93
|
end # method pluralize
|
86
94
|
|
95
|
+
# Determines whether or not the given word is in singular form. If calling
|
96
|
+
# #singularize(word) is equal to word, the word is considered singular.
|
97
|
+
#
|
98
|
+
# @return [Boolean] True if the word is in singular form, otherwise false.
|
99
|
+
def singular? word
|
100
|
+
word == singularize(word)
|
101
|
+
end # method singular?
|
102
|
+
|
87
103
|
# (see PluralInflector#singularize)
|
88
104
|
def singularize str
|
89
105
|
require_string! str
|
@@ -5,6 +5,10 @@ require 'sleeping_king_studios/tools/all'
|
|
5
5
|
module SleepingKingStudios::Tools
|
6
6
|
# Helper object for quick access to all available tools.
|
7
7
|
class Toolbelt < BasicObject
|
8
|
+
def self.instance
|
9
|
+
@instance ||= new
|
10
|
+
end # class method instance
|
11
|
+
|
8
12
|
namespace = ::SleepingKingStudios::Tools
|
9
13
|
|
10
14
|
%w(array core hash integer object string).each do |name|
|
@@ -16,5 +20,15 @@ module SleepingKingStudios::Tools
|
|
16
20
|
end # begin-rescue
|
17
21
|
end # each
|
18
22
|
end # each
|
23
|
+
|
24
|
+
def inspect
|
25
|
+
@to_s ||=
|
26
|
+
begin
|
27
|
+
object_class = class << self; self; end.superclass
|
28
|
+
|
29
|
+
"#<#{object_class.name}>"
|
30
|
+
end # string
|
31
|
+
end # method inspect
|
32
|
+
alias_method :to_s, :inspect
|
19
33
|
end # module
|
20
34
|
end # module
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# lib/sleeping_king_studios/tools/toolbox/constant_map.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tools/string_tools'
|
4
|
+
require 'sleeping_king_studios/tools/toolbox'
|
5
|
+
|
6
|
+
module SleepingKingStudios::Tools::Toolbox
|
7
|
+
# Provides an enumerable interface for defining a group of constants.
|
8
|
+
module ConstantMap
|
9
|
+
class << self
|
10
|
+
# Creates a new ConstantMap.
|
11
|
+
#
|
12
|
+
# @param constants [Hash] The constants to define.
|
13
|
+
def new constants
|
14
|
+
mod = Module.new
|
15
|
+
mod.extend self
|
16
|
+
|
17
|
+
constants.each do |const_name, const_value|
|
18
|
+
mod.const_set const_name, const_value
|
19
|
+
end # each
|
20
|
+
|
21
|
+
mod
|
22
|
+
end # class method new
|
23
|
+
end # eigenclass
|
24
|
+
|
25
|
+
# Returns a hash with the names and values of the defined constants.
|
26
|
+
#
|
27
|
+
# @return [Hash] The defined constants.
|
28
|
+
def all
|
29
|
+
constants.each.with_object({}) do |const_name, hsh|
|
30
|
+
hsh[const_name] = const_get(const_name)
|
31
|
+
end # each
|
32
|
+
end # method all
|
33
|
+
|
34
|
+
# Iterates through the defined constants, yielding the name and value of
|
35
|
+
# each constant to the block.
|
36
|
+
#
|
37
|
+
# @yieldparam key [Symbol] The name of the symbol.
|
38
|
+
# @yieldparam value [Object] The value of the symbol.
|
39
|
+
def each &block
|
40
|
+
all.each(&block)
|
41
|
+
end # method each
|
42
|
+
|
43
|
+
# Freezes the constant map and recursively freezes every constant value
|
44
|
+
# using ObjectTools#deep_freeze. Also pre-emptively defines any reader
|
45
|
+
# methods that are not already undefined.
|
46
|
+
#
|
47
|
+
# @see ObjectTools#deep_freeze
|
48
|
+
def freeze
|
49
|
+
constants.each do |const_name|
|
50
|
+
reader_name = const_name.downcase
|
51
|
+
|
52
|
+
define_reader(const_name, reader_name) unless methods.include?(reader_name)
|
53
|
+
|
54
|
+
object_tools.deep_freeze const_get(const_name)
|
55
|
+
end # each
|
56
|
+
|
57
|
+
super
|
58
|
+
end # method freeze
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def define_reader const_name, reader_name = nil
|
63
|
+
reader_name ||= const_name.downcase
|
64
|
+
|
65
|
+
define_singleton_method reader_name, ->() { const_get const_name }
|
66
|
+
end # method define_reader
|
67
|
+
|
68
|
+
def method_missing symbol, *args, &block
|
69
|
+
const_name = string_tools.underscore(symbol.to_s).upcase.intern
|
70
|
+
|
71
|
+
if constants.include?(const_name)
|
72
|
+
define_reader(const_name, symbol)
|
73
|
+
|
74
|
+
return send(symbol, *args, &block)
|
75
|
+
end # if
|
76
|
+
|
77
|
+
super
|
78
|
+
end # method method_missing
|
79
|
+
|
80
|
+
def object_tools
|
81
|
+
::SleepingKingStudios::Tools::ObjectTools
|
82
|
+
end # method object_tools
|
83
|
+
|
84
|
+
def respond_to_missing? symbol, include_all = false
|
85
|
+
const_name = string_tools.underscore(symbol.to_s).upcase.intern
|
86
|
+
|
87
|
+
constants.include?(const_name) || super
|
88
|
+
end # method respond_to_missing?
|
89
|
+
|
90
|
+
def string_tools
|
91
|
+
::SleepingKingStudios::Tools::StringTools
|
92
|
+
end # method string_tools
|
93
|
+
end # module
|
94
|
+
end # module
|
@@ -19,14 +19,14 @@ module SleepingKingStudios::Tools::Toolbox
|
|
19
19
|
#
|
20
20
|
# @example Delegate to an object
|
21
21
|
# class MyModule
|
22
|
-
# extend SleepingKingStudios::Tools::Delegator
|
22
|
+
# extend SleepingKingStudios::Tools::Toolbox::Delegator
|
23
23
|
#
|
24
24
|
# delegate :my_method, :to => MyService
|
25
25
|
# end # class
|
26
26
|
#
|
27
27
|
# @example Delegate to a method
|
28
28
|
# class MyModule
|
29
|
-
# extend SleepingKingStudios::Tools::Delegator
|
29
|
+
# extend SleepingKingStudios::Tools::Toolbox::Delegator
|
30
30
|
#
|
31
31
|
# def my_service
|
32
32
|
# MyService.new
|
@@ -37,7 +37,7 @@ module SleepingKingStudios::Tools::Toolbox
|
|
37
37
|
#
|
38
38
|
# @example Delegate to an instance variable
|
39
39
|
# class MyModule
|
40
|
-
# extend SleepingKingStudios::Tools::Delegator
|
40
|
+
# extend SleepingKingStudios::Tools::Toolbox::Delegator
|
41
41
|
#
|
42
42
|
# def initialize
|
43
43
|
# @my_service = MyService.new
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# lib/sleeping_king_studios/tools/toolbox/mixin.rb
|
2
|
+
|
3
|
+
require 'sleeping_king_studios/tools/toolbox'
|
4
|
+
|
5
|
+
module SleepingKingStudios::Tools::Toolbox
|
6
|
+
# Implements recursive inheritance of both class and instance methods.
|
7
|
+
module Mixin
|
8
|
+
# @api private
|
9
|
+
def self.mixin? mod
|
10
|
+
return false unless mod.is_a?(Module)
|
11
|
+
|
12
|
+
mod.singleton_class.include?(self)
|
13
|
+
end # class method mixin?
|
14
|
+
|
15
|
+
# @api private
|
16
|
+
def included other
|
17
|
+
return super unless defined?(self::ClassMethods)
|
18
|
+
|
19
|
+
if SleepingKingStudios::Tools::Toolbox::Mixin.mixin?(other)
|
20
|
+
unless other.constants(false).include?(:ClassMethods)
|
21
|
+
other.const_set(:ClassMethods, Module.new)
|
22
|
+
end # unless
|
23
|
+
|
24
|
+
other::ClassMethods.send :include, self::ClassMethods
|
25
|
+
else
|
26
|
+
other.extend self::ClassMethods
|
27
|
+
end # if-else
|
28
|
+
|
29
|
+
super
|
30
|
+
end # method included
|
31
|
+
end # module
|
32
|
+
end # module
|
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
|
+
version: 0.6.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:
|
11
|
+
date: 2017-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -104,7 +104,9 @@ files:
|
|
104
104
|
- lib/sleeping_king_studios/tools/string_tools/plural_inflector.rb
|
105
105
|
- lib/sleeping_king_studios/tools/toolbelt.rb
|
106
106
|
- lib/sleeping_king_studios/tools/toolbox.rb
|
107
|
+
- lib/sleeping_king_studios/tools/toolbox/constant_map.rb
|
107
108
|
- lib/sleeping_king_studios/tools/toolbox/delegator.rb
|
109
|
+
- lib/sleeping_king_studios/tools/toolbox/mixin.rb
|
108
110
|
- lib/sleeping_king_studios/tools/toolbox/semantic_version.rb
|
109
111
|
- lib/sleeping_king_studios/tools/version.rb
|
110
112
|
homepage: http://sleepingkingstudios.com
|
@@ -122,12 +124,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
124
|
version: '0'
|
123
125
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
126
|
requirements:
|
125
|
-
- - "
|
127
|
+
- - ">"
|
126
128
|
- !ruby/object:Gem::Version
|
127
|
-
version:
|
129
|
+
version: 1.3.1
|
128
130
|
requirements: []
|
129
131
|
rubyforge_project:
|
130
|
-
rubygems_version: 2.
|
132
|
+
rubygems_version: 2.6.8
|
131
133
|
signing_key:
|
132
134
|
specification_version: 4
|
133
135
|
summary: A library of utility services and concerns.
|