class Pod::YAMLHelper

Converts objects to their YAML representation.

This class was created for the need having control on how the YAML is representation is generated. In details it provides:

@note This class misses important features necessary for a correct YAML

serialization and thus it is safe to use only for the Lockfile.
The missing features include:
- Strings are never quoted even when ambiguous.

@todo Remove any code required solely for Ruby 1.8.x.

Constants

INDICATOR_START
INDICATOR_START_CHARS
RESOLVED_TAGS
RESOLVED_TAGS_PATTERN
VALID_PLAIN_SCALAR_STRING

Public Class Methods

convert(value) click to toggle source

Returns the YAML representation of the given object. If the given object is a Hash, it accepts an optional hint for sorting the keys.

@param [String, Symbol, Array, Hash] object

the object to convert

@param [Array] hash_keys_hint

an array to use as a hint for sorting the keys of the object to
convert if it is a hash.

@return [String] the YAML representation of the given object.

# File lib/cocoapods-core/yaml_helper.rb, line 35
def convert(value)
  result = process_according_to_class(value)
  result << "\n"
end
convert_hash(value, hash_keys_hint, line_separator = "\n") click to toggle source
# File lib/cocoapods-core/yaml_helper.rb, line 40
def convert_hash(value, hash_keys_hint, line_separator = "\n")
  result = process_hash(value, hash_keys_hint, line_separator)
  result << "\n"
end
load_file(file_path) click to toggle source

Loads a YAML file and leans on the load_string imp to do error detection

@param [Pathname] file_path

The file path to be used for read for the YAML file

@return [Hash, Array] the Ruby YAML representaton

# File lib/cocoapods-core/yaml_helper.rb, line 74
def load_file(file_path)
  load_string(File.read(file_path), file_path)
end
load_string(yaml_string, file_path = nil) click to toggle source

Loads a YAML string and provide more informative error messages in special cases like merge conflict.

@param [String] yaml_string

The YAML String to be loaded

@param [Pathname] file_path

The (optional) file path to be used for read for the YAML file

@return [Hash, Array] the Ruby YAML representaton

# File lib/cocoapods-core/yaml_helper.rb, line 56
def load_string(yaml_string, file_path = nil)
  YAML.load(yaml_string)
rescue
  if yaml_has_merge_error?(yaml_string)
    raise Informative, yaml_merge_conflict_msg(yaml_string, file_path)
  else
    raise Informative, yaml_parsing_error_msg(yaml_string, file_path)
  end
end
sorted_array(array) click to toggle source

Sorts an array according to the string representation of it values. This method allows to sort arrays which contains strings or hashes.

@note If the value contained in the array is another Array or a Hash

the first value of the collection is used for sorting, as this
method is more useful, for arrays which contains a collection
composed by one object.

@todo This stuff is here only because the Lockfile intermixes strings

and hashes for the `PODS` key. The Lockfile should be more
consistent.

@return [Array] The sorted array.

# File lib/cocoapods-core/yaml_helper.rb, line 256
def sorted_array(array)
  array.each_with_index.sort_by do |element, index|
    [sorting_string(element), index]
  end.map(&:first)
end

Private Class Methods

process_according_to_class(value, hash_keys_hint = nil) click to toggle source

@return [String] the YAML representation of the given object.

# File lib/cocoapods-core/yaml_helper.rb, line 95
def process_according_to_class(value, hash_keys_hint = nil)
  case value
  when Array      then process_array(value)
  when Hash       then process_hash(value, hash_keys_hint)
  when String     then process_string(value)
  else                 YAML.dump(value, :line_width => 2**31 - 1).sub(/\A---/, '').sub(/[.]{3}\s*\Z/, '')
  end.strip
end
process_array(array) click to toggle source

Converts an array to YAML after sorting it.

@param [Array] array

the array to convert.

@return [String] the YAML representation of the given object.

# File lib/cocoapods-core/yaml_helper.rb, line 111
def process_array(array)
  return '[]' if array.empty?

  result = sorted_array(array).map do |array_value|
    processed = process_according_to_class(array_value)
    case array_value
    when Array, Hash
      if array_value.size > 1
        processed = processed.gsub(/^.*/).to_a
        head = processed.shift
        processed.map { |s| "  #{s}" }.prepend(head).join("\n")
      else
        processed
      end
    else
      processed
    end
  end
  "- #{result.join("\n- ").strip}"
