hashery 1.5.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/.ruby +30 -17
  2. data/.yardopts +1 -0
  3. data/Config.rb +28 -0
  4. data/{QED.rdoc → DEMO.rdoc} +0 -0
  5. data/HISTORY.rdoc +37 -0
  6. data/LICENSE.txt +26 -0
  7. data/NOTICE.txt +46 -0
  8. data/README.rdoc +10 -7
  9. data/lib/hashery.rb +6 -6
  10. data/lib/hashery.yml +30 -17
  11. data/lib/hashery/association.rb +169 -109
  12. data/lib/hashery/casting_hash.rb +128 -135
  13. data/lib/hashery/core_ext.rb +89 -61
  14. data/lib/hashery/crud_hash.rb +365 -0
  15. data/lib/hashery/dictionary.rb +545 -345
  16. data/lib/hashery/fuzzy_hash.rb +177 -125
  17. data/lib/hashery/ini_hash.rb +321 -0
  18. data/lib/hashery/key_hash.rb +54 -179
  19. data/lib/hashery/linked_list.rb +245 -191
  20. data/lib/hashery/lru_hash.rb +292 -202
  21. data/lib/hashery/open_cascade.rb +133 -78
  22. data/lib/hashery/open_hash.rb +127 -61
  23. data/lib/hashery/ordered_hash.rb +128 -122
  24. data/lib/hashery/path_hash.rb +238 -0
  25. data/lib/hashery/property_hash.rb +144 -80
  26. data/lib/hashery/query_hash.rb +85 -29
  27. data/lib/hashery/stash.rb +7 -3
  28. data/lib/hashery/static_hash.rb +46 -41
  29. data/test/case_association.rb +65 -4
  30. data/test/case_dictionary.rb +149 -5
  31. data/test/{case_keyhash.rb → case_key_hash.rb} +20 -14
  32. data/test/case_lru_hash.rb +162 -0
  33. data/test/{case_opencascade.rb → case_open_cascade.rb} +4 -8
  34. data/test/case_open_hash.rb +87 -0
  35. data/test/case_query_hash.rb +226 -0
  36. data/test/helper.rb +8 -0
  37. metadata +33 -63
  38. data/COPYING.rdoc +0 -45
  39. data/lib/hashery/basic_object.rb +0 -74
  40. data/lib/hashery/basic_struct.rb +0 -288
  41. data/lib/hashery/basicobject.rb +0 -1
  42. data/lib/hashery/basicstruct.rb +0 -1
  43. data/lib/hashery/castinghash.rb +0 -1
  44. data/lib/hashery/fuzzyhash.rb +0 -1
  45. data/lib/hashery/ini.rb +0 -268
  46. data/lib/hashery/keyhash.rb +0 -1
  47. data/lib/hashery/linkedlist.rb +0 -1
  48. data/lib/hashery/lruhash.rb +0 -1
  49. data/lib/hashery/memoizer.rb +0 -64
  50. data/lib/hashery/open_object.rb +0 -1
  51. data/lib/hashery/opencascade.rb +0 -1
  52. data/lib/hashery/openhash.rb +0 -1
  53. data/lib/hashery/openobject.rb +0 -1
  54. data/lib/hashery/orderedhash.rb +0 -1
  55. data/lib/hashery/ostructable.rb +0 -186
  56. data/lib/hashery/propertyhash.rb +0 -1
  57. data/lib/hashery/queryhash.rb +0 -1
  58. data/lib/hashery/statichash.rb +0 -1
  59. data/qed/01_openhash.rdoc +0 -57
  60. data/qed/02_queryhash.rdoc +0 -21
  61. data/qed/03_castinghash.rdoc +0 -13
  62. data/qed/04_statichash.rdoc +0 -22
  63. data/qed/05_association.rdoc +0 -59
  64. data/qed/06_opencascade.rdoc +0 -58
  65. data/qed/07_fuzzyhash.rdoc +0 -141
  66. data/qed/08_properyhash.rdoc +0 -38
  67. data/qed/09_ostructable.rdoc +0 -56
  68. data/qed/applique/ae.rb +0 -1
  69. data/test/case_basicstruct.rb +0 -192
  70. data/test/case_openhash.rb +0 -22
