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.
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