cocoapods-core 0.30.0 → 1.15.2

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 (50) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +7 -10
  3. data/lib/cocoapods-core/build_type.rb +121 -0
  4. data/lib/cocoapods-core/cdn_source.rb +501 -0
  5. data/lib/cocoapods-core/core_ui.rb +4 -3
  6. data/lib/cocoapods-core/dependency.rb +100 -73
  7. data/lib/cocoapods-core/gem_version.rb +1 -2
  8. data/lib/cocoapods-core/github.rb +32 -5
  9. data/lib/cocoapods-core/http.rb +86 -0
  10. data/lib/cocoapods-core/lockfile.rb +161 -56
  11. data/lib/cocoapods-core/metrics.rb +47 -0
  12. data/lib/cocoapods-core/platform.rb +99 -11
  13. data/lib/cocoapods-core/podfile/dsl.rb +623 -124
  14. data/lib/cocoapods-core/podfile/target_definition.rb +662 -109
  15. data/lib/cocoapods-core/podfile.rb +138 -65
  16. data/lib/cocoapods-core/requirement.rb +37 -8
  17. data/lib/cocoapods-core/source/acceptor.rb +16 -13
  18. data/lib/cocoapods-core/source/aggregate.rb +79 -103
  19. data/lib/cocoapods-core/source/health_reporter.rb +9 -18
  20. data/lib/cocoapods-core/source/manager.rb +488 -0
  21. data/lib/cocoapods-core/source/metadata.rb +79 -0
  22. data/lib/cocoapods-core/source.rb +241 -70
  23. data/lib/cocoapods-core/specification/consumer.rb +187 -47
  24. data/lib/cocoapods-core/specification/dsl/attribute.rb +49 -85
  25. data/lib/cocoapods-core/specification/dsl/attribute_support.rb +6 -8
  26. data/lib/cocoapods-core/specification/dsl/deprecations.rb +9 -126
  27. data/lib/cocoapods-core/specification/dsl/platform_proxy.rb +30 -20
  28. data/lib/cocoapods-core/specification/dsl.rb +943 -296
  29. data/lib/cocoapods-core/specification/json.rb +64 -23
  30. data/lib/cocoapods-core/specification/linter/analyzer.rb +218 -0
  31. data/lib/cocoapods-core/specification/linter/result.rb +128 -0
  32. data/lib/cocoapods-core/specification/linter.rb +310 -309
  33. data/lib/cocoapods-core/specification/root_attribute_accessors.rb +90 -39
  34. data/lib/cocoapods-core/specification/set/presenter.rb +35 -71
  35. data/lib/cocoapods-core/specification/set.rb +42 -96
  36. data/lib/cocoapods-core/specification.rb +368 -130
  37. data/lib/cocoapods-core/standard_error.rb +45 -24
  38. data/lib/cocoapods-core/trunk_source.rb +14 -0
  39. data/lib/cocoapods-core/vendor/requirement.rb +133 -53
  40. data/lib/cocoapods-core/vendor/version.rb +197 -156
  41. data/lib/cocoapods-core/vendor.rb +1 -5
  42. data/lib/cocoapods-core/version.rb +137 -42
  43. data/lib/cocoapods-core/yaml_helper.rb +334 -0
  44. data/lib/cocoapods-core.rb +10 -4
  45. metadata +100 -27
  46. data/lib/cocoapods-core/source/abstract_data_provider.rb +0 -71
  47. data/lib/cocoapods-core/source/file_system_data_provider.rb +0 -150
  48. data/lib/cocoapods-core/source/github_data_provider.rb +0 -143
  49. data/lib/cocoapods-core/specification/set/statistics.rb +0 -266
  50. data/lib/cocoapods-core/yaml_converter.rb +0 -192
@@ -1,5 +1,4 @@
1
1
  module Pod
2
-
3
2
  # The Lockfile stores information about the pods that were installed by
4
3
  # CocoaPods.
