darthjee-core_ext 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +5 -0
  5. data/Gemfile.lock +62 -0
  6. data/LICENSE +22 -0
  7. data/README.md +188 -0
  8. data/Rakefile +7 -0
  9. data/core_ext.gemspec +27 -0
  10. data/lib/array.rb +23 -0
  11. data/lib/array/hash_builder.rb +20 -0
  12. data/lib/darthjee.rb +4 -0
  13. data/lib/darthjee/core_ext.rb +12 -0
  14. data/lib/darthjee/core_ext/version.rb +5 -0
  15. data/lib/enumerable.rb +45 -0
  16. data/lib/hash.rb +195 -0
  17. data/lib/hash/deep_hash_constructor.rb +83 -0
  18. data/lib/hash/key_changer.rb +76 -0
  19. data/lib/hash/value_changer.rb +61 -0
  20. data/lib/numeric.rb +6 -0
  21. data/lib/symbol.rb +9 -0
  22. data/spec/lib/array_spec.rb +229 -0
  23. data/spec/lib/enumerable_spec.rb +31 -0
  24. data/spec/lib/hash/deep_hash_constructor_spec.rb +167 -0
  25. data/spec/lib/hash/key_changer_spec.rb +55 -0
  26. data/spec/lib/hash_spec.rb +347 -0
  27. data/spec/lib/numeric_spec.rb +61 -0
  28. data/spec/lib/symbol_spec.rb +35 -0
  29. data/spec/spec_helper.rb +32 -0
  30. data/spec/support/models/hash/value_changer/dummy.rb +15 -0
  31. data/spec/support/models/hash/value_changer/dummy_iteractor.rb +12 -0
  32. data/spec/support/shared_examples/array_random.rb +16 -0
  33. data/spec/support/shared_examples/chain_fetch.rb +88 -0
  34. data/spec/support/shared_examples/chain_hash_keys_changer.rb +88 -0
  35. data/spec/support/shared_examples/clean.rb +143 -0
  36. data/spec/support/shared_examples/expected.rb +6 -0
  37. data/spec/support/shared_examples/hash_keys_changer.rb +85 -0
  38. data/spec/support/shared_examples/keys_appender.rb +43 -0
  39. data/spec/support/shared_examples/keys_camelizer.rb +285 -0
  40. data/spec/support/shared_examples/keys_underscorer.rb +82 -0
  41. data/spec/support/shared_examples/remap.rb +89 -0
  42. data/spec/support/shared_examples/value_changer.rb +92 -0
  43. 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
@@ -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,12 @@
1
+ class Hash::ValueChanger::DummyIteractor
2
+ def initialize(*array)
3
+ @array = array
4
+ end
5
+
6
+ delegate :each, :to_a, to: :array
7
+
8
+ private
9
+
10
+ attr_reader :array
11
+ end
12
+
@@ -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