cocoapods-core 0.17.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +36 -0
  4. data/lib/cocoapods-core/core_ui.rb +19 -0
  5. data/lib/cocoapods-core/dependency.rb +295 -0
  6. data/lib/cocoapods-core/gem_version.rb +6 -0
  7. data/lib/cocoapods-core/lockfile.rb +440 -0
  8. data/lib/cocoapods-core/platform.rb +171 -0
  9. data/lib/cocoapods-core/podfile/dsl.rb +459 -0
  10. data/lib/cocoapods-core/podfile/target_definition.rb +503 -0
  11. data/lib/cocoapods-core/podfile.rb +345 -0
  12. data/lib/cocoapods-core/requirement.rb +15 -0
  13. data/lib/cocoapods-core/source/validator.rb +183 -0
  14. data/lib/cocoapods-core/source.rb +284 -0
  15. data/lib/cocoapods-core/specification/consumer.rb +356 -0
  16. data/lib/cocoapods-core/specification/dsl/attribute.rb +245 -0
  17. data/lib/cocoapods-core/specification/dsl/attribute_support.rb +76 -0
  18. data/lib/cocoapods-core/specification/dsl/deprecations.rb +47 -0
  19. data/lib/cocoapods-core/specification/dsl/platform_proxy.rb +67 -0
  20. data/lib/cocoapods-core/specification/dsl.rb +1110 -0
  21. data/lib/cocoapods-core/specification/linter.rb +436 -0
  22. data/lib/cocoapods-core/specification/root_attribute_accessors.rb +152 -0
  23. data/lib/cocoapods-core/specification/set/presenter.rb +229 -0
  24. data/lib/cocoapods-core/specification/set/statistics.rb +277 -0
  25. data/lib/cocoapods-core/specification/set.rb +171 -0
  26. data/lib/cocoapods-core/specification/yaml.rb +60 -0
  27. data/lib/cocoapods-core/specification.rb +592 -0
  28. data/lib/cocoapods-core/standard_error.rb +84 -0
  29. data/lib/cocoapods-core/vendor/dependency.rb +264 -0
  30. data/lib/cocoapods-core/vendor/requirement.rb +208 -0
  31. data/lib/cocoapods-core/vendor/version.rb +333 -0
  32. data/lib/cocoapods-core/vendor.rb +56 -0
  33. data/lib/cocoapods-core/version.rb +99 -0
  34. data/lib/cocoapods-core/yaml_converter.rb +202 -0
  35. data/lib/cocoapods-core.rb +23 -0
  36. metadata +154 -0
