hashery 1.0.0 → 1.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.
- data/HISTORY +21 -0
- data/lib/hashery/association.rb +160 -0
- data/lib/hashery/ini.rb +267 -0
- data/lib/hashery/linkedlist.rb +195 -0
- data/lib/hashery/opencascade.rb +3 -2
- data/lib/hashery/openhash.rb +1 -1
- data/lib/hashery/openobject.rb +5 -5
- data/lib/hashery/orderedhash.rb +120 -370
- data/lib/hashery/sparsearray.rb +586 -0
- data/meta/version +1 -1
- data/test/case_association.rb +28 -0
- metadata +8 -3
@@ -0,0 +1,195 @@
|
|
1
|
+
# LinkedList
|
2
|
+
#
|
3
|
+
# Copyright (C) 2006 Kirk Haines <khaines@enigo.com>.
|
4
|
+
#
|
5
|
+
# General Public License (GPL)
|
6
|
+
#
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
# a copy of this software and associated documentation files (the
|
9
|
+
# "Software"), to deal in the Software without restriction, including
|
10
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
13
|
+
# the following conditions:
|
14
|
+
#
|
15
|
+
# The above copyright notice and this permission notice shall be
|
16
|
+
# included in all copies or substantial portions of the Software.
|
17
|
+
#
|
18
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
21
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
22
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
23
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
24
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
25
|
+
|
26
|
+
require 'enumerator'
|
27
|
+
|
28
|
+
# LinkedList implements a simple doubly linked list with efficient
|
29
|
+
# hash-like element access.
|
30
|
+
#
|
31
|
+
# This is a simple linked list implementation with efficient random
|
32
|
+
# access of data elements. It was inspired by George Moscovitis'
|
33
|
+
# LRUCache implementation found in Facets 1.7.30, but unlike the
|
34
|
+
# linked list in that cache, this one does not require the use of a
|
35
|
+
# mixin on any class to be stored. The linked list provides the
|
36
|
+
# push, pop, shift, unshift, first, last, delete and length methods
|
37
|
+
# which work just like their namesakes in the Array class, but it
|
38
|
+
# also supports setting and retrieving values by key, just like a
|
39
|
+
# hash.
|
40
|
+
#
|
41
|
+
# LinkedList was ported from the original in Kirk Hanes IOWA web framework.
|
42
|
+
#
|
43
|
+
class LinkedList
|
44
|
+
|
45
|
+
include Enumerable
|
46
|
+
|
47
|
+
# Represents a single node of the linked list.
|
48
|
+
|
49
|
+
class Node
|
50
|
+
attr_accessor :key, :value, :prev_node, :next_node
|
51
|
+
|
52
|
+
def initialize(key=nil,value=nil,prev_node=nil,next_node=nil)
|
53
|
+
@key = key
|
54
|
+
@value = value
|
55
|
+
@prev_node = prev_node
|
56
|
+
@next_node = next_node
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize
|
61
|
+
@head = Node.new
|
62
|
+
@tail = Node.new
|
63
|
+
@lookup = Hash.new
|
64
|
+
node_join(@head,@tail)
|
65
|
+
end
|
66
|
+
|
67
|
+
def [](v)
|
68
|
+
@lookup[v].value
|
69
|
+
end
|
70
|
+
|
71
|
+
def []=(k,v)
|
72
|
+
if @lookup.has_key?(k)
|
73
|
+
@lookup[k].value = v
|
74
|
+
else
|
75
|
+
n = Node.new(k,v,@head,@head.next_node)
|
76
|
+
node_join(n,@head.next_node)
|
77
|
+
node_join(@head,n)
|
78
|
+
@lookup[k] = n
|
79
|
+
end
|
80
|
+
v
|
81
|
+
end
|
82
|
+
|
83
|
+
def empty?
|
84
|
+
@lookup.empty?
|
85
|
+
end
|
86
|
+
|
87
|
+
def delete(k)
|
88
|
+
n = @lookup.delete(k)
|
89
|
+
v = n ? node_purge(n) : nil
|
90
|
+
v
|
91
|
+
end
|
92
|
+
|
93
|
+
def first
|
94
|
+
@head.next_node.value
|
95
|
+
end
|
96
|
+
|
97
|
+
def last
|
98
|
+
@tail.prev_node.value
|
99
|
+
end
|
100
|
+
|
101
|
+
def shift
|
102
|
+
k = @head.next_node.key
|
103
|
+
n = @lookup.delete(k)
|
104
|
+
node_delete(n) if n
|
105
|
+
end
|
106
|
+
|
107
|
+
def unshift(v)
|
108
|
+
if @lookup.has_key?(v)
|
109
|
+
n = @lookup[v]
|
110
|
+
node_delete(n)
|
111
|
+
node_join(n,@head.next_node)
|
112
|
+
node_join(@head,n)
|
113
|
+
else
|
114
|
+
n = Node.new(v,v,@head,@head.next_node)
|
115
|
+
node_join(n,@head.next_node)
|
116
|
+
node_join(@head,n)
|
117
|
+
@lookup[v] = n
|
118
|
+
end
|
119
|
+
v
|
120
|
+
end
|
121
|
+
|
122
|
+
def pop
|
123
|
+
k = @tail.prev_node.key
|
124
|
+
n = @lookup.delete(k)
|
125
|
+
node_delete(n) if n
|
126
|
+
end
|
127
|
+
|
128
|
+
def push(v)
|
129
|
+
if @lookup.has_key?(v)
|
130
|
+
n = @lookup[v]
|
131
|
+
node_delete(n)
|
132
|
+
node_join(@tail.prev_node,n)
|
133
|
+
node_join(n,@tail)
|
134
|
+
else
|
135
|
+
n = Node.new(v,v,@tail.prev_node,@tail)
|
136
|
+
node_join(@tail.prev_node,n)
|
137
|
+
node_join(n,@tail)
|
138
|
+
@lookup[v] = n
|
139
|
+
end
|
140
|
+
v
|
141
|
+
end
|
142
|
+
|
143
|
+
def queue
|
144
|
+
r = []
|
145
|
+
n = @head
|
146
|
+
while (n = n.next_node) and n != @tail
|
147
|
+
r << n.key
|
148
|
+
end
|
149
|
+
r
|
150
|
+
end
|
151
|
+
|
152
|
+
def to_a
|
153
|
+
r = []
|
154
|
+
n = @head
|
155
|
+
while (n = n.next_node) and n != @tail
|
156
|
+
r << n.value
|
157
|
+
end
|
158
|
+
r
|
159
|
+
end
|
160
|
+
|
161
|
+
def length
|
162
|
+
@lookup.length
|
163
|
+
end
|
164
|
+
|
165
|
+
def each
|
166
|
+
n = @head
|
167
|
+
while (n = n.next_node) and n != @tail
|
168
|
+
yield(n.key,n.value)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def node_delete(n)
|
175
|
+
node_join(n.prev_node,n.next_node)
|
176
|
+
v = n.value
|
177
|
+
end
|
178
|
+
|
179
|
+
def node_purge(n)
|
180
|
+
node_join(n.prev_node,n.next_node)
|
181
|
+
v = n.value
|
182
|
+
n.value = nil
|
183
|
+
n.key = nil
|
184
|
+
n.next_node = nil
|
185
|
+
n.prev_node = nil
|
186
|
+
v
|
187
|
+
end
|
188
|
+
|
189
|
+
def node_join(a,b)
|
190
|
+
a.next_node = b
|
191
|
+
b.prev_node = a
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
data/lib/hashery/opencascade.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# OpenCascade Copyright (c) 2006 Thomas Sawyer
|
2
|
+
|
3
|
+
require 'hashery/openobject'
|
1
4
|
#require 'facets/boolean' # bool
|
2
5
|
#require 'facets/nullclass'
|
3
|
-
require 'hashery/openobject'
|
4
6
|
|
5
7
|
# = OpenCascade
|
6
8
|
#
|
@@ -79,4 +81,3 @@ class OpenCascade < OpenObject
|
|
79
81
|
end
|
80
82
|
|
81
83
|
end
|
82
|
-
|
data/lib/hashery/openhash.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
#
|
6
6
|
# Because OpenHash is a subclass of Hash, it can do everything a Hash
|
7
7
|
# can *unless* a Hash method has been explicity exempted for use
|
8
|
-
#
|
8
|
+
# as an open read/writer via the #omit! method.
|
9
9
|
|
10
10
|
class OpenHash < Hash
|
11
11
|
|
data/lib/hashery/openobject.rb
CHANGED
@@ -7,7 +7,7 @@ require 'facets/basicobject'
|
|
7
7
|
#
|
8
8
|
# OpenObject is very similar to Ruby's own OpenStruct, but it offers some
|
9
9
|
# advantages. With OpenStruct, slots with the same name as predefined
|
10
|
-
# Object methods
|
10
|
+
# Object methods cannot be used. With OpenObject, almost any slot can be
|
11
11
|
# defined. OpenObject is a subclass of BasicObject to ensure all method
|
12
12
|
# slots, except those that are absolutely essential, are open for use.
|
13
13
|
#
|
@@ -164,13 +164,13 @@ class OpenObject < BasicObject
|
|
164
164
|
end
|
165
165
|
|
166
166
|
#
|
167
|
-
def []=(
|
168
|
-
@hash[
|
167
|
+
def []=(key, value)
|
168
|
+
@hash[key.to_sym] = value
|
169
169
|
end
|
170
170
|
|
171
171
|
#
|
172
|
-
def [](
|
173
|
-
@hash[
|
172
|
+
def [](key)
|
173
|
+
@hash[key.to_sym]
|
174
174
|
end
|
175
175
|
|
176
176
|
#
|
data/lib/hashery/orderedhash.rb
CHANGED
@@ -1,417 +1,167 @@
|
|
1
1
|
# = OrderedHash
|
2
2
|
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# an OrderedHash object preserves insertion order, but any
|
6
|
-
# order can be specified including alphabetical key order.
|
3
|
+
# A simple ordered hash implmentation, for users of
|
4
|
+
# Ruby 1.8.7 or less.
|
7
5
|
#
|
8
|
-
#
|
6
|
+
# NOTE: As of Ruby 1.9+ this class is not needed, since
|
7
|
+
# Ruby 1.9's standard Hash tracks inseration order.
|
9
8
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# # You can do simply
|
13
|
-
# hsh = OrderedHash.new
|
14
|
-
# hsh['z'] = 1
|
15
|
-
# hsh['a'] = 2
|
16
|
-
# hsh['c'] = 3
|
17
|
-
# p hsh.keys #=> ['z','a','c']
|
18
|
-
#
|
19
|
-
# # or using OrderedHash[] method
|
20
|
-
# hsh = OrderedHash['z', 1, 'a', 2, 'c', 3]
|
21
|
-
# p hsh.keys #=> ['z','a','c']
|
22
|
-
#
|
23
|
-
# # but this don't preserve order
|
24
|
-
# hsh = OrderedHash['z'=>1, 'a'=>2, 'c'=>3]
|
25
|
-
# p hsh.keys #=> ['a','c','z']
|
26
|
-
#
|
27
|
-
# # OrderedHash has useful extensions: push, pop and unshift
|
28
|
-
# p hsh.push('to_end', 15) #=> true, key added
|
29
|
-
# p hsh.push('to_end', 30) #=> false, already - nothing happen
|
30
|
-
# p hsh.unshift('to_begin', 50) #=> true, key added
|
31
|
-
# p hsh.unshift('to_begin', 60) #=> false, already - nothing happen
|
32
|
-
# p hsh.keys #=> ["to_begin", "a", "c", "z", "to_end"]
|
33
|
-
# p hsh.pop #=> ["to_end", 15], if nothing remains, return nil
|
34
|
-
# p hsh.keys #=> ["to_begin", "a", "c", "z"]
|
35
|
-
# p hsh.shift #=> ["to_begin", 30], if nothing remains, return nil
|
36
|
-
#
|
37
|
-
# == Usage Notes
|
38
|
-
#
|
39
|
-
# * You can use #order_by to set internal sort order.
|
40
|
-
# * #<< takes a two element [k,v] array and inserts.
|
41
|
-
# * Use ::auto which creates Dictionay sub-entries as needed.
|
42
|
-
# * And ::alpha which creates a new OrderedHash sorted by key.
|
43
|
-
#
|
44
|
-
# == Acknowledgments
|
45
|
-
#
|
46
|
-
# * Andrew Johnson (merge, to_a, inspect, shift and Hash[])
|
47
|
-
# * Jeff Sharpe (reverse and reverse!)
|
48
|
-
# * Thomas Leitner (has_key? and key?)
|
49
|
-
#
|
50
|
-
# Ported from OrderHash 2.0, Copyright (c) 2005 Jan Molic
|
51
|
-
|
52
|
-
class OrderedHash
|
53
|
-
|
54
|
-
include Enumerable
|
55
|
-
|
56
|
-
class << self
|
57
|
-
#--
|
58
|
-
# TODO is this needed? Doesn't the super class do this?
|
59
|
-
#++
|
60
|
-
|
61
|
-
def [](*args)
|
62
|
-
hsh = new
|
63
|
-
if Hash === args[0]
|
64
|
-
hsh.replace(args[0])
|
65
|
-
elsif (args.size % 2) != 0
|
66
|
-
raise ArgumentError, "odd number of elements for Hash"
|
67
|
-
else
|
68
|
-
while !args.empty?
|
69
|
-
hsh[args.shift] = args.shift
|
70
|
-
end
|
71
|
-
end
|
72
|
-
hsh
|
73
|
-
end
|
74
|
-
|
75
|
-
# Like #new but the block sets the order.
|
76
|
-
#
|
77
|
-
def new_by(*args, &blk)
|
78
|
-
new(*args).order_by(&blk)
|
79
|
-
end
|
9
|
+
# This implementation derives from the same class in
|
10
|
+
# ActiveSupport library.
|
80
11
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
# d["y"] = 2
|
86
|
-
# d["x"] = 3
|
87
|
-
# d #=> {"x"=>3,"y"=>2,"z"=>2}
|
88
|
-
#
|
89
|
-
# This is equivalent to:
|
90
|
-
#
|
91
|
-
# OrderedHash.new.order_by { |key,value| key }
|
92
|
-
|
93
|
-
def alpha(*args, &block)
|
94
|
-
new(*args, &block).order_by_key
|
95
|
-
end
|
12
|
+
class OrderedHash < ::Hash
|
13
|
+
def to_yaml_type
|
14
|
+
"!tag:yaml.org,2002:omap"
|
15
|
+
end
|
96
16
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
leet = lambda { |hsh, key| hsh[key] = new(&leet) }
|
105
|
-
new(*args, &leet)
|
17
|
+
def to_yaml(opts = {})
|
18
|
+
YAML.quick_emit(self, opts) do |out|
|
19
|
+
out.seq(taguri, to_yaml_style) do |seq|
|
20
|
+
each do |k, v|
|
21
|
+
seq.add(k => v)
|
22
|
+
end
|
23
|
+
end
|
106
24
|
end
|
107
25
|
end
|
108
26
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
if blk
|
115
|
-
dict = self # This ensure autmatic key entry effect the
|
116
|
-
oblk = lambda{ |hsh, key| blk[dict,key] } # dictionary rather then just the interal hash.
|
117
|
-
@hash = Hash.new(*args, &oblk)
|
118
|
-
else
|
119
|
-
@hash = Hash.new(*args)
|
27
|
+
# Hash is ordered in Ruby 1.9!
|
28
|
+
if RUBY_VERSION < '1.9'
|
29
|
+
def initialize(*args, &block)
|
30
|
+
super
|
31
|
+
@keys = []
|
120
32
|
end
|
121
|
-
end
|
122
33
|
|
123
|
-
|
124
|
-
|
125
|
-
@order
|
126
|
-
end
|
34
|
+
def self.[](*args)
|
35
|
+
ordered_hash = new
|
127
36
|
|
128
|
-
|
37
|
+
if (args.length == 1 && args.first.is_a?(Array))
|
38
|
+
args.first.each do |key_value_pair|
|
39
|
+
next unless (key_value_pair.is_a?(Array))
|
40
|
+
ordered_hash[key_value_pair[0]] = key_value_pair[1]
|
41
|
+
end
|
129
42
|
|
130
|
-
|
131
|
-
|
132
|
-
order
|
133
|
-
self
|
134
|
-
end
|
43
|
+
return ordered_hash
|
44
|
+
end
|
135
45
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
# d["z"] = 1
|
140
|
-
# d["y"] = 2
|
141
|
-
# d["x"] = 3
|
142
|
-
# d #=> {"x"=>3,"y"=>2,"z"=>2}
|
143
|
-
#
|
144
|
-
# This is equivalent to:
|
145
|
-
#
|
146
|
-
# OrderedHash.new.order_by { |key,value| key }
|
147
|
-
#
|
148
|
-
# The initializer OrderedHash#alpha also provides this.
|
149
|
-
|
150
|
-
def order_by_key
|
151
|
-
@order_by = lambda { |k,v| k }
|
152
|
-
order
|
153
|
-
self
|
154
|
-
end
|
46
|
+
unless (args.size % 2 == 0)
|
47
|
+
raise ArgumentError.new("odd number of arguments for Hash")
|
48
|
+
end
|
155
49
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
# d["y"] = 2
|
161
|
-
# d["x"] = 3
|
162
|
-
# d #=> {"x"=>3,"y"=>2,"z"=>2}
|
163
|
-
#
|
164
|
-
# This is equivalent to:
|
165
|
-
#
|
166
|
-
# OrderedHash.new.order_by { |key,value| value }
|
167
|
-
|
168
|
-
def order_by_value
|
169
|
-
@order_by = lambda { |k,v| v }
|
170
|
-
order
|
171
|
-
self
|
172
|
-
end
|
50
|
+
args.each_with_index do |val, ind|
|
51
|
+
next if (ind % 2 != 0)
|
52
|
+
ordered_hash[val] = args[ind + 1]
|
53
|
+
end
|
173
54
|
|
174
|
-
|
175
|
-
def reorder
|
176
|
-
if @order_by
|
177
|
-
assoc = @order.collect{ |k| [k,@hash[k]] }.sort_by(&@order_by)
|
178
|
-
@order = assoc.collect{ |k,v| k }
|
55
|
+
ordered_hash
|
179
56
|
end
|
180
|
-
@order
|
181
|
-
end
|
182
57
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
#end
|
187
|
-
|
188
|
-
def ==(hsh2)
|
189
|
-
if hsh2.is_a?( OrderedHash )
|
190
|
-
@order == hsh2.order &&
|
191
|
-
@hash == hsh2.instance_variable_get("@hash")
|
192
|
-
else
|
193
|
-
false
|
58
|
+
def initialize_copy(other)
|
59
|
+
super(other)
|
60
|
+
@keys = other.keys
|
194
61
|
end
|
195
|
-
end
|
196
|
-
|
197
|
-
def [] k
|
198
|
-
@hash[ k ]
|
199
|
-
end
|
200
|
-
|
201
|
-
def fetch(k, *a, &b)
|
202
|
-
@hash.fetch(k, *a, &b)
|
203
|
-
end
|
204
62
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
#
|
209
|
-
# Or with additional index.
|
210
|
-
#
|
211
|
-
# h[key,index] = value
|
212
|
-
|
213
|
-
def []=(k, i=nil, v=nil)
|
214
|
-
if v
|
215
|
-
insert(i,k,v)
|
216
|
-
else
|
217
|
-
store(k,i)
|
63
|
+
def []=(key, value)
|
64
|
+
@keys << key unless key?(key)
|
65
|
+
super(key, value)
|
218
66
|
end
|
219
|
-
end
|
220
|
-
|
221
|
-
def insert( i,k,v )
|
222
|
-
@order.insert( i,k )
|
223
|
-
@hash.store( k,v )
|
224
|
-
end
|
225
|
-
|
226
|
-
def store( a,b )
|
227
|
-
@order.push( a ) unless @hash.has_key?( a )
|
228
|
-
@hash.store( a,b )
|
229
|
-
end
|
230
|
-
|
231
|
-
def clear
|
232
|
-
@order = []
|
233
|
-
@hash.clear
|
234
|
-
end
|
235
|
-
|
236
|
-
def delete( key )
|
237
|
-
@order.delete( key )
|
238
|
-
@hash.delete( key )
|
239
|
-
end
|
240
|
-
|
241
|
-
def each_key
|
242
|
-
order.each { |k| yield( k ) }
|
243
|
-
self
|
244
|
-
end
|
245
|
-
|
246
|
-
def each_value
|
247
|
-
order.each { |k| yield( @hash[k] ) }
|
248
|
-
self
|
249
|
-
end
|
250
|
-
|
251
|
-
def each
|
252
|
-
order.each { |k| yield( k,@hash[k] ) }
|
253
|
-
self
|
254
|
-
end
|
255
|
-
alias each_pair each
|
256
|
-
|
257
|
-
def delete_if
|
258
|
-
order.clone.each { |k| delete k if yield(k,@hash[k]) }
|
259
|
-
self
|
260
|
-
end
|
261
|
-
|
262
|
-
def values
|
263
|
-
ary = []
|
264
|
-
order.each { |k| ary.push @hash[k] }
|
265
|
-
ary
|
266
|
-
end
|
267
|
-
|
268
|
-
def keys
|
269
|
-
order
|
270
|
-
end
|
271
|
-
|
272
|
-
def invert
|
273
|
-
hsh2 = self.class.new
|
274
|
-
order.each { |k| hsh2[@hash[k]] = k }
|
275
|
-
hsh2
|
276
|
-
end
|
277
|
-
|
278
|
-
def reject(&block)
|
279
|
-
self.dup.delete_if(&block)
|
280
|
-
end
|
281
67
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
case hsh2
|
289
|
-
when Hash
|
290
|
-
@order = hsh2.keys
|
291
|
-
@hash = hsh2
|
292
|
-
else
|
293
|
-
@order = hsh2.order
|
294
|
-
@hash = hsh2.hash
|
68
|
+
def delete(key)
|
69
|
+
if has_key? key
|
70
|
+
index = @keys.index(key)
|
71
|
+
@keys.delete_at(index)
|
72
|
+
end
|
73
|
+
super(key)
|
295
74
|
end
|
296
|
-
reorder
|
297
|
-
end
|
298
|
-
|
299
|
-
def shift
|
300
|
-
key = order.first
|
301
|
-
key ? [key,delete(key)] : super
|
302
|
-
end
|
303
75
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
true
|
309
|
-
else
|
310
|
-
false
|
76
|
+
def delete_if
|
77
|
+
super
|
78
|
+
sync_keys!
|
79
|
+
self
|
311
80
|
end
|
312
|
-
end
|
313
|
-
|
314
|
-
def <<(kv)
|
315
|
-
push(*kv)
|
316
|
-
end
|
317
81
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
true
|
323
|
-
else
|
324
|
-
false
|
82
|
+
def reject!
|
83
|
+
super
|
84
|
+
sync_keys!
|
85
|
+
self
|
325
86
|
end
|
326
|
-
end
|
327
87
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
end
|
88
|
+
def reject(&block)
|
89
|
+
dup.reject!(&block)
|
90
|
+
end
|
332
91
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
'{' + ary.join(", ") + '}'
|
337
|
-
end
|
92
|
+
def keys
|
93
|
+
@keys.dup
|
94
|
+
end
|
338
95
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
self.class[*a]
|
343
|
-
end
|
96
|
+
def values
|
97
|
+
@keys.collect{ |key| self[key] }
|
98
|
+
end
|
344
99
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
self
|
349
|
-
end
|
350
|
-
alias :merge! update
|
100
|
+
def to_hash
|
101
|
+
self
|
102
|
+
end
|
351
103
|
|
352
|
-
|
353
|
-
|
354
|
-
|
104
|
+
def to_a
|
105
|
+
@keys.map{ |key| [ key, self[key] ] }
|
106
|
+
end
|
355
107
|
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
ary
|
360
|
-
end
|
108
|
+
def each_key
|
109
|
+
@keys.each{ |key| yield(key) }
|
110
|
+
end
|
361
111
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
end
|
112
|
+
def each_value
|
113
|
+
@keys.each{ |key| yield(self[key]) }
|
114
|
+
end
|
366
115
|
|
367
|
-
|
368
|
-
|
369
|
-
|
116
|
+
def each
|
117
|
+
@keys.each{ |key| yield(key, self[key]) }
|
118
|
+
end
|
370
119
|
|
371
|
-
|
372
|
-
def first(x=nil)
|
373
|
-
return @hash[order.first] unless x
|
374
|
-
order.first(x).collect { |k| @hash[k] }
|
375
|
-
end
|
120
|
+
alias_method :each_pair, :each
|
376
121
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
122
|
+
def clear
|
123
|
+
super
|
124
|
+
@keys.clear
|
125
|
+
self
|
126
|
+
end
|
382
127
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
128
|
+
def shift
|
129
|
+
k = @keys.first
|
130
|
+
v = delete(k)
|
131
|
+
[k, v]
|
132
|
+
end
|
387
133
|
|
388
|
-
|
389
|
-
|
390
|
-
|
134
|
+
def merge!(other_hash)
|
135
|
+
other_hash.each{ |k,v| self[k] = v }
|
136
|
+
self
|
137
|
+
end
|
391
138
|
|
392
|
-
|
393
|
-
|
394
|
-
|
139
|
+
def merge(other_hash)
|
140
|
+
dup.merge!(other_hash)
|
141
|
+
end
|
395
142
|
|
396
|
-
|
397
|
-
|
398
|
-
|
143
|
+
# When replacing with another hash, the initial order of our
|
144
|
+
# keys must come from the other hash, ordered or not.
|
145
|
+
def replace(other)
|
146
|
+
super
|
147
|
+
@keys = other.keys
|
148
|
+
self
|
149
|
+
end
|
399
150
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
ary
|
404
|
-
end
|
151
|
+
def inspect
|
152
|
+
"#<OrderedHash #{super}>"
|
153
|
+
end
|
405
154
|
|
406
|
-
|
407
|
-
|
155
|
+
private
|
156
|
+
def sync_keys!
|
157
|
+
@keys.delete_if{ |k| !key?(k) }
|
158
|
+
end
|
408
159
|
end
|
160
|
+
end
|
409
161
|
|
410
|
-
|
411
|
-
@hash.dup
|
412
|
-
end
|
162
|
+
require 'yaml'
|
413
163
|
|
414
|
-
|
415
|
-
|
416
|
-
end
|
164
|
+
YAML.add_builtin_type("omap") do |type, val|
|
165
|
+
ActiveSupport::OrderedHash[val.map(&:to_a).map(&:first)]
|
417
166
|
end
|
167
|
+
|