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,99 +1,154 @@
1
1
  require 'hashery/open_hash'
2
- #require 'facets/nullclass'
3
2
 
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
3
+ module Hashery
62
4
 
5
+ # OpenCascade is subclass of OpenHash. It differs in a few
6
+ # significant ways. The reason this class is called "cascade" is that
7
+ # every internal Hash is transformed into an OpenCascade dynamically
8
+ # upon access. This makes it easy to create "cascading" references.
9
+ #
10
+ # h = { :x => { :y => { :z => 1 } } }
11
+ # c = OpenCascade[h]
12
+ # c.x.y.z #=> 1
13
+ #
14
+ # As soon as you access a node it automatically becomes an OpenCascade.
15
+ #
16
+ # c = OpenCascade.new #=> #<OpenCascade:0x7fac3680ccf0 {}>
17
+ # c.r #=> #<OpenCascade:0x7fac368084c0 {}>
18
+ # c.a.b #=> #<OpenCascade:0x7fac3680a4f0 {}>
63
19
  #
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])
20
+ # But if you set a node, then that will be that value.
21
+ #
22
+ # c.a.b = 4 #=> 4
23
+ #
24
+ # To query a node without causing the auto-creation of an OpenCasade
25
+ # instance, use the `?`-mark.
26
+ #
27
+ # c.a.z? #=> nil
28
+ #
29
+ # OpenCascade also transforms Hashes within Arrays.
30
+ #
31
+ # h = { :x=>[ {:a=>1}, {:a=>2} ], :y=>1 }
32
+ # c = OpenCascade[h]
33
+ # c.x.first.a.assert == 1
34
+ # c.x.last.a.assert == 2
35
+ #
36
+ # Finally, you can set call a private method via bang methods using the `!`-mark.
37
+ #
38
+ # c = OpenCascade.new #=> #<OpenCascade:0x7fac3680ccf0 {}>
39
+ # c.each = 4
40
+ # c.each! do |k,v|
41
+ # ...
42
+ # end
43
+ #
44
+ # c.x!(4).y!(3) #=> #<OpenCascade:0x7fac3680ccf0 {:x=>4, :y=>3}>
45
+ #
46
+ class OpenCascade < OpenHash
47
+
48
+ #
49
+ #def self.[](hash)
50
+ # oc = new
51
+ # hash.each{ |(k,v)| oc.store(k,v) }
52
+ # oc
53
+ #end
54
+
55
+ #
56
+ # Initialize new OpenCascade instance.
57
+ #
58
+ # default - The usual default object.
59
+ #
60
+ def initialize(*default)
61
+ @read = {}
62
+
63
+ leet = lambda { |h,k| h[k] = OpenCascade.new(&leet) }
64
+ super(*default, &leet)
65
+ end
66
+
67
+ #
68
+ # Alias for original read method.
69
+ #
70
+ alias :read! :read
71
+
72
+ #
73
+ # Read value given a +key+.
74
+ #
75
+ # key - Index keey to lookup.
76
+ #
77
+ # Returns value.
78
+ #
79
+ def read(key)
80
+ if @read[cast_key(key)]
81
+ super(key)
78
82
  else
79
- self[name] = OpenCascade.new #self.class.new
83
+ @read[cast_key(key)] = store(key, cast_value(super(key)))
80
84
  end
81
85
  end
82
- end
86
+
87
+ #
88
+ #
89
+ #
90
+ def method_missing(sym, *args, &blk)
91
+ type = sym.to_s[-1,1]
92
+ name = sym.to_s.gsub(/[=!?]$/, '').to_sym
93
+
94
+ case type
95
+ when '='
96
+ store(name, args.first)
97
+ when '?'
98
+ key?(name) ? read!(name) : nil # key?(name)
99
+ when '!'
100
+ __send__(name, *args, &blk)
101
+ else
102
+ #if key?(name)
103
+ read(name)
104
+ #else
105
+ # #default = OpenCascade.new #self.class.new
106
+ # #default = default_proc ? default_proc.call(self, name) : default
107
+ # store(name, read(name))
108
+ #end
109
+ end
110
+ end
111
+
112
+ #def each
113
+ # super do |key, entry|
114
+ # yield([key, transform_entry(entry)])
115
+ # end
116
+ #end
83
117
 
