darthjee-core_ext 1.5.6 → 1.6.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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +14 -0
- data/.rubocop.yml +17 -0
- data/.rubocop_todo.yml +12 -0
- data/Gemfile +2 -1
- data/Rakefile +2 -0
- data/core_ext.gemspec +6 -3
- data/lib/darthjee/core_ext/array/hash_builder.rb +21 -13
- data/lib/darthjee/core_ext/array.rb +4 -2
- data/lib/darthjee/core_ext/date.rb +2 -0
- data/lib/darthjee/core_ext/enumerable.rb +5 -3
- data/lib/darthjee/core_ext/hash/chain_fetcher.rb +33 -0
- data/lib/darthjee/core_ext/hash/deep_hash_constructor.rb +62 -60
- data/lib/darthjee/core_ext/hash/key_changer.rb +64 -54
- data/lib/darthjee/core_ext/hash/keys_sorter.rb +31 -0
- data/lib/darthjee/core_ext/hash/squasher.rb +31 -0
- data/lib/darthjee/core_ext/hash/to_hash_mapper.rb +21 -0
- data/lib/darthjee/core_ext/hash/value_changer.rb +48 -44
- data/lib/darthjee/core_ext/hash.rb +28 -58
- data/lib/darthjee/core_ext/math.rb +4 -2
- data/lib/darthjee/core_ext/numeric.rb +5 -3
- data/lib/darthjee/core_ext/object/default_value.rb +2 -1
- data/lib/darthjee/core_ext/object.rb +2 -0
- data/lib/darthjee/core_ext/symbol.rb +2 -0
- data/lib/darthjee/core_ext/time.rb +2 -0
- data/lib/darthjee/core_ext/version.rb +3 -1
- data/lib/darthjee/core_ext.rb +2 -0
- data/lib/darthjee.rb +2 -1
- data/spec/lib/array_spec.rb +27 -19
- data/spec/lib/date_spec.rb +2 -0
- data/spec/lib/enumerable_spec.rb +10 -8
- data/spec/lib/hash/chain_fetcher_spec.rb +11 -0
- data/spec/lib/hash/deep_hash_constructor_spec.rb +3 -1
- data/spec/lib/hash/key_changer_spec.rb +19 -5
- data/spec/lib/hash/keys_sorter_spec.rb +10 -0
- data/spec/lib/hash/squasher_spec.rb +9 -0
- data/spec/lib/hash/to_hash_mapper_spec.rb +10 -0
- data/spec/lib/hash_spec.rb +16 -46
- data/spec/lib/math_spec.rb +2 -0
- data/spec/lib/numeric_spec.rb +2 -0
- data/spec/lib/object/default_value_spe.rb +2 -0
- data/spec/lib/object_spec.rb +2 -0
- data/spec/lib/symbol_spec.rb +2 -0
- data/spec/lib/time_spec.rb +2 -0
- data/spec/spec_helper.rb +2 -1
- data/spec/support/models/default_value.rb +2 -0
- data/spec/support/models/hash/value_changer/dummy.rb +19 -13
- data/spec/support/models/hash/value_changer/dummy_iteractor.rb +13 -8
- data/spec/support/shared_examples/{array_random.rb → array/array_random.rb} +5 -2
- data/spec/support/shared_examples/clean.rb +14 -2
- data/spec/support/shared_examples/date.rb +2 -0
- data/spec/support/shared_examples/expected.rb +2 -1
- data/spec/support/shared_examples/{chain_fetch.rb → hash/chain_fetch.rb} +9 -7
- data/spec/support/shared_examples/{chain_hash_keys_changer.rb → hash/chain_hash_keys_changer.rb} +14 -11
- data/spec/support/shared_examples/{hash_keys_changer.rb → hash/hash_keys_changer.rb} +7 -5
- data/spec/support/shared_examples/hash/hash_squasher.rb +23 -0
- data/spec/support/shared_examples/{hash_transpose.rb → hash/hash_transpose.rb} +8 -6
- data/spec/support/shared_examples/hash/keys_appender.rb +69 -0
- data/spec/support/shared_examples/{keys_camelizer.rb → hash/keys_camelizer.rb} +6 -4
- data/spec/support/shared_examples/hash/keys_sorter.rb +67 -0
- data/spec/support/shared_examples/{keys_underscorer.rb → hash/keys_underscorer.rb} +4 -3
- data/spec/support/shared_examples/{map_to_hash.rb → hash/map_to_hash.rb} +16 -16
- data/spec/support/shared_examples/{remap.rb → hash/remap.rb} +16 -13
- data/spec/support/shared_examples/hash/value_changer.rb +192 -0
- metadata +76 -30
- data/circle.yml +0 -10
- data/spec/support/shared_examples/keys_appender.rb +0 -43
- data/spec/support/shared_examples/value_changer.rb +0 -147
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f91f602918068826bc0e97f7e555f680226b429c
|
4
|
+
data.tar.gz: ccb555082fd2cc831024d1f9b565f6ca2dcf543a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11af6fe53de559202c101a5809ccbeca632c8daaba4a49d8a7415a75885f697d378bbd970607ee89f5d26ec145d1309875b0f20d2fa2abbca2f7ba55eadcbe01
|
7
|
+
data.tar.gz: 874149c8200c544b455efce3302aba8a720794272457b72dcb0353d9d05df68441a26753f9a368a082d92a1cf23947791894aee76aba280c039eb3159805d2f5
|
@@ -0,0 +1,14 @@
|
|
1
|
+
version: 2
|
2
|
+
jobs:
|
3
|
+
build:
|
4
|
+
docker:
|
5
|
+
- image: circleci/ruby:2.4.1
|
6
|
+
steps:
|
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 $?
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
TargetRubyVersion: 2.4
|
5
|
+
|
6
|
+
Naming/PredicateName:
|
7
|
+
Exclude:
|
8
|
+
- 'lib/darthjee/core_ext/object.rb'
|
9
|
+
|
10
|
+
Metrics/ClassLength:
|
11
|
+
Exclude:
|
12
|
+
- 'lib/darthjee/core_ext/hash.rb'
|
13
|
+
|
14
|
+
Metrics/BlockLength:
|
15
|
+
Exclude:
|
16
|
+
- 'spec/**/*_spec.rb'
|
17
|
+
- 'spec/support/shared_*/**/*.rb'
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2018-07-26 20:39:06 +0000 using RuboCop version 0.58.1.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 16
|
10
|
+
Style/Documentation:
|
11
|
+
Enabled: false
|
12
|
+
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/core_ext.gemspec
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'darthjee/core_ext/version'
|
5
6
|
|
@@ -20,8 +21,10 @@ Gem::Specification.new do |gem|
|
|
20
21
|
gem.add_runtime_dependency 'activesupport', '>= 5.x'
|
21
22
|
|
22
23
|
gem.add_development_dependency 'bundler', '~> 1.6'
|
24
|
+
gem.add_development_dependency 'pry-nav', '~> 0.2.4'
|
23
25
|
gem.add_development_dependency 'rake', '>= 12.3.1'
|
24
26
|
gem.add_development_dependency 'rspec', '>= 3.7'
|
25
|
-
gem.add_development_dependency '
|
27
|
+
gem.add_development_dependency 'rubocop'
|
26
28
|
gem.add_development_dependency 'simplecov', '~> 0.14.1'
|
29
|
+
gem.add_development_dependency 'yard'
|
27
30
|
end
|
@@ -1,20 +1,28 @@
|
|
1
|
-
|
2
|
-
attr_accessor :values, :keys
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
3
|
+
class Array
|
4
|
+
class HashBuilder
|
5
|
+
attr_accessor :values, :keys
|
8
6
|
|
9
|
-
|
10
|
-
|
7
|
+
def initialize(values, keys)
|
8
|
+
@values = values.dup
|
9
|
+
@keys = keys.dup
|
10
|
+
end
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
def build
|
13
|
+
fixes_sizes
|
14
|
+
|
15
|
+
Hash[[keys, values].transpose]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
14
19
|
|
15
|
-
|
20
|
+
def fixes_sizes
|
21
|
+
values.concat Array.new(keys.size - values.size) if needs_resizing?
|
22
|
+
end
|
16
23
|
|
17
|
-
|
18
|
-
|
24
|
+
def needs_resizing?
|
25
|
+
keys.size > values.size
|
26
|
+
end
|
19
27
|
end
|
20
28
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Array
|
2
|
-
autoload :HashBuilder,
|
4
|
+
autoload :HashBuilder, 'darthjee/core_ext/array/hash_builder'
|
3
5
|
|
4
6
|
def mapk(*keys)
|
5
7
|
keys.inject(self) do |enum, key|
|
@@ -39,6 +41,6 @@ class Array
|
|
39
41
|
end
|
40
42
|
|
41
43
|
def random!
|
42
|
-
|
44
|
+
slice!(rand(size))
|
43
45
|
end
|
44
46
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Enumerable
|
2
4
|
def clean
|
3
5
|
deep_dup.clean!
|
@@ -38,8 +40,8 @@ module Enumerable
|
|
38
40
|
|
39
41
|
private
|
40
42
|
|
41
|
-
def empty_value?(
|
42
|
-
|
43
|
-
((
|
43
|
+
def empty_value?(value)
|
44
|
+
value.nil? || value.try(:empty?) ||
|
45
|
+
((value.is_a?(Hash) || value.is_a?(Array)) && value.clean!.empty?)
|
44
46
|
end
|
45
47
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
class ChainFetcher
|
5
|
+
def initialize(hash, *keys, &block)
|
6
|
+
@hash = hash
|
7
|
+
@keys = keys
|
8
|
+
@block = block
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch
|
12
|
+
block.present? ? fetch_with_block : fetch_without_block
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :hash, :keys, :block
|
18
|
+
|
19
|
+
def fetch_with_block
|
20
|
+
@hash = hash.fetch(keys.shift) do |*args|
|
21
|
+
missed_keys = keys
|
22
|
+
@keys = []
|
23
|
+
block.call(*(args + [missed_keys]))
|
24
|
+
end until keys.empty?
|
25
|
+
hash
|
26
|
+
end
|
27
|
+
|
28
|
+
def fetch_without_block
|
29
|
+
@hash = hash.fetch(keys.shift) until keys.empty?
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,83 +1,85 @@
|
|
1
|
-
|
2
|
-
attr_accessor :separator
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
class Hash
|
4
|
+
class DeepHashConstructor
|
5
|
+
attr_accessor :separator
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
array_deep_hash(object)
|
11
|
-
elsif object.is_a? Hash
|
12
|
-
hash_deep_hash(object)
|
13
|
-
else
|
14
|
-
object
|
7
|
+
def initialize(separator)
|
8
|
+
@separator = separator
|
15
9
|
end
|
16
|
-
end
|
17
10
|
|
18
|
-
|
11
|
+
def deep_hash(object)
|
12
|
+
if object.is_a? Array
|
13
|
+
array_deep_hash(object)
|
14
|
+
elsif object.is_a? Hash
|
15
|
+
hash_deep_hash(object)
|
16
|
+
else
|
17
|
+
object
|
18
|
+
end
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
array.map { |v| v.is_a?(Hash) ? deep_hash(v) : v }
|
22
|
-
end
|
21
|
+
private
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
base_key, child_key = split_key(k, separator)
|
28
|
-
set_deep_hash_positioned_value(new_hash, base_key, v, child_key)
|
29
|
-
end
|
23
|
+
def array_deep_hash(array)
|
24
|
+
array.map { |v| v.is_a?(Hash) ? deep_hash(v) : v }
|
25
|
+
end
|
30
26
|
|
31
|
-
|
32
|
-
|
27
|
+
def hash_deep_hash(hash)
|
28
|
+
{}.tap do |new_hash|
|
29
|
+
hash.each do |k, v|
|
30
|
+
base_key, child_key = split_key(k, separator)
|
31
|
+
set_deep_hash_positioned_value(new_hash, base_key, v, child_key)
|
32
|
+
end
|
33
|
+
|
34
|
+
new_hash.each do |k, v|
|
35
|
+
new_hash[k] = deep_hash(v)
|
36
|
+
end
|
33
37
|
end
|
34
38
|
end
|
35
|
-
end
|
36
39
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
def split_key(key, separator)
|
41
|
+
separator_rxp = separator == '.' ? "\\#{separator}" : separator
|
42
|
+
skipper = "[^#{separator}]"
|
43
|
+
regexp = Regexp.new("^(#{skipper}*)#{separator_rxp}(.*)")
|
44
|
+
match = key.match(regexp)
|
42
45
|
|
43
|
-
|
44
|
-
|
46
|
+
match ? match[1..2] : key
|
47
|
+
end
|
45
48
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
+
def set_deep_hash_array_value(hash, base_key, index, value, key = nil)
|
50
|
+
key_without_index = base_key.gsub("[#{index}]", '')
|
51
|
+
hash[key_without_index] ||= []
|
49
52
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
if key.nil?
|
54
|
+
hash[key_without_index][index] = value
|
55
|
+
else
|
56
|
+
hash[key_without_index][index] ||= {}
|
57
|
+
hash[key_without_index][index][key] = value
|
58
|
+
end
|
55
59
|
end
|
56
|
-
end
|
57
60
|
|
58
|
-
|
59
|
-
|
61
|
+
def set_deep_hash_positioned_value(new_hash, base_key, value, child_key)
|
62
|
+
index = array_index(base_key)
|
60
63
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
64
|
+
if index
|
65
|
+
set_deep_hash_array_value(new_hash, base_key, index, value, child_key)
|
66
|
+
else
|
67
|
+
set_deep_hash_value(new_hash, base_key, value, child_key)
|
68
|
+
end
|
65
69
|
end
|
66
|
-
end
|
67
70
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
match[1].to_i
|
71
|
+
def array_index(key)
|
72
|
+
match = key.match(/\[([^)]+)\]/)
|
73
|
+
match && match[1].to_i
|
72
74
|
end
|
73
|
-
end
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
76
|
+
def set_deep_hash_value(hash, base_key, value, key = nil)
|
77
|
+
if key.nil?
|
78
|
+
hash[base_key] = value
|
79
|
+
else
|
80
|
+
hash[base_key] ||= {}
|
81
|
+
hash[base_key][key] = value
|
82
|
+
end
|
81
83
|
end
|
82
84
|
end
|
83
85
|
end
|
@@ -1,76 +1,86 @@
|
|
1
|
-
|
2
|
-
attr_reader :hash, :block
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
class Hash
|
4
|
+
class KeyChanger
|
5
|
+
def initialize(hash)
|
6
|
+
@hash = hash
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
def remap(keys_map)
|
10
|
+
new_hash = {}
|
11
|
+
keys_map.each do |o, n|
|
12
|
+
new_hash[n] = hash.delete(o)
|
13
|
+
end
|
14
|
+
hash.merge! new_hash
|
15
|
+
end
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
def change_keys(settings = {}, &block)
|
18
|
+
merge_options({
|
19
|
+
recursive: true
|
20
|
+
}, settings)
|
21
|
+
|
22
|
+
if options[:recursive]
|
23
|
+
hash.deep_transform_keys!(&block)
|
24
|
+
else
|
25
|
+
hash.transform_keys!(&block)
|
26
|
+
end
|
17
27
|
end
|
18
|
-
end
|
19
28
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
29
|
+
def camelize_keys(settings = {})
|
30
|
+
merge_options({
|
31
|
+
uppercase_first_letter: true
|
32
|
+
}, settings)
|
24
33
|
|
25
|
-
|
34
|
+
type = options[:uppercase_first_letter] ? :upper : :lower
|
26
35
|
|
27
|
-
|
28
|
-
|
36
|
+
change_keys do |k|
|
37
|
+
k.camelize(type)
|
38
|
+
end
|
29
39
|
end
|
30
|
-
end
|
31
40
|
|
32
|
-
|
33
|
-
|
41
|
+
def underscore_keys(settings = {})
|
42
|
+
merge_options({}, settings)
|
34
43
|
|
35
|
-
|
36
|
-
k.underscore
|
44
|
+
change_keys(&:underscore)
|
37
45
|
end
|
38
|
-
end
|
39
46
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
47
|
+
def change_text(options = {})
|
48
|
+
merge_options({
|
49
|
+
type: :keep
|
50
|
+
}, options)
|
44
51
|
|
45
|
-
|
46
|
-
|
52
|
+
change_keys do |key|
|
53
|
+
cast_new_key yield(key), key.class
|
54
|
+
end
|
47
55
|
end
|
48
|
-
end
|
49
56
|
|
50
|
-
|
57
|
+
private
|
51
58
|
|
52
|
-
|
53
|
-
@options = {}.merge!(default).merge!(custom).merge!(options)
|
54
|
-
end
|
59
|
+
attr_reader :hash
|
55
60
|
|
56
|
-
|
57
|
-
|
58
|
-
|
61
|
+
def merge_options(default, custom)
|
62
|
+
@options = {}.merge!(default).merge!(custom).merge!(options)
|
63
|
+
end
|
59
64
|
|
60
|
-
|
61
|
-
|
62
|
-
when :symbol then
|
63
|
-
key.to_sym
|
64
|
-
when :string then
|
65
|
-
key.to_s
|
65
|
+
def options
|
66
|
+
@options ||= {}
|
66
67
|
end
|
67
|
-
end
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
def cast_new_key(key, old_clazz)
|
70
|
+
case class_cast(old_clazz)
|
71
|
+
when :symbol then
|
72
|
+
key.to_sym
|
73
|
+
when :string then
|
74
|
+
key.to_s
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def keep_class?
|
79
|
+
options[:type] == :keep
|
80
|
+
end
|
72
81
|
|
73
|
-
|
74
|
-
|
82
|
+
def class_cast(old_clazz)
|
83
|
+
keep_class? && old_clazz.to_s.downcase.to_sym || options[:type]
|
84
|
+
end
|
75
85
|
end
|
76
|
-
end
|
86
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
class KeysSorter
|
5
|
+
def initialize(hash, recursive: true)
|
6
|
+
@hash = hash
|
7
|
+
@recursive = recursive
|
8
|
+
end
|
9
|
+
|
10
|
+
def sort
|
11
|
+
{}.tap do |new_hash|
|
12
|
+
sorted_keys.each do |key|
|
13
|
+
new_hash[key] = change_value(hash[key])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def sorted_keys
|
21
|
+
hash.keys.sort
|
22
|
+
end
|
23
|
+
|
24
|
+
def change_value(value)
|
25
|
+
return value unless value.is_a?(Hash) && recursive
|
26
|
+
value.sort_keys(recursive: true)
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :hash, :recursive
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
module Squasher
|
5
|
+
class Builder
|
6
|
+
attr_reader :key, :value
|
7
|
+
|
8
|
+
def initialize(key, value)
|
9
|
+
@value = value
|
10
|
+
@key = key
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
if value.is_a? Hash
|
15
|
+
value.squash.inject({}) do |hash, (k, v)|
|
16
|
+
new_key = [key, k].join('.')
|
17
|
+
hash.merge!(new_key => v)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
{ key => value }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.squash(origin)
|
26
|
+
origin.inject({}) do |hash, (key, value)|
|
27
|
+
hash.merge!(Builder.new(key, value).to_h)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
class ToHashMapper
|
5
|
+
def initialize(hash)
|
6
|
+
@hash = hash
|
7
|
+
end
|
8
|
+
|
9
|
+
def map
|
10
|
+
{}.tap do |new_hash|
|
11
|
+
hash.each do |k, v|
|
12
|
+
new_hash[k] = yield(k, v)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :hash
|
20
|
+
end
|
21
|
+
end
|