hashery 1.4.0 → 1.5.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 (54) hide show
  1. data/.ruby +57 -92
  2. data/.yardopts +8 -0
  3. data/COPYING.rdoc +45 -0
  4. data/HISTORY.rdoc +18 -0
  5. data/QED.rdoc +1 -0
  6. data/README.rdoc +42 -16
  7. data/lib/hashery.rb +16 -9
  8. data/lib/hashery.yml +57 -92
  9. data/lib/hashery/association.rb +3 -1
  10. data/lib/hashery/basic_object.rb +74 -0
  11. data/lib/hashery/basic_struct.rb +288 -1
  12. data/lib/hashery/basicobject.rb +1 -74
  13. data/lib/hashery/basicstruct.rb +1 -280
  14. data/lib/hashery/casting_hash.rb +171 -1
  15. data/lib/hashery/castinghash.rb +1 -171
  16. data/lib/hashery/core_ext.rb +82 -0
  17. data/lib/hashery/dictionary.rb +3 -0
  18. data/lib/hashery/fuzzy_hash.rb +154 -1
  19. data/lib/hashery/fuzzyhash.rb +1 -154
  20. data/lib/hashery/ini.rb +3 -2
  21. data/lib/hashery/key_hash.rb +186 -0
  22. data/lib/hashery/keyhash.rb +1 -0
  23. data/lib/hashery/linked_list.rb +195 -1
  24. data/lib/hashery/linkedlist.rb +1 -195
  25. data/lib/hashery/lru_hash.rb +273 -1
  26. data/lib/hashery/lruhash.rb +1 -273
  27. data/lib/hashery/open_cascade.rb +99 -1
  28. data/lib/hashery/open_hash.rb +77 -1
  29. data/lib/hashery/opencascade.rb +1 -99
  30. data/lib/hashery/openhash.rb +1 -77
  31. data/lib/hashery/ordered_hash.rb +168 -1
  32. data/lib/hashery/orderedhash.rb +1 -167
  33. data/lib/hashery/property_hash.rb +97 -1
  34. data/lib/hashery/propertyhash.rb +1 -97
  35. data/lib/hashery/query_hash.rb +35 -1
  36. data/lib/hashery/queryhash.rb +1 -35
  37. data/lib/hashery/stash.rb +3 -174
  38. data/lib/hashery/static_hash.rb +48 -1
  39. data/lib/hashery/statichash.rb +1 -48
  40. data/qed/06_opencascade.rdoc +12 -12
  41. data/test/case_association.rb +29 -15
  42. data/test/case_basicstruct.rb +192 -0
  43. data/test/case_dictionary.rb +149 -109
  44. data/test/case_keyhash.rb +175 -0
  45. data/test/case_opencascade.rb +89 -43
  46. data/test/case_openhash.rb +15 -11
  47. metadata +85 -78
  48. data/LICENSE +0 -206
  49. data/NOTICE +0 -11
  50. data/lib/hashery/sparse_array.rb +0 -1
  51. data/lib/hashery/sparsearray.rb +0 -577
  52. data/test/case_openobject.rb +0 -130
  53. data/test/case_sparsearray.rb +0 -316
  54. data/test/case_stash.rb +0 -131