5
4
  #
@@ -11,7 +10,6 @@ module Pod
11
10
  # need to be installed or removed.
12
11
  #
13
12
  class Lockfile
14
-
15
13
  # @todo The symbols should be converted to a String and back to symbol
16
14
  # when reading (EXTERNAL SOURCES Download options)
17
15
 
@@ -39,8 +37,7 @@ module Pod
39
37
  #
40
38
  def self.from_file(path)
41
39
  return nil unless path.exist?
42
- require 'yaml'
43
- hash = File.open(path) { |f| YAML.load(f) }
40
+ hash = YAMLHelper.load_file(path)
44
41
  unless hash && hash.is_a?(Hash)
45
42
  raise Informative, "Invalid Lockfile in `#{path}`"
46
43
  end
@@ -53,7 +50,7 @@ module Pod
53
50
  #
54
51
  attr_accessor :defined_in_file
55
52
 
56
- # @return [Bool] Whether the Podfiles are equal.
53
+ # @return [Boolean] Whether the Podfiles are equal.
57
54
  #
58
55
  def ==(other)
59
56
  other && to_hash == other.to_hash
@@ -80,7 +77,7 @@ module Pod
80
77
 
81
78
  # Returns the version of the given Pod.
82
79
  #
83
- # @param [name] The name of the Pod (root name of the specification).
80
+ # @param [String] pod_name The name of the Pod (root name of the specification).
84
81
  #
85
82
  # @return [Version] The version of the pod.
86
83
  #
@@ -95,9 +92,21 @@ module Pod
95
92
  pod_versions[root_name]
96
93
  end
97
94
 
95
+ # Returns the source of the given Pod.
96
+ #
97
+ # @param [String] pod_name The name of the Pod (root name of the specification).
98
+ #
99
+ # @return [String] The source of the pod.
100
+ #
101
+ # @return [Nil] If there is no source stored for the given name.
102
+ #
103
+ def spec_repo(pod_name)
104
+ spec_repos_by_pod[pod_name]
105
+ end
106
+
98
107
  # Returns the checksum for the given Pod.
99
108
  #
100
- # @param [name] The name of the Pod (root name of the specification).
109
+ # @param [String] name The name of the Pod (root name of the specification).
101
110
  #
102
111
  # @return [String] The checksum of the specification for the given Pod.
103
112
  #
@@ -124,6 +133,17 @@ module Pod
124
133
  @dependencies
125
134
  end
126
135
 
136
+ # Returns pod names grouped by the spec repo they were sourced from.
137
+ #
138
+ # @return [Hash<String, Array<String>>] A hash, where the keys are spec
139
+ # repo source URLs (or names), and the values are arrays of pod names.
140
+ #
141
+ # @note It does not include pods that come from "external sources".
142
+ #
143
+ def pods_by_spec_repo
144
+ @pods_by_spec_repo ||= internal_data['SPEC REPOS'] || {}
145
+ end
146
+
127
147
  # Generates a dependency that requires the exact version of the Pod with the
128
148
  # given name.
129
149
  #
@@ -135,20 +155,38 @@ module Pod
135
155
  #
136
156
  # @raise If there is no version stored for the given name.
137
157
  #
138
- # @return [Dependency] the generated dependency.
158
+ # @return [Array<Dependency>] the generated dependency.
139
159
  #
140
- def dependency_to_lock_pod_named(name)
141
- dep = dependencies.find { |d| d.name == name || d.root_name == name }
142
- version = version(name)
160
+ def dependencies_to_lock_pod_named(name)
161
+ deps = dependencies.select { |d| d.root_name == name }
162
+ if deps.empty?
163
+ raise StandardError, "Attempt to lock the `#{name}` Pod without a " \
164
+ 'known dependency.'
165
+ end
143
166
 
