Class: Pod::Specification

Inherits:
Object
  • Object
show all
Includes:
DSL, DSL::Deprecations, JSONSupport, RootAttributesAccessors
Defined in:
lib/cocoapods-core/specification.rb,
lib/cocoapods-core/specification/dsl.rb,
lib/cocoapods-core/specification/set.rb,
lib/cocoapods-core/specification/json.rb,
lib/cocoapods-core/specification/linter.rb,
lib/cocoapods-core/specification/consumer.rb,
lib/cocoapods-core/specification/dsl/attribute.rb,
lib/cocoapods-core/specification/linter/result.rb,
lib/cocoapods-core/specification/set/presenter.rb,
lib/cocoapods-core/specification/linter/analyzer.rb,
lib/cocoapods-core/specification/dsl/deprecations.rb,
lib/cocoapods-core/specification/dsl/platform_proxy.rb,
lib/cocoapods-core/specification/dsl/attribute_support.rb,
lib/cocoapods-core/specification/root_attribute_accessors.rb

Overview

The Specification provides a DSL to describe a Pod. A pod is defined as a library originating from a source. A specification can support detailed attributes for modules of code through subspecs.

Usually it is stored in files with ‘podspec` extension.

Defined Under Namespace

Modules: DSL, JSONSupport Classes: Consumer, Linter, Set

Constant Summary

Constants included from DSL

DSL::LICENSE_KEYS, DSL::PLATFORMS, DSL::SOURCE_KEYS

Instance Attribute Summary collapse

Hierarchy collapse

Dependencies & Subspecs collapse

DSL helpers collapse

DSL attribute writers collapse

File representation collapse

Validation collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from JSONSupport

#to_hash, #to_json, #to_pretty_json

Methods included from DSL::Deprecations

#xcconfig=

Methods included from DSL

#authors=, #cocoapods_version=, #compiler_flags=, #default_subspecs=, #dependency, #deployment_target=, #deprecated=, #deprecated_in_favor_of=, #description=, #documentation_url=, #exclude_files=, #frameworks=, #header_dir=, #header_mappings_dir=, #homepage=, #ios, #libraries=, #license=, #module_map=, #module_name=, #name=, #osx, #platform=, #pod_target_xcconfig=, #prefix_header_contents=, #prefix_header_file=, #prepare_command=, #preserve_paths=, #private_header_files=, #public_header_files=, #requires_arc=, #resource_bundles=, #resources=, #screenshots=, #social_media_url=, #source=, #source_files=, #subspec, #summary=, #tvos, #user_target_xcconfig=, #vendored_frameworks=, #vendored_libraries=, #version=, #watchos, #weak_frameworks=

Methods included from DSL::AttributeSupport

#attribute, #root_attribute

Constructor Details

#initialize(parent = nil, name = nil) {|_self| ... } ⇒ Specification

Returns a new instance of Specification.

Yields:

  • (_self)

Yield Parameters:



33
34
35
36
37
38
39
40
41
# File 'lib/cocoapods-core/specification.rb', line 33

def initialize(parent = nil, name = nil)
  @attributes_hash = {}
  @subspecs = []
  @consumers = {}
  @parent = parent
  attributes_hash['name'] = name

  yield self if block_given?
end

Instance Attribute Details

#attributes_hashHash



46
47
48
# File 'lib/cocoapods-core/specification.rb', line 46

def attributes_hash
  @attributes_hash
end

#parentSpecification (readonly)



26
27
28
# File 'lib/cocoapods-core/specification.rb', line 26

def parent
  @parent
end

#subspecsArray<Specification>



50
51
52
# File 'lib/cocoapods-core/specification.rb', line 50

def subspecs
  @subspecs
end

Class Method Details

.from_file(path, subspec_name = nil) ⇒ Specification

Loads a specification form the given path.

Raises:

  • If the file doesn’t return a Pods::Specification after evaluation.



522
523
524
525
526
527
528
529
530
531
532
533
534
535
# File 'lib/cocoapods-core/specification.rb', line 522

def self.from_file(path, subspec_name = nil)
  path = Pathname.new(path)
  unless path.exist?
    raise Informative, "No podspec exists at path `#{path}`."
  end

  string = File.open(path, 'r:utf-8', &:read)
  # Work around for Rubinius incomplete encoding in 1.9 mode
  if string.respond_to?(:encoding) && string.encoding.name != 'UTF-8'
    string.encode!('UTF-8')
  end

  from_string(string, path, subspec_name)