@@ -1,186 +1,61 @@
1
- require 'hashery/core_ext'
2
-
3
- # The KeyHash class is a Hash compatible class which converts
4
- # all keys to strings. This has two advantages. First it
5
- # means hash entries have indifferent access. <tt>1</tt>,
6
- # <tt>"1"</tt> and <tt>:1</tt> are all equivalent. Any object
7
- # that defines <tt>#to_s</tt> can be used as a key. Secondly,
8
- # since strings are garbage collected so are KeyHash objects.
9
- #
10
- # The KeyHash class works like a normal Hash. But notice the
11
- # significant distinction of indifferent key access.
12
- #
13
- # s = KeyHash.new
14
- # s[:x] = 1
15
- # s[:x] #=> 1
16
- # s['x'] #=> 1
17
- #
18
- # We can see that internally the key has indeed been converted
19
- # to a String.
20
- #
21
- # s.to_h #=> {'x'=>1 }
22
- #
23
- # Becuase of the way in which KeyHash is designed, it has a nice
24
- # secondary usage. KeyHash defines a private method called
25
- # #convert_key. This method handles the conversion of the key
26
- # whenever the underlying hash is altered. If you have need
27
- # for a different kind of Hash, one the has a special restraint
28
- # on the key, it is easy enough to subclass KeyHash and override
29
- # the is method. Eg.
30
- #
31
- # class Upash < KeyHash
32
- # def convert_key(key)
33
- # key.to_s.upcase
34
- # end
35
- # end
36
- #
37
- # u = Upash.new
38
- # u.replace(:a=>1, :b=>2)
39
- # u.to_h #=> { 'A'=>1, 'B'=>2 }
40
- #
41
- #
42
- # NOTE: KeyHash does not yet handle default_proc.
43
-
44
- class KeyHash < Hash
45
-
46
- #
47
- def self.[](*hash)
48
- s = new
49
- super(*hash).each{ |k,v| s[k] = v }
50
- s
51
- end
52
-
53
- #
54
- def [](key)
55
- super(convert_key(key))
56
- end
57
-
58
- #
59
- def []=(key,value)
60
- super(convert_key(key), value)
61
- end
62
-
63
- #
64
- def <<(other)
65
- case other
66
- when Hash
67
- super(other.rekey{ |key| convert_key(key) })
68
- when Array
69
- self[other[0]] = other[1]
70
- else
71
- raise ArgumentError
72
- end
73
- end
74
-
75
- #
76
- def fetch(key)
77
- super(convert_key(key))
78
- end
79
-
80
- #
81
- def store(key, value)
82
- super(convert_key(key), value)
83
- end
84
-
85
- #
86
- def key?(key)
87
- super(convert_key(key))
88
- end
89
-
90
- #
91
- def has_key?(key)
92
- super(convert_key(key))
93
- end
94
-
95
- #
96
- def include?(key)
97
- super(convert_key(key))
98
- end
99
-
100
- #
101
- def member?(key)
102
- super(convert_key(key))
103
- end
104
-
105
- # Synonym for #rekey, but modifies the receiver in place (and returns it).
106
- #
107
- # foo = { :name=>'Gavin', :wife=>:Lisa }.to_stash
108
- # foo.rekey!{ |k| k.upcase } #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
109
- # foo.inspect #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
110
- #
111
- def rekey!(*args, &block)
112
- # for backward comptability (TODO: DEPRECATE?).
113
- block = args.pop.to_sym.to_proc if args.size == 1
114
- if args.empty?
115
- block = lambda{|k| k} unless block
116
- keys.each do |k|
117
- nk = block[k]
118
- self[nk.to_s]=delete(k) #if nk
119
- end
120
- else
121
- raise ArgumentError, "3 for 2" if block
122
- to, from = *args
123
- self[to] = delete(from) if has_key?(from)
1
+ require 'hashery/crud_hash'
2
+
3
+ module Hashery
4
+
5
+ # The KeyHash class is a Hash class which accepts a block for
6
+ # normalizing keys.
7
+ #
8
+ # The KeyHash class is essentially the same as a normal Hash.
9
+ # But notice the significant distinction of indifferent key
10
+ # access.
11
+ #
12
+ # s = KeyHash.new
13
+ # s[:x] = 1
14
+ # s[:x] #=> 1
15
+ # s['x'] #=> 1
16
+ #
17
+ # We can see that internally the key has indeed been converted
18
+ # to a String.
19
+ #
20
+ # s.to_h #=> {'x'=>1 }
21
+ #
22
+ # By default all keys are converted to strings. This has two advantages
23
+ # over a regular Hash is many usecases. First it means hash entries have
24
+ # indifferent access. <tt>1</tt>, <tt>"1"</tt> and <tt>:1</tt> are all
25
+ # equivalent --any object that defines <tt>#to_s</tt> can be used as a key.
26
+ # Secondly, since strings are garbage collected so will default KeyHash
27
+ # objects.
28
+ #
29
+ # But keys can be normalized by any function. Theses functions can be quite
30
+ # unique.
31
+ #
32
+ # h = KeyHash.new(0){ |k| k.to_i }
33
+ # h[1.34] += 1
34
+ # h[1.20] += 1
35
+ # h[1.00] += 1
36
+ # h #=> { 1 => 3 }
37
+ #
38
+ class KeyHash < CRUDHash
39
+
40
+ #
41
+ # Unlike a regular Hash, a KeyHash's block sets the `key_proc` rather
42
+ # than the `default_proc`.
43
+ #
44
+ def initialize(*default, &block)
45
+ super(*default)
46
+ @key_proc = block || Proc.new{ |k| k.to_s }
124
47
  end
