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