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.
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
-