144
- unless dep && version
145
- raise StandardError, "Attempt to lock the `#{name}` Pod without an " \
146
- "known dependency."
167
+ deps.map do |dep|
168
+ version = version(dep.name)
169
+ locked_dependency = dep.dup
170
+ locked_dependency.specific_version = version
171
+ locked_dependency
147
172
  end
173
+ end
148
174
 
149
- locked_dependency = dep.dup
150
- locked_dependency.specific_version = version
151
- locked_dependency
175
+ # Returns the specific checkout options for the external source of the pod
176
+ # with the given name.
177
+ #
178
+ # @example Output
179
+ # {:commit => "919903db28535c3f387c4bbaa6a3feae4428e993"
180
+ # :git => "https://github.com/luisdelarosa/AFRaptureXMLRequestOperation.git"}
181
+ #
182
+ # @return [Hash] a hash of the checkout options for the external source of
183
+ # the pod with the given name.
184
+ #
185
+ # @param [String] name
186
+ # the name of the Pod.
187
+ #
188
+ def checkout_options_for_pod_named(name)
189
+ checkout_options_data[name]
152
190
  end
153
191
 
154
192
  # @return [Version] The version of CocoaPods which generated this lockfile.
@@ -184,7 +222,14 @@ module Pod
184
222
  # that required the pod.
185
223
  #
186
224
  def external_sources_data
187
- @external_sources_data ||= internal_data["EXTERNAL SOURCES"] || {}
225
+ @external_sources_data ||= internal_data['EXTERNAL SOURCES'] || {}
226
+ end
227
+
228
+ # @return [Hash{String => Hash}] a hash where the name of the pods are the
229
+ # keys and the values are a hash of specific checkout options.
230
+ #
231
+ def checkout_options_data
232
+ @checkout_options_data ||= internal_data['CHECKOUT OPTIONS'] || {}
188
233
  end
189
234
 
190
235
  # @return [Hash{String => Version}] a Hash containing the name of the root
@@ -203,6 +248,17 @@ module Pod
203
248
  internal_data['SPEC CHECKSUMS'] || {}
204
249
  end
205
250
 
251
+ # @return [Hash{String => String}] A hash containing the spec repo used for the specification
252
+ # by the name of the root spec.
253
+ #
254
+ def spec_repos_by_pod
255
+ @spec_repos_by_pod ||= pods_by_spec_repo.each_with_object({}) do |(spec_repo, pods), spec_repos_by_pod|
256
+ pods.each do |pod|
257
+ spec_repos_by_pod[pod] = spec_repo
258
+ end
259
+ end
260
+ end
261
+
206
262
  #-------------------------------------------------------------------------#
207
263
 
208
264
  # !@group Comparison with a Podfile
@@ -217,7 +273,7 @@ module Pod
217
273
  # - added: Pods that weren't present in the Podfile.
218
274
  # - changed: Pods that were present in the Podfile but changed:
219
275
  # - Pods whose version is not compatible anymore with Podfile,
220
- # - Pods that changed their head or external options.
276
+ # - Pods that changed their external options.
221
277
  # - removed: Pods that were removed form the Podfile.
222
278
  # - unchanged: Pods that are still compatible with Podfile.
223
279
  #
@@ -234,13 +290,23 @@ module Pod
234
290
  result = {}
235
291
  [:added, :changed, :removed, :unchanged].each { |k| result[k] = [] }
236
292
 
237
- installed_deps = dependencies.map do |dep|
238
- dependency_to_lock_pod_named(dep.name)
293
+ installed_deps = {}
294
+ dependencies.each do |dep|
295
+ name = dep.root_name
296
+ installed_deps[name] ||= dependencies_to_lock_pod_named(name)
239
297
  end
240
- all_dep_names = (dependencies + podfile.dependencies).map(&:name).uniq
298
+
299
+ installed_deps = installed_deps.values.flatten(1).group_by(&:name)
300
+
301
+ podfile_dependencies = podfile.dependencies
302
+ podfile_dependencies_by_name = podfile_dependencies.group_by(&:name)
303
+
304
+ all_dep_names = (dependencies + podfile_dependencies).map(&:name).uniq
241
305
  all_dep_names.each do |name|
