hashugar 0.0.1
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/.gitignore +19 -0
- data/.rvmrc +1 -0
- data/Gemfile +6 -0
- data/README.md +48 -0
- data/Rakefile +35 -0
- data/TODO +6 -0
- data/hashugar.gemspec +21 -0
- data/lib/hashugar.rb +55 -0
- data/lib/hashugar/version.rb +3 -0
- data/spec/hashugar_spec.rb +52 -0
- data/spec/spec_helper.rb +7 -0
- metadata +120 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3@hashugar --create
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
Hashugar
|
2
|
+
========
|
3
|
+
|
4
|
+
Nested OpenStruct alternative optimized for speed especially for many short-lived objects (e.g. results from db).
|
5
|
+
|
6
|
+
|
7
|
+
Usage
|
8
|
+
-----
|
9
|
+
|
10
|
+
`$ gem install hashugar`
|
11
|
+
|
12
|
+
-----
|
13
|
+
```ruby
|
14
|
+
hashugar = {:a => 1, 'b' => {:c => 3}}.to_hashugar
|
15
|
+
hashugar.a # => 1
|
16
|
+
hashugar.b # => 2
|
17
|
+
hashugar.b.c # => 3
|
18
|
+
```
|
19
|
+
|
20
|
+
How fast is it?
|
21
|
+
---------------
|
22
|
+
|
23
|
+
Ruby 1.9.3 benchmark
|
24
|
+
|
25
|
+
OpenStruct create small hash and access once
|
26
|
+
25546.3 (±5.9%) i/s - 128865 in 5.060934s (cycle=2343)
|
27
|
+
Hashugar create small hash and access once
|
28
|
+
570523.2 (±6.3%) i/s - 2857400 in 5.031212s (cycle=28574)
|
29
|
+
|
30
|
+
OpenStruct create big hash and access once
|
31
|
+
780.5 (±8.5%) i/s - 3927 in 5.066012s (cycle=77)
|
32
|
+
Hashugar create big hash and access once
|
33
|
+
779118.2 (±4.4%) i/s - 3911640 in 5.031364s (cycle=32597)
|
34
|
+
|
35
|
+
OpenStruct create small hash and access ten times
|
36
|
+
29389.7 (±10.6%) i/s - 146720 in 5.058931s (cycle=2620)
|
37
|
+
Hashugar create small hash and access ten times
|
38
|
+
105626.2 (±3.7%) i/s - 534421 in 5.066869s (cycle=8761)
|
39
|
+
|
40
|
+
OpenStruct create small hash and access fifty times
|
41
|
+
24329.8 (±4.2%) i/s - 123390 in 5.082089s (cycle=2285)
|
42
|
+
Hashugar create small hash and access fifty times
|
43
|
+
22246.2 (±2.9%) i/s - 112008 in 5.039232s (cycle=2154)
|
44
|
+
|
45
|
+
OpenStruct create small hash and access hundred times
|
46
|
+
20432.0 (±13.4%) i/s - 100912 in 5.011692s (cycle=1904)
|
47
|
+
Hashugar create small hash and access hundred times
|
48
|
+
11296.5 (±3.3%) i/s - 56940 in 5.046262s (cycle=1095)
|
data/Rakefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new('spec')
|
6
|
+
|
7
|
+
# If you want to make this the default task
|
8
|
+
task :default => :spec
|
9
|
+
|
10
|
+
desc "Benchmark"
|
11
|
+
task :bench do
|
12
|
+
require 'benchmark/ips'
|
13
|
+
require 'ostruct'
|
14
|
+
require 'hashugar'
|
15
|
+
|
16
|
+
SMALL_HASH = {:a => 1, :b => 2}
|
17
|
+
BIG_HASH = {}; 100.times {|i| BIG_HASH[i.to_s] = "item#{i}" }
|
18
|
+
|
19
|
+
Benchmark.ips do |x|
|
20
|
+
x.report 'OpenStruct create small hash and access once', 'OpenStruct.new(SMALL_HASH).item5'
|
21
|
+
x.report 'Hashugar create small hash and access once', 'Hashugar.new(SMALL_HASH).item5'
|
22
|
+
|
23
|
+
x.report 'OpenStruct create big hash and access once', 'OpenStruct.new(BIG_HASH).item5'
|
24
|
+
x.report 'Hashugar create big hash and access once', 'Hashugar.new(BIG_HASH).item5'
|
25
|
+
|
26
|
+
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'
|
27
|
+
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'
|
28
|
+
|
29
|
+
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'
|
30
|
+
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'
|
31
|
+
|
32
|
+
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'
|
33
|
+
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'
|
34
|
+
end
|
35
|
+
end
|
data/TODO
ADDED
data/hashugar.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/hashugar/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Jan Suchal"]
|
6
|
+
gem.email = ["johno@jsmf.net"]
|
7
|
+
gem.summary = %q{Fast Nested OpenStruct}
|
8
|
+
gem.description = %q{Nested OpenStruct optimized for short-lived objects.}
|
9
|
+
gem.homepage = "http://github.com/jsuchal/hashugar"
|
10
|
+
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.name = "hashugar"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Hashugar::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency 'rspec'
|
19
|
+
gem.add_development_dependency 'benchmark_suite'
|
20
|
+
gem.add_development_dependency 'ffi'
|
21
|
+
end
|
data/lib/hashugar.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require "hashugar/version"
|
2
|
+
|
3
|
+
class Hashugar
|
4
|
+
def initialize(hash)
|
5
|
+
@table = hash
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing(method, *args, &block)
|
9
|
+
method = method.to_s
|
10
|
+
if method.chomp!('=')
|
11
|
+
self[method] = args.first
|
12
|
+
else
|
13
|
+
@table[method]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](key)
|
18
|
+
@table[convert_key(key)]
|
19
|
+
end
|
20
|
+
|
21
|
+
def []=(key, value)
|
22
|
+
@table[convert_key(key)] = value
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_hashugar
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def convert_key(key)
|
31
|
+
key.is_a?(Symbol) ? key.to_s : key
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Hash
|
36
|
+
def to_hashugar
|
37
|
+
# TODO lazy?
|
38
|
+
table = {}
|
39
|
+
each_pair do |key, value|
|
40
|
+
table[convert_key(key)] = value.to_hashugar
|
41
|
+
end
|
42
|
+
Hashugar.new(table)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def convert_key(key)
|
47
|
+
key.is_a?(Symbol) ? key.to_s : key
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Object
|
52
|
+
def to_hashugar
|
53
|
+
self
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hashugar do
|
4
|
+
context 'when accessing simple hash' do
|
5
|
+
it 'should be make accessible string and symbol keys' do
|
6
|
+
hashugar = {:a => 1, 'b' => 2}.to_hashugar
|
7
|
+
hashugar.a.should == 1
|
8
|
+
hashugar.b.should == 2
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should be readable through nice methods' do
|
12
|
+
hashugar = {:a => 1, :b => 2}.to_hashugar
|
13
|
+
hashugar.a.should == 1
|
14
|
+
hashugar.b.should == 2
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should be writable through nice methods' do
|
18
|
+
hashugar = {:a => 1}.to_hashugar
|
19
|
+
hashugar.a = 2
|
20
|
+
hashugar.b = 3
|
21
|
+
hashugar.a.should == 2
|
22
|
+
hashugar.b.should == 3
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should be readable through old methods' do
|
26
|
+
hashugar = {:a => 1}.to_hashugar
|
27
|
+
hashugar[:a].should == 1
|
28
|
+
hashugar['a'].should == 1
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should be writable through old methods' do
|
32
|
+
hashugar = {:a => 1}.to_hashugar
|
33
|
+
hashugar['a'] = 2
|
34
|
+
hashugar.a.should == 2
|
35
|
+
hashugar[:a] = 3
|
36
|
+
hashugar.a.should == 3
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when accessing nested hash' do
|
41
|
+
it 'should be writable through nice methods' do
|
42
|
+
hashugar = {:a => {:b => 1}}.to_hashugar
|
43
|
+
hashugar.a.b.should == 1
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should be writable through nice methods' do
|
47
|
+
hashugar = {:a =>{}}.to_hashugar
|
48
|
+
hashugar.a.b = 1
|
49
|
+
hashugar.a.b.should == 1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hashugar
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 856480538658449761
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jan Suchal
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-12-07 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 2002549777813010636
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: benchmark_suite
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 2002549777813010636
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: ffi
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 2002549777813010636
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
description: Nested OpenStruct optimized for short-lived objects.
|
64
|
+
email:
|
65
|
+
- johno@jsmf.net
|
66
|
+
executables: []
|
67
|
+
|
68
|
+
extensions: []
|
69
|
+
|
70
|
+
extra_rdoc_files: []
|
71
|
+
|
72
|
+
files:
|
73
|
+
- .gitignore
|
74
|
+
- .rvmrc
|
75
|
+
- Gemfile
|
76
|
+
- README.md
|
77
|
+
- Rakefile
|
78
|
+
- TODO
|
79
|
+
- hashugar.gemspec
|
80
|
+
- lib/hashugar.rb
|
81
|
+
- lib/hashugar/version.rb
|
82
|
+
- spec/hashugar_spec.rb
|
83
|
+
- spec/spec_helper.rb
|
84
|
+
has_rdoc: true
|
85
|
+
homepage: http://github.com/jsuchal/hashugar
|
86
|
+
licenses: []
|
87
|
+
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options: []
|
90
|
+
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
hash: 2002549777813010636
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
hash: 2002549777813010636
|
108
|
+
segments:
|
109
|
+
- 0
|
110
|
+
version: "0"
|
111
|
+
requirements: []
|
112
|
+
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 1.5.2
|
115
|
+
signing_key:
|
116
|
+
specification_version: 3
|
117
|
+
summary: Fast Nested OpenStruct
|
118
|
+
test_files:
|
119
|
+
- spec/hashugar_spec.rb
|
120
|
+
- spec/spec_helper.rb
|