Class: OrderedHash
- Inherits:
-
Hash
show all
- Defined in:
- lib/deltacloud/core_ext/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.
Class Method Summary
collapse
Instance Method Summary
collapse
Methods inherited from Hash
#gsub_keys, #symbolize_keys, #to_query_params
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.
69
70
71
72
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 69
def initialize(*args, &block)
super
@keys = []
end
|
Class Method Details
.[](*args) ⇒ Object
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 74
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
104
105
106
107
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 104
def []=(key, value)
@keys << key unless has_key?(key)
super
end
|
#clear ⇒ Object
175
176
177
178
179
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 175
def clear
super
@keys.clear
self
end
|
#delete(key) ⇒ Object
109
110
111
112
113
114
115
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 109
def delete(key)
if has_key? key
index = @keys.index(key)
@keys.delete_at index
end
super
end
|
#delete_if ⇒ Object
117
118
119
120
121
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 117
def delete_if
super
sync_keys!
self
end
|
#each ⇒ Object
161
162
163
164
165
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 161
def each
return to_enum(:each) unless block_given?
@keys.each {|key| yield [key, self[key]]}
self
end
|
#each_key ⇒ Object
149
150
151
152
153
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 149
def each_key
return to_enum(:each_key) unless block_given?
@keys.each { |key| yield key }
self
end
|
#each_pair ⇒ Object
167
168
169
170
171
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 167
def each_pair
return to_enum(:each_pair) unless block_given?
@keys.each {|key| yield key, self[key]}
self
end
|
#each_value ⇒ Object
155
156
157
158
159
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 155
def each_value
return to_enum(:each_value) unless block_given?
@keys.each { |key| yield self[key]}
self
end
|
#encode_with(coder) ⇒ Object
29
30
31
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 29
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!
52
53
54
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 52
def
true
end
|
#initialize_copy(other) ⇒ Object
98
99
100
101
102
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 98
def initialize_copy(other)
super
@keys = other.keys
end
|
#inspect ⇒ Object
213
214
215
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 213
def inspect
"#<OrderedHash #{super}>"
end
|
#invert ⇒ Object
209
210
211
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 209
def invert
OrderedHash[self.to_a.map!{|key_value_pair| key_value_pair.reverse}]
end
|
#keys ⇒ Object
133
134
135
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 133
def keys
@keys.dup
end
|
#merge(other_hash, &block) ⇒ Object
198
199
200
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 198
def merge(other_hash, &block)
dup.merge!(other_hash, &block)
end
|
#merge!(other_hash) ⇒ Object
Also known as:
update
187
188
189
190
191
192
193
194
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 187
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
47
48
49
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 47
def nested_under_indifferent_access
self
end
|
#reject(&block) ⇒ Object
129
130
131
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 129
def reject(&block)
dup.reject!(&block)
end
|
#reject! ⇒ Object
123
124
125
126
127
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 123
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.
203
204
205
206
207
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 203
def replace(other)
super
@keys = other.keys
self
end
|
#shift ⇒ Object
181
182
183
184
185
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 181
def shift
k = @keys.first
v = delete(k)
[k, v]
end
|
#to_a ⇒ Object
145
146
147
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 145
def to_a
@keys.map { |key| [ key, self[key] ] }
end
|
#to_hash ⇒ Object
141
142
143
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 141
def to_hash
self
end
|
#to_yaml(opts = {}) ⇒ Object
33
34
35
36
37
38
39
40
41
42
43
44
45
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 33
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
25
26
27
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 25
def to_yaml_type
"!tag:yaml.org,2002:omap"
end
|
#values ⇒ Object
137
138
139
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 137
def values
@keys.collect { |key| self[key] }
end
|