hashery 1.0.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 +15 -0
- data/LICENSE +23 -0
- data/README.rdoc +47 -0
- data/ROADMAP.rdoc +13 -0
- data/lib/hashery.rb +13 -0
- data/lib/hashery/castinghash.rb +171 -0
- data/lib/hashery/dictionary.rb +430 -0
- data/lib/hashery/lruhash.rb +274 -0
- data/lib/hashery/memoizer.rb +64 -0
- data/lib/hashery/opencascade.rb +82 -0
- data/lib/hashery/openhash.rb +65 -0
- data/lib/hashery/openobject.rb +279 -0
- data/lib/hashery/orderedhash.rb +417 -0
- data/lib/hashery/ostructable.rb +209 -0
- data/lib/hashery/queryhash.rb +35 -0
- data/lib/hashery/stash.rb +181 -0
- data/lib/hashery/statichash.rb +48 -0
- data/meta/authors +3 -0
- data/meta/created +1 -0
- data/meta/description +5 -0
- data/meta/homepage +1 -0
- data/meta/license +1 -0
- data/meta/name +1 -0
- data/meta/release +1 -0
- data/meta/repository +1 -0
- data/meta/suite +1 -0
- data/meta/summary +1 -0
- data/meta/version +1 -0
- data/test/case_dictionary.rb +142 -0
- data/test/case_opencascade.rb +68 -0
- data/test/case_openhash.rb +18 -0
- data/test/case_openobject.rb +130 -0
- data/test/case_stash.rb +131 -0
- metadata +102 -0
@@ -0,0 +1,279 @@
|
|
1
|
+
require 'facets/basicobject'
|
2
|
+
#require 'facets/hash/to_h'
|
3
|
+
#require 'facets/kernel/object_class'
|
4
|
+
#require 'facets/kernel/object_hexid'
|
5
|
+
|
6
|
+
# = OpenObject
|
7
|
+
#
|
8
|
+
# OpenObject is very similar to Ruby's own OpenStruct, but it offers some
|
9
|
+
# advantages. With OpenStruct, slots with the same name as predefined
|
10
|
+
# Object methods can not be used. With OpenObject, almost any slot can be
|
11
|
+
# defined. OpenObject is a subclass of BasicObject to ensure all method
|
12
|
+
# slots, except those that are absolutely essential, are open for use.
|
13
|
+
#
|
14
|
+
#--
|
15
|
+
# If you wish to pass an OpenObject to a routine that normal takes a Hash,
|
16
|
+
# but are uncertain it can handle the distictions properly you can convert
|
17
|
+
# easily to a Hash using #as_hash! and the result will automatically be
|
18
|
+
# converted back to an OpenObject on return.
|
19
|
+
#
|
20
|
+
# o = OpenObject.new(:a=>1,:b=>2)
|
21
|
+
# o.as_hash!{ |h| h.update(:a=>6) }
|
22
|
+
# o #=> #<OpenObject {:a=>6,:b=>2}>
|
23
|
+
#++
|
24
|
+
#
|
25
|
+
# Unlike a Hash, all OpenObject's keys are symbols and all keys are converted
|
26
|
+
# to such using #to_sym on the fly.
|
27
|
+
|
28
|
+
class OpenObject < BasicObject
|
29
|
+
|
30
|
+
#PUBLIC_METHODS = /(^__|^instance_|^object_|^\W|^as$|^send$|^class$|\?$)/
|
31
|
+
#protected(*public_instance_methods.select{ |m| m !~ PUBLIC_METHODS })
|
32
|
+
|
33
|
+
def self.[](hash=nil)
|
34
|
+
new(hash)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Inititalizer for OpenObject is slightly different than that of Hash.
|
38
|
+
# It does not take a default parameter, but an initial priming Hash,
|
39
|
+
# like OpenStruct. The initializer can still take a default block
|
40
|
+
# however. To set the default value use <code>#default!(value)</code>.
|
41
|
+
#
|
42
|
+
# OpenObject.new(:a=>1).default!(0)
|
43
|
+
#
|
44
|
+
def initialize(hash=nil, &yld)
|
45
|
+
@hash = Hash.new(&yld)
|
46
|
+
if hash
|
47
|
+
hash.each{ |k,v| store(k,v) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
def initialize_copy( orig )
|
53
|
+
orig.each{ |k,v| store(k,v) }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Object inspection.
|
57
|
+
# TODO: Need to get __class__ and __id__ in hex form.
|
58
|
+
def inspect
|
59
|
+
#@hash.inspect
|
60
|
+
hexid = __id__
|
61
|
+
klass = "OpenObject" # __class__
|
62
|
+
"#<#{klass}:#{hexid} #{@hash.inspect}>"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Convert to an associative array.
|
66
|
+
def to_a
|
67
|
+
@hash.to_a
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
def to_h
|
72
|
+
@hash.dup
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
def to_hash
|
77
|
+
@hash.dup
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
def to_openobject
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
# Convert to an assignment procedure.
|
86
|
+
def to_proc(response=false)
|
87
|
+
hash = @hash
|
88
|
+
if response
|
89
|
+
lambda do |o|
|
90
|
+
hash.each do |k,v|
|
91
|
+
o.__send__("#{k}=", v) rescue nil
|
92
|
+
end
|
93
|
+
end
|
94
|
+
else
|
95
|
+
lambda do |o|
|
96
|
+
hash.each{ |k,v| o.__send__("#{k}=", v) }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# NOT SURE ABOUT THIS
|
102
|
+
def as_hash
|
103
|
+
@hash
|
104
|
+
end
|
105
|
+
|
106
|
+
# Is a given +key+ defined?
|
107
|
+
def key?(key)
|
108
|
+
@hash.key?(key.to_sym)
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
def is_a?(klass)
|
113
|
+
return true if klass == Hash # TODO: Is this wise? How to fake a subclass?
|
114
|
+
return true if klass == OpenObject
|
115
|
+
false
|
116
|
+
end
|
117
|
+
|
118
|
+
# Iterate over each key-value pair.
|
119
|
+
def each(&yld)
|
120
|
+
@hash.each(&yld)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Set the default value.
|
124
|
+
def default!(default)
|
125
|
+
@hash.default = default
|
126
|
+
end
|
127
|
+
|
128
|
+
# Check equality.
|
129
|
+
def ==( other )
|
130
|
+
case other
|
131
|
+
when OpenObject
|
132
|
+
@hash == other.as_hash
|
133
|
+
when Hash
|
134
|
+
@hash == other
|
135
|
+
else
|
136
|
+
if other.respond_to?(:to_hash)
|
137
|
+
@hash == other.to_hash
|
138
|
+
else
|
139
|
+
false
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
def eql?( other )
|
146
|
+
case other
|
147
|
+
when OpenObject
|
148
|
+
@hash.eql?(other.as_hash)
|
149
|
+
else
|
150
|
+
false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
def <<(x)
|
156
|
+
case x
|
157
|
+
when Hash
|
158
|
+
@hash.update(x)
|
159
|
+
when Array
|
160
|
+
x.each_slice(2) do |(k,v)|
|
161
|
+
@hash[k] = v
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
#
|
167
|
+
def []=(k,v)
|
168
|
+
@hash[k.to_sym] = v
|
169
|
+
end
|
170
|
+
|
171
|
+
#
|
172
|
+
def [](k)
|
173
|
+
@hash[k.to_sym]
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
def merge!(other)
|
178
|
+
OpenObject.new(@hash.merge!(other))
|
179
|
+
end
|
180
|
+
|
181
|
+
#
|
182
|
+
def update!(other)
|
183
|
+
@hash.update(other)
|
184
|
+
self
|
185
|
+
end
|
186
|
+
|
187
|
+
protected
|
188
|
+
|
189
|
+
def store(k, v)
|
190
|
+
@hash.store(k.to_sym, v)
|
191
|
+
end
|
192
|
+
|
193
|
+
def fetch(k, *d, &b)
|
194
|
+
@hash.fetch(k.to_sym, *d, &b)
|
195
|
+
end
|
196
|
+
|
197
|
+
#def as_hash!
|
198
|
+
# Functor.new do |op,*a,&b|
|
199
|
+
# result = @hash.__send__(op,*a,&b)
|
200
|
+
# case result
|
201
|
+
# when Hash
|
202
|
+
# OpenObject.new(result)
|
203
|
+
# else
|
204
|
+
# result
|
205
|
+
# end
|
206
|
+
# end
|
207
|
+
#end
|
208
|
+
|
209
|
+
#def define_slot(key, value=nil)
|
210
|
+
# @hash[key.to_sym] = value
|
211
|
+
#end
|
212
|
+
|
213
|
+
#def protect_slot( key )
|
214
|
+
# (class << self; self; end).class_eval {
|
215
|
+
# protected key rescue nil
|
216
|
+
# }
|
217
|
+
#end
|
218
|
+
|
219
|
+
def method_missing(sym, *args, &blk)
|
220
|
+
type = sym.to_s[-1,1]
|
221
|
+
key = sym.to_s.sub(/[=?!]$/,'').to_sym
|
222
|
+
case type
|
223
|
+
when '='
|
224
|
+
store(key, args[0])
|
225
|
+
when '!'
|
226
|
+
@hash.__send__(key, *args, &blk)
|
227
|
+
# if key?(key)
|
228
|
+
# fetch(key)
|
229
|
+
# else
|
230
|
+
# store(key, OpenObject.new)
|
231
|
+
# end
|
232
|
+
when '?'
|
233
|
+
fetch(key)
|
234
|
+
else
|
235
|
+
fetch(key)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
# Core Extensions
|
242
|
+
|
243
|
+
class Hash
|
244
|
+
# Convert a Hash into an OpenObject.
|
245
|
+
def to_openobject
|
246
|
+
OpenObject[self]
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
=begin
|
251
|
+
class NilClass
|
252
|
+
# Nil converts to an empty OpenObject.
|
253
|
+
def to_openobject
|
254
|
+
OpenObject.new
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
class Proc
|
259
|
+
# Translates a Proc into an OpenObject. By droping an OpenObject into
|
260
|
+
# the Proc, the resulting assignments incured as the procedure is
|
261
|
+
# evaluated produce the OpenObject. This technique is simlar to that
|
262
|
+
# of MethodProbe.
|
263
|
+
#
|
264
|
+
# p = lambda { |x|
|
265
|
+
# x.word = "Hello"
|
266
|
+
# }
|
267
|
+
# o = p.to_openobject
|
268
|
+
# o.word #=> "Hello"
|
269
|
+
#
|
270
|
+
# NOTE The Proc must have an arity of one --no more and no less.
|
271
|
+
def to_openobject
|
272
|
+
raise ArgumentError, 'bad arity for converting Proc to openobject' if arity != 1
|
273
|
+
o = OpenObject.new
|
274
|
+
self.call( o )
|
275
|
+
o
|
276
|
+
end
|
277
|
+
end
|
278
|
+
=end
|
279
|
+
|
@@ -0,0 +1,417 @@
|
|
1
|
+
# = OrderedHash
|
2
|
+
#
|
3
|
+
# The OrderedHash class is a Hash that preserves order.
|
4
|
+
# So it has some array-like extensions also. By defualt
|
5
|
+
# an OrderedHash object preserves insertion order, but any
|
6
|
+
# order can be specified including alphabetical key order.
|
7
|
+
#
|
8
|
+
# == Usage
|
9
|
+
#
|
10
|
+
# Just require this file and use OrderedHash instead of Hash.
|
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
|
80
|
+
|
81
|
+
# Alternate to #new which creates a dictionary sorted by key.
|
82
|
+
#
|
83
|
+
# d = OrderedHash.alpha
|
84
|
+
# d["z"] = 1
|
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
|
96
|
+
|
97
|
+
# Alternate to #new which auto-creates sub-dictionaries as needed.
|
98
|
+
#
|
99
|
+
# d = OrderedHash.auto
|
100
|
+
# d["a"]["b"]["c"] = "abc" #=> { "a"=>{"b"=>{"c"=>"abc"}}}
|
101
|
+
#
|
102
|
+
def auto(*args)
|
103
|
+
#AutoOrderedHash.new(*args)
|
104
|
+
leet = lambda { |hsh, key| hsh[key] = new(&leet) }
|
105
|
+
new(*args, &leet)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# New Dictiionary.
|
110
|
+
|
111
|
+
def initialize(*args, &blk)
|
112
|
+
@order = []
|
113
|
+
@order_by = nil
|
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)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def order
|
124
|
+
reorder if @order_by
|
125
|
+
@order
|
126
|
+
end
|
127
|
+
|
128
|
+
# Keep dictionary sorted by a specific sort order.
|
129
|
+
|
130
|
+
def order_by( &block )
|
131
|
+
@order_by = block
|
132
|
+
order
|
133
|
+
self
|
134
|
+
end
|
135
|
+
|
136
|
+
# Keep dictionary sorted by key.
|
137
|
+
#
|
138
|
+
# d = OrderedHash.new.order_by_key
|
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
|
155
|
+
|
156
|
+
# Keep dictionary sorted by value.
|
157
|
+
#
|
158
|
+
# d = OrderedHash.new.order_by_value
|
159
|
+
# d["z"] = 1
|
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
|
173
|
+
|
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 }
|
179
|
+
end
|
180
|
+
@order
|
181
|
+
end
|
182
|
+
|
183
|
+
#def ==( hsh2 )
|
184
|
+
# return false if @order != hsh2.order
|
185
|
+
# super hsh2
|
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
|
194
|
+
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
|
+
|
205
|
+
# Store operator.
|
206
|
+
#
|
207
|
+
# h[key] = value
|
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)
|
218
|
+
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
|
+
|
282
|
+
def reject!( &block )
|
283
|
+
hsh2 = reject(&block)
|
284
|
+
self == hsh2 ? nil : hsh2
|
285
|
+
end
|
286
|
+
|
287
|
+
def replace(hsh2)
|
288
|
+
case hsh2
|
289
|
+
when Hash
|
290
|
+
@order = hsh2.keys
|
291
|
+
@hash = hsh2
|
292
|
+
else
|
293
|
+
@order = hsh2.order
|
294
|
+
@hash = hsh2.hash
|
295
|
+
end
|
296
|
+
reorder
|
297
|
+
end
|
298
|
+
|
299
|
+
def shift
|
300
|
+
key = order.first
|
301
|
+
key ? [key,delete(key)] : super
|
302
|
+
end
|
303
|
+
|
304
|
+
def unshift( k,v )
|
305
|
+
unless @hash.include?( k )
|
306
|
+
@order.unshift( k )
|
307
|
+
@hash.store( k,v )
|
308
|
+
true
|
309
|
+
else
|
310
|
+
false
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def <<(kv)
|
315
|
+
push(*kv)
|
316
|
+
end
|
317
|
+
|
318
|
+
def push( k,v )
|
319
|
+
unless @hash.include?( k )
|
320
|
+
@order.push( k )
|
321
|
+
@hash.store( k,v )
|
322
|
+
true
|
323
|
+
else
|
324
|
+
false
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def pop
|
329
|
+
key = order.last
|
330
|
+
key ? [key,delete(key)] : nil
|
331
|
+
end
|
332
|
+
|
333
|
+
def inspect
|
334
|
+
ary = []
|
335
|
+
each {|k,v| ary << k.inspect + "=>" + v.inspect}
|
336
|
+
'{' + ary.join(", ") + '}'
|
337
|
+
end
|
338
|
+
|
339
|
+
def dup
|
340
|
+
a = []
|
341
|
+
each{ |k,v| a << k; a << v }
|
342
|
+
self.class[*a]
|
343
|
+
end
|
344
|
+
|
345
|
+
def update( hsh2 )
|
346
|
+
hsh2.each { |k,v| self[k] = v }
|
347
|
+
reorder
|
348
|
+
self
|
349
|
+
end
|
350
|
+
alias :merge! update
|
351
|
+
|
352
|
+
def merge( hsh2 )
|
353
|
+
self.dup.update(hsh2)
|
354
|
+
end
|
355
|
+
|
356
|
+
def select
|
357
|
+
ary = []
|
358
|
+
each { |k,v| ary << [k,v] if yield k,v }
|
359
|
+
ary
|
360
|
+
end
|
361
|
+
|
362
|
+
def reverse!
|
363
|
+
@order.reverse!
|
364
|
+
self
|
365
|
+
end
|
366
|
+
|
367
|
+
def reverse
|
368
|
+
dup.reverse!
|
369
|
+
end
|
370
|
+
|
371
|
+
#
|
372
|
+
def first(x=nil)
|
373
|
+
return @hash[order.first] unless x
|
374
|
+
order.first(x).collect { |k| @hash[k] }
|
375
|
+
end
|
376
|
+
|
377
|
+
#
|
378
|
+
def last(x=nil)
|
379
|
+
return @hash[order.last] unless x
|
380
|
+
order.last(x).collect { |k| @hash[k] }
|
381
|
+
end
|
382
|
+
|
383
|
+
def length
|
384
|
+
@order.length
|
385
|
+
end
|
386
|
+
alias :size :length
|
387
|
+
|
388
|
+
def empty?
|
389
|
+
@hash.empty?
|
390
|
+
end
|
391
|
+
|
392
|
+
def has_key?(key)
|
393
|
+
@hash.has_key?(key)
|
394
|
+
end
|
395
|
+
|
396
|
+
def key?(key)
|
397
|
+
@hash.key?(key)
|
398
|
+
end
|
399
|
+
|
400
|
+
def to_a
|
401
|
+
ary = []
|
402
|
+
each { |k,v| ary << [k,v] }
|
403
|
+
ary
|
404
|
+
end
|
405
|
+
|
406
|
+
def to_s
|
407
|
+
self.to_a.to_s
|
408
|
+
end
|
409
|
+
|
410
|
+
def to_hash
|
411
|
+
@hash.dup
|
412
|
+
end
|
413
|
+
|
414
|
+
def to_h
|
415
|
+
@hash.dup
|
416
|
+
end
|
417
|
+
end
|