125
- self
126
- end
127
-
128
- #
129
- def rekey(*args, &block)
130
- dup.rekey!(*args, &block)
131
- end
132
-
133
- #
134
- def delete(key)
135
- super(convert_key(key))
136
- end
137
-
138
- #
139
- def update(other)
140
- super(other.rekey{ |key| convert_key(key) })
141
- end
142
-
143
- # Same as #update.
144
- def merge!(other)
145
- super(other.rekey{ |key| convert_key(key) })
146
- end
147
48
 
148
- #
149
- def merge(other)
150
- super(other.rekey{ |key| convert_key(key) })
151
- end
152
-
153
- #
154
- def replace(other)
155
- super(other.rekey{ |key| convert_key(key) })
156
- end
157
-
158
- #
159
- def values_at(*keys)
160
- super(*keys.map{ |key| convert_key(key) })
161
- end
162
-
163
- #
164
- def to_hash
165
- h = {}
166
- each{ |k,v| h[k] = v }
167
- h
168
49
  end
169
50
 
170
- alias_method :to_h, :to_hash
171
-
172
- private
173
-
174
- def convert_key(key)
175
- key.to_s
176
- end
177
-
178
51
  end
179
52
 
180
- class Hash
181
- # Convert a Hash to a KeyHash object.
182
- def to_keyhash
183
- KeyHash[self]
184
- end
185
- end
53
+ #class Hash
54
+ # #
55
+ # # Convert a Hash to a KeyHash object.
56
+ # #
57
+ # def to_keyhash
58
+ # Hashery::KeyHash[self]
59
+ # end
60
+ #end
186
61
 
