darthjee-core_ext 1.2.6
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 +7 -0
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +62 -0
- data/LICENSE +22 -0
- data/README.md +188 -0
- data/Rakefile +7 -0
- data/core_ext.gemspec +27 -0
- data/lib/array.rb +23 -0
- data/lib/array/hash_builder.rb +20 -0
- data/lib/darthjee.rb +4 -0
- data/lib/darthjee/core_ext.rb +12 -0
- data/lib/darthjee/core_ext/version.rb +5 -0
- data/lib/enumerable.rb +45 -0
- data/lib/hash.rb +195 -0
- data/lib/hash/deep_hash_constructor.rb +83 -0
- data/lib/hash/key_changer.rb +76 -0
- data/lib/hash/value_changer.rb +61 -0
- data/lib/numeric.rb +6 -0
- data/lib/symbol.rb +9 -0
- data/spec/lib/array_spec.rb +229 -0
- data/spec/lib/enumerable_spec.rb +31 -0
- data/spec/lib/hash/deep_hash_constructor_spec.rb +167 -0
- data/spec/lib/hash/key_changer_spec.rb +55 -0
- data/spec/lib/hash_spec.rb +347 -0
- data/spec/lib/numeric_spec.rb +61 -0
- data/spec/lib/symbol_spec.rb +35 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/models/hash/value_changer/dummy.rb +15 -0
- data/spec/support/models/hash/value_changer/dummy_iteractor.rb +12 -0
- data/spec/support/shared_examples/array_random.rb +16 -0
- data/spec/support/shared_examples/chain_fetch.rb +88 -0
- data/spec/support/shared_examples/chain_hash_keys_changer.rb +88 -0
- data/spec/support/shared_examples/clean.rb +143 -0
- data/spec/support/shared_examples/expected.rb +6 -0
- data/spec/support/shared_examples/hash_keys_changer.rb +85 -0
- data/spec/support/shared_examples/keys_appender.rb +43 -0
- data/spec/support/shared_examples/keys_camelizer.rb +285 -0
- data/spec/support/shared_examples/keys_underscorer.rb +82 -0
- data/spec/support/shared_examples/remap.rb +89 -0
- data/spec/support/shared_examples/value_changer.rb +92 -0
- metadata +217 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Numeric do
|
4
|
+
describe '#percent_of' do
|
5
|
+
context 'when number is float' do
|
6
|
+
let(:number) { 120.0 }
|
7
|
+
|
8
|
+
it 'converts to percentage of number' do
|
9
|
+
expect(number.percent_of(240)).to eq(50)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'converts to percentage of number' do
|
13
|
+
expect(number.percent_of(60)).to eq(200)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'do not raise an error when divisor is 0' do
|
17
|
+
expect(100.0.percent_of(0)).to eq(Float::INFINITY)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'do not raise an error when divisor is 0.0' do
|
21
|
+
expect(100.0.percent_of(0.0)).to eq(Float::INFINITY)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when number is integer' do
|
26
|
+
it 'converts to percentage of number' do
|
27
|
+
expect(500.percent_of(50)).to eq(1000)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'converts to percentage of number' do
|
31
|
+
expect(0.percent_of(50)).to eq(0)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'converts to percentage of number' do
|
35
|
+
expect(10.percent_of(100)).to eq(10)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'do not raise an error when divisor is 0' do
|
39
|
+
expect(100.percent_of(0)).to eq(Float::INFINITY)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when a number is 0' do
|
44
|
+
context 'when divident is 0' do
|
45
|
+
it { expect(0.percent_of(100)).to eq(0) }
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when divisor is 0' do
|
49
|
+
it { expect(100.percent_of(0)).to eq(Float::INFINITY) }
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'both are 0' do
|
53
|
+
it { expect(0.percent_of(0)).to eq(Float::INFINITY) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when divisor is nil' do
|
58
|
+
it { expect(100.percent_of(nil)).to eq(Float::INFINITY) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Symbol do
|
4
|
+
describe '#camelize' do
|
5
|
+
it { expect(:sym.camelize).to be_kind_of(Symbol) }
|
6
|
+
|
7
|
+
context 'when called with upper option' do
|
8
|
+
it 'camelize the symbol' do
|
9
|
+
expect(:underscore_sym.camelize(:upper)).to eq(:UnderscoreSym)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'when called with lower option' do
|
14
|
+
it 'camelize the symbol without captalization' do
|
15
|
+
expect(:underscore_sym.camelize(:lower)).to eq(:underscoreSym)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when called without option' do
|
20
|
+
it 'camelize the symbol' do
|
21
|
+
expect(:underscore_sym.camelize).to eq(:UnderscoreSym)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#underscore' do
|
27
|
+
it { expect(:symBol.underscore).to be_kind_of(Symbol) }
|
28
|
+
|
29
|
+
context 'when called with upper option' do
|
30
|
+
it 'underscore the symbol' do
|
31
|
+
expect(:symBol.underscore).to eq(:sym_bol)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
SimpleCov.profiles.define 'gem' do
|
4
|
+
add_filter '/spec/'
|
5
|
+
end
|
6
|
+
|
7
|
+
SimpleCov.start 'gem'
|
8
|
+
require 'pry-nav'
|
9
|
+
require 'darthjee/core_ext'
|
10
|
+
|
11
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
12
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
13
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
14
|
+
# loaded once.
|
15
|
+
#
|
16
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
17
|
+
|
18
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
19
|
+
# in spec/support/ and its subdirectories.
|
20
|
+
Dir['./spec/support/**/*.rb'].each { |f| require f }
|
21
|
+
|
22
|
+
RSpec.configure do |config|
|
23
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
24
|
+
config.run_all_when_everything_filtered = true
|
25
|
+
config.filter_run :focus
|
26
|
+
|
27
|
+
# Run specs in random order to surface order dependencies. If you find an
|
28
|
+
# order dependency and want to debug it, you can fix the order by providing
|
29
|
+
# the seed, which is printed after each run.
|
30
|
+
# --seed 1234
|
31
|
+
config.order = 'random'
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Hash::ValueChanger::Dummy
|
2
|
+
attr_reader :value
|
3
|
+
|
4
|
+
delegate :+, to: :value
|
5
|
+
|
6
|
+
def initialize(value)
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def eql?(other)
|
11
|
+
return true if equals?(other)
|
12
|
+
return false unless other.is_a?(self.class)
|
13
|
+
a.value == value
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
shared_examples 'a method that returns a random element' do |method|
|
2
|
+
let(:array) { [ 7, 5, 3 ] }
|
3
|
+
|
4
|
+
(0..2).each do |index|
|
5
|
+
context "when random returns #{index}" do
|
6
|
+
let!(:expected) { array[index] }
|
7
|
+
before do
|
8
|
+
allow_any_instance_of(Array).to receive(:rand).with(array.size) { index }
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns the randomized index of the array' do
|
12
|
+
expect(array.public_send(method)).to eq(expected)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
shared_examples 'an object with chain_fetch method' do
|
2
|
+
describe :chain_fetch do
|
3
|
+
let(:value) { 10 }
|
4
|
+
let(:hash) do
|
5
|
+
{
|
6
|
+
b: 1, c: 2, d: 3, a: {
|
7
|
+
c: 3, d: 5, b: {
|
8
|
+
d: 6, a: 1, b: 2, c: {
|
9
|
+
d: value
|
10
|
+
}
|
11
|
+
}
|
12
|
+
}
|
13
|
+
}
|
14
|
+
end
|
15
|
+
let(:keys) { [:a, :b, :c, :d] }
|
16
|
+
let(:result) { hash.chain_fetch(*keys) }
|
17
|
+
|
18
|
+
context 'when fetching existing keys' do
|
19
|
+
it 'returns the value' do
|
20
|
+
expect(result).to eq(value)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when fetching non existing keys keys' do
|
25
|
+
let(:keys) { [:a, :x, :y] }
|
26
|
+
|
27
|
+
context 'when there is no default value' do
|
28
|
+
it 'raises fetch error' do
|
29
|
+
expect { result }.to raise_error(KeyError)
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when the hash has no keys' do
|
33
|
+
let(:hash) { {} }
|
34
|
+
let(:keys) { [:a] }
|
35
|
+
|
36
|
+
it 'raises fetch error' do
|
37
|
+
expect { result }.to raise_error(KeyError)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with a simple level hash' do
|
42
|
+
let(:hash) { { a: 1 } }
|
43
|
+
let(:keys) { [:c] }
|
44
|
+
|
45
|
+
it 'raises fetch error' do
|
46
|
+
expect { result }.to raise_error(KeyError)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'but a default value block is given' do
|
52
|
+
let(:default_value) { 100 }
|
53
|
+
let(:result) { hash.chain_fetch(*keys) { default_value } }
|
54
|
+
|
55
|
+
it 'returns the default_value' do
|
56
|
+
expect(result).to eq(default_value)
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'and the block logs the missing keys' do
|
60
|
+
it 'hnadles the missing keys' do
|
61
|
+
missing_keys = nil
|
62
|
+
hash.chain_fetch(*keys) do |_, keys|
|
63
|
+
missing_keys = keys
|
64
|
+
end
|
65
|
+
|
66
|
+
expect(missing_keys).to eq([:y])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'and the block uses the key for the return' do
|
71
|
+
let(:result) { hash.chain_fetch(*keys) { |k| "returned #{k}" } }
|
72
|
+
it 'hnadles the missing keys' do
|
73
|
+
expect(result).to eq('returned x')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when mixing key types' do
|
80
|
+
let(:hash) { { a: { 'b' => { 100 => { true => value } } } } }
|
81
|
+
let(:keys) { [:a, 'b', 100, true] }
|
82
|
+
|
83
|
+
it 'returns the value' do
|
84
|
+
expect(result).to eq(value)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
shared_examples 'a class with chain_change_key method' do
|
2
|
+
let(:hash) do
|
3
|
+
{ 'a' => 1, b: 2, c: { d: 3, e: 4 }, f: [{ g: 5 }, { h: 6 }] }
|
4
|
+
end
|
5
|
+
|
6
|
+
describe :chain_change_keys do
|
7
|
+
|
8
|
+
it_behaves_like 'a method that is able to chain change keys', :chain_change_keys
|
9
|
+
it 'does not affects the original hash' do
|
10
|
+
expect do
|
11
|
+
hash.chain_change_keys(:to_s, :upcase)
|
12
|
+
end.not_to change { hash }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe :ichain_change_keys! do
|
17
|
+
it_behaves_like 'a method that is able to chain change keys', :chain_change_keys!
|
18
|
+
|
19
|
+
it 'affects the original hash' do
|
20
|
+
expect do
|
21
|
+
hash.chain_change_keys!(:to_s, :upcase)
|
22
|
+
end.to change { hash }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
shared_examples 'a method that is able to chain change keys' do |method|
|
28
|
+
let(:result) { hash.public_send(method, *transformations, options) }
|
29
|
+
let(:options) { {} }
|
30
|
+
let(:transformations) { [ :to_s ] }
|
31
|
+
|
32
|
+
context 'with simple level hash' do
|
33
|
+
let(:hash) { { 'a' => 1, b: 2 } }
|
34
|
+
|
35
|
+
context 'with symbol transformation' do
|
36
|
+
let(:transformations) { [ :to_sym ] }
|
37
|
+
let(:expected) { { a: 1, b: 2 } }
|
38
|
+
it_behaves_like 'result is as expected'
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with string transformation' do
|
42
|
+
let(:expected) { { 'a' => 1, 'b' => 2 } }
|
43
|
+
it_behaves_like 'result is as expected'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with recursive hash' do
|
48
|
+
let(:hash) { { 'a' => 1, b: { c: 3, 'd' => 4 } } }
|
49
|
+
let(:expected) do
|
50
|
+
{ 'a' => 1, 'b' => { 'c' => 3, 'd' => 4 } }
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when no options are given' do
|
54
|
+
it_behaves_like 'result is as expected'
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when options are given' do
|
58
|
+
let(:options) { { recursive: recursive } }
|
59
|
+
|
60
|
+
context 'with recursion' do
|
61
|
+
let(:recursive) { true }
|
62
|
+
it_behaves_like 'result is as expected'
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'without recursion' do
|
66
|
+
let(:recursive) { false }
|
67
|
+
let(:expected) { { 'a' => 1, 'b' => { c: 3, 'd' => 4 } } }
|
68
|
+
it_behaves_like 'result is as expected'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with many many levels' do
|
74
|
+
let(:hash) { { a: 1, b: { c: 2, d: { e: 3, f: 4 } } } }
|
75
|
+
let(:expected) do
|
76
|
+
{ 'a' => 1, 'b' => { 'c' => 2, 'd' => { 'e' => 3, 'f' => 4 } } }
|
77
|
+
end
|
78
|
+
it_behaves_like 'result is as expected'
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'calling with chained transformations' do
|
82
|
+
let(:transformations) { [ :to_s, :upcase, :to_sym ] }
|
83
|
+
|
84
|
+
let(:hexpected) do
|
85
|
+
{ A: 1, B: 2, C: { D: 3, E: 4 }, F: [{ G: 5 }, { H: 6 }] }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
shared_examples 'a hash clean method' do |method|
|
2
|
+
context 'when hash has one level' do
|
3
|
+
let(:subject) do
|
4
|
+
{ a: 1, b: nil, c: '', d: {} }
|
5
|
+
end
|
6
|
+
|
7
|
+
let(:expected) do
|
8
|
+
{ a: 1 }
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'cleans the hash from empty and nil values' do
|
12
|
+
expect(subject.send(method)).to eq(expected)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when hash has two levels' do
|
17
|
+
let(:subject) do
|
18
|
+
{ a: 1, c: '', d: { e: 1 }, f: { g: { b: nil } } }
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:expected) do
|
22
|
+
{ a: 1, d: { e: 1 } }
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'cleans the hash from empty and nil values' do
|
26
|
+
expect(subject.send(method)).to eq(expected)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when hash has many levels' do
|
31
|
+
let(:subject) do
|
32
|
+
{ a: 1, d: { e: { k: { l: { m: { n: 1 } } } } }, f: { g: { h: { i: { j: { c: '' } } } } } }
|
33
|
+
end
|
34
|
+
|
35
|
+
let(:expected) do
|
36
|
+
{ a: 1, d: { e: { k: { l: { m: { n: 1 } } } } } }
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'cleans the hash from empty and nil values' do
|
40
|
+
expect(subject.send(method)).to eq(expected)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when hash has one nil value and one valid value' do
|
45
|
+
let(:subject) do
|
46
|
+
{ a: { b: 1, c: nil } }
|
47
|
+
end
|
48
|
+
|
49
|
+
let(:expected) do
|
50
|
+
{ a: { b: 1 } }
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'cleans the hash from empty and nil values' do
|
54
|
+
expect(subject.send(method)).to eq(expected)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when hash has arrays' do
|
59
|
+
let(:subject) do
|
60
|
+
{ a: [] }
|
61
|
+
end
|
62
|
+
|
63
|
+
let(:expected) do
|
64
|
+
{}
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'cleans the hash from empty and nil values' do
|
68
|
+
expect(subject.send(method)).to eq(expected)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when hash has arrays with hashes' do
|
73
|
+
let(:subject) do
|
74
|
+
{ a: [{ c: nil }] }
|
75
|
+
end
|
76
|
+
|
77
|
+
let(:expected) do
|
78
|
+
{}
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'cleans the hash from empty and nil values' do
|
82
|
+
expect(subject.send(method)).to eq(expected)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when hash has arrays with hashes with valid values' do
|
87
|
+
let(:subject) do
|
88
|
+
{ a: [{ c: 1 }] }
|
89
|
+
end
|
90
|
+
|
91
|
+
let(:expected) do
|
92
|
+
{ a: [{ c: 1 }] }
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'cleans the hash from empty and nil values' do
|
96
|
+
expect(subject.send(method)).to eq(expected)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when hash has arrays with hashes with valid and invalid values' do
|
101
|
+
let(:subject) do
|
102
|
+
{ a: [{ c: nil }, { d: 1 }] }
|
103
|
+
end
|
104
|
+
|
105
|
+
let(:expected) do
|
106
|
+
{ a: [{ d: 1 }] }
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'cleans the hash from empty and nil values' do
|
110
|
+
expect(subject.send(method)).to eq(expected)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
shared_examples 'an array clean method' do |method|
|
116
|
+
context 'when array has one level' do
|
117
|
+
let(:subject) do
|
118
|
+
[1, nil, '', {}, []]
|
119
|
+
end
|
120
|
+
|
121
|
+
let(:expected) do
|
122
|
+
[1]
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'cleans the hash from empty and nil values' do
|
126
|
+
expect(subject.send(method)).to eq(expected)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'when array has many levels' do
|
131
|
+
let(:subject) do
|
132
|
+
[1, nil, '', {}, [[[{ a: [[[[[[[]]]]]]] }]]], [[[[[[[2]]]]]]], [{ a: [2] }]]
|
133
|
+
end
|
134
|
+
|
135
|
+
let(:expected) do
|
136
|
+
[1, [[[[[[[2]]]]]]], [{ a: [2] }]]
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'cleans the hash from empty and nil values' do
|
140
|
+
expect(subject.send(method)).to eq(expected)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|