bidu-core_ext 1.0.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.
@@ -0,0 +1,83 @@
1
+ class Hash::DeepHashConstructor
2
+ attr_accessor :separator
3
+
4
+ def initialize(separator)
5
+ @separator = separator
6
+ end
7
+
8
+ def deep_hash(object)
9
+ if object.is_a? Array
10
+ array_deep_hash(object)
11
+ elsif object.is_a? Hash
12
+ hash_deep_hash(object)
13
+ else
14
+ object
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def array_deep_hash(array)
21
+ array.map { |v| v.is_a?(Hash) ? deep_hash(v) : v }
22
+ end
23
+
24
+ def hash_deep_hash(hash)
25
+ {}.tap do |new_hash|
26
+ hash.each do |k, v|
27
+ base_key, child_key = split_key(k, separator)
28
+ set_deep_hash_positioned_value(new_hash, base_key, v, child_key)
29
+ end
30
+
31
+ new_hash.each do |k, v|
32
+ new_hash[k] = deep_hash(v)
33
+ end
34
+ end
35
+ end
36
+
37
+ def split_key(key, separator)
38
+ separator_rxp = (separator == '.') ? "\\#{separator}" : separator
39
+ skipper = "[^#{separator}]"
40
+ regexp = Regexp.new("^(#{skipper}*)#{separator_rxp}(.*)")
41
+ match = key.match(regexp)
42
+
43
+ match ? match[1..2] : key
44
+ end
45
+
46
+ def set_deep_hash_array_value(hash, base_key, index, value, key = nil)
47
+ key_without_index = base_key.gsub("[#{index}]", '')
48
+ hash[key_without_index] ||= []
49
+
50
+ if key.nil?
51
+ hash[key_without_index][index] = value
52
+ else
53
+ hash[key_without_index][index] ||= {}
54
+ hash[key_without_index][index][key] = value
55
+ end
56
+ end
57
+
58
+ def set_deep_hash_positioned_value(new_hash, base_key, v, child_key)
59
+ index = array_index(base_key)
60
+
61
+ if index
62
+ set_deep_hash_array_value(new_hash, base_key, index, v, child_key)
63
+ else
64
+ set_deep_hash_value(new_hash, base_key, v, child_key)
65
+ end
66
+ end
67
+
68
+ def array_index(key)
69
+ match = key.match(/\[([^)]+)\]/)
70
+ if match
71
+ match[1].to_i
72
+ end
73
+ end
74
+
75
+ def set_deep_hash_value(hash, base_key, value, key = nil)
76
+ if key.nil?
77
+ hash[base_key] = value
78
+ else
79
+ hash[base_key] ||= {}
80
+ hash[base_key][key] = value
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,68 @@
1
+ class Hash::KeyChanger
2
+ attr_reader :hash, :block
3
+
4
+ def initialize(hash)
5
+ @hash = hash
6
+ end
7
+
8
+ def change_keys(settings = {}, &block)
9
+ merge_options({
10
+ recursive: true
11
+ }, settings)
12
+
13
+ if options[:recursive]
14
+ hash.deep_transform_keys!(&block)
15
+ else
16
+ hash.transform_keys!(&block)
17
+ end
18
+ end
19
+
20
+ def camelize_keys(settings = {})
21
+ merge_options({
22
+ uppercase_first_letter: true
23
+ }, settings)
24
+
25
+ type = options[:uppercase_first_letter] ? :upper : :lower
26
+
27
+ change_keys do |k|
28
+ k.camelize(type)
29
+ end
30
+ end
31
+
32
+ def change_text(options = {}, &block)
33
+ merge_options({
34
+ type: :keep
35
+ }, options)
36
+
37
+ change_keys do |key|
38
+ cast_new_key block.call(key), key.class
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def merge_options(default, custom)
45
+ @options = {}.merge!(default).merge!(custom).merge!(options)
46
+ end
47
+
48
+ def options
49
+ @options ||= {}
50
+ end
51
+
52
+ def cast_new_key(key, old_clazz)
53
+ case class_cast(old_clazz)
54
+ when :symbol then
55
+ key.to_sym
56
+ when :string then
57
+ key.to_s
58
+ end
59
+ end
60
+
61
+ def keep_class?
62
+ options[:type] == :keep
63
+ end
64
+
65
+ def class_cast(old_clazz)
66
+ keep_class? && old_clazz.to_s.downcase.to_sym || options[:type]
67
+ end
68
+ end
@@ -0,0 +1,52 @@
1
+ class Hash::ValueChanger
2
+ attr_accessor :options, :block
3
+
4
+ def initialize(options, &block)
5
+ @options = {
6
+ recursive: true,
7
+ skip_inner: true
8
+ }.merge(options)
9
+
10
+ @block = block
11
+ end
12
+
13
+ def change(object)
14
+ if object.is_a? Hash
15
+ change_hash(object)
16
+ elsif object.is_a? Array
17
+ change_array(object)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def change_hash(original_hash)
24
+ original_hash.tap do |hash|
25
+ original_hash.each do |key, value|
26
+ value = new_value(value)
27
+ hash[key] = value
28
+ end
29
+ end
30
+ end
31
+
32
+ def change_array(array)
33
+ array.each.with_index do |value, index|
34
+ value = value.change_values(options, &block) if value.is_a? Hash
35
+ value = change_array(value) if value.is_a? Array
36
+ array[index] = value
37
+ end
38
+ end
39
+
40
+ def change_value?(value)
41
+ !(value.is_a?(Hash) || value.is_a?(Array)) || !options[:skip_inner]
42
+ end
43
+
44
+ def new_value(value)
45
+ value = block.call(value) if change_value?(value)
46
+ apply_recursion?(value) ? change(value) : value
47
+ end
48
+
49
+ def apply_recursion?(value)
50
+ (value.is_a?(Hash) || value.is_a?(Array)) && options[:recursive]
51
+ end
52
+ end
data/lib/numeric.rb ADDED
@@ -0,0 +1,6 @@
1
+ class Numeric
2
+ def percent_of(n)
3
+ return Float::INFINITY if n == 0
4
+ (to_f / n.to_f) * 100.0
5
+ end
6
+ end
data/lib/symbol.rb ADDED
@@ -0,0 +1,5 @@
1
+ class Symbol
2
+ def camelize(type = :upper)
3
+ to_s.camelize(type).to_sym
4
+ end
5
+ end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ describe Array do
4
+ describe '#chain_map' do
5
+ let(:array) { [ :a, :long_name, :sym ] }
6
+ let(:mapped) { array.chain_map(:to_s, :size, :to_s) }
7
+
8
+ it 'calls each argument as method of the mapped result' do
9
+ expect(mapped).to eq([ '1', '9', '3' ])
10
+ end
11
+
12
+ context 'when an extra block is given' do
13
+ let(:mapped) do
14
+ array.chain_map(:to_s, :size) do |v|
15
+ "final: #{v}"
16
+ end
17
+ end
18
+
19
+ it 'calls each argument as method of the mapped result' do
20
+ expect(mapped).to eq([ 'final: 1', 'final: 9', 'final: 3' ])
21
+ end
22
+ end
23
+ end
24
+
25
+ describe '#as_hash' do
26
+ let(:array) { [1, 2, 3] }
27
+ let(:keys) { %w(a b c) }
28
+ let(:expected) { { 'a' => 1, 'b' => 2, 'c' => 3 } }
29
+
30
+ it 'creates a hash using the array as value and the argument as keys' do
31
+ expect(array.as_hash(keys)).to eq(expected)
32
+ end
33
+
34
+ context 'when there are more keys than values' do
35
+ let(:keys) { %w(a b c d e f) }
36
+ let(:expected) { { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => nil, 'e' => nil, 'f' => nil } }
37
+
38
+ it 'creates a hash with nil values for the extra keys' do
39
+ expect(array.as_hash(keys)).to eq(expected)
40
+ end
41
+
42
+ it { expect { array.as_hash(keys) }.not_to change { keys } }
43
+ it { expect { array.as_hash(keys) }.not_to change { array } }
44
+ end
45
+
46
+ context 'when there are more values than keys' do
47
+ let(:array) { [1, 2, 3, 4, 5, 6, 7] }
48
+
49
+ it { expect { array.as_hash(keys) }.to raise_error(IndexError) }
50
+
51
+ it { expect { array.as_hash(keys) rescue nil }.not_to change { keys } }
52
+ it { expect { array.as_hash(keys) rescue nil }.not_to change { array } }
53
+ end
54
+ end
55
+
56
+ describe '#map_and_find' do
57
+ let(:array) { [1, 2, 3, 4] }
58
+ let(:value) { array.map_and_find(&block) }
59
+
60
+ context 'when block returns nil' do
61
+ let(:block) { proc {} }
62
+ it { expect(value).to be_nil }
63
+ end
64
+
65
+ context 'when block returns false' do
66
+ let(:block) { proc { false } }
67
+ it { expect(value).to be_nil }
68
+ end
69
+
70
+ context 'when block returns a true evaluated value' do
71
+ let(:block) { proc(&:to_s) }
72
+
73
+ it { expect(value).to eq('1') }
74
+
75
+ context 'but not for the first value' do
76
+ let(:transformer) { double(:transformer) }
77
+ let(:block) { proc { |v| transformer.transform(v) } }
78
+
79
+ before do
80
+ allow(transformer).to receive(:transform) do |v|
81
+ v.to_s if v > 1
82
+ end
83
+ value
84
+ end
85
+
86
+ it { expect(value).to eq('2') }
87
+ it 'calls the mapping only until it returns a valid value' do
88
+ expect(transformer).to have_received(:transform).exactly(2)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,31 @@
1
+ describe Enumerable do
2
+ describe '#clean!' do
3
+ it_behaves_like 'an array clean method', :clean!
4
+ it_behaves_like 'a hash clean method', :clean!
5
+
6
+ it 'changes the original hash' do
7
+ hash = { a: nil}
8
+ expect { hash.clean! }.to change { hash }
9
+ end
10
+
11
+ it 'changes original array' do
12
+ array = [{ a: nil}]
13
+ expect { array.clean! }.to change { array }
14
+ end
15
+ end
16
+
17
+ describe '#clean' do
18
+ it_behaves_like 'an array clean method', :clean
19
+ it_behaves_like 'a hash clean method', :clean
20
+
21
+ it 'does not change the original hash' do
22
+ hash = { a: nil}
23
+ expect { hash.clean }.not_to change { hash }
24
+ end
25
+
26
+ it 'does not change the original array' do
27
+ array = [{ a: nil}]
28
+ expect { array.clean }.not_to change { array }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,167 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hash::DeepHashConstructor do
4
+ let(:subject) { described_class.new('.') }
5
+ let(:deep_hash) { subject.deep_hash(hash) }
6
+
7
+ describe '.deep_hash' do
8
+ let(:hash) do
9
+ {
10
+ 'person.name' => 'Some name',
11
+ 'person.age' => 22,
12
+ 'status' => :success,
13
+ 'vehicle.fuel' => 'GASOLINE',
14
+ 'vehicle.doors' => 4
15
+ }
16
+ end
17
+
18
+ let(:expected) do
19
+ {
20
+ 'person' => { 'name' => 'Some name', 'age' => 22 },
21
+ 'vehicle' => { 'fuel' => 'GASOLINE', 'doors' => 4 },
22
+ 'status' => :success
23
+ }
24
+ end
25
+
26
+ it 'build a deep hash' do
27
+ expect(deep_hash).to eq(expected)
28
+ end
29
+
30
+ context 'with indexed keys' do
31
+ let(:hash) do
32
+ {
33
+ 'person[0].name' => 'First person',
34
+ 'person[0].age' => 22,
35
+ 'person[1].name' => 'Second person',
36
+ 'person[1].age' => 27,
37
+ 'device[0]' => 'GEAR_LOCK',
38
+ 'device[1]' => 'GPS',
39
+ 'zipCode' => '122345-123'
40
+ }
41
+ end
42
+
43
+ let(:expected) do
44
+ {
45
+ 'person' => [
46
+ { 'name' => 'First person', 'age' => 22 },
47
+ { 'name' => 'Second person', 'age' => 27 }
48
+ ],
49
+ 'device' => %w(GEAR_LOCK GPS),
50
+ 'zipCode' => '122345-123'
51
+ }
52
+ end
53
+
54
+ it 'build a deep hash with arrays' do
55
+ expect(deep_hash).to eq(expected)
56
+ end
57
+ end
58
+
59
+ context 'with a n level hash' do
60
+ let(:hash) do
61
+ {
62
+ 'quote_request.personal.person.name' => 'Some name',
63
+ 'quote_request.personal.person.age' => 22,
64
+ 'quote_request.insurance.vehicle.fuel' => 'GASOLINE',
65
+ 'quote_request.insurance.vehicle.doors' => 4,
66
+ 'request.status' => :success,
67
+ 'trials' => 3
68
+ }
69
+ end
70
+
71
+ let(:expected) do
72
+ {
73
+ 'quote_request' => {
74
+ 'personal' => {
75
+ 'person' => { 'name' => 'Some name', 'age' => 22 }
76
+ },
77
+ 'insurance' => {
78
+ 'vehicle' => { 'fuel' => 'GASOLINE', 'doors' => 4 }
79
+ }
80
+ },
81
+ 'request' => { 'status' => :success },
82
+ 'trials' => 3
83
+ }
84
+ end
85
+
86
+ it 'build a deep hash with arrays' do
87
+ expect(deep_hash).to eq(expected)
88
+ end
89
+ end
90
+
91
+ context 'with a n level hash and arrays' do
92
+ let(:hash) do
93
+ {
94
+ 'quote_request.personal.person[0].name' => 'Some name 1',
95
+ 'quote_request.personal.person[0].age' => 22,
96
+ 'quote_request.personal.person[1].name' => 'Some name 2',
97
+ 'quote_request.personal.person[1].age' => 23,
98
+ 'request[0].status.clazz' => String,
99
+ 'request[1].status.clazz' => Fixnum,
100
+ 'request[2].status.clazz' => Date,
101
+ 'trials' => 3
102
+ }
103
+ end
104
+
105
+ let(:expected) do
106
+ {
107
+ 'quote_request' => {
108
+ 'personal' => {
109
+ 'person' => [
110
+ { 'name' => 'Some name 1', 'age' => 22 },
111
+ { 'name' => 'Some name 2', 'age' => 23 }
112
+ ]
113
+ }
114
+ },
115
+ 'request' => [
116
+ { 'status' => { 'clazz' => String } },
117
+ { 'status' => { 'clazz' => Fixnum } },
118
+ { 'status' => { 'clazz' => Date } }
119
+ ],
120
+ 'trials' => 3
121
+ }
122
+ end
123
+
124
+ it 'build a deep hash with arrays' do
125
+ expect(deep_hash).to eq(expected)
126
+ end
127
+ end
128
+
129
+ context 'with custom separator' do
130
+ let(:subject) { described_class.new('_') }
131
+ let(:hash) do
132
+ {
133
+ 'person_name' => 'Some name',
134
+ 'person_age' => 22,
135
+ 'status' => :success,
136
+ 'vehicle_fuel' => 'GASOLINE',
137
+ 'vehicle_doors' => 4
138
+ }
139
+ end
140
+
141
+ it 'build a deep hash with arrays' do
142
+ expect(deep_hash).to eq(expected)
143
+ end
144
+ end
145
+
146
+ context 'with custom separator on n level deep hash' do
147
+ let(:subject) { described_class.new('_') }
148
+ let(:hash) do
149
+ {
150
+ 'person_name_clazz' => String
151
+ }
152
+ end
153
+
154
+ let(:expected) do
155
+ {
156
+ 'person' => {
157
+ 'name' => { 'clazz' => String }
158
+ }
159
+ }
160
+ end
161
+
162
+ it 'build a deep hash with arrays' do
163
+ expect(deep_hash).to eq(expected)
164
+ end
165
+ end
166
+ end
167
+ end