fast_open_struct 0.1.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.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +50 -0
  3. data/lib/fast_open_struct.rb +132 -0
  4. metadata +46 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3461061a4d05eff011d1c5256280b11165cf168a
4
+ data.tar.gz: 363a6a1c6f32c7665be1e259e65087da1531e77e
5
+ SHA512:
6
+ metadata.gz: 14d23a7bf402b01068a6405d748063a5d6e60d4cabc80f9ccd963175689a013a77cc89ba8b1d8f3bd889aec349daaa4e37c9520350ace6d55c36284061763efe
7
+ data.tar.gz: 7871c5327d6d93efdffb2a28173991d19052a4ef18bf3b0cdc18964bf000a6727e74a818effcb5b3d17ba3d959446cbbec96899c5e0b0f9726503fbddb60f724
@@ -0,0 +1,50 @@
1
+ # FastOpenStruct
2
+
3
+ FastOpenStruct is a reimplementation of Ruby's OpenStruct that avoids invalidating MRI's method caches on every instantiation.
4
+
5
+ It should be a drop in replacement for OpenStruct.
6
+
7
+ ## Performance
8
+
9
+ ```
10
+ λ ruby -I./lib bench/attribute_lookup.rb
11
+ user system total real
12
+ OpenStruct 0.730000 0.000000 0.730000 ( 0.732052)
13
+ FastOpenStruct 0.220000 0.000000 0.220000 ( 0.224770)
14
+ ```
15
+
16
+ ```
17
+ λ ruby -I./lib bench/10_000_instantiations.rb
18
+ user system total real
19
+ OpenStruct 0.630000 0.010000 0.640000 ( 0.645598)
20
+ FastOpenStruct 0.240000 0.000000 0.240000 ( 0.239307)
21
+ ```
22
+
23
+ ## Licence
24
+
25
+ Simplified BSD
26
+
27
+ ```
28
+ Copyright (C) 2013 Charlie Somerville. All rights reserved.
29
+ All rights reserved.
30
+
31
+ Redistribution and use in source and binary forms, with or without
32
+ modification, are permitted provided that the following conditions are met:
33
+
34
+ 1. Redistributions of source code must retain the above copyright notice, this
35
+ list of conditions and the following disclaimer.
36
+ 2. Redistributions in binary form must reproduce the above copyright notice,
37
+ this list of conditions and the following disclaimer in the documentation
38
+ and/or other materials provided with the distribution.
39
+
40
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
41
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
42
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
44
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
45
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
47
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
48
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
49
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50
+ ```
@@ -0,0 +1,132 @@
1
+ require "set"
2
+
3
+ class FastOpenStruct
4
+ class << self
5
+ private
6
+ alias_method :__new, :new
7
+ private :__new
8
+
9
+ def __create_class(keys)
10
+ Class.new self do
11
+ attr_accessor *keys
12
+ class << self
13
+ alias_method :new, :__new
14
+ public :new
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ @cache = {}
21
+
22
+ def self.new(table = {})
23
+ keys = table.each_pair.map { |key, _| key.intern }.sort
24
+ if cached = @cache[keys]
25
+ cached.new table
26
+ else
27
+ (@cache[keys] = __create_class(keys)).new table
28
+ end
29
+ end
30
+
31
+ def initialize(table = {})
32
+ table.each_pair do |k, v|
33
+ instance_variable_set "@#{k}", v
34
+ end
35
+ end
36
+
37
+ def [](name)
38
+ instance_variable_get "@#{name}"
39
+ end
40
+
41
+ def []=(name, value)
42
+ instance_variable_set "@#{name}", value
43
+ value
44
+ rescue RuntimeError
45
+ raise TypeError, "can't modify frozen #{__apparent_class__}"
46
+ end
47
+
48
+ def delete_field(name)
49
+ value = self[name]
50
+ remove_instance_variable "@#{name}"
51
+ value
52
+ end
53
+
54
+ def each_pair
55
+ return to_enum(__method__) unless block_given?
56
+ instance_variables.each do |ivar|
57
+ yield ivar[1..-1].intern, instance_variable_get(ivar)
58
+ end
59
+ self
60
+ end
61
+
62
+ def ==(other)
63
+ return false unless other.is_a? FastOpenStruct
64
+ ivars = instance_variables
65
+ return false if (ivars - other.instance_variables).any?
66
+ ivars.all? { |ivar| instance_variable_get(ivar) == other.instance_variable_get(ivar) }
67
+ end
68
+
69
+ def eql?(other)
70
+ return false unless other.is_a? FastOpenStruct
71
+ ivars = instance_variables
72
+ return false if (ivars - other.instance_variables).any?
73
+ ivars.all? { |ivar| instance_variable_get(ivar).eql? other.instance_variable_get(ivar) }
74
+ end
75
+
76
+ def inspect
77
+ str = "#<#{__apparent_class__}"
78
+ ids = (Thread.current[:__fast_open_struct_inspect_key__] ||= Set.new)
79
+ return str << " ...>" if ids.include? object_id
80
+ ids << object_id
81
+ begin
82
+ first = true
83
+ instance_variables.each do |ivar|
84
+ str << "," unless first
85
+ first = false
86
+ str << " #{ivar[1..-1]}=#{instance_variable_get(ivar).inspect}"
87
+ end
88
+ str << ">"
89
+ ensure
90
+ ids.delete object_id
91
+ end
92
+ end
93
+
94
+ def to_h
95
+ Hash[each_pair.to_a]
96
+ end
97
+
98
+ def hash
99
+ hash = 0x1337
100
+ each_pair do |key, value|
101
+ hash ^= key.hash ^ value.hash
102
+ end
103
+ hash
104
+ end
105
+
106
+ def method_missing(sym, *args)
107
+ if sym[-1] == "=" and args.size == 1
108
+ self[sym[0...-1]] = args[0]
109
+ elsif args.size == 0 and instance_variable_defined?("@#{sym}")
110
+ self[sym]
111
+ else
112
+ super
113
+ end
114
+ end
115
+
116
+ def respond_to?(sym)
117
+ if sym[-1] == "="
118
+ respond_to?(sym[0...-1])
119
+ elsif instance_variable_defined?("@#{sym}")
120
+ true
121
+ else
122
+ super
123
+ end
124
+ end
125
+
126
+ private
127
+ def __apparent_class__
128
+ klass = self.class
129
+ klass = klass.superclass until klass.name
130
+ klass
131
+ end
132
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fast_open_struct
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Charlie Somerville
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-08 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: An almost drop-in replacement for OpenStruct that does not invalidate
14
+ the method cache on every instantiation
15
+ email: charlie@charliesomerville.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - README.md
21
+ - lib/fast_open_struct.rb
22
+ homepage: https://github.com/charliesome/fast_open_struct
23
+ licenses: []
24
+ metadata: {}
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ requirements: []
40
+ rubyforge_project:
41
+ rubygems_version: 2.0.3
42
+ signing_key:
43
+ specification_version: 4
44
+ summary: A faster OpenStruct
45
+ test_files: []
46
+ has_rdoc: