darthjee-core_ext 1.7.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +7 -1
  3. data/.gitignore +2 -0
  4. data/.reek.yml +3 -0
  5. data/ARRAY_README.md +72 -15
  6. data/CLASS_README.md +154 -0
  7. data/DATE_README.md +19 -9
  8. data/Dockerfile +2 -5
  9. data/ENUMERABLE_README.md +154 -4
  10. data/HASH_README.md +276 -135
  11. data/MATH_README.md +14 -10
  12. data/OBJECT_README.md +18 -35
  13. data/README.md +8 -4
  14. data/Rakefile +1 -0
  15. data/SYMBOL_README.md +13 -18
  16. data/config/rubycritc.rb +12 -0
  17. data/config/yardstick.yml +45 -3
  18. data/core_ext.gemspec +10 -8
  19. data/docker-compose.yml +15 -7
  20. data/lib/darthjee/core_ext/array.rb +17 -12
  21. data/lib/darthjee/core_ext/array/hash_builder.rb +20 -4
  22. data/lib/darthjee/core_ext/class.rb +28 -10
  23. data/lib/darthjee/core_ext/date.rb +1 -0
  24. data/lib/darthjee/core_ext/enumerable.rb +67 -30
  25. data/lib/darthjee/core_ext/hash.rb +4 -2
  26. data/lib/darthjee/core_ext/hash/cameliazable.rb +39 -8
  27. data/lib/darthjee/core_ext/hash/chain_fetcher.rb +17 -1
  28. data/lib/darthjee/core_ext/hash/changeable.rb +88 -0
  29. data/lib/darthjee/core_ext/hash/deep_hash_constructor.rb +127 -63
  30. data/lib/darthjee/core_ext/hash/deep_hash_constructor/setter.rb +112 -0
  31. data/lib/darthjee/core_ext/hash/key_changeable.rb +126 -54
  32. data/lib/darthjee/core_ext/hash/key_changer.rb +140 -40
  33. data/lib/darthjee/core_ext/hash/keys_sorter.rb +42 -6
  34. data/lib/darthjee/core_ext/hash/squasher.rb +131 -18
  35. data/lib/darthjee/core_ext/hash/transformable.rb +133 -41
  36. data/lib/darthjee/core_ext/hash/transposeable.rb +37 -8
  37. data/lib/darthjee/core_ext/hash/value_changer.rb +76 -36
  38. data/lib/darthjee/core_ext/math.rb +37 -6
  39. data/lib/darthjee/core_ext/numeric.rb +10 -0
  40. data/lib/darthjee/core_ext/object.rb +29 -0
  41. data/lib/darthjee/core_ext/symbol.rb +22 -2
  42. data/lib/darthjee/core_ext/version.rb +1 -1
  43. data/scripts/check_readme.sh +6 -0
  44. data/scripts/rubycritic.sh +10 -0
  45. data/spec/integration/readme/array_spec.rb +96 -0
  46. data/spec/integration/readme/class_spec.rb +123 -0
  47. data/spec/integration/readme/date_spec.rb +20 -0
  48. data/spec/integration/readme/enumerable_spec.rb +87 -0
  49. data/spec/integration/readme/hash_spec.rb +391 -0
  50. data/spec/integration/readme/math_spec.rb +31 -0
  51. data/spec/integration/readme/object_spec.rb +49 -0
  52. data/spec/integration/readme/symbol_spec.rb +29 -0
  53. data/spec/integration/yard/darthjee/core_ext/enumerable_spec.rb +24 -4
  54. data/spec/integration/yard/darthjee/core_ext/hash/cameliazable_spec.rb +11 -0
  55. data/spec/integration/yard/darthjee/core_ext/hash/changeable_spec.rb +68 -0
  56. data/spec/integration/yard/darthjee/core_ext/hash/deep_hash_constructor/setter_spec.rb +34 -0
  57. data/spec/integration/yard/darthjee/core_ext/hash/deep_hash_constructor_spec.rb +65 -0
  58. data/spec/integration/yard/darthjee/core_ext/hash/key_changeable_spec.rb +8 -0
  59. data/spec/integration/yard/darthjee/core_ext/hash/key_changer_spec.rb +59 -0
  60. data/spec/integration/yard/darthjee/core_ext/hash/keys_sorter_spec.rb +25 -0
  61. data/spec/integration/yard/darthjee/core_ext/hash/squasher_spec.rb +60 -0
  62. data/spec/integration/yard/darthjee/core_ext/hash/transformable_spec.rb +66 -36
  63. data/spec/integration/yard/darthjee/core_ext/hash/transposeable_spec.rb +35 -0
  64. data/spec/integration/yard/darthjee/core_ext/hash_spec.rb +13 -2
  65. data/spec/integration/yard/darthjee/core_ext/math_spec.rb +28 -0
  66. data/spec/integration/yard/darthjee/core_ext/numeric_spec.rb +11 -0
  67. data/spec/integration/yard/darthjee/core_ext/object_spec.rb +47 -0
  68. data/spec/integration/yard/darthjee/core_ext/symbol_spec.rb +17 -0
  69. data/spec/lib/darthjee/core_ext/hash/deep_hash_constructor/setter_spec.rb +64 -0
  70. data/spec/lib/darthjee/core_ext/hash/deep_hash_constructor_spec.rb +16 -156
  71. data/spec/lib/darthjee/core_ext/hash/keys_sorter_spec.rb +5 -4
  72. data/spec/lib/darthjee/core_ext/hash/squasher_spec.rb +8 -2
  73. data/spec/lib/darthjee/core_ext/hash/value_changer_spec.rb +4 -12
  74. data/spec/lib/hash_spec.rb +92 -146
  75. data/spec/lib/object_spec.rb +32 -0
  76. data/spec/support/models/client.rb +22 -0
  77. data/spec/support/shared_examples/hash/deep_hash.rb +166 -0
  78. data/spec/support/shared_examples/hash/hash_squasher.rb +54 -9
  79. data/spec/support/shared_examples/hash/keys_sorter.rb +266 -6
  80. metadata +70 -8
  81. data/lib/darthjee/core_ext/hash/to_hash_mapper.rb +0 -25
  82. data/spec/lib/darthjee/core_ext/hash/to_hash_mapper_spec.rb +0 -11
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Darthjee
4
4
  module CoreExt
