public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
rails / activesupport / lib / active_support / ordered_hash.rb
100644 135 lines (107 sloc) 2.491 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# OrderedHash is namespaced to prevent conflicts with other implementations
module ActiveSupport
  # Hash is ordered in Ruby 1.9!
  if RUBY_VERSION >= '1.9'
    OrderedHash = ::Hash
  else
    class OrderedHash < Hash #:nodoc:
      def initialize(*args, &block)
        super
        @keys = []
      end
 
      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
 
      def initialize_copy(other)
        super
        # make a deep copy of keys
        @keys = other.keys
      end
 
      def []=(key, value)
        @keys << key if !has_key?(key)
        super
      end
 
      def delete(key)
        if has_key? key
          index = @keys.index(key)
          @keys.delete_at index
        end
        super
      end
      
      def delete_if
        super
        sync_keys!
        self
      end
 
      def reject!
        super
        sync_keys!
        self
      end
 
      def reject(&block)
        dup.reject!(&block)
      end
 
      def keys
        @keys.dup
      end
 
      def values
        @keys.collect { |key| self[key] }
      end
 
      def to_hash
        self
      end
 
      def to_a
        @keys.map { |key| [ key, self[key] ] }
      end
 
      def each_key
        @keys.each { |key| yield key }
      end
 
      def each_value
        @keys.each { |key| yield self[key]}
      end
 
      def each
        @keys.each {|key| yield [key, self[key]]}
      end
 
      alias_method :each_pair, :each
 
      def clear
        super
        @keys.clear
        self
      end
 
      def shift
        k = @keys.first
        v = delete(k)
        [k, v]
      end
 
      def merge!(other_hash)
        other_hash.each {|k,v| self[k] = v }
        self
      end
 
      def merge(other_hash)
        dup.merge!(other_hash)
      end
 
      def inspect
        "#<OrderedHash #{super}>"
      end
 
    private
 
      def sync_keys!
        @keys.delete_if {|k| !has_key?(k)}
      end
    end
  end
end