darthjee-core_ext 1.7.3 → 1.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +19 -8
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +7 -0
  5. data/.rubocop_todo.yml +7 -3
  6. data/Dockerfile +9 -0
  7. data/README.md +5 -6
  8. data/Rakefile +2 -0
  9. data/config/yardstick.rb +13 -0
  10. data/config/yardstick.yml +35 -0
  11. data/core_ext.gemspec +9 -7
  12. data/docker-compose.yml +3 -6
  13. data/lib/darthjee/core_ext/array.rb +2 -2
  14. data/lib/darthjee/core_ext/class.rb +90 -4
  15. data/lib/darthjee/core_ext/enumerable.rb +5 -1
  16. data/lib/darthjee/core_ext/hash.rb +30 -0
  17. data/lib/darthjee/core_ext/hash/cameliazable.rb +91 -0
  18. data/lib/darthjee/core_ext/hash/chain_fetcher.rb +10 -0
  19. data/lib/darthjee/core_ext/hash/key_changeable.rb +85 -53
  20. data/lib/darthjee/core_ext/hash/key_changer.rb +41 -31
  21. data/lib/darthjee/core_ext/hash/value_changer.rb +128 -11
  22. data/lib/darthjee/core_ext/version.rb +1 -1
  23. data/spec/integration/yard/{array → darthjee/core_ext/array}/hash_builder_spec.rb +3 -3
  24. data/spec/integration/yard/{array_spec.rb → darthjee/core_ext/array_spec.rb} +0 -0
  25. data/spec/integration/yard/darthjee/core_ext/class/default_value_spec.rb +143 -0
  26. data/spec/integration/yard/{date → darthjee/core_ext/date}/days_between_spec.rb +6 -6
  27. data/spec/integration/yard/{enumerable_spec.rb → darthjee/core_ext/enumerable_spec.rb} +0 -0
  28. data/spec/integration/yard/darthjee/core_ext/hash/cameliazable_spec.rb +34 -0
  29. data/spec/integration/yard/darthjee/core_ext/hash/chain_fetcher_spec.rb +51 -0
  30. data/spec/integration/yard/darthjee/core_ext/hash/key_changeable_spec.rb +48 -0
  31. data/spec/integration/yard/{hash → darthjee/core_ext/hash}/transformable_spec.rb +7 -3
  32. data/spec/integration/yard/darthjee/core_ext/hash/value_changer_spec.rb +66 -0
  33. data/spec/integration/yard/darthjee/core_ext/hash_spec.rb +42 -0
  34. data/spec/lib/array_spec.rb +27 -17
  35. data/spec/lib/class_spec.rb +108 -7
  36. data/spec/lib/darthjee/core_ext/hash/deep_hash_constructor_spec.rb +1 -1
  37. data/spec/lib/darthjee/core_ext/hash/key_changer_spec.rb +8 -8
  38. data/spec/lib/darthjee/core_ext/hash/keys_sorter_spec.rb +1 -0
  39. data/spec/lib/darthjee/core_ext/hash/to_hash_mapper_spec.rb +1 -0
  40. data/spec/lib/darthjee/core_ext/hash/value_changer_spec.rb +246 -0
  41. data/spec/lib/date_spec.rb +5 -4
  42. data/spec/lib/hash_spec.rb +45 -32
  43. data/spec/lib/math_spec.rb +1 -0
  44. data/spec/lib/numeric_spec.rb +39 -17
  45. data/spec/lib/object_spec.rb +7 -7
  46. data/spec/lib/symbol_spec.rb +2 -2
  47. data/spec/lib/time_spec.rb +5 -4
  48. data/spec/support/models/default_reader_model.rb +8 -0
  49. data/spec/support/models/default_value_model.rb +2 -0
  50. data/spec/support/models/dummy_iterator.rb +15 -0
  51. data/spec/support/models/dummy_transformer.rb +15 -0
  52. data/spec/support/shared_examples/array/array_random.rb +2 -1
  53. data/spec/support/shared_examples/clean.rb +20 -20
  54. data/spec/support/shared_examples/date.rb +18 -13
  55. data/spec/support/shared_examples/hash/chain_fetch.rb +4 -3
  56. data/spec/support/shared_examples/hash/chain_hash_keys_changer.rb +14 -7
  57. data/spec/support/shared_examples/hash/hash_keys_changer.rb +10 -4
  58. data/spec/support/shared_examples/hash/hash_transpose.rb +1 -1
  59. data/spec/support/shared_examples/hash/keys_appender.rb +14 -4
  60. data/spec/support/shared_examples/hash/keys_camelizer.rb +7 -7
  61. data/spec/support/shared_examples/hash/keys_sorter.rb +3 -3
  62. data/spec/support/shared_examples/hash/keys_underscorer.rb +2 -2
  63. data/spec/support/shared_examples/hash/map_to_hash.rb +14 -12
  64. data/spec/support/shared_examples/hash/remap.rb +4 -4
  65. data/spec/support/shared_examples/hash/value_changer.rb +40 -33
  66. metadata +70 -20
  67. data/spec/integration/yard/class/default_value_spec.rb +0 -58
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 75f22a94cfe27dfcc43f9209d7684ee7cef8546c
4
- data.tar.gz: 7077d45122b6498b960f459c5fda5c9965138902
3
+ metadata.gz: 103b4b6d1acc61970210009223f1dafb42ffe566
4
+ data.tar.gz: 6887e4ef498e5e8edaa14c604ac8b79b91f9e709
5
5
  SHA512:
