whoopee-cushion 0.1.0 → 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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +44 -14
- data/Rakefile +9 -1
- data/lib/whoopee_cushion.rb +16 -27
- data/lib/whoopee_cushion/version.rb +1 -1
- data/test/benchmarks.rb +72 -0
- data/test/inflate_test.rb +21 -7
- data/test/test_helper.rb +0 -49
- data/whoopee_cushion.gemspec +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 511989dd2912ff76496a7633ed8b3879d25550f9
|
4
|
+
data.tar.gz: 48e85a251bd17590807ec59f986da00507d70eef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b0501be20f64d23f1ad6e0e3580f8230f9ca4af9b33acfddbdf55f5e63ed341d1e0b1598b0d638e6c6933d07be46244ef80d20b13bd7009cb7e45b7872d910c
|
7
|
+
data.tar.gz: 2f87403c437fc9d363b1a4bc7c3e4bc4505dadcf3e4f3195322f6a1f5eea20ea89336dd5321e984e70d71a256e79b4f4d75391f8d8c33cf61385fdfcffa789ff
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -12,40 +12,70 @@ Wouldn't it be nice if you could access all your API response data like this?
|
|
12
12
|
|
13
13
|
`obj.products.first.customer.customer_id`
|
14
14
|
|
15
|
-
whoopee-cushion will let you do just that. It's faster than using OpenStructs
|
15
|
+
whoopee-cushion will let you do just that. It's faster than using OpenStructs and any recursive algorithms based on them
|
16
16
|
because it uses Ruby's faster Struct objects under the hood.
|
17
17
|
|
18
18
|
Setup
|
19
19
|
=====
|
20
20
|
|
21
|
-
`
|
21
|
+
`
|
22
|
+
gem install whoopee-cushion
|
23
|
+
`
|
22
24
|
|
23
25
|
or
|
24
26
|
|
25
|
-
`
|
27
|
+
`
|
28
|
+
gem "whoopee-cushion"
|
29
|
+
`
|
26
30
|
|
27
31
|
in your Gemfile.
|
28
32
|
|
29
33
|
In your Ruby code:
|
30
34
|
|
31
|
-
`
|
35
|
+
`
|
36
|
+
require 'whoopee_cushion'
|
37
|
+
`
|
32
38
|
|
33
39
|
then
|
34
40
|
|
35
|
-
`
|
41
|
+
`
|
42
|
+
hash = {:a => 1, :CamelCase => 2, :c => 3, :d => { :e => 4, :f => [1,2,3,4,5]}}
|
36
43
|
|
37
|
-
|
44
|
+
obj = WhoopeeCushion::Inflate.from_hash(hash)
|
38
45
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
`json = '{"CamelCase": "no", "json": "yes"}'`
|
46
|
+
puts obj.a
|
47
|
+
puts obj.camel_case
|
48
|
+
puts obj.d.f.first
|
49
|
+
`
|
44
50
|
|
45
51
|
You can also go straight from JSON, or turn off the automatic camel case conversion:
|
46
52
|
|
47
|
-
`
|
53
|
+
`
|
54
|
+
json = '{"CamelCase": "no", "json": "yes"}'
|
55
|
+
|
56
|
+
obj = WhoopeeCushion::Inflate.from_json(json, :convert_keys => false)
|
57
|
+
|
58
|
+
puts obj.CamelCase
|
59
|
+
`
|
60
|
+
|
61
|
+
If you want to carry out your own string conversion, use a lambda:
|
62
|
+
|
63
|
+
`
|
64
|
+
hash = {:a => 1, :CamelCase => 2, :c => 3, :d => { :e => 4, :f => [1,2,3,4,5]}}
|
65
|
+
|
66
|
+
obj = WhoopeeCushion::Inflate.from_hash(hash, :convert_keys => lambda {|s| '#{s}_foo'})
|
67
|
+
|
68
|
+
puts obj.a_foo
|
69
|
+
puts obj.CamelCase_foo
|
70
|
+
puts obj.d_foo.f_foo.first
|
71
|
+
`
|
72
|
+
|
73
|
+
Performance
|
74
|
+
===========
|
48
75
|
|
49
|
-
`
|
76
|
+
Check the project out, bundle it and run the simple `rake benchmark` suite to see some figures. Comparisons are made
|
77
|
+
against the recursive-open-struct gem and simple OpenStruct creates. The whoopee-cushion gem performs very well against
|
78
|
+
both when not converting strings to snake case (quite an expensive operation, using a stripped-down version of the
|
79
|
+
Rails 'underscore' method.) When converting strings the performance increase is diminished, but it still comes out well.
|
50
80
|
|
51
|
-
|
81
|
+
If you can increase performance (or otherwise improve the gem in any way) please fork it and issue a pull request.
|
data/Rakefile
CHANGED
@@ -1,8 +1,16 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
currdir = File.dirname(__FILE__)
|
3
|
+
require currdir+ '/test/benchmarks'
|
2
4
|
|
3
5
|
require 'rake/testtask'
|
4
6
|
|
5
7
|
Rake::TestTask.new do |t|
|
6
8
|
t.libs << 'test'
|
7
9
|
t.pattern = "test/*_test.rb"
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
desc 'Run the benchmarks'
|
14
|
+
task :benchmark do
|
15
|
+
benchmarks
|
8
16
|
end
|
data/lib/whoopee_cushion.rb
CHANGED
@@ -26,42 +26,31 @@ module WhoopeeCushion
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.from_hash(hash, options = {})
|
29
|
-
|
30
|
-
keys = hash
|
31
|
-
|
32
|
-
out = model.new
|
33
|
-
hash.each do |key, value|
|
34
|
-
out.send("#{key}=", self.from_object(value, options))
|
35
|
-
end
|
36
|
-
out
|
29
|
+
@iter ||= 1
|
30
|
+
keys, values = process_hash hash, options
|
31
|
+
Struct.new(*keys).new(*values)
|
37
32
|
end
|
38
33
|
|
39
34
|
private
|
40
35
|
|
41
36
|
def self.process_hash hash, options
|
42
|
-
|
43
|
-
|
44
|
-
|
37
|
+
keys = []
|
38
|
+
values = []
|
39
|
+
hash.each do |k,v|
|
40
|
+
keys << (options[:convert_keys] == false ? k : underscore_key(k, options)).to_sym
|
41
|
+
values << from_object(v, options)
|
45
42
|
end
|
46
|
-
|
43
|
+
# Split the keys and values to arrays for 1: speed and 2: backwards compatibility with Ruby < 1.9
|
44
|
+
# where hashes are unordered
|
45
|
+
[keys, values]
|
47
46
|
end
|
48
47
|
|
49
|
-
def self.underscore_key(
|
50
|
-
|
51
|
-
underscore(key.to_s)
|
52
|
-
elsif key.is_a? String
|
53
|
-
underscore(key)
|
54
|
-
else
|
55
|
-
key
|
56
|
-
end
|
57
|
-
end
|
48
|
+
def self.underscore_key(string, options)
|
49
|
+
return options[:convert_keys].call(string) if options[:convert_keys]
|
58
50
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
63
|
-
tr("-", "_").
|
64
|
-
downcase
|
51
|
+
string.to_s.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
52
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
53
|
+
downcase
|
65
54
|
end
|
66
55
|
end
|
67
56
|
end
|
data/test/benchmarks.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'whoopee_cushion'
|
2
|
+
require 'byebug'
|
3
|
+
require 'benchmark'
|
4
|
+
require 'recursive-open-struct'
|
5
|
+
|
6
|
+
def benchmarks
|
7
|
+
puts "Benchmarking 10000 operations on deep hash:"
|
8
|
+
|
9
|
+
hash = {:aaaaBbbb => 'ccccDDDD',
|
10
|
+
:a => 2, :b => 2, :c => 2, :d => 2, :e => 2,
|
11
|
+
:f => 2, :g => 2, :h => 2, :i => 2, :j => 2,
|
12
|
+
:k => 2, :l => 2, :m => 2, :n => 2, :o => 2,
|
13
|
+
:p => 2, :q => 2, :r => 2, :s => 2, :t => 2,
|
14
|
+
'eeeeEeee' =>[{"NameThe1" => {"CamelName" => 4444},
|
15
|
+
"NameThe3" => [4,5,6]}, "3", "4"]}
|
16
|
+
puts "whoopee-cushion"
|
17
|
+
puts Benchmark.measure {
|
18
|
+
10000.times do
|
19
|
+
a = WhoopeeCushion::Inflate.from_hash hash, :convert_keys => false
|
20
|
+
raise 'Incorrect value found' if a.eeeeEeee.first.NameThe3[0] != 4
|
21
|
+
end
|
22
|
+
}
|
23
|
+
|
24
|
+
puts "whoopee-cushion with camel to snake case conversion"
|
25
|
+
puts Benchmark.measure {
|
26
|
+
10000.times do
|
27
|
+
a = WhoopeeCushion::Inflate.from_hash hash
|
28
|
+
raise 'Incorrect value found' if a.eeee_eeee.first.name_the3[0] != 4
|
29
|
+
end
|
30
|
+
}
|
31
|
+
|
32
|
+
puts 'recursive-open-struct gem for comparison'
|
33
|
+
puts Benchmark.measure {
|
34
|
+
10000.times do
|
35
|
+
a = RecursiveOpenStruct.new hash, :recurse_over_arrays => true
|
36
|
+
raise 'Incorrect value found' if a.eeeeEeee.first.NameThe3[0] != 4
|
37
|
+
end
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
puts "Benchmarking 10000 operations on light hash:"
|
43
|
+
|
44
|
+
hash = {:a => 2, :b => 2, :c => 2, :d => 2, :e => 2,
|
45
|
+
:f => 2, :g => 2, :h => 2, :i => 2, :j => 2,
|
46
|
+
:k => 2, :l => 2, :m => 2, :n => 2, :c1 => "Lorem Ipsum"}
|
47
|
+
|
48
|
+
|
49
|
+
puts Benchmark.measure {
|
50
|
+
10000.times do
|
51
|
+
x = WhoopeeCushion::Inflate.from_hash hash, :convert_keys => false
|
52
|
+
x.c1
|
53
|
+
end
|
54
|
+
}
|
55
|
+
|
56
|
+
puts "Benchmarking 10000 operations on light hash with camel case conversion:"
|
57
|
+
puts Benchmark.measure {
|
58
|
+
10000.times do
|
59
|
+
x = WhoopeeCushion::Inflate.from_hash hash
|
60
|
+
x.c1
|
61
|
+
end
|
62
|
+
}
|
63
|
+
|
64
|
+
puts "Benchmarking 10000 OpenStruct creates"
|
65
|
+
|
66
|
+
puts Benchmark.measure {
|
67
|
+
10000.times do
|
68
|
+
x = OpenStruct.new(hash)
|
69
|
+
x.c1
|
70
|
+
end
|
71
|
+
}
|
72
|
+
end
|
data/test/inflate_test.rb
CHANGED
@@ -19,7 +19,7 @@ end
|
|
19
19
|
|
20
20
|
describe 'converting keys to snake case' do
|
21
21
|
before do
|
22
|
-
@json = { 'CaseOne' => 'FirstCase', 'caseTwo' => 'secondCase', 'case_three' => 'third_case' }
|
22
|
+
@json = { 'CaseOne' => 'FirstCase', 'caseTwo' => 'secondCase', 'case_three' => 'third_case', 'CASEFour' => '4' }
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'should convert CamelCase' do
|
@@ -32,18 +32,23 @@ describe 'converting keys to snake case' do
|
|
32
32
|
assert_equal 'secondCase', obj.case_two
|
33
33
|
end
|
34
34
|
|
35
|
+
it 'should convert CAMELCase with acronyms' do
|
36
|
+
obj = WhoopeeCushion::Inflate.from_hash @json
|
37
|
+
assert_equal '4', obj.case_four, "Could not find case_four: #{obj.inspect}"
|
38
|
+
end
|
39
|
+
|
35
40
|
it 'should not convert camel case with snake keys option false' do
|
36
|
-
obj = WhoopeeCushion::Inflate.from_hash @json, :
|
41
|
+
obj = WhoopeeCushion::Inflate.from_hash @json, :convert_keys => false
|
37
42
|
assert_equal 'FirstCase', obj.CaseOne
|
38
43
|
end
|
39
44
|
|
40
45
|
it 'should not convert camel back with snake keys option false' do
|
41
|
-
obj = WhoopeeCushion::Inflate.from_hash @json, :
|
46
|
+
obj = WhoopeeCushion::Inflate.from_hash @json, :convert_keys => false
|
42
47
|
assert_equal 'secondCase', obj.caseTwo
|
43
48
|
end
|
44
49
|
|
45
50
|
it 'should leave snake case alone with snake keys option false' do
|
46
|
-
obj = WhoopeeCushion::Inflate.from_hash @json, :
|
51
|
+
obj = WhoopeeCushion::Inflate.from_hash @json, :convert_keys => false
|
47
52
|
assert_equal 'third_case', obj.case_three
|
48
53
|
end
|
49
54
|
|
@@ -64,7 +69,7 @@ describe 'converting recursive hashes' do
|
|
64
69
|
end
|
65
70
|
|
66
71
|
it 'should not convert keys to snake case with snake keys option false' do
|
67
|
-
obj = WhoopeeCushion::Inflate.from_hash @json, :
|
72
|
+
obj = WhoopeeCushion::Inflate.from_hash @json, :convert_keys => false
|
68
73
|
assert_equal 'value', obj.CaseOne.caseTwo.ThisIsCaseThree
|
69
74
|
end
|
70
75
|
end
|
@@ -82,7 +87,7 @@ describe 'converting deep arrays' do
|
|
82
87
|
end
|
83
88
|
|
84
89
|
it 'should get deep array values correctly with snake keys option false' do
|
85
|
-
obj = WhoopeeCushion::Inflate.from_hash @json, :
|
90
|
+
obj = WhoopeeCushion::Inflate.from_hash @json, :convert_keys => false
|
86
91
|
assert_equal 2, obj.CaseOne[0].caseTwo
|
87
92
|
assert_equal 'four', obj.CaseOne[0].CaseThree[0].CaseFour
|
88
93
|
assert_equal 5, obj.CaseOne[0].CaseThree[1]
|
@@ -113,8 +118,17 @@ describe 'converting from array' do
|
|
113
118
|
end
|
114
119
|
|
115
120
|
it 'should convert an embedded hash without changing keys with snake keys option false' do
|
116
|
-
obj = WhoopeeCushion::Inflate.from_array @array, :
|
121
|
+
obj = WhoopeeCushion::Inflate.from_array @array, :convert_keys => false
|
117
122
|
assert_equal 'now', obj[4].ThePeople
|
118
123
|
end
|
119
124
|
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe 'converting keys' do
|
128
|
+
it 'should use the lambda if possible' do
|
129
|
+
hash = {'power' => 'to', 'the_people' => 'now', 'bar' => {'interesting' => 'times'}}
|
130
|
+
obj = WhoopeeCushion::Inflate.from_hash hash, :convert_keys => lambda {|s| "#{s}_foo"}
|
131
|
+
assert_equal 'to', obj.power_foo
|
132
|
+
assert_equal 'times', obj.bar_foo.interesting_foo
|
133
|
+
end
|
120
134
|
end
|
data/test/test_helper.rb
CHANGED
@@ -3,52 +3,3 @@ require 'minitest/unit'
|
|
3
3
|
require 'minitest/autorun'
|
4
4
|
require 'minitest/pride'
|
5
5
|
require 'byebug'
|
6
|
-
require 'benchmark'
|
7
|
-
require 'recursive-open-struct'
|
8
|
-
|
9
|
-
puts "Benchmarking 10000 operations on deep hash:"
|
10
|
-
|
11
|
-
hash = {:aaaaBbbb => 'ccccDDDD',
|
12
|
-
:a => 2, :b => 2, :c => 2, :d => 2, :e => 2,
|
13
|
-
:f => 2, :g => 2, :h => 2, :i => 2, :j => 2,
|
14
|
-
:k => 2, :l => 2, :m => 2, :n => 2,
|
15
|
-
'eeeeEeee' =>[{"splandact" => {"Griffin" => 4444},
|
16
|
-
"splortitude" => [4,5,6]}, "3", "4"]}
|
17
|
-
puts "whoopee-cushion"
|
18
|
-
puts Benchmark.measure {
|
19
|
-
10000.times do
|
20
|
-
a = WhoopeeCushion::Inflate.from_hash hash, :to_snake_keys => false
|
21
|
-
raise 'Incorrect value found' if a.eeeeEeee.first.splortitude[0] != 4
|
22
|
-
end
|
23
|
-
}
|
24
|
-
puts 'recursive-open-struct'
|
25
|
-
|
26
|
-
puts Benchmark.measure {
|
27
|
-
10000.times do
|
28
|
-
a = RecursiveOpenStruct.new hash, :recurse_over_arrays => true
|
29
|
-
raise 'Incorrect value found' if a.eeeeEeee.first.splortitude[0] != 4
|
30
|
-
end
|
31
|
-
}
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
puts "Benchmarking 10000 operations on light hash:"
|
36
|
-
|
37
|
-
hash = {:a => 2, :b => 2, :c => 2, :d => 2, :e => 2,
|
38
|
-
:f => 2, :g => 2, :h => 2, :i => 2, :j => 2,
|
39
|
-
:k => 2, :l => 2, :m => 2, :n => 2, :c => "Lorem Ipsum"}
|
40
|
-
|
41
|
-
|
42
|
-
puts Benchmark.measure {
|
43
|
-
10000.times do
|
44
|
-
WhoopeeCushion::Inflate.from_hash hash, :to_snake_keys => false
|
45
|
-
end
|
46
|
-
}
|
47
|
-
|
48
|
-
puts "Benchmarking 10000 OpenStruct creates"
|
49
|
-
|
50
|
-
puts Benchmark.measure {
|
51
|
-
10000.times do
|
52
|
-
x = OpenStruct.new(hash)
|
53
|
-
end
|
54
|
-
}
|
data/whoopee_cushion.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["ben@chemica.co.uk"]
|
11
11
|
spec.summary = %q{Allow recursive inflation of JSON data into structs.}
|
12
12
|
spec.description = %q{Inflates JSON data recursively into structs to allow use of dot notation for data access.}
|
13
|
-
spec.homepage = ""
|
13
|
+
spec.homepage = "https://github.com/chemica/whoopee-cushion?source=c"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: whoopee-cushion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Dunkley
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02-
|
11
|
+
date: 2014-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -97,10 +97,11 @@ files:
|
|
97
97
|
- Rakefile
|
98
98
|
- lib/whoopee_cushion.rb
|
99
99
|
- lib/whoopee_cushion/version.rb
|
100
|
+
- test/benchmarks.rb
|
100
101
|
- test/inflate_test.rb
|
101
102
|
- test/test_helper.rb
|
102
103
|
- whoopee_cushion.gemspec
|
103
|
-
homepage:
|
104
|
+
homepage: https://github.com/chemica/whoopee-cushion?source=c
|
104
105
|
licenses:
|
105
106
|
- MIT
|
106
107
|
metadata: {}
|
@@ -125,5 +126,6 @@ signing_key:
|
|
125
126
|
specification_version: 4
|
126
127
|
summary: Allow recursive inflation of JSON data into structs.
|
127
128
|
test_files:
|
129
|
+
- test/benchmarks.rb
|
128
130
|
- test/inflate_test.rb
|
129
131
|
- test/test_helper.rb
|