84
118
  private
85
119
 
86
120
  #
87
- def transform_entry(entry)
121
+ # Cast value, such that Hashes are converted to OpenCascades.
122
+ # And Hashes in Arrays are converted to OpenCascades as well.
123
+ #
124
+ def cast_value(entry)
88
125
  case entry
89
126
  when Hash
90
- OpenCascade.new(entry) #self.class.new(val)
127
+ OpenCascade[entry] #self.class.new(val)
91
128
  when Array
92
- entry.map{ |e| transform_entry(e) }
129
+ entry.map{ |e| cast_value(e) }
93
130
  else
94
131
  entry
95
132
  end
96
133
  end
97
134
 
135
+ end
136
+
98
137
  end
99
138
 
139
+ #--
140
+ # Last, when an entry is not found, 'null' is returned rather then 'nil'.
141
+ # This allows for run-on entries withuot error. Eg.
142
+ #
143
+ # o = OpenCascade.new
144
+ # o.a.b.c #=> null
145
+ #
146
+ # Unfortuately this requires an explict test for null? in 'if' conditions.
147
+ #
148
+ # if o.a.b.c.null? # true if null
149
+ # if o.a.b.c.nil? # true if nil or null
150
+ # if o.a.b.c.not? # true if nil or null or false
151
+ #
152
+ # So be sure to take that into account.
153
+ #++
154
+
@@ -1,77 +1,143 @@
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.
1
+ require 'hashery/crud_hash'
9
2
 
10
- class OpenHash < Hash
11
-
12
- # New OpenHash.
13
- def initialize(data={})
14
- super()
15
- merge!(data)
16
- end
3
+ module Hashery
17
4
 
5
+ # OpenHash is a Hash, but also supports open properties much like
6
+ # OpenStruct.
18
7
  #
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
8
+ # Only names that are name methods of Hash can be used as open slots.
9
+ # To open a slot for a name that would otherwise be a method, the
10
+ # method needs to be made private. The `#open!` method can be used
11
+ # to handle this.
12
+ #
13
+ # Examples
14
+ #
15
+ # o = OpenHash.new
16
+ # o.open!(:send)
17
+ # o.send = 4
18
+ #
19
+ class OpenHash < CRUDHash
20
+
21
+ alias :object_class :class
22
+
23
+ #FILTER = /(^__|^\W|^instance_|^object_|^to_)/
24
+ #methods = Hash.instance_methods(true).select{ |m| m !~ FILTER }
25
+ #methods = methods - [:each, :inspect, :send] # :class, :as]
26
+ #private *methods
27
+
28
+ #
29
+ # Initialize new OpenHash instance.
30
+ #
31
+ # TODO: Maybe `safe` should be the first argument?
32
+ #
33
+ def initialize(default=nil, safe=false, &block)
34
+ @safe = safe
35
+ super(*[default].compact, &block)
27
36
  end
28
- end
29
37
 
30
- #
31
- def respond_to?(name)
32
- key?(name.to_sym) || super(name)
33
- end
38
+ #
39
+ # If safe is set to true, then public methods cannot be overriden
40
+ # by hash keys.
41
+ #
42
+ attr_accessor :safe
34
43
 
35
- #
36
- def to_h
37
- dup
38
- end
44
+ #
45
+ # Index `value` to `key`. Unless safe mode, will also open up the
46
+ # key if it is not already open.
47
+ #
48
+ # key - Index key to associate with value.
49
+ # value - Value to be associate with key.
50
+ #
51
+ # Returns +value+.
52
+ #
53
+ def store(key, value)
54
+ open!(key)
55
+ super(key, value)
56
+ end
39
57
 
