fast_open_struct 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: