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/association.rb
CHANGED
@@ -7,7 +7,9 @@
|
|
7
7
|
# link-lists, simple ordered maps and mixed collections,
|
8
8
|
# among them.
|
9
9
|
#
|
10
|
-
# NOTE: This class is still fairly experimental.
|
10
|
+
# NOTE: This class is still fairly experimental. And it is not
|
11
|
+
# loaded along with the other Hashery libraries when using
|
12
|
+
# `require 'hashery'`.
|
11
13
|
#
|
12
14
|
# == Usage
|
13
15
|
#
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# Facets' BasicObject is an implementation of Jim Weirich's BlankSlate.
|
2
|
+
#
|
3
|
+
# BlankSlate
|
4
|
+
# Copyright 2004 by Jim Weirich (jim@weirichhouse.org).
|
5
|
+
# All rights reserved.
|
6
|
+
#
|
7
|
+
# Since Ruby 1.9 has a BasicObject class this will of course be
|
8
|
+
# deprecated as 1.9 goes mainstream.
|
9
|
+
|
10
|
+
unless defined? BasicObject # in case it already exists!
|
11
|
+
|
12
|
+
# BasicObject provides an abstract base class with no predefined
|
13
|
+
# methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
|
14
|
+
# BlankSlate is useful as a base class when writing classes that
|
15
|
+
# depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
|
16
|
+
class BasicObject
|
17
|
+
class << self
|
18
|
+
# Hide the method named +name+ in the BlankSlate class. Don't
|
19
|
+
# hide +instance_eval+ or any method beginning with "__".
|
20
|
+
#
|
21
|
+
# According to 1.9.1 it should have only these methods:
|
22
|
+
#
|
23
|
+
# * #__send__
|
24
|
+
# * #instance_eval
|
25
|
+
# * #instance_exec
|
26
|
+
# * #equal?
|
27
|
+
# * #==
|
28
|
+
# * #!
|
29
|
+
# * #!=
|
30
|
+
# * respond_to?
|
31
|
+
#
|
32
|
+
# Seems to me it should have #__id__ too.
|
33
|
+
def hide(name)
|
34
|
+
undef_method name if
|
35
|
+
instance_methods.include?(name.to_s) and
|
36
|
+
name !~ /^(__|respond_to\?|instance_eval$|instance_exec$|equal\?$|\=\=$)/
|
37
|
+
end
|
38
|
+
end
|
39
|
+
instance_methods.each{ |m| hide(m) }
|
40
|
+
end
|
41
|
+
|
42
|
+
# Since Ruby is very dynamic, methods added to the ancestors of
|
43
|
+
# BlankSlate <em>after BlankSlate is defined</em> will show up in the
|
44
|
+
# list of available BlankSlate methods. We handle this by defining a
|
45
|
+
# hook in the Object and Kernel classes that will hide any defined
|
46
|
+
module Kernel #:nodoc:
|
47
|
+
class << self
|
48
|
+
alias_method :basic_object_method_added, :method_added
|
49
|
+
|
50
|
+
# Detect method additions to Kernel and remove them in the
|
51
|
+
# BlankSlate class.
|
52
|
+
def method_added(name)
|
53
|
+
basic_object_method_added(name)
|
54
|
+
return if self != Kernel
|
55
|
+
BasicObject.hide(name)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Object #:nodoc:
|
61
|
+
class << self
|
62
|
+
alias_method :basic_object_method_added, :method_added
|
63
|
+
|
64
|
+
# Detect method additions to Object and remove them in the
|
65
|
+
# BlankSlate class.
|
66
|
+
def method_added(name)
|
67
|
+
basic_object_method_added(name)
|
68
|
+
return if self != Object
|
69
|
+
BasicObject.hide(name)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
data/lib/hashery/basic_struct.rb
CHANGED
@@ -1 +1,288 @@
|
|
1
|
-
|
1
|
+
unless defined?(BasicObject)
|
2
|
+
require 'blankslate'
|
3
|
+
BasicObject = BlankSlate
|
4
|
+
end
|
5
|
+
|
6
|
+
# = BasicStruct
|
7
|
+
#
|
8
|
+
# BasicStruct 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 cannot be used. With BasicStruct, almost any slot can be
|
11
|
+
# defined. BasicStruct 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 a BasicStruct 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 BasicStruct on return.
|
19
|
+
#
|
20
|
+
# o = BasicStruct.new(:a=>1,:b=>2)
|
21
|
+
# o.as_hash!{ |h| h.update(:a=>6) }
|
22
|
+
# o #=> #<BasicObject {:a=>6,:b=>2}>
|
23
|
+
#++
|
24
|
+
#
|
25
|
+
# Unlike a Hash, all BasicStruct's keys are symbols and all keys are converted
|
26
|
+
# to such using #to_sym on the fly.
|
27
|
+
|
28
|
+
class BasicStruct < 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 BasicObject 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
|
+
# BasicObject.new(:a=>1).default!(0)
|
43
|
+
#
|
44
|
+
def initialize(hash=nil, &yld)
|
45
|
+
@table = ::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
|
+
#@table.inspect
|
60
|
+
hexid = __id__
|
61
|
+
klass = "BasicObject" # __class__
|
62
|
+
"#<#{klass}:#{hexid} #{@table.inspect}>"
|
63
|
+
end
|
64
|
+
|
65
|
+
# Convert to an associative array.
|
66
|
+
def to_a
|
67
|
+
@table.to_a
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
def to_h
|
72
|
+
@table.dup
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
def to_hash
|
77
|
+
@table.dup
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
def to_basicstruct
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
# Convert to an assignment procedure.
|
86
|
+
def to_proc(response=false)
|
87
|
+
hash = @table
|
88
|
+
if response
|
89
|
+
::Proc.new do |o|
|
90
|
+
hash.each do |k,v|
|
91
|
+
o.__send__("#{k}=", v) rescue nil
|
92
|
+
end
|
93
|
+
end
|
94
|
+
else
|
95
|
+
::Proc.new 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
|
+
@table
|
104
|
+
end
|
105
|
+
|
106
|
+
# Is a given +key+ defined?
|
107
|
+
def key?(key)
|
108
|
+
@table.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 == ::BasicObject
|
115
|
+
false
|
116
|
+
end
|
117
|
+
|
118
|
+
# Iterate over each key-value pair.
|
119
|
+
def each(&yld)
|
120
|
+
@table.each(&yld)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Set the default value.
|
124
|
+
def default!(default)
|
125
|
+
@table.default = default
|
126
|
+
end
|
127
|
+
|
128
|
+
# Check equality.
|
129
|
+
def ==( other )
|
130
|
+
case other
|
131
|
+
when ::BasicStruct
|
132
|
+
@table == other.as_hash
|
133
|
+
when ::Hash
|
134
|
+
@table == other
|
135
|
+
else
|
136
|
+
if other.respond_to?(:to_hash)
|
137
|
+
@table == other.to_hash
|
138
|
+
else
|
139
|
+
false
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
def eql?( other )
|
146
|
+
case other
|
147
|
+
when ::BasicStruct
|
148
|
+
@table.eql?(other.as_hash)
|
149
|
+
else
|
150
|
+
false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
def <<(x)
|
156
|
+
case x
|
157
|
+
when ::Hash
|
158
|
+
@table.update(x)
|
159
|
+
when ::Array
|
160
|
+
x.each_slice(2) do |(k,v)|
|
161
|
+
@table[k] = v
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
#
|
167
|
+
def []=(key, value)
|
168
|
+
@table[key.to_sym] = value
|
169
|
+
end
|
170
|
+
|
171
|
+
#
|
172
|
+
def [](key)
|
173
|
+
@table[key.to_sym]
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
def merge!(other)
|
178
|
+
BasicObject.new(@table.merge!(other))
|
179
|
+
end
|
180
|
+
|
181
|
+
#
|
182
|
+
def update!(other)
|
183
|
+
@table.update(other)
|
184
|
+
self
|
185
|
+
end
|
186
|
+
|
187
|
+
#
|
188
|
+
def respond_to?(key)
|
189
|
+
key?(key)
|
190
|
+
end
|
191
|
+
|
192
|
+
# NOTE: These were protected, why?
|
193
|
+
|
194
|
+
#
|
195
|
+
def store(k, v)
|
196
|
+
@table.store(k.to_sym, v)
|
197
|
+
end
|
198
|
+
|
199
|
+
#
|
200
|
+
def fetch(k, *d, &b)
|
201
|
+
@table.fetch(k.to_sym, *d, &b)
|
202
|
+
end
|
203
|
+
|
204
|
+
protected
|
205
|
+
|
206
|
+
#def as_hash!
|
207
|
+
# Functor.new do |op,*a,&b|
|
208
|
+
# result = @table.__send__(op,*a,&b)
|
209
|
+
# case result
|
210
|
+
# when Hash
|
211
|
+
# BasicObject.new(result)
|
212
|
+
# else
|
213
|
+
# result
|
214
|
+
# end
|
215
|
+
# end
|
216
|
+
#end
|
217
|
+
|
218
|
+
#def define_slot(key, value=nil)
|
219
|
+
# @table[key.to_sym] = value
|
220
|
+
#end
|
221
|
+
|
222
|
+
#def protect_slot( key )
|
223
|
+
# (class << self; self; end).class_eval {
|
224
|
+
# protected key rescue nil
|
225
|
+
# }
|
226
|
+
#end
|
227
|
+
|
228
|
+
def method_missing(sym, *args, &blk)
|
229
|
+
type = sym.to_s[-1,1]
|
230
|
+
key = sym.to_s.sub(/[=?!]$/,'').to_sym
|
231
|
+
case type
|
232
|
+
when '='
|
233
|
+
store(key, args[0])
|
234
|
+
when '!'
|
235
|
+
@table.__send__(key, *args, &blk)
|
236
|
+
# if key?(key)
|
237
|
+
# fetch(key)
|
238
|
+
# else
|
239
|
+
# store(key, BasicObject.new)
|
240
|
+
# end
|
241
|
+
when '?'
|
242
|
+
fetch(key)
|
243
|
+
else
|
244
|
+
fetch(key)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
|
250
|
+
# Core Extensions
|
251
|
+
|
252
|
+
class Hash
|
253
|
+
# Convert a Hash into a BasicStruct.
|
254
|
+
def to_basicstruct
|
255
|
+
BasicStruct[self]
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
=begin
|
260
|
+
class NilClass
|
261
|
+
# Nil converts to an empty BasicObject.
|
262
|
+
def to_basicstruct
|
263
|
+
BasicObject.new
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
class Proc
|
268
|
+
# Translates a Proc into an BasicObject. By droping an BasicObject into
|
269
|
+
# the Proc, the resulting assignments incured as the procedure is
|
270
|
+
# evaluated produce the BasicObject. This technique is simlar to that
|
271
|
+
# of MethodProbe.
|
272
|
+
#
|
273
|
+
# p = lambda { |x|
|
274
|
+
# x.word = "Hello"
|
275
|
+
# }
|
276
|
+
# o = p.to_basicstruct
|
277
|
+
# o.word #=> "Hello"
|
278
|
+
#
|
279
|
+
# NOTE The Proc must have an arity of one --no more and no less.
|
280
|
+
def to_basicstruct
|
281
|
+
raise ArgumentError, 'bad arity for converting Proc to basicstruct' if arity != 1
|
282
|
+
o = BasicObject.new
|
283
|
+
self.call( o )
|
284
|
+
o
|
285
|
+
end
|
286
|
+
end
|
287
|
+
=end
|
288
|
+
|
data/lib/hashery/basicobject.rb
CHANGED
@@ -1,74 +1 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
# BlankSlate
|
4
|
-
# Copyright 2004 by Jim Weirich (jim@weirichhouse.org).
|
5
|
-
# All rights reserved.
|
6
|
-
#
|
7
|
-
# Since Ruby 1.9 has a BasicObject class this will of course be
|
8
|
-
# deprecated as 1.9 goes mainstream.
|
9
|
-
|
10
|
-
unless defined? BasicObject # in case it already exists!
|
11
|
-
|
12
|
-
# BasicObject provides an abstract base class with no predefined
|
13
|
-
# methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
|
14
|
-
# BlankSlate is useful as a base class when writing classes that
|
15
|
-
# depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
|
16
|
-
class BasicObject
|
17
|
-
class << self
|
18
|
-
# Hide the method named +name+ in the BlankSlate class. Don't
|
19
|
-
# hide +instance_eval+ or any method beginning with "__".
|
20
|
-
#
|
21
|
-
# According to 1.9.1 it should have only these methods:
|
22
|
-
#
|
23
|
-
# * #__send__
|
24
|
-
# * #instance_eval
|
25
|
-
# * #instance_exec
|
26
|
-
# * #equal?
|
27
|
-
# * #==
|
28
|
-
# * #!
|
29
|
-
# * #!=
|
30
|
-
# * respond_to?
|
31
|
-
#
|
32
|
-
# Seems to me it should have #__id__ too.
|
33
|
-
def hide(name)
|
34
|
-
undef_method name if
|
35
|
-
instance_methods.include?(name.to_s) and
|
36
|
-
name !~ /^(__|respond_to\?|instance_eval$|instance_exec$|equal\?$|\=\=$)/
|
37
|
-
end
|
38
|
-
end
|
39
|
-
instance_methods.each{ |m| hide(m) }
|
40
|
-
end
|
41
|
-
|
42
|
-
# Since Ruby is very dynamic, methods added to the ancestors of
|
43
|
-
# BlankSlate <em>after BlankSlate is defined</em> will show up in the
|
44
|
-
# list of available BlankSlate methods. We handle this by defining a
|
45
|
-
# hook in the Object and Kernel classes that will hide any defined
|
46
|
-
module Kernel #:nodoc:
|
47
|
-
class << self
|
48
|
-
alias_method :basic_object_method_added, :method_added
|
49
|
-
|
50
|
-
# Detect method additions to Kernel and remove them in the
|
51
|
-
# BlankSlate class.
|
52
|
-
def method_added(name)
|
53
|
-
basic_object_method_added(name)
|
54
|
-
return if self != Kernel
|
55
|
-
BasicObject.hide(name)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
class Object #:nodoc:
|
61
|
-
class << self
|
62
|
-
alias_method :basic_object_method_added, :method_added
|
63
|
-
|
64
|
-
# Detect method additions to Object and remove them in the
|
65
|
-
# BlankSlate class.
|
66
|
-
def method_added(name)
|
67
|
-
basic_object_method_added(name)
|
68
|
-
return if self != Object
|
69
|
-
BasicObject.hide(name)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
1
|
+
require 'hasery/basic_object'
|