dynamic_class 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f0bcefb083d8034817163abd4a89cea881857f76
4
- data.tar.gz: f022a9ff7afefd4f40383b5e2be213a9510dab95
3
+ metadata.gz: 9b151ef4fe4e1436998fe710a7398d0f4260f17c
4
+ data.tar.gz: 7814c667c0cb6bfb2495e65a216198de3b23338a
5
5
  SHA512:
6
- metadata.gz: 1743ad57ee809cc4900c37b33d02e97838570ba5e408aa5f9a2f690b5c071b0cdb6bff9582e8e2f2d88fdb6d726966632c6f7e5392c5b91f78b11eca718f4027
7
- data.tar.gz: dddc7b18eb8ca3a59439fb72df86e756384a8e94b0b7bdf1cef88835ec8bc64cd687e3983a32182024249c5f3a24f27290e7a2af301cb6dd5cfebacdf4a9a785
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 11.183k i/100ms
46
- PersistentOpenStruct 46.448k i/100ms
47
- OpenFastStruct 47.295k i/100ms
48
- DynamicClass 47.797k i/100ms
49
- RegularClass 101.410k i/100ms
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 138.431k13.8%) i/s - 682.163k
52
- PersistentOpenStruct 757.737k (± 5.3%) i/s - 3.809M
53
- OpenFastStruct 783.310k6.0%) i/s - 3.925M
54
- DynamicClass 766.130k3.6%) i/s - 3.872M
55
- RegularClass 3.037M (± 7.2%) i/s - 15.110M
51
+ OpenStruct 165.010k 6.0%) i/s - 836.076k
52
+ PersistentOpenStruct 793.144k (± 5.4%) i/s - 3.969M
53
+ OpenFastStruct 850.827k5.0%) i/s - 4.273M
54
+ DynamicClass 1.026M4.0%) i/s - 5.180M
55
+ RegularClass 3.451M3.7%) i/s - 17.311M
56
56
 
57
57
  Comparison:
58
- RegularClass: 3037473.6 i/s
59
- OpenFastStruct: 783309.5 i/s - 3.88x slower
60
- DynamicClass: 766129.7 i/s - 3.96x slower
61
- PersistentOpenStruct: 757736.8 i/s - 4.01x slower
62
- OpenStruct: 138430.6 i/s - 21.94x slower
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 107.675k i/100ms
70
- PersistentOpenStruct 108.952k i/100ms
71
- OpenFastStruct 59.163k i/100ms
72
- DynamicClass 133.406k i/100ms
73
- RegularClass 134.345k i/100ms
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.511M4.2%) i/s - 17.551M
76
- PersistentOpenStruct 3.491M4.3%) i/s - 17.432M
77
- OpenFastStruct 950.760k (± 4.8%) i/s - 4.792M
78
- DynamicClass 8.891M (± 5.7%) i/s - 44.291M
79
- RegularClass 8.939M5.8%) i/s - 44.603M
75
+ OpenStruct 3.773M5.8%) i/s - 18.839M
76
+ PersistentOpenStruct 3.737M6.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.017M7.6%) i/s - 44.795M
80
80
 
81
81
  Comparison:
82
- RegularClass: 8939463.2 i/s
83
- DynamicClass: 8890563.0 i/s - 1.01x slower
84
- OpenStruct: 3511253.2 i/s - 2.55x slower
85
- PersistentOpenStruct: 3491119.3 i/s - 2.56x slower
86
- OpenFastStruct: 950760.2 i/s - 9.40x slower
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 121.935k i/100ms
94
- PersistentOpenStruct 122.673k i/100ms
95
- OpenFastStruct 111.492k i/100ms
96
- DynamicClass 136.066k i/100ms
97
- RegularClass 135.946k i/100ms
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.603M6.1%) i/s - 27.923M
100
- PersistentOpenStruct 5.613M5.8%) i/s - 27.969M
101
- OpenFastStruct 3.683M6.9%) i/s - 18.396M
102
- DynamicClass 9.674M5.8%) i/s - 48.167M
103
- RegularClass 9.809M (± 5.5%) i/s - 48.941M
99
+ OpenStruct 5.409M5.3%) i/s - 26.968M
100
+ PersistentOpenStruct 5.341M6.3%) i/s - 26.607M
101
+ OpenFastStruct 4.094M5.5%) i/s - 20.474M
102
+ DynamicClass 9.623M6.1%) i/s - 48.006M
103
+ RegularClass 9.655M (± 5.9%) i/s - 48.153M
104
104
 
105
105
  Comparison:
106
- RegularClass: 9808944.8 i/s
107
- DynamicClass: 9674457.9 i/s - 1.01x slower
108
- PersistentOpenStruct: 5612626.6 i/s - 1.75x slower
109
- OpenStruct: 5603365.4 i/s - 1.75x slower
110
- OpenFastStruct: 3683298.4 i/s - 2.66x slower
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 11.371k i/100ms
118
- PersistentOpenStruct 41.683k i/100ms
119
- OpenFastStruct 30.589k i/100ms
120
- DynamicClass 52.041k i/100ms
121
- RegularClass 100.225k i/100ms
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 136.382k14.6%) i/s - 659.518k
124
- PersistentOpenStruct 647.752k4.4%) i/s - 3.251M
125
- OpenFastStruct 416.183k5.4%) i/s - 2.080M
126
- DynamicClass 827.546k4.3%) i/s - 4.163M
127
- RegularClass 3.034M6.6%) i/s - 15.134M
123
+ OpenStruct 161.775k 5.7%) i/s - 809.200k
124
+ PersistentOpenStruct 625.010k5.7%) i/s - 3.133M
125
+ OpenFastStruct 446.903k4.8%) i/s - 2.263M
126
+ DynamicClass 995.236k5.0%) i/s - 4.997M
127
+ RegularClass 3.102M5.7%) i/s - 15.501M
128
128
 
129
129
  Comparison:
130
- RegularClass: 3033808.8 i/s
131
- DynamicClass: 827546.3 i/s - 3.67x slower
132
- PersistentOpenStruct: 647751.5 i/s - 4.68x slower
133
- OpenFastStruct: 416183.1 i/s - 7.29x slower
134
- OpenStruct: 136382.0 i/s - 22.24x slower
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 (or
138
- effectively tied for best) out of the pack when it comes to `OpenStruct` and
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 "dynamic_class/version"
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
- {}.tap do |hash|
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(:[]=, key, value)
62
+ send(:"#{key}=", value)
35
63
  end
36
64
  end
37
65
 
38
66
  def to_h
39
- {}.tap do |hash|
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
- self[key] = nil
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
@@ -1,3 +1,3 @@
1
1
  module DynamicClass
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  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.1.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.0.14
140
+ rubygems_version: 2.4.8
141
141
  signing_key:
142
142
  specification_version: 4
143
143
  summary: Create classes that define themselves... eventually.