Class: Hash

Inherits:
Object show all
Defined in:
lib/base/helpers/support.xml.rb,
lib/base/helpers/support.rb

Overview

:nodoc:

Constant Summary collapse

RIGHTXMLSUPPORT_SORTORDERREGEXP =
/(\{#(\d+)\})$/

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

._order(key_name = nil) ⇒ String

Generate a consecutive id for a new key. If String or Symbol is passed then adds the id to it.

The method is widely used for MS Azure XMLs because MS requires XML tags to appear in a predefined order. Grrr… ;)

Examples:

Hash::_order('hahaha') #=> "hahaha{#1}"
Hash::_order('hohoho') #=> "hohoho{#2}"
Hash::_order           #=> 3
hash = {
  Hash::_order('foo') => 34,
  Hash::_order('boo') => 45,
    Hash::_order('zoo') => 53,
    Hash::_order('poo') => 10,
    Hash::_order('moo') => {
    Hash::_order('noo') => 101,
    Hash::_order('too') => 113,
    Hash::_order('koo') => 102,
  },
  Hash::_order('woo') => 03,
  Hash::_order('hoo') => 1
}
hash._to_xml(:indent => '  ') #=>
   <boo>45</boo>
   <zoo>53</zoo>
   <poo>10</poo>
   <moo>
   <noo>101</noo>
     <too>113</too>
     <koo>102</koo>
   </moo>
   <woo>3</woo>
   <hoo>1</hoo>

Parameters:

  • (defaults to: nil)

    Usually a tag name.

Returns:

  • A string containing the original one and the current ordering ID. if key_name was not set then it returns the next id value.



197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/base/helpers/support.xml.rb', line 197

def self._order(key_name=nil)
  @_next_ordered_key_id ||= 0
  @_next_ordered_key_id  += 1
  if key_name
    fail(RuntimeError.new('String or Symbol is expected')) unless key_name.is_a?(String) || key_name.is_a?(Symbol)
    result = "#{key_name}{##{@_next_ordered_key_id}}"
    result = result.to_sym if key_name.is_a?(Symbol)
    result
  else
    @_next_ordered_key_id
  end
end

Instance Method Details

#_arrayifyArray

Wraps the hash into an array.

Examples:

{1 => 2}._arrayify #=> [{1 => 2}]

Returns:



267
268
269
# File 'lib/base/helpers/support.rb', line 267

def _arrayify
  [ self ]
end

#_arrayify_at(*path) ⇒ Array

Extracts a value from the hash by its path and arrayifies it.

Examples:

{}._arrayify_at('x', 'y', 'z')                                     #=>  []
{ 'x' => { 'y' => { 'z' => 'value'} }}._arrayify_at('x', 'y', 'z') #=>  ['value']

Parameters:

  • The path to the key. If the very last value is a hash then it is treated as a set of options.

Returns:

  • Single item array with whatever value the requested key has.



256
257
258
# File 'lib/base/helpers/support.rb', line 256

def _arrayify_at(*path)
  _at(path << { :arrayify => true, :default => [] })
end

#_at(*path) { ... } ⇒ Object

Extract a value from the hash by its path. The path is a comma-separated list of keys, staring from the root key.

The options are:

- :arrayify Convert the result into Array (unless it is).
- :default A value to be returned unless the requested key exist.

Examples:

{}._at('x','y')                                          #=>  Item at "x"->"y" is not found or not a Hash instance (RuntimeError)
{}._at('x', :default => 'defval')                        #=>  'defval'
{}._at('x'){ 'defval' }                                  #=>  'defval'
{}._at('x'){ fail "NotFound.MyCoolError" }               #=>  NotFound.MyCoolError (RuntimeError)
{'x' => nil}._at('x')                                    #=>  nil
{'x' => 4}._at('x')                                      #=>  4
{'x' => { 'y' => { 'z' => 'value'} } }._at('x', 'y', 'z') #=>  'value'
{'x' => { 'y' => { 'z' => 'value'} } }._at('x', 'y', 'z', :arrayify => true) #=> ['value']

Parameters:

  • The path to the key. If the very last value is a hash then it is treated as a set of options.

Yields:

  • If a block is given and the key is not found then it calls the block.

Yield Returns:

  • (Object)

    he block may raise a custom exception or return anything. The returned value it used for the method return.

Returns:

  • Whatever value the requested key has or the default value.



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/base/helpers/support.rb', line 226

def _at(*path, &block)
  path    = path.flatten
  options = path.last.is_a?(Hash) ? path.pop.dup : {}
  key     = path.shift
  (options[:path] ||= []) << key
  if key?(key)
    if path._blank?
      # We have reached the final key in the list - report it back.
      return options[:arrayify] ?  self[key]._arrayify : self[key]
    end
    return self[key]._at(path << options, &block) if self[key].is_a?(Hash)
  end
  return options[:default]  if options.key?(:default)
  return block.call         if block
  fail(StandardError.new("Item at #{options[:path].map{|i| i.inspect}.join('->')} is not found or not a Hash instance"))
end

#_stringify_keysHash

Converts the keys of the hash to strings.

Returns:



191
192
193
194
195
196
197
198
# File 'lib/base/helpers/support.rb', line 191

def _stringify_keys
  inject({}) do |hash, (key, value)|
    new_key = key.to_s              if key.respond_to?(:to_s)
    value   = value._stringify_keys if value.respond_to?(:_stringify_keys)
    hash[new_key] = value
    hash
  end
end

#_symbolize_keysHash

Converts the root keys of the hash to symbols.

Returns:



178
179
180
181
182
183
184
185
# File 'lib/base/helpers/support.rb', line 178

def _symbolize_keys
  inject({}) do |hash, (key, value)|
    new_key = key.respond_to?(:to_sym) ? key.to_sym : key
    value   = value._symbolize_keys if value.respond_to?(:_symbolize_keys)
    hash[new_key] = value
    hash
  end
end

#_to_xml(opts = {}) ⇒ String

Returns an XML-representation if the hash object.

Examples:

({ 'a' => [ 1, { :c => 'd' } ] })._to_xml #=>
  "<a>1</a><a><c>d</c></a>"
{ 'screen' => {
    '@width' => 1080,
    '@hight' => 720,
    '@@text' => 'HD',
    'color'  => {
      '@max-colors' => 65535,
      '@dinamic-resolution' => '1:1000000',
      '@@text' => '<"PAL">',
        'brightness' => {
          'bright' => true
        }
      }
    }
  }._to_xml(:indent => '  ',
            :escape => true) #=>
     <screen width="1080" hight="720">
       HD
       <color max-colors="65535" dinamic-resolution="1:1000000">
         &lt;&quot;PAL&quot;&gt;
         <brightness>
           <bright>true</bright>
         </brightness>
       </color>
     </screen>

Parameters:

  • (defaults to: {})

    A set of options.

Options Hash (opts):

  • :escape (Boolean)

    The flag.

  • :indent (Boolean)

    The indentation string (is blank by default).

  • :crfl (Boolean)

    The CR/LF string (is blank by default).

Returns:



275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/base/helpers/support.xml.rb', line 275

def _to_xml(opts={})
  result    = ''
  opts      = _xml_get_opts(opts)
  next_opts = opts.merge(:level => opts[:level] + 1)
  _xml_sort_keys.each do |tag_name|
    value    = self[tag_name]
    tag_name = tag_name.to_s.sub(RIGHTXMLSUPPORT_SORTORDERREGEXP, '')
    if value.is_a?(Hash)
      tag_attributes = ''; tag_elements = ''; tag_text = ''
      value._xml_sort_keys.each do |item|
        item_value = value[item]
        item       = item.to_s.sub(RIGHTXMLSUPPORT_SORTORDERREGEXP, '')
        case
        when item == '@@text' then tag_text       << item_value._xml_conditional_escape(opts)
        when item[/^@[^@]/]   then tag_attributes << %Q{ #{item[1..-1]}="#{item_value._xml_conditional_escape(opts)}"}
        else                       tag_elements   << { item => item_value }._to_xml(next_opts)
        end
      end
      result << _xml_finalize_tag(tag_name, tag_attributes, tag_text, tag_elements, opts)
    elsif value.is_a?(Array)
      value.each do |item|
        item    = { tag_name => item } if item.is_a?(Array)
        result << { tag_name => item }._to_xml(opts)
      end
    else
      result << _xml_finalize_tag(tag_name, '', value.to_s, '', opts)
    end
  end
  result
end

#_xml_finalize_tag(tag_name, tag_attributes, tag_text, tag_elements, opts) ⇒ Object

Builds the final XML tag text.



224
225
226
227
228
229
230
231
232
233
234
# File 'lib/base/helpers/support.xml.rb', line 224

def _xml_finalize_tag(tag_name, tag_attributes, tag_text, tag_elements, opts) # :nodoc:
  next_opts = opts.merge(:level => opts[:level] + 1)
  case
  when tag_elements.empty? && tag_text.empty? then "<#{tag_name}#{tag_attributes}/>"._xml_align(opts)
  when tag_elements.empty?                    then "<#{tag_name}#{tag_attributes}>#{tag_text}</#{tag_name}>"._xml_align(opts)
  else                                             "<#{tag_name}#{tag_attributes}>"._xml_align(opts) +
                                                   tag_text._xml_align(next_opts)                    +
                                                   tag_elements                                     +
                                                   "</#{tag_name}>"._xml_align(opts)
  end
end

#_xml_sort_keysObject

Sorts the keys accordingly to their order definition (if Hash::_order was used).



211
212
213
214
215
216
217
218
219
220
221
# File 'lib/base/helpers/support.xml.rb', line 211

def _xml_sort_keys # :nodoc:
  keys.sort do |key1, key2|
    key1idx = key1.to_s[RIGHTXMLSUPPORT_SORTORDERREGEXP] && $2 && $2.to_i
    key2idx = key2.to_s[RIGHTXMLSUPPORT_SORTORDERREGEXP] && $2 && $2.to_i
    if    key1idx && key2idx then key1idx <=> key2idx
    elsif key1idx            then -1
    elsif key2idx            then  1
    else                           0
    end
  end
end