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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3227b681ac258bbee96c30202fa75f3100b9de31
4
- data.tar.gz: b89aca8c0dab167cc523f25b6f1ef533a84c4f62
3
+ metadata.gz: 7643481360065ffb89a2bd3e439caf8a6483edea
4
+ data.tar.gz: 3c956ccdcd390d4c3e3368210b6e7759f98bff96
5
5
  SHA512:
6
- metadata.gz: 1aa82e451bd91b63a253d8b5e54eed13c614f5ac87587b88a8ca09f21bf27645eb4ef8fa90be5dcc32267c0445adaf8417a95c3e82c4ef1f072f046cf165e215
7
- data.tar.gz: 91ac849f14d1573bc6fa2eb616aa84a0a0ddcd8cf723516d482814c8d81e6820045a763fa8eba500cf8ef2dd17f13c24364fa69be28ac16e8985032e8c21b1aa
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
- #### Tools
19
+ - HashTools::slice, ::bisect_keys
20
+ - ObjectTools::apply_with_arity
21
+ - ObjectTools::method_arity
22
+ - StringTools#map_lines |
10
23
 
11
- - StringTools#chain |
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
- tools.chain(str, :underscore, :pluralize)
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.new
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 and fixnums.
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
- StringTools.pluralize 4, 'light', 'lights'
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
- ### Delegator
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
- require 'sleeping_king_studios/tools/delegator'
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
@@ -3,7 +3,7 @@
3
3
  require 'sleeping_king_studios/tools'
4
4
 
5
5
  module SleepingKingStudios::Tools
6
- # Tools for working with integers and fixnums.
6
+ # Tools for working with integers.
7
7
  module IntegerTools
8
8
  extend self
9
9
 
@@ -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, **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
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
- if kwargs.empty?
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, Fixnum, Float, NilClass, Symbol, TrueClass
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, Fixnum, Float, NilClass, Symbol, TrueClass
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
@@ -13,10 +13,10 @@ module SleepingKingStudios
13
13
  private
14
14
 
15
15
  MAJOR = 0
16
- MINOR = 5
16
+ MINOR = 6
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.5.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: 2016-09-12 00:00:00.000000000 Z
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: '0'
129
+ version: 1.3.1
128
130
  requirements: []
129
131
  rubyforge_project:
130
- rubygems_version: 2.5.1
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.