cocoapods 1.4.0 → 1.5.0.beta.1

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +149 -0
  3. data/lib/cocoapods.rb +1 -0
  4. data/lib/cocoapods/command/outdated.rb +2 -2
  5. data/lib/cocoapods/command/repo/push.rb +5 -0
  6. data/lib/cocoapods/command/update.rb +21 -5
  7. data/lib/cocoapods/gem_version.rb +1 -1
  8. data/lib/cocoapods/generator/acknowledgements.rb +6 -3
  9. data/lib/cocoapods/generator/constant.rb +19 -0
  10. data/lib/cocoapods/generator/copy_resources_script.rb +15 -3
  11. data/lib/cocoapods/generator/embed_frameworks_script.rb +11 -2
  12. data/lib/cocoapods/generator/module_map.rb +56 -5
  13. data/lib/cocoapods/generator/xcconfig/aggregate_xcconfig.rb +19 -13
  14. data/lib/cocoapods/generator/xcconfig/pod_xcconfig.rb +4 -6
  15. data/lib/cocoapods/generator/xcconfig/xcconfig_helper.rb +25 -2
  16. data/lib/cocoapods/installer.rb +17 -8
  17. data/lib/cocoapods/installer/analyzer.rb +48 -38
  18. data/lib/cocoapods/installer/analyzer/analysis_result.rb +11 -0
  19. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +7 -6
  20. data/lib/cocoapods/installer/analyzer/pod_variant.rb +8 -8
  21. data/lib/cocoapods/installer/analyzer/pod_variant_set.rb +3 -3
  22. data/lib/cocoapods/installer/analyzer/podfile_dependency_cache.rb +54 -0
  23. data/lib/cocoapods/installer/analyzer/specs_state.rb +16 -16
  24. data/lib/cocoapods/installer/analyzer/target_inspector.rb +7 -11
  25. data/lib/cocoapods/installer/pod_source_installer.rb +2 -3
  26. data/lib/cocoapods/installer/podfile_validator.rb +11 -10
  27. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +72 -28
  28. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +8 -2
  29. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +9 -0
  30. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +32 -24
  31. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +97 -54
  32. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +9 -11
  33. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +4 -9
  34. data/lib/cocoapods/installer/xcode/target_validator.rb +32 -18
  35. data/lib/cocoapods/project.rb +32 -17
  36. data/lib/cocoapods/resolver.rb +59 -31
  37. data/lib/cocoapods/resolver/lazy_specification.rb +28 -18
  38. data/lib/cocoapods/sandbox.rb +2 -4
  39. data/lib/cocoapods/sandbox/file_accessor.rb +25 -9
  40. data/lib/cocoapods/sandbox/headers_store.rb +31 -6
  41. data/lib/cocoapods/sandbox/path_list.rb +36 -46
  42. data/lib/cocoapods/target.rb +7 -4
  43. data/lib/cocoapods/target/aggregate_target.rb +10 -8
  44. data/lib/cocoapods/target/pod_target.rb +87 -20
  45. data/lib/cocoapods/user_interface/error_report.rb +1 -1
  46. data/lib/cocoapods/user_interface/inspector_reporter.rb +4 -4
  47. data/lib/cocoapods/validator.rb +40 -29
  48. metadata +11 -9
@@ -81,11 +81,8 @@ module Pod
81
81
  end
82
82
 
83
83
  if target.requires_frameworks?
84
- framework_name = target.product_module_name
85
- settings['PRODUCT_NAME'] = framework_name
86
84
  if target.static_framework?
87
- settings['PUBLIC_HEADERS_FOLDER_PATH'] = framework_name + '.framework' + '/Headers'
88
- settings['PRIVATE_HEADERS_FOLDER_PATH'] = framework_name + '.framework' + '/PrivateHeaders'
85
+ settings['MACH_O_TYPE'] = 'staticlib'
89
86
  end
90
87
  else
91
88
  settings.merge!('OTHER_LDFLAGS' => '', 'OTHER_LIBTOOLFLAGS' => '')
@@ -105,6 +102,7 @@ module Pod
105
102
  # @return [Void]
106
103
  #
107
104
  def update_changed_file(generator, path)
105
+ path.dirname.mkpath
108
106
  if path.exist?
109
107
  generator.save_as(support_files_temp_dir)
110
108
  unless FileUtils.identical?(support_files_temp_dir, path)
@@ -169,9 +167,6 @@ module Pod
169
167
  # Creates the module map file which ensures that the umbrella header is