40
- #
41
- def to_hash
42
- dup
43
- end
58
+ #
59
+ # Open up a slot that that would normally be a Hash method.
60
+ #
61
+ # The only methods that can't be opened are ones starting with `__`.
62
+ #
63
+ # methods - [Array<String,Symbol>] method names
64
+ #
65
+ # Returns Array of slot names that were opened.
66
+ #
67
+ def open!(*methods)
68
+ # only select string and symbols, any other type of key is allowed,
69
+ # it just won't be accessible via dynamic methods.
70
+ methods = methods.select{ |x| String === x || Symbol === x }
71
+ # @todo should we just ignore these instead of raising an error?
72
+ #methods.reject!{ |x| x.to_s =~ /^__/ }
73
+ if methods.any?{ |m| m.to_s.start_with?('__') }
74
+ raise ArgumentError, "cannot set shadow methods"
75
+ end
76
+ # only public methods need to be made private
77
+ methods = methods.map{ |x| x.to_sym }
78
+ methods = methods & public_methods(true)
79
+ if @safe
80
+ raise ArgumentError, "cannot set public method" unless methods.empty?
81
+ else
82
+ (class << self; self; end).class_eval{ private *methods }
83
+ end
84
+ methods
85
+ end
44
86
 
45
- #
46
- def inspect
47
- super
48
- end
87
+ # @deprecated
88
+ alias :omit! :open!
49
89
 
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
90
+ #
91
+ # Is a slot open?
92
+ #
93
+ # method - [String,Symbol] method name
94
+ #
95
+ # Returns `true` or `false`.
96
+ #
97
+ def open?(method)
98
+ ! public_methods(true).include?(method.to_sym)
99
+ end
55
100
 
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]
101
+ #
102
+ # Make specific Hash methods available for use that have previously opened.
103
+ #
104
+ # methods - [Array<String,Symbol>] method names
105
+ #
106
+ # Returns +methods+.
107
+ #
108
+ def close!(*methods)
109
+ (class << self; self; end).class_eval{ public *methods }
110
+ methods
111
+ end
112
+
113
+ #
114
+ #
115
+ #
116
+ def method_missing(s,*a, &b)
117
+ type = s.to_s[-1,1]
118
+ name = s.to_s.sub(/[!?=]$/, '')
119
+ key = name.to_sym
120
+
121
+ case type
122
+ when '='
123
+ #open!(key) unless open?(key)
124
+ #self[key] = a.first
125
+ store(key, a.first)
126
+ when '?'
127
+ key?(key)
128
+ when '!'
129
+ # call an underlying private method
130
+ # TODO: limit this to omitted methods (from included) ?
131
+ __send__(name, *a, &b)
71
132
  else
72
- super(s,*a,&b)
133
+ #if key?(key)
134
+ read(key)
135
+ #else
136
+ # super(s,*a,&b)
137
+ #end
73
138
  end
74
139
  end
140
+
75
141
  end
76
142
 
77
143
  end
@@ -1,163 +1,169 @@
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)
1
+ module Hashery
2
+
3
+ # OrderedHash is 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
23
24
  end
24
25
  end
25
26
  end
26
- end
27
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
28
+ # Hash is ordered in Ruby 1.9!
29
+ if RUBY_VERSION < '1.9'
30
+
31
+ def initialize(*args, &block)
32
+ super
33
+ @keys = []
34
+ end
35
+
36
+ def self.[](*args)
37
+ ordered_hash = new
34
38
 
35
- def self.[](*args)
36
- ordered_hash = new
39
+ if (args.length == 1 && args.first.is_a?(Array))
40
+ args.first.each do |key_value_pair|
41
+ next unless (key_value_pair.is_a?(Array))
42
+ ordered_hash[key_value_pair[0]] = key_value_pair[1]
43
+ end
37
44
 
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]
45
+ return ordered_hash
42
46
  end
43
47
 
44
- return ordered_hash
45
- end
48
+ unless (args.size % 2 == 0)
49
+ raise ArgumentError.new("odd number of arguments for Hash")
50
+ end
46
51
 
47
- unless (args.size % 2 == 0)
48
- raise ArgumentError.new("odd number of arguments for Hash")
49
- end
52
+ args.each_with_index do |val, ind|
53
+ next if (ind % 2 != 0)
54
+ ordered_hash[val] = args[ind + 1]
55
+ end
50
56
 
51
- args.each_with_index do |val, ind|
52
- next if (ind % 2 != 0)
53
- ordered_hash[val] = args[ind + 1]
57
+ ordered_hash
54
58
  end
55
59
 
56
- ordered_hash
57
- end
58
-
59
- def initialize_copy(other)
60
- super(other)
61
- @keys = other.keys
62
- end
60
+ def initialize_copy(other)
61
+ super(other)
62
+ @keys = other.keys
63
+ end
63
64
 