242
- installed_dep = installed_deps.find { |d| d.name == name }
243
- podfile_dep = podfile.dependencies.find { |d| d.name == name }
306
+ installed_dep = installed_deps[name]
307
+ installed_dep &&= installed_dep.first
308
+ podfile_dep = podfile_dependencies_by_name[name]
309
+ podfile_dep &&= podfile_dep.first
244
310
 
245
311
  if installed_dep.nil? then key = :added
246
312
  elsif podfile_dep.nil? then key = :removed
@@ -267,8 +333,17 @@ module Pod
267
333
  #
268
334
  def write_to_disk(path)
269
335
  path.dirname.mkpath unless path.dirname.exist?
270
- File.open(path, 'w') { |f| f.write(to_yaml) }
271
336
  self.defined_in_file = path
337
+ # rubocop:disable Lint/RescueException
338
+ # rubocop:disable Lint/HandleExceptions
339
+ begin
340
+ existing = Lockfile.from_file(path)
341
+ return if existing == self
342
+ rescue Exception
343
+ end
344
+ path.open('w') { |f| f.write(to_yaml) }
345
+ # rubocop:enable Lint/HandleExceptions
346
+ # rubocop:enable Lint/RescueException
272
347
  end
273
348
 
274
349
  # @return [Hash{String=>Array,Hash,String}] a hash representation of the
@@ -285,6 +360,7 @@ module Pod
285
360
  # 'EXTERNAL SOURCES' => { "JSONKit" => { :podspec => path/JSONKit.podspec } },
286
361
  # 'SPEC CHECKSUMS' => { "BananaLib" => "439d9f683377ecf4a27de43e8cf3bce6be4df97b",
287
362
  # "JSONKit", "92ae5f71b77c8dec0cd8d0744adab79d38560949" },
363
+ # 'PODFILE CHECKSUM' => "439d9f683377ecf4a27de43e8cf3bce6be4df97b",
288
364
  # 'COCOAPODS' => "0.17.0"
289
365
  # }
290
366
  #
@@ -292,11 +368,25 @@ module Pod
292
368
  def to_hash
293
369
  hash = {}
294
370
  internal_data.each do |key, value|
295
- hash[key] = value unless value.empty?
371
+ hash[key] = value unless value.nil? || value.empty?
296
372
  end
297
373
  hash
298
374
  end
299
375
 
376
+ # @return [Array<String>] The order in which the hash keys should appear in
377
+ # a serialized Lockfile.
378
+ #
379
+ HASH_KEY_ORDER = [
380
+ 'PODS',
381
+ 'DEPENDENCIES',
382
+ 'SPEC REPOS',
383
+ 'EXTERNAL SOURCES',
384
+ 'CHECKOUT OPTIONS',
385
+ 'SPEC CHECKSUMS',
386
+ 'PODFILE CHECKSUM',
387
+ 'COCOAPODS',
388
+ ].map(&:freeze).freeze
389
+
300
390
  # @return [String] the YAML representation of the Lockfile, used for
301
391
  # serialization.
302
392
  #
@@ -305,20 +395,12 @@ module Pod
305
395
  # @note The YAML string is prettified.
306
396
  #
307
397
  def to_yaml
308
- keys_hint = [
309
- "PODS",
310
- "DEPENDENCIES",
311
- "EXTERNAL SOURCES",
312
- "SPEC CHECKSUMS",
313
- "COCOAPODS",
314
- ]
315
- YAMLConverter.convert_hash(to_hash, keys_hint, "\n\n")
398
+ YAMLHelper.convert_hash(to_hash, HASH_KEY_ORDER, "\n\n")
316
399
  end
317
400
 
318
401
  #-------------------------------------------------------------------------#
319
402
 
320
403
  class << self
321
-
322
404
  # !@group Generation
