darthjee-core_ext 1.7.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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