64
- def []=(key, value)
65
- @keys << key unless key?(key)
66
- super(key, value)
67
- end
65
+ def []=(key, value)
66
+ @keys << key unless key?(key)
67
+ super(key, value)
68
+ end
68
69
 
69
- def delete(key)
70
- if has_key? key
71
- index = @keys.index(key)
72
- @keys.delete_at(index)
70
+ def delete(key)
71
+ if has_key? key
72
+ index = @keys.index(key)
73
+ @keys.delete_at(index)
74
+ end
75
+ super(key)
73
76
  end
74
- super(key)
75
- end
76
77
 
77
- def delete_if
78
- super
79
- sync_keys!
80
- self
81
- end
78
+ def delete_if
79
+ super
80
+ sync_keys!
81
+ self
82
+ end
82
83
 
83
- def reject!
84
- super
85
- sync_keys!
86
- self
87
- end
84
+ def reject!
85
+ super
86
+ sync_keys!
87
+ self
88
+ end
88
89
 
89
- def reject(&block)
90
- dup.reject!(&block)
91
- end
90
+ def reject(&block)
91
+ dup.reject!(&block)
92
+ end
92
93
 
93
- def keys
94
- @keys.dup
95
- end
94
+ def keys
95
+ @keys.dup
96
+ end
96
97
 
97
- def values
98
- @keys.collect{ |key| self[key] }
99
- end
98
+ def values
99
+ @keys.collect{ |key| self[key] }
100
+ end
100
101
 
101
- def to_hash
102
- self
103
- end
102
+ def to_hash
103
+ self
104
+ end
104
105
 
105
- def to_a
106
- @keys.map{ |key| [ key, self[key] ] }
107
- end
106
+ def to_a
107
+ @keys.map{ |key| [ key, self[key] ] }
108
+ end
108
109
 
109
- def each_key
110
- @keys.each{ |key| yield(key) }
111
- end
110
+ def each_key
111
+ @keys.each{ |key| yield(key) }
112
+ end
112
113
 
113
- def each_value
114
- @keys.each{ |key| yield(self[key]) }
115
- end
114
+ def each_value
115
+ @keys.each{ |key| yield(self[key]) }
116
+ end
116
117
 
117
- def each
118
- @keys.each{ |key| yield(key, self[key]) }
119
- end
118
+ def each
119
+ @keys.each{ |key| yield(key, self[key]) }
120
+ end
120
121
 
121
- alias_method :each_pair, :each
122
+ alias_method :each_pair, :each
122
123
 
123
- def clear
124
- super
125
- @keys.clear
126
- self
127
- end
124
+ def clear
125
+ super
126
+ @keys.clear
127
+ self
128
+ end
128
129
 
129
- def shift
130
- k = @keys.first
131
- v = delete(k)
132
- [k, v]
133
- end
130
+ def shift
131
+ k = @keys.first
132
+ v = delete(k)
133
+ [k, v]
134
+ end
134
135
 
135
- def merge!(other_hash)
136
- other_hash.each{ |k,v| self[k] = v }
137
- self
138
- end
136
+ def merge!(other_hash)
137
+ other_hash.each{ |k,v| self[k] = v }
138
+ self
139
+ end
139
140
 
140
- def merge(other_hash)
141
- dup.merge!(other_hash)
142
- end
141
+ def merge(other_hash)
142
+ dup.merge!(other_hash)
143
+ end
143
144
 
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
145
+ # When replacing with another hash, the initial order of our
146
+ # keys must come from the other hash, ordered or not.
147
+ def replace(other)
148
+ super
149
+ @keys = other.keys
150
+ self
151
+ end
151
152
 
152
- def inspect
153
- "#<OrderedHash #{super}>"
154
- end
153
+ def inspect
154
+ "#<OrderedHash #{super}>"
155
+ end
155
156
 
156
157
  private
158
+
157
159
  def sync_keys!
158
160
  @keys.delete_if{ |k| !key?(k) }
159
161
  end
162
+
163
+ end
164
+
160
165
  end
166
+
161
167
  end
162
168
 
163
169
  require 'yaml'