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/propertyhash.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'hashery/property_hash'
|
data/lib/hashery/queryhash.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'hashery/query_hash'
|
data/lib/hashery/statichash.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'hashery/static_hash'
|
data/qed/01_openhash.rdoc
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
= OpenHash
|
2
|
-
|
3
|
-
An OpenHash is a Hash that provides +open+ access to its entries via method
|
4
|
-
calls. Writers (methods ending in =-marks) assign entries. Methods without
|
5
|
-
special puncuation will retrieve entries.
|
6
|
-
|
7
|
-
require 'hashery/openhash'
|
8
|
-
|
9
|
-
o = OpenHash.new
|
10
|
-
o.a = 1
|
11
|
-
o.b = 2
|
12
|
-
o.a.assert == 1
|
13
|
-
o.b.assert == 2
|
14
|
-
|
15
|
-
Writers always use a Symbol for keys in the underlying Hash.
|
16
|
-
|
17
|
-
o.to_h.assert == { :a=>1, :b=>2 }
|
18
|
-
|
19
|
-
All the usual Hash methods are still available in an OpenHash.
|
20
|
-
|
21
|
-
o.map{ |k,v| [k,v] }
|
22
|
-
|
23
|
-
And they are protected from being overridden by writers.
|
24
|
-
|
25
|
-
o.map = 3
|
26
|
-
o.map{ |k,v| [k,v] }
|
27
|
-
|
28
|
-
Even so, the underlying Hash object does contain the entry even
|
29
|
-
when it can not be accessed via a reader method.
|
30
|
-
|
31
|
-
o.to_h.assert == {:a=>1, :b=>2, :map=>3 }
|
32
|
-
|
33
|
-
For some usecases it may be necessary to give up access to one or
|
34
|
-
more Hash methods in favor of access to the hash entries. This can
|
35
|
-
be done using the #omit! method.
|
36
|
-
|
37
|
-
o.omit!(:map, :merge)
|
38
|
-
o.map.assert == 3
|
39
|
-
o.merge = 4
|
40
|
-
o.merge.assert == 4
|
41
|
-
|
42
|
-
Becuase of nature of a writer, a certain set of Hash methods are always
|
43
|
-
protected, namely any of those ending in a puctuation mark. In addition,
|
44
|
-
the implementation protects all shadow methods (e.g. __id__).
|
45
|
-
|
46
|
-
o.__id__ = 4
|
47
|
-
o.__id__.assert! == 4
|
48
|
-
|
49
|
-
Even though writers alwasy use Symbols as keys, because an OpenHash
|
50
|
-
is a true Hash object, any object can be used as a key internally.
|
51
|
-
|
52
|
-
o = OpenHash.new
|
53
|
-
o[nil] = "Nothing"
|
54
|
-
o.to_h.assert == { nil=>"Nothing" }
|
55
|
-
|
56
|
-
It simply will not be accessible via a reader method.
|
57
|
-
|
data/qed/02_queryhash.rdoc
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
= QueryHash
|
2
|
-
|
3
|
-
A QueryHash is a Hash that provides open access much like
|
4
|
-
an OpenHash, but it limits readers to query methods (i.e.
|
5
|
-
method ending in ?-marks).
|
6
|
-
|
7
|
-
require 'hashery/queryhash'
|
8
|
-
|
9
|
-
q = QueryHash.new
|
10
|
-
q.a = 1
|
11
|
-
q.b = 2
|
12
|
-
q.a?.assert == 1
|
13
|
-
q.b?.assert == 2
|
14
|
-
|
15
|
-
Writers always use Symbols for entry keys.
|
16
|
-
|
17
|
-
q.assert == { :a=>1, :b=>2 }
|
18
|
-
|
19
|
-
A QueryHash is compatible with Ruby's standard Hash in
|
20
|
-
every other respect.
|
21
|
-
|
data/qed/03_castinghash.rdoc
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
= CastingHash
|
2
|
-
|
3
|
-
A CastingHash is a Hash that allows _casting_ procedures to
|
4
|
-
defined that the keys and values pass through upon assignment.
|
5
|
-
|
6
|
-
require 'hashery/castinghash'
|
7
|
-
|
8
|
-
c = CastingHash.new{ |x| x.to_s }
|
9
|
-
|
10
|
-
c[:a] = 1
|
11
|
-
|
12
|
-
c.assert == {'a'=>1}
|
13
|
-
|
data/qed/04_statichash.rdoc
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
= StaticHash
|
2
|
-
|
3
|
-
A StaticHash is simply a Hash that can only be assigned
|
4
|
-
once per key. Once assigned a subsequent attempt to assign
|
5
|
-
a value to the same key will raise an ArgumentError.
|
6
|
-
|
7
|
-
require 'hashery/statichash'
|
8
|
-
|
9
|
-
h = StaticHash.new
|
10
|
-
|
11
|
-
h["x"] = 1
|
12
|
-
|
13
|
-
expect ArgumentError do
|
14
|
-
h["x"] = 2
|
15
|
-
end
|
16
|
-
|
17
|
-
The same error will be raised when using #update or #merge!.
|
18
|
-
|
19
|
-
expect ArgumentError do
|
20
|
-
h.update( :x=>2 )
|
21
|
-
end
|
22
|
-
|
data/qed/05_association.rdoc
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
= Association
|
2
|
-
|
3
|
-
An Association is a class for creating simple pairings.
|
4
|
-
|
5
|
-
require 'hashery/association'
|
6
|
-
|
7
|
-
An Association can bew created through the usual means
|
8
|
-
of instantiation.
|
9
|
-
|
10
|
-
Association.new(:a, :b)
|
11
|
-
|
12
|
-
Or the shortcut method #>> can be used in most cases.
|
13
|
-
|
14
|
-
:x >> :z
|
15
|
-
|
16
|
-
An association provides two methods to access its content, #index and #value.
|
17
|
-
|
18
|
-
a = 'foo' >> 'bar'
|
19
|
-
|
20
|
-
a.index.assert == 'foo'
|
21
|
-
a.value.assert == 'bar'
|
22
|
-
|
23
|
-
Associations can be used to create ordered-hashes via normal
|
24
|
-
arrays.
|
25
|
-
|
26
|
-
keys = []
|
27
|
-
vals = []
|
28
|
-
|
29
|
-
ohash = [ 'A' >> '3', 'B' >> '2', 'C' >> '1' ]
|
30
|
-
|
31
|
-
ohash.each{ |k,v| keys << k ; vals << v }
|
32
|
-
|
33
|
-
keys.assert == ['A','B','C']
|
34
|
-
vals.assert == ['3','2','1']
|
35
|
-
|
36
|
-
|
37
|
-
Becuase Associations are objects in themselves more complex
|
38
|
-
collections can also be created.
|
39
|
-
|
40
|
-
complex = [
|
41
|
-
'parent' >> 'child',
|
42
|
-
'childless',
|
43
|
-
'another_parent' >> [
|
44
|
-
'subchildless',
|
45
|
-
'subparent' >> 'subchild'
|
46
|
-
]
|
47
|
-
]
|
48
|
-
|
49
|
-
An experimental feature of Association keeps a cache of all defined associations.
|
50
|
-
|
51
|
-
o = Object.new
|
52
|
-
o >> :a
|
53
|
-
o >> :b
|
54
|
-
o >> :c
|
55
|
-
|
56
|
-
o.associations.assert == [:a, :b, :c]
|
57
|
-
|
58
|
-
However this feature will probably be deprecated.
|
59
|
-
|
data/qed/06_opencascade.rdoc
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
= OpenCascade
|
2
|
-
|
3
|
-
OpenCascade is subclass of OpenObject. It differs in a few
|
4
|
-
significant ways.
|
5
|
-
|
6
|
-
require 'hashery/opencascade'
|
7
|
-
|
8
|
-
The reason this class is labeled "cascade", is that every internal
|
9
|
-
Hash is transformed into an OpenCascade dynamically upon access.
|
10
|
-
This makes it easy to create _cascading_ references.
|
11
|
-
|
12
|
-
h = { :x => { :y => { :z => 1 } } }
|
13
|
-
c = OpenCascade[h]
|
14
|
-
assert c.x.y.z == 1
|
15
|
-
|
16
|
-
As soon as you access a node it automatically becomes an OpenCascade.
|
17
|
-
|
18
|
-
c = OpenCascade.new
|
19
|
-
assert c.r.is_a?(OpenCascade)
|
20
|
-
assert c.a.b.is_a?(OpenCascade)
|
21
|
-
|
22
|
-
But if you set a node, then that will be it's value.
|
23
|
-
|
24
|
-
c.a.b = 4
|
25
|
-
assert c.a.b == 4
|
26
|
-
|
27
|
-
To query a node without causing the auto-creation of an OpenCasade
|
28
|
-
object, use the ?-mark.
|
29
|
-
|
30
|
-
assert c.a.z? == nil
|
31
|
-
|
32
|
-
OpenCascade also transforms Hashes within Arrays.
|
33
|
-
|
34
|
-
h = { :x=>[ {:a=>1}, {:a=>2} ], :y=>1 }
|
35
|
-
c = OpenCascade[h]
|
36
|
-
assert c.x.first.a == 1
|
37
|
-
assert c.x.last.a == 2
|
38
|
-
|
39
|
-
Like OpenObject, OpenCascade allows you to insert entries as array
|
40
|
-
pairs.
|
41
|
-
|
42
|
-
c = OpenCascade.new
|
43
|
-
c << [:x,8]
|
44
|
-
c << [:y,9]
|
45
|
-
|
46
|
-
assert c.x == 8
|
47
|
-
assert c.y == 9
|
48
|
-
|
49
|
-
Finally, you can call methods ending in a !-mark to access the
|
50
|
-
underlying hash (Note that these differ in behavior from the
|
51
|
-
built-in !-methods).
|
52
|
-
|
53
|
-
bk = c.map!{ |k,v| k.to_s.upcase }
|
54
|
-
bk.sort.assert == ['X', 'Y']
|
55
|
-
|
56
|
-
So you can see that for the most an OpenCascade is just like
|
57
|
-
OpenObject, but it allows you to conveniently build open sub-layers.
|
58
|
-
|
data/qed/07_fuzzyhash.rdoc
DELETED
@@ -1,141 +0,0 @@
|
|
1
|
-
= FuzzyHash
|
2
|
-
|
3
|
-
Require the library.
|
4
|
-
|
5
|
-
require 'hashery/fuzzyhash'
|
6
|
-
|
7
|
-
Should accept strings and retrieve based on them.
|
8
|
-
|
9
|
-
l = FuzzyHash.new
|
10
|
-
l['asd'] = 'qwe'
|
11
|
-
l['asd'].should == 'qwe'
|
12
|
-
|
13
|
-
Should accept strings, but the second time you set the same string, it should overwrite.
|
14
|
-
|
15
|
-
l = FuzzyHash.new
|
16
|
-
l['asd'] = 'asd'
|
17
|
-
l['asd'] = 'qwe'
|
18
|
-
l['asd'].should == 'qwe'
|
19
|
-
|
20
|
-
Should accept regexs too.
|
21
|
-
|
22
|
-
l = FuzzyHash.new
|
23
|
-
l[/asd.*/] = 'qwe'
|
24
|
-
l['asdqweasd'].should == 'qwe'
|
25
|
-
|
26
|
-
Should accept regexs too, but the second time you set the same regex, it should overwrite.
|
27
|
-
|
28
|
-
l = FuzzyHash.new
|
29
|
-
l[/asd/] = 'asd'
|
30
|
-
l[/asd/] = 'qwe'
|
31
|
-
l['asdqweasd'].should == 'qwe'
|
32
|
-
|
33
|
-
Should accept regexs too with the match.
|
34
|
-
|
35
|
-
l = FuzzyHash.new
|
36
|
-
l[/asd.*/] = 'qwe'
|
37
|
-
l.match_with_result('asdqweasd').should == ['qwe', 'asdqweasd']
|
38
|
-
|
39
|
-
Should accept regexs that match the whole strong too with the match.
|
40
|
-
|
41
|
-
l = FuzzyHash.new
|
42
|
-
l[/asd/] = 'qwe'
|
43
|
-
l.match_with_result('asd').should == ['qwe', 'asd']
|
44
|
-
|
45
|
-
Should prefer string to regex matches.
|
46
|
-
|
47
|
-
l = FuzzyHash.new
|
48
|
-
l['asd'] = 'qwe2'
|
49
|
-
l[/asd.*/] = 'qwe'
|
50
|
-
l['asd'].should == 'qwe2'
|
51
|
-
|
52
|
-
Should allow nil keys.
|
53
|
-
|
54
|
-
l = FuzzyHash.new
|
55
|
-
l[nil] = 'qwe2'
|
56
|
-
l['asd'] = 'qwe'
|
57
|
-
l['asd'].should == 'qwe'
|
58
|
-
l[nil].should == 'qwe2'
|
59
|
-
|
60
|
-
Should allow boolean keys.
|
61
|
-
|
62
|
-
l = FuzzyHash.new
|
63
|
-
l[false] = 'false'
|
64
|
-
l[true] = 'true'
|
65
|
-
l[/.*/] = 'everything else'
|
66
|
-
l[true].should == 'true'
|
67
|
-
l[false].should == 'false'
|
68
|
-
l['false'].should == 'everything else'
|
69
|
-
|
70
|
-
Should pick between the correct regex.
|
71
|
-
|
72
|
-
hash = FuzzyHash.new
|
73
|
-
hash[/^\d+$/] = 'number'
|
74
|
-
hash[/.*/] = 'something'
|
75
|
-
hash['123asd'].should == 'something'
|
76
|
-
|
77
|
-
Should be able to delete by value for hash.
|
78
|
-
|
79
|
-
l = FuzzyHash.new
|
80
|
-
l[nil] = 'qwe2'
|
81
|
-
l['asd'] = 'qwe'
|
82
|
-
l['asd'].should == 'qwe'
|
83
|
-
l[nil].should == 'qwe2'
|
84
|
-
l.delete_value('qwe2')
|
85
|
-
l[nil].should == nil
|
86
|
-
|
87
|
-
Should be able to delete by value for regex.
|
88
|
-
|
89
|
-
l = FuzzyHash.new
|
90
|
-
l[/qwe.*/] = 'qwe2'
|
91
|
-
l['asd'] = 'qwe'
|
92
|
-
l['asd'].should == 'qwe'
|
93
|
-
l['qweasd'].should == 'qwe2'
|
94
|
-
l.delete_value('qwe2')
|
95
|
-
l['qweasd'].should == nil
|
96
|
-
|
97
|
-
Should iterate through the keys.
|
98
|
-
|
99
|
-
l = FuzzyHash.new
|
100
|
-
l[/qwe.*/] = 'qwe2'
|
101
|
-
l['asd'] = 'qwe'
|
102
|
-
l['zxc'] = 'qwe'
|
103
|
-
l.keys.size.should == 3
|
104
|
-
|
105
|
-
Should iterate through the values.
|
106
|
-
|
107
|
-
l = FuzzyHash.new
|
108
|
-
l[/qwe.*/] = 'qwe2'
|
109
|
-
l['asd'] = 'qwe'
|
110
|
-
l['zxc'] = 'qwelkj'
|
111
|
-
(['qwe2','qwe','qwelkj'] & l.values).size.should == 3
|
112
|
-
|
113
|
-
Should clear.
|
114
|
-
|
115
|
-
l = FuzzyHash.new
|
116
|
-
l[/qwe.*/] = 'qwe2'
|
117
|
-
l['asd'] = 'qwe'
|
118
|
-
l['zxc'] = 'qwelkj'
|
119
|
-
l.clear
|
120
|
-
l.empty?.should == true
|
121
|
-
|
122
|
-
Should handle equality.
|
123
|
-
|
124
|
-
l_1 = FuzzyHash.new
|
125
|
-
l_1[/qwe.*/] = 'qwe2'
|
126
|
-
l_1['asd'] = 'qwelkj'
|
127
|
-
l_1['zxc'] = 'qwe'
|
128
|
-
l_2 = FuzzyHash.new
|
129
|
-
l_2['zxc'] = 'qwe'
|
130
|
-
l_2['asd'] = 'qwelkj'
|
131
|
-
l_2[/qwe.*/] = 'qwe2'
|
132
|
-
l_1.should == l_2
|
133
|
-
|
134
|
-
Should return the value when adding the value.
|
135
|
-
|
136
|
-
h = FuzzyHash.new
|
137
|
-
(h[/asd/] = '123').should == '123'
|
138
|
-
(h['qwe'] = '123').should == '123'
|
139
|
-
|
140
|
-
That's It.
|
141
|
-
|
data/qed/08_properyhash.rdoc
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
= PropertyHash
|
2
|
-
|
3
|
-
Require the library.
|
4
|
-
|
5
|
-
require 'hashery/propertyhash'
|
6
|
-
|
7
|
-
The Property hash can be used an object in itself.
|
8
|
-
|
9
|
-
h = PropertyHash.new(:a=>1, :b=>2)
|
10
|
-
h[:a] #=> 1
|
11
|
-
h[:a] = 3
|
12
|
-
h[:a] #=> 3
|
13
|
-
|
14
|
-
Becuase the properties are fixed, if we try to set a key that is not present,
|
15
|
-
then we will get an error.
|
16
|
-
|
17
|
-
expect ArgumentError do
|
18
|
-
h[:x] = 5
|
19
|
-
end
|
20
|
-
|
21
|
-
The PropertyHash can also be used as a superclass.
|
22
|
-
|
23
|
-
class MyPropertyHash < PropertyHash
|
24
|
-
property :a, :default => 1
|
25
|
-
property :b, :default => 2
|
26
|
-
end
|
27
|
-
|
28
|
-
h = MyPropertyHash.new
|
29
|
-
h[:a] #=> 1
|
30
|
-
h[:a] = 3
|
31
|
-
h[:a] #=> 3
|
32
|
-
|
33
|
-
Again, if we try to set key that was not fixed, then we will get an error.
|
34
|
-
|
35
|
-
expect ArgumentError do
|
36
|
-
h[:x] = 5
|
37
|
-
end
|
38
|
-
|
data/qed/09_ostructable.rdoc
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
= OpenStructable
|
2
|
-
|
3
|
-
OpensStructable is a mixin module which can provide OpenStruct behavior to
|
4
|
-
any class or object. OpenStructable allows extention of data objects
|
5
|
-
with arbitrary attributes.
|
6
|
-
|
7
|
-
require 'hashery/ostructable'
|
8
|
-
|
9
|
-
class Record
|
10
|
-
include OpenStructable
|
11
|
-
end
|
12
|
-
|
13
|
-
Now let's create a new record and see if we can assign values to open
|
14
|
-
properties.
|
15
|
-
|
16
|
-
record = Record.new
|
17
|
-
record.name = "John Smith"
|
18
|
-
record.age = 70
|
19
|
-
record.pension = 300
|
20
|
-
|
21
|
-
We can see that the values were set.
|
22
|
-
|
23
|
-
record.name.assert == "John Smith"
|
24
|
-
record.age.assert == 70
|
25
|
-
record.pension.assert == 300
|
26
|
-
|
27
|
-
If we havent' assigned a value to a property it should just return +nil+.
|
28
|
-
|
29
|
-
record.address.assert == nil
|
30
|
-
|
31
|
-
OpenStructable is also smart enough to adjust itself to work with a subclass
|
32
|
-
of a Hash.
|
33
|
-
|
34
|
-
class HashRecord < Hash
|
35
|
-
include OpenStructable
|
36
|
-
end
|
37
|
-
|
38
|
-
We can apply similar settings as above.
|
39
|
-
|
40
|
-
record = HashRecord.new
|
41
|
-
record.name = "John Doe"
|
42
|
-
record.age = 40
|
43
|
-
record.pension = 200
|
44
|
-
|
45
|
-
We can see that the values were set.
|
46
|
-
|
47
|
-
record.name.assert == "John Doe"
|
48
|
-
record.age.assert == 40
|
49
|
-
record.pension.assert == 200
|
50
|
-
|
51
|
-
The differnce here is that the data is accessible via the normal Hash
|
52
|
-
methods too.
|
53
|
-
|
54
|
-
record.assert == {:name=>"John Doe", :age=>40, :pension=>200}
|
55
|
-
|
56
|
-
Notice that entries are converted to Symbols, not Strings.
|