end

.from_hash(hash, parent = nil) ⇒ Specification

Configures a new specification from the given hash.



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/cocoapods-core/specification/json.rb', line 57

def self.from_hash(hash, parent = nil)
  spec = Spec.new(parent)
  attributes_hash = hash.dup
  subspecs = attributes_hash.delete('subspecs')
  spec.attributes_hash = attributes_hash
  if subspecs
    spec.subspecs = subspecs.map do |s_hash|
      Specification.from_hash(s_hash, spec)
    end
  end
  spec
end

.from_json(json) ⇒ Specification

Configures a new specification from the given JSON representation.



44
45
46
47
48
# File 'lib/cocoapods-core/specification/json.rb', line 44

def self.from_json(json)
  require 'json'
  hash = JSON.parse(json)
  from_hash(hash)
end

.from_string(spec_contents, path, subspec_name = nil) ⇒ Specification

Loads a specification with the given string. The specification is evaluated in the context of ‘path`.



548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
# File 'lib/cocoapods-core/specification.rb', line 548

def self.from_string(spec_contents, path, subspec_name = nil)
  path = Pathname.new(path)
  spec = nil
  Dir.chdir(path.parent.directory? ? path.parent : Dir.pwd) do
    case path.extname
    when '.podspec'
      spec = ::Pod._eval_podspec(spec_contents, path)
      unless spec.is_a?(Specification)
        raise Informative, "Invalid podspec file at path `#{path}`."
      end
    when '.json'
      spec = Specification.from_json(spec_contents)
    else
      raise Informative, "Unsupported specification format `#{path.extname}`."
    end
  end

  spec.defined_in_file = path
  spec.subspec_by_name(subspec_name)
end

.name_and_version_from_string(string_representation) ⇒ Array<String, Version>

Returns the name and the version of a pod.

Examples:

Input examples


"libPusher (1.0)"
"RestKit/JSON (1.0)"


117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/cocoapods-core/specification.rb', line 117

