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.
65
66
67
68
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 65
def initialize(*args, &block)
super
@keys = []
end
|
Class Method Details
.[](*args) ⇒ Object
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 70
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
100
101
102
103
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 100
def []=(key, value)
@keys << key unless has_key?(key)
super
end
|
#clear ⇒ Object
171
172
173
174
175
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 171
def clear
super
@keys.clear
self
end
|
#delete(key) ⇒ Object
105
106
107
108
109
110
111
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 105
def delete(key)
if has_key? key
index = @keys.index(key)
@keys.delete_at index
end
super
end
|
#delete_if ⇒ Object
113
114
115
116
117
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 113
def delete_if
super
sync_keys!
self
end
|
#each ⇒ Object
157
158
159
160
161
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 157
def each
return to_enum(:each) unless block_given?
@keys.each {|key| yield [key, self[key]]}
self
end
|
#each_key ⇒ Object
145
146
147
148
149
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 145
def each_key
return to_enum(:each_key) unless block_given?
@keys.each { |key| yield key }
self
end
|
#each_pair ⇒ Object
163
164
165
166
167
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 163
def each_pair
return to_enum(:each_pair) unless block_given?
@keys.each {|key| yield key, self[key]}
self
end
|
#each_value ⇒ Object
151
152
153
154
155
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 151
def each_value
return to_enum(:each_value) unless block_given?
@keys.each { |key| yield self[key]}
self
end
|
#encode_with(coder) ⇒ Object
25
26
27
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 25
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!
48
49
50
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 48
def
true
end
|
#initialize_copy(other) ⇒ Object
94
95
96
97
98
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 94
def initialize_copy(other)
super
@keys = other.keys
end
|
#inspect ⇒ Object
209
210
211
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 209
def inspect
"#<OrderedHash #{super}>"
end
|
#invert ⇒ Object
205
206
207
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 205
def invert
OrderedHash[self.to_a.map!{|key_value_pair| key_value_pair.reverse}]
end
|
#keys ⇒ Object
129
130
131
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 129
def keys
@keys.dup
end
|
#merge(other_hash, &block) ⇒ Object
194
195
196
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 194
def merge(other_hash, &block)
dup.merge!(other_hash, &block)
end
|
#merge!(other_hash) ⇒ Object
Also known as:
update
183
184
185
186
187
188
189
190
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 183
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
43
44
45
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 43
def nested_under_indifferent_access
self
end
|
#reject(&block) ⇒ Object
125
126
127
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 125
def reject(&block)
dup.reject!(&block)
end
|
#reject! ⇒ Object
119
120
121
122
123
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 119
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.
199
200
201
202
203
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 199
def replace(other)
super
@keys = other.keys
self
end
|
#shift ⇒ Object
177
178
179
180
181
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 177
def shift
k = @keys.first
v = delete(k)
[k, v]
end
|
#to_a ⇒ Object
141
142
143
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 141
def to_a
@keys.map { |key| [ key, self[key] ] }
end
|
#to_hash ⇒ Object
137
138
139
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 137
def to_hash
self
end
|
#to_yaml(opts = {}) ⇒ Object
29
30
31
32
33
34
35
36
37
38
39
40
41
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 29
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
21
22
23
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 21
def to_yaml_type
"!tag:yaml.org,2002:omap"
end
|
#values ⇒ Object
133
134
135
|
# File 'lib/deltacloud/core_ext/ordered_hash.rb', line 133
def values
@keys.collect { |key| self[key] }
end
|