hashery 1.4.0 → 1.5.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/.ruby +57 -92
- data/.yardopts +8 -0
- data/COPYING.rdoc +45 -0
- data/HISTORY.rdoc +18 -0
- data/QED.rdoc +1 -0
- data/README.rdoc +42 -16
- data/lib/hashery.rb +16 -9
- data/lib/hashery.yml +57 -92
- data/lib/hashery/association.rb +3 -1
- data/lib/hashery/basic_object.rb +74 -0
- data/lib/hashery/basic_struct.rb +288 -1
- data/lib/hashery/basicobject.rb +1 -74
- data/lib/hashery/basicstruct.rb +1 -280
- data/lib/hashery/casting_hash.rb +171 -1
- data/lib/hashery/castinghash.rb +1 -171
- data/lib/hashery/core_ext.rb +82 -0
- data/lib/hashery/dictionary.rb +3 -0
- data/lib/hashery/fuzzy_hash.rb +154 -1
- data/lib/hashery/fuzzyhash.rb +1 -154
- data/lib/hashery/ini.rb +3 -2
- data/lib/hashery/key_hash.rb +186 -0
- data/lib/hashery/keyhash.rb +1 -0
- data/lib/hashery/linked_list.rb +195 -1
- data/lib/hashery/linkedlist.rb +1 -195
- data/lib/hashery/lru_hash.rb +273 -1
- data/lib/hashery/lruhash.rb +1 -273
- data/lib/hashery/open_cascade.rb +99 -1
- data/lib/hashery/open_hash.rb +77 -1
- data/lib/hashery/opencascade.rb +1 -99
- data/lib/hashery/openhash.rb +1 -77
- data/lib/hashery/ordered_hash.rb +168 -1
- data/lib/hashery/orderedhash.rb +1 -167
- data/lib/hashery/property_hash.rb +97 -1
- data/lib/hashery/propertyhash.rb +1 -97
- data/lib/hashery/query_hash.rb +35 -1
- data/lib/hashery/queryhash.rb +1 -35
- data/lib/hashery/stash.rb +3 -174
- data/lib/hashery/static_hash.rb +48 -1
- data/lib/hashery/statichash.rb +1 -48
- data/qed/06_opencascade.rdoc +12 -12
- data/test/case_association.rb +29 -15
- data/test/case_basicstruct.rb +192 -0
- data/test/case_dictionary.rb +149 -109
- data/test/case_keyhash.rb +175 -0
- data/test/case_opencascade.rb +89 -43
- data/test/case_openhash.rb +15 -11
- metadata +85 -78
- data/LICENSE +0 -206
- data/NOTICE +0 -11
- data/lib/hashery/sparse_array.rb +0 -1
- data/lib/hashery/sparsearray.rb +0 -577
- data/test/case_openobject.rb +0 -130
- data/test/case_sparsearray.rb +0 -316
- data/test/case_stash.rb +0 -131
data/lib/hashery/basicstruct.rb
CHANGED
@@ -1,280 +1 @@
|
|
1
|
-
require 'hashery/
|
2
|
-
|
3
|
-
#require 'facets/hash/to_h'
|
4
|
-
#require 'facets/kernel/object_class'
|
5
|
-
#require 'facets/kernel/object_hexid'
|
6
|
-
|
7
|
-
# = BasicStruct
|
8
|
-
#
|
9
|
-
# BasicObject is very similar to Ruby's own OpenStruct, but it offers some
|
10
|
-
# advantages. With OpenStruct, slots with the same name as predefined
|
11
|
-
# Object methods cannot be used. With BasicObject, almost any slot can be
|
12
|
-
# defined. BasicObject is a subclass of BasicObject to ensure all method
|
13
|
-
# slots, except those that are absolutely essential, are open for use.
|
14
|
-
#
|
15
|
-
#--
|
16
|
-
# If you wish to pass an BasicObject to a routine that normal takes a Hash,
|
17
|
-
# but are uncertain it can handle the distictions properly you can convert
|
18
|
-
# easily to a Hash using #as_hash! and the result will automatically be
|
19
|
-
# converted back to an BasicObject on return.
|
20
|
-
#
|
21
|
-
# o = BasicObject.new(:a=>1,:b=>2)
|
22
|
-
# o.as_hash!{ |h| h.update(:a=>6) }
|
23
|
-
# o #=> #<BasicObject {:a=>6,:b=>2}>
|
24
|
-
#++
|
25
|
-
#
|
26
|
-
# Unlike a Hash, all BasicObject's keys are symbols and all keys are converted
|
27
|
-
# to such using #to_sym on the fly.
|
28
|
-
|
29
|
-
class BasicStruct < BasicObject
|
30
|
-
|
31
|
-
#PUBLIC_METHODS = /(^__|^instance_|^object_|^\W|^as$|^send$|^class$|\?$)/
|
32
|
-
#protected(*public_instance_methods.select{ |m| m !~ PUBLIC_METHODS })
|
33
|
-
|
34
|
-
def self.[](hash=nil)
|
35
|
-
new(hash)
|
36
|
-
end
|
37
|
-
|
38
|
-
# Inititalizer for BasicObject is slightly different than that of Hash.
|
39
|
-
# It does not take a default parameter, but an initial priming Hash,
|
40
|
-
# like OpenStruct. The initializer can still take a default block
|
41
|
-
# however. To set the default value use <code>#default!(value)</code>.
|
42
|
-
#
|
43
|
-
# BasicObject.new(:a=>1).default!(0)
|
44
|
-
#
|
45
|
-
def initialize(hash=nil, &yld)
|
46
|
-
@table = Hash.new(&yld)
|
47
|
-
if hash
|
48
|
-
hash.each{ |k,v| store(k,v) }
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
#
|
53
|
-
def initialize_copy(orig)
|
54
|
-
orig.each{ |k,v| store(k,v) }
|
55
|
-
end
|
56
|
-
|
57
|
-
# Object inspection.
|
58
|
-
# TODO: Need to get __class__ and __id__ in hex form.
|
59
|
-
def inspect
|
60
|
-
#@table.inspect
|
61
|
-
hexid = __id__
|
62
|
-
klass = "BasicObject" # __class__
|
63
|
-
"#<#{klass}:#{hexid} #{@table.inspect}>"
|
64
|
-
end
|
65
|
-
|
66
|
-
# Convert to an associative array.
|
67
|
-
def to_a
|
68
|
-
@table.to_a
|
69
|
-
end
|
70
|
-
|
71
|
-
#
|
72
|
-
def to_h
|
73
|
-
@table.dup
|
74
|
-
end
|
75
|
-
|
76
|
-
#
|
77
|
-
def to_hash
|
78
|
-
@table.dup
|
79
|
-
end
|
80
|
-
|
81
|
-
#
|
82
|
-
def to_basicstruct
|
83
|
-
self
|
84
|
-
end
|
85
|
-
|
86
|
-
# Convert to an assignment procedure.
|
87
|
-
def to_proc(response=false)
|
88
|
-
hash = @table
|
89
|
-
if response
|
90
|
-
lambda do |o|
|
91
|
-
hash.each do |k,v|
|
92
|
-
o.__send__("#{k}=", v) rescue nil
|
93
|
-
end
|
94
|
-
end
|
95
|
-
else
|
96
|
-
lambda do |o|
|
97
|
-
hash.each{ |k,v| o.__send__("#{k}=", v) }
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
# NOT SURE ABOUT THIS
|
103
|
-
def as_hash
|
104
|
-
@table
|
105
|
-
end
|
106
|
-
|
107
|
-
# Is a given +key+ defined?
|
108
|
-
def key?(key)
|
109
|
-
@table.key?(key.to_sym)
|
110
|
-
end
|
111
|
-
|
112
|
-
#
|
113
|
-
def is_a?(klass)
|
114
|
-
return true if klass == Hash # TODO: Is this wise? How to fake a subclass?
|
115
|
-
return true if klass == BasicObject
|
116
|
-
false
|
117
|
-
end
|
118
|
-
|
119
|
-
# Iterate over each key-value pair.
|
120
|
-
def each(&yld)
|
121
|
-
@table.each(&yld)
|
122
|
-
end
|
123
|
-
|
124
|
-
# Set the default value.
|
125
|
-
def default!(default)
|
126
|
-
@table.default = default
|
127
|
-
end
|
128
|
-
|
129
|
-
# Check equality.
|
130
|
-
def ==( other )
|
131
|
-
case other
|
132
|
-
when BasicObject
|
133
|
-
@table == other.as_hash
|
134
|
-
when Hash
|
135
|
-
@table == other
|
136
|
-
else
|
137
|
-
if other.respond_to?(:to_hash)
|
138
|
-
@table == other.to_hash
|
139
|
-
else
|
140
|
-
false
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
#
|
146
|
-
def eql?( other )
|
147
|
-
case other
|
148
|
-
when BasicObject
|
149
|
-
@table.eql?(other.as_hash)
|
150
|
-
else
|
151
|
-
false
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
#
|
156
|
-
def <<(x)
|
157
|
-
case x
|
158
|
-
when Hash
|
159
|
-
@table.update(x)
|
160
|
-
when Array
|
161
|
-
x.each_slice(2) do |(k,v)|
|
162
|
-
@table[k] = v
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
#
|
168
|
-
def []=(key, value)
|
169
|
-
@table[key.to_sym] = value
|
170
|
-
end
|
171
|
-
|
172
|
-
#
|
173
|
-
def [](key)
|
174
|
-
@table[key.to_sym]
|
175
|
-
end
|
176
|
-
|
177
|
-
#
|
178
|
-
def merge!(other)
|
179
|
-
BasicObject.new(@table.merge!(other))
|
180
|
-
end
|
181
|
-
|
182
|
-
#
|
183
|
-
def update!(other)
|
184
|
-
@table.update(other)
|
185
|
-
self
|
186
|
-
end
|
187
|
-
|
188
|
-
protected
|
189
|
-
|
190
|
-
def store(k, v)
|
191
|
-
@table.store(k.to_sym, v)
|
192
|
-
end
|
193
|
-
|
194
|
-
def fetch(k, *d, &b)
|
195
|
-
@table.fetch(k.to_sym, *d, &b)
|
196
|
-
end
|
197
|
-
|
198
|
-
#def as_hash!
|
199
|
-
# Functor.new do |op,*a,&b|
|
200
|
-
# result = @table.__send__(op,*a,&b)
|
201
|
-
# case result
|
202
|
-
# when Hash
|
203
|
-
# BasicObject.new(result)
|
204
|
-
# else
|
205
|
-
# result
|
206
|
-
# end
|
207
|
-
# end
|
208
|
-
#end
|
209
|
-
|
210
|
-
#def define_slot(key, value=nil)
|
211
|
-
# @table[key.to_sym] = value
|
212
|
-
#end
|
213
|
-
|
214
|
-
#def protect_slot( key )
|
215
|
-
# (class << self; self; end).class_eval {
|
216
|
-
# protected key rescue nil
|
217
|
-
# }
|
218
|
-
#end
|
219
|
-
|
220
|
-
def method_missing(sym, *args, &blk)
|
221
|
-
type = sym.to_s[-1,1]
|
222
|
-
key = sym.to_s.sub(/[=?!]$/,'').to_sym
|
223
|
-
case type
|
224
|
-
when '='
|
225
|
-
store(key, args[0])
|
226
|
-
when '!'
|
227
|
-
@table.__send__(key, *args, &blk)
|
228
|
-
# if key?(key)
|
229
|
-
# fetch(key)
|
230
|
-
# else
|
231
|
-
# store(key, BasicObject.new)
|
232
|
-
# end
|
233
|
-
when '?'
|
234
|
-
fetch(key)
|
235
|
-
else
|
236
|
-
fetch(key)
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
end
|
241
|
-
|
242
|
-
# Core Extensions
|
243
|
-
|
244
|
-
class Hash
|
245
|
-
# Convert a Hash into a BasicStruct.
|
246
|
-
def to_basicstruct
|
247
|
-
BasicStruct[self]
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
=begin
|
252
|
-
class NilClass
|
253
|
-
# Nil converts to an empty BasicObject.
|
254
|
-
def to_basicstruct
|
255
|
-
BasicObject.new
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
class Proc
|
260
|
-
# Translates a Proc into an BasicObject. By droping an BasicObject into
|
261
|
-
# the Proc, the resulting assignments incured as the procedure is
|
262
|
-
# evaluated produce the BasicObject. This technique is simlar to that
|
263
|
-
# of MethodProbe.
|
264
|
-
#
|
265
|
-
# p = lambda { |x|
|
266
|
-
# x.word = "Hello"
|
267
|
-
# }
|
268
|
-
# o = p.to_basicstruct
|
269
|
-
# o.word #=> "Hello"
|
270
|
-
#
|
271
|
-
# NOTE The Proc must have an arity of one --no more and no less.
|
272
|
-
def to_basicstruct
|
273
|
-
raise ArgumentError, 'bad arity for converting Proc to basicstruct' if arity != 1
|
274
|
-
o = BasicObject.new
|
275
|
-
self.call( o )
|
276
|
-
o
|
277
|
-
end
|
278
|
-
end
|
279
|
-
=end
|
280
|
-
|
1
|
+
require 'hashery/basic_struct'
|
data/lib/hashery/casting_hash.rb
CHANGED
@@ -1 +1,171 @@
|
|
1
|
-
|
1
|
+
# CastingHash is just like Hash, except that all keys and values
|
2
|
+
# are passed through casting procedures.
|
3
|
+
#--
|
4
|
+
# TODO: Handle default_proc.
|
5
|
+
#++
|
6
|
+
class CastingHash < Hash
|
7
|
+
|
8
|
+
# Default key conversion procedure.
|
9
|
+
KEY_PROC = lambda{ |x| x } #.to_s }
|
10
|
+
|
11
|
+
# Default value conversion procedure.
|
12
|
+
VAL_PROC = lambda{ |x| x }
|
13
|
+
|
14
|
+
#
|
15
|
+
def self.[](hash)
|
16
|
+
s = new
|
17
|
+
hash.each{ |k,v| s[k] = v }
|
18
|
+
s
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
def initialize(hash={}, value_cast=nil, &key_cast)
|
23
|
+
@key_proc = (key_cast || KEY_PROC)
|
24
|
+
@value_proc = (value_cast || VAL_PROC).to_proc
|
25
|
+
hash.each{ |k,v| self[k] = v }
|
26
|
+
end
|
27
|
+
|
28
|
+
#
|
29
|
+
def key_proc
|
30
|
+
@key_proc
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
def key_proc=(proc)
|
35
|
+
@key_proc = proc.to_proc
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
def value_proc
|
40
|
+
@value_proc
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
def value_proc=(proc)
|
45
|
+
@value_proc = proc.to_proc
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
def [](k)
|
50
|
+
super(key_proc[k])
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
def []=(k,v)
|
55
|
+
super(key_proc[k], value_proc[v])
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
def <<(other)
|
60
|
+
case other
|
61
|
+
when Hash
|
62
|
+
super(cast(other))
|
63
|
+
when Array
|
64
|
+
self[other[0]] = other[1]
|
65
|
+
else
|
66
|
+
raise ArgumentError
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def fetch(k)
|
71
|
+
super(key_proc[k])
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
def store(k, v)
|
76
|
+
super(key_proc[k], value_proc[v])
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
def key?(k)
|
81
|
+
super(key_proc[k])
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
def has_key?(k)
|
86
|
+
super(key_proc[k])
|
87
|
+
end
|
88
|
+
|
89
|
+
# Synonym for Hash#rekey, but modifies the receiver in place (and returns it).
|
90
|
+
#
|
91
|
+
# foo = { :name=>'Gavin', :wife=>:Lisa }.to_stash
|
92
|
+
# foo.rekey!{ |k| k.upcase } #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
|
93
|
+
# foo.inspect #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
|
94
|
+
#
|
95
|
+
def rekey!(*args, &block)
|
96
|
+
# for backward comptability (DEPRECATE?).
|
97
|
+
block = args.pop.to_sym.to_proc if args.size == 1
|
98
|
+
if args.empty?
|
99
|
+
block = lambda{|k| k} unless block
|
100
|
+
keys.each do |k|
|
101
|
+
nk = block[k]
|
102
|
+
self[nk] = delete(k) #if nk
|
103
|
+
end
|
104
|
+
else
|
105
|
+
raise ArgumentError, "3 for 2" if block
|
106
|
+
to, from = *args
|
107
|
+
self[to] = delete(from) if has_key?(from)
|
108
|
+
end
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
def rekey(*args, &block)
|
114
|
+
dup.rekey!(*args, &block)
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
def delete(k)
|
119
|
+
super(key_proc[k])
|
120
|
+
end
|
121
|
+
|
122
|
+
#
|
123
|
+
def update(other)
|
124
|
+
super(cast(other))
|
125
|
+
end
|
126
|
+
|
127
|
+
# Same as #update.
|
128
|
+
def merge!(other)
|
129
|
+
super(cast(other))
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
def replace(other)
|
134
|
+
super(cast(other))
|
135
|
+
end
|
136
|
+
|
137
|
+
#
|
138
|
+
def values_at(*keys)
|
139
|
+
super(keys.map(&key_proc))
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
def to_hash
|
144
|
+
h = {}; each{ |k,v| h[k] = v }; h
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
alias_method :to_h, :to_hash
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
#
|
153
|
+
def cast(hash)
|
154
|
+
h
|
155
|
+
hash.each do |k,v|
|
156
|
+
h[key_proc[k]] = value_proc[v]
|
157
|
+
end
|
158
|
+
h
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
#class Hash
|
165
|
+
#
|
166
|
+
# # Convert a Hash to a CastingHash.
|
167
|
+
# def to_casting_hash(value_cast=nil, &key_cast)
|
168
|
+
# CastingHash.new(self, value_cast, &key_cast)
|
169
|
+
# end
|
170
|
+
#
|
171
|
+
#end
|