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