deep_hash_transformer 2.1.0 → 2.2.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/lib/deep_hash_transformer/blank.rb +28 -0
- data/lib/deep_hash_transformer/collection_operation.rb +29 -0
- data/lib/deep_hash_transformer/{operation.rb → element_operation.rb} +1 -1
- data/lib/deep_hash_transformer/version.rb +1 -1
- data/lib/deep_hash_transformer.rb +32 -14
- data/spec/deep_hash_transformer/blank_spec.rb +26 -0
- data/spec/deep_hash_transformer/collection_operation_spec.rb +31 -0
- data/spec/deep_hash_transformer/{operation_spec.rb → element_operation_spec.rb} +2 -2
- data/spec/deep_hash_transformer_spec.rb +51 -2
- data/spec/spec_helper.rb +3 -1
- metadata +10 -118
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e757436383ce13e17ee8e2b68e48d419e2f9f3c2e57fcfa76503e723ecde5e0
|
4
|
+
data.tar.gz: 5508770653b53402c6be53f9a3b1c0ea42a899b42760c2844565c3befa4bc54c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02c165dda7044c595af36f476fe4234dfca724654e4384d971c183f14dadab6a1f9782f58dd5736f2b82962b7811a41fd51350b2a755ef62cfe684b259dd705d
|
7
|
+
data.tar.gz: 41ed65816b738a755fdfbf9e97c0c6ef408fa022a16230d504b0acb4f744ef10279f98954b3eb1c22eaf7af552a9ef5a40c61b75e68cfe4f723f444ebd7e9987
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class DeepHashTransformer
|
4
|
+
class Blank
|
5
|
+
BLANK_STRING = /\A[[:space:]]*\z/.freeze
|
6
|
+
|
7
|
+
def self.call(value)
|
8
|
+
new(value).blank?
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(value)
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def blank?
|
16
|
+
return true unless value
|
17
|
+
return value.blank? if value.respond_to?(:blank?)
|
18
|
+
return BLANK_STRING.match?(value) if value.is_a?(String)
|
19
|
+
return value.empty? if value.respond_to?(:empty?)
|
20
|
+
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :value
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './blank'
|
4
|
+
|
5
|
+
class DeepHashTransformer
|
6
|
+
module CollectionOperation
|
7
|
+
class << self
|
8
|
+
def compact(val)
|
9
|
+
case val
|
10
|
+
when Array, Hash
|
11
|
+
val.compact
|
12
|
+
else
|
13
|
+
val
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def compact_blank(val)
|
18
|
+
case val
|
19
|
+
when Array
|
20
|
+
val.reject { |elem| Blank.call(elem) }
|
21
|
+
when Hash
|
22
|
+
val.reject { |_, v| Blank.call(v) }
|
23
|
+
else
|
24
|
+
val
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'deep_hash_transformer/
|
3
|
+
require 'deep_hash_transformer/collection_operation'
|
4
|
+
require 'deep_hash_transformer/element_operation'
|
4
5
|
require 'deep_hash_transformer/version'
|
5
6
|
|
6
7
|
class DeepHashTransformer
|
7
|
-
|
8
|
+
ELEMENT_OPS = %i[
|
8
9
|
camel_case
|
9
10
|
dasherize
|
10
11
|
identity
|
@@ -15,15 +16,22 @@ class DeepHashTransformer
|
|
15
16
|
underscore
|
16
17
|
].freeze
|
17
18
|
|
19
|
+
COLLECTION_OPS = %i[
|
20
|
+
compact
|
21
|
+
compact_blank
|
22
|
+
].freeze
|
23
|
+
|
24
|
+
OPS = ELEMENT_OPS + COLLECTION_OPS
|
25
|
+
|
18
26
|
def initialize(hash)
|
19
27
|
@hash = hash
|
20
28
|
end
|
21
29
|
|
22
30
|
def tr(*ops)
|
23
|
-
|
24
|
-
if
|
31
|
+
unknown_transformations = ops.map(&:to_s) - OPS.map(&:to_s)
|
32
|
+
if unknown_transformations.any?
|
25
33
|
raise(
|
26
|
-
ArgumentError, "unknown transformation(s): #{
|
34
|
+
ArgumentError, "unknown transformation(s): #{unknown_transformations.join(',')}"
|
27
35
|
)
|
28
36
|
end
|
29
37
|
|
@@ -38,20 +46,30 @@ class DeepHashTransformer
|
|
38
46
|
|
39
47
|
attr_reader :hash
|
40
48
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
value.map { |e| transform_value(e, ops) }
|
45
|
-
when Hash
|
46
|
-
value.map { |k, v| [transform_key(k, ops), transform_value(v, ops)] }.to_h
|
47
|
-
else
|
48
|
-
value
|
49
|
+
def transform_collection(collection, ops)
|
50
|
+
ops.inject(collection) do |c, op|
|
51
|
+
COLLECTION_OPS.include?(op) ? CollectionOperation.public_send(op, c) : c
|
49
52
|
end
|
50
53
|
end
|
51
54
|
|
55
|
+
def transform_value(value, ops)
|
56
|
+
collection = case value
|
57
|
+
when Array
|
58
|
+
value.map { |e| transform_value(e, ops) }
|
59
|
+
when Hash
|
60
|
+
value.map { |k, v| [transform_key(k, ops), transform_value(v, ops)] }.to_h
|
61
|
+
else
|
62
|
+
value
|
63
|
+
end
|
64
|
+
|
65
|
+
transform_collection(collection, ops)
|
66
|
+
end
|
67
|
+
|
52
68
|
def transform_key(key, ops)
|
53
69
|
return key unless [String, Symbol].include?(key.class)
|
54
70
|
|
55
|
-
ops.inject(key)
|
71
|
+
ops.inject(key) do |k, op|
|
72
|
+
ELEMENT_OPS.include?(op) ? ElementOperation.public_send(op, k) : k
|
73
|
+
end
|
56
74
|
end
|
57
75
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe DeepHashTransformer::Blank do
|
4
|
+
describe '.call' do
|
5
|
+
subject { described_class.call(value) }
|
6
|
+
|
7
|
+
presents = [true, 1, 0, 'any', [nil], { A: nil }]
|
8
|
+
blanks = [nil, false, '', ' ', [], {}]
|
9
|
+
|
10
|
+
presents.each do |value|
|
11
|
+
context "with #{value.inspect}" do
|
12
|
+
let(:value) { value }
|
13
|
+
|
14
|
+
it { is_expected.to be false }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
blanks.each do |value|
|
19
|
+
context "with #{value.inspect}" do
|
20
|
+
let(:value) { value }
|
21
|
+
|
22
|
+
it { is_expected.to be true }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe DeepHashTransformer::CollectionOperation do
|
4
|
+
examples = [
|
5
|
+
{ a: 'b' }, { a: nil }, { a: ' ' }, [:foo], ['', nil]
|
6
|
+
]
|
7
|
+
|
8
|
+
subject do
|
9
|
+
examples.map { |value| described_class.public_send(method, value) }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.compact' do
|
13
|
+
let(:method) { :compact }
|
14
|
+
|
15
|
+
expected_output = [
|
16
|
+
{ a: 'b' }, {}, { a: ' ' }, [:foo], ['']
|
17
|
+
]
|
18
|
+
|
19
|
+
it { is_expected.to eq(expected_output) }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '.compact_blank' do
|
23
|
+
let(:method) { :compact_blank }
|
24
|
+
|
25
|
+
expected_output = [
|
26
|
+
{ a: 'b' }, {}, {}, [:foo], []
|
27
|
+
]
|
28
|
+
|
29
|
+
it { is_expected.to eq(expected_output) }
|
30
|
+
end
|
31
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
RSpec.describe DeepHashTransformer::
|
3
|
+
RSpec.describe DeepHashTransformer::ElementOperation do
|
4
4
|
examples = [
|
5
5
|
:symbol, 'string', 'camelCase', 'dashed-key', 'PascalCase', 'under_scored'
|
6
6
|
]
|
@@ -22,7 +22,7 @@ RSpec.describe DeepHashTransformer::Operation do
|
|
22
22
|
}
|
23
23
|
# rubocop:enable Layout/HashAlignment, Style/SymbolArray, Style/WordArray
|
24
24
|
|
25
|
-
DeepHashTransformer::
|
25
|
+
DeepHashTransformer::ELEMENT_OPS.each do |method|
|
26
26
|
describe "##{method}" do
|
27
27
|
let(:method) { method }
|
28
28
|
|
@@ -6,11 +6,11 @@ RSpec.describe DeepHashTransformer do
|
|
6
6
|
let(:example) { { foo: 'bar' } }
|
7
7
|
|
8
8
|
describe 'autogenerated methods' do
|
9
|
-
DeepHashTransformer::
|
9
|
+
DeepHashTransformer::ELEMENT_OPS.each do |method|
|
10
10
|
describe ".#{method}" do
|
11
11
|
it "delegates to `Operation.#{method}`" do
|
12
12
|
expect(
|
13
|
-
DeepHashTransformer::
|
13
|
+
DeepHashTransformer::ElementOperation
|
14
14
|
).to receive(method).with(:foo).once # rubocop:disable RSpec/MessageSpies
|
15
15
|
|
16
16
|
operation.public_send(method)
|
@@ -71,6 +71,55 @@ RSpec.describe DeepHashTransformer do
|
|
71
71
|
)
|
72
72
|
end
|
73
73
|
end
|
74
|
+
|
75
|
+
context 'with nil values' do
|
76
|
+
subject { super().tr(:compact, :stringify) }
|
77
|
+
|
78
|
+
let(:example) do
|
79
|
+
{ a: { b: ['', nil, :value], c: '', d: nil, e: true, f: false, g: 123, h: [''] } }
|
80
|
+
end
|
81
|
+
|
82
|
+
it do # rubocop:disable RSpec/ExampleLength
|
83
|
+
is_expected.to eq( # rubocop:disable RSpec/ImplicitSubject
|
84
|
+
'a' => {
|
85
|
+
'b' => ['', :value],
|
86
|
+
'c' => '',
|
87
|
+
'e' => true,
|
88
|
+
'f' => false,
|
89
|
+
'g' => 123,
|
90
|
+
'h' => ['']
|
91
|
+
}
|
92
|
+
)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'with blank values' do
|
97
|
+
subject { super().tr(:compact_blank, :stringify) }
|
98
|
+
|
99
|
+
let(:example) do
|
100
|
+
{ a: { b: ['', nil, :value], c: '', d: nil, e: true, f: false, g: 123, h: [''] } }
|
101
|
+
end
|
102
|
+
|
103
|
+
it do # rubocop:disable RSpec/ExampleLength
|
104
|
+
is_expected.to eq( # rubocop:disable RSpec/ImplicitSubject
|
105
|
+
'a' => {
|
106
|
+
'b' => [:value],
|
107
|
+
'e' => true,
|
108
|
+
'g' => 123
|
109
|
+
}
|
110
|
+
)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'with deeply nested blank values' do
|
115
|
+
subject { super().tr(:compact_blank) }
|
116
|
+
|
117
|
+
let(:example) do
|
118
|
+
{ a: { b: [nil, { c: nil }] } }
|
119
|
+
end
|
120
|
+
|
121
|
+
it { is_expected.to eq({}) }
|
122
|
+
end
|
74
123
|
end
|
75
124
|
|
76
125
|
it 'has a version number' do
|
data/spec/spec_helper.rb
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'deep_hash_transformer'
|
5
|
-
require 'deep_hash_transformer/
|
5
|
+
require 'deep_hash_transformer/blank'
|
6
|
+
require 'deep_hash_transformer/collection_operation'
|
7
|
+
require 'deep_hash_transformer/element_operation'
|
6
8
|
require 'simplecov'
|
7
9
|
|
8
10
|
SimpleCov.start do
|
metadata
CHANGED
@@ -1,127 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deep_hash_transformer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Spickermann
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: rake
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :development
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rspec
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rubocop
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: rubocop-performance
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rubocop-rake
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: rubocop-rspec
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: simplecov
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: simplecov-lcov
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - ">="
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - ">="
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '0'
|
11
|
+
date: 2023-05-16 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
125
13
|
description: " DeepHashTransformer helps to transform keys in deeply nested hash
|
126
14
|
structures\n"
|
127
15
|
email:
|
@@ -132,9 +20,13 @@ extra_rdoc_files: []
|
|
132
20
|
files:
|
133
21
|
- MIT-LICENSE
|
134
22
|
- lib/deep_hash_transformer.rb
|
135
|
-
- lib/deep_hash_transformer/
|
23
|
+
- lib/deep_hash_transformer/blank.rb
|
24
|
+
- lib/deep_hash_transformer/collection_operation.rb
|
25
|
+
- lib/deep_hash_transformer/element_operation.rb
|
136
26
|
- lib/deep_hash_transformer/version.rb
|
137
|
-
- spec/deep_hash_transformer/
|
27
|
+
- spec/deep_hash_transformer/blank_spec.rb
|
28
|
+
- spec/deep_hash_transformer/collection_operation_spec.rb
|
29
|
+
- spec/deep_hash_transformer/element_operation_spec.rb
|
138
30
|
- spec/deep_hash_transformer_spec.rb
|
139
31
|
- spec/spec_helper.rb
|
140
32
|
homepage: https://github.com/spickermann/deep_hash_transformer
|
@@ -157,7 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
49
|
- !ruby/object:Gem::Version
|
158
50
|
version: '0'
|
159
51
|
requirements: []
|
160
|
-
rubygems_version: 3.
|
52
|
+
rubygems_version: 3.4.10
|
161
53
|
signing_key:
|
162
54
|
specification_version: 4
|
163
55
|
summary: Transforms deeply nested hash structure
|