def self.name_and_version_from_string(string_representation)
  match_data = string_representation.match(/\A((?:\s?[^\s(])+)(?: \((.+)\))?\Z/)
  unless match_data
    raise Informative, 'Invalid string representation for a ' \
      "specification: `#{string_representation}`. " \
      'The string representation should include the name and ' \
      'optionally the version of the Pod.'
  end
  name = match_data[1]
  vers = Version.new(match_data[2])
  [name, vers]
end

.root_name(full_name) ⇒ String

Returns the root name of a specification.



136
137
138
# File 'lib/cocoapods-core/specification.rb', line 136

def self.root_name(full_name)
  full_name.split('/').first
end

Instance Method Details

#==(other) ⇒ Bool Also known as: eql?

TODO:

Not sure if comparing only the name and the version is the way to go. This is used by the installer to group specifications by root spec.

Checks if a specification is equal to the given one according its name and to its version.



64
65
66
67
68
# File 'lib/cocoapods-core/specification.rb', line 64

def ==(other)
  other.is_a?(self.class) &&
    name == other.name &&
    version == other.version
end

#all_dependencies(platform = nil) ⇒ Array<Dependency>



303
304
305
# File 'lib/cocoapods-core/specification.rb', line 303

def all_dependencies(platform = nil)
  dependencies(platform) + subspec_dependencies(platform)
end

#available_platformsArray<Platform>

Note:

If no platform is specified, this method returns all known platforms.

Returns The platforms that the Pod is supported on.



359
360
361
362
363
# File 'lib/cocoapods-core/specification.rb', line 359

def available_platforms
  names = supported_platform_names
  names = PLATFORMS if names.empty?
  names.map { |name| Platform.new(name, deployment_target(name)) }
end

#checksumString, Nil



492
493
494
495
496
497
498
499
# File 'lib/cocoapods-core/specification.rb', line 492

def checksum
  unless defined_in_file.nil?
    require 'digest'
    checksum = Digest::SHA1.hexdigest(File.read(defined_in_file))
    checksum = checksum.encode('UTF-8') if checksum.respond_to?(:encode)
    checksum
  end
end

#consumer(platform) ⇒ Specification::Consumer

Returns a consumer to access the multi-platform attributes.



314
315
316
317
# File 'lib/cocoapods-core/specification.rb', line 314

def consumer(platform)
  platform = platform.to_sym
  @consumers[platform] ||= Consumer.new(self, platform)
end

#default_subspecsArray<String>



251
252
253
254
# File 'lib/cocoapods-core/specification.rb', line 251

def default_subspecs
  # TODO: remove singular form and update the JSON specs.
  Array(attributes_hash['default_subspecs'] || attributes_hash['default_subspec'])
end

#defined_in_fileString



504
505
506
# File 'lib/cocoapods-core/specification.rb', line 504

def defined_in_file
  root? ? @defined_in_file : root.defined_in_file
end

#dependencies(platform = nil) ⇒ Array<Dependency>

Note:

External dependencies are inherited by subspecs

Returns the dependencies on other Pods or subspecs of other Pods.



291
292
293
294
295
296
297
298
299
# File 'lib/cocoapods-core/specification.rb', line 291

def dependencies(platform = nil)
  if platform
    consumer(platform).dependencies || []
  else
    available_platforms.map do |spec_platform|
      consumer(spec_platform).dependencies
    end.flatten.uniq
  end
end

#deployment_target(platform_name) ⇒ String, Nil

Returns the deployment target for the specified platform.



373
374
375
376
377
# File 'lib/cocoapods-core/specification.rb', line 373

def deployment_target(platform_name)
  result = platform_hash[platform_name.to_s]
  result ||= parent.deployment_target(platform_name) if parent
  result
end

#hashFixnum

Note:

This function must have the property that a.eql?(b) implies a.hash == b.hash.

Note:

This method is used by the Hash class.

Return the hash value for this specification according to its attributes hash.



82
83
84
# File 'lib/cocoapods-core/specification.rb', line 82

def hash
  (name.hash * 53) ^ version.hash
end

#inspectString



101
102
103
# File 'lib/cocoapods-core/specification.rb', line 101

def inspect
  "#<#{self.class.name} name=#{name.inspect}>"
end

#local?Bool



328
329
330
331
# File 'lib/cocoapods-core/specification.rb', line 328

def local?
  return true if source[:path]
  false
end

#module_nameString

Returns the module name of a specification



144
145
146
147
148
# File 'lib/cocoapods-core/specification.rb', line 144

def module_name
  attributes_hash['module_name'] ||
    c99ext_identifier(attributes_hash['header_dir']) ||
    c99ext_identifier(attributes_hash['name'])
end

#recursive_subspecsArray<Specifications>



201
202
203
204
205
206
207
208
# File 'lib/cocoapods-core/specification.rb', line 201

def recursive_subspecs
  mapper = lambda do |spec|
    spec.subspecs.map do |subspec|
      [subspec, *mapper.call(subspec)]
    end.flatten
  end
  mapper.call(self)
end

#rootSpecification



176
177
178
# File 'lib/cocoapods-core/specification.rb', line 176

def root
  parent ? parent.root : self
end

#root?Bool



182
183
184
# File 'lib/cocoapods-core/specification.rb', line 182

def root?
  parent.nil?
end

#store_attribute(name, value, platform_name = nil) ⇒ Object

Note:

If the provides value is Hash the keys are converted to a string.

Sets the value for the attribute with the given name.



436
437
438
439
440
441
442
443
444
445
446
447
# File 'lib/cocoapods-core/specification.rb', line 436

def store_attribute(name, value, platform_name = nil)
  name = name.to_s
  value = convert_keys_to_string(value) if value.is_a?(Hash)
  value = value.strip_heredoc.strip if value.respond_to?(:strip_heredoc)
  if platform_name
    platform_name = platform_name.to_s
    attributes_hash[platform_name] ||= {}
    attributes_hash[platform_name][name] = value
  else
    attributes_hash[name] = value
  end
end

#subspec?Bool



188
189
190
# File 'lib/cocoapods-core/specification.rb', line 188

def subspec?
  !parent.nil?
end

#subspec_by_name(relative_name, raise_if_missing = true) ⇒ Specification

Returns the subspec with the given name or the receiver if the name is nil or equal to the name of the receiver.

Examples:

Retrieving a subspec


s.subspec_by_name('Pod/subspec').name #=> 'subspec'


227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/cocoapods-core/specification.rb', line 227

def subspec_by_name(relative_name, raise_if_missing = true)
  if relative_name.nil? || relative_name == base_name
    self
  elsif relative_name.downcase == base_name.downcase
    raise Informative, "Trying to access a `#{relative_name}` " \
      "specification from `#{base_name}`, which has a different case."
  else
    remainder = relative_name[base_name.size + 1..-1]
    subspec_name = remainder.split('/').shift
    subspec = subspecs.find { |s| s.base_name == subspec_name }
    unless subspec
      if raise_if_missing
        raise Informative, 'Unable to find a specification named ' \
          "`#{relative_name}` in `#{name} (#{version})`."
      else
        return nil
      end
    end
    subspec.subspec_by_name(remainder, raise_if_missing)
  end
end

#subspec_dependencies(platform = nil) ⇒ Array<Dependency>

Note:

A specification has a dependency on either the #default_subspecs or each of its children subspecs that are compatible with its platform.

Returns the dependencies on subspecs.



267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/cocoapods-core/specification.rb', line 267

def subspec_dependencies(platform = nil)
  specs = if default_subspecs.empty?
            subspecs.compact
          else
            default_subspecs.map do |subspec_name|
              root.subspec_by_name("#{name}/#{subspec_name}")
            end
          end
  if platform
    specs = specs.select { |s| s.supported_on_platform?(platform) }
  end
  specs.map { |s| Dependency.new(s.name, version) }
end

#supported_on_platform?(platform) ⇒ Bool #supported_on_platform?(symbolic_name, deployment_target) ⇒ Bool

Returns whether the specification is supported in the given platform.



349
350
351
352
# File 'lib/cocoapods-core/specification.rb', line 349

def supported_on_platform?(*platform)
  platform = Platform.new(*platform)
  available_platforms.any? { |available| platform.supports?(available) }
end

#to_sString



89
90
91
92
93
94
95
96
97
# File 'lib/cocoapods-core/specification.rb', line 89

def to_s
  if name && !version.version.empty?
    "#{name} (#{version})"
  elsif name
    name
  else
    'No-name'
  end
end

#validate_cocoapods_versionObject

Validates the cocoapods_version in the specification against the current version of Core. It will raise an Informative error if the version is not satisfied.



590
591
592
593
594
595
# File 'lib/cocoapods-core/specification.rb', line 590

def validate_cocoapods_version
  unless cocoapods_version.satisfied_by?(Version.create(CORE_VERSION))
    raise Informative, "`#{name}` requires CocoaPods version `#{cocoapods_version}`, " \
                       "which is not satisified by your current version, `#{CORE_VERSION}`."
  end
end