@@ -1,171 +1 @@
1
- # CastingHash is just like Hash, except that all keys and values
2
- # are passed through casting procedures.
3
- #--
4
- # TODO: Handle default_proc.
5
- #++
6
- class CastingHash < Hash
7
-
8
- # Default key conversion procedure.
9
- KEY_PROC = lambda{ |x| x } #.to_s }
10
-
11
- # Default value conversion procedure.
12
- VAL_PROC = lambda{ |x| x }
13
-
14
- #
15
- def self.[](hash)
16
- s = new
17
- hash.each{ |k,v| s[k] = v }
18
- s
19
- end
20
-
21
- #
22
- def initialize(hash={}, value_cast=nil, &key_cast)
23
- @key_proc = (key_cast || KEY_PROC)
24
- @value_proc = (value_cast || VAL_PROC).to_proc
25
- hash.each{ |k,v| self[k] = v }
26
- end
27
-
28
- #
29
- def key_proc
30
- @key_proc
31
- end
32
-
33
- #
34
- def key_proc=(proc)
35
- @key_proc = proc.to_proc
36
- end
37
-
38
- #
39
- def value_proc
40
- @value_proc
41
- end
42
-
43
- #
44
- def value_proc=(proc)
45
- @value_proc = proc.to_proc
46
- end
47
-
48
- #
49
- def [](k)
50
- super(key_proc[k])
51
- end
52
-
53
- #
54
- def []=(k,v)
55
- super(key_proc[k], value_proc[v])
56
- end
57
-
58
- #
59
- def <<(other)
60
- case other
61
- when Hash
62
- super(cast(other))
63
- when Array
64
- self[other[0]] = other[1]
65
- else
66
- raise ArgumentError
67
- end
68
- end
69
-
70
- def fetch(k)
71
- super(key_proc[k])
72
- end
73
-
74
- #
75
- def store(k, v)
76
- super(key_proc[k], value_proc[v])
77
- end
78
-
79
- #
80
- def key?(k)
81
- super(key_proc[k])
82
- end
83
-
84
- #
85
- def has_key?(k)
86
- super(key_proc[k])
87
- end
88
-
89
- # Synonym for Hash#rekey, but modifies the receiver in place (and returns it).
90
- #
91
- # foo = { :name=>'Gavin', :wife=>:Lisa }.to_stash
92
- # foo.rekey!{ |k| k.upcase } #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
93
- # foo.inspect #=> { "NAME"=>"Gavin", "WIFE"=>:Lisa }
94
- #
95
- def rekey!(*args, &block)
96
- # for backward comptability (DEPRECATE?).
97
- block = args.pop.to_sym.to_proc if args.size == 1
98
- if args.empty?
99
- block = lambda{|k| k} unless block
100
- keys.each do |k|
101
- nk = block[k]
102
- self[nk] = delete(k) #if nk
103
- end
104
- else
105
- raise ArgumentError, "3 for 2" if block
106
- to, from = *args
107
- self[to] = delete(from) if has_key?(from)
108
- end
109
- self
110
- end
111
-
112
- #
113
- def rekey(*args, &block)
114
- dup.rekey!(*args, &block)
115
- end
116
-
117
- #
118
- def delete(k)
119
- super(key_proc[k])
120
- end
121
-
122
- #
123
- def update(other)
124
- super(cast(other))
125
- end
126
-
127
- # Same as #update.
128
- def merge!(other)
129
- super(cast(other))
130
- end
131
-
132
- #
133
- def replace(other)
134
- super(cast(other))
135
- end
136
-
137
- #
138
- def values_at(*keys)
139
- super(keys.map(&key_proc))
140
- end
141
-
142
- #
143
- def to_hash
144
- h = {}; each{ |k,v| h[k] = v }; h
145
- end
146
-
147
- #
148
- alias_method :to_h, :to_hash
149
-
150
- private
151
-
152
- #
153
- def cast(hash)
154
- h
155
- hash.each do |k,v|
156
- h[key_proc[k]] = value_proc[v]
157
- end
158
- h
159
- end
160
-
161
- end
162
-
163
-
164
- #class Hash
165
- #
166
- # # Convert a Hash to a CastingHash.
167
- # def to_casting_hash(value_cast=nil, &key_cast)
168
- # CastingHash.new(self, value_cast, &key_cast)
169
- # end
170
- #
171
- #end
1
+ require 'hashery/casting_hash'
@@ -0,0 +1,82 @@
1
+ module Hashery
2
+
3
+ # This module is included into Ruby's core Hash class.
4
+ #
5
+ # These method derive from Ruby Facets.
6
+ module CoreExt
7
+
8
+ #
9
+ def to_h
10
+ self
11
+ end
12
+
13
+ #
14
+ def to_hash
15
+ self
16
+ end
17
+
18
+ # Synonym for Hash#rekey, but modifies the receiver in place (and returns it).
19
+ #
20
+ # foo = { :name=>'Gavin', :wife=>:Lisa }
21
+ # foo.rekey!{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa }
22
+ # foo.inspect #=> { "name"=>"Gavin", "wife"=>:Lisa }
23
+ #
24
+ def rekey(key_map=nil, &block)
25
+ if !(key_map or block)
26
+ block = lambda{|k| k.to_sym}
27
+ end
28
+
29
+ key_map ||= {}
30
+
31
+ hash = {}
32
+
33
+ (keys - key_map.keys).each do |key|
34
+ hash[key] = self[key]
35
+ end
36
+
37
+ key_map.each do |from, to|
38
+ hash[to] = self[from] if key?(from)
39
+ end
40
+
41
+ hash2 = {}
42
+
43
+ if block
44
+ if block.arity == 1 # TODO: is this condition needed?
45
+ hash.each do |k, v|
46
+ nk = block[k]
47
+ #nk = (NA == nk ? k : nk) # TODO: Can't support this here.
48
+ hash2[nk] = v
49
+ end
50
+ else
51
+ hash.each do |k, v|
52
+ nk = block[k,v]
53
+ #nk = (NA == nk ? k : nk) # TODO:
54
+ hash2[nk] = v
55
+ end
56
+ end
57
+ else
58
+ hash2 = hash
59
+ end
60
+
61
+ hash2
62
+ end
63
+
64
+ # Synonym for Hash#rekey, but modifies the receiver in place (and returns it).
65
+ #
66
+ # foo = { :name=>'Gavin', :wife=>:Lisa }
67
+ # foo.rekey!{ |k| k.to_s } #=> { "name"=>"Gavin", "wife"=>:Lisa }
68
+ # foo #=> { "name"=>"Gavin", "wife"=>:Lisa }
69
+ #
70
+ # CREDIT: Trans, Gavin Kistner
71
+
72
+ def rekey!(key_map=nil, &block)
73
+ replace(rekey(key_map, &block))
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+
80
+ class Hash #:nodoc:
81
+ include Hashery::CoreExt
82
+ end
@@ -124,6 +124,8 @@ class Dictionary
124
124
  end