5
+ # @api public
5
6
  module Class
6
7
  private
7
8
 
@@ -22,8 +23,6 @@ module Darthjee
22
23
  # MyClass.new.name # returns 'John'
23
24
  #
24
25
  # @example Comparing value across instances
25
- # # frozen_string_literal: false
26
- #
27
26
  # class MyClass
28
27
  # default_value :name, 'John'
29
28
  # end
@@ -33,6 +32,8 @@ module Darthjee
33
32
  #
34
33
  # instance.name.equal?('John') # returns false
35
34
  # instance.name.equal?(other.name) # returns true
35
+ #
36
+ # @return [::Symbol] The name of the added method
36
37
  def default_value(name, value)
37
38
  define_method(name) { |*_| value }
38
39
  end
@@ -78,17 +79,24 @@ module Darthjee
78
79
  #
79
80
  # instance.nick_name.equal?('John') # returns false
80
81
  # instance.nick_name.equal?(instance.name) # returns true
82
+ #
83
+ # @return [::Array<::Symbol>] Name of defined methods
81
84
  def default_values(*names, value)
82
- names.each do |name|
85
+ names.map do |name|
83
86
  default_value(name, value)
84
87
  end
85
88
  end
86
89
 
87
90
  # @!visibility public
88
91
  #
89
- # Creates a method that will act as reader, but will
90
- # return a default value when the instance variable
91
- # was never set
92
+ # Creates a method that will act as reader with default value
93
+ #
94
+ # The method will be a reader, but when no value was
95
+ # defined for the instance variable, it will
96
+ # return a default
97
+ #
98
+ # @param [::Symbol,::String] name Name of the method to be added
99
+ # @param [::Object] value default value
92
100
  #
