hashery 1.5.0 → 2.0.0

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