Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

vistahigherlearning / logstash   deb

Repository URL to install this package:

/ opt / logstash / vendor / bundle / jruby / 1.9 / gems / extlib-0.9.16 / lib / extlib / hash.rb

require 'bigdecimal'
require 'time'
require 'uri'

require 'extlib/object'
require 'extlib/mash'
require 'extlib/class'
require 'extlib/string'

class Hash
  URI_ENCODE_PATTERN = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]").freeze

  class << self
    # Converts valid XML into a Ruby Hash structure.
    #
    # Mixed content is treated as text and any tags in it are left unparsed
    #
    # Any attributes other than type on a node containing a text node will be
    # discarded
    #
    # [Typecasting is performed on elements that have a +type+ attribute:]
    #   integer:: Returns an Integer
    #   boolean:: Anything other than "true" evaluates to false.
    #   datetime::
    #     Returns a Time object. See Time documentation for valid Time strings.
    #   date::
    #     Returns a Date object. See Date documentation for valid Date strings.
    #
    # Keys are automatically converted to +snake_case+
    #
    # [Simple]
    #
    #   <user gender='m'>
    #     <age type='integer'>35</age>
    #     <name>Home Simpson</name>
    #     <dob type='date'>1988-01-01</dob>
    #     <joined-at type='datetime'>2000-04-28 23:01</joined-at>
    #     <is-cool type='boolean'>true</is-cool>
    #   </user>
    #
    # Becomes:
    #
    #   { "user" => {
    #       "gender"    => "m",
    #       "age"       => 35,
    #       "name"      => "Home Simpson",
    #       "dob"       => DateObject( 1998-01-01 ),
    #       "joined_at" => TimeObject( 2000-04-28 23:01),
    #       "is_cool"   => true
    #     }
    #   }
    #
    # [Mixed Content]
    #
    #   <story>
    #     A Quick <em>brown</em> Fox
    #   </story>
    #
    # Evaluates to:
    #
    #   { "story" => "A Quick <em>brown</em> Fox" }
    #
    # [Attributes other than type on a node containing text]
    #
    #   <story is-good='false'>
    #     A Quick <em>brown</em> Fox
    #   </story>
    #
    # Are ignored:
    #
    #   { "story" => "A Quick <em>brown</em> Fox" }
    #
    # [Other attributes in addition to +type+]
    #
    #   <bicep unit='inches' type='integer'>60</bicep>
    #
    # Evaluates with a typecast to an integer. But unit attribute is ignored:
    #
    #   { "bicep" => 60 }
    #
    # @param [String] xml A string representation of valid XML.
    #
    # @return [Hash] A hash created by parsing +xml+
    def from_xml( xml )
      ToHashParser.from_xml(xml)
    end
  end

  # Convert to Mash. This class has semantics of ActiveSupport's
  # HashWithIndifferentAccess and we only have it so that people can write
  # params[:key] instead of params['key'].
  #
  # @return [Mash] This hash as a Mash for string or symbol key access.
  def to_mash
    hash = Mash.new(self)
    hash.default = default
    hash
  end

  ##
  # Convert to URL query param string
  #
  #   { :name => "Bob",
  #     :address => {
  #       :street => '111 Ruby Ave.',
  #       :city => 'Ruby Central',
  #       :phones => ['111-111-1111', '222-222-2222']
  #     }
  #   }.to_params
  #     #=> "name=Bob&address[city]=Ruby Central&address[phones][]=111-111-1111&address[phones][]=222-222-2222&address[street]=111 Ruby Ave."
  #
  # @return [String] This hash as a query string
  #
  # @api public
  def to_params
    params = self.map { |k,v| normalize_param(k,v) }.join
    params.chop! # trailing &
    params
  end

  ##
  # Convert a key, value pair into a URL query param string
  #
  #   normalize_param(:name, "Bob")   #=> "name=Bob&"
  #
  # @param [Object] key The key for the param.
  # @param [Object] value The value for the param.
  #
  # @return [String] This key value pair as a param
  #
  # @api public
  def normalize_param(key, value)
    param = ''
    stack = []

    if value.is_a?(Array)
      param << value.map { |element| normalize_param("#{key}[]", element) }.join
    elsif value.is_a?(Hash)
      stack << [key,value]
    else
      param << [key,value].map {|v| URI.encode(v.to_s, URI_ENCODE_PATTERN)}.join('=') + '&'
    end

    stack.each do |parent, hash|
      hash.each do |k, v|
        if v.is_a?(Hash)
          stack << ["#{parent}[#{k}]", v]
        else
          param << normalize_param("#{parent}[#{k}]", v)
        end
      end
    end

    param
  end

  ##
  # Create a hash with *only* key/value pairs in receiver and +allowed+
  #
  #   { :one => 1, :two => 2, :three => 3 }.only(:one)    #=> { :one => 1 }
  #
  # @param [Array[String, Symbol]] *allowed The hash keys to include.
  #
  # @return [Hash] A new hash with only the selected keys.
  #
  # @api public
  def only(*allowed)
    hash = {}
    allowed.each {|k| hash[k] = self[k] if self.has_key?(k) }
    hash
  end

  ##
  # Create a hash with all key/value pairs in receiver *except* +rejected+
  #
  #    { :one => 1, :two => 2, :three => 3 }.except(:one)
  #     #=> { :two => 2, :three => 3 }
  #
  # @param [Array[String, Symbol]] *rejected The hash keys to exclude.
  #
  # @return [Hash] A new hash without the selected keys.
  #
  # @api public
  def except(*rejected)
    hash = self.dup
    rejected.each {|k| hash.delete(k) }
    hash
  end

  # @return [String] The hash as attributes for an XML tag.
  #
  # @example
  #   { :one => 1, "two"=>"TWO" }.to_xml_attributes
  #     #=> 'one="1" two="TWO"'
  def to_xml_attributes
    map do |k,v|
      %{#{k.to_s.snake_case.sub(/^(.{1,1})/) { |m| m.downcase }}="#{v}"}
    end.join(' ')
  end

  alias_method :to_html_attributes, :to_xml_attributes

  # @param html_class<#to_s>
  #   The HTML class to add to the :class key. The html_class will be
  #   concatenated to any existing classes.
  #
  # @example hash[:class] #=> nil
  # @example hash.add_html_class!(:selected)
  # @example hash[:class] #=> "selected"
  # @example hash.add_html_class!("class1 class2")
  # @example hash[:class] #=> "selected class1 class2"
  def add_html_class!(html_class)
    if self[:class]
      self[:class] = "#{self[:class]} #{html_class}"
    else
      self[:class] = html_class.to_s
    end
  end

  # Converts all keys into string values. This is used during reloading to
  # prevent problems when classes are no longer declared.
  #
  # @return [Array] An array of they hash's keys
  #
  # @example
  #   hash = { One => 1, Two => 2 }.proctect_keys!
  #   hash # => { "One" => 1, "Two" => 2 }
  def protect_keys!
    keys.each {|key| self[key.to_s] = delete(key) }
  end

  # Attempts to convert all string keys into Class keys. We run this after
  # reloading to convert protected hashes back into usable hashes.
  #
  # @example
  #   # Provided that classes One and Two are declared in this scope:
  #   hash = { "One" => 1, "Two" => 2 }.unproctect_keys!
  #   hash # => { One => 1, Two => 2 }
  def unprotect_keys!
    keys.each do |key|
      (self[Object.full_const_get(key)] = delete(key)) rescue nil
    end
  end

  # Destructively and non-recursively convert each key to an uppercase string,
  # deleting nil values along the way.
  #
  # @return [Hash] The newly environmentized hash.
  #
  # @example
  #   { :name => "Bob", :contact => { :email => "bob@bob.com" } }.environmentize_keys!
  #     #=> { "NAME" => "Bob", "CONTACT" => { :email => "bob@bob.com" } }
  def environmentize_keys!
    keys.each do |key|
      val = delete(key)
      next if val.nil?
      self[key.to_s.upcase] = val
    end
    self
  end
end

require 'rexml/parsers/streamparser'
require 'rexml/parsers/baseparser'
require 'rexml/light/node'

# This is a slighly modified version of the XMLUtilityNode from
# http://merb.devjavu.com/projects/merb/ticket/95 (has.sox@gmail.com)
# It's mainly just adding vowels, as I ht cd wth n vwls :)
# This represents the hard part of the work, all I did was change the
# underlying parser.
class REXMLUtilityNode
  attr_accessor :name, :attributes, :children, :type
  cattr_accessor :typecasts, :available_typecasts

  self.typecasts = {}
  self.typecasts["integer"]       = lambda{|v| v.nil? ? nil : v.to_i}
  self.typecasts["boolean"]       = lambda{|v| v.nil? ? nil : (v.strip != "false")}
  self.typecasts["datetime"]      = lambda{|v| v.nil? ? nil : Time.parse(v).utc}
  self.typecasts["date"]          = lambda{|v| v.nil? ? nil : Date.parse(v)}
  self.typecasts["dateTime"]      = lambda{|v| v.nil? ? nil : Time.parse(v).utc}
  self.typecasts["decimal"]       = lambda{|v| BigDecimal(v)}
  self.typecasts["double"]        = lambda{|v| v.nil? ? nil : v.to_f}
  self.typecasts["float"]         = lambda{|v| v.nil? ? nil : v.to_f}
  self.typecasts["string"]        = lambda{|v| v.to_s}
  self.typecasts["base64Binary"]  = lambda{|v| v.unpack('m').first }

  self.available_typecasts = self.typecasts.keys

  def initialize(name, attributes = {})
    @name         = name.tr("-", "_")
    # leave the type alone if we don't know what it is
    @type         = self.class.available_typecasts.include?(attributes["type"]) ? attributes.delete("type") : attributes["type"]

    @nil_element  = attributes.delete("nil") == "true"
    @attributes   = undasherize_keys(attributes)
    @children     = []
    @text         = false
  end

  def add_node(node)
    @text = true if node.is_a? String
    @children << node
  end

  def to_hash
    if @type == "file"
      f = StringIO.new((@children.first || '').unpack('m').first)
      class << f
        attr_accessor :original_filename, :content_type
      end
      f.original_filename = attributes['name'] || 'untitled'
      f.content_type = attributes['content_type'] || 'application/octet-stream'
      return {name => f}
    end

    if @text
      return { name => typecast_value( translate_xml_entities( inner_html ) ) }
    else
      #change repeating groups into an array
      groups = @children.inject({}) { |s,e| (s[e.name] ||= []) << e; s }

      out = nil
      if @type == "array"
        out = []
        groups.each do |k, v|
          if v.size == 1
            out << v.first.to_hash.entries.first.last
          else
            out << v.map{|e| e.to_hash[k]}
          end
        end
        out = out.flatten

      else # If Hash
        out = {}
        groups.each do |k,v|
          if v.size == 1
            out.merge!(v.first)
          else
            out.merge!( k => v.map{|e| e.to_hash[k]})
          end
        end
        out.merge! attributes unless attributes.empty?
        out = out.empty? ? nil : out
Loading ...