93
101
  # @example Defining a default value
94
102
  # class Person
@@ -119,6 +127,8 @@ module Darthjee
119
127
  # model.name = 'Bob'
120
128
  # model.name # returns 'Bob'
121
129
  # Person.new.name # returns 'John Doe'
130
+ #
131
+ # @return [::Symbol] Defined method name
122
132
  def default_reader(name, value)
123
133
  define_method(name) do
124
134
  return value unless instance_variable_defined?("@#{name}")
@@ -128,9 +138,15 @@ module Darthjee
128
138
 
129
139
  # @!visibility public
130
140
  #
131
- # Creates methods that will act as readers, but will
132
- # return a default value when the instance variables
133
- # ware never set
141
+ # Creates methods that will act as reader with default value
142
+ #
143
+ # The methods will be readers, but when no value was
144
+ # defined for the instance variable, it will
145
+ # return a default
146
+ #
147
+ # @param [::Array<::Symbol,::String>] names Names of the
148
+ # methods to be added
149
+ # @param [::Object] value default value
134
150
  #
135
151
  # @example Defining default values
136
152
  # class Person
@@ -166,8 +182,10 @@ module Darthjee
166
182
  # model.cars # returns 'none'
167
183
  # model.cars.equal?('none') # returns false
168
184
  # model.nick_name.equal?(model.houses) # returns true
185
+ #
186
+ # @return [::Array<::Symbol>] Name of defined methods
169
187
  def default_readers(*names, value)
170
- names.each do |name|
188
+ names.map do |name|
171
189
  default_reader(name, value)
172
190
  end
173
191
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Darthjee
4
4
  module CoreExt
5
+ # @api public
5
6
  module Date
6
7
  # Calculates the number of days between 2 dates
7
8
  #
@@ -1,10 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # @api public
3
4
  module Enumerable
4
- # (see #clean!)
5
+ # Removes any element that is nil or empty
6
+ #
7
+ # @see #clean!
5
8
  #
6
9
  # This method does not change the original
7
10
  # enumerable
11
+ #
12
+ # @example cleaning a Hash
13
+ # hash = {
14
+ # keep: 'value',
15
+ # nil_value: nil,
16
+ # empty_array: [],
17
+ # empty_string: '',
18
+ # empty_hash: {}
19
+ # }
20
+ #
21
+ # hash.clean # returns { keep: 'value' } without changing the hash
22
+ #
23
+ # @example cleaning an Array
24
+ # array = ['value', nil, [], '', {}]
25
+ #
26
+ # array.clean # returns ['value'] without changing the array
27
+ # @return [::Enumerable] same class of +self+
8
28
  def clean
9
29
  deep_dup.clean!
10
30
  end
@@ -21,23 +41,23 @@ module Enumerable
21
41
  # empty_string: '',
22
42
  # empty_hash: {}
23
43
  # }
24
- # hash.clean! # changes the hash to
25
- # # { keep: 'value' }
44
+ #
45
+ # hash.clean! # changes the hash to { keep: 'value' }
26
46
  #
27
47
  # @example cleaning an Array
28
48
  # array = ['value', nil, [], '', {}]
29
- # array.clean! # changes the array to be
30
- # # ['value']
49
+ #
50
+ # array.clean! # changes the array to be ['value']
51
+ #
52
+ # @return [::Enumerable] same class of +self+
31
53
  def clean!
32
- if is_a?(Hash)
33
- delete_if { |_k, v| empty_value?(v) }
34
- else
35
- delete_if { |v| empty_value?(v) }
36
- end
54
+ delete_if { |*args| empty_value?(args.last) }
37
55
  end
38
56
 
39
- # Maps the elements into a new value, returning
40
- # the first element that is evaluated to true
57
+ # Maps the elements into a new value, returning only one
58
+ #
59
+ # The result to be returned is
60
+ # the first mapping that is evaluated to true
41
61
  #
42
62
  # This method is equivalent to #map#find but
43
63
  # only calling the map block up to when a value
