Class: Pod::YAMLHelper

Inherits:
Object
  • Object
show all
Defined in:
lib/cocoapods-core/yaml_helper.rb

Overview

TODO:

Remove any code required solely for Ruby 1.8.x.

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.

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:

  • sorting for hashes in ruby 1.8.x
  • ability to hint the sorting of the keys of a dictionary when converting it. In this case the keys are also separated by an additional new line feed for readability.

Private Helpers collapse

Array Sorting collapse

Class Method Summary collapse

Class Method Details

.convert(value) ⇒ String

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

Parameters:

  • object (String, Symbol, Array, Hash)

    the object to convert

  • hash_keys_hint (Array)

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

Returns:

  • (String)

    the YAML representation of the given object.


35
36
37
38
# 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") ⇒ Object


40
41
42
43
# 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) ⇒ Hash, Array

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

Parameters:

  • file_path (Pathname)

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

Returns:

  • (Hash, Array)

    the Ruby YAML representaton


74
75
76
# 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) ⇒ Hash, Array

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

Parameters:

  • yaml_string (String)

    The YAML String to be loaded

  • file_path (Pathname) (defaults to: nil)

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

Returns:

  • (Hash, Array)

    the Ruby YAML representaton


56
57
58
59
60
61
62
63
64
# 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

.process_according_to_class(value, hash_keys_hint = nil) ⇒ String (private)

Returns the YAML representation of the given object.

Returns:

  • (String)

    the YAML representation of the given object.


95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/cocoapods-core/yaml_helper.rb', line 95

def process_according_to_class(value, hash_keys_hint = nil)
  case value
  when String     then YAML.dump(value).sub(/^---/, '').sub(/[.]{3}\s*$/, '').strip
  when Symbol     then ":#{value}"
  when TrueClass  then 'true'
  when FalseClass then 'false'
  when Array      then process_array(value)
  when Hash       then process_hash(value, hash_keys_hint)
  else
    raise StandardError, 'Unsupported class for YAML conversion ' \
      "#{value.class}"
  end
end

.process_array(array) ⇒ String (private)

Converts an array to YAML after sorting it.

Parameters:

  • array (Array)

    the array to convert.

Returns:

  • (String)

    the YAML representation of the given object.


116
117
118
119
120
121
122
# File 'lib/cocoapods-core/yaml_helper.rb', line 116

def process_array(array)
  result = []
  sorted_array(array).each do |array_value|
    result << process_according_to_class(array_value)
  end
  "- #{result * "\n- "}"
end

.process_hash(hash, hash_keys_hint = nil, line_separator = "\n") ⇒ String (private)

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.

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

Parameters:

  • hash (Hash)

    the hash to convert.

Returns:

  • (String)

    the YAML representation of the given object.


139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/cocoapods-core/yaml_helper.rb', line 139

def process_hash(hash, hash_keys_hint = nil, line_separator = "\n")
  keys = sorted_array_with_hint(hash.keys, hash_keys_hint)
  key_lines = []
  keys.each do |key|
    key_value = hash[key]
    processed = process_according_to_class(key_value)
    processed_key = process_according_to_class(key)
    case key_value
    when Array, Hash
      key_partial_yaml = processed.lines.map { |line| "  #{line}" } * ''
      key_lines << "#{processed_key}:\n#{key_partial_yaml}"
    else
      key_lines << "#{processed_key}: #{processed}"
    end
  end
  key_lines * line_separator
end

.sorted_array(array) ⇒ Array (private)

TODO:

This stuff is here only because the Lockfile intermixes strings and hashes for the PODS key. The Lockfile should be more consistent.

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.

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

Returns:

  • (Array)

    The sorted array.


247
248
249
250
251
252
253
# File 'lib/cocoapods-core/yaml_helper.rb', line 247

def sorted_array(array)
  array.sort do |x, y|
    x_string = sorting_string(x)
    y_string = sorting_string(y)
    x_string <=> y_string
  end
end

.sorted_array_with_hint(array, sort_hint) ⇒ Array (private)

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.

Parameters:

  • array (Array)

    The array which needs to be sorted.

  • sort_hint (Array)

    The array which should be used to sort the keys.

Returns:

  • (Array)

    The sorted Array.


223
224
225
226
227
228
229
230
231
# File 'lib/cocoapods-core/yaml_helper.rb', line 223

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) ⇒ String (private)

Returns the string representation of a value useful for sorting.

Parameters:

  • value (String, Symbol, Array, Hash)

    The value which needs to be sorted

Returns:

  • (String)

    A string useful to compare the value with other ones.


262
263
264
265
266
267
268
269
270
# File 'lib/cocoapods-core/yaml_helper.rb', line 262

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
  end
end

.yaml_has_merge_error?(yaml_string) ⇒ Boolean (private)

Check for merge errors in a YAML string.

Parameters:

  • yaml_string (String)

    A YAML string to evaluate

Returns:

  • (Boolean)

    If a merge error was detected or not.


164
165
166
# File 'lib/cocoapods-core/yaml_helper.rb', line 164

def yaml_has_merge_error?(yaml_string)
  yaml_string.include?('<<<<<<< HEAD')
end

.yaml_merge_conflict_msg(yaml, path = nil) ⇒ String (private)

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

Parameters:

  • yaml (String)

    Offending YAML

  • path (Pathname) (defaults to: nil)

    The (optional) offending path

Returns:

  • (String)

    The Error Message


179
180
181
182
183
184
# File 'lib/cocoapods-core/yaml_helper.rb', line 179

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) ⇒ String (private)

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

Parameters:

  • yaml (String)

    Offending YAML

  • path (Pathname) (defaults to: nil)

    The (optional) offending path

Returns:

  • (String)

    The Error Message


197
198
199
200
201
202
# File 'lib/cocoapods-core/yaml_helper.rb', line 197

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