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 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.