Class: Pod::Specification::Linter::Analyzer

Inherits:
Object
  • Object
show all
Defined in:
lib/cocoapods-core/specification/linter/analyzer.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(consumer, results) ⇒ Analyzer

Returns a new instance of Analyzer


7
8
9
10
11
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 7

def initialize(consumer, results)
  @consumer = consumer
  @results = results
  @results.consumer = @consumer
end

Instance Attribute Details

#consumerObject (readonly, private)

Returns the value of attribute consumer


27
28
29
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 27

def consumer
  @consumer
end

#resultsObject (readonly, private)

Returns the value of attribute results


29
30
31
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 29

def results
  @results
end

Instance Method Details

#analyzeResults

Analyzes the consumer adding a Result for any failed check to the #results object.

Returns:

  • (Results)

    the results of the analysis.


18
19
20
21
22
23
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 18

def analyze
  check_attributes
  validate_file_patterns
  check_if_spec_is_empty
  results
end

#check_attributesObject (private)

Note:

Sub-keys are not checked per-platform as there is no attribute supporting this combination.

Note:

The keys of sub-keys are not checked as they are only used by the source attribute and they are subject to change according to the support in the cocoapods-downloader gem.

Checks the attributes hash for any unknown key which might be the result of a misspelling in a JSON file.


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 42

def check_attributes
  attributes_keys = Pod::Specification::DSL.attributes.keys.map(&:to_s)
  platform_keys = Specification::DSL::PLATFORMS.map(&:to_s)
  valid_keys = attributes_keys + platform_keys
  attributes_hash = consumer.spec.attributes_hash
  keys = attributes_hash.keys
  Specification::DSL::PLATFORMS.each do |platform|
    if attributes_hash[platform.to_s]
      keys += attributes_hash[platform.to_s].keys
    end
  end
  unknown_keys = keys - valid_keys

  unknown_keys.each do |key|
    results.add_warning('attributes', "Unrecognized `#{key}` key.")
  end

  Pod::Specification::DSL.attributes.each do |_key, attribute|
    declared_value = consumer.spec.attributes_hash[attribute.name.to_s]
    validate_attribute_occurrence(attribute, declared_value)
    validate_attribute_type(attribute, declared_value)
    if attribute.name != :platforms
      value = value_for_attribute(attribute)
      validate_attribute_value(attribute, value) if value
    end
  end
end

#check_if_spec_is_emptyObject (private)

Check empty subspec attributes


96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 96

def check_if_spec_is_empty
  methods = %w( source_files resources resource_bundles preserve_paths
                dependencies vendored_libraries vendored_frameworks )
  empty_patterns = methods.all? { |m| consumer.send(m).empty? }
  empty = empty_patterns && consumer.spec.subspecs.empty?
  if empty
    results.add_error('File Patterns', "The #{consumer.spec} spec is " \
      'empty (no source files, resources, resource_bundles, ' \
      'preserve paths, vendored_libraries, vendored_frameworks, ' \
      'dependencies, nor subspecs).')
  end
end

#validate_attribute_array_keys(attribute, value) ⇒ Object (private)


170
171
172
173
174
175
176
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 170

def validate_attribute_array_keys(attribute, value)
  unknown_keys = value.keys.map(&:to_s) - attribute.keys.map(&:to_s)
  unknown_keys.each do |unknown_key|
    results.add_warning('keys', "Unrecognized `#{unknown_key}` key for " \
      "`#{attribute.name}` attribute.")
  end
end

#validate_attribute_hash_keys(attribute, value) ⇒ Object (private)


178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 178

def validate_attribute_hash_keys(attribute, value)
  major_keys = value.keys & attribute.keys.keys
  if major_keys.count.zero?
    results.add_warning('keys', "Missing primary key for `#{attribute.name}` " \
      'attribute. The acceptable ones are: ' \
      "`#{attribute.keys.keys.map(&:to_s).sort.join(', ')}`.")
  elsif major_keys.count == 1
    acceptable = attribute.keys[major_keys.first] || []
    unknown = value.keys - major_keys - acceptable
    unless unknown.empty?
      results.add_warning('keys', "Incompatible `#{unknown.sort.join(', ')}` " \
        "key(s) with `#{major_keys.first}` primary key for " \
        "`#{attribute.name}` attribute.")
    end
  else
    sorted_keys = major_keys.map(&:to_s).sort
    results.add_warning('keys', "Incompatible `#{sorted_keys.join(', ')}` " \
      "keys for `#{attribute.name}` attribute.")
  end
end

#validate_attribute_occurrence(attribute, value) ⇒ Object (private)

Parameters:

  • value (Object)

    The value of the attribute.


138
139
140
141
142
143
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 138

def validate_attribute_occurrence(attribute, value)
  if attribute.root_only? && !value.nil? && !consumer.spec.root?
    results.add_error('attributes', "Can't set `#{attribute.name}` attribute for " \
      "subspecs (in `#{consumer.spec.name}`).")
  end
end

#validate_attribute_type(attribute, value) ⇒ Object (private)


161
162
163
164
165
166
167
168
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 161

def validate_attribute_type(attribute, value)
  return unless value
  types = attribute.supported_types
  if types.none? { |klass| value.class == klass }
    results.add_error('attributes', 'Unacceptable type ' \
      "`#{value.class}` for `#{attribute.name}`. Allowed values: `#{types.inspect}`.")
  end
end

#validate_attribute_value(attribute, value) ⇒ Object (private)

Validates the given value for the given attribute.

Parameters:

  • attribute (Spec::DSL::Attribute)

    The attribute.

  • value (Object)

    The value of the attribute.


153
154
155
156
157
158
159
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 153

def validate_attribute_value(attribute, value)
  if attribute.keys.is_a?(Array)
    validate_attribute_array_keys(attribute, value)
  elsif attribute.keys.is_a?(Hash)
    validate_attribute_hash_keys(attribute, value)
  end
end

#validate_file_patternsObject (private)

TODO:

Check the attributes hash directly.

Checks the attributes that represent file patterns.


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/cocoapods-core/specification/linter/analyzer.rb', line 74

def validate_file_patterns
  attributes = DSL.attributes.values.select(&:file_patterns?)
  attributes.each do |attrb|
    patterns = consumer.send(attrb.name)

    if patterns.is_a?(Hash)
      patterns = patterns.values.flatten(1)
    end

    if patterns.respond_to?(:each)
      patterns.each do |pattern|
        if pattern.respond_to?(:start_with?) && pattern.start_with?('/')
          results.add_error('File Patterns', 'File patterns must be ' \
            "relative and cannot start with a slash (#{attrb.name}).")
        end
      end
    end
  end
end

#value_for_attribute(attribute) ⇒ mixed (private)

Returns the own or inherited (if applicable) value of the given attribute.

Parameters:

  • attribute (Spec::DSL::Attribute)

    The attribute.

Returns:

  • (mixed)

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

def value_for_attribute(attribute)
  if attribute.root_only?
    consumer.spec.send(attribute.name)
  else
    consumer.send(attribute.name) if consumer.respond_to?(attribute.name)
  end
rescue => e
  results.add_error('attributes', "Unable to validate `#{attribute.name}` (#{e}).")
  nil
end