Module: MultiXml::Helpers

Included in:
MultiXml
Defined in:
lib/multi_xml/helpers.rb

Overview

Methods for transforming parsed XML hash structures

These helper methods handle key transformation and type casting of parsed XML data structures.

Class Method Summary collapse

Class Method Details

.apply_converter(hash, content, converter) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Apply a type converter to content

Parameters:

  • hash (Hash)

    Original hash with type info

  • content (String)

    Content to convert

  • converter (Proc)

    Converter to apply

Returns:

  • (Object)

    Converted value



220
221
222
223
224
225
226
# File 'lib/multi_xml/helpers.rb', line 220

def apply_converter(hash, content, converter)
  # Binary converters need access to entity attributes (e.g., encoding, name)
  return converter.call(content, hash) if converter.arity == 2

  hash.delete("type")
  unwrap_if_simple(hash, converter.call(content))
end

.convert_hash(hash, type, disallowed_types) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Convert a hash based on its type and content

Parameters:

  • hash (Hash)

    Hash to convert

  • type (String, nil)

    Type attribute value

  • disallowed_types (Array<String>)

    Types to reject

Returns:

  • (Object)

    Converted value



93
94
95
96
97
98
99
100
# File 'lib/multi_xml/helpers.rb', line 93

def convert_hash(hash, type, disallowed_types)
  return extract_array_entries(hash, disallowed_types) if type == "array"
  return convert_text_content(hash) if hash.key?(TEXT_CONTENT_KEY)
  return "" if type == "string" && !hash["nil"].eql?("true")
  return nil if empty_value?(hash, type)

  typecast_children(hash, disallowed_types)
end

.convert_text_content(hash) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Convert text content using type converters

Parameters:

  • hash (Hash)

    Hash containing text content and type

Returns:

  • (Object)

    Converted value



155
156
157
158
159
160
161
162
# File 'lib/multi_xml/helpers.rb', line 155

def convert_text_content(hash)
  content = hash.fetch(TEXT_CONTENT_KEY)
  converter = TYPE_CONVERTERS[hash["type"]]

  return unwrap_if_simple(hash, content) unless converter

  apply_converter(hash, content, converter)
end

.disallowed_type?(type, disallowed_types) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if a type is in the disallowed list

Parameters:

  • type (String, nil)

    Type to check

  • disallowed_types (Array<String>)

    Disallowed type list

Returns:

  • (Boolean)

    true if type is disallowed



82
83
84
# File 'lib/multi_xml/helpers.rb', line 82

def disallowed_type?(type, disallowed_types)
  type && !type.is_a?(Hash) && disallowed_types.include?(type)
end

.empty_value?(hash, type) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if a hash represents an empty value

Parameters:

  • hash (Hash)

    Hash to check

  • type (String, nil)

    Type attribute value

Returns:

  • (Boolean)

    true if value should be nil



180
181
182
183
184
# File 'lib/multi_xml/helpers.rb', line 180

def empty_value?(hash, type)
  hash.empty? ||
    hash["nil"] == "true" ||
    (type && hash.size == 1 && !type.is_a?(Hash))
end

.extract_array_entries(hash, disallowed_types) ⇒ Array

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Extract array entries from element with type="array"

Parameters:

  • hash (Hash)

    Hash containing array entries

  • disallowed_types (Array<String>)

    Types to reject

Returns:

  • (Array)

    Extracted and typecasted entries

See Also:



120
121
122
123
124
125
# File 'lib/multi_xml/helpers.rb', line 120

def extract_array_entries(hash, disallowed_types)
  entries = find_array_entries(hash)
  return [] unless entries

  wrap_and_typecast(entries, disallowed_types)
end

.find_array_entries(hash) ⇒ Array, ...

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Find array or hash entries in a hash, excluding the type key

Parameters:

  • hash (Hash)

    Hash to search

Returns:

  • (Array, Hash, nil)

    Found entries or nil



132
133
134
135
136
137
# File 'lib/multi_xml/helpers.rb', line 132

def find_array_entries(hash)
  hash.each do |key, value|
    return value if !key.eql?("type") && (value.is_a?(Array) || value.is_a?(Hash))
  end
  nil
end

.symbolize_keys(data) ⇒ Hash, ...

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Recursively convert all hash keys to symbols

Examples:

Symbolize hash keys

symbolize_keys({"name" => "John"}) #=> {name: "John"}

Parameters:

  • data (Hash, Array, Object)

    Data to transform

Returns:

  • (Hash, Array, Object)

    Transformed data with symbolized keys



18
19
20
# File 'lib/multi_xml/helpers.rb', line 18

def symbolize_keys(data)
  transform_keys(data, &:to_sym)
end

.transform_keys(data, &block) ⇒ Hash, ...

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Recursively transform hash keys using a block

Parameters:

  • data (Hash, Array, Object)

    Data to transform

Returns:

  • (Hash, Array, Object)

    Transformed data



193
194
195
196
197
198
199
200
201
# File 'lib/multi_xml/helpers.rb', line 193