323
405
 
324
406
  public
@@ -336,12 +418,15 @@ module Pod
336
418
  #
337
419
  # @return [Lockfile] a new lockfile.
338
420
  #
339
- def generate(podfile, specs)
421
+ def generate(podfile, specs, checkout_options, spec_repos = {})
340
422
  hash = {
341
423
  'PODS' => generate_pods_data(specs),
342
424
  'DEPENDENCIES' => generate_dependencies_data(podfile),
425
+ 'SPEC REPOS' => generate_spec_repos(spec_repos),
343
426
  'EXTERNAL SOURCES' => generate_external_sources_data(podfile),
427
+ 'CHECKOUT OPTIONS' => checkout_options,
344
428
  'SPEC CHECKSUMS' => generate_checksums(specs),
429
+ 'PODFILE CHECKSUM' => podfile.checksum,
345
430
  'COCOAPODS' => CORE_VERSION,
346
431
  }
347
432
  Lockfile.new(hash)
@@ -369,22 +454,17 @@ module Pod
369
454
  #
370
455
  #
371
456
  def generate_pods_data(specs)
372
- pod_and_deps = specs.map do |spec|
373
- [spec.to_s, spec.all_dependencies.map(&:to_s).sort]
374
- end.uniq
375
-
376
- tmp = {}
377
- pod_and_deps.each do |name, deps|
378
- if tmp[name]
379
- tmp[name].concat(deps).uniq!
380
- else
381
- tmp[name] = deps
382
- end
457
+ pods_and_deps_merged = specs.reduce({}) do |result, spec|
458
+ name = spec.to_s
459
+ result[name] ||= []
460
+ result[name].concat(spec.all_dependencies.map(&:to_s))
461
+ result
383
462
  end
384
- pod_and_deps = tmp.sort_by(&:first).map do |name, deps|
385
- deps.empty? ? name : { name => deps }
463
+
464
+ pod_and_deps = pods_and_deps_merged.map do |name, deps|
465
+ deps.empty? ? name : { name => YAMLHelper.sorted_array(deps.uniq) }
386
466
  end
387
- pod_and_deps
467
+ YAMLHelper.sorted_array(pod_and_deps)
388
468
  end
389
469
 
390
470
  # Generates the list of the dependencies of the Podfile.
@@ -396,7 +476,36 @@ module Pod
396
476
  # @return [Array] the generated data.
397
477
  #
398
478
  def generate_dependencies_data(podfile)
399
- podfile.dependencies.map { |d| d.to_s }.sort
479
+ YAMLHelper.sorted_array(podfile.dependencies.map(&:to_s))
480
+ end
481
+
482
+ # Generates the hash of spec repo sources used in the Podfile.
483
+ #
484
+ # @example Output
485
+ # { "https://github.com/cocoapods/cocoapods.git" => ["Alamofire", "Moya"] }
486
+ #
487
+ def generate_spec_repos(spec_repos)
488
+ output = Hash.new {|h, k| h[k] = Array.new(0)}
489
+ spec_repos.each do |source, specs|
490
+ next unless source
491
+ next if specs.empty?
492
+ key = source.url || source.name
493
+
494
+ # save `trunk` as 'trunk' so that the URL itself can be changed without lockfile churn
495
+ key = Pod::TrunkSource::TRUNK_REPO_NAME if source.name == Pod::TrunkSource::TRUNK_REPO_NAME
496
+
497
+ value = specs.map { |s| s.root.name }
498
+
499
+ if output.has_key?(key)
500
+ value = value + output[key]
501
+ end
502
+
503
+ if value.length > 0
504
+ output[key] = YAMLHelper.sorted_array(value.uniq)
505
+ end
506
+ end
507
+
508
+ output.compact
400
509
  end
401
510
 
402
511
  # Generates the information of the external sources.
@@ -408,10 +517,6 @@ module Pod
408
517
  # the values store the external source hashes of each
409
518
  # dependency.