170
168
  # recognized with a customized path
171
169
  #
172
- # @yield_param [Generator::ModuleMap]
173
- # yielded once to configure the private headers
174
- #
175
170
  # @return [void]
176
171
  #
177
172
  def create_module_map
@@ -207,10 +202,10 @@ module Pod
207
202
  file_ref = add_file_to_support_group(path)
208
203
  native_target.add_file_references([file_ref])
209
204
 
210
- # Make the umbrella header public
205
+ acl = target.requires_frameworks? ? 'Public' : 'Project'
211
206
  build_file = native_target.headers_build_phase.build_file(file_ref)
212
207
  build_file.settings ||= {}
213
- build_file.settings['ATTRIBUTES'] = ['Public']
208
+ build_file.settings['ATTRIBUTES'] = [acl]
214
209
  end
215
210
  end
216
211
 
@@ -35,7 +35,7 @@ module Pod
35
35
  verify_no_duplicate_framework_and_library_names
36
36
  verify_no_static_framework_transitive_dependencies
37
37
  verify_no_pods_used_with_multiple_swift_versions
38
- verify_framework_usage
38
+ verify_swift_pods_have_module_dependencies
39
39
  end
40
40
 
41
41
  private
@@ -71,16 +71,22 @@ module Pod
71
71
  next unless aggregate_target.requires_frameworks?
72
72
 
73
73
  aggregate_target.user_build_configurations.keys.each do |config|
74
- pod_targets = aggregate_target.pod_targets_for_build_configuration(config)
74
+ dynamic_pod_targets = aggregate_target.pod_targets_for_build_configuration(config).reject(&:static_framework?)
75
75
 
76
- dependencies = pod_targets.select(&:should_build?).reject(&:static_framework?).flat_map(&:dependencies)
77
- depended_upon_targets = pod_targets.select { |t| dependencies.include?(t.pod_name) && !t.should_build? }
76
+ dependencies = dynamic_pod_targets.select(&:should_build?).flat_map(&:dependencies)
77
+ depended_upon_targets = dynamic_pod_targets.select { |t| dependencies.include?(t.pod_name) && !t.should_build? }
78
78
 
79
79
  static_libs = depended_upon_targets.flat_map(&:file_accessors).flat_map(&:vendored_static_artifacts)
80
80
  unless static_libs.empty?
81
81
  raise Informative, "The '#{aggregate_target.label}' target has " \
82
82
  "transitive dependencies that include static binaries: (#{static_libs.to_sentence})"
83
83
  end
84
+
85
+ static_framework_deps = dynamic_pod_targets.select(&:should_build?).flat_map(&:recursive_dependent_targets).select(&:static_framework?)
86
+ unless static_framework_deps.empty?
87
+ raise Informative, "The '#{aggregate_target.label}' target has " \
88
+ "transitive dependencies that include static frameworks: (#{static_framework_deps.flat_map(&:name).to_sentence})"
89
+ end
84
90
  end
85
91
  end
86
92
  end
@@ -100,26 +106,34 @@ module Pod
100
106
 
101
107
  unless error_messages.empty?
102
108
  raise Informative, 'The following pods are integrated into targets ' \
103
- "that do not have the same Swift version:\n\n#{error_messages.join("\n")}"
109
+ "that do not have the same Swift version:\n\n#{error_messages.join("\n")}"
104
110
  end
105
111
  end
106
112
 
107
- def verify_framework_usage
108
- aggregate_targets.each do |aggregate_target|
109
- next if aggregate_target.requires_frameworks?
110
-
111
- aggregate_target.user_build_configurations.keys.each do |config|
112
- pod_targets = aggregate_target.pod_targets_for_build_configuration(config)
113
+ def verify_swift_pods_have_module_dependencies
114
+ error_messages = []
115
+ pod_targets.each do |pod_target|
116
+ next unless pod_target.uses_swift?
113
117
 
114
- swift_pods = pod_targets.select(&:uses_swift?)
115
- unless swift_pods.empty?
116
- raise Informative, 'Pods written in Swift can only be integrated as frameworks; ' \
117
- 'add `use_frameworks!` to your Podfile or target to opt into using it. ' \
118
- "The Swift #{swift_pods.size == 1 ? 'Pod being used is' : 'Pods being used are'}: " +
119
- swift_pods.map(&:name).to_sentence
120
- end
118
+ non_module_dependencies = []
119
+ pod_target.dependent_targets.each do |dependent_target|
120
+ next if !dependent_target.should_build? || dependent_target.defines_module?
121
+ non_module_dependencies << dependent_target.name
121
122
  end
