Class: Urbane::ActiveSupport::OrderedHash
- Inherits:
-
Hash
- Object
- Hash
- Urbane::ActiveSupport::OrderedHash
- Defined in:
- lib/urbane/vendor/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 # => [:a, :b], this order is guaranteed
ActiveSupport::OrderedHash
is namespaced to prevent conflicts with other implementations.
Class Method Summary collapse
Instance Method Summary collapse
- #[]=(key, value) ⇒ Object
- #clear ⇒ Object
- #delete(key) ⇒ Object
- #delete_if ⇒ Object
- #each ⇒ Object
- #each_key ⇒ Object
- #each_pair ⇒ Object
- #each_value ⇒ Object
- #encode_with(coder) ⇒ Object
-
#extractable_options? ⇒ Boolean
Returns true to make sure that this hash is extractable via
Array#extract_options!
. -
#initialize(*args, &block) ⇒ OrderedHash
constructor
In MRI the Hash class is core and written in C.
- #initialize_copy(other) ⇒ Object
- #inspect ⇒ Object
- #invert ⇒ Object
- #keys ⇒ Object
- #merge(other_hash, &block) ⇒ Object
- #merge!(other_hash) ⇒ Object (also: #update)
- #nested_under_indifferent_access ⇒ Object
- #reject(&block) ⇒ Object
- #reject! ⇒ Object
-
#replace(other) ⇒ Object
When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
- #shift ⇒ Object
- #to_a ⇒ Object
- #to_hash ⇒ Object
- #to_yaml(opts = {}) ⇒ Object
-
#to_yaml_type ⇒ Object
:nodoc:.
- #values ⇒ Object
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/urbane/vendor/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/urbane/vendor/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/urbane/vendor/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/urbane/vendor/ordered_hash.rb', line 175 def clear super @keys.clear self end |
#delete(key) ⇒ Object
109 110 111 112 113 114 115 |
# File 'lib/urbane/vendor/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/urbane/vendor/ordered_hash.rb', line 117 def delete_if super sync_keys! self end |
#each ⇒ Object
161 162 163 164 165 |
# File 'lib/urbane/vendor/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/urbane/vendor/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/urbane/vendor/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/urbane/vendor/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/urbane/vendor/ordered_hash.rb', line 29 def encode_with(coder) coder.represent_seq '!omap', map { |k,v| { k => v } } end |
#extractable_options? ⇒ Boolean
Returns true to make sure that this hash is extractable via Array#extract_options!
52 53 54 |
# File 'lib/urbane/vendor/ordered_hash.rb', line 52 def true end |
#initialize_copy(other) ⇒ Object
98 99 100 101 102 |
# File 'lib/urbane/vendor/ordered_hash.rb', line 98 def initialize_copy(other) super # make a deep copy of keys @keys = other.keys end |
#inspect ⇒ Object
213 214 215 |
# File 'lib/urbane/vendor/ordered_hash.rb', line 213 def inspect "#<OrderedHash #{super}>" end |
#invert ⇒ Object
209 210 211 |
# File 'lib/urbane/vendor/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/urbane/vendor/ordered_hash.rb', line 133 def keys @keys.dup end |
#merge(other_hash, &block) ⇒ Object
198 199 200 |
# File 'lib/urbane/vendor/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/urbane/vendor/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/urbane/vendor/ordered_hash.rb', line 47 def nested_under_indifferent_access self end |
#reject(&block) ⇒ Object
129 130 131 |
# File 'lib/urbane/vendor/ordered_hash.rb', line 129 def reject(&block) dup.reject!(&block) end |
#reject! ⇒ Object
123 124 125 126 127 |
# File 'lib/urbane/vendor/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/urbane/vendor/ordered_hash.rb', line 203 def replace(other) super @keys = other.keys self end |
#shift ⇒ Object
181 182 183 184 185 |
# File 'lib/urbane/vendor/ordered_hash.rb', line 181 def shift k = @keys.first v = delete(k) [k, v] end |
#to_a ⇒ Object
145 146 147 |
# File 'lib/urbane/vendor/ordered_hash.rb', line 145 def to_a @keys.map { |key| [ key, self[key] ] } end |
#to_hash ⇒ Object
141 142 143 |
# File 'lib/urbane/vendor/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/urbane/vendor/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
:nodoc:
25 26 27 |
# File 'lib/urbane/vendor/ordered_hash.rb', line 25 def to_yaml_type "!tag:yaml.org,2002:omap" end |
#values ⇒ Object
137 138 139 |
# File 'lib/urbane/vendor/ordered_hash.rb', line 137 def values @keys.collect { |key| self[key] } end |