cocoapods-core 0.17.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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