@@ -57,10 +77,14 @@ module Enumerable
57
77
  #
58
78
  # keys = %i[a b c d e]
59
79
  #
60
- # keys.map_and_find { |key| service_values.delete(key) }
61
- # # returns 'found me'
80
+ # keys.map_and_find do |key| #
81
+ # service_values.delete(key) #
82
+ # end # returns 'found me'
83
+ #
62
84
  # service_map # has lost only 3 keys returning
63
85
  # # { d: nil, e: 'didnt find me' }
86
+ #
87
+ # @return [::Object]
64
88
  def map_and_find
65
89
  mapped = nil
66
90
  find do |*args|
@@ -69,8 +93,10 @@ module Enumerable
69
93
  mapped || nil
70
94
  end
71
95
 
72
- # Maps the elements into a new value returning an
73
- # array of the values mapped to non false values
96
+ # Maps the elements into a new value returning a subset
97
+ #
98
+ # The subset returned has the values mapped to non
99
+ # false values
74
100
  #
75
101
  # This method is equivalent to call #map#select
76
102
  #
@@ -88,15 +114,18 @@ module Enumerable
88
114
  # end
89
115
  #
90
116
  # values # returns [3, 1]
91
- def map_and_select
92
- mapped = map do |*args|
93
- yield(*args)
94
- end
95
- mapped.select { |e| e }
117
+ #
118
+ # @return [::Array<::Object>]
119
+ def map_and_select(&block)
120
+ map(&block).select(&:trueful?)
96
121
  end
97
122
 
98
- # Maps values and creates a hash whose values are
99
- # the result of the #map and the keys are the original values
123
+ # Maps values and creates a hash
124
+ #
125
+ # The keys will be the original values used in the
126
+ # mapping and the values the result of the #map
127
+ #
128
+ # @return [::Hash]
100
129
  #
101
130
  # @yield (*args) the mapping block
102
131
  #
@@ -105,17 +134,25 @@ module Enumerable
105
134
  #
106
135
  # strings.map_to_hash(&:size) # returns { 'word' => 4, 'big_word' => 8 }
107
136
  def map_to_hash
108
- {}.tap do |hash|
109
- each do |element|
110
- hash[element] = yield(element)
111
- end
112
- end
137
+ map do |value|
138
+ [value, yield(value)]
139
+ end.to_h
113
140
  end
114
141
 
115
142
  private
116
143
 
144
+ # @api private
145
+ #
146
+ # @private
147
+ #
148
+ # Checks if a value is considered empty
149
+ #
150
+ # This also clean empty values
151
+ #
152
+ # @return [::TrueClass,::FalseClass]
117
153
  def empty_value?(value)
118
- value.nil? || value.try(:empty?) ||
119
- ((value.is_a?(Hash) || value.is_a?(Array)) && value.clean!.empty?)
154
+ return true unless value.present?
155
+ return unless value.is_a?(Enumerable)
156
+ value.clean!.empty?
120
157
  end
121
158
  end
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'darthjee/core_ext/hash/cameliazable'
4
+ require 'darthjee/core_ext/hash/changeable'
4
5
  require 'darthjee/core_ext/hash/key_changeable'
5
6
  require 'darthjee/core_ext/hash/transposeable'
6
7
  require 'darthjee/core_ext/hash/transformable'
7
8
 
8
9
  module Darthjee
9
10
  module CoreExt
11
+ # @api public
10
12
  module Hash
11
13
  autoload :ChainFetcher, "#{PATH}/hash/chain_fetcher"
12
14
  autoload :DeepHashConstructor, "#{PATH}/hash/deep_hash_constructor"
@@ -14,10 +16,10 @@ module Darthjee
14
16
  autoload :KeysSorter, "#{PATH}/hash/keys_sorter"
15
17
  autoload :Squasher, "#{PATH}/hash/squasher"
16
18
  autoload :ValueChanger, "#{PATH}/hash/value_changer"
17
- autoload :ToHashMapper, "#{PATH}/hash/to_hash_mapper"
18
19
 
19
20
  include Hash::Cameliazable
