The order of iteration over hashes in Ruby 1.8 is undefined. For example,
you do not know the order in which keys will return keys, or
each yield pairs. ActiveSupport::OrderedHash implements a
hash that preserves insertion order, as in Ruby 1.9:
oh = ActiveSupport::OrderedHash.new
oh[:a] = 1
oh[:b] = 2
oh.keys # => [:a, :b], this order is guaranteed
ActiveSupport::OrderedHash is namespaced to prevent conflicts with
other implementations.
Methods
- #
-
- C
-
- D
-
- E
-
- I
-
- K
-
- M
-
- N
-
- R
-
- S
-
- T
-
- V
-
Class Public methods
Source: show
| on GitHub
73: def self.[](*args)
74: ordered_hash = new
75:
76: if (args.length == 1 && args.first.is_a?(Array))
77: args.first.each do |key_value_pair|
78: next unless (key_value_pair.is_a?(Array))
79: ordered_hash[key_value_pair[0]] = key_value_pair[1]
80: end
81:
82: return ordered_hash
83: end
84:
85: unless (args.size % 2 == 0)
86: raise ArgumentError.new("odd number of arguments for Hash")
87: end
88:
89: args.each_with_index do |val, ind|
90: next if (ind % 2 != 0)
91: ordered_hash[val] = args[ind + 1]
92: end
93:
94: ordered_hash
95: end
In MRI the Hash class is core and written in C.
In particular, methods are programmed with explicit C function calls and
polymorphism is not honored.
For example, []= is crucial in this implementation to maintain the @keys
array but hash.c invokes rb_hash_aset() originally. This prevents method
reuse through inheritance and forces us to reimplement stuff.
For instance, we cannot use the inherited merge! because albeit the algorithm
itself would work, our []= is not being called at all by the C code.
Source: show
| on GitHub
68: def initialize(*args, &block)
69: super
70: @keys = []
71: end
Instance Public methods
Source: show
| on GitHub
103: def []=(key, value)
104: @keys << key unless has_key?(key)
105: super
106: end
Source: show
| on GitHub
174: def clear
175: super
176: @keys.clear
177: self
178: end
Source: show
| on GitHub
108: def delete(key)
109: if has_key? key
110: index = @keys.index(key)
111: @keys.delete_at index
112: end
113: super
114: end
Source: show
| on GitHub
116: def delete_if
117: super
118: sync_keys!
119: self
120: end
Source: show
| on GitHub
160: def each
161: return to_enum(:each) unless block_given?
162: @keys.each {|key| yield [key, self[key]]}
163: self
164: end
Source: show
| on GitHub
148: def each_key
149: return to_enum(:each_key) unless block_given?
150: @keys.each { |key| yield key }
151: self
152: end
Source: show
| on GitHub
166: def each_pair
167: return to_enum(:each_pair) unless block_given?
168: @keys.each {|key| yield key, self[key]}
169: self
170: end
Source: show
| on GitHub
154: def each_value
155: return to_enum(:each_value) unless block_given?
156: @keys.each { |key| yield self[key]}
157: self
158: end
Source: show
| on GitHub
28: def encode_with(coder)
29: coder.represent_seq '!omap', map { |k,v| { k => v } }
30: end
Source: show
| on GitHub
51: def extractable_options?
52: true
53: end
Source: show
| on GitHub
97: def initialize_copy(other)
98: super
99:
100: @keys = other.keys
101: end
Source: show
| on GitHub
212: def inspect
213: "#<OrderedHash #{super}>"
214: end
Source: show
| on GitHub
208: def invert
209: OrderedHash[self.to_a.map!{|key_value_pair| key_value_pair.reverse}]
210: end
merge(other_hash, &block)
Source: show
| on GitHub
197: def merge(other_hash, &block)
198: dup.merge!(other_hash, &block)
199: end
Source: show
| on GitHub
186: def merge!(other_hash)
187: if block_given?
188: other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v }
189: else
190: other_hash.each { |k, v| self[k] = v }
191: end
192: self
193: end
nested_under_indifferent_access()
Source: show
| on GitHub
46: def nested_under_indifferent_access
47: self
48: end
Source: show
| on GitHub
128: def reject(&block)
129: dup.reject!(&block)
130: end
Source: show
| on GitHub
122: def reject!
123: super
124: sync_keys!
125: self
126: end
When replacing with another hash, the initial order of our keys must come
from the other hash -ordered or not.
Source: show
| on GitHub
202: def replace(other)
203: super
204: @keys = other.keys
205: self
206: end
Source: show
| on GitHub
180: def shift
181: k = @keys.first
182: v = delete(k)
183: [k, v]
184: end
Source: show
| on GitHub
217: def sync_keys!
218: @keys.delete_if {|k| !has_key?(k)}
219: end
Source: show
| on GitHub
144: def to_a
145: @keys.map { |key| [ key, self[key] ] }
146: end
Source: show
| on GitHub
32: def to_yaml(opts = {})
33: if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
34: return super
35: end
36:
37: YAML.quick_emit(self, opts) do |out|
38: out.seq(taguri) do |seq|
39: each do |k, v|
40: seq.add(k => v)
41: end
42: end
43: end
44: end
Source: show
| on GitHub
24: def to_yaml_type
25: "!tag:yaml.org,2002:omap"
26: end
Source: show
| on GitHub
136: def values
137: @keys.collect { |key| self[key] }
138: end