Class: ActiveSupport::OrderedHash
- Inherits:
-
Hash
show all
- Defined in:
- lib/active_support/ordered_hash.rb
Overview
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
ActiveSupport::OrderedHash
is namespaced to prevent conflicts with other implementations.
Constant Summary
Constants inherited
from Hash
Hash::DISALLOWED_XML_TYPES
Class Method Summary
collapse
Instance Method Summary
collapse
Methods inherited from Hash
#as_json, #assert_valid_keys, #deep_dup, #deep_merge, #deep_merge!, #diff, #encode_json, #except, #except!, #extract!, from_trusted_xml, from_xml, #reverse_merge, #reverse_merge!, #slice, #slice!, #stringify_keys, #stringify_keys!, #symbolize_keys, #symbolize_keys!, #to_param, #to_xml, #with_indifferent_access
Constructor Details
#initialize(*args, &block) ⇒ OrderedHash
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.
68
69
70
71
|
# File 'lib/active_support/ordered_hash.rb', line 68
def initialize(*args, &block)
super
@keys = []
end
|
Class Method Details
.[](*args) ⇒ Object
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
# File 'lib/active_support/ordered_hash.rb', line 73
def self.[](*args)
ordered_hash = new
if (args.length == 1 && args.first.is_a?(Array))
args.first.each do |key_value_pair|
next unless (key_value_pair.is_a?(Array))
ordered_hash[key_value_pair[0]] = key_value_pair[1]
end
return ordered_hash
end
unless (args.size % 2 == 0)
raise ArgumentError.new("odd number of arguments for Hash")
end
args.each_with_index do |val, ind|
next if (ind % 2 != 0)
ordered_hash[val] = args[ind + 1]
end
ordered_hash
end
|
Instance Method Details
#[]=(key, value) ⇒ Object
103
104
105
106
|
# File 'lib/active_support/ordered_hash.rb', line 103
def []=(key, value)
@keys << key unless has_key?(key)
super
end
|
174
175
176
177
178
|
# File 'lib/active_support/ordered_hash.rb', line 174
def clear
super
@keys.clear
self
end
|
#delete(key) ⇒ Object
108
109
110
111
112
113
114
|
# File 'lib/active_support/ordered_hash.rb', line 108
def delete(key)
if has_key? key
index = @keys.index(key)
@keys.delete_at index
end
super
end
|
#delete_if ⇒ Object
116
117
118
119
120
|
# File 'lib/active_support/ordered_hash.rb', line 116
def delete_if
super
sync_keys!
self
end
|
160
161
162
163
164
|
# File 'lib/active_support/ordered_hash.rb', line 160
def each
return to_enum(:each) unless block_given?
@keys.each {|key| yield [key, self[key]]}
self
end
|
148
149
150
151
152
|
# File 'lib/active_support/ordered_hash.rb', line 148
def each_key
return to_enum(:each_key) unless block_given?
@keys.each { |key| yield key }
self
end
|
#each_pair ⇒ Object
166
167
168
169
170
|
# File 'lib/active_support/ordered_hash.rb', line 166
def each_pair
return to_enum(:each_pair) unless block_given?
@keys.each {|key| yield key, self[key]}
self
end
|
#each_value ⇒ Object
154
155
156
157
158
|
# File 'lib/active_support/ordered_hash.rb', line 154
def each_value
return to_enum(:each_value) unless block_given?
@keys.each { |key| yield self[key]}
self
end
|
#encode_with(coder) ⇒ Object
28
29
30
|
# File 'lib/active_support/ordered_hash.rb', line 28
def encode_with(coder)
coder.represent_seq '!omap', map { |k,v| { k => v } }
end
|
Returns true to make sure that this hash is extractable via Array#extract_options!
51
52
53
|
# File 'lib/active_support/ordered_hash.rb', line 51
def
true
end
|
#initialize_copy(other) ⇒ Object
97
98
99
100
101
|
# File 'lib/active_support/ordered_hash.rb', line 97
def initialize_copy(other)
super
@keys = other.keys
end
|
212
213
214
|
# File 'lib/active_support/ordered_hash.rb', line 212
def inspect
"#<OrderedHash #{super}>"
end
|
208
209
210
|
# File 'lib/active_support/ordered_hash.rb', line 208
def invert
OrderedHash[self.to_a.map!{|key_value_pair| key_value_pair.reverse}]
end
|
132
133
134
|
# File 'lib/active_support/ordered_hash.rb', line 132
def keys
@keys.dup
end
|
#merge(other_hash, &block) ⇒ Object
197
198
199
|
# File 'lib/active_support/ordered_hash.rb', line 197
def merge(other_hash, &block)
dup.merge!(other_hash, &block)
end
|
#merge!(other_hash) ⇒ Object
Also known as:
update
186
187
188
189
190
191
192
193
|
# File 'lib/active_support/ordered_hash.rb', line 186
def merge!(other_hash)
if block_given?
other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v }
else
other_hash.each { |k, v| self[k] = v }
end
self
end
|
#nested_under_indifferent_access ⇒ Object
46
47
48
|
# File 'lib/active_support/ordered_hash.rb', line 46
def nested_under_indifferent_access
self
end
|
#reject(&block) ⇒ Object
128
129
130
|
# File 'lib/active_support/ordered_hash.rb', line 128
def reject(&block)
dup.reject!(&block)
end
|
122
123
124
125
126
|
# File 'lib/active_support/ordered_hash.rb', line 122
def reject!
super
sync_keys!
self
end
|
#replace(other) ⇒ Object
When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
202
203
204
205
206
|
# File 'lib/active_support/ordered_hash.rb', line 202
def replace(other)
super
@keys = other.keys
self
end
|
180
181
182
183
184
|
# File 'lib/active_support/ordered_hash.rb', line 180
def shift
k = @keys.first
v = delete(k)
[k, v]
end
|
144
145
146
|
# File 'lib/active_support/ordered_hash.rb', line 144
def to_a
@keys.map { |key| [ key, self[key] ] }
end
|
140
141
142
|
# File 'lib/active_support/ordered_hash.rb', line 140
def to_hash
self
end
|
#to_yaml(opts = {}) ⇒ Object
32
33
34
35
36
37
38
39
40
41
42
43
44
|
# File 'lib/active_support/ordered_hash.rb', line 32
def to_yaml(opts = {})
if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
return super
end
YAML.quick_emit(self, opts) do |out|
out.seq(taguri) do |seq|
each do |k, v|
seq.add(k => v)
end
end
end
end
|
#to_yaml_type ⇒ Object
24
25
26
|
# File 'lib/active_support/ordered_hash.rb', line 24
def to_yaml_type
"!tag:yaml.org,2002:omap"
end
|
136
137
138
|
# File 'lib/active_support/ordered_hash.rb', line 136
def values
@keys.collect { |key| self[key] }
end
|