@@ -1,195 +1,249 @@
1
- # LinkedList
2
- #
3
- # Copyright (C) 2006 Kirk Haines <khaines@enigo.com>.
4
- #
5
- # General Public License (GPL)
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining
8
- # a copy of this software and associated documentation files (the
9
- # "Software"), to deal in the Software without restriction, including
10
- # without limitation the rights to use, copy, modify, merge, publish,
11
- # distribute, sublicense, and/or sell copies of the Software, and to
12
- # permit persons to whom the Software is furnished to do so, subject to
13
- # the following conditions:
14
- #
15
- # The above copyright notice and this permission notice shall be
16
- # included in all copies or substantial portions of the Software.
17
- #
18
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
-
26
1
  require 'enumerator'
27
2
 
28
- # LinkedList implements a simple doubly linked list with efficient
29
- # hash-like element access.
30
- #
31
- # This is a simple linked list implementation with efficient random
32
- # access of data elements. It was inspired by George Moscovitis'
33
- # LRUCache implementation found in Facets 1.7.30, but unlike the
34
- # linked list in that cache, this one does not require the use of a
35
- # mixin on any class to be stored. The linked list provides the
36
- # push, pop, shift, unshift, first, last, delete and length methods
37
- # which work just like their namesakes in the Array class, but it
38
- # also supports setting and retrieving values by key, just like a
39
- # hash.
40
- #
41
- # LinkedList was ported from the original in Kirk Hanes IOWA web framework.
42
- #
43
- class LinkedList
44
-
45
- include Enumerable
46
-
47
- # Represents a single node of the linked list.
48
-
49
- class Node
50
- attr_accessor :key, :value, :prev_node, :next_node
51
-
52
- def initialize(key=nil,value=nil,prev_node=nil,next_node=nil)
53
- @key = key
54
- @value = value
55
- @prev_node = prev_node
56
- @next_node = next_node
57
- end
58
- end
59
-
60
- def initialize
61
- @head = Node.new
62
- @tail = Node.new
63
- @lookup = Hash.new
64
- node_join(@head,@tail)
65
- end
66
-
67
- def [](v)
68
- @lookup[v].value
69
- end
70
-
71
- def []=(k,v)
72
- if @lookup.has_key?(k)
73
- @lookup[k].value = v
74
- else
75
- n = Node.new(k,v,@head,@head.next_node)
76
- node_join(n,@head.next_node)
77
- node_join(@head,n)
78
- @lookup[k] = n
79
- end
80
- v
81
- end
82
-
83
- def empty?
84
- @lookup.empty?
85
- end
86
-
87
- def delete(k)
88
- n = @lookup.delete(k)
89
- v = n ? node_purge(n) : nil
90
- v
91
- end
92
-
93
- def first
94
- @head.next_node.value
95
- end
96
-
97
- def last
98
- @tail.prev_node.value
99
- end
100
-
101
- def shift
102
- k = @head.next_node.key
103
- n = @lookup.delete(k)
104
- node_delete(n) if n
105
- end
106
-
107
- def unshift(v)
108
- if @lookup.has_key?(v)
109
- n = @lookup[v]
110
- node_delete(n)
111
- node_join(n,@head.next_node)
112
- node_join(@head,n)
113
- else
114
- n = Node.new(v,v,@head,@head.next_node)
115
- node_join(n,@head.next_node)
116
- node_join(@head,n)
117
- @lookup[v] = n
118
- end
119
- v
120
- end
121
-
122
- def pop
123
- k = @tail.prev_node.key
124
- n = @lookup.delete(k)
125
- node_delete(n) if n
126
- end
127
-
128
- def push(v)
129
- if @lookup.has_key?(v)
130
- n = @lookup[v]
131
- node_delete(n)
132
- node_join(@tail.prev_node,n)
133
- node_join(n,@tail)
134
- else
135
- n = Node.new(v,v,@tail.prev_node,@tail)
136
- node_join(@tail.prev_node,n)
137
- node_join(n,@tail)
138
- @lookup[v] = n
139
- end
140
- v
141
- end
142
-
143
- def queue
144
- r = []
145
- n = @head
146
- while (n = n.next_node) and n != @tail
147
- r << n.key
148
- end
149
- r
150
- end
151
-
152
- def to_a
153
- r = []
154
- n = @head
155
- while (n = n.next_node) and n != @tail
156
- r << n.value
157
- end
158
- r
159
- end
160
-
161
- def length
162
- @lookup.length
163
- end
164
-
165
- def each
166
- n = @head
167
- while (n = n.next_node) and n != @tail
168
- yield(n.key,n.value)
169
- end
170
- end
171
-
172
- private
173
-
174
- def node_delete(n)
175
- node_join(n.prev_node,n.next_node)
176
- v = n.value
177
- end
178
-
179
- def node_purge(n)
180
- node_join(n.prev_node,n.next_node)
181
- v = n.value
182
- n.value = nil
183
- n.key = nil
184
- n.next_node = nil
185
- n.prev_node = nil
186
- v
187
- end
188
-
189
- def node_join(a,b)
190
- a.next_node = b
191
- b.prev_node = a
192
- end
3
+ module Hashery
4
+
5
+ # LinkedList implements a simple doubly linked list with efficient
6
+ # hash-like element access.
7
+ #
8
+ # This is a simple linked-list implementation with efficient random
9
+ # access of data elements. It was inspired by George Moscovitis'
10
+ # LRUCache implementation found in Facets 1.7.30, but unlike the
11
+ # linked-list in that cache, this one does not require the use of a
12
+ # mixin on any class to be stored. The linked-list provides the
13
+ # push, pop, shift, unshift, first, last, delete and length methods
14
+ # which work just like their namesakes in the Array class, but it
15
+ # also supports setting and retrieving values by key, just like a
16
+ # hash.
17
+ #
18
+ # LinkedList was ported from the original in Kirk Hanes IOWA web framework.
19
+ #
20
+ # == Acknowledgements
21
+ #
22
+ # LinkedList is based on the LinkedList library by Kirk Haines.
23
+ #
24
+ # Copyright (C) 2006 Kirk Haines <khaines@enigo.com>.
25
+ #
26
+ class LinkedList
27
+
28
+ include Enumerable
29
+
30
+ # Represents a single node of the linked list.
31
+ #
32
+ class Node
33
+ attr_accessor :key, :value, :prev_node, :next_node
34
+
35
+ def initialize(key=nil,value=nil,prev_node=nil,next_node=nil)
36
+ @key = key
37
+ @value = value
38
+ @prev_node = prev_node
39
+ @next_node = next_node
40
+ end
41
+ end
42
+
43
+ #
44
+ # Initialize new LinkedList instance.
45
+ #
46
+ def initialize
47
+ @head = Node.new
48
+ @tail = Node.new
49
+ @lookup = Hash.new
50
+
51
+ node_join(@head,@tail)
52
+ end
53
+
54
+ #
55
+ # Lookup entry by key.
56
+ #
57
+ def [](key)
58
+ @lookup[key].value
59
+ end
60
+
61
+ #
62
+ # Add node to linked list.
63
+ #
64
+ def []=(k,v)
65
+ if @lookup.has_key?(k)
66
+ @lookup[k].value = v
67
+ else
68
+ n = Node.new(k,v,@head,@head.next_node)
69
+ node_join(n,@head.next_node)
70
+ node_join(@head,n)
71
+ @lookup[k] = n
72
+ end
73
+ v
74
+ end
75
+
76
+ #
77
+ # Is linked list empty?
78
+ #
79
+ def empty?
80
+ @lookup.empty?
81
+ end
82
+
83
+ #
84
+ # Remove node idenified by key.
85
+ #
86
+ def delete(key)
87
+ n = @lookup.delete(key)
88
+ v = n ? node_purge(n) : nil
89
+ v
90
+ end
91
+
92
+ #
93
+ # Get value of first node.
94
+ #
95
+ def first
96
+ @head.next_node.value
97
+ end
98
+
99
+ #
100
+ # Get value of last node.
101
+ #
102
+ def last
103
+ @tail.prev_node.value
104
+ end
105
+
106
+ #
107
+ #
108
+ #
109
+ def shift
110
+ k = @head.next_node.key
111
+ n = @lookup.delete(k)
112
+ node_delete(n) if n
113
+ end
114
+
115
+ #
116
+ #
117
+ #
118
+ def unshift(v)
119
+ if @lookup.has_key?(v)
120
+ n = @lookup[v]
121
+ node_delete(n)
122
+ node_join(n,@head.next_node)
123
+ node_join(@head,n)
124
+ else
125
+ n = Node.new(v,v,@head,@head.next_node)
126
+ node_join(n,@head.next_node)
127
+ node_join(@head,n)
128
+ @lookup[v] = n
129
+ end
130
+ v
131
+ end
132
+
133
+ #
134
+ #
135
+ #
136
+ def pop
137
+ k = @tail.prev_node.key
138
+ n = @lookup.delete(k)
139
+ node_delete(n) if n
140
+ end
141
+
142
+ #
143
+ #
144
+ #
145
+ def push(v)
146
+ if @lookup.has_key?(v)
147
+ n = @lookup[v]
148
+ node_delete(n)
149
+ node_join(@tail.prev_node,n)
150
+ node_join(n,@tail)
151
+ else
152
+ n = Node.new(v,v,@tail.prev_node,@tail)
153
+ node_join(@tail.prev_node,n)
154
+ node_join(n,@tail)
155
+ @lookup[v] = n
156
+ end
157
+ v
158
+ end
159
+
160
+ alias :<< :push
161
+
162
+ #
163
+ # Produces an Array of key values.
164
+ #
165
+ # Returns [Array].
166
+ #
167
+ def queue
168
+ r = []
169
+ n = @head
170
+ while (n = n.next_node) and n != @tail
171
+ r << n.key
172
+ end
173
+ r
174
+ end
175
+
176
+ #
177
+ # Converts to an Array of node values.
178
+ #
179
+ # Returns [Array].
180
+ #
181
+ def to_a
182
+ r = []
183
+ n = @head
184
+ while (n = n.next_node) and n != @tail
185
+ r << n.value
186
+ end
187
+ r
188
+ end
189
+
190
+ #
191
+ # Number of nodes.
192
+ #
193
+ def length
194
+ @lookup.length
195
+ end
196
+
197
+ alias size length
198
+
199
+ #
200
+ # Iterate over nodes, starting with the head node
201
+ # and ending with the tail node.
202
+ #
203
+ def each
204
+ n = @head
205
+ while (n = n.next_node) and n != @tail
206
+ yield(n.key,n.value)
207
+ end
208
+ end
209
+
210
+ private
211
+
212
+ #
213
+ # Delete a node.
214
+ #
215
+ # n - A node.
216
+ #
217
+ def node_delete(n)
218
+ node_join(n.prev_node,n.next_node)
219
+ v = n.value
220
+ end
221
+
222
+ #
223
+ # Purge a node.
224
+ #
225
+ # n - A node.
226
+ #
227
+ def node_purge(n)
228
+ node_join(n.prev_node,n.next_node)
229
+ v = n.value
230
+ n.value = nil
231
+ n.key = nil
232
+ n.next_node = nil
233
+ n.prev_node = nil
234
+ v
235
+ end
236
+
237
+ # Join two nodes.
238
+ #
239
+ # a - A node.
240
+ # b - A node.
241
+ #
242
+ def node_join(a,b)
243
+ a.next_node = b
244
+ b.prev_node = a
245
+ end
246
+
247
+ end
193
248
 
194
249
  end
195
-