123
+
124
+ next if non_module_dependencies.empty?
125
+
126
+ error_messages << "The Swift pod `#{pod_target.name}` depends upon #{non_module_dependencies.map { |d| "`#{d}`" }.to_sentence}, " \
127
+ 'which do not define modules. ' \
128
+ 'To opt into those targets generating module maps '\
129
+ '(which is necessary to import them from Swift when building as static libraries), ' \
130
+ 'you may set `use_modular_headers!` globally in your Podfile, '\
131
+ 'or specify `:modular_headers => true` for particular dependencies.'
122
132
  end
133
+ return if error_messages.empty?
134
+
135
+ raise Informative, 'The following Swift pods cannot yet be integrated '\
136
+ "as static libraries:\n\n#{error_messages.join("\n\n")}"
123
137
  end
124
138
  end
125
139
  end
@@ -40,6 +40,23 @@ module Pod
40
40
  #
41
41
  attr_reader :development_pods
42
42
 
43
+ # Generates a list of new UUIDs that created objects can be assigned.
44
+ #
45
+ # @note Overridden to generate UUIDs in a much faster way, since we don't need to check for collisions
46
+ # (as the Pods project is regenerated each time, and thus all UUIDs will have come from this method)
47
+ #
48
+ # @param [Integer] count
49
+ # The number of UUIDs to generate
50
+ #
51
+ # @return [Void]
52
+ #
53
+ def generate_available_uuid_list(count = 100)
54
+ start = @generated_uuids.size
55
+ uniques = Array.new(count) { |i| format('%011X0', start + i) }
56
+ @generated_uuids += uniques
57
+ @available_uuids += uniques
58
+ end
59
+
43
60
  public
44
61
 
45
62
  # @!group Legacy Xcode build root
@@ -185,15 +202,14 @@ module Pod
185
202
  # @return [PBXFileReference] The new file reference.
186
203
  #
187
204
  def add_file_reference(absolute_path, group, reflect_file_system_structure = false, base_path = nil)
188
- file_path_name = absolute_path.is_a?(Pathname) ? absolute_path : Pathname.new(absolute_path)
189
- group = group_for_path_in_group(file_path_name, group, reflect_file_system_structure, base_path)
190
- if ref = reference_for_path(file_path_name.realpath)
191
- @refs_by_absolute_path[absolute_path.to_s] = ref
192
- ref
193
- else
194
- ref = group.new_file(file_path_name.realpath)
195
- @refs_by_absolute_path[absolute_path.to_s] = ref
205
+ file_path_name = absolute_path.is_a?(Pathname) ? absolute_path : Pathname(absolute_path)
206
+ if ref = reference_for_path(file_path_name)
207
+ return ref
196
208
  end
209
+
210
+ group = group_for_path_in_group(file_path_name, group, reflect_file_system_structure, base_path)
211
+ ref = group.new_file(file_path_name.realpath)
212
+ @refs_by_absolute_path[file_path_name.to_s] = ref
197
213
  end
198
214
 
199
215
  # Returns the file reference for the given absolute path.
@@ -205,11 +221,12 @@ module Pod
205
221
  # @return [Nil] If no file reference could be found.
206
222
  #
207
223
  def reference_for_path(absolute_path)
208
- unless Pathname.new(absolute_path).absolute?
224
+ absolute_path = absolute_path.is_a?(Pathname) ? absolute_path : Pathname(absolute_path)
225
+ unless absolute_path.absolute?
209
226
  raise ArgumentError, "Paths must be absolute #{absolute_path}"
210
227
  end
211
228
 
212
- refs_by_absolute_path[absolute_path.to_s]
229
+ refs_by_absolute_path[absolute_path.to_s] ||= refs_by_absolute_path[absolute_path.realpath.to_s]
213
230
  end
214
231
 
215
232
  # Adds a file reference to the Podfile.
@@ -336,28 +353,26 @@ module Pod
336
353
  relative_base = base_path.nil? ? group.real_path : base_path.realdirpath
337
354
  relative_pathname = absolute_pathname.relative_path_from(relative_base)
338
355
  relative_dir = relative_pathname.dirname
339
- lproj_regex = /\.lproj/i
340
356
 
341
357
  # Add subgroups for directories, but treat .lproj as a file
342
358
  if reflect_file_system_structure
