cocoapods 0.16.4 → 0.17.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +108 -0
  3. data/README.md +3 -3
  4. data/bin/pod +1 -1
  5. data/lib/cocoapods.rb +31 -31
  6. data/lib/cocoapods/command.rb +62 -107
  7. data/lib/cocoapods/command/inter_process_communication.rb +103 -0
  8. data/lib/cocoapods/command/list.rb +45 -44
  9. data/lib/cocoapods/command/outdated.rb +28 -25
  10. data/lib/cocoapods/command/project.rb +90 -0
  11. data/lib/cocoapods/command/push.rb +50 -32
  12. data/lib/cocoapods/command/repo.rb +125 -155
  13. data/lib/cocoapods/command/search.rb +23 -12
  14. data/lib/cocoapods/command/setup.rb +103 -64
  15. data/lib/cocoapods/command/spec.rb +329 -90
  16. data/lib/cocoapods/config.rb +197 -44
  17. data/lib/cocoapods/downloader.rb +47 -34
  18. data/lib/cocoapods/executable.rb +98 -41
  19. data/lib/cocoapods/external_sources.rb +325 -0
  20. data/lib/cocoapods/file_list.rb +8 -1
  21. data/lib/cocoapods/gem_version.rb +7 -0
  22. data/lib/cocoapods/generator/acknowledgements.rb +71 -7
  23. data/lib/cocoapods/generator/acknowledgements/markdown.rb +10 -9
  24. data/lib/cocoapods/generator/acknowledgements/plist.rb +9 -8
  25. data/lib/cocoapods/generator/copy_resources_script.rb +2 -2
  26. data/lib/cocoapods/generator/documentation.rb +153 -37
  27. data/lib/cocoapods/generator/prefix_header.rb +82 -0
  28. data/lib/cocoapods/generator/target_header.rb +58 -0
  29. data/lib/cocoapods/generator/xcconfig.rb +130 -0
  30. data/lib/cocoapods/hooks/installer_representation.rb +123 -0
  31. data/lib/cocoapods/hooks/library_representation.rb +79 -0
  32. data/lib/cocoapods/hooks/pod_representation.rb +74 -0
  33. data/lib/cocoapods/installer.rb +398 -147
  34. data/lib/cocoapods/installer/analyzer.rb +556 -0
  35. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +253 -0
  36. data/lib/cocoapods/installer/file_references_installer.rb +179 -0
  37. data/lib/cocoapods/installer/pod_source_installer.rb +289 -0
  38. data/lib/cocoapods/installer/target_installer.rb +307 -112
  39. data/lib/cocoapods/installer/user_project_integrator.rb +140 -176
  40. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +193 -0
  41. data/lib/cocoapods/library.rb +195 -0
  42. data/lib/cocoapods/open_uri.rb +16 -14
  43. data/lib/cocoapods/project.rb +175 -52
  44. data/lib/cocoapods/resolver.rb +151 -164
  45. data/lib/cocoapods/sandbox.rb +276 -54
  46. data/lib/cocoapods/sandbox/file_accessor.rb +210 -0
  47. data/lib/cocoapods/sandbox/headers_store.rb +96 -0
  48. data/lib/cocoapods/sandbox/path_list.rb +178 -0
  49. data/lib/cocoapods/sources_manager.rb +218 -0
  50. data/lib/cocoapods/user_interface.rb +82 -18
  51. data/lib/cocoapods/{command → user_interface}/error_report.rb +5 -5
  52. data/lib/cocoapods/validator.rb +379 -0
  53. metadata +74 -55
  54. data/lib/cocoapods/command/install.rb +0 -55
  55. data/lib/cocoapods/command/linter.rb +0 -317
  56. data/lib/cocoapods/command/update.rb +0 -25
  57. data/lib/cocoapods/dependency.rb +0 -285
  58. data/lib/cocoapods/downloader/git.rb +0 -276
  59. data/lib/cocoapods/downloader/http.rb +0 -99
  60. data/lib/cocoapods/downloader/mercurial.rb +0 -26
  61. data/lib/cocoapods/downloader/subversion.rb +0 -42
  62. data/lib/cocoapods/local_pod.rb +0 -620
  63. data/lib/cocoapods/lockfile.rb +0 -274
  64. data/lib/cocoapods/platform.rb +0 -127
  65. data/lib/cocoapods/podfile.rb +0 -551
  66. data/lib/cocoapods/source.rb +0 -223
  67. data/lib/cocoapods/specification.rb +0 -579
  68. data/lib/cocoapods/specification/set.rb +0 -175
  69. data/lib/cocoapods/specification/statistics.rb +0 -112
  70. data/lib/cocoapods/user_interface/ui_pod.rb +0 -130
  71. data/lib/cocoapods/version.rb +0 -26
