hstruct 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.ruby-version +1 -0
- data/Gemfile +0 -2
- data/README.md +73 -28
- data/benchmarks/all.rb +23 -0
- data/benchmarks/attr_extras.rb +23 -0
- data/benchmarks/benchmark.rb +43 -0
- data/benchmarks/class_args_send.rb +23 -0
- data/benchmarks/class_hash_args.rb +25 -0
- data/benchmarks/class_hash_args_fetch.rb +25 -0
- data/benchmarks/hash_missing.rb +15 -0
- data/benchmarks/hashie.rb +20 -0
- data/benchmarks/hstruct.rb +4 -116
- data/benchmarks/open_struct.rb +7 -0
- data/benchmarks/virtus.rb +20 -0
- data/hstruct.gemspec +1 -1
- data/lib/hstruct.rb +16 -5
- data/test/lib/hstruct_test.rb +51 -0
- data/test/test_helper.rb +1 -1
- metadata +16 -19
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YjBlZTJhZTFjOGYyZGNjNjI4ODk4MDZkMDE1NWJjODRkODM1NmFjZQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MmEzMTY3ZWExNjk4YTU1OTlmYzE5NjU0Y2YxNzNkODE1ZDIxOWYwMw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
OTRlNGRjYTg1ZDY1NzM3MmY3NTkzNTcyNjc3NmYzZWFlOThmZjM5MGQ1MDRm
|
10
|
+
MDE0ZTkxNzRiOWMxMmFmYmJkMWZiYWU0NTQ0NjA0MTdlYTk4MTQzODZjODhi
|
11
|
+
Nzk3NDFhNTNkNTNjOWM0NmU5ZTcxYmQ0ZjcyODkxYWUzODk2NzM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZTkxMjcxOTQ0OTNlODVkYjMxZjdjZmYwMzY2ZjQxYjZkMzNhNjk5ODAxZjNk
|
14
|
+
MjUxNGEzYWYyNzI4MGVmMmU5YjM1Zjc0OWQwOTJkYjdjZGI5OGQ1YWY3OGY0
|
15
|
+
NWNmZWZmYjFiZjhjZjQzMjQxOTM4NjA5MjQzYThmYWRhMTQ1MWM=
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0-p247
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
[![travis](https://secure.travis-ci.org/cambridge-healthcare/hstruct.png)](https://travis-ci.org/cambridge-healthcare/hstruct)
|
2
|
+
[![Code Climate](https://codeclimate.com/github/cambridge-healthcare/hstruct.png)](https://codeclimate.com/github/cambridge-healthcare/hstruct)
|
3
|
+
# HStruct
|
2
4
|
|
3
|
-
|
5
|
+
Ruby Structs with the convenience of instantiating from a Hash.
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
a `to_h` method by default (no, you don't have to be running Ruby 2.0).
|
7
|
+
It benchmarks about 3x slower than the plain object variant, but it's
|
8
|
+
3.5x faster than OpenStruct, 5x faster than Hashie and 120x faster than
|
9
|
+
Virtus. Most importantly, it needs significanlty less setup code than
|
10
|
+
all other gems. Here's the plain object version:
|
10
11
|
|
11
12
|
```ruby
|
12
13
|
class ClassWithArgsHash
|
13
|
-
|
14
|
+
attr_accessor :foo, :bar, :baz, :qux
|
14
15
|
|
15
16
|
def initialize(args)
|
16
17
|
@foo = args[:foo]
|
@@ -18,39 +19,48 @@ class ClassWithArgsHash
|
|
18
19
|
@baz = args[:baz]
|
19
20
|
@qux = args[:qux]
|
20
21
|
end
|
21
|
-
end
|
22
22
|
|
23
|
+
def to_h
|
24
|
+
{
|
25
|
+
:foo => foo,
|
26
|
+
:bar => bar,
|
27
|
+
:baz => baz,
|
28
|
+
:qux => qux
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
23
32
|
```
|
24
33
|
|
25
|
-
And this is the
|
34
|
+
And this is the **hstruct** equivalent:
|
26
35
|
|
27
36
|
```ruby
|
28
37
|
MyHStruct = HStruct.new(:foo, :bar, :baz, :qux)
|
29
38
|
```
|
30
39
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
## Installation
|
36
|
-
|
37
|
-
Add this line to your application's Gemfile:
|
38
|
-
|
39
|
-
gem 'hstruct'
|
40
|
-
|
41
|
-
And then execute:
|
42
|
-
|
43
|
-
$ bundle
|
44
|
-
|
45
|
-
Or install it yourself as:
|
40
|
+
The only gem faster than **hstruct** is
|
41
|
+
[attr_extras](https://github.com/barsoom/attr_extras). Even though
|
42
|
+
attr_extras is 30% quicker, it requires more setup code:
|
46
43
|
|
47
|
-
|
44
|
+
```ruby
|
45
|
+
class AttrExtrasClass
|
46
|
+
attr_initialize [:foo, :bar, :baz, :qux]
|
47
|
+
attr_accessor :foo, :bar, :baz, :qux
|
48
|
+
|
49
|
+
def to_h
|
50
|
+
{
|
51
|
+
:foo => foo,
|
52
|
+
:bar => bar,
|
53
|
+
:baz => baz,
|
54
|
+
:qux => qux
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
```
|
48
59
|
|
49
60
|
## Usage
|
50
61
|
|
51
|
-
This is a
|
52
|
-
|
53
|
-
default value:
|
62
|
+
This is a super simple and straightforward gem. Here's a usage example
|
63
|
+
with a default value:
|
54
64
|
|
55
65
|
```ruby
|
56
66
|
HeartRate = HStruct.new(:patient_id, :bpm, :timestamp) do
|
@@ -74,6 +84,41 @@ end
|
|
74
84
|
=> {:patient_id=>1, :bpm=>88, :timestamp=>1368786389}
|
75
85
|
```
|
76
86
|
|
87
|
+
## Benchmarks
|
88
|
+
|
89
|
+
There is a complete suite of benchmarks against the normal plain object
|
90
|
+
approach and the more popular gems. Run specific benchmarks eg `ruby
|
91
|
+
hstruct.rb`, or run them all: `ruby all.rb`
|
92
|
+
|
93
|
+
Benchmarks running on **Intel i7 2.2Ghz (MBP 8,2)** and **ruby 2.0.0p247
|
94
|
+
(2013-06-27 revision 41674) [x86_64-darwin12.4.0]**:
|
95
|
+
|
96
|
+
```
|
97
|
+
ClassHashArgs 238075.1 (±9.4%) i/s - 237690 in 1.006158s
|
98
|
+
ClassHashArgsFetch 223183.1 (±8.7%) i/s - 235035 in 1.060172s
|
99
|
+
AttrExtrasClass 117151.4 (±3.1%) i/s - 124553 in 1.064184s
|
100
|
+
ClassArgsSend 105091.4 (±4.2%) i/s - 107544 in 1.025204s
|
101
|
+
PlainHStruct 83266.2 (±2.2%) i/s - 86724 in 1.042059s
|
102
|
+
HashMissing 71163.5 (±3.7%) i/s - 76536 in 1.077050s
|
103
|
+
OpenStruct 24342.6 (±6.1%) i/s - 24310 in 1.003123s
|
104
|
+
HashieStruct 15659.2 (±3.7%) i/s - 16698 in 1.067853s
|
105
|
+
VirtusStruct 6853.9 (±2.5%) i/s - 7359 in 1.074312s
|
106
|
+
```
|
107
|
+
|
108
|
+
## Installation
|
109
|
+
|
110
|
+
Add this line to your application's Gemfile:
|
111
|
+
|
112
|
+
gem 'hstruct'
|
113
|
+
|
114
|
+
And then execute:
|
115
|
+
|
116
|
+
$ bundle
|
117
|
+
|
118
|
+
Or install it yourself as:
|
119
|
+
|
120
|
+
$ gem install hstruct
|
121
|
+
|
77
122
|
## Contributing
|
78
123
|
|
79
124
|
1. Fork it
|
data/benchmarks/all.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'class_hash_args'
|
2
|
+
require_relative 'class_hash_args_fetch'
|
3
|
+
require_relative 'attr_extras'
|
4
|
+
require_relative 'class_args_send'
|
5
|
+
require_relative 'hstruct'
|
6
|
+
require_relative 'hash_missing'
|
7
|
+
require_relative 'open_struct'
|
8
|
+
require_relative 'hashie'
|
9
|
+
require_relative 'virtus'
|
10
|
+
|
11
|
+
# All benchmarks were run on:
|
12
|
+
# * ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.4.0]
|
13
|
+
# * Intel i7 2.2Ghz (MBP 8,2)
|
14
|
+
#
|
15
|
+
# ClassHashArgs 238075.1 (±9.4%) i/s - 237690 in 1.006158s
|
16
|
+
# ClassHashArgsFetch 223183.1 (±8.7%) i/s - 235035 in 1.060172s
|
17
|
+
# AttrExtrasClass 117151.4 (±3.1%) i/s - 124553 in 1.064184s
|
18
|
+
# ClassArgsSend 105091.4 (±4.2%) i/s - 107544 in 1.025204s
|
19
|
+
# PlainHStruct 83266.2 (±2.2%) i/s - 86724 in 1.042059s
|
20
|
+
# HashMissing 71163.5 (±3.7%) i/s - 76536 in 1.077050s
|
21
|
+
# OpenStruct 24342.6 (±6.1%) i/s - 24310 in 1.003123s
|
22
|
+
# HashieStruct 15659.2 (±3.7%) i/s - 16698 in 1.067853s
|
23
|
+
# VirtusStruct 6853.9 (±2.5%) i/s - 7359 in 1.074312s
|
@@ -0,0 +1,23 @@
|
|
1
|
+
begin
|
2
|
+
require 'attr_extras'
|
3
|
+
class AttrExtrasClass
|
4
|
+
attr_initialize [:foo, :bar, :baz, :qux]
|
5
|
+
attr_accessor :foo, :bar, :baz, :qux
|
6
|
+
|
7
|
+
def to_h
|
8
|
+
{
|
9
|
+
:foo => foo,
|
10
|
+
:bar => bar,
|
11
|
+
:baz => baz,
|
12
|
+
:qux => qux
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require_relative 'benchmark'
|
18
|
+
benchmark.call(
|
19
|
+
AttrExtrasClass.method(:new)
|
20
|
+
)
|
21
|
+
rescue LoadError
|
22
|
+
puts "attr_extras gem not installed, cannot run benchmark"
|
23
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'benchmark/ips'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
ImplementationError = Class.new(StandardError)
|
5
|
+
|
6
|
+
def benchmark
|
7
|
+
->(object_builder) {
|
8
|
+
Benchmark.ips(ENV.fetch('RUNS', 1).to_i) do |x|
|
9
|
+
hash = {
|
10
|
+
:foo => 1,
|
11
|
+
:bar => 2,
|
12
|
+
:baz => 3,
|
13
|
+
:qux => 4,
|
14
|
+
}
|
15
|
+
|
16
|
+
hash2 = {
|
17
|
+
:foo => "foo",
|
18
|
+
:bar => "bar",
|
19
|
+
:baz => "baz",
|
20
|
+
:qux => "qux",
|
21
|
+
}
|
22
|
+
|
23
|
+
x.report(object_builder.call(hash).class.name) {
|
24
|
+
o = object_builder.call(hash)
|
25
|
+
o.foo == hash[:foo] || raise(ImplementationError, "#foo")
|
26
|
+
o.bar == hash[:bar] || raise(ImplementationError, "#bar")
|
27
|
+
o.baz == hash[:baz] || raise(ImplementationError, "#baz")
|
28
|
+
o.qux == hash[:qux] || raise(ImplementationError, "#qux")
|
29
|
+
o.to_h == hash || raise(ImplementationError, "#to_h")
|
30
|
+
|
31
|
+
o.foo = hash2[:foo]
|
32
|
+
o.foo == hash2[:foo] || raise(ImplementationError, "#foo=")
|
33
|
+
o.bar = hash2[:bar]
|
34
|
+
o.bar == hash2[:bar] || raise(ImplementationError, "#bar=")
|
35
|
+
o.baz = hash2[:baz]
|
36
|
+
o.baz == hash2[:baz] || raise(ImplementationError, "#baz=")
|
37
|
+
o.qux = hash2[:qux]
|
38
|
+
o.qux == hash2[:qux] || raise(ImplementationError, "#qux=")
|
39
|
+
o.to_h == hash2 || raise(ImplementationError, "#to_h")
|
40
|
+
}
|
41
|
+
end
|
42
|
+
}
|
43
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'benchmark'
|
2
|
+
|
3
|
+
class ClassArgsSend
|
4
|
+
attr_accessor :foo, :bar, :baz, :qux
|
5
|
+
|
6
|
+
def initialize(args)
|
7
|
+
@args = args
|
8
|
+
args.each { |k, v| self.send("#{k}=", v) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_h
|
12
|
+
{
|
13
|
+
:foo => foo,
|
14
|
+
:bar => bar,
|
15
|
+
:baz => baz,
|
16
|
+
:qux => qux
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
benchmark.call(
|
22
|
+
ClassArgsSend.method(:new)
|
23
|
+
)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'benchmark'
|
2
|
+
|
3
|
+
class ClassHashArgs
|
4
|
+
attr_accessor :foo, :bar, :baz, :qux
|
5
|
+
|
6
|
+
def initialize(args)
|
7
|
+
self.foo = args[:foo]
|
8
|
+
self.bar = args[:bar]
|
9
|
+
self.baz = args[:baz]
|
10
|
+
self.qux = args[:qux]
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
{
|
15
|
+
:foo => foo,
|
16
|
+
:bar => bar,
|
17
|
+
:baz => baz,
|
18
|
+
:qux => qux
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
benchmark.call(
|
24
|
+
ClassHashArgs.method(:new)
|
25
|
+
)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative 'benchmark'
|
2
|
+
|
3
|
+
class ClassHashArgsFetch
|
4
|
+
attr_accessor :foo, :bar, :baz, :qux
|
5
|
+
|
6
|
+
def initialize(args)
|
7
|
+
self.foo = args.fetch(:foo)
|
8
|
+
self.bar = args.fetch(:bar)
|
9
|
+
self.baz = args.fetch(:baz)
|
10
|
+
self.qux = args.fetch(:qux)
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_h
|
14
|
+
{
|
15
|
+
:foo => foo,
|
16
|
+
:bar => bar,
|
17
|
+
:baz => baz,
|
18
|
+
:qux => qux
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
benchmark.call(
|
24
|
+
ClassHashArgsFetch.method(:new)
|
25
|
+
)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'benchmark'
|
2
|
+
|
3
|
+
class HashMissing < Hash
|
4
|
+
def method_missing(method, *value)
|
5
|
+
if value.any?
|
6
|
+
self[method[0..-2].to_sym] = value.first
|
7
|
+
else
|
8
|
+
self[method] || super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
benchmark.call(
|
14
|
+
HashMissing.method(:[])
|
15
|
+
)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
begin
|
2
|
+
require 'hashie'
|
3
|
+
class HashieStruct < Hashie::Dash
|
4
|
+
property :foo
|
5
|
+
property :bar
|
6
|
+
property :baz
|
7
|
+
property :qux
|
8
|
+
|
9
|
+
def to_h
|
10
|
+
to_hash(:symbolize_keys => true)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
require_relative 'benchmark'
|
15
|
+
benchmark.call(
|
16
|
+
HashieStruct.method(:new)
|
17
|
+
)
|
18
|
+
rescue LoadError
|
19
|
+
puts "hashie gem not installed, cannot run benchmark"
|
20
|
+
end
|
data/benchmarks/hstruct.rb
CHANGED
@@ -1,119 +1,7 @@
|
|
1
|
-
require 'benchmark/ips'
|
2
|
-
require 'pry'
|
3
|
-
|
4
|
-
# OpenStruct
|
5
|
-
require 'ostruct'
|
6
|
-
|
7
|
-
# Struct
|
8
|
-
PlainStruct = Struct.new(:foo, :bar, :baz, :qux)
|
9
|
-
|
10
|
-
# HStruct
|
11
1
|
require_relative '../lib/hstruct'
|
12
2
|
PlainHStruct = HStruct.new(:foo, :bar, :baz, :qux)
|
13
3
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def initialize(foo, bar, baz, qux)
|
19
|
-
@foo = foo
|
20
|
-
@bar = bar
|
21
|
-
@baz = baz
|
22
|
-
@qux = qux
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class CleverClass
|
27
|
-
attr_reader :foo, :bar, :baz, :qux
|
28
|
-
|
29
|
-
def initialize(args)
|
30
|
-
args.each { |k, v| instance_variable_set("@#{k}", v) }
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class HashArgsClass
|
35
|
-
attr_reader :foo, :bar, :baz, :qux
|
36
|
-
|
37
|
-
def initialize(args)
|
38
|
-
@foo = args[:foo]
|
39
|
-
@bar = args[:bar]
|
40
|
-
@baz = args[:baz]
|
41
|
-
@qux = args[:qux]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
hash = {
|
46
|
-
:foo => 1,
|
47
|
-
:bar => 2,
|
48
|
-
:baz => 3,
|
49
|
-
:qux => 4,
|
50
|
-
}
|
51
|
-
|
52
|
-
#require 'attr_extras'
|
53
|
-
#class AttrExtrasClass
|
54
|
-
#attr_initialize [:foo, :bar, :baz, :qux]
|
55
|
-
#attr_reader :foo, :bar, :baz, :qux
|
56
|
-
#end
|
57
|
-
|
58
|
-
# All benchmarks were run on:
|
59
|
-
# * ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-darwin12.3.0]
|
60
|
-
# * Intel i7 2.2Ghz (MBP 8,2)
|
61
|
-
|
62
|
-
runs = ENV.fetch('RUNS', 5).to_i
|
63
|
-
|
64
|
-
Benchmark.ips(runs) do |x|
|
65
|
-
# 14k/s
|
66
|
-
x.report('OpenStruct') do
|
67
|
-
OpenStruct.new(hash)
|
68
|
-
end
|
69
|
-
|
70
|
-
# 80k/s
|
71
|
-
x.report('Class Clever') do
|
72
|
-
CleverClass.new(hash)
|
73
|
-
end
|
74
|
-
|
75
|
-
# 185k/s
|
76
|
-
x.report('HStruct') do
|
77
|
-
PlainHStruct.new(hash)
|
78
|
-
end
|
79
|
-
|
80
|
-
# 380k/s
|
81
|
-
x.report('Hash') do
|
82
|
-
hash = {
|
83
|
-
:foo => 1,
|
84
|
-
:bar => 2,
|
85
|
-
:baz => 3,
|
86
|
-
:qux => 4,
|
87
|
-
}
|
88
|
-
end
|
89
|
-
|
90
|
-
# 200k/s
|
91
|
-
#x.report('Class AttrExtras') do
|
92
|
-
#AttrExtrasClass.new(hash)
|
93
|
-
#end
|
94
|
-
|
95
|
-
# 385k/s
|
96
|
-
x.report('Class Hash Args') do
|
97
|
-
HashArgsClass.new(hash)
|
98
|
-
end
|
99
|
-
|
100
|
-
# 470k/s
|
101
|
-
x.report('Class Plain') do
|
102
|
-
SimpleClass.new(1, 2, 3, 4)
|
103
|
-
end
|
104
|
-
|
105
|
-
# 620k/s
|
106
|
-
x.report('Struct') do
|
107
|
-
PlainStruct.new(1, 2, 3, 4)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
### This is how some of the more popular gems compare to the above:
|
112
|
-
#
|
113
|
-
# Virtus => 12k/s (no coercions) & 17k/s (coercions)
|
114
|
-
# Hashr => 20k/s
|
115
|
-
# FastOpenStruct => 30k/s
|
116
|
-
# Hashie::Dash => 35k/s
|
117
|
-
# Hashie MI & MA => 100k/s
|
118
|
-
# AttrExtras => 200k/s
|
119
|
-
#
|
4
|
+
require_relative 'benchmark'
|
5
|
+
benchmark.call(
|
6
|
+
PlainHStruct.method(:new)
|
7
|
+
)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
begin
|
2
|
+
require 'virtus'
|
3
|
+
class VirtusStruct
|
4
|
+
include Virtus
|
5
|
+
|
6
|
+
attribute :foo
|
7
|
+
attribute :bar
|
8
|
+
attribute :baz
|
9
|
+
attribute :qux
|
10
|
+
|
11
|
+
alias_method :to_h, :attributes
|
12
|
+
end
|
13
|
+
|
14
|
+
require_relative 'benchmark'
|
15
|
+
benchmark.call(
|
16
|
+
VirtusStruct.method(:new)
|
17
|
+
)
|
18
|
+
rescue LoadError
|
19
|
+
puts "virtus gem not installed, cannot run benchmark"
|
20
|
+
end
|
data/hstruct.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "hstruct"
|
7
|
-
spec.version = "0.
|
7
|
+
spec.version = "0.7.0"
|
8
8
|
spec.authors = ["Gerhard Lazu", "Stephen Best"]
|
9
9
|
spec.email = ["gerhard@lazu.co.uk", "bestie@gmail.com"]
|
10
10
|
spec.description = %q{Struct with the convenience of instantiating from a Hash}
|
data/lib/hstruct.rb
CHANGED
@@ -1,16 +1,27 @@
|
|
1
1
|
class HStruct < Struct
|
2
2
|
def initialize(args = {})
|
3
|
-
|
3
|
+
ensure_enumerable(args)
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
result[k.to_sym] = v
|
8
|
-
end
|
5
|
+
args = args.each_with_object({}) do |(k,v), result|
|
6
|
+
result[k.to_sym] = v
|
9
7
|
end
|
10
8
|
|
11
9
|
super(*members.map { |m| args[m] })
|
12
10
|
end
|
13
11
|
|
12
|
+
def update(args={})
|
13
|
+
ensure_enumerable(args)
|
14
|
+
|
15
|
+
args.each do |(k,v)|
|
16
|
+
self[k.to_sym] = v
|
17
|
+
end
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def ensure_enumerable(args)
|
22
|
+
raise ArgumentError unless args.is_a?(Enumerable)
|
23
|
+
end
|
24
|
+
|
14
25
|
def to_h
|
15
26
|
Hash[each_pair.to_a]
|
16
27
|
end
|
data/test/lib/hstruct_test.rb
CHANGED
@@ -61,5 +61,56 @@ describe "Person defined from an HStruct" do
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
64
|
+
|
65
|
+
describe "updated from a hash" do
|
66
|
+
describe "with Symbol keys" do
|
67
|
+
let(:person_hash) { {
|
68
|
+
:first_name => "Jimmy",
|
69
|
+
} }
|
70
|
+
let(:updated_person_hash) { {
|
71
|
+
:first_name => "Laura",
|
72
|
+
} }
|
73
|
+
|
74
|
+
let(:person) { Person.new(person_hash) }
|
75
|
+
let(:updated_person) { person.update(updated_person_hash) }
|
76
|
+
|
77
|
+
it "first name" do
|
78
|
+
updated_person.first_name.must_equal "Laura"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "last name" do
|
82
|
+
updated_person.last_name.must_equal nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "with String keys" do
|
87
|
+
let(:person_hash) { {
|
88
|
+
"first_name" => "Alex",
|
89
|
+
} }
|
90
|
+
let(:updated_person_hash) { {
|
91
|
+
"first_name" => "Elise",
|
92
|
+
} }
|
93
|
+
|
94
|
+
let(:person) { Person.new(person_hash) }
|
95
|
+
let(:updated_person) { person.update(updated_person_hash) }
|
96
|
+
|
97
|
+
it "first name" do
|
98
|
+
updated_person.first_name.must_equal "Elise"
|
99
|
+
end
|
100
|
+
|
101
|
+
it "last name" do
|
102
|
+
updated_person.last_name.must_equal nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "when converting back to a hash" do
|
107
|
+
let(:person) { Person.new( :first_name => "Jimmy" ) }
|
108
|
+
let(:updated_person) { person.update( :first_name => "Laura" ) }
|
109
|
+
|
110
|
+
it "includes empty values" do
|
111
|
+
updated_person.to_h.must_equal Hash[:first_name => "Laura", :last_name => nil]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
64
115
|
end
|
65
116
|
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hstruct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.7.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Gerhard Lazu
|
@@ -10,12 +9,11 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date: 2013-
|
12
|
+
date: 2013-11-08 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: benchmark-ips
|
17
16
|
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
17
|
requirements:
|
20
18
|
- - ~>
|
21
19
|
- !ruby/object:Gem::Version
|
@@ -23,7 +21,6 @@ dependencies:
|
|
23
21
|
type: :development
|
24
22
|
prerelease: false
|
25
23
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
24
|
requirements:
|
28
25
|
- - ~>
|
29
26
|
- !ruby/object:Gem::Version
|
@@ -31,7 +28,6 @@ dependencies:
|
|
31
28
|
- !ruby/object:Gem::Dependency
|
32
29
|
name: bundler
|
33
30
|
requirement: !ruby/object:Gem::Requirement
|
34
|
-
none: false
|
35
31
|
requirements:
|
36
32
|
- - ~>
|
37
33
|
- !ruby/object:Gem::Version
|
@@ -39,7 +35,6 @@ dependencies:
|
|
39
35
|
type: :development
|
40
36
|
prerelease: false
|
41
37
|
version_requirements: !ruby/object:Gem::Requirement
|
42
|
-
none: false
|
43
38
|
requirements:
|
44
39
|
- - ~>
|
45
40
|
- !ruby/object:Gem::Version
|
@@ -47,7 +42,6 @@ dependencies:
|
|
47
42
|
- !ruby/object:Gem::Dependency
|
48
43
|
name: minitest
|
49
44
|
requirement: !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
45
|
requirements:
|
52
46
|
- - ~>
|
53
47
|
- !ruby/object:Gem::Version
|
@@ -55,7 +49,6 @@ dependencies:
|
|
55
49
|
type: :development
|
56
50
|
prerelease: false
|
57
51
|
version_requirements: !ruby/object:Gem::Requirement
|
58
|
-
none: false
|
59
52
|
requirements:
|
60
53
|
- - ~>
|
61
54
|
- !ruby/object:Gem::Version
|
@@ -63,7 +56,6 @@ dependencies:
|
|
63
56
|
- !ruby/object:Gem::Dependency
|
64
57
|
name: minitest-reporters
|
65
58
|
requirement: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
59
|
requirements:
|
68
60
|
- - ~>
|
69
61
|
- !ruby/object:Gem::Version
|
@@ -71,7 +63,6 @@ dependencies:
|
|
71
63
|
type: :development
|
72
64
|
prerelease: false
|
73
65
|
version_requirements: !ruby/object:Gem::Requirement
|
74
|
-
none: false
|
75
66
|
requirements:
|
76
67
|
- - ~>
|
77
68
|
- !ruby/object:Gem::Version
|
@@ -79,7 +70,6 @@ dependencies:
|
|
79
70
|
- !ruby/object:Gem::Dependency
|
80
71
|
name: pry
|
81
72
|
requirement: !ruby/object:Gem::Requirement
|
82
|
-
none: false
|
83
73
|
requirements:
|
84
74
|
- - ! '>='
|
85
75
|
- !ruby/object:Gem::Version
|
@@ -87,7 +77,6 @@ dependencies:
|
|
87
77
|
type: :development
|
88
78
|
prerelease: false
|
89
79
|
version_requirements: !ruby/object:Gem::Requirement
|
90
|
-
none: false
|
91
80
|
requirements:
|
92
81
|
- - ! '>='
|
93
82
|
- !ruby/object:Gem::Version
|
@@ -95,7 +84,6 @@ dependencies:
|
|
95
84
|
- !ruby/object:Gem::Dependency
|
96
85
|
name: rake
|
97
86
|
requirement: !ruby/object:Gem::Requirement
|
98
|
-
none: false
|
99
87
|
requirements:
|
100
88
|
- - ~>
|
101
89
|
- !ruby/object:Gem::Version
|
@@ -103,7 +91,6 @@ dependencies:
|
|
103
91
|
type: :development
|
104
92
|
prerelease: false
|
105
93
|
version_requirements: !ruby/object:Gem::Requirement
|
106
|
-
none: false
|
107
94
|
requirements:
|
108
95
|
- - ~>
|
109
96
|
- !ruby/object:Gem::Version
|
@@ -117,13 +104,24 @@ extensions: []
|
|
117
104
|
extra_rdoc_files: []
|
118
105
|
files:
|
119
106
|
- .gitignore
|
107
|
+
- .ruby-version
|
120
108
|
- .travis.yml
|
121
109
|
- CHANGELOG.md
|
122
110
|
- Gemfile
|
123
111
|
- LICENSE.txt
|
124
112
|
- README.md
|
125
113
|
- Rakefile
|
114
|
+
- benchmarks/all.rb
|
115
|
+
- benchmarks/attr_extras.rb
|
116
|
+
- benchmarks/benchmark.rb
|
117
|
+
- benchmarks/class_args_send.rb
|
118
|
+
- benchmarks/class_hash_args.rb
|
119
|
+
- benchmarks/class_hash_args_fetch.rb
|
120
|
+
- benchmarks/hash_missing.rb
|
121
|
+
- benchmarks/hashie.rb
|
126
122
|
- benchmarks/hstruct.rb
|
123
|
+
- benchmarks/open_struct.rb
|
124
|
+
- benchmarks/virtus.rb
|
127
125
|
- hstruct.gemspec
|
128
126
|
- lib/hstruct.rb
|
129
127
|
- test/lib/hstruct_test.rb
|
@@ -131,27 +129,26 @@ files:
|
|
131
129
|
homepage: https://github.com/cambridge-healthcare/hstruct
|
132
130
|
licenses:
|
133
131
|
- MIT
|
132
|
+
metadata: {}
|
134
133
|
post_install_message:
|
135
134
|
rdoc_options: []
|
136
135
|
require_paths:
|
137
136
|
- lib
|
138
137
|
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
-
none: false
|
140
138
|
requirements:
|
141
139
|
- - ! '>='
|
142
140
|
- !ruby/object:Gem::Version
|
143
141
|
version: '0'
|
144
142
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
143
|
requirements:
|
147
144
|
- - ! '>='
|
148
145
|
- !ruby/object:Gem::Version
|
149
146
|
version: '0'
|
150
147
|
requirements: []
|
151
148
|
rubyforge_project:
|
152
|
-
rubygems_version: 1.
|
149
|
+
rubygems_version: 2.1.5
|
153
150
|
signing_key:
|
154
|
-
specification_version:
|
151
|
+
specification_version: 4
|
155
152
|
summary: When you care about speed and convenience, this is what you've been looking
|
156
153
|
for
|
157
154
|
test_files:
|