343
359
  path = relative_base
344
360
  relative_dir.each_filename do |name|
345
- break if name.to_s =~ lproj_regex
361
+ break if name.to_s.downcase.include? '.lproj'
346
362
  next if name == '.'
347
363
  # Make sure groups have the correct absolute path set, as intermittent
348
364
  # directories may not be included in the group structure
349
365
  path += name
350
- group = group[name] || group.new_group(name, path)
366
+ group = group.children.find { |c| c.display_name == name } || group.new_group(name, path)
351
367
  end
352
368
  end
353
369
 
354
370
  # Turn files inside .lproj directories into a variant group
355
- if relative_dir.basename.to_s =~ lproj_regex
371
+ if relative_dir.basename.to_s.downcase.include? '.lproj'
356
372
  group_name = variant_group_name(absolute_pathname)
357
373
  lproj_parent_dir = absolute_pathname.dirname.dirname
358
- group = @variant_groups_by_path_and_name[[lproj_parent_dir, group_name]] ||
359
- group.new_variant_group(group_name, lproj_parent_dir)
360
- @variant_groups_by_path_and_name[[lproj_parent_dir, group_name]] ||= group
374
+ group = @variant_groups_by_path_and_name[[lproj_parent_dir, group_name]] ||=
375
+ group.new_variant_group(group_name, lproj_parent_dir)
361
376
  end
362
377
 
363
378
  group
@@ -20,14 +20,19 @@ module Pod
20
20
  #
21
21
  attr_reader :spec
22
22
 
23
+ # @return [Source] the spec repo source the specification came from
24
+ #
25
+ attr_reader :source
26
+
23
27
  # @return [Bool] whether this resolved specification is only used by tests.
24
28
  #
25
29
  attr_reader :used_by_tests_only
26
30
  alias used_by_tests_only? used_by_tests_only
27
31
 
28
- def initialize(spec, used_by_tests_only)
32
+ def initialize(spec, used_by_tests_only, source)
29
33
  @spec = spec
30
34
  @used_by_tests_only = used_by_tests_only
35
+ @source = source
31
36
  end
32
37
 
33
38
  def name
@@ -66,11 +71,11 @@ module Pod
66
71
  # @return [Array<Source>] The list of the sources which will be used for
67
72
  # the resolution.
68
73
  #
69
- attr_accessor :sources
74
+ attr_reader :sources
70
75
 
71
76
  # @return [Bool] Whether the resolver has sources repositories up-to-date.
72
77
  #
73
- attr_accessor :specs_updated
78
+ attr_reader :specs_updated
74
79
  alias specs_updated? specs_updated
75
80
 
76
81
  # Init a new Resolver
@@ -79,12 +84,18 @@ module Pod
79
84
  # @param [Podfile] podfile @see podfile
80
85
  # @param [Array<Dependency>] locked_dependencies @see locked_dependencies
81
86
  # @param [Array<Source>, Source] sources @see sources
87
+ # @param [Boolean] specs_updated @see specs_updated
88
+ # @param [PodfileDependencyCache] podfile_dependency_cache the podfile dependency cache to use
89
+ # within this Resolver.
82
90
  #
83
- def initialize(sandbox, podfile, locked_dependencies, sources)
91
+ def initialize(sandbox, podfile, locked_dependencies, sources, specs_updated,
92
+ podfile_dependency_cache: Installer::Analyzer::PodfileDependencyCache.from_podfile(podfile))
84
93
  @sandbox = sandbox
85
94
  @podfile = podfile
86
95
  @locked_dependencies = locked_dependencies
87
96
  @sources = Array(sources)
97
+ @specs_updated = specs_updated
98
+ @podfile_dependency_cache = podfile_dependency_cache
88
99
  @platforms_by_dependency = Hash.new { |h, k| h[k] = [] }
89
100
  @cached_sets = {}
90
101
  end
@@ -102,11 +113,13 @@ module Pod
102
113
  # definition.
103
114
  #
104
115
  def resolve
105
- dependencies = podfile.target_definition_list.flat_map do |target|
106
- target.dependencies.each do |dep|
107
- @platforms_by_dependency[dep].push(target.platform).uniq! if target.platform
116
+ dependencies = @podfile_dependency_cache.target_definition_list.flat_map do |target|
117
+ @podfile_dependency_cache.target_definition_dependencies(target).each do |dep|
118
+ next unless target.platform
119
+ @platforms_by_dependency[dep].push(target.platform)
108
120
  end