410
519
  #
411
- # @todo The downloader should generate an external source hash that
412
- # should be store for dependencies in head mode and for those
413
- # with external source.
414
- #
415
520
  def generate_external_sources_data(podfile)
416
521
  deps = podfile.dependencies.select(&:external?)
417
522
  deps = deps.sort { |d, other| d.name <=> other.name }
@@ -434,7 +539,7 @@ module Pod
434
539
  #
435
540
  def generate_checksums(specs)
436
541
  checksums = {}
437
- specs.select { |spec| !spec.defined_in_file.nil? }.each do |spec|
542
+ specs.select(&:defined_in_file).each do |spec|
438
543
  checksums[spec.root.name] = spec.checksum
439
544
  end
440
545
  checksums
@@ -0,0 +1,47 @@
1
+ module Pod
2
+ # Allows to access metrics about pods.
3
+ #
4
+ # This class is stored in Core because it might be used by web services.
5
+ #
6
+ module Metrics
7
+ # Returns the metrics of a pod.
8
+ #
9
+ # @param [String] name
10
+ # The name of the pod.
11
+ #
12
+ # @return [Hash] The metrics for the pod.
13
+ #
14
+ def self.pod(name)
15
+ peform_request("http://metrics.cocoapods.org/api/v1/pods/#{name}")
16
+ end
17
+
18
+ private
19
+
20
+ # @!group Private helpers
21
+ #-------------------------------------------------------------------------#
22
+
23
+ # Performs a get request with the given URL.
24
+ #
25
+ # @param [String] url
26
+ # The URL of the resource.
27
+ #
28
+ # @return [Array, Hash] The information of the resource as Ruby objects.
29
+ #
30
+ def self.peform_request(url)
31
+ require 'rest'
32
+ require 'json'
33
+ headers = { 'User-Agent' => "CocoaPods #{Pod::CORE_VERSION}" }
34
+ response = REST.get(url, headers)
35
+ body = JSON.parse(response.body)
36
+ if response.ok?
37
+ body
38
+ else
39
+ CoreUI.warn "Request to #{url} failed - #{response.status_code}"
40
+ CoreUI.warn body['message']
41
+ nil
42
+ end
43
+ end
44
+
45
+ #-------------------------------------------------------------------------#
46
+ end
47
+ end
@@ -1,14 +1,11 @@
1
1
  module Pod
2
-
3
2
  # A Platform describes an SDK name and deployment target.
4
3
  #
5
4
  class Platform
6
-
7
5
  # @return [Symbol, String] the name of the SDK represented by the platform.
8
6
  #
9
- def name
10
- @symbolic_name
11
- end
7
+ attr_reader :symbolic_name
8
+ alias_method :name, :symbolic_name
12
9
 
13
10
  # @return [Version] the deployment target of the platform.
14
11
  #
@@ -48,7 +45,19 @@ module Pod
48
45
  @symbolic_name = input.name
49
46
  @deployment_target = input.deployment_target
50
47
  else
51
- @symbolic_name = input.to_sym
48
+ input = input.to_s.downcase
49
+
50
+ name = case input
51
+ when 'macos'
52
+ # Allow `Platform.new('macos')` to be equivalent to `Platform.macos`
53
+ 'osx'
54
+ when 'xros'
55
+ # Compatibility with older references to 'xrOS'
56
+ 'visionos'
57
+ else
58
+ input
59
+ end
60
+ @symbolic_name = name.to_sym
52
61
  target = target[:deployment_target] if target.is_a?(Hash)
53
62
  @deployment_target = Version.create(target)
54
63
  end
@@ -70,6 +79,46 @@ module Pod
70
79
  new :osx
71
80
  end
72
81
 