125
125
  end
126
126
 
127
+ #
128
+
127
129
  def order
128
130
  reorder if @order_by
129
131
  @order
@@ -176,6 +178,7 @@ class Dictionary
176
178
  end
177
179
 
178
180
  #
181
+
179
182
  def reorder
180
183
  if @order_by
181
184
  assoc = @order.collect{ |k| [k,@hash[k]] }.sort_by(&@order_by)
@@ -1 +1,154 @@
1
- require 'hashery/fuzzyhash'
1
+ require 'set'
2
+
3
+ # = Fuzzy Hash
4
+ #
5
+ # A weird hash with special semantics for regex keys.
6
+ #
7
+ # This is useful when you want to have a lookup table that can either contain strings or regexes.
8
+ # For instance, you might want a catch all for certain regexes that perform a certain logic.
9
+ #
10
+ # >> hash = FuzzyHash.new
11
+ # >> hash[/^\d+$/] = 'number'
12
+ # >> hash[/.*/] = 'something'
13
+ # >> hash['chunky'] = 'bacon'
14
+ # >> hash['foo'] = 'vader'
15
+ #
16
+ # >> hash['foo']
17
+ # << 'vader'
18
+ # >> hash['food']
19
+ # << 'something'
20
+ # >> hash['123']
21
+ # << 'number'
22
+ #
23
+ # Copyright (c) 2009 Joshua Hull
24
+
25
+ class FuzzyHash
26
+
27
+ def initialize(init_hash = nil)
28
+ @fuzzies = []
29
+ @hash_reverse = {}
30
+ @fuzzies_reverse = {}
31
+ @fuzzy_hash = {}
32
+ @hash = {}
33
+ init_hash.each{ |key,value| self[key] = value } if init_hash
34
+ end
35
+
36
+ def clear
37
+ hash.clear
38
+ fuzzies.clear
39
+ hash_reverse.clear
40
+ fuzzies_reverse.clear
41
+ end
42
+
43
+ def size
44
+ hash.size + fuzzies.size
45
+ end
46
+ alias_method :count, :size
47
+
48
+
49
+ def ==(o)
50
+ o.is_a?(FuzzyHash)
51
+ o.send(:hash) == hash &&
52
+ o.send(:fuzzies) == fuzzies
53
+ end
54
+
55
+ def empty?
56
+ hash.empty? && fuzzies.empty?
57
+ end
58
+
59
+ def keys
60
+ hash.keys + fuzzy_hash.keys
61
+ end
62
+
63
+ def values
64
+ hash.values + fuzzies.collect{|r| r.last}
65
+ end
66
+
67
+ def each
68
+ hash.each{|k,v| yield k,v }
69
+ fuzzies.each{|v| yield v.first, v.last }
70
+ end
71
+
72
+ def delete_value(value)
73
+ hash.delete(hash_reverse[value]) || ((rr = fuzzies_reverse[value]) && fuzzies.delete_at(rr[0]))
74
+ end
75
+
76
+ def []=(key, value)
77
+ if Regexp === key
78
+ fuzzies.delete_if{|f| f.first.inspect.hash == key.inspect.hash}
79
+ fuzzies_reverse.delete_if{|k, v| v[1].inspect.hash == key.inspect.hash}
80
+ hash_reverse.delete_if{|k,v| v.inspect.hash == key.inspect.hash}
81
+
82
+ fuzzy_hash[key] = value
83
+ fuzzies << [key, value]
84
+ reset_fuzz_test!
85
+ fuzzies_reverse[value] = [fuzzies.size - 1, key, value]
86
+ else
87
+ hash[key] = value
88
+ hash_reverse.delete_if{|k,v| v.hash == key.hash}
89
+ hash_reverse[value] = key
90
+ end
91
+ value
92
+ end
93
+
94
+ def replace(src, dest)
95
+ if hash_reverse.key?(src)
96
+ key = hash_reverse[src]
97
+ hash[key] = dest
98
+ hash_reverse.delete(src)
99
+ hash_reverse[dest] = key
100
+ elsif fuzzies_reverse.key?(src)
101
+ key = fuzzies_reverse[src]
102
+ fuzzies[rkey[0]] = [rkey[1], dest]
103
+ fuzzies_reverse.delete(src)
104
+ fuzzies_reverse[dest] = [rkey[0], rkey[1], dest]
105
+ end
106
+ end
107
+
108
+ def [](key)
109
+ (hash.key?(key) && hash[key]) ||
110
+ ((lookup = fuzzy_lookup(key)) && lookup && lookup.first) ||
111
+ fuzzy_hash[key]
112
+ end
113
+
114
+ def match_with_result(key)
115
+ if hash.key?(key)
116
+ [hash[key], key]
117
+ else
118
+ fuzzy_lookup(key)
119
+ end
120
+ end
121
+
122
+ private
123
+ attr_reader :fuzzies, :hash_reverse, :fuzzies_reverse, :hash, :fuzzy_hash
124
+ attr_writer :fuzz_test
125
+
126
+ def reset_fuzz_test!
127
+ self.fuzz_test = nil
128
+ end
129
+
130
+ def fuzz_test
131
+ unless @fuzz_test
132
+ @fuzz_test = Object.new
133
+ @fuzz_test.instance_variable_set(:'@fuzzies', fuzzies)
134
+ method = "
135
+ def match(str)
136
+ case str\n
137
+ "
138
+ fuzzies.each_with_index do |reg, index|
139
+ method << "when #{reg.first.inspect}; [@fuzzies[#{index}][1], Regexp.last_match(0)];"
140
+ end
141
+ method << "end\nend\n"
142
+ @fuzz_test.instance_eval method
143
+ end
144
+ @fuzz_test
145
+ end
146
+
147
+ def fuzzy_lookup(key)
148
+ if !fuzzies.empty? && (value = fuzz_test.match(key))
149
+ value
150
+ end
151
+ end
152
+
153
+ end
154
+
@@ -1,154 +1 @@
1
- require 'set'
2
-
3
- # = Fuzzy Hash
4
- #
5
- # A weird hash with special semantics for regex keys.
6
- #
7
- # This is useful when you want to have a lookup table that can either contain strings or regexes.
8
- # For instance, you might want a catch all for certain regexes that perform a certain logic.
9
- #
10
- # >> hash = FuzzyHash.new
11
- # >> hash[/^\d+$/] = 'number'
12
- # >> hash[/.*/] = 'something'
13
- # >> hash['chunky'] = 'bacon'
14
- # >> hash['foo'] = 'vader'
15
- #
16
- # >> hash['foo']
17
- # << 'vader'
18
- # >> hash['food']
19
- # << 'something'
20
- # >> hash['123']
21
- # << 'number'
22
- #
23
- # Copyright (c) 2009 Joshua Hull
24
-
25
- class FuzzyHash
26
-
27
- def initialize(init_hash = nil)
28
- @fuzzies = []
29
- @hash_reverse = {}
30
- @fuzzies_reverse = {}
31
- @fuzzy_hash = {}
32
- @hash = {}
33
- init_hash.each{ |key,value| self[key] = value } if init_hash
34
- end
35
-
36
- def clear
37
- hash.clear
38
- fuzzies.clear
39
- hash_reverse.clear
40
- fuzzies_reverse.clear
41
- end
42
-
43
- def size
44
- hash.size + fuzzies.size
45
- end
46
- alias_method :count, :size
47
-
48
-
49
- def ==(o)
50
- o.is_a?(FuzzyHash)
51
- o.send(:hash) == hash &&
52
- o.send(:fuzzies) == fuzzies
53
- end
54
-
55
- def empty?
56
- hash.empty? && fuzzies.empty?
57
- end
58
-
59
- def keys
60
- hash.keys + fuzzy_hash.keys
61
- end
62
-
63
- def values
64
- hash.values + fuzzies.collect{|r| r.last}
65
- end
66
-
67
- def each
68
- hash.each{|k,v| yield k,v }
69
- fuzzies.each{|v| yield v.first, v.last }
70
- end
71
-
72
- def delete_value(value)
73
- hash.delete(hash_reverse[value]) || ((rr = fuzzies_reverse[value]) && fuzzies.delete_at(rr[0]))
74
- end
75
-
76
- def []=(key, value)
77
- if Regexp === key
78
- fuzzies.delete_if{|f| f.first.inspect.hash == key.inspect.hash}
79
- fuzzies_reverse.delete_if{|k, v| v[1].inspect.hash == key.inspect.hash}
80
- hash_reverse.delete_if{|k,v| v.inspect.hash == key.inspect.hash}
81
-
82
- fuzzy_hash[key] = value
83
- fuzzies << [key, value]
84
- reset_fuzz_test!
85
- fuzzies_reverse[value] = [fuzzies.size - 1, key, value]
86
- else
87
- hash[key] = value
88
- hash_reverse.delete_if{|k,v| v.hash == key.hash}
89
- hash_reverse[value] = key
90
- end
91
- value
92
- end
93
-
94
- def replace(src, dest)
95
- if hash_reverse.key?(src)
96
- key = hash_reverse[src]
97
- hash[key] = dest
98
- hash_reverse.delete(src)
99
- hash_reverse[dest] = key
100
- elsif fuzzies_reverse.key?(src)
101
- key = fuzzies_reverse[src]
102
- fuzzies[rkey[0]] = [rkey[1], dest]
103
- fuzzies_reverse.delete(src)
104
- fuzzies_reverse[dest] = [rkey[0], rkey[1], dest]
105
- end
106
- end
107
-
108
- def [](key)
109
- (hash.key?(key) && hash[key]) ||
110
- ((lookup = fuzzy_lookup(key)) && lookup && lookup.first) ||
111
- fuzzy_hash[key]
112
- end
113
-
114
- def match_with_result(key)
115
- if hash.key?(key)
116
- [hash[key], key]
117
- else
118
- fuzzy_lookup(key)
119
- end
120
- end
121
-
122
- private
123
- attr_reader :fuzzies, :hash_reverse, :fuzzies_reverse, :hash, :fuzzy_hash
124
- attr_writer :fuzz_test
125
-
126
- def reset_fuzz_test!
127
- self.fuzz_test = nil
128
- end
129
-
130
- def fuzz_test
131
- unless @fuzz_test
132
- @fuzz_test = Object.new
133
- @fuzz_test.instance_variable_set(:'@fuzzies', fuzzies)
134
- method = "
135
- def match(str)
136
- case str\n
137
- "
138
- fuzzies.each_with_index do |reg, index|
139
- method << "when #{reg.first.inspect}; [@fuzzies[#{index}][1], Regexp.last_match(0)];"
140
- end
141
- method << "end\nend\n"
142
- @fuzz_test.instance_eval method
143
- end
144
- @fuzz_test
145
- end
146
-
147
- def fuzzy_lookup(key)
148
- if !fuzzies.empty? && (value = fuzz_test.match(key))
149
- value
150
- end
151
- end
152
-
153
- end
154
-
1
+ require 'hashery/fuzzy_hash'