109
121
  end
122
+ @platforms_by_dependency.each_value(&:uniq!)
110
123
  @activated = Molinillo::Resolver.new(self, self).resolve(dependencies, locked_dependencies)
111
124
  resolver_specs_by_target
112
125
  rescue Molinillo::ResolverError => e
@@ -120,16 +133,22 @@ module Pod
120
133
  #
121
134
  def resolver_specs_by_target
122
135
  @resolver_specs_by_target ||= {}.tap do |resolver_specs_by_target|
123
- podfile.target_definition_list.each do |target|
124
- dependencies = {}
125
- specs = target.dependencies.map(&:name).flat_map do |name|
136
+ dependencies = {}
137
+ @podfile_dependency_cache.target_definition_list.each do |target|
138
+ specs = @podfile_dependency_cache.target_definition_dependencies(target).flat_map do |dep|
139
+ name = dep.name
126
140
  node = @activated.vertex_named(name)
127
141
  (valid_dependencies_for_target_from_node(target, dependencies, node) << node).map { |s| [s, node.payload.test_specification?] }
128
142
  end
129
143
 
130
144
  resolver_specs_by_target[target] = specs.
131
145
  group_by(&:first).
132
- map { |vertex, spec_test_only_tuples| ResolverSpecification.new(vertex.payload, spec_test_only_tuples.map { |tuple| tuple[1] }.all?) }.
146
+ map do |vertex, spec_test_only_tuples|
147
+ test_only = spec_test_only_tuples.all? { |tuple| tuple[1] }
148
+ payload = vertex.payload
149
+ spec_source = payload.respond_to?(:spec_source) && payload.spec_source
150
+ ResolverSpecification.new(payload, test_only, spec_source)
151
+ end.
133
152
  sort_by(&:name)
134
153
  end
135
154
  end
@@ -153,7 +172,9 @@ module Pod
153
172
  def search_for(dependency)
154
173
  @search ||= {}
155
174
  @search[dependency] ||= begin
156
- specifications_for_dependency(dependency, [requirement_for_locked_pod_named(dependency.name)])
175
+ locked_requirement = requirement_for_locked_pod_named(dependency.name)
176
+ additional_requirements = Array(locked_requirement)
177
+ specifications_for_dependency(dependency, additional_requirements)
157
178
  end
158
179
  @search[dependency].dup
159
180
  end
@@ -327,7 +348,7 @@ module Pod
327
348
  # one Pod installation, so different version of the same Pods for
328
349
  # target definitions are not allowed.
329
350
  #
330
- attr_accessor :cached_sets
351
+ attr_reader :cached_sets
331
352
 
332
353
  #-------------------------------------------------------------------------#
333
354
 
@@ -347,7 +368,7 @@ module Pod
347
368
  # @return [Array<Specification>] List of specifications satisfying given requirements.
348
369
  #
349
370
  def specifications_for_dependency(dependency, additional_requirements = [])
350
- requirement = Requirement.new(dependency.requirement.as_list + additional_requirements)
371
+ requirement = Requirement.new(dependency.requirement.as_list + additional_requirements.flat_map(&:as_list))
351
372
  find_cached_set(dependency).
352
373
  all_specifications(installation_options.warn_for_multiple_pod_sources).
353
374
  select { |s| requirement.satisfied_by? s.version }.
@@ -477,7 +498,7 @@ module Pod
477
498
  # Conflict was caused by not specifying an explicit version for the requirement #[name],
478
499
  # and there is no available stable version satisfying constraints for the requirement.
479
500
  o << "\nThere are only pre-release versions available satisfying the following requirements:\n"
480
- conflict.requirements.values.flatten.each do |r|
501
+ conflict.requirements.values.flatten.uniq.each do |r|
481
502
  unless search_for(r).empty?
482
503
  o << "\n\t'#{name}', '#{r.requirement}'\n"
483
504
  end
@@ -525,11 +546,15 @@ module Pod
525
546
  vertex = dependency_graph.vertex_named(dependency.name)
526
547
  predecessors = vertex.recursive_predecessors.select(&:root)
527
548
  predecessors << vertex if vertex.root?
528
- platforms_to_satisfy = predecessors.flat_map(&:explicit_requirements).flat_map { |r| @platforms_by_dependency[r] }
549
+ platforms_to_satisfy = predecessors.flat_map(&:explicit_requirements).flat_map { |r| @platforms_by_dependency[r] }.uniq
550
+
551
+ available_platforms = spec.available_platforms
529
552
 