20
21
  include Hash::KeyChangeable
22
+ include Hash::Changeable
21
23
  include Hash::Transposeable
22
24
  include Hash::Transformable
23
25
 
@@ -39,7 +41,7 @@ module Darthjee
39
41
  # @yield (key_not_found, keys_missing) The result of the yield
40
42
  # will be the returned value instead of raising KeyError
41
43
  #
42
- # @return Object value fetched
44
+ # @return [::Object] value fetched
43
45
  #
44
46
  # @example
45
47
  # hash = {
@@ -3,17 +3,16 @@
3
3
  module Darthjee
4
4
  module CoreExt
5
5
  module Hash
6
- # Module holding methods responsible for camelizing
7
- # keys of a hash
6
+ # Module holding methods for camelizing keys of a hash
8
7
  #
9
8
  # @api public
10
9
  module Cameliazable
11
- # Change keys to CamelCase without changing the
12
- # original hash
10
+ # Change keys to CamelCase without changing the original hash
13
11
  #
14
12
  # @return [::Hash] new hash with changed keys
15
13
  # @param [::Hash] options options of camelization
16
- # @option options [::Boolean] uppercase_first_letter: flag
14
+ # @option options [::TrueClass,::FalseClass]
15
+ # uppercase_first_letter: flag
17
16
  # defining the type of CamelCase
18
17
  #
19
18
  # @see Hash::KeyChanger#camelize_keys
@@ -37,12 +36,12 @@ module Darthjee
37
36
  dup.camelize_keys!(options)
38
37
  end
39
38
 
40
- # Change keys to CamelCase changing the
41
- # original hash
39
+ # Change keys to CamelCase changing the original hash
42
40
  #
43
41
  # @return [::Hash] new hash with changed keys
44
42
  # @param [::Hash] options options of camelization
45
- # @option options [::Boolean] uppercase_first_letter: flag
43
+ # @option options [::TrueClass,::FalseClass]
44
+ # uppercase_first_letter: flag
46
45
  # defining the type of CamelCase
47
46
  #
48
47
  # @example (see #camelize_keys)
@@ -78,10 +77,42 @@ module Darthjee
78
77
  camelize_keys!(options)
79
78
  end
80
79
 
80
+ # Change all keys to be snakecase
81
+ #
82
+ # THis method does not change the original hash
83
+ #
84
+ # @param options [::Hash]
85
+ # @option options recursive [::TrueClass,::FalseClass]
86
+ # flag for recursive transformation
87
+ #
88
+ # @see Hash::KeyChanger#change_keys
89
+ #
90
+ # @example underscoring all keys
91
+ # hash = { firstKey: 1, 'SecondKey' => 2 }
92
+ #
93
+ # hash.underscore_keys # returns {
94
+ # # first_key: 1,
95
+ # # 'second_key' => 2
96
+ # # }
97
+ #
98
+ # @return [::Hash]
81
99
  def underscore_keys(options = {})
82
100
  dup.underscore_keys!(options)
83
101
  end
84
102
 
103
+ # Change all keys to be snakecase
104
+ #
105
+ # THis method changes the original hash
106
+ #
107
+ # @param options [::Hash]
108
+ # @option options recursive [::TrueClass,::FalseClass]
109
+ # flag for recursive transformation
110
+ #
111
+ # @see Hash::KeyChanger#change_keys
112
+ #
113
+ # @example (see #underscore_keys)
114
+ #
115
+ # @return [::Hash]
85
116
  def underscore_keys!(options = {})
86
117
  Hash::KeyChanger.new(self).underscore_keys(options)
87
118
  end
@@ -7,6 +7,8 @@ module Darthjee
7
7
  #
8
8
  # @api private
9
9
  #
10
+ # @author Darthjee
11
+ #
10
12
  # @see Darthjee::CoreExt::Hash#chain_fetch
11
13
  class ChainFetcher
12
14
  def initialize(hash, *keys, &block)
@@ -21,13 +23,22 @@ module Darthjee
21
23
  #
22
24
  # @return [Object] value fetched from array