end
process_hash(hash, hash_keys_hint = nil, line_separator = "\n") click to toggle source

Converts a hash to YAML after sorting its keys. Optionally accepts a hint for sorting the keys.

@note If a hint for sorting the keys is provided the array is assumed

to be the root object and the keys are separated by an
additional new line feed for readability.

@note If the value of a given key is a String it displayed inline,

otherwise it is displayed below and indented.

@param [Hash] hash

the hash to convert.

@return [String] the YAML representation of the given object.

# File lib/cocoapods-core/yaml_helper.rb, line 147
def process_hash(hash, hash_keys_hint = nil, line_separator = "\n")
  return '{}' if hash.empty?

  keys = sorted_array_with_hint(hash.keys, hash_keys_hint)
  key_lines = keys.map do |key|
    key_value = hash[key]
    processed = process_according_to_class(key_value)
    processed_key = process_according_to_class(key)
    case key_value
    when Hash, Array
      key_partial_yaml = processed.lines.map { |line| "  #{line}" } * ''
      "#{processed_key}:\n#{key_partial_yaml}"
    else
      "#{processed_key}: #{processed}"
    end
  end
  key_lines * line_separator
end
process_string(string) click to toggle source
# File lib/cocoapods-core/yaml_helper.rb, line 309
def process_string(string)
  case string
  when RESOLVED_TAGS_PATTERN
    "'#{string}'"
  when /\A\s*\z/, INDICATOR_START, /:\z/
    string.inspect
  when VALID_PLAIN_SCALAR_STRING
    string
  else
    string.inspect
  end
end
sorted_array_with_hint(array, sort_hint) click to toggle source

Sorts an array using another one as a sort hint. All the values of the hint which appear in the array will be returned respecting the order in the hint. If any other key is present in the original array they are sorted using the {#sorted_array} method.

@param [Array] array

The array which needs to be sorted.

@param [Array] sort_hint

The array which should be used to sort the keys.

@return [Array] The sorted Array.

# File lib/cocoapods-core/yaml_helper.rb, line 230
def sorted_array_with_hint(array, sort_hint)
  if sort_hint
    hinted = sort_hint & array
    remaining = array - sort_hint
    hinted + sorted_array(remaining)
  else
    sorted_array(array)
  end
end
sorting_string(value) click to toggle source

Returns the string representation of a value useful for sorting.

@param [String, Symbol, Array, Hash] value

The value which needs to be sorted

@return [String] A string useful to compare the value with other ones.

# File lib/cocoapods-core/yaml_helper.rb, line 271
def sorting_string(value)
  return '' unless value
  case value
  when String then value.downcase
  when Symbol then sorting_string(value.to_s)
  when Array  then sorting_string(value.first)
  when Hash   then value.keys.map { |key| key.to_s.downcase }.sort.first
  else             raise ArgumentError, "Cannot sort #{value.inspect}"
  end
end
yaml_has_merge_error?(yaml_string) click to toggle source

Check for merge errors in a YAML string.

@param [String] yaml_string

A YAML string to evaluate

@return If a merge error was detected or not.

# File lib/cocoapods-core/yaml_helper.rb, line 173
def yaml_has_merge_error?(yaml_string)
  yaml_string.include?('<<<<<<< HEAD')
end
yaml_merge_conflict_msg(yaml, path = nil) click to toggle source

Error message describing that a merge conflict was found while parsing the YAML.

@param [String] yaml

Offending YAML

@param [Pathname] path

The (optional) offending path

@return [String] The Error Message

# File lib/cocoapods-core/yaml_helper.rb, line 188
def yaml_merge_conflict_msg(yaml, path = nil)
  err = 'ERROR: Parsing unable to continue due '
  err += "to merge conflicts present in:\n"
  err += "the file located at #{path}\n" if path
  err + "#{yaml}"
end
yaml_parsing_error_msg(yaml, path = nil) click to toggle source

Error message describing a general error took happened while parsing the YAML.

@param [String] yaml

Offending YAML

@param [Pathname] path

The (optional) offending path

@return [String] The Error Message

# File lib/cocoapods-core/yaml_helper.rb, line 206
def yaml_parsing_error_msg(yaml, path = nil)
  err = 'ERROR: Parsing unable to continue due '
  err += "to parsing error:\n"
  err += "contained in the file located at #{path}\n" if path
  err + "#{yaml}"
end