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:
-
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.
@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
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
# 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
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
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.safe_load(yaml_string, :permitted_classes => [Date, Time, Symbol]) 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
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
@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
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
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
# File lib/cocoapods-core/yaml_helper.rb, line 320 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
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
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
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
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
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