def transform_keys(data, &block)
  case data
  when Hash then data.each_with_object(
    {} #: Hash[Symbol, MultiXml::xmlValue] # rubocop:disable Layout/LeadingCommentSpace
  ) { |(key, value), acc| acc[yield(key)] = transform_keys(value, &block) }
  when Array then data.map { |item| transform_keys(item, &block) }
  else data
  end
end

.typecast_array(array, disallowed_types) ⇒ Object, Array

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Typecast array elements and unwrap single-element arrays

Parameters:

  • array (Array)

    Array to typecast

  • disallowed_types (Array<String>)

    Types to reject

Returns:

  • (Object, Array)

    Typecasted array or single element



57
58
59
60
# File 'lib/multi_xml/helpers.rb', line 57

def typecast_array(array, disallowed_types)
  array.map! { |item| typecast_xml_value(item, disallowed_types) }
  array.one? ? array.first : array
end

.typecast_children(hash, disallowed_types) ⇒ Hash, StringIO

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Typecast all child values in a hash

Parameters:

  • hash (Hash)

    Hash with children to typecast

  • disallowed_types (Array<String>)

    Types to reject

Returns:

  • (Hash, StringIO)

    Typecasted hash or unwrapped file



108
109
110
111
# File 'lib/multi_xml/helpers.rb', line 108

def typecast_children(hash, disallowed_types)
  result = hash.transform_values { |v| typecast_xml_value(v, disallowed_types) }
  unwrap_file_if_present(result)
end

.typecast_hash(hash, disallowed_types) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Typecast a hash based on its type attribute

Parameters:

  • hash (Hash)

    Hash to typecast

  • disallowed_types (Array<String>)

    Types to reject

Returns:

  • (Object)

    Typecasted value

Raises:



69
70
71
72
73
74
# File 'lib/multi_xml/helpers.rb', line 69

def typecast_hash(hash, disallowed_types)
  type = hash["type"]
  raise DisallowedTypeError, type if disallowed_type?(type, disallowed_types)

  convert_hash(hash, type, disallowed_types)
end

.typecast_xml_value(value, disallowed_types = DISALLOWED_TYPES) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Recursively typecast XML values based on type attributes

Examples:

Typecast integer value

typecast_xml_value({"__content__" => "42", "type" => "integer"})
#=> 42

Parameters:

  • value (Hash, Array, Object)

    Value to typecast

  • disallowed_types (Array<String>) (defaults to: DISALLOWED_TYPES)

    Types to reject

Returns:

  • (Object)

    Typecasted value

Raises:



43
44
45
46
47
48
49
# File 'lib/multi_xml/helpers.rb', line 43

def typecast_xml_value(value, disallowed_types = DISALLOWED_TYPES)
  case value
  when Hash then typecast_hash(value, disallowed_types)
  when Array then typecast_array(value, disallowed_types)
  else value
  end
end

.undasherize_keys(data) ⇒ Hash, ...

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Recursively convert dashes in hash keys to underscores

Examples:

Convert dashed keys

undasherize_keys({"first-name" => "John"}) #=> {"first_name" => "John"}

Parameters:

  • data (Hash, Array, Object)

    Data to transform

Returns:

  • (Hash, Array, Object)

    Transformed data with undasherized keys



29
30
31
# File 'lib/multi_xml/helpers.rb', line 29

def undasherize_keys(data)
  transform_keys(data) { |key| key.tr("-", "_") }
end

.unwrap_file_if_present(result) ⇒ Hash, StringIO

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Unwrap a file object from the result hash if present

Parameters:

  • result (Hash)

    Hash that may contain a file

Returns:

  • (Hash, StringIO)

    The file if present, otherwise the hash



208
209
210
211
# File 'lib/multi_xml/helpers.rb', line 208

def unwrap_file_if_present(result)
  file = result["file"]
  file.is_a?(StringIO) ? file : result
end

.unwrap_if_simple(hash, value) ⇒ Object, Hash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Unwrap value if hash has no other significant keys

Parameters:

  • hash (Hash)

    Original hash

  • value (Object)

    Converted value

Returns:

  • (Object, Hash)

    Value or hash with merged content



170
171
172
# File 'lib/multi_xml/helpers.rb', line 170

def unwrap_if_simple(hash, value)
  (hash.size > 1) ? hash.merge(TEXT_CONTENT_KEY => value) : value
end

.wrap_and_typecast(entries, disallowed_types) ⇒ Array

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Wrap hash in array if needed and typecast all entries

Parameters:

  • entries (Array, Hash)

    Entries to process

  • disallowed_types (Array<String>)

    Types to reject

Returns:

  • (Array)

    Typecasted entries



145
146
147
148
# File 'lib/multi_xml/helpers.rb', line 145

def wrap_and_typecast(entries, disallowed_types)
  entries = [entries] if entries.is_a?(Hash)
  entries.map { |entry| typecast_xml_value(entry, disallowed_types) }
end