Class: Hash

Inherits:
Object show all
Defined in:
lib/extlib/hash.rb

Direct Known Subclasses

Extlib::SimpleSet, Mash

Constant Summary collapse

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

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.from_xml(xml) ⇒ Hash

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 }

84
85
86
# File 'lib/extlib/hash.rb', line 84

def from_xml( xml )
  ToHashParser.from_xml(xml)
end

Instance Method Details

#add_html_class!(html_class) ⇒ Object

Examples:

hash #=> nil


hash.add_html_class!(:selected)


hash #=> “selected”


hash.add_html_class!(“class1 class2”)


hash #=> “selected class1 class2”



212
213
214
215
216
217
218
# File 'lib/extlib/hash.rb', line 212

def add_html_class!(html_class)
  if self[:class]
    self[:class] = "#{self[:class]} #{html_class}"
  else
    self[:class] = html_class.to_s
  end
end

#environmentize_keys!Hash

Destructively and non-recursively convert each key to an uppercase string, deleting nil values along the way.

Examples:

{ :name => "Bob", :contact => { :email => "[email protected]" } }.environmentize_keys!
  #=> { "NAME" => "Bob", "CONTACT" => { :email => "[email protected]" } }

253
254
255
256
257
258
259
260
# File 'lib/extlib/hash.rb', line 253

def environmentize_keys!
  keys.each do |key|
    val = delete(key)
    next if val.nil?
    self[key.to_s.upcase] = val
  end
  self
end

#except(*rejected) ⇒ Hash

Create a hash with all key/value pairs in receiver except rejected

{ :one => 1, :two => 2, :three => 3 }.except(:one)
 #=> { :two => 2, :three => 3 }

184
185
186
187
188
# File 'lib/extlib/hash.rb', line 184

def except(*rejected)
  hash = self.dup
  rejected.each {|k| hash.delete(k) }
  hash
end

#normalize_param(key, value) ⇒ String

Convert a key, value pair into a URL query param string

normalize_param(:name, "Bob")   #=> "name=Bob&"

132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/extlib/hash.rb', line 132

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

#only(*allowed) ⇒ Hash

Create a hash with only key/value pairs in receiver and allowed

{ :one => 1, :two => 2, :three => 3 }.only(:one)    #=> { :one => 1 }

167
168
169
170
171
# File 'lib/extlib/hash.rb', line 167

def only(*allowed)
  hash = {}
  allowed.each {|k| hash[k] = self[k] if self.has_key?(k) }
  hash
end

#protect_keys!Array

Converts all keys into string values. This is used during reloading to prevent problems when classes are no longer declared.

Examples:

hash = { One => 1, Two => 2 }.proctect_keys!
hash # => { "One" => 1, "Two" => 2 }

228
229
230
# File 'lib/extlib/hash.rb', line 228

def protect_keys!
  keys.each {|key| self[key.to_s] = delete(key) }
end

#to_mashMash

Convert to Mash. This class has semantics of ActiveSupport's HashWithIndifferentAccess and we only have it so that people can write params instead of params.


94
95
96
97
98
# File 'lib/extlib/hash.rb', line 94

def to_mash
  hash = Mash.new(self)
  hash.default = default
  hash
end

#to_paramsString

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."

115
116
117
118
119
# File 'lib/extlib/hash.rb', line 115

def to_params
  params = self.map { |k,v| normalize_param(k,v) }.join
  params.chop! # trailing &
  params
end

#to_xml_attributesString Also known as: to_html_attributes

Returns The hash as attributes for an XML tag.

Examples:

{ :one => 1, "two"=>"TWO" }.to_xml_attributes
  #=> 'one="1" two="TWO"'

195
196
197
198
199
# File 'lib/extlib/hash.rb', line 195

def to_xml_attributes
  map do |k,v|
    %{#{k.to_s.snake_case.sub(/^(.{1,1})/) { |m| m.downcase }}="#{v}"}
  end.join(' ')
end

#unprotect_keys!Object

Attempts to convert all string keys into Class keys. We run this after reloading to convert protected hashes back into usable hashes.

Examples:

# Provided that classes One and Two are declared in this scope:
hash = { "One" => 1, "Two" => 2 }.unproctect_keys!
hash # => { One => 1, Two => 2 }

239
240
241
242
243
# File 'lib/extlib/hash.rb', line 239

def unprotect_keys!
  keys.each do |key|
    (self[Object.full_const_get(key)] = delete(key)) rescue nil
  end
end