deltacloud-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lut...@redhat.com
Subject [PATCH 6/9] Inorporate OrderedHash from ActiveSupport
Date Wed, 19 Sep 2012 02:54:06 GMT
From: David Lutterkort <lutter@redhat.com>

We need this to control the order of elements in CIMI under Ruby 1.8.x
---
 server/LICENSE                                 |   23 +++
 server/NOTICE                                  |    3 +
 server/lib/deltacloud/core_ext.rb              |    1 +
 server/lib/deltacloud/core_ext/ordered_hash.rb |  222 ++++++++++++++++++++++++
 4 files changed, 249 insertions(+), 0 deletions(-)
 create mode 100644 server/lib/deltacloud/core_ext/ordered_hash.rb

diff --git a/server/LICENSE b/server/LICENSE
index aac62ce..1fac0f4 100644
--- a/server/LICENSE
+++ b/server/LICENSE
@@ -319,3 +319,26 @@ For the lib/sinatra/url_for.rb component:
   DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
   OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
   USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+For the lib/deltacloud/core_ext/ordered_hash.rb component:
+
+  Copyright (c) 2005-2011 David Heinemeier Hansson
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/server/NOTICE b/server/NOTICE
index fad0b4b..6a45135 100644
--- a/server/NOTICE
+++ b/server/NOTICE
@@ -20,3 +20,6 @@ This product includes icons created by David Vignon licensed under LGPL
 
 This product includes software developed by Christian Neukirchen
 (https://github.com/rack/rack)
+
+This product includes software developed by the Ruby On Rails project
+(https://github.com/rails)
\ No newline at end of file
diff --git a/server/lib/deltacloud/core_ext.rb b/server/lib/deltacloud/core_ext.rb
index 76359f1..0d37343 100644
--- a/server/lib/deltacloud/core_ext.rb
+++ b/server/lib/deltacloud/core_ext.rb
@@ -19,5 +19,6 @@ require 'require_relative' if RUBY_VERSION < '1.9'
 require_relative './core_ext/array'
 require_relative './core_ext/hash'
 require_relative './core_ext/integer'
+require_relative './core_ext/ordered_hash'
 require_relative './core_ext/proc'
 require_relative './core_ext/string'
diff --git a/server/lib/deltacloud/core_ext/ordered_hash.rb b/server/lib/deltacloud/core_ext/ordered_hash.rb
new file mode 100644
index 0000000..a7cee7a
--- /dev/null
+++ b/server/lib/deltacloud/core_ext/ordered_hash.rb
@@ -0,0 +1,222 @@
+# Code from ActiveSupport, https://github.com/rails/rails/tree/3-2-stable/activesupport
+# MIT licensed
+begin
+  require 'psych'
+rescue LoadError
+end
+
+require 'yaml'
+
+YAML.add_builtin_type("omap") do |type, val|
+  ActiveSupport::OrderedHash[val.map{ |v| v.to_a.first }]
+end
+
+# 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. <tt>ActiveSupport::OrderedHash</tt>
+# 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
+#
+# <tt>ActiveSupport::OrderedHash</tt> is namespaced to prevent conflicts with
other implementations.
+class OrderedHash < ::Hash
+  def to_yaml_type
+    "!tag:yaml.org,2002:omap"
+  end
+
+  def encode_with(coder)
+    coder.represent_seq '!omap', map { |k,v| { k => v } }
+  end
+
+  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
+
+  def nested_under_indifferent_access
+    self
+  end
+
+  # Returns true to make sure that this hash is extractable via <tt>Array#extract_options!</tt>
+  def extractable_options?
+    true
+  end
+
+  # Hash is ordered in Ruby 1.9!
+  if RUBY_VERSION < '1.9'
+
+    # 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.
+
+    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 unless 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
+      return to_enum(:each_key) unless block_given?
+      @keys.each { |key| yield key }
+      self
+    end
+
+    def each_value
+      return to_enum(:each_value) unless block_given?
+      @keys.each { |key| yield self[key]}
+      self
+    end
+
+    def each
+      return to_enum(:each) unless block_given?
+      @keys.each {|key| yield [key, self[key]]}
+      self
+    end
+
+    def each_pair
+      return to_enum(:each_pair) unless block_given?
+      @keys.each {|key| yield key, self[key]}
+      self
+    end
+
+    alias_method :select, :find_all
+
+    def clear
+      super
+      @keys.clear
+      self
+    end
+
+    def shift
+      k = @keys.first
+      v = delete(k)
+      [k, v]
+    end
+
+    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
+
+    alias_method :update, :merge!
+
+    def merge(other_hash, &block)
+      dup.merge!(other_hash, &block)
+    end
+
+    # When replacing with another hash, the initial order of our keys must come from the
other hash -ordered or not.
+    def replace(other)
+      super
+      @keys = other.keys
+      self
+    end
+
+    def invert
+      OrderedHash[self.to_a.map!{|key_value_pair| key_value_pair.reverse}]
+    end
+
+    def inspect
+      "#<OrderedHash #{super}>"
+    end
+
+    private
+    def sync_keys!
+      @keys.delete_if {|k| !has_key?(k)}
+    end
+  end
+end
-- 
1.7.7.6


Mime
View raw message