@@ -0,0 +1,333 @@
1
+ module Pod::Vendor
2
+
3
+ ##
4
+ # The Version class processes string versions into comparable
5
+ # values. A version string should normally be a series of numbers
6
+ # separated by periods. Each part (digits separated by periods) is
7
+ # considered its own number, and these are used for sorting. So for
8
+ # instance, 3.10 sorts higher than 3.2 because ten is greater than
9
+ # two.
10
+ #
11
+ # If any part contains letters (currently only a-z are supported) then
12
+ # that version is considered prerelease. Versions with a prerelease
13
+ # part in the Nth part sort less than versions with N-1
14
+ # parts. Prerelease parts are sorted alphabetically using the normal
15
+ # Ruby string sorting rules. If a prerelease part contains both
16
+ # letters and numbers, it will be broken into multiple parts to
17
+ # provide expected sort behavior (1.0.a10 becomes 1.0.a.10, and is
18
+ # greater than 1.0.a9).
19
+ #
20
+ # Prereleases sort between real releases (newest to oldest):
21
+ #
22
+ # 1. 1.0
23
+ # 2. 1.0.b1
24
+ # 3. 1.0.a.2
25
+ # 4. 0.9
26
+ #
27
+ # == How Software Changes
28
+ #
29
+ # Users expect to be able to specify a version constraint that gives them
30
+ # some reasonable expectation that new versions of a library will work with
31
+ # their software if the version constraint is true, and not work with their
32
+ # software if the version constraint is false. In other words, the perfect
33
+ # system will accept all compatible versions of the library and reject all
34
+ # incompatible versions.
35
+ #
36
+ # Libraries change in 3 ways (well, more than 3, but stay focused here!).
37
+ #
38
+ # 1. The change may be an implementation detail only and have no effect on
39
+ # the client software.
40
+ # 2. The change may add new features, but do so in a way that client software
41
+ # written to an earlier version is still compatible.
42
+ # 3. The change may change the public interface of the library in such a way
43
+ # that old software is no longer compatible.
44
+ #
45
+ # Some examples are appropriate at this point. Suppose I have a Stack class
46
+ # that supports a <tt>push</tt> and a <tt>pop</tt> method.
47
+ #
48
+ # === Examples of Category 1 changes:
49
+ #
50
+ # * Switch from an array based implementation to a linked-list based
51
+ # implementation.
52
+ # * Provide an automatic (and transparent) backing store for large stacks.
53
+ #
54
+ # === Examples of Category 2 changes might be:
55
+ #
56
+ # * Add a <tt>depth</tt> method to return the current depth of the stack.
57
+ # * Add a <tt>top</tt> method that returns the current top of stack (without
58
+ # changing the stack).
59
+ # * Change <tt>push</tt> so that it returns the item pushed (previously it
60
+ # had no usable return value).
61
+ #
62
+ # === Examples of Category 3 changes might be:
63
+ #
64
+ # * Changes <tt>pop</tt> so that it no longer returns a value (you must use
65
+ # <tt>top</tt> to get the top of the stack).
66
+ # * Rename the methods to <tt>push_item</tt> and <tt>pop_item</tt>.
67
+ #
68
+ # == RubyGems Rational Versioning
69
+ #
70
+ # * Versions shall be represented by three non-negative integers, separated
71
+ # by periods (e.g. 3.1.4). The first integers is the "major" version
72
+ # number, the second integer is the "minor" version number, and the third
73
+ # integer is the "build" number.
74
+ #
75
+ # * A category 1 change (implementation detail) will increment the build
76
+ # number.
77
+ #
78
+ # * A category 2 change (backwards compatible) will increment the minor
79
+ # version number and reset the build number.
80
+ #
81
+ # * A category 3 change (incompatible) will increment the major build number
82
+ # and reset the minor and build numbers.
83
+ #
84
+ # * Any "public" release of a gem should have a different version. Normally
85
+ # that means incrementing the build number. This means a developer can
86
+ # generate builds all day long for himself, but as soon as he/she makes a
87
+ # public release, the version must be updated.
88
+ #
89
+ # === Examples
90
+ #
91
+ # Let's work through a project lifecycle using our Stack example from above.
92
+ #
93
+ # Version 0.0.1:: The initial Stack class is release.
94
+ # Version 0.0.2:: Switched to a linked=list implementation because it is
95
+ # cooler.
96
+ # Version 0.1.0:: Added a <tt>depth</tt> method.
97
+ # Version 1.0.0:: Added <tt>top</tt> and made <tt>pop</tt> return nil
98
+ # (<tt>pop</tt> used to return the old top item).
99
+ # Version 1.1.0:: <tt>push</tt> now returns the value pushed (it used it
100
+ # return nil).
101
+ # Version 1.1.1:: Fixed a bug in the linked list implementation.
102
+ # Version 1.1.2:: Fixed a bug introduced in the last fix.
103
+ #
104
+ # Client A needs a stack with basic push/pop capability. He writes to the
105
+ # original interface (no <tt>top</tt>), so his version constraint looks
106
+ # like:
107
+ #
108
+ # gem 'stack', '~> 0.0'
109
+ #
110
+ # Essentially, any version is OK with Client A. An incompatible change to
111
+ # the library will cause him grief, but he is willing to take the chance (we
112
+ # call Client A optimistic).
113
+ #
114
+ # Client B is just like Client A except for two things: (1) He uses the
115
+ # <tt>depth</tt> method and (2) he is worried about future
116
+ # incompatibilities, so he writes his version constraint like this:
117
+ #
118
+ # gem 'stack', '~> 0.1'
119
+ #
120
+ # The <tt>depth</tt> method was introduced in version 0.1.0, so that version
121
+ # or anything later is fine, as long as the version stays below version 1.0
122
+ # where incompatibilities are introduced. We call Client B pessimistic
123
+ # because he is worried about incompatible future changes (it is OK to be
124
+ # pessimistic!).
125
+ #
126
+ # == Preventing Version Catastrophe:
127
+ #
128
+ # From: http://blog.zenspider.com/2008/10/rubygems-howto-preventing-cata.html
129
+ #
130
+ # Let's say you're depending on the fnord gem version 2.y.z. If you
131
+ # specify your dependency as ">= 2.0.0" then, you're good, right? What
132
+ # happens if fnord 3.0 comes out and it isn't backwards compatible
133
+ # with 2.y.z? Your stuff will break as a result of using ">=". The
134
+ # better route is to specify your dependency with a "spermy" version
135
+ # specifier. They're a tad confusing, so here is how the dependency
136
+ # specifiers work:
137
+ #
138
+ # Specification From ... To (exclusive)
139
+ # ">= 3.0" 3.0 ... &infin;
140
+ # "~> 3.0" 3.0 ... 4.0
141
+ # "~> 3.0.0" 3.0.0 ... 3.1
142
+ # "~> 3.5" 3.5 ... 4.0
143
+ # "~> 3.5.0" 3.5.0 ... 3.6
144
+
145
+ class Gem::Version
146
+ autoload :Requirement, 'rubygems/requirement'
147
+
148
+ include Comparable
149
+
150
+ VERSION_PATTERN = '[0-9]+(\.[0-9a-zA-Z]+)*' # :nodoc:
151
+ ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})*\s*\z/ # :nodoc:
152
+
153
+ ##
154
+ # A string representation of this Version.
155
+
156
+ attr_reader :version
157
+ alias to_s version
158
+
159
+ ##
160
+ # True if the +version+ string matches RubyGems' requirements.
161
+
162
+ def self.correct? version
163
+ version.to_s =~ ANCHORED_VERSION_PATTERN
164
+ end
165
+
166
+ ##
167
+ # Factory method to create a Version object. Input may be a Version
168
+ # or a String. Intended to simplify client code.
169
+ #
170
+ # ver1 = Version.create('1.3.17') # -> (Version object)
171
+ # ver2 = Version.create(ver1) # -> (ver1)
172
+ # ver3 = Version.create(nil) # -> nil
173
+
174
+ def self.create input
175
+ if input.respond_to? :version then
176
+ input
177
+ elsif input.nil? then
178
+ nil
179
+ else
180
+ new input
181
+ end
182
+ end
183
+
184
+ ##
185
+ # Constructs a Version from the +version+ string. A version string is a
186
+ # series of digits or ASCII letters separated by dots.
187
+
188
+ def initialize version
189
+ raise ArgumentError, "Malformed version number string #{version}" unless
190
+ self.class.correct?(version)
191
+
192
+ @version = version.to_s
193
+ @version.strip!
194
+ end
195
+
196
+ ##
197
+ # Return a new version object where the next to the last revision
198
+ # number is one greater (e.g., 5.3.1 => 5.4).
199
+ #
200
+ # Pre-release (alpha) parts, e.g, 5.3.1.b.2 => 5.4, are ignored.
201
+
202
+ def bump
203
+ segments = self.segments.dup
204
+ segments.pop while segments.any? { |s| String === s }
205
+ segments.pop if segments.size > 1
206
+
207
+ segments[-1] = segments[-1].succ
208
+ self.class.new segments.join(".")
209
+ end
210
+
211
+ ##
212
+ # A Version is only eql? to another version if it's specified to the
213
+ # same precision. Version "1.0" is not the same as version "1".
214
+
215
+ def eql? other
216
+ self.class === other and @version == other.version
217
+ end
218
+
219
+ def hash # :nodoc:
220
+ @hash ||= segments.hash
221
+ end
222
+
223
+ def init_with coder # :nodoc:
224
+ yaml_initialize coder.tag, coder.map
225
+ end
226
+
227
+ def inspect # :nodoc:
228
+ "#<#{self.class} #{version.inspect}>"
229
+ end
230
+
231
+ ##
232
+ # Dump only the raw version string, not the complete object. It's a
233
+ # string for backwards (RubyGems 1.3.5 and earlier) compatibility.
234
+
235
+ def marshal_dump
236
+ [version]
237
+ end
238
+
239
+ ##
240
+ # Load custom marshal format. It's a string for backwards (RubyGems
241
+ # 1.3.5 and earlier) compatibility.
242
+
243
+ def marshal_load array
244
+ initialize array[0]
245
+ end
246
+
247
+ def yaml_initialize(tag, map)
248
+ @version = map['version']
249
+ @segments = nil
250
+ @hash = nil
251
+ end
252
+
253
+ ##
254
+ # A version is considered a prerelease if it contains a letter.
255
+
256
+ def prerelease?
257
+ @prerelease ||= @version =~ /[a-zA-Z]/
258
+ end
259
+
260
+ def pretty_print q # :nodoc:
261
+ q.text "Gem::Version.new(#{version.inspect})"
262
+ end
263
+
264
+ ##
265
+ # The release for this version (e.g. 1.2.0.a -> 1.2.0).
266
+ # Non-prerelease versions return themselves.
267
+
268
+ def release
269
+ return self unless prerelease?
270
+
271
+ segments = self.segments.dup
272
+ segments.pop while segments.any? { |s| String === s }
273
+ self.class.new segments.join('.')
274
+ end
275
+
276
+ def segments # :nodoc:
277
+
278
+ # segments is lazy so it can pick up version values that come from
279
+ # old marshaled versions, which don't go through marshal_load.
280
+
281
+ @segments ||= @version.scan(/[0-9]+|[a-z]+/i).map do |s|
282
+ /^\d+$/ =~ s ? s.to_i : s
283
+ end
284
+ end
285
+
286
+ ##
287
+ # A recommended version for use with a ~> Requirement.
288
+
289
+ def spermy_recommendation
290
+ segments = self.segments.dup
291
+
292
+ segments.pop while segments.any? { |s| String === s }
293
+ segments.pop while segments.size > 2
294
+ segments.push 0 while segments.size < 2
295
+
296
+ "~> #{segments.join(".")}"
297
+ end
298
+
299
+ ##
300
+ # Compares this version with +other+ returning -1, 0, or 1 if the
301
+ # other version is larger, the same, or smaller than this
302
+ # one. Attempts to compare to something that's not a
303
+ # <tt>Gem::Version</tt> return +nil+.
304
+
305
+ def <=> other
306
+ return unless Gem::Version === other
307
+ return 0 if @version == other.version
308
+
309
+ lhsegments = segments
310
+ rhsegments = other.segments
311
+
312
+ lhsize = lhsegments.size
313
+ rhsize = rhsegments.size
314
+ limit = (lhsize > rhsize ? lhsize : rhsize) - 1
315
+
316
+ i = 0
317
+
318
+ while i <= limit
319
+ lhs, rhs = lhsegments[i] || 0, rhsegments[i] || 0
320
+ i += 1
321
+
322
+ next if lhs == rhs
323
+ return -1 if String === lhs && Numeric === rhs
324
+ return 1 if Numeric === lhs && String === rhs
325
+
326
+ return lhs <=> rhs
327
+ end
328
+
329
+ return 0
330
+ end
331
+ end
332
+
333
+ end
@@ -0,0 +1,56 @@
1
+ module Pod
2
+
3
+ # Namespaces the vendored modules.
4
+ #
5
+ module Vendor
6
+
7
+ # Namespaces the classes of RubyGems used by CocoaPods.
8
+ #
9
+ # CocoaPods needs to vendor RubyGems because OS X ships with `v1.3.6` which
10
+ # has a couple of bugs related to the comparison of pre-release versions.
11
+ #
12
+ # E.g. https://github.com/CocoaPods/CocoaPods/issues/398
13
+ #
14
+ # The following classes are copied from RubyGems `v1.8.24`. The changes
15
+ # performed to the source files are the following:
16
+ #
17
+ # - Namespaced in `Pod::Vendor`
18
+ # - commented all the `require` calls
19
+ # - replaced `::Gem` with `Pod::Vendor::Gem`
20
+ #
21
+ module Gem
22
+
23
+ require 'cocoapods-core/vendor/version'
24
+ require 'cocoapods-core/vendor/requirement'
25
+ require 'cocoapods-core/vendor/dependency'
26
+
27
+ #-----------------------------------------------------------------------#
28
+ # RubyGems License #
29
+ # https://github.com/rubygems/rubygems/blob/master/MIT.txt
30
+ #-----------------------------------------------------------------------#
31
+
32
+ # Copyright (c) Chad Fowler, Rich Kilmer, Jim Weirich and others.
33
+ #
34
+ # Permission is hereby granted, free of charge, to any person obtaining
35
+ # a copy of this software and associated documentation files (the
36
+ # 'Software'), to deal in the Software without restriction, including
37
+ # without limitation the rights to use, copy, modify, merge, publish,
38
+ # distribute, sublicense, and/or sell copies of the Software, and to
39
+ # permit persons to whom the Software is furnished to do so, subject to
40
+ # the following conditions:
41
+ #
42
+ # The above copyright notice and this permission notice shall be
43
+ # included in all copies or substantial portions of the Software.
44
+ #
45
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
46
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
47
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
48
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
49
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
50
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
51
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52
+
53
+ end
54
+ end
55
+ end
56
+
@@ -0,0 +1,99 @@
1
+ module Pod
2
+
3
+ # The Version class stores information about the version of a
4
+ # {Specification}.
5
+ #
6
+ # It is based on the RubyGems class adapted to support head information.
7
+ #
8
+ # ### From RubyGems:
9
+ #
10
+ # The Version class processes string versions into comparable
11
+ # values. A version string should normally be a series of numbers
12
+ # separated by periods. Each part (digits separated by periods) is
13
+ # considered its own number, and these are used for sorting. So for
14
+ # instance, 3.10 sorts higher than 3.2 because ten is greater than
15
+ # two.
16
+ #
17
+ # If any part contains letters (currently only a-z are supported) then
18
+ # that version is considered prerelease. Versions with a prerelease
19
+ # part in the Nth part sort less than versions with N-1
20
+ # parts. Prerelease parts are sorted alphabetically using the normal
21
+ # Ruby string sorting rules. If a prerelease part contains both
22
+ # letters and numbers, it will be broken into multiple parts to
23
+ # provide expected sort behavior (1.0.a10 becomes 1.0.a.10, and is
24
+ # greater than 1.0.a9).
25
+ #
26
+ # Prereleases sort between real releases (newest to oldest):
27
+ #
28
+ # 1. 1.0
29
+ # 2. 1.0.b1
30
+ # 3. 1.0.a.2
31
+ # 4. 0.9
32
+ #
33
+ class Version < Pod::Vendor::Gem::Version
34
+
35
+ # Override the constants defined by the superclass to add Semantic
36
+ # Versioning prerelease support (with a dash). E.g.: 1.0.0-alpha1
37
+ #
38
+ # For more info, see: http://semver.org
39
+ #
40
+ VERSION_PATTERN = '[0-9]+(\.[0-9a-zA-Z\-]+)*'
41
+ ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})*\s*\z/
42
+
43
+ # @return [Bool] whether the version represents the `head` of repository.
44
+ #
45
+ attr_accessor :head
46
+ alias_method :head?, :head
47
+
48
+ # @param [String,Version] version
49
+ # A string representing a version, or another version.
50
+ #
51
+ # @todo The `from` part of the regular expression should be remove in
52
+ # CocoaPods 1.0.0.
53
+ #
54
+ def initialize(version)
55
+ if version.is_a?(Version) && version.head?
56
+ version = version.version
57
+ @head = true
58
+ elsif version.is_a?(String) && version =~ /HEAD (based on|from) (.*)/
59
+ version = $2
60
+ @head = true
61
+ end
62
+ super(version)
63
+ end
64
+
65
+ # @return [String] a string representation that indicates if the version is
66
+ # head.
67
+ #
68
+ # @note The raw version string is still accessible with the {#version}
69
+ # method.
70
+ #
71
+ def to_s
72
+ head? ? "HEAD based on #{super}" : super
73
+ end
74
+
75
+ # @return [String] a string representation suitable for debugging.
76
+ #
77
+ def inspect
78
+ "<#{self.class} version=#{self.version}>"
79
+ end
80
+
81
+ # @return [Boolean] indicates whether or not the version is a prerelease.
82
+ #
83
+ # @note Prerelease Pods can contain a hyphen and/or a letter (conforms to
84
+ # Semantic Versioning instead of RubyGems).
85
+ #
86
+ # For more info, see: http://semver.org
87
+ #
88
+ def prerelease?
89
+ @prerelease ||= @version =~ /[a-zA-Z\-]/
90
+ end
91
+
92
+ # @return [Bool] Whether a string representation is correct.
93
+ #
94
+ def self.correct? version
95
+ version.to_s =~ ANCHORED_VERSION_PATTERN
96
+ end
97
+ end
98
+ end
99
+
@@ -0,0 +1,202 @@
1
+ module Pod
2
+
3
+ # Converts objects to their YAML representation.
4
+ #
5
+ # This class was created for the need having control on how the YAML is
6
+ # representation is generated. In details it provides:
7
+ #
8
+ # - sorting for hashes in ruby 1.8.x
9
+ # - ability to hint the sorting of the keys of a dictionary when converting
10
+ # it. In this case the keys are also separated by an additional new line
11
+ # feed for readability.
12
+ #
13
+ # @note This class misses important features necessary for a correct YAML
14
+ # serialization and thus it is safe to use only for the Lockfile.
15
+ # The missing features include:
16
+ # - Strings are never quoted even when ambiguous.
17
+ #
18
+ class YAMLConverter
19
+
20
+ class << self
21
+
22
+ # Returns the YAML representation of the given object. If the given object
23
+ # is an Hash it accepts an optional hint for sorting the keys.
24
+ #
25
+ # @param [String, Symbol, Array, Hash] object
26
+ # the object to convert
27
+ #
28
+ # @param [Array] hash_keys_hint
29
+ # an array to use as a hint for sorting the keys of the object to
30
+ # convert if it is an hash.
31
+ #
32
+ # @return [String] the YAML representation of the given object.
33
+ #
34
+ def convert(value)
35
+ result = process_according_to_class(value)
36
+ result << "\n"
37
+ end
38
+
39
+ def convert_hash(value, hash_keys_hint, line_separator = "\n")
40
+ result = process_hash(value, hash_keys_hint, line_separator)
41
+ result << "\n"
42
+ end
43
+
44
+ #-----------------------------------------------------------------------#
45
+
46
+ private
47
+
48
+ # Implementation notes:
49
+ #
50
+ # - each of the methods returns a YAML partial without an ending new
51
+ # line.
52
+ # - if a partial needs to be indented is responsibility of the method
53
+ # using it.
54
+ #
55
+ # ---
56
+
57
+ # @!group Private Helpers
58
+
59
+ # @return [String] the YAML representation of the given object.
60
+ #
61
+ def process_according_to_class(value, hash_keys_hint = nil)
62
+ case value
63
+ when String then value
64
+ when Symbol then ":#{value}"
65
+ when TrueClass then 'true'
66
+ when FalseClass then 'false'
67
+ when Array then process_array(value)
68
+ when Hash then process_hash(value, hash_keys_hint)
69
+ else
70
+ raise "Unsupported class for YAML conversion #{value.class}"
71
+ end
72
+ end
73
+
74
+ # Converts a string to YAML.
75
+ #
76
+ # @param [String] string
77
+ # the string to convert.
78
+ #
79
+ # @return [String] the YAML representation of the given object.
80
+ #
81
+ def process_string(string)
82
+ string
83
+ end
84
+
85
+ # Converts an array to YAML after sorting it.
86
+ #
87
+ # @param [Array] array
88
+ # the array to convert.
89
+ #
90
+ # @return [String] the YAML representation of the given object.
91
+ #
92
+ def process_array(array)
93
+ result = []
94
+ sorted_array(array).each do |array_value|
95
+ result << process_according_to_class(array_value)
96
+ end
97
+ "- #{result*"\n- "}"
98
+ end
99
+
100
+ # Converts a hash to YAML after sorting its keys. Optionally accepts a
101
+ # hint for sorting the keys.
102
+ #
103
+ # @note If a hint for sorting the keys is provided the array is assumed
104
+ # to be the root object and the keys are separated by an
105
+ # additional new line feed for readability.
106
+ #
107
+ # @note If the value of a given key is a String it displayed inline,
108
+ # otherwise it is displayed below and indented.
109
+ #
110
+ # @param [Hash] hash
111
+ # the hash to convert.
112
+ #
113
+ # @return [String] the YAML representation of the given object.
114
+ #
115
+ def process_hash(hash, hash_keys_hint = nil, line_separator = "\n")
116
+ keys = sorted_array_with_hint(hash.keys, hash_keys_hint)
117
+ key_lines = []
118
+ keys.each do |key|
119
+ key_value = hash[key]
120
+ processed = process_according_to_class(key_value)
121
+ processed_key = process_according_to_class(key)
122
+ case key_value
123
+ when Array, Hash
124
+ key_partial_yaml = processed.lines.map { |line| " #{line}" } * ""
125
+ key_lines << "#{processed_key}:\n#{key_partial_yaml}"
126
+ else
127
+ key_lines << "#{processed_key}: #{processed}"
128
+ end
129
+ end
130
+ key_lines * line_separator
131
+ end
132
+
133
+ #-----------------------------------------------------------------------#
134
+
135
+ private
136
+
137
+ # @!group Array Sorting
138
+
139
+ # Sorts an array using another one as a sort hint. All the values of the
140
+ # hint which appear in the array will be returned respecting the order in
141
+ # the hint. If any other key is present in the original array they are
142
+ # sorted using the {#sorted_array} method.
143
+ #
144
+ # @param [Array] array
145
+ # The array which needs to be sorted.
146
+ #
147
+ # @param [Array] sort_hint
148
+ # The array which should be used to sort the keys.
149
+ #
150
+ # @return [Array] The sorted Array.
151
+ #
152
+ def sorted_array_with_hint(array, sort_hint)
153
+ if sort_hint
154
+ hinted = sort_hint & array
155
+ remaining = array - sort_hint
156
+ hinted + sorted_array(remaining)
157
+ else
158
+ sorted_array(array)
159
+ end
160
+ end
161
+
162
+ # Sorts an array according to the string representation of it values.
163
+ # This method allows to sort arrays which contains strings or hashes.
164
+ #
165
+ # @note If the value contained in the array is another Array or a Hash
166
+ # the first value of the collection is used for sorting, as this
167
+ # method is more useful, for arrays which contains a collection
168
+ # composed by one object.
169
+ #
170
+ # @todo This stuff is here only because the Lockfile intermixes strings
171
+ # and hashes for the `PODS` key. The Lockfile should be more
172
+ # consistent.
173
+ #
174
+ # @return [Array] The sorted array.
175
+ #
176
+ def sorted_array(array)
177
+ array.sort do |x, y|
178
+ x_string = sorting_string(x)
179
+ y_string = sorting_string(y)
180
+ x_string <=> y_string
181
+ end
182
+ end
183
+
184
+ # Returns the string representation of a value useful for sorting.
185
+ #
186
+ # @param [String, Symbol, Array, Hash] value
187
+ # The value which needs to be sorted
188
+ #
189
+ # @return [String] A string useful to compare the value with other ones.
190
+ #
191
+ def sorting_string(value)
192
+ return "" unless value
193
+ case value
194
+ when String then value.downcase
195
+ when Symbol then sorting_string(value.to_s)
196
+ when Array then sorting_string(value.first)
197
+ when Hash then sorting_string(value.keys.sort.first)
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end