6
- metadata.gz: df8e4a2c6c6a6b27611d9ba1d52785323239ec7df2a9239862a1116db897b4112a875d6d279f1a507c7906615247d88375198a9e921e33d9272c6e76d8e46d4c
7
- data.tar.gz: a71629faafba5302d768e80c556d5deec6249e9a09b14f1a3fd7457e97edf4d14bcd075ca89b89d0c9a2110e2dfcf6e6b86ea3540c43ad334c5e50de1da70b8b
6
+ metadata.gz: 21eed9f42d42a66a273413cdd784b32e3f1b07b9be39e6c34e8dba7162c442ad2cb4b96be93177a4d6b33e87e20365524b4e5d72bccbe27cbc22d1f0943c28db
7
+ data.tar.gz: 6de12c71400aa5f5cbd50b7614df418c50815ddf4f222cfe56b3cc852acbd2a745108e3f56394f065de4fb9c518fe02b0a77ddc02669f626b17f0c77b7b17054
@@ -2,13 +2,24 @@ version: 2
2
2
  jobs:
3
3
  build:
4
4
  docker:
5
- - image: circleci/ruby:2.4.1
5
+ - image: darthjee/circleci_ruby_240:0.1.0
6
6
  steps:
7
7
  - checkout
8
- - run: curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
9
- - run: chmod +x ./cc-test-reporter
10
- - run: ./cc-test-reporter before-build
11
- - run: bundle install
12
- - run: bundle exec rspec
13
- - run: rubocop
14
- - run: ./cc-test-reporter after-build --exit-code $?
8
+ - run:
9
+ name: Prepare Coverage Test Report
10
+ command: cc-test-reporter before-build
11
+ - run:
12
+ name: Bundle Install
13
+ command: bundle install
14
+ - run:
15
+ name: RSpec
16
+ command: bundle exec rspec
17
+ - run:
18
+ name: Rubocop
19
+ command: rubocop
20
+ - run:
21
+ name: Coverage Test Report
22
+ command: cc-test-reporter after-build --exit-code $?
23
+ - run:
24
+ name: Yardstick coverage check
25
+ command: bundle exec rake verify_measurements
data/.gitignore CHANGED
@@ -3,3 +3,4 @@ pkg
3
3
  Gemfile.lock
4
4
  doc
5
5
  .yardoc
6
+ measurement
@@ -1,3 +1,4 @@
1
+ require: rubocop-rspec
1
2
  inherit_from: .rubocop_todo.yml
2
3
 
3
4
  AllCops:
@@ -11,3 +12,9 @@ Metrics/BlockLength:
11
12
  Exclude:
12
13
  - 'spec/**/*_spec.rb'
13
14
  - 'spec/support/shared_*/**/*.rb'