530
553
  platforms_to_satisfy.all? do |platform_to_satisfy|
531
- spec.available_platforms.select { |spec_platform| spec_platform.name == platform_to_satisfy.name }.
532
- all? { |spec_platform| platform_to_satisfy.supports?(spec_platform) }
554
+ available_platforms.all? do |spec_platform|
555
+ next true unless spec_platform.name == platform_to_satisfy.name
556
+ platform_to_satisfy.supports?(spec_platform)
557
+ end
533
558
  end
534
559
  end
535
560
 
@@ -542,28 +567,31 @@ module Pod
542
567
  # dependencies for `target`.
543
568
  #
544
569
  def valid_dependencies_for_target_from_node(target, dependencies, node)
545
- dependencies[node.name] ||= begin
570
+ dependencies[[node.name, target.platform]] ||= begin
546
571
  validate_platform(node.payload, target)
547
- dependency_nodes = node.outgoing_edges.select do |edge|
548
- edge_is_valid_for_target?(edge, target)
549
- end.map(&:destination)
550
-
551
- dependency_nodes + dependency_nodes.flat_map do |item|
552
- node_result = valid_dependencies_for_target_from_node(target, dependencies, item)
553
- node_result
572
+ dependency_nodes = []
573
+ node.outgoing_edges.each do |edge|
574
+ next unless edge_is_valid_for_target_platform?(edge, target.platform)
575
+ dependency_nodes << edge.destination
554
576
  end
577
+
578
+ dependency_nodes.flat_map do |item|
579
+ valid_dependencies_for_target_from_node(target, dependencies, item)
580
+ end.concat dependency_nodes
555
581
  end
556
582
  end
557
583
 
558
584
  # Whether the given `edge` should be followed to find dependencies for the
559
- # given `target`.
585
+ # given `target_platform`.
560
586
  #
561
587
  # @return [Bool]
562
588
  #
563
- def edge_is_valid_for_target?(edge, target)
564
- dependencies_for_target_platform =
565
- edge.origin.payload.all_dependencies(target.platform).map(&:name)
566
- dependencies_for_target_platform.include?(edge.requirement.name)
589
+ def edge_is_valid_for_target_platform?(edge, target_platform)
590
+ requirement_name = edge.requirement.name
591
+
592
+ edge.origin.payload.all_dependencies(target_platform).any? do |dep|
593
+ dep.name == requirement_name
594
+ end
567
595
  end
568
596
  end
569
597
  end
@@ -1,34 +1,44 @@
1
+ require 'delegate'
1
2
  module Pod
2
3
  class Specification
3
4
  class Set
4
- class LazySpecification < BasicObject
5
- attr_reader :name, :version, :source
6
-
7
- def initialize(name, version, source)
8
- @name = name
9
- @version = version
10
- @source = source
5
+ class SpecWithSource < DelegateClass(Specification)
6
+ attr_reader :spec_source
7
+ def initialize(spec, source)
8
+ super(spec)
9
+ @spec_source = source
11
10
  end
12
11
 
13
- def method_missing(method, *args, &block)
14
- specification.send(method, *args, &block)
15
- end
12
+ undef is_a?
13
+ end
14
+
15
+ class LazySpecification < DelegateClass(Specification)
16
+ attr_reader :name, :version, :spec_source
16
17
 
17
- def respond_to_missing?(method, include_all = false)
18
- specification.respond_to?(method, include_all)
18
+ def initialize(name, version, spec_source)
19
+ @name = name
20
+ @version = version
21
+ @spec_source = spec_source
19
22
  end
20
23
 
21
24
  def subspec_by_name(name = nil, raise_if_missing = true, include_test_specifications = false)
22
- if !name || name == self.name
23
- self
24
- else
25
- specification.subspec_by_name(name, raise_if_missing, include_test_specifications)
26
- end
25
+ subspec =
26
+ if !name || name == self.name
27
+ self
28
+ else
29
+ specification.subspec_by_name(name, raise_if_missing, include_test_specifications)
30
+ end
31
+ return unless subspec
32
+
33
+ SpecWithSource.new subspec, spec_source
27
34
  end
28
35
 
29
36
  def specification
30
- @specification ||= source.specification(name, version.version)
37
+ @specification ||= spec_source.specification(name, version.version)
31
38
  end
39
+ alias __getobj__ specification
40
+
41
+ undef is_a?
32
42
  end
33
43
 
34
44
  class External