hstruct 0.6.0 → 0.7.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 +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
|
[](https://travis-ci.org/cambridge-healthcare/hstruct)
|
2
|
+
[](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:
|