23
25
  def fetch
24
- block.present? ? fetch_with_block : fetch_without_block
26
+ return fetch_with_block if block.present?
27
+ fetch_without_block
25
28
  end
26
29
 
27
30
  private
28
31
 
32
+ # @private
29
33
  attr_reader :hash, :keys, :block
30
34
 
35
+ # @private
36
+ #
37
+ # Perform chain fetch when block is given
38
+ #
39
+ # The block will be called in case a key is missed
40
+ #
41
+ # @return [Object]
31
42
  def fetch_with_block
32
43
  @hash = hash.fetch(keys.shift) do |*args|
33
44
  missed_keys = keys
@@ -37,6 +48,11 @@ module Darthjee
37
48
  hash
38
49
  end
39
50
 
51
+ # @private
52
+ #
53
+ # Perform chain fetch when block is not given
54
+ #
55
+ # @return [Object]
40
56
  def fetch_without_block
41
57
  @hash = hash.fetch(keys.shift) until keys.empty?
42
58
  hash
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Darthjee
4
+ module CoreExt
5
+ module Hash
6
+ # Methods responsible for changing hash values
7
+ #
8
+ # @api public
9
+ #
10
+ # @author Darthjee
11
+ module Changeable
12
+ # Creates a new hash with changes in its values
13
+ #
14
+ # @param options [::Hash]
15
+ # @option options [::TrueClass,::FalseClass]
16
+ # recursive (true) flag indicating recursive sorting
17
+ # @option options [::TrueClass,::FalseClass]
18
+ # skip_inner (true) Flag indicating to skip running
19
+ # transformation on Hash objects
20
+ #
21
+ # @yield (value) changing value block
22
+ #
23
+ # @return [::Hash]
24
+ #
25
+ # @example Simple Usage
26
+ # hash = { a: 1, b: 2 }
27
+ # hash.change_values do |value|
28
+ # value + 1
29
+ # end # returns { a: 2, b: 3 }
30
+ #
31
+ # @example Skipping inner hash transformation
32
+ # hash = { a: 1, b: { c: 1 } }
33
+ #
34
+ # hash.change_values(&:to_s)) # returns {
35
+ # # a: "1",
36
+ # # b: { c: "1" }
37
+ # # }
38
+ #
39
+ # @example Not skipping inner hash transformation
40
+ # hash = { a: 1, b: { c: 1 } }
41
+ #
42
+ # hash.change_values(skip_inner: false, &:to_s))
43
+ # # returns {
44
+ # # a: "1",
45
+ # # b: "{:c=>1}"
46
+ # # }
47
+ def change_values(options = {}, &block)
48
+ deep_dup.change_values!(options, &block)
49
+ end
50
+
51
+ # Changes the values of a hash
52
+ #
53
+ # @param options [::Hash]
54
+ # @option options [::TrueClass,::FalseClass]
55
+ # recursive (true) flag indicating recursive sorting
56
+ # @option options [::TrueClass,::FalseClass]
57
+ # skip_inner (true) Flag indicating to skip running
58
+ # transformation on Hash objects
59
+ #
60
+ # @yield (value) changing value block
61
+ #
62
+ # @return [::Hash]
63
+ #
64
+ # @example (see change_values)
65
+ #
66
+ # @example Changing inner hash
67
+ # inner_hash = { c: 2 }
68
+ # hash = { a: 1, b: inner_hash }
69
+ #
70
+ # hash.change_values!(&:to_s)
71
+ #
72
+ # inner_hash # changed to { c: "2" }
73
+ #
74
+ # @example Not changing inner hash
75
+ # inner_hash = { c: 2 }
76
+ # hash = { a: 1, b: inner_hash }
77
+ #
78
+ # hash.change_values!(skip_inner: false, &:to_s)
79
+ #
80
+ # hash # changed to { a: "1", b: "{:c=>2}" }
81
+ # inner_hash # still { c: 2 }
82
+ def change_values!(options = {}, &block)
83
+ Hash::ValueChanger.new(options, &block).change(self)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end