82
+ # Convenience method to initialize a macOS platform.
83
+ #
84
+ # @return [Platform] a macOS platform.
85
+ #
86
+ def self.macos
87
+ osx
88
+ end
89
+
90
+ # Convenience method to initialize a tvOS platform.
91
+ #
92
+ # @return [Platform] a tvOS platform.
93
+ #
94
+ def self.tvos
95
+ new :tvos
96
+ end
97
+
98
+ # Convenience method to initialize a visionOS platform.
99
+ #
100
+ # @return [Platform] a visionOS platform.
101
+ #
102
+ def self.visionos
103
+ new :visionos
104
+ end
105
+
106
+ # Convenience method to initialize a watchOS platform.
107
+ #
108
+ # @return [Platform] a watchOS platform.
109
+ #
110
+ def self.watchos
111
+ new :watchos
112
+ end
113
+
114
+ # Convenience method to get all available platforms.
115
+ #
116
+ # @return [Array<Platform>] list of platforms.
117
+ #
118
+ def self.all
119
+ [ios, osx, watchos, visionos, tvos]
120
+ end
121
+
73
122
  # Checks if a platform is equivalent to another one or to a symbol
74
123
  # representation.
75
124
  #
@@ -89,13 +138,25 @@ module Pod
89
138
  end
90
139
  end
91
140
 
141
+ # (see #==)
142
+ alias_method :eql?, :==
143
+
144
+ # Hashes the instance by the platform name and deployment target.
145
+ #
146
+ # This adds support to make instances usable as Hash keys.
147
+ #
148
+ # @!visibility private
149
+ def hash
150
+ name.hash ^ deployment_target.hash
151
+ end
152
+
92
153
  # Checks whether a platform supports another one.
93
154
  #
94
155
  # In the context of operating system SDKs, a platform supports another
95
156
  # one if they have the same name and the other platform has a minor or
96
157
  # equal deployment target.
97
158
  #
98
- # @return [Bool] whether the platform supports another platform.
159
+ # @return [Boolean] whether the platform supports another platform.
99
160
  #
100
161
  def supports?(other)
101
162
  other = Platform.new(other)
@@ -146,17 +207,40 @@ module Pod
146
207
  end
147
208
  end
148
209
 
149
- # @return [Bool] whether the platform requires legacy architectures for
210
+ # @return [Boolean] whether the platform requires legacy architectures for
150
211
  # iOS.
151
212
  #
152
213
  def requires_legacy_ios_archs?
153
214
  if name == :ios
154
- deployment_target && (deployment_target < Version.new("4.3"))
215
+ deployment_target && (deployment_target < Version.new('4.3'))
155
216
  else
156
217
  false
157
218
  end
158
219
  end
159
220
 
221
+ # @return [Boolean] whether the platform supports dynamic frameworks.
222
+ #
223
+ def supports_dynamic_frameworks?
224
+ if name == :ios
225
+ deployment_target && (deployment_target >= Version.new(8.0))
226
+ else
227
+ true
228
+ end
229
+ end
230
+
231
+ # @return [String] The string that describes the #symbolic_name.
232
+ #
233
+ def string_name
234
+ self.class.string_name(symbolic_name)
235
+ end
236
+
237
+ # @return [String] The string that describes the #symbolic_name,
238
+ # which doesn't contain spaces and is so safe to use in
239
+ # paths which might not be quoted or escaped consequently.
240
+ def safe_string_name
241
+ string_name.tr(' ', '')
242
+ end
243
+
160
244
  # Converts the symbolic name of a platform to a string name suitable to be
161
245
  # presented to the user.
162
246
  #
@@ -168,8 +252,12 @@ module Pod
168
252
  def self.string_name(symbolic_name)
169
253
  case symbolic_name
170
254
  when :ios then 'iOS'
171
- when :osx then 'OS X'
172
- else symbolic_name.to_s end
255
+ when :osx then 'macOS'
256
+ when :watchos then 'watchOS'
257
+ when :tvos then 'tvOS'
258
+ when :visionos then 'visionOS'
259
+ else symbolic_name.to_s
260
+ end
173
261
  end
174
262
  end
175
263
  end