hashery 1.5.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby +30 -17
- data/.yardopts +1 -0
- data/Config.rb +28 -0
- data/{QED.rdoc → DEMO.rdoc} +0 -0
- data/HISTORY.rdoc +37 -0
- data/LICENSE.txt +26 -0
- data/NOTICE.txt +46 -0
- data/README.rdoc +10 -7
- data/lib/hashery.rb +6 -6
- data/lib/hashery.yml +30 -17
- data/lib/hashery/association.rb +169 -109
- data/lib/hashery/casting_hash.rb +128 -135
- data/lib/hashery/core_ext.rb +89 -61
- data/lib/hashery/crud_hash.rb +365 -0
- data/lib/hashery/dictionary.rb +545 -345
- data/lib/hashery/fuzzy_hash.rb +177 -125
- data/lib/hashery/ini_hash.rb +321 -0
- data/lib/hashery/key_hash.rb +54 -179
- data/lib/hashery/linked_list.rb +245 -191
- data/lib/hashery/lru_hash.rb +292 -202
- data/lib/hashery/open_cascade.rb +133 -78
- data/lib/hashery/open_hash.rb +127 -61
- data/lib/hashery/ordered_hash.rb +128 -122
- data/lib/hashery/path_hash.rb +238 -0
- data/lib/hashery/property_hash.rb +144 -80
- data/lib/hashery/query_hash.rb +85 -29
- data/lib/hashery/stash.rb +7 -3
- data/lib/hashery/static_hash.rb +46 -41
- data/test/case_association.rb +65 -4
- data/test/case_dictionary.rb +149 -5
- data/test/{case_keyhash.rb → case_key_hash.rb} +20 -14
- data/test/case_lru_hash.rb +162 -0
- data/test/{case_opencascade.rb → case_open_cascade.rb} +4 -8
- data/test/case_open_hash.rb +87 -0
- data/test/case_query_hash.rb +226 -0
- data/test/helper.rb +8 -0
- metadata +33 -63
- data/COPYING.rdoc +0 -45
- data/lib/hashery/basic_object.rb +0 -74
- data/lib/hashery/basic_struct.rb +0 -288
- data/lib/hashery/basicobject.rb +0 -1
- data/lib/hashery/basicstruct.rb +0 -1
- data/lib/hashery/castinghash.rb +0 -1
- data/lib/hashery/fuzzyhash.rb +0 -1
- data/lib/hashery/ini.rb +0 -268
- data/lib/hashery/keyhash.rb +0 -1
- data/lib/hashery/linkedlist.rb +0 -1
- data/lib/hashery/lruhash.rb +0 -1
- data/lib/hashery/memoizer.rb +0 -64
- data/lib/hashery/open_object.rb +0 -1
- data/lib/hashery/opencascade.rb +0 -1
- data/lib/hashery/openhash.rb +0 -1
- data/lib/hashery/openobject.rb +0 -1
- data/lib/hashery/orderedhash.rb +0 -1
- data/lib/hashery/ostructable.rb +0 -186
- data/lib/hashery/propertyhash.rb +0 -1
- data/lib/hashery/queryhash.rb +0 -1
- data/lib/hashery/statichash.rb +0 -1
- data/qed/01_openhash.rdoc +0 -57
- data/qed/02_queryhash.rdoc +0 -21
- data/qed/03_castinghash.rdoc +0 -13
- data/qed/04_statichash.rdoc +0 -22
- data/qed/05_association.rdoc +0 -59
- data/qed/06_opencascade.rdoc +0 -58
- data/qed/07_fuzzyhash.rdoc +0 -141
- data/qed/08_properyhash.rdoc +0 -38
- data/qed/09_ostructable.rdoc +0 -56
- data/qed/applique/ae.rb +0 -1
- data/test/case_basicstruct.rb +0 -192
- data/test/case_openhash.rb +0 -22
data/lib/hashery/query_hash.rb
CHANGED
@@ -1,35 +1,91 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
# QueryHash is a similar to OpenHash. Like OpenHash,
|
4
|
-
# entries can be assigned via setter methods, but
|
5
|
-
# entries can only be looked up via query methods
|
6
|
-
# (i.e. methods ending in a ?-mark), hence the name
|
7
|
-
# of this class.
|
8
|
-
#
|
9
|
-
# A QueryHash is not quite as elegant as an OpenHash
|
10
|
-
# in that reader methods must end in ?-marks, but
|
11
|
-
# it remains fully compatible with Hash regardless
|
12
|
-
# of it's settings.
|
13
|
-
|
14
|
-
class QueryHash < Hash
|
15
|
-
|
16
|
-
def to_h
|
17
|
-
dup
|
18
|
-
end
|
1
|
+
module Hashery
|
19
2
|
|
20
|
-
|
21
|
-
|
22
|
-
|
3
|
+
require 'hashery/key_hash'
|
4
|
+
|
5
|
+
# QueryHash is essentially a Hash class, but with some OpenStruct-like features.
|
6
|
+
#
|
7
|
+
# q = QueryHash.new
|
8
|
+
#
|
9
|
+
# Entries can be added to the Hash via a setter method.
|
10
|
+
#
|
11
|
+
# q.a = 1
|
12
|
+
#
|
13
|
+
# Then looked up via a query method.
|
14
|
+
#
|
15
|
+
# q.a? #=> 1
|
16
|
+
#
|
17
|
+
# The can also be looked up via a bang method.
|
18
|
+
#
|
19
|
+
# q.a! #=> 1
|
20
|
+
#
|
21
|
+
# The difference between query methods and bang methods is that the bang method
|
22
|
+
# will auto-instantiate the entry if not present, where as a query method will not.
|
23
|
+
#
|
24
|
+
# A QueryHash might not be quite as elegant as an OpenHash in that reader
|
25
|
+
# methods must end in `?` or `!`, but it remains fully compatible with Hash
|
26
|
+
# regardless of it's settings.
|
27
|
+
#
|
28
|
+
class QueryHash < CRUDHash
|
23
29
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
#
|
31
|
+
# By default the `key_proc` is set to convert all keys to strings via `#to_s`.
|
32
|
+
#
|
33
|
+
# default - Default object, or
|
34
|
+
# default_proc - Default procedure.
|
35
|
+
#
|
36
|
+
def initialize(*default, &default_proc)
|
37
|
+
@key_proc = Proc.new{ |k| k.to_s }
|
38
|
+
super(*default, &default_proc)
|
32
39
|
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Route get and set calls.
|
43
|
+
#
|
44
|
+
# s - [Symbol] Name of method.
|
45
|
+
# a - [Array] Method arguments.
|
46
|
+
# b - [Proc] Block argument.
|
47
|
+
#
|
48
|
+
# Examples
|
49
|
+
#
|
50
|
+
# o = QueryHash.new
|
51
|
+
# o.a = 1
|
52
|
+
# o.a? #=> 1
|
53
|
+
# o.b? #=> nil
|
54
|
+
#
|
55
|
+
def method_missing(s,*a, &b)
|
56
|
+
type = s.to_s[-1,1]
|
57
|
+
name = s.to_s.sub(/[!?=]$/, '')
|
58
|
+
key = name #key = cast_key(name)
|
59
|
+
|
60
|
+
case type
|
61
|
+
when '='
|
62
|
+
store(key, a.first)
|
63
|
+
when '!'
|
64
|
+
default = (default_proc ? default_proc.call(self, key) : default)
|
65
|
+
key?(key) ? fetch(key) : store(key, default)
|
66
|
+
when '?'
|
67
|
+
key?(key) ? fetch(key) : nil
|
68
|
+
else
|
69
|
+
# return self[key] if key?(key)
|
70
|
+
super(s,*a,&b)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Custom #respond_to to account for #method_missing.
|
76
|
+
#
|
77
|
+
# name - The method name to check.
|
78
|
+
#
|
79
|
+
# Returns `true` or `false`.
|
80
|
+
#
|
81
|
+
def respond_to?(name)
|
82
|
+
return true if name.to_s.end_with?('=')
|
83
|
+
return true if name.to_s.end_with?('?')
|
84
|
+
return true if name.to_s.end_with?('!')
|
85
|
+
#key?(name.to_sym) || super(name)
|
86
|
+
super(name)
|
87
|
+
end
|
88
|
+
|
33
89
|
end
|
34
90
|
|
35
91
|
end
|
data/lib/hashery/stash.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
-
require 'hashery/
|
1
|
+
require 'hashery/key_hash'
|
2
2
|
|
3
|
-
|
3
|
+
module Hashery
|
4
|
+
# Stash is the original name for the KeyHash.
|
5
|
+
Stash = KeyHash
|
6
|
+
end
|
4
7
|
|
5
8
|
class Hash
|
6
9
|
# Convert Hash to Stash.
|
7
10
|
def to_stash
|
8
|
-
Stash[self]
|
11
|
+
Hashery::Stash[self]
|
9
12
|
end
|
10
13
|
end
|
14
|
+
|
data/lib/hashery/static_hash.rb
CHANGED
@@ -1,48 +1,53 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
# A Hash object which raises an error if any
|
4
|
-
# previously-defined key attempts to be set again.
|
5
|
-
#
|
6
|
-
# == Synopsis
|
7
|
-
#
|
8
|
-
# foo = StaticHash.new
|
9
|
-
# foo['name'] = 'Tom' #=> 'Tom'
|
10
|
-
# foo['age'] = 30 #=> 30
|
11
|
-
# foo['name'] = 'Bob'
|
12
|
-
#
|
13
|
-
# _produces_
|
14
|
-
#
|
15
|
-
# ArgumentError: Duplicate key for StaticHash -- 'name'
|
16
|
-
#
|
17
|
-
# == Credit
|
18
|
-
#
|
19
|
-
# StaticHash has it's orgins in Gavin Kistner's WriteOnceHash
|
20
|
-
# class found in his +basiclibrary.rb+ script.
|
1
|
+
module Hashery
|
21
2
|
|
22
|
-
|
23
|
-
|
24
|
-
#
|
25
|
-
#
|
3
|
+
# StaticHash ia a Hash object which raises an error if any
|
4
|
+
# previously-defined key attempts to be set again.
|
5
|
+
#
|
6
|
+
# foo = StaticHash.new
|
7
|
+
# foo['name'] = 'Tom' #=> 'Tom'
|
8
|
+
# foo['age'] = 30 #=> 30
|
9
|
+
# foo['name'] = 'Bob'
|
10
|
+
#
|
11
|
+
# produces
|
12
|
+
#
|
13
|
+
# ArgumentError: Duplicate key for StaticHash -- 'name'
|
14
|
+
#
|
15
|
+
# StaticHash has it's orgins in Gavin Kistner's WriteOnceHash
|
16
|
+
# class found in his +basiclibrary.rb+ script.
|
17
|
+
#
|
18
|
+
# TODO: Maybe StaticHash isn't bets name for this class?
|
19
|
+
#
|
20
|
+
class StaticHash < CRUDHash
|
26
21
|
|
27
|
-
|
28
|
-
|
29
|
-
|
22
|
+
#
|
23
|
+
# Set a value for a key. Raises an error if that key already
|
24
|
+
# exists with a different value.
|
25
|
+
#
|
26
|
+
# key - Index key to associate with value.
|
27
|
+
# value - Value to associate with key.
|
28
|
+
#
|
29
|
+
# Retruns value.
|
30
|
+
#
|
31
|
+
def store(key, value)
|
32
|
+
if key?(key) && read(key) != value
|
33
|
+
raise ArgumentError, "Duplicate key for StaticHash -- #{key.inspect}"
|
34
|
+
end
|
35
|
+
super(key, value)
|
30
36
|
end
|
31
|
-
super(key, value)
|
32
|
-
end
|
33
37
|
|
34
|
-
|
35
|
-
|
36
|
-
dups = (keys | hash.keys)
|
37
|
-
if dups.empty?
|
38
|
-
|
39
|
-
else
|
40
|
-
|
41
|
-
end
|
42
|
-
|
38
|
+
#
|
39
|
+
#def update(hash)
|
40
|
+
# dups = (keys | hash.keys)
|
41
|
+
# if dups.empty?
|
42
|
+
# super(hash)
|
43
|
+
# else
|
44
|
+
# raise ArgumentError, "Duplicate key for StaticHash -- #{dups.inspect}"
|
45
|
+
# end
|
46
|
+
#end
|
43
47
|
|
44
|
-
|
45
|
-
|
48
|
+
#
|
49
|
+
#alias_method :merge!, :update
|
46
50
|
|
47
|
-
end
|
51
|
+
end
|
48
52
|
|
53
|
+
end
|
data/test/case_association.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
require 'ae'
|
1
|
+
require 'helper'
|
3
2
|
|
3
|
+
# must be required independently
|
4
4
|
require 'hashery/association'
|
5
5
|
|
6
6
|
testcase Association do
|
@@ -11,6 +11,28 @@ testcase Association do
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
class_method :[] do
|
15
|
+
test do
|
16
|
+
a = Association[:a, 1]
|
17
|
+
a.assert.index == :a
|
18
|
+
a.assert.value == 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
method :index do
|
23
|
+
test do
|
24
|
+
a = Association.new(:a,1)
|
25
|
+
a.index.assert == :a
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
method :value do
|
30
|
+
test do
|
31
|
+
a = Association.new(:a,1)
|
32
|
+
a.value.assert == 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
14
36
|
method :to_ary do
|
15
37
|
test do
|
16
38
|
k,v = [],[]
|
@@ -28,13 +50,52 @@ testcase Association do
|
|
28
50
|
end
|
29
51
|
end
|
30
52
|
|
53
|
+
method :<=> do
|
54
|
+
test 'when differnt in value' do
|
55
|
+
a = Association.new(:a,1)
|
56
|
+
b = Association.new(:b,2)
|
57
|
+
(a <=> b).assert == -1
|
58
|
+
(b <=> a).assert == 1
|
59
|
+
end
|
60
|
+
|
61
|
+
test 'when equal value' do
|
62
|
+
a = Association.new(:a,1)
|
63
|
+
b = Association.new(:b,1)
|
64
|
+
(a <=> b).assert == 0
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
method :invert! do
|
69
|
+
test do
|
70
|
+
a = Association.new(:a,1)
|
71
|
+
a.invert!
|
72
|
+
a.index.assert == 1
|
73
|
+
a.value.assert == :a
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
method :inspect do
|
78
|
+
test do
|
79
|
+
a = Association.new(:a,1)
|
80
|
+
a.inspect.assert == ":a >> 1"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
method :to_s do
|
85
|
+
test do
|
86
|
+
a = Association.new(:a,1)
|
87
|
+
a.to_s.assert == "a >> 1"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
31
91
|
end
|
32
92
|
|
33
93
|
testcase Object do
|
34
94
|
method :associations do
|
35
95
|
test do
|
36
|
-
|
37
|
-
|
96
|
+
s = 'a'
|
97
|
+
complex = [ s >> :b, s >> :c ]
|
98
|
+
s.associations.assert == [:b, :c]
|
38
99
|
end
|
39
100
|
end
|
40
101
|
|
data/test/case_dictionary.rb
CHANGED
@@ -1,8 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'ae'
|
3
|
-
require 'ae/legacy'
|
4
|
-
|
5
|
-
require 'hashery/dictionary'
|
1
|
+
require 'helper'
|
6
2
|
|
7
3
|
testcase Dictionary do
|
8
4
|
include AE::Legacy::Assertions
|
@@ -178,5 +174,153 @@ testcase Dictionary do
|
|
178
174
|
end
|
179
175
|
end
|
180
176
|
|
177
|
+
method :select do
|
178
|
+
test do
|
179
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
180
|
+
r = d.select{ |k,v| v % 2 == 1 }
|
181
|
+
r.assert == [[:a, 1], [:c, 3]]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
method :to_h do
|
186
|
+
test do
|
187
|
+
d = Dictionary[:a=>1, :b=>2]
|
188
|
+
h = d.to_h
|
189
|
+
h.assert == {:a=>1, :b=>2}
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
method :replace do
|
194
|
+
test do
|
195
|
+
d1 = Dictionary[:a=>1, :b=>2]
|
196
|
+
d2 = Dictionary[:c=>3, :d=>4]
|
197
|
+
d1.replace(d2)
|
198
|
+
d1.to_h.assert == {:c=>3, :d=>4}
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
method :reverse do
|
203
|
+
test do
|
204
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
205
|
+
r = d.reverse
|
206
|
+
r.first.assert == 3
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
method :invert do
|
211
|
+
test do
|
212
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
213
|
+
r = d.invert
|
214
|
+
Dictionary.assert === r
|
215
|
+
r.to_h.assert == {1=>:a, 2=>:b, 3=>:c}
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
method :each_key do
|
220
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
221
|
+
a = []
|
222
|
+
d.each_key{ |k| a << k }
|
223
|
+
a.assert == [:a, :b, :c]
|
224
|
+
end
|
225
|
+
|
226
|
+
method :each_value do
|
227
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
228
|
+
a = []
|
229
|
+
d.each_value{ |v| a << v }
|
230
|
+
a.assert == [1, 2, 3]
|
231
|
+
end
|
232
|
+
|
233
|
+
method :clear do
|
234
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
235
|
+
d.clear
|
236
|
+
d.to_a.assert == []
|
237
|
+
end
|
238
|
+
|
239
|
+
method :fetch do
|
240
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
241
|
+
d.fetch(:a).assert == 1
|
242
|
+
end
|
243
|
+
|
244
|
+
method :key? do
|
245
|
+
test do
|
246
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
247
|
+
d.assert.key?(:a)
|
248
|
+
d.refute.key?(:d)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
method :has_key? do
|
253
|
+
test do
|
254
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
255
|
+
d.assert.has_key?(:a)
|
256
|
+
d.refute.has_key?(:d)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
method :length do
|
261
|
+
test do
|
262
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
263
|
+
d.length.assert == 3
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
method :to_a do
|
268
|
+
test do
|
269
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
270
|
+
d.to_a.assert == [[:a,1], [:b,2], [:c,3]]
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
method :to_hash do
|
275
|
+
test do
|
276
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
277
|
+
d.to_hash.assert == {:a=>1, :b=>2, :c=>3}
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
method :empty? do
|
282
|
+
test "is emtpy" do
|
283
|
+
d = Dictionary[]
|
284
|
+
d.assert.empty?
|
285
|
+
end
|
286
|
+
|
287
|
+
test 'is not emtpy' do
|
288
|
+
d = Dictionary[:a=>1, :b=>2, :c=>3]
|
289
|
+
d.refute.empty?
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
method :order_by_key do
|
294
|
+
test do
|
295
|
+
d = Dictionary[:b=>1, :c=>2, :a=>4]
|
296
|
+
d.order_by_key
|
297
|
+
d.order.assert == [:a, :b, :c]
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
method :order_by_value do
|
302
|
+
test do
|
303
|
+
d = Dictionary[:b=>1, :c=>2, :a=>4]
|
304
|
+
d.order_by_value
|
305
|
+
d.order.assert == [:b, :c, :a]
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
class_method :alpha do
|
310
|
+
test do
|
311
|
+
d = Dictionary.alpha
|
312
|
+
d.update(:b=>1, :c=>2, :a=>4)
|
313
|
+
d.order.assert == [:a, :b, :c]
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
class_method :auto do
|
318
|
+
test do
|
319
|
+
d = Dictionary.auto
|
320
|
+
s = d[:foo]
|
321
|
+
s.class.assert == Dictionary
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
181
325
|
end
|
182
326
|
|