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 +1,99 @@
1
- require 'hashery/opencascade'
1
+ require 'hashery/open_hash'
2
+ #require 'facets/nullclass'
3
+
4
+ # = OpenCascade
5
+ #
6
+ # OpenCascade is subclass of OpenHash. It differs in a few
7
+ # significant ways.
8
+ #
9
+ # The main reason this class is labeled "cascade", every internal
10
+ # Hash is transformed into an OpenCascade dynamically upon access.
11
+ # This makes it easy to create "cascading" references.
12
+ #
13
+ # h = { :x => { :y => { :z => 1 } } }
14
+ # c = OpenCascade[h]
15
+ # c.x.y.z #=> 1
16
+ #
17
+ # As soon as you access a node it automatically becomes an OpenCascade.
18
+ #
19
+ # c = OpenCascade.new #=> #<OpenCascade:0x7fac3680ccf0 {}>
20
+ # c.r #=> #<OpenCascade:0x7fac368084c0 {}>
21
+ # c.a.b #=> #<OpenCascade:0x7fac3680a4f0 {}>
22
+ #
23
+ # But if you set a node, then that will be it's value.
24
+ #
25
+ # c.a.b = 4 #=> 4
26
+ #
27
+ # To query a node without causing the auto-creation of an OpenCasade
28
+ # object, use the ?-mark.
29
+ #
30
+ # 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
+ # c.x.first.a.assert == 1
37
+ # c.x.last.a.assert == 2
38
+ #
39
+ # Finally, you can set a node and get the reciever back using
40
+ # the !-mark.
41
+ #
42
+ # c = OpenCascade.new #=> #<OpenCascade:0x7fac3680ccf0 {}>
43
+ # c.x!(4).y!(3) #=> #<OpenCascade:0x7fac3680ccf0 {:x=>4, :y=>3}>
44
+ #
45
+ #--
46
+ # Last, when an entry is not found, 'null' is returned rather then 'nil'.
47
+ # This allows for run-on entries withuot error. Eg.
48
+ #
49
+ # o = OpenCascade.new
50
+ # o.a.b.c #=> null
51
+ #
52
+ # Unfortuately this requires an explict test for null? in 'if' conditions.
53
+ #
54
+ # if o.a.b.c.null? # true if null
55
+ # if o.a.b.c.nil? # true if nil or null
56
+ # if o.a.b.c.not? # true if nil or null or false
57
+ #
58
+ # So be sure to take that into account.
59
+ #++
60
+
61
+ class OpenCascade < OpenHash
62
+
63
+ #
64
+ def method_missing(sym, *args, &blk)
65
+ type = sym.to_s[-1,1]
66
+ name = sym.to_s.gsub(/[=!?]$/, '').to_sym
67
+ case type
68
+ when '='
69
+ self[name] = args.first
70
+ when '!'
71
+ #@hash.__send__(name, *args, &blk)
72
+ __send__(name, *args, &blk)
73
+ when '?'
74
+ self[name]
75
+ else
76
+ if key?(name)
77
+ self[name] = transform_entry(self[name])
78
+ else
79
+ self[name] = OpenCascade.new #self.class.new
80
+ end
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ #
87
+ def transform_entry(entry)
88
+ case entry
89
+ when Hash
90
+ OpenCascade.new(entry) #self.class.new(val)
91
+ when Array
92
+ entry.map{ |e| transform_entry(e) }
93
+ else
94
+ entry
95
+ end
96
+ end
97
+
98
+ end
99
+
@@ -1 +1,77 @@
1
- require 'hashery/openhash'
1
+ # = OpenHash
2
+ #
3
+ # OpenHash is very similar to Ruby's own OpenStruct, but it offers some
4
+ # useful advantages in that it is a true Hash object.
5
+ #
6
+ # Because OpenHash is a subclass of Hash, it can do everything a Hash
7
+ # can *unless* a Hash method has been explicity exempted for use
8
+ # as an open read/writer via the #omit! method.
9
+
10
+ class OpenHash < Hash
11
+
12
+ # New OpenHash.
13
+ def initialize(data={})
14
+ super()
15
+ merge!(data)
16
+ end
17
+
18
+ #
19
+ def <<(x)
20
+ case x
21
+ when Hash
22
+ update(x)
23
+ when Array
24
+ x.each_slice(2) do |(k,v)|
25
+ self[k] = v
26
+ end
27
+ end
28
+ end
29
+
30
+ #
31
+ def respond_to?(name)
32
+ key?(name.to_sym) || super(name)
33
+ end
34
+
35
+ #
36
+ def to_h
37
+ dup
38
+ end
39
+
40
+ #
41
+ def to_hash
42
+ dup
43
+ end
44
+
45
+ #
46
+ def inspect
47
+ super
48
+ end
49
+
50
+ # Omit specific Hash methods from slot protection.
51
+ def omit!(*methods)
52
+ methods.reject!{ |x| x.to_s =~ /^__/ }
53
+ (class << self; self; end).class_eval{ private *methods }
54
+ end
55
+
56
+ # Route get and set calls.
57
+ def method_missing(s,*a, &b)
58
+ type = s.to_s[-1,1]
59
+ name = s.to_s.sub(/[!?=]$/, '')
60
+ key = name.to_sym
61
+ case type
62
+ when '='
63
+ self[key] = a[0]
64
+ #when '!'
65
+ # self[s] = OpenHash.new
66
+ when '?'
67
+ key?(key)
68
+ else
69
+ if key?(key)
70
+ self[key]
71
+ else
72
+ super(s,*a,&b)
73
+ end
74
+ end
75
+ end
76
+
77
+ end
@@ -1,99 +1 @@
1
- require 'hashery/openhash'
2
- #require 'facets/nullclass'
3
-
4
- # = OpenCascade
5
- #
6
- # OpenCascade is subclass of OpenHash. It differs in a few
7
- # significant ways.
8
- #
9
- # The main reason this class is labeled "cascade", every internal
10
- # Hash is transformed into an OpenCascade dynamically upon access.
11
- # This makes it easy to create "cascading" references.
12
- #
13
- # h = { :x => { :y => { :z => 1 } } }
14
- # c = OpenCascade[h]
15
- # c.x.y.z #=> 1
16
- #
17
- # As soon as you access a node it automatically becomes an OpenCascade.
18
- #
19
- # c = OpenCascade.new #=> #<OpenCascade:0x7fac3680ccf0 {}>
20
- # c.r #=> #<OpenCascade:0x7fac368084c0 {}>
21
- # c.a.b #=> #<OpenCascade:0x7fac3680a4f0 {}>
22
- #
23
- # But if you set a node, then that will be it's value.
24
- #
25
- # c.a.b = 4 #=> 4
26
- #
27
- # To query a node without causing the auto-creation of an OpenCasade
28
- # object, use the ?-mark.
29
- #
30
- # 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
- # c.x.first.a.assert == 1
37
- # c.x.last.a.assert == 2
38
- #
39
- # Finally, you can set a node and get the reciever back using
40
- # the !-mark.
41
- #
42
- # c = OpenCascade.new #=> #<OpenCascade:0x7fac3680ccf0 {}>
43
- # c.x!(4).y!(3) #=> #<OpenCascade:0x7fac3680ccf0 {:x=>4, :y=>3}>
44
- #
45
- #--
46
- # Last, when an entry is not found, 'null' is returned rather then 'nil'.
47
- # This allows for run-on entries withuot error. Eg.
48
- #
49
- # o = OpenCascade.new
50
- # o.a.b.c #=> null
51
- #
52
- # Unfortuately this requires an explict test for null? in 'if' conditions.
53
- #
54
- # if o.a.b.c.null? # true if null
55
- # if o.a.b.c.nil? # true if nil or null
56
- # if o.a.b.c.not? # true if nil or null or false
57
- #
58
- # So be sure to take that into account.
59
- #++
60
-
61
- class OpenCascade < OpenHash
62
-
63
- #
64
- def method_missing(sym, *args, &blk)
65
- type = sym.to_s[-1,1]
66
- name = sym.to_s.gsub(/[=!?]$/, '').to_sym
67
- case type
68
- when '='
69
- self[name] = args.first
70
- when '!'
71
- #@hash.__send__(name, *args, &blk)
72
- __send__(name, *args, &blk)
73
- when '?'
74
- self[name]
75
- else
76
- if key?(name)
77
- self[name] = transform_entry(self[name])
78
- else
79
- self[name] = OpenCascade.new #self.class.new
80
- end
81
- end
82
- end
83
-
84
- private
85
-
86
- #
87
- def transform_entry(entry)
88
- case entry
89
- when Hash
90
- OpenCascade.new(entry) #self.class.new(val)
91
- when Array
92
- entry.map{ |e| transform_entry(e) }
93
- else
94
- entry
95
- end
96
- end
97
-
98
- end
99
-
1
+ require 'hashery/open_cascade'
@@ -1,77 +1 @@
1
- # = OpenHash
2
- #
3
- # OpenHash is very similar to Ruby's own OpenStruct, but it offers some
4
- # useful advantages in that it is a true Hash object.
5
- #
6
- # Because OpenHash is a subclass of Hash, it can do everything a Hash
7
- # can *unless* a Hash method has been explicity exempted for use
8
- # as an open read/writer via the #omit! method.
9
-
10
- class OpenHash < Hash
11
-
12
- # New OpenHash.
13
- def initialize(data={})
14
- super()
15
- merge!(data)
16
- end
17
-
18
- #
19
- def <<(x)
20
- case x
21
- when Hash
22
- update(x)
23
- when Array
24
- x.each_slice(2) do |(k,v)|
25
- self[k] = v
26
- end
27
- end
28
- end
29
-
30
- #
31
- def respond_to?(name)
32
- key?(name.to_sym) || super(name)
33
- end
34
-
35
- #
36
- def to_h
37
- dup
38
- end
39
-
40
- #
41
- def to_hash
42
- dup
43
- end
44
-
45
- #
46
- def inspect
47
- super
48
- end
49
-
50
- # Omit specific Hash methods from slot protection.
51
- def omit!(*methods)
52
- methods.reject!{ |x| x.to_s =~ /^__/ }
53
- (class << self; self; end).class_eval{ private *methods }
54
- end
55
-
56
- # Route get and set calls.
57
- def method_missing(s,*a, &b)
58
- type = s.to_s[-1,1]
59
- name = s.to_s.sub(/[!?=]$/, '')
60
- key = name.to_sym
61
- case type
62
- when '='
63
- self[key] = a[0]
64
- #when '!'
65
- # self[s] = OpenHash.new
66
- when '?'
67
- key?(key)
68
- else
69
- if key?(key)
70
- self[key]
71
- else
72
- super(s,*a,&b)
73
- end
74
- end
75
- end
76
-
77
- end
1
+ require 'hashery/open_hash'
@@ -1 +1,168 @@
1
- require 'hashery/orderedhash'
1
+ # = OrderedHash
2
+ #
3
+ # A simple ordered hash implmentation, for users of
4
+ # Ruby 1.8.7 or less.
5
+ #
6
+ # NOTE: As of Ruby 1.9+ this class is not needed, since
7
+ # Ruby 1.9's standard Hash tracks inseration order.
8
+ #
9
+ # This implementation derives from the same class in
10
+ # ActiveSupport library.
11
+
12
+ class OrderedHash < ::Hash
13
+
14
+ def to_yaml_type
15
+ "!tag:yaml.org,2002:omap"
16
+ end
17
+
18
+ def to_yaml(opts = {})
19
+ YAML.quick_emit(self, opts) do |out|
20
+ out.seq(taguri, to_yaml_style) do |seq|
21
+ each do |k, v|
22
+ seq.add(k => v)
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ # Hash is ordered in Ruby 1.9!
29
+ if RUBY_VERSION < '1.9'
30
+ def initialize(*args, &block)
31
+ super
32
+ @keys = []
33
+ end
34
+
35
+ def self.[](*args)
36
+ ordered_hash = new
37
+
38
+ if (args.length == 1 && args.first.is_a?(Array))
39
+ args.first.each do |key_value_pair|
40
+ next unless (key_value_pair.is_a?(Array))
41
+ ordered_hash[key_value_pair[0]] = key_value_pair[1]
42
+ end
43
+
44
+ return ordered_hash
45
+ end
46
+
47
+ unless (args.size % 2 == 0)
48
+ raise ArgumentError.new("odd number of arguments for Hash")
49
+ end
50
+
51
+ args.each_with_index do |val, ind|
52
+ next if (ind % 2 != 0)
53
+ ordered_hash[val] = args[ind + 1]
54
+ end
55
+
56
+ ordered_hash
57
+ end
58
+
59
+ def initialize_copy(other)
60
+ super(other)
61
+ @keys = other.keys
62
+ end
63
+
64
+ def []=(key, value)
65
+ @keys << key unless key?(key)
66
+ super(key, value)
67
+ end
68
+
69
+ def delete(key)
70
+ if has_key? key
71
+ index = @keys.index(key)
72
+ @keys.delete_at(index)
73
+ end
74
+ super(key)
75
+ end
76
+
77
+ def delete_if
78
+ super
79
+ sync_keys!
80
+ self
81
+ end
82
+
83
+ def reject!
84
+ super
85
+ sync_keys!
86
+ self
87
+ end
88
+
89
+ def reject(&block)
90
+ dup.reject!(&block)
91
+ end
92
+
93
+ def keys
94
+ @keys.dup
95
+ end
96
+
97
+ def values
98
+ @keys.collect{ |key| self[key] }
99
+ end
100
+
101
+ def to_hash
102
+ self
103
+ end
104
+
105
+ def to_a
106
+ @keys.map{ |key| [ key, self[key] ] }
107
+ end
108
+
109
+ def each_key
110
+ @keys.each{ |key| yield(key) }
111
+ end
112
+
113
+ def each_value
114
+ @keys.each{ |key| yield(self[key]) }
115
+ end
116
+
117
+ def each
118
+ @keys.each{ |key| yield(key, self[key]) }
119
+ end
120
+
121
+ alias_method :each_pair, :each
122
+
123
+ def clear
124
+ super
125
+ @keys.clear
126
+ self
127
+ end
128
+
129
+ def shift
130
+ k = @keys.first
131
+ v = delete(k)
132
+ [k, v]
133
+ end
134
+
135
+ def merge!(other_hash)
136
+ other_hash.each{ |k,v| self[k] = v }
137
+ self
138
+ end
139
+
140
+ def merge(other_hash)
141
+ dup.merge!(other_hash)
142
+ end
143
+
144
+ # When replacing with another hash, the initial order of our
145
+ # keys must come from the other hash, ordered or not.
146
+ def replace(other)
147
+ super
148
+ @keys = other.keys
149
+ self
150
+ end
151
+
152
+ def inspect
153
+ "#<OrderedHash #{super}>"
154
+ end
155
+
156
+ private
157
+ def sync_keys!
158
+ @keys.delete_if{ |k| !key?(k) }
159
+ end
160
+ end
161
+ end
162
+
163
+ require 'yaml'
164
+
165
+ YAML.add_builtin_type("omap") do |type, val|
166
+ OrderedHash[val.map(&:to_a).map(&:first)]
167
+ end
168
+