15
+
16
+ RSpec/AlignLeftLetBrace:
17
+ Enabled: true
18
+
19
+ RSpec/NestedGroups:
20
+ Max: 5
@@ -1,12 +1,16 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2018-07-26 20:39:06 +0000 using RuboCop version 0.58.1.
3
+ # on 2019-02-18 18:10:37 +0000 using RuboCop version 0.58.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 16
9
+ # Offense count: 3
10
+ # Configuration parameters: AggregateFailuresByDefault.
11
+ RSpec/MultipleExpectations:
12
+ Max: 2
13
+
14
+ # Offense count: 24
10
15
  Style/Documentation:
11
16
  Enabled: false
12
-
@@ -0,0 +1,9 @@
1
+ FROM darthjee/ruby_240:0.2.2
2
+
3
+ USER app
4
+ COPY ./ /home/app/app/
5
+
6
+ RUN gem uninstall bundler
7
+ RUN gem install bundler -v '1.17.3'
8
+ RUN bundle install
9
+
data/README.md CHANGED
@@ -3,9 +3,8 @@ Darthjee/CoreExt
3
3
 
4
4
  ![core_ext](https://raw.githubusercontent.com/darthjee/core_ext/master/mech.jpg)
5
5
 
6
- [![Code Climate](https://codeclimate.com/github/darthjee/core_ext/badges/gpa.svg)](https://codeclimate.com/github/darthjee/core_ext)
7
- [![Test Coverage](https://codeclimate.com/github/darthjee/core_ext/badges/coverage.svg)](https://codeclimate.com/github/darthjee/core_ext/coverage)
8
- [![Issue Count](https://codeclimate.com/github/darthjee/core_ext/badges/issue_count.svg)](https://codeclimate.com/github/darthjee/core_ext)
6
+ [![Maintainability](https://api.codeclimate.com/v1/badges/23f472dcc717ed285737/maintainability)](https://codeclimate.com/github/darthjee/core_ext/maintainability)
7
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/23f472dcc717ed285737/test_coverage)](https://codeclimate.com/github/darthjee/core_ext/test_coverage)
9
8
 
10
9
  Yard Documentation
11
10
  -------------------
@@ -16,17 +15,17 @@ This project adds some new methods to the core ruby classes
16
15
 
17
16
  To use core-ext either intall directly
18
17
 
19
- ```console
18
+ ```shell
20
19
  gem install darthjee-core_ext
21
20
  ```
22
21
 
23
22
  or add it to Gemfile
24
23
 
25
- ```
24
+ ```shell
26
25
  gem 'darthjee-core_ext'
27
26
  ```
28
27
 
29
- ```console
28
+ ```shell
30
29
  bundle install darthjee-core_ext
31
30
  ```
32
31
 
data/Rakefile CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
+ require 'yardstick/rake/measurement'
6
+ require './config/yardstick'
5
7
 
6
8
  RSpec::Core::RakeTask.new
7
9
 
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yardstick/rake/measurement'
4
+ require 'yardstick/rake/verify'
5
+ require 'yaml'
6
+
7
+ options = YAML.load_file('config/yardstick.yml')
8
+
9
+ Yardstick::Rake::Measurement.new(:yardstick_measure, options) do |measurement|
10
+ measurement.output = 'measurement/report.txt'
11
+ end
12
+
13
+ Yardstick::Rake::Verify.new(:verify_measurements, options)
@@ -0,0 +1,35 @@
1
+ threshold: 65.4
2
+ require_exact_threshold: false
3
+ rules:
4
+ ApiTag::Presence:
5
+ enabled: true
6
+ exclude: []
7
+ ApiTag::Inclusion:
8
+ enabled: true
9
+ exclude: []
10
+ ApiTag::ProtectedMethod:
11
+ enabled: true
12
+ exclude: []
13
+ ApiTag::PrivateMethod:
14
+ enabled: true
15
+ exclude: []
16
+ ExampleTag:
17
+ enabled: true
18
+ exclude: []
19
+ ReturnTag:
20
+ enabled: true
21
+ exclude:
22
+ - Darthjee::CoreExt::Hash::ChainFetcher
23
+ Summary::Presence:
24
+ enabled: true
25
+ exclude:
26
+ - Darthjee::CoreExt::Hash::ChainFetcher
27
+ Summary::Length:
28
+ enabled: true
29
+ exclude: []
30
+ Summary::Delimiter:
31
+ enabled: true
32
+ exclude: []
33
+ Summary::SingleLine:
34
+ enabled: true
35
+ exclude: []
@@ -20,11 +20,13 @@ Gem::Specification.new do |gem|
20
20
 
21
21
  gem.add_runtime_dependency 'activesupport', '>= 5.2.x'
22
22
 
23
- gem.add_development_dependency 'bundler'
24
- gem.add_development_dependency 'pry-nav', '~> 0.2.4'
25
- gem.add_development_dependency 'rake', '>= 12.3.1'
26
- gem.add_development_dependency 'rspec', '>= 3.8'
27
- gem.add_development_dependency 'rubocop', '0.58.1'
28
- gem.add_development_dependency 'simplecov', '~> 0.16.x'
29
- gem.add_development_dependency 'yard', '>= 0.9'
23
+ gem.add_development_dependency 'bundler', '~> 1.17.x'
24
+ gem.add_development_dependency 'pry-nav', '~> 0.2.4'
25
+ gem.add_development_dependency 'rake', '>= 12.3.1'
26
+ gem.add_development_dependency 'rspec', '>= 3.8'
27
+ gem.add_development_dependency 'rubocop', '0.58.1'
28
+ gem.add_development_dependency 'rubocop-rspec', '1.30.0'
29
+ gem.add_development_dependency 'simplecov', '~> 0.16.x'
30
+ gem.add_development_dependency 'yard', '>= 0.9.18'
31
+ gem.add_development_dependency 'yardstick', '>= 0.9.9'
30
32
  end
@@ -1,18 +1,15 @@
1
1
  version: '2'
2
2
  services:
3
3
  base: &base
4
- image: ruby:2.4.0
4
+ build:
5
+ context: ./
5
6
  working_dir: /home/app/core_ext
6
7
  volumes:
7
8
  - .:/home/app/core_ext
8
- - core_ext_gems_2_4_0:/usr/local/bundle
9
9
 
10
10
  #################### CONTAINERS ####################
11
11
 
12
12
  core_ext:
13
13
  <<: *base
14
14
  container_name: core_ext
15
- command: bash -c 'gem install bundler; bundle install; bundle exec rspec'
16
-
17
- volumes:
18
- core_ext_gems_2_4_0:
15
+ command: bash -c 'bundle exec rspec'
@@ -142,7 +142,7 @@ module Darthjee
142
142
  # array.random # might return 10, 20 or 30
143
143
  # array # returns unchanged [10, 20, 30]
144
144
  def random
145
- self[rand(size)]
145
+ self[Random.rand(size)]
146
146
  end
147
147
 
148
148
  # Reeturns a random element of the array removing it from the array
@@ -152,7 +152,7 @@ module Darthjee
152
152
  # array.random! # might return 10, 20 or 30 ... lets say 20
153
153
  # array # returns changed [20, 30]
154
154
  def random!
155
- slice!(rand(size))
155
+ slice!(Random.rand(size))
156
156
  end
157
157
  end
158
158
  end
@@ -48,6 +48,8 @@ module Darthjee
48
48
  # methods to be added
49
49
  # @param [::Object] value default value
50
50
  #
51
+ # @see default_value
52
+ #
51
53
  # @example Defining a default values
52
54
  # class MyClass
53
55
  # default_values :name, :nick_name, 'John'
@@ -57,8 +59,6 @@ module Darthjee
57
59
  # MyClass.new.nick_name # returns 'John'
58
60
  #
59
61
  # @example Comparing value across instances
60
- # # frozen_string_literal: false
61
- #
62
62
  # class MyClass
63
63
  # default_values :name, :nick_name, 'John'
64
64
  # end
@@ -70,8 +70,6 @@ module Darthjee
70
70
  # instance.name.equal?(other.name) # returns true
71
71
  #
72
72
  # @example Comparing value across methods
73
- # # frozen_string_literal: false
74
- #
75
73
  # class MyClass
76
74
  # default_values :name, :nick_name, 'John'
77
75
  # end
@@ -85,6 +83,94 @@ module Darthjee
85
83
  default_value(name, value)
86
84
  end
87
85
  end
86
+
87
+ # @!visibility public
88
+ #
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
+ #
93
+ # @example Defining a default value
94
+ # class Person
95
+ # attr_writer :name
96
+ # default_reader :name, 'John Doe'
97
+ # end
98
+ #
99
+ # model = Person.new
100
+ #
101
+ # model.name # returns 'John Doe'
102
+ #
103
+ # @example Changing the instance value
104
+ #
105
+ # model = Person.new
106
+ # model.name # returns 'John Doe'
107
+ #
108
+ # model.name = 'Joe'
109
+ # model.name # returns 'Joe'
110
+ #
111
+ # model.name = nil
112
+ # model.name # returns nil
113
+ #
114
+ # @example Changing values accros instances
115
+ #
116
+ # model = Person.new
117
+ # model.name # returns 'John Doe'
118
+ #
119
+ # model.name = 'Bob'
120
+ # model.name # returns 'Bob'
121
+ # Person.new.name # returns 'John Doe'
122
+ def default_reader(name, value)
123
+ define_method(name) do
124
+ return value unless instance_variable_defined?("@#{name}")
125
+ instance_variable_get("@#{name}")
126
+ end
127
+ end
128
+
129
+ # @!visibility public
130
+ #
131
+ # Creates methods that will act as readers, but will
132
+ # return a default value when the instance variables
133
+ # ware never set
134
+ #
135
+ # @example Defining default values
136
+ # class Person
137
+ # attr_writer :cars, :houses
138
+ # default_reader :cars, :houses, 'none'
139
+ # end
140
+ #
141
+ # model = Person.new
142
+ #
143
+ # model.cars # returns 'none'
144
+ #
145
+ # @example Changing the instance value
146
+ #
147
+ # model = Person.new
148
+ # model.cars # returns 'none'
149
+ #
150
+ # model.cars = ['volvo']
151
+ # model.cars # returns ['volvo']
152
+ #
153
+ # model.cars = nil
154
+ # model.cars # returns nil
155
+ #
156
+ # @example Changing values accros instances
157
+ #
158
+ # model = Person.new
159
+ # model.cars # returns 'none'
160
+ #
161
+ # model.cars = ['volvo']
162
+ # model.cars # returns ['volvo']
163
+ # Person.new.cars # returns 'none'
164
+ #
165
+ # @example Comparing value across methods
166
+ # model.cars # returns 'none'
167
+ # model.cars.equal?('none') # returns false
168
+ # model.nick_name.equal?(model.houses) # returns true
169
+ def default_readers(*names, value)
170
+ names.each do |name|
171
+ default_reader(name, value)
172
+ end
173
+ end
88
174
  end
89
175
  end
90
176
  end
@@ -1,13 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Enumerable
4
+ # (see #clean!)
5
+ #
6
+ # This method does not change the original
7
+ # enumerable
4
8
  def clean
5
9
  deep_dup.clean!
6
10
  end
7
11
 
8
12
  # Removes any element that is nil or empty
9
13
  #
10
- # @returns [::Enumerable] the enumerable itself
14
+ # @return [::Enumerable] the enumerable itself
11
15
  #
12
16
  # @example cleaning a Hash
13
17
  # hash = {
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'darthjee/core_ext/hash/cameliazable'
3
4
  require 'darthjee/core_ext/hash/key_changeable'
4
5
  require 'darthjee/core_ext/hash/transposeable'
5
6
  require 'darthjee/core_ext/hash/transformable'
@@ -15,6 +16,7 @@ module Darthjee
15
16
  autoload :ValueChanger, "#{PATH}/hash/value_changer"
16
17
  autoload :ToHashMapper, "#{PATH}/hash/to_hash_mapper"
17
18
 
19
+ include Hash::Cameliazable
18
20
  include Hash::KeyChangeable
19
21
  include Hash::Transposeable
20
22
  include Hash::Transformable
@@ -23,6 +25,34 @@ module Darthjee
23
25
  # Fetching methods
24
26
  #########################################
25
27
 
28
+ # Crawls through the hash fetching a key value from inside it
29
+ #
30
+ # this is the equivalent of chaining several calls to fetch method
31
+ #
32
+ # ```
33
+ # hash.chain_fetch(:key1, :key2)
34
+ # hash.fetch(:key1).fetch(:key2)
35
+ # ```
36
+ #
37
+ # @param [::Array<::Object>] keys List of keys to be fetched
38
+ # @param [::Proc] block block to be called in case of key not found
39
+ # @yield (key_not_found, keys_missing) The result of the yield
40
+ # will be the returned value instead of raising KeyError
41
+ #
42
+ # @return Object value fetched
43
+ #
44
+ # @example
45
+ # hash = {
46
+ # a: {
47
+ # b: { c: 1, d: 2 }
48
+ # }
49
+ # }
50
+ #
51
+ # hash.chain_fetch(:a, :b, :c) # returns 1
52
+ # hash.chain_fetch(:a, :c, :d) # raises KeyError
53
+ # hash.chain_fetch(:a, :c, :d) { 10 } # returns 10
54
+ # hash.chain_fetch(:a, :c, :d) { |key, _| key } # returns :c
55
+ # hash.chain_fetch(:a, :c, :d) { |_, missing| missing } # returns [:d]
26
56
  def chain_fetch(*keys, &block)
27
57
  ::Hash::ChainFetcher.new(self, *keys, &block).fetch
28
58
  end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Darthjee
4
+ module CoreExt
5
+ module Hash
6
+ # Module holding methods responsible for camelizing
7
+ # keys of a hash
8
+ #
9
+ # @api public
10
+ module Cameliazable
11
+ # Change keys to CamelCase without changing the
12
+ # original hash
13
+ #
14
+ # @return [::Hash] new hash with changed keys
15
+ # @param [::Hash] options options of camelization
16
+ # @option options [::Boolean] uppercase_first_letter: flag
17
+ # defining the type of CamelCase
18
+ #
19
+ # @see Hash::KeyChanger#camelize_keys
20
+ #
21
+ # @example
22
+ # hash = { first_key: 1, 'second_key' => 2 }
23
+ # hash.camelize_keys # returns {
24
+ # # FirstKey: 1,
25
+ # # 'SecondKey' => 2
26
+ # # }
27
+ #
28
+ # @example
29
+ # hash = { first_key: 1, 'second_key' => 2 }
30
+ # options = { uppercase_first_letter: false }
31
+ # hash.camelize_keys(options) # returns {
32
+ # # firstKey: 1,
33
+ # # 'secondKey' => 2
34
+ # # }
35
+ #
36
+ def camelize_keys(options = {})
37
+ dup.camelize_keys!(options)
38
+ end
39
+
40
+ # Change keys to CamelCase changing the
41
+ # original hash
42
+ #
43
+ # @return [::Hash] new hash with changed keys
44
+ # @param [::Hash] options options of camelization
45
+ # @option options [::Boolean] uppercase_first_letter: flag
46
+ # defining the type of CamelCase
47
+ #
48
+ # @example (see #camelize_keys)
49
+ #
50
+ # @see #camelize_keys
51
+ def camelize_keys!(options = {})
52
+ Hash::KeyChanger.new(self).camelize_keys(options)
53
+ end
54
+
55
+ # Camelize all keys in the hash as `key.camelize(:lower)
56
+ #
57
+ # @return [::Hash] the resulting hash
58
+ #
59
+ # @example
60
+ # hash = { first_key: 1, 'second_key' => 2 }
61
+ # hash.lower_camelize_keys # {
62
+ # # firstKey: 1,
63
+ # # 'secondKey' => 2
64
+ # # }
65
+ #
66
+ def lower_camelize_keys(options = {})
67
+ dup.lower_camelize_keys!(options)
68
+ end
69
+
70
+ # Camelize all keys in the hash
71
+ #
72
+ # @return [::Hash] self after changing the keys
73
+ #
74
+ # @example (see #lower_camelize_keys)
75
+ def lower_camelize_keys!(options = {})
76
+ options = options.merge(uppercase_first_letter: false)
77
+
78
+ camelize_keys!(options)
79
+ end
80
+
81
+ def underscore_keys(options = {})
82
+ dup.underscore_keys!(options)
83
+ end
84
+
85
+ def underscore_keys!(options = {})
86
+ Hash::KeyChanger.new(self).underscore_keys(options)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end