hashery 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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'