hashery 1.5.0 → 2.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/.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
|
|