dynamic_class 0.1.0 → 0.2.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/README.md +63 -64
- data/lib/dynamic_class.rb +38 -39
- data/lib/dynamic_class/version.rb +1 -1
- metadata +19 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9b151ef4fe4e1436998fe710a7398d0f4260f17c
|
|
4
|
+
data.tar.gz: 7814c667c0cb6bfb2495e65a216198de3b23338a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0f2bf53ba80db5106d3b26b498cc694e72b81adb5a4bafeb6dc0597f6b65f503c0fdcd55c85a3068645058a86abdd4d245381bf375e2c0a1f460d6ed70cb8ff7
|
|
7
|
+
data.tar.gz: 0f2a16f2112a9cccd930ad8bb49ce34f0a4ea99866c0edeb11efd12c14e3c65c049a6fb08a24288490123a344aa93063686fcd26b3ac20b2a34d4320477b64d9
|
data/README.md
CHANGED
|
@@ -36,107 +36,106 @@ the cost of setting a property drops.
|
|
|
36
36
|
|
|
37
37
|
The results are pretty astounding. Here are the results of the benchmark in
|
|
38
38
|
`bin/benchmark.rb` (including a few other `OpenStruct`-like solutions for
|
|
39
|
-
comparison):
|
|
39
|
+
comparison), run on Ruby 2.2.4:
|
|
40
40
|
|
|
41
41
|
```
|
|
42
42
|
Initialization benchmark
|
|
43
43
|
|
|
44
44
|
Calculating -------------------------------------
|
|
45
|
-
OpenStruct
|
|
46
|
-
PersistentOpenStruct
|
|
47
|
-
OpenFastStruct
|
|
48
|
-
DynamicClass
|
|
49
|
-
RegularClass
|
|
45
|
+
OpenStruct 14.668k i/100ms
|
|
46
|
+
PersistentOpenStruct 50.880k i/100ms
|
|
47
|
+
OpenFastStruct 49.682k i/100ms
|
|
48
|
+
DynamicClass 60.946k i/100ms
|
|
49
|
+
RegularClass 107.521k i/100ms
|
|
50
50
|
-------------------------------------------------
|
|
51
|
-
OpenStruct
|
|
52
|
-
PersistentOpenStruct
|
|
53
|
-
OpenFastStruct
|
|
54
|
-
DynamicClass
|
|
55
|
-
RegularClass 3.
|
|
51
|
+
OpenStruct 165.010k (± 6.0%) i/s - 836.076k
|
|
52
|
+
PersistentOpenStruct 793.144k (± 5.4%) i/s - 3.969M
|
|
53
|
+
OpenFastStruct 850.827k (± 5.0%) i/s - 4.273M
|
|
54
|
+
DynamicClass 1.026M (± 4.0%) i/s - 5.180M
|
|
55
|
+
RegularClass 3.451M (± 3.7%) i/s - 17.311M
|
|
56
56
|
|
|
57
57
|
Comparison:
|
|
58
|
-
RegularClass:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
PersistentOpenStruct:
|
|
62
|
-
OpenStruct:
|
|
58
|
+
RegularClass: 3451422.2 i/s
|
|
59
|
+
DynamicClass: 1026234.0 i/s - 3.36x slower
|
|
60
|
+
OpenFastStruct: 850827.2 i/s - 4.06x slower
|
|
61
|
+
PersistentOpenStruct: 793144.4 i/s - 4.35x slower
|
|
62
|
+
OpenStruct: 165009.7 i/s - 20.92x slower
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
Assignment Benchmark
|
|
67
67
|
|
|
68
68
|
Calculating -------------------------------------
|
|
69
|
-
OpenStruct
|
|
70
|
-
PersistentOpenStruct
|
|
71
|
-
OpenFastStruct
|
|
72
|
-
DynamicClass
|
|
73
|
-
RegularClass
|
|
69
|
+
OpenStruct 112.139k i/100ms
|
|
70
|
+
PersistentOpenStruct 113.798k i/100ms
|
|
71
|
+
OpenFastStruct 62.780k i/100ms
|
|
72
|
+
DynamicClass 140.472k i/100ms
|
|
73
|
+
RegularClass 141.757k i/100ms
|
|
74
74
|
-------------------------------------------------
|
|
75
|
-
OpenStruct 3.
|
|
76
|
-
PersistentOpenStruct 3.
|
|
77
|
-
OpenFastStruct
|
|
78
|
-
DynamicClass
|
|
79
|
-
RegularClass
|
|
75
|
+
OpenStruct 3.773M (± 5.8%) i/s - 18.839M
|
|
76
|
+
PersistentOpenStruct 3.737M (± 6.8%) i/s - 18.663M
|
|
77
|
+
OpenFastStruct 1.086M (± 4.8%) i/s - 5.462M
|
|
78
|
+
DynamicClass 9.237M (± 5.8%) i/s - 46.075M
|
|
79
|
+
RegularClass 9.017M (± 7.6%) i/s - 44.795M
|
|
80
80
|
|
|
81
81
|
Comparison:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
OpenStruct:
|
|
85
|
-
PersistentOpenStruct:
|
|
86
|
-
OpenFastStruct:
|
|
82
|
+
DynamicClass: 9236626.8 i/s
|
|
83
|
+
RegularClass: 9017300.5 i/s - 1.02x slower
|
|
84
|
+
OpenStruct: 3773095.2 i/s - 2.45x slower
|
|
85
|
+
PersistentOpenStruct: 3737490.7 i/s - 2.47x slower
|
|
86
|
+
OpenFastStruct: 1085576.3 i/s - 8.51x slower
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
|
|
90
90
|
Access Benchmark
|
|
91
91
|
|
|
92
92
|
Calculating -------------------------------------
|
|
93
|
-
OpenStruct
|
|
94
|
-
PersistentOpenStruct
|
|
95
|
-
OpenFastStruct
|
|
96
|
-
DynamicClass
|
|
97
|
-
RegularClass
|
|
93
|
+
OpenStruct 126.018k i/100ms
|
|
94
|
+
PersistentOpenStruct 123.179k i/100ms
|
|
95
|
+
OpenFastStruct 113.118k i/100ms
|
|
96
|
+
DynamicClass 139.960k i/100ms
|
|
97
|
+
RegularClass 142.888k i/100ms
|
|
98
98
|
-------------------------------------------------
|
|
99
|
-
OpenStruct 5.
|
|
100
|
-
PersistentOpenStruct 5.
|
|
101
|
-
OpenFastStruct
|
|
102
|
-
DynamicClass 9.
|
|
103
|
-
RegularClass 9.
|
|
99
|
+
OpenStruct 5.409M (± 5.3%) i/s - 26.968M
|
|
100
|
+
PersistentOpenStruct 5.341M (± 6.3%) i/s - 26.607M
|
|
101
|
+
OpenFastStruct 4.094M (± 5.5%) i/s - 20.474M
|
|
102
|
+
DynamicClass 9.623M (± 6.1%) i/s - 48.006M
|
|
103
|
+
RegularClass 9.655M (± 5.9%) i/s - 48.153M
|
|
104
104
|
|
|
105
105
|
Comparison:
|
|
106
|
-
RegularClass:
|
|
107
|
-
DynamicClass:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
OpenFastStruct:
|
|
106
|
+
RegularClass: 9655298.6 i/s
|
|
107
|
+
DynamicClass: 9623042.4 i/s - 1.00x slower
|
|
108
|
+
OpenStruct: 5409401.0 i/s - 1.78x slower
|
|
109
|
+
PersistentOpenStruct: 5341124.3 i/s - 1.81x slower
|
|
110
|
+
OpenFastStruct: 4094344.3 i/s - 2.36x slower
|
|
111
111
|
|
|
112
112
|
|
|
113
113
|
|
|
114
114
|
All-Together Benchmark
|
|
115
115
|
|
|
116
116
|
Calculating -------------------------------------
|
|
117
|
-
OpenStruct
|
|
118
|
-
PersistentOpenStruct
|
|
119
|
-
OpenFastStruct
|
|
120
|
-
DynamicClass
|
|
121
|
-
RegularClass
|
|
117
|
+
OpenStruct 14.450k i/100ms
|
|
118
|
+
PersistentOpenStruct 46.072k i/100ms
|
|
119
|
+
OpenFastStruct 34.287k i/100ms
|
|
120
|
+
DynamicClass 58.110k i/100ms
|
|
121
|
+
RegularClass 107.647k i/100ms
|
|
122
122
|
-------------------------------------------------
|
|
123
|
-
OpenStruct
|
|
124
|
-
PersistentOpenStruct
|
|
125
|
-
OpenFastStruct
|
|
126
|
-
DynamicClass
|
|
127
|
-
RegularClass 3.
|
|
123
|
+
OpenStruct 161.775k (± 5.7%) i/s - 809.200k
|
|
124
|
+
PersistentOpenStruct 625.010k (± 5.7%) i/s - 3.133M
|
|
125
|
+
OpenFastStruct 446.903k (± 4.8%) i/s - 2.263M
|
|
126
|
+
DynamicClass 995.236k (± 5.0%) i/s - 4.997M
|
|
127
|
+
RegularClass 3.102M (± 5.7%) i/s - 15.501M
|
|
128
128
|
|
|
129
129
|
Comparison:
|
|
130
|
-
RegularClass:
|
|
131
|
-
DynamicClass:
|
|
132
|
-
PersistentOpenStruct:
|
|
133
|
-
OpenFastStruct:
|
|
134
|
-
OpenStruct:
|
|
130
|
+
RegularClass: 3102088.4 i/s
|
|
131
|
+
DynamicClass: 995235.5 i/s - 3.12x slower
|
|
132
|
+
PersistentOpenStruct: 625010.1 i/s - 4.96x slower
|
|
133
|
+
OpenFastStruct: 446902.6 i/s - 6.94x slower
|
|
134
|
+
OpenStruct: 161775.4 i/s - 19.18x slower
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
`DynamicClass` is still behind plain old Ruby classes, but it's the best
|
|
138
|
-
|
|
139
|
-
friends.
|
|
137
|
+
`DynamicClass` is still behind plain old Ruby classes, but it's the best out of
|
|
138
|
+
the pack when it comes to `OpenStruct` and friends.
|
|
140
139
|
|
|
141
140
|
## Installation
|
|
142
141
|
|
data/lib/dynamic_class.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require
|
|
1
|
+
require 'dynamic_class/version'
|
|
2
2
|
require 'set'
|
|
3
3
|
|
|
4
4
|
module DynamicClass
|
|
@@ -19,34 +19,58 @@ module DynamicClass
|
|
|
19
19
|
def inherited(subclass)
|
|
20
20
|
subclass.class_eval <<-RUBY
|
|
21
21
|
def to_h
|
|
22
|
-
{}
|
|
23
|
-
each_pair do |key, value|
|
|
24
|
-
hash[key] = value
|
|
25
|
-
end
|
|
26
|
-
end
|
|
22
|
+
{}
|
|
27
23
|
end
|
|
28
24
|
RUBY
|
|
29
25
|
end
|
|
26
|
+
|
|
27
|
+
def mutex
|
|
28
|
+
@mutex ||= Mutex.new
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def add_methods!(key)
|
|
32
|
+
class_exec do
|
|
33
|
+
mutex.synchronize do
|
|
34
|
+
attr_accessor key
|
|
35
|
+
attributes << key
|
|
36
|
+
|
|
37
|
+
# I'm pretty sure this is safe, because attempting to add an attribute
|
|
38
|
+
# that isn't a valid instance variable name will raise an error. Please
|
|
39
|
+
# contact the maintainer if you find a situation where this could be a
|
|
40
|
+
# security problem.
|
|
41
|
+
#
|
|
42
|
+
# The reason to use class_eval here is because, based on benchmarking,
|
|
43
|
+
# this defines the fastest version of #to_h possible.
|
|
44
|
+
class_eval <<-RUBY
|
|
45
|
+
def to_h
|
|
46
|
+
{
|
|
47
|
+
#{
|
|
48
|
+
attributes.map { |attribute|
|
|
49
|
+
"#{attribute.inspect} => #{attribute}"
|
|
50
|
+
}.join(",\n")
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
end
|
|
54
|
+
RUBY
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
30
58
|
end
|
|
31
59
|
|
|
32
60
|
def initialize(attributes = {})
|
|
33
61
|
attributes.each_pair do |key, value|
|
|
34
|
-
send(:
|
|
62
|
+
send(:"#{key}=", value)
|
|
35
63
|
end
|
|
36
64
|
end
|
|
37
65
|
|
|
38
66
|
def to_h
|
|
39
|
-
{}
|
|
40
|
-
each_pair do |key, value|
|
|
41
|
-
hash[key] = value
|
|
42
|
-
end
|
|
43
|
-
end
|
|
67
|
+
{}
|
|
44
68
|
end
|
|
45
69
|
|
|
46
70
|
def []=(key, value)
|
|
47
71
|
key = key.to_sym
|
|
48
72
|
instance_variable_set(:"@#{key}", value)
|
|
49
|
-
add_methods!(key) unless self.class.attributes.include?(key)
|
|
73
|
+
self.class.add_methods!(key) unless self.class.attributes.include?(key)
|
|
50
74
|
end
|
|
51
75
|
|
|
52
76
|
def [](key)
|
|
@@ -75,7 +99,7 @@ module DynamicClass
|
|
|
75
99
|
end
|
|
76
100
|
|
|
77
101
|
def delete_field(key)
|
|
78
|
-
|
|
102
|
+
instance_variable_set(:"@#{key}", nil)
|
|
79
103
|
end
|
|
80
104
|
|
|
81
105
|
def ==(other)
|
|
@@ -89,30 +113,5 @@ module DynamicClass
|
|
|
89
113
|
def hash
|
|
90
114
|
to_h.hash
|
|
91
115
|
end
|
|
92
|
-
|
|
93
|
-
private
|
|
94
|
-
def add_methods!(key)
|
|
95
|
-
self.class.send(:attr_accessor, key)
|
|
96
|
-
self.class.attributes << key
|
|
97
|
-
|
|
98
|
-
# I'm pretty sure this is safe, because attempting to add an attribute
|
|
99
|
-
# that isn't a valid instance variable name will raise an error. Please
|
|
100
|
-
# contact the maintainer if you find a situation where this could be a
|
|
101
|
-
# security problem.
|
|
102
|
-
#
|
|
103
|
-
# The reason to use class_eval here is because, based on benchmarking,
|
|
104
|
-
# this defines the fastest version of #to_h possible.
|
|
105
|
-
self.class.class_eval <<-RUBY
|
|
106
|
-
def to_h
|
|
107
|
-
{
|
|
108
|
-
#{
|
|
109
|
-
self.class.attributes.map { |attribute|
|
|
110
|
-
"#{attribute.inspect} => #{attribute}"
|
|
111
|
-
}.join(",\n")
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
end
|
|
115
|
-
RUBY
|
|
116
|
-
end
|
|
117
116
|
end
|
|
118
117
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dynamic_class
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- amcaplan
|
|
@@ -14,84 +14,84 @@ dependencies:
|
|
|
14
14
|
name: bundler
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - ~>
|
|
17
|
+
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: '1.11'
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - ~>
|
|
24
|
+
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '1.11'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - ~>
|
|
31
|
+
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: '10.0'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - ~>
|
|
38
|
+
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '10.0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rspec
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - ~>
|
|
45
|
+
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
47
|
version: '3.0'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- - ~>
|
|
52
|
+
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '3.0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: ofstruct
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- - ~>
|
|
59
|
+
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
61
|
version: '0.2'
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
|
-
- - ~>
|
|
66
|
+
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0.2'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: persistent_open_struct
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
|
-
- - ~>
|
|
73
|
+
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
75
|
version: '0.0'
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
|
-
- - ~>
|
|
80
|
+
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0.0'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: benchmark-ips
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
-
- - ~>
|
|
87
|
+
- - "~>"
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
89
|
version: 2.3.0
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
|
-
- - ~>
|
|
94
|
+
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: 2.3.0
|
|
97
97
|
description: Specifically designed as an OpenStruct-like tool for consuming APIs,
|
|
@@ -103,9 +103,9 @@ executables: []
|
|
|
103
103
|
extensions: []
|
|
104
104
|
extra_rdoc_files: []
|
|
105
105
|
files:
|
|
106
|
-
- .gitignore
|
|
107
|
-
- .rspec
|
|
108
|
-
- .travis.yml
|
|
106
|
+
- ".gitignore"
|
|
107
|
+
- ".rspec"
|
|
108
|
+
- ".travis.yml"
|
|
109
109
|
- CODE_OF_CONDUCT.md
|
|
110
110
|
- Gemfile
|
|
111
111
|
- LICENSE.txt
|
|
@@ -127,17 +127,17 @@ require_paths:
|
|
|
127
127
|
- lib
|
|
128
128
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
129
129
|
requirements:
|
|
130
|
-
- -
|
|
130
|
+
- - ">="
|
|
131
131
|
- !ruby/object:Gem::Version
|
|
132
132
|
version: '0'
|
|
133
133
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
134
|
requirements:
|
|
135
|
-
- -
|
|
135
|
+
- - ">="
|
|
136
136
|
- !ruby/object:Gem::Version
|
|
137
137
|
version: '0'
|
|
138
138
|
requirements: []
|
|
139
139
|
rubyforge_project:
|
|
140
|
-
rubygems_version: 2.
|
|
140
|
+
rubygems_version: 2.4.8
|
|
141
141
|
signing_key:
|
|
142
142
|
specification_version: 4
|
|
143
143
|
summary: Create classes that define themselves... eventually.
|