@@ -0,0 +1,556 @@
1
+ module Pod
2
+ class Installer
3
+
4
+ # Analyzes the Podfile, the Lockfile, and the sandbox manifest to generate
5
+ # the information relative to a CocoaPods installation.
6
+ #
7
+ class Analyzer
8
+
9
+ include Config::Mixin
10
+
11
+ autoload :SandboxAnalyzer, 'cocoapods/installer/analyzer/sandbox_analyzer'
12
+
13
+ # @return [Sandbox] The sandbox where the Pods should be installed.
14
+ #
15
+ attr_reader :sandbox
16
+
17
+ # @return [Podfile] The Podfile specification that contains the
18
+ # information of the Pods that should be installed.
19
+ #
20
+ attr_reader :podfile
21
+
22
+ # @return [Lockfile] The Lockfile that stores the information about the
23
+ # Pods previously installed on any machine.
24
+ #
25
+ attr_reader :lockfile
26
+
27
+ # @param [Sandbox] sandbox @see sandbox
28
+ # @param [Podfile] podfile @see podfile
29
+ # @param [Lockfile] lockfile @see lockfile
30
+ #
31
+ def initialize(sandbox, podfile, lockfile = nil)
32
+ @sandbox = sandbox
33
+ @podfile = podfile
34
+ @lockfile = lockfile
35
+
36
+ @update_mode = false
37
+ @allow_pre_downloads = true
38
+ end
39
+
40
+ # Performs the analysis.
41
+ #
42
+ # The Podfile and the Lockfile provide the information necessary to
43
+ # compute which specification should be installed. The manifest of the
44
+ # sandbox returns which specifications are installed.
45
+ #
46
+ # @return [AnalysisResult]
47
+ #
48
+ def analyze
49
+ update_repositories_if_needed
50
+ @result = AnalysisResult.new
51
+ @result.podfile_state = generate_podfile_state
52
+ @locked_dependencies = generate_version_locking_dependencies
53
+
54
+ @result.libraries = generated_libraries
55
+ fetch_external_sources
56
+ @result.specs_by_target = resolve_dependencies
57
+ @result.specifications = generate_specifications
58
+ @result.sandbox_state = generate_sandbox_state
59
+ @result
60
+ end
61
+
62
+ attr_accessor :result
63
+
64
+ # @return [Bool] Whether an installation should be performed or this
65
+ # CocoaPods project is already up to date.
66
+ #
67
+ def needs_install?
68
+ podfile_needs_install? || sandbox_needs_install?
69
+ end
70
+
71
+ # @return [Bool] Whether the podfile has changes respect to the lockfile.
72
+ #
73
+ def podfile_needs_install?
74
+ state = generate_podfile_state
75
+ needing_install = state.added + state.changed + state.deleted
76
+ !needing_install.empty?
77
+ end
78
+
79
+ # @return [Bool] Whether the sandbox is in synch with the lockfile.
80
+ #
81
+ def sandbox_needs_install?
82
+ lockfile != sandbox.manifest
83
+ end
84
+
85
+ #-----------------------------------------------------------------------#
86
+
87
+ # @!group Configuration
88
+
89
+ # @return [Bool] Whether the version of the dependencies which did non
90
+ # change in the Podfile should be locked.
91
+ #
92
+ attr_accessor :update_mode
93
+ alias_method :update_mode?, :update_mode
94
+
95
+ # @return [Bool] Whether the analysis allows pre-downloads and thus
96
+ # modifications to the sandbox.
97
+ #
98
+ # @note This flag should not be used in installations.
99
+ #
100
+ # @note This is used by the `pod outdated` command to prevent
101
+ # modification of the sandbox in the resolution process.
102
+ #
103
+ attr_accessor :allow_pre_downloads
104
+ alias_method :allow_pre_downloads?, :allow_pre_downloads
105
+
106
+ #-----------------------------------------------------------------------#
107
+
108
+ private
109
+
110
+ # @!group Analysis steps
111
+
112
+ # Compares the {Podfile} with the {Lockfile} in order to detect which
113
+ # dependencies should be locked.
114
+ #
115
+ # @return [SpecsState] the states of the Podfile specs.
116
+ #
117
+ # @note As the target definitions share the same sandbox they should have
118
+ # the same version of a Pod. For this reason this method returns
119
+ # the name of the Pod (root name of the dependencies) and doesn't
120
+ # group them by target definition.
121
+ #
122
+ # @todo [CocoaPods > 0.18] If there isn't a Lockfile all the Pods should
123
+ # be marked as added.
124
+ #
125
+ def generate_podfile_state
126
+ if lockfile
127
+ pods_state = nil
128
+ UI.section "Finding Podfile changes" do
129
+ pods_by_state = lockfile.detect_changes_with_podfile(podfile)
130
+ pods_by_state.dup.each do |state, full_names|
131
+ pods_by_state[state] = full_names.map { |fn| Specification.root_name(fn) }
132
+ end
133
+ pods_state = SpecsState.new(pods_by_state)
134
+ pods_state.print
135
+ end
136
+ pods_state
137
+ else
138
+ state = SpecsState.new
139
+ state.added.concat(podfile.dependencies.map(&:root_name).uniq)
140
+ state
141
+ end
142
+ end
143
+
144
+ # Updates the source repositories unless the config indicates to skip it.
145
+ #
146
+ # @return [void]
147
+ #
148
+ def update_repositories_if_needed
149
+ unless config.skip_repo_update?
150
+ UI.section 'Updating spec repositories' do
151
+ SourcesManager.update
152
+ end
153
+ end
154
+ end
155
+
156
+ # Creates the models that represent the libraries generated by CocoaPods.
157
+ #
158
+ # @note The libraries are generated before the resolution process
159
+ # because it might be necessary to infer the platform from the
160
+ # user targets, which in turns requires to identify the user
161
+ # project.
162
+ #
163
+ # @note The specification of the libraries are added in the
164
+ # {#resolve_dependencies} step.
165
+ #
166
+ # @return [Array<Libraries>] the generated libraries.
167
+ #
168
+ def generated_libraries
169
+ libraries = []
170
+ podfile.target_definitions.values.each do |target_definition|
171
+ lib = Library.new(target_definition)
172
+ lib.support_files_root = sandbox.library_support_files_dir(lib.name)
173
+
174
+ if config.integrate_targets?
175
+ project_path = compute_user_project_path(target_definition)
176
+ user_project = Xcodeproj::Project.new(project_path)
177
+ targets = compute_user_project_targets(target_definition, user_project)
178
+
179
+ lib.user_project_path = project_path
180
+ lib.user_target_uuids = targets.map(&:uuid)
181
+ lib.user_build_configurations = compute_user_build_configurations(target_definition, targets)
182
+ lib.platform = compute_platform_for_target_definition(target_definition, targets)
183
+ else
184
+ unless target_definition.platform
185
+ raise Informative, "It is necessary to specify the platform in the Podfile if not integrating."
186
+ end
187
+ lib.user_project_path = config.installation_root
188
+ lib.user_target_uuids = []
189
+ lib.user_build_configurations = {}
190
+ lib.platform = target_definition.platform
191
+ end
192
+ libraries << lib
193
+ end
194
+ libraries
195
+ end
196
+
197
+ # Generates dependencies that require the specific version of the Pods
198
+ # that haven't changed in the {Lockfile}.
199
+ #
200
+ # These dependencies are passed to the {Resolver}, unless the installer
201
+ # is in update mode, to prevent it from upgrading the Pods that weren't
202
+ # changed in the {Podfile}.
203
+ #
204
+ # @return [Array<Dependency>] the dependencies generate by the lockfile
205
+ # that prevent the resolver to update a Pod.
206
+ #
207
+ def generate_version_locking_dependencies
208
+ if update_mode?
209
+ []
210
+ else
211
+ result.podfile_state.unchanged.map do |pod|
212
+ lockfile.dependency_to_lock_pod_named(pod)
213
+ end
214
+ end
215
+ end
216
+
217
+ # Fetches the podspecs of external sources if modifications to the
218
+ # sandbox are allowed.
219
+ #
220
+ # @note In update mode all the external sources are refreshed while in
221
+ # normal mode they are refreshed only if added or changed in the
222
+ # Podfile. Moreover, in normal specifications for unchanged Pods
223
+ # which are missing or are generated from an local source are
224
+ # fetched as well.
225
+ #
226
+ # @note It is possible to perform this step before the resolution
227
+ # process because external sources identify a single specific
228
+ # version (checkout). If the other dependencies are not
229
+ # compatible with the version reported by the podspec of the
230
+ # external source the resolver will raise.
231
+ #
232
+ # @return [void]
233
+ #
234
+ # TODO Specs
235
+ #
236
+ def fetch_external_sources
237
+ return unless allow_pre_downloads?
238
+ deps_to_fetch = []
239
+ deps_to_fetch_if_needed = []
240
+ deps_with_external_source = podfile.dependencies.select { |dep| dep.external_source }
241
+ if update_mode?
242
+ deps_to_fetch = deps_with_external_source
243
+ else
244
+ pods_to_fetch = result.podfile_state.added + result.podfile_state.changed
245
+ deps_to_fetch = deps_with_external_source.select { |dep| pods_to_fetch.include?(dep.root_name) }
246
+ deps_to_fetch_if_needed = deps_with_external_source.select { |dep| result.podfile_state.unchanged.include?(dep.root_name) }
247
+ deps_to_fetch += deps_to_fetch_if_needed.select { |dep| sandbox.specification(dep.root_name).nil? || !dep.external_source[:local].nil? }
248
+ end
249
+
250
+ unless deps_to_fetch.empty?
251
+ UI.section "Fetching external sources" do
252
+ deps_to_fetch.uniq.sort.each do |dependency|
253
+ source = ExternalSources.from_dependency(dependency, podfile.defined_in_file)
254
+ source.fetch(sandbox)
255
+ end
256
+ end
257
+ end
258
+ end
259
+
260
+ # Converts the Podfile in a list of specifications grouped by target.
261
+ #
262
+ # @note In this step the specs are added to the libraries.
263
+ #
264
+ # @note As some dependencies might have external sources the resolver
265
+ # is aware of the {Sandbox} and interacts with it to download the
266
+ # podspecs of the external sources. This is necessary because the
267
+ # resolver needs their specifications to analyze their
268
+ # dependencies.
269
+ #
270
+ # @note The specifications of the external sources which are added,
271
+ # modified or removed need to deleted from the sandbox before the
272
+ # resolution process. Otherwise the resolver might use an
273
+ # incorrect specification instead of pre-downloading it.
274
+ #
275
+ # @note In update mode the resolver is set to always update the specs
276
+ # from external sources.
277
+ #
278
+ # @return [Hash{TargetDefinition => Array<Spec>}] the specifications
279
+ # grouped by target.
280
+ #
281
+ def resolve_dependencies
282
+ specs_by_target = nil
283
+
284
+ UI.section "Resolving dependencies of #{UI.path podfile.defined_in_file}" do
285
+ resolver = Resolver.new(sandbox, podfile, locked_dependencies)
286
+ specs_by_target = resolver.resolve
287
+ end
288
+
289
+ specs_by_target.each do |target_definition, specs|
290
+ lib = result.libraries.find { |l| l.target_definition == target_definition}
291
+ lib.specs = specs
292
+ end
293
+
294
+ specs_by_target
295
+ end
296
+
297
+ # Returns the list of all the resolved the resolved specifications.
298
+ #
299
+ # @return [Array<Specification>] the list of the specifications.
300
+ #
301
+ def generate_specifications
302
+ result.specs_by_target.values.flatten.uniq
303
+ end
304
+
305
+ # Computes the state of the sandbox respect to the resolved
306
+ # specifications.
307
+ #
308
+ # @return [SpecsState] the representation of the state of the manifest
309
+ # specifications.
310
+ #
311
+ def generate_sandbox_state
312
+ sandbox_state = nil
313
+ UI.section "Comparing resolved specification to the sandbox manifest" do
314
+ sandbox_analyzer = SandboxAnalyzer.new(sandbox, result.specifications, update_mode, lockfile)
315
+ sandbox_state = sandbox_analyzer.analyze
316
+ sandbox_state.print
317
+ end
318
+ sandbox_state
319
+ end
320
+
321
+ #-----------------------------------------------------------------------#
322
+
323
+ # @!group Analysis internal products
324
+
325
+ # @return [Array<Dependency>] the dependencies generate by the lockfile
326
+ # that prevent the resolver to update a Pod.
327
+ #
328
+ attr_reader :locked_dependencies
329
+
330
+ #-----------------------------------------------------------------------#
331
+
332
+ private
333
+
334
+ # @!group Analysis sub-steps
335
+
336
+ # Returns the path of the user project that the {TargetDefinition}
337
+ # should integrate.
338
+ #
339
+ # @raise If the project is implicit and there are multiple projects.
340
+ #
341
+ # @raise If the path doesn't exits.
342
+ #
343
+ # @return [Pathname] the path of the user project.
344
+ #
345
+ def compute_user_project_path(target_definition)
346
+ if target_definition.user_project_path
347
+ path = config.installation_root + target_definition.user_project_path
348
+ path = "#{path}.xcodeproj" unless File.extname(path) == '.xcodeproj'
349
+ path = Pathname.new(path)
350
+ unless path.exist?
351
+ raise Informative, "Unable to find the Xcode project " \
352
+ "`#{path}` for the target `#{target_definition.label}`."
353
+ end
354
+
355
+ else
356
+ xcodeprojs = Pathname.glob(config.installation_root + '*.xcodeproj')
357
+ if xcodeprojs.size == 1
358
+ path = xcodeprojs.first
359
+ else
360
+ raise Informative, "Could not automatically select an Xcode project. " \
361
+ "Specify one in your Podfile like so:\n\n" \
362
+ " xcodeproj 'path/to/Project.xcodeproj'\n"
363
+ end
364
+ end
365
+ path
366
+ end
367
+
368
+ # Returns a list of the targets from the project of {TargetDefinition}
369
+ # that needs to be integrated.
370
+ #
371
+ # @note The method first looks if there is a target specified with
372
+ # the `link_with` option of the {TargetDefinition}. Otherwise
373
+ # it looks for the target that has the same name of the target
374
+ # definition. Finally if no target was found the first
375
+ # encountered target is returned (it is assumed to be the one
376
+ # to integrate in simple projects).
377
+ #
378
+ # @note This will only return targets that do **not** already have
379
+ # the Pods library in their frameworks build phase.
380
+ #
381
+ #
382
+ def compute_user_project_targets(target_definition, user_project)
383
+ if link_with = target_definition.link_with
384
+ targets = native_targets(user_project).select { |t| link_with.include?(t.name) }
385
+ raise Informative, "Unable to find the targets named `#{link_with.to_sentence}` to link with target definition `#{target_definition.name}`" if targets.empty?
386
+ elsif target_definition.name == :default
387
+ targets = [ native_targets(user_project).first ].compact
388
+ raise Informative, "Unable to find a target" if targets.empty?
389
+ else
390
+ target = native_targets(user_project).find { |t| t.name == target_definition.name.to_s }
391
+ targets = [ target ].compact
392
+ raise Informative, "Unable to find a target named `#{target_definition.name.to_s}`" if targets.empty?
393
+ end
394
+ targets
395
+ end
396
+
397
+ # @return [Array<PBXNativeTarget>] Returns the user’s targets, excluding
398
+ # aggregate targets.
399
+ #
400
+ def native_targets(user_project)
401
+ user_project.targets.reject do |target|
402
+ target.is_a? Xcodeproj::Project::Object::PBXAggregateTarget
403
+ end
404
+ end
405
+
406
+ # @return [Hash{String=>Symbol}] A hash representing the user build
407
+ # configurations where each key corresponds to the name of a
408
+ # configuration and its value to its type (`:debug` or `:release`).
409
+ #
410
+ def compute_user_build_configurations(target_definition, user_targets)
411
+ if user_targets
412
+ user_targets.map { |t| t.build_configurations.map(&:name) }.flatten.inject({}) do |hash, name|
413
+ unless name == 'Debug' || name == 'Release'
414
+ hash[name] = :release
415
+ end
416
+ hash
417
+ end.merge(target_definition.build_configurations || {})
418
+ else
419
+ target_definition.build_configurations || {}
420
+ end
421
+ end
422
+
423
+ # @return [Platform] The platform for the library.
424
+ #
425
+ # @note This resolves to the lowest deployment target across the user
426
+ # targets.
427
+ #
428
+ # @todo Is assigning the platform to the target definition the best way
429
+ # to go?
430
+ #
431
+ def compute_platform_for_target_definition(target_definition, user_targets)
432
+ return target_definition.platform if target_definition.platform
433
+ name = nil
434
+ deployment_target = nil
435
+
436
+ user_targets.each do |target|
437
+ name ||= target.platform_name
438
+ raise Informative, "Targets with different platforms" unless name == target.platform_name
439
+ if !deployment_target || deployment_target > Version.new(target.deployment_target)
440
+ deployment_target = Version.new(target.deployment_target)
441
+ end
442
+ end
443
+
444
+ target_definition.set_platform(name, deployment_target)
445
+ platform = Platform.new(name, deployment_target)
446
+ platform
447
+ end
448
+
449
+ #-----------------------------------------------------------------------#
450
+
451
+ class AnalysisResult
452
+
453
+ # @return [SpecsState] the states of the Podfile specs.
454
+ #
455
+ attr_accessor :podfile_state
456
+
457
+ # @return [Hash{TargetDefinition => Array<Spec>}] the specifications
458
+ # grouped by target.
459
+ #
460
+ attr_accessor :specs_by_target
461
+
462
+ # @return [Array<Specification>] the specifications of the resolved
463
+ # version of Pods that should be installed.
464
+ #
465
+ attr_accessor :specifications
466
+
467
+ # @return [SpecsState] the states of the {Sandbox} respect the resolved
468
+ # specifications.
469
+ #
470
+ attr_accessor :sandbox_state
471
+
472
+ # @return [Array<Library>] the libraries generated by the target
473
+ # definitions.
474
+ #
475
+ attr_accessor :libraries
476
+
477
+ end
478
+
479
+ #-----------------------------------------------------------------------#
480
+
481
+ # This class represents the state of a collection of Pods.
482
+ #
483
+ # @note The names of the pods stored by this class are always the **root**
484
+ # name of the specification.
485
+ #
486
+ # @note The motivation for this class is to ensure that the names of the
487
+ # subspecs are added instead of the name of the Pods.
488
+ #
489
+ class SpecsState
490
+
491
+ # @param [Hash{Symbol=>String}] pods_by_state
492
+ # The **root** name of the pods grouped by their state
493
+ # (`:added`, `:removed`, `:changed` or `:unchanged`).
494
+ #
495
+ def initialize(pods_by_state = nil)
496
+ @added = []
497
+ @deleted = []
498
+ @changed = []
499
+ @unchanged = []
500
+
501
+ if pods_by_state
502
+ @added = pods_by_state[:added] || []
503
+ @deleted = pods_by_state[:removed] || []
504
+ @changed = pods_by_state[:changed] || []
505
+ @unchanged = pods_by_state[:unchanged] || []
506
+ end
507
+ end
508
+
509
+ # @return [Array<String>] the names of the pods that were added.
510
+ #
511
+ attr_accessor :added
512
+
513
+ # @return [Array<String>] the names of the pods that were changed.
514
+ #
515
+ attr_accessor :changed
516
+
517
+ # @return [Array<String>] the names of the pods that were deleted.
518
+ #
519
+ attr_accessor :deleted
520
+
521
+ # @return [Array<String>] the names of the pods that were unchanged.
522
+ #
523
+ attr_accessor :unchanged
524
+
525
+ # Displays the state of each pod.
526
+ #
527
+ # @return [void]
528
+ #
529
+ def print
530
+ added .sort.each { |pod| UI.message("A".green + " #{pod}", '', 2) }
531
+ deleted .sort.each { |pod| UI.message("R".red + " #{pod}", '', 2) }
532
+ changed .sort.each { |pod| UI.message("M".yellow + " #{pod}", '', 2) }
533
+ unchanged.sort.each { |pod| UI.message("-" + " #{pod}", '', 2) }
534
+ end
535
+
536
+ # Adds the name of a Pod to the give state.
537
+ #
538
+ # @param [String]
539
+ # the name of the Pod.
540
+ #
541
+ # @param [Symbol]
542
+ # the state of the Pod.
543
+ #
544
+ # @raise If there is an attempt to add the name of a subspec.
545
+ #
546
+ # @return [void]
547
+ #
548
+ def add_name(name, state)
549
+ raise "[Bug] Attempt to add subspec to the pods state" if name.include?('/')
550
+ self.send(state) << name
551
+ end
552
+
553
+ end
554
+ end
555
+ end
556
+ end