hashugar 0.0.6 → 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.
- data/README.md +36 -33
- data/Rakefile +13 -13
- data/lib/hashugar/version.rb +1 -1
- data/lib/hashugar.rb +7 -12
- data/spec/hashugar_spec.rb +20 -20
- metadata +31 -11
data/README.md
CHANGED
@@ -26,39 +26,42 @@ Let's compare to the competitors - [OpenStruct](http://www.ruby-doc.org/stdlib-1
|
|
26
26
|
|
27
27
|
`$ rake bench`
|
28
28
|
|
29
|
-
Ruby 1.
|
29
|
+
Ruby 2.1.3 benchmark
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
31
|
+
```
|
32
|
+
OpenStruct create small hash and access once
|
33
|
+
110766.3 (±4.7%) i/s - 557010 in 5.039303s
|
34
|
+
Hashr create small hash and access once
|
35
|
+
147007.1 (±2.6%) i/s - 742596 in 5.054958s
|
36
|
+
Hashugar create small hash and access once
|
37
|
+
427133.4 (±2.7%) i/s - 2157935 in 5.055919s
|
38
|
+
OpenStruct create big hash and access once
|
39
|
+
2018.7 (±7.8%) i/s - 10050 in 5.005609s
|
40
|
+
Hashr create big hash and access once
|
41
|
+
5021.0 (±4.5%) i/s - 25143 in 5.016474s
|
42
|
+
Hashugar create big hash and access once
|
43
|
+
14542.7 (±31.7%) i/s - 65232 in 5.113105s
|
44
|
+
OpenStruct create small hash and access ten times
|
45
|
+
100424.9 (±5.0%) i/s - 509004 in 5.080745s
|
46
|
+
Hashr create small hash and access ten times
|
47
|
+
86539.9 (±3.7%) i/s - 433116 in 5.011856s
|
48
|
+
Hashugar create small hash and access ten times
|
49
|
+
166080.6 (±2.6%) i/s - 844704 in 5.089568s
|
50
|
+
OpenStruct create small hash and access fifty times
|
51
|
+
70585.2 (±5.0%) i/s - 356460 in 5.062517s
|
52
|
+
Hashr create small hash and access fifty times
|
53
|
+
32565.7 (±2.4%) i/s - 164788 in 5.063123s
|
54
|
+
Hashugar create small hash and access fifty times
|
55
|
+
46460.1 (±4.0%) i/s - 233677 in 5.038378s
|
56
|
+
OpenStruct create small hash and access hundred times
|
57
|
+
51480.7 (±4.1%) i/s - 261131 in 5.081082s
|
58
|
+
Hashr create small hash and access hundred times
|
59
|
+
18201.2 (±2.3%) i/s - 91443 in 5.026730s
|
60
|
+
Hashugar create small hash and access hundred times
|
61
|
+
24413.4 (±2.0%) i/s - 124185 in 5.088771s
|
62
|
+
```
|
51
63
|
|
52
|
-
|
53
|
-
|
54
|
-
Hashr create small hash and access fifty times
|
55
|
-
15584.9 (±2.5%) i/s - 78312 in 5.028076s (cycle=1506)
|
56
|
-
Hashugar create small hash and access fifty times
|
57
|
-
21513.9 (±6.0%) i/s - 107952 in 5.039238s (cycle=2076)
|
64
|
+
Why is it so fast?
|
65
|
+
------------------
|
58
66
|
|
59
|
-
|
60
|
-
28617.9 (±2.7%) i/s - 144928 in 5.068069s (cycle=2588)
|
61
|
-
Hashr create small hash and access hundred times
|
62
|
-
8860.7 (±1.7%) i/s - 45103 in 5.091664s (cycle=851)
|
63
|
-
Hashugar create small hash and access hundred times
|
64
|
-
11491.3 (±2.4%) i/s - 57512 in 5.007677s (cycle=1106)
|
67
|
+
[OpenStruct defines a method using metaprogramming](https://github.com/ruby/ruby/blob/trunk/lib/ostruct.rb#L166-L173) on first access, but this is a slow operation. [Hashr is converting whole hash on initialization](https://github.com/svenfuchs/hashr/blob/master/lib/hashr.rb#L102-L114) which is slower when you don't need to access all keys and nested keys. Hashugar uses `method_missing`, which is slower in the long run, but faster for short-lived objects, it's also lazy so there is no precomputation/conversion step.
|
data/Rakefile
CHANGED
@@ -15,27 +15,27 @@ task :bench do
|
|
15
15
|
require 'hashugar'
|
16
16
|
|
17
17
|
SMALL_HASH = {:a => 1, :b => 2}
|
18
|
-
BIG_HASH = {}; 100.times {|i| BIG_HASH[i
|
18
|
+
BIG_HASH = {}; 100.times {|i| BIG_HASH["item#{i}"] = "item#{i}" }
|
19
19
|
|
20
20
|
Benchmark.ips do |x|
|
21
|
-
x.report 'OpenStruct create small hash and access once', 'OpenStruct.new(SMALL_HASH).
|
22
|
-
x.report 'Hashr create small hash and access once', 'Hashr.new(SMALL_HASH).
|
23
|
-
x.report 'Hashugar create small hash and access once', 'Hashugar.new(SMALL_HASH).
|
21
|
+
x.report 'OpenStruct create small hash and access once', 'OpenStruct.new(SMALL_HASH).a'
|
22
|
+
x.report 'Hashr create small hash and access once', 'Hashr.new(SMALL_HASH).a'
|
23
|
+
x.report 'Hashugar create small hash and access once', 'Hashugar.new(SMALL_HASH).a'
|
24
24
|
|
25
|
-
x.report 'OpenStruct create big hash and access once', 'OpenStruct.new(BIG_HASH).
|
26
|
-
x.report 'Hashr
|
27
|
-
x.report 'Hashugar create big hash and access once', 'Hashugar.new(BIG_HASH).
|
25
|
+
x.report 'OpenStruct create big hash and access once', 'OpenStruct.new(BIG_HASH).item50'
|
26
|
+
x.report 'Hashr create big hash and access once', 'Hashr.new(BIG_HASH).item50'
|
27
|
+
x.report 'Hashugar create big hash and access once', 'Hashugar.new(BIG_HASH).item50'
|
28
28
|
|
29
29
|
x.report 'OpenStruct create small hash and access ten times', 'h = OpenStruct.new(SMALL_HASH); i = 0; while i < 10; h.a; i += 1; end'
|
30
|
-
x.report 'Hashr create small hash and access ten times', 'h = Hashr.new(SMALL_HASH);
|
31
|
-
x.report 'Hashugar create small hash and access ten times', 'h = Hashugar.new(SMALL_HASH);
|
30
|
+
x.report 'Hashr create small hash and access ten times', 'h = Hashr.new(SMALL_HASH); i = 0; while i < 10; h.a; i += 1; end'
|
31
|
+
x.report 'Hashugar create small hash and access ten times', 'h = Hashugar.new(SMALL_HASH); i = 0; while i < 10; h.a; i += 1; end'
|
32
32
|
|
33
33
|
x.report 'OpenStruct create small hash and access fifty times', 'h = OpenStruct.new(SMALL_HASH); i = 0; while i < 50; h.a; i += 1; end'
|
34
|
-
x.report 'Hashr create small hash and access fifty times', 'h = Hashr.new(SMALL_HASH);
|
35
|
-
x.report 'Hashugar create small hash and access fifty times', 'h = Hashugar.new(SMALL_HASH);
|
34
|
+
x.report 'Hashr create small hash and access fifty times', 'h = Hashr.new(SMALL_HASH); i = 0; while i < 50; h.a; i += 1; end'
|
35
|
+
x.report 'Hashugar create small hash and access fifty times', 'h = Hashugar.new(SMALL_HASH); i = 0; while i < 50; h.a; i += 1; end'
|
36
36
|
|
37
37
|
x.report 'OpenStruct create small hash and access hundred times', 'h = OpenStruct.new(SMALL_HASH); i = 0; while i < 100; h.a; i += 1; end'
|
38
|
-
x.report 'Hashr create small hash and access hundred times', 'h = Hashr.new(SMALL_HASH);
|
39
|
-
x.report 'Hashugar create small hash and access hundred times', 'h = Hashugar.new(SMALL_HASH);
|
38
|
+
x.report 'Hashr create small hash and access hundred times', 'h = Hashr.new(SMALL_HASH); i = 0; while i < 100; h.a; i += 1; end'
|
39
|
+
x.report 'Hashugar create small hash and access hundred times', 'h = Hashugar.new(SMALL_HASH); i = 0; while i < 100; h.a; i += 1; end'
|
40
40
|
end
|
41
41
|
end
|
data/lib/hashugar/version.rb
CHANGED
data/lib/hashugar.rb
CHANGED
@@ -7,33 +7,29 @@ class Hashugar
|
|
7
7
|
hash.each_pair do |key, value|
|
8
8
|
hashugar = value.to_hashugar
|
9
9
|
@table_with_original_keys[key] = hashugar
|
10
|
-
@table[
|
10
|
+
@table[stringify(key)] = hashugar
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
def method_missing(method, *args, &block)
|
15
15
|
method = method.to_s
|
16
16
|
if method.chomp!('=')
|
17
|
-
|
17
|
+
@table[method] = args.first
|
18
18
|
else
|
19
19
|
@table[method]
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
def [](key)
|
24
|
-
@table[
|
24
|
+
@table[stringify(key)]
|
25
25
|
end
|
26
26
|
|
27
27
|
def []=(key, value)
|
28
|
-
@table[
|
29
|
-
end
|
30
|
-
|
31
|
-
def to_hashugar
|
32
|
-
self
|
28
|
+
@table[stringify(key)] = value
|
33
29
|
end
|
34
30
|
|
35
31
|
def respond_to?(key)
|
36
|
-
@table.has_key?(
|
32
|
+
@table.has_key?(stringify(key))
|
37
33
|
end
|
38
34
|
|
39
35
|
def each(&block)
|
@@ -41,7 +37,7 @@ class Hashugar
|
|
41
37
|
end
|
42
38
|
|
43
39
|
private
|
44
|
-
def
|
40
|
+
def stringify(key)
|
45
41
|
key.is_a?(Symbol) ? key.to_s : key
|
46
42
|
end
|
47
43
|
end
|
@@ -54,8 +50,7 @@ end
|
|
54
50
|
|
55
51
|
class Array
|
56
52
|
def to_hashugar
|
57
|
-
|
58
|
-
Array.new(collect(&:to_hashugar))
|
53
|
+
map(&:to_hashugar)
|
59
54
|
end
|
60
55
|
end
|
61
56
|
|
data/spec/hashugar_spec.rb
CHANGED
@@ -4,73 +4,73 @@ describe Hashugar do
|
|
4
4
|
context 'when accessing simple hash' do
|
5
5
|
it 'should be make accessible string and symbol keys' do
|
6
6
|
hashugar = {:a => 1, 'b' => 2}.to_hashugar
|
7
|
-
hashugar.a.
|
8
|
-
hashugar.b.
|
7
|
+
expect(hashugar.a).to eq(1)
|
8
|
+
expect(hashugar.b).to eq(2)
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'should be readable through nice methods' do
|
12
12
|
hashugar = {:a => 1, :b => 2}.to_hashugar
|
13
|
-
hashugar.a.
|
14
|
-
hashugar.b.
|
13
|
+
expect(hashugar.a).to eq(1)
|
14
|
+
expect(hashugar.b).to eq(2)
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should be writable through nice methods' do
|
18
18
|
hashugar = {:a => 1}.to_hashugar
|
19
19
|
hashugar.a = 2
|
20
20
|
hashugar.b = 3
|
21
|
-
hashugar.a.
|
22
|
-
hashugar.b.
|
21
|
+
expect(hashugar.a).to eq(2)
|
22
|
+
expect(hashugar.b).to eq(3)
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'should be readable through old methods' do
|
26
26
|
hashugar = {:a => 1}.to_hashugar
|
27
|
-
hashugar[:a].
|
28
|
-
hashugar['a'].
|
27
|
+
expect(hashugar[:a]).to eq(1)
|
28
|
+
expect(hashugar['a']).to eq(1)
|
29
29
|
end
|
30
30
|
|
31
31
|
it 'should be writable through old methods' do
|
32
32
|
hashugar = {:a => 1}.to_hashugar
|
33
33
|
hashugar['a'] = 2
|
34
|
-
hashugar.a.
|
34
|
+
expect(hashugar.a).to eq(2)
|
35
35
|
hashugar[:a] = 3
|
36
|
-
hashugar.a.
|
36
|
+
expect(hashugar.a).to eq(3)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
40
|
context 'when accessing nested hash' do
|
41
41
|
it 'should be writable through nice methods' do
|
42
42
|
hashugar = {:a => {:b => 1}}.to_hashugar
|
43
|
-
hashugar.a.b.
|
43
|
+
expect(hashugar.a.b).to eq(1)
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'should be writable through nice methods' do
|
47
47
|
hashugar = {:a =>{}}.to_hashugar
|
48
48
|
hashugar.a.b = 1
|
49
|
-
hashugar.a.b.
|
49
|
+
expect(hashugar.a.b).to eq(1)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
context 'when accessing hashes in array' do
|
54
54
|
it 'should return hashugars' do
|
55
55
|
hashugar = [{:a => 1}, {:b => 2}].to_hashugar
|
56
|
-
hashugar[0].a.
|
57
|
-
hashugar.last.b.
|
56
|
+
expect(hashugar[0].a).to eq(1)
|
57
|
+
expect(hashugar.last.b).to eq(2)
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
61
|
context 'when using respond_to?' do
|
62
62
|
it 'should return true on valid key' do
|
63
63
|
hashugar = {:a => 1}.to_hashugar
|
64
|
-
hashugar.respond_to?('a').
|
65
|
-
hashugar.respond_to?(:a).
|
66
|
-
hashugar.respond_to?(:b).
|
64
|
+
expect(hashugar.respond_to?('a')).to be_truthy
|
65
|
+
expect(hashugar.respond_to?(:a)).to be_truthy
|
66
|
+
expect(hashugar.respond_to?(:b)).to be_falsey
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
70
|
context 'when creating using Hashugar#new' do
|
71
71
|
it 'should accept hash in contructor' do
|
72
72
|
hashugar = Hashugar.new({:a => {:b => 1}})
|
73
|
-
hashugar.a.b.
|
73
|
+
expect(hashugar.a.b).to eq(1)
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
@@ -85,8 +85,8 @@ describe Hashugar do
|
|
85
85
|
values << v
|
86
86
|
end
|
87
87
|
|
88
|
-
keys.
|
89
|
-
values.
|
88
|
+
expect(keys).to eq([:a, :c])
|
89
|
+
expect(values).to eq([4, 2])
|
90
90
|
end
|
91
91
|
end
|
92
92
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hashugar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-11-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: benchmark_suite
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: ffi
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: '0'
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: hashr
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
@@ -54,7 +69,12 @@ dependencies:
|
|
54
69
|
version: '0'
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
58
78
|
description: Nested OpenStruct optimized for short-lived objects.
|
59
79
|
email:
|
60
80
|
- johno@jsmf.net
|
@@ -94,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
114
|
version: '0'
|
95
115
|
requirements: []
|
96
116
|
rubyforge_project:
|
97
|
-
rubygems_version: 1.8.
|
117
|
+
rubygems_version: 1.8.23.2
|
98
118
|
signing_key:
|
99
119
|
specification_version: 3
|
100
120
|
summary: Fast Nested OpenStruct
|