cocoapods-core 0.17.0.rc1
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.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +36 -0
- data/lib/cocoapods-core/core_ui.rb +19 -0
- data/lib/cocoapods-core/dependency.rb +295 -0
- data/lib/cocoapods-core/gem_version.rb +6 -0
- data/lib/cocoapods-core/lockfile.rb +440 -0
- data/lib/cocoapods-core/platform.rb +171 -0
- data/lib/cocoapods-core/podfile/dsl.rb +459 -0
- data/lib/cocoapods-core/podfile/target_definition.rb +503 -0
- data/lib/cocoapods-core/podfile.rb +345 -0
- data/lib/cocoapods-core/requirement.rb +15 -0
- data/lib/cocoapods-core/source/validator.rb +183 -0
- data/lib/cocoapods-core/source.rb +284 -0
- data/lib/cocoapods-core/specification/consumer.rb +356 -0
- data/lib/cocoapods-core/specification/dsl/attribute.rb +245 -0
- data/lib/cocoapods-core/specification/dsl/attribute_support.rb +76 -0
- data/lib/cocoapods-core/specification/dsl/deprecations.rb +47 -0
- data/lib/cocoapods-core/specification/dsl/platform_proxy.rb +67 -0
- data/lib/cocoapods-core/specification/dsl.rb +1110 -0
- data/lib/cocoapods-core/specification/linter.rb +436 -0
- data/lib/cocoapods-core/specification/root_attribute_accessors.rb +152 -0
- data/lib/cocoapods-core/specification/set/presenter.rb +229 -0
- data/lib/cocoapods-core/specification/set/statistics.rb +277 -0
- data/lib/cocoapods-core/specification/set.rb +171 -0
- data/lib/cocoapods-core/specification/yaml.rb +60 -0
- data/lib/cocoapods-core/specification.rb +592 -0
- data/lib/cocoapods-core/standard_error.rb +84 -0
- data/lib/cocoapods-core/vendor/dependency.rb +264 -0
- data/lib/cocoapods-core/vendor/requirement.rb +208 -0
- data/lib/cocoapods-core/vendor/version.rb +333 -0
- data/lib/cocoapods-core/vendor.rb +56 -0
- data/lib/cocoapods-core/version.rb +99 -0
- data/lib/cocoapods-core/yaml_converter.rb +202 -0
- data/lib/cocoapods-core.rb +23 -0
- metadata +154 -0
@@ -0,0 +1,436 @@
|
|
1
|
+
module Pod
|
2
|
+
class Specification
|
3
|
+
|
4
|
+
# The Linter check specifications for errors and warnings.
|
5
|
+
#
|
6
|
+
# It is designed not only to guarantee the formal functionality of a
|
7
|
+
# specification, but also to support the maintenance of sources.
|
8
|
+
#
|
9
|
+
class Linter
|
10
|
+
|
11
|
+
# @return [Specification] the specification to lint.
|
12
|
+
#
|
13
|
+
attr_reader :spec
|
14
|
+
|
15
|
+
# @return [Pathname] the path of the `podspec` file where {#spec} is
|
16
|
+
# defined.
|
17
|
+
#
|
18
|
+
attr_reader :file
|
19
|
+
|
20
|
+
# @param [Specification, Pathname, String] spec_or_path
|
21
|
+
# the Specification or the path of the `podspec` file to lint.
|
22
|
+
#
|
23
|
+
def initialize(spec_or_path)
|
24
|
+
if spec_or_path.is_a?(Specification)
|
25
|
+
@spec = spec_or_path
|
26
|
+
@file = @spec.defined_in_file
|
27
|
+
else
|
28
|
+
@file = Pathname.new(spec_or_path)
|
29
|
+
begin
|
30
|
+
@spec = Specification.from_file(@file)
|
31
|
+
rescue Exception => e
|
32
|
+
@spec = nil
|
33
|
+
@raise_message = e.message
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Lints the specification adding a {Result} for any failed check to the
|
39
|
+
# {#results} list.
|
40
|
+
#
|
41
|
+
# @return [Bool] whether the specification passed validation.
|
42
|
+
#
|
43
|
+
def lint
|
44
|
+
@results = []
|
45
|
+
if spec
|
46
|
+
perform_textual_analysis
|
47
|
+
check_required_root_attributes
|
48
|
+
run_root_validation_hooks
|
49
|
+
perform_all_specs_ananlysis
|
50
|
+
else
|
51
|
+
error "The specification defined in `#{file}` could not be loaded." \
|
52
|
+
"\n\n#{@raise_message}"
|
53
|
+
end
|
54
|
+
results.empty?
|
55
|
+
end
|
56
|
+
|
57
|
+
#-----------------------------------------------------------------------#
|
58
|
+
|
59
|
+
# !@group Lint results
|
60
|
+
|
61
|
+
public
|
62
|
+
|
63
|
+
# @return [Array<Result>] all the results generated by the Linter.
|
64
|
+
#
|
65
|
+
attr_reader :results
|
66
|
+
|
67
|
+
# @return [Array<Result>] all the errors generated by the Linter.
|
68
|
+
#
|
69
|
+
def errors
|
70
|
+
@errors ||= results.select { |r| r.type == :error }
|
71
|
+
end
|
72
|
+
|
73
|
+
# @return [Array<Result>] all the warnings generated by the Linter.
|
74
|
+
#
|
75
|
+
def warnings
|
76
|
+
@warnings ||= results.select { |r| r.type == :warning }
|
77
|
+
end
|
78
|
+
|
79
|
+
#-----------------------------------------------------------------------#
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
# !@group Lint steps
|
84
|
+
|
85
|
+
# It reads a podspec file and checks for strings corresponding
|
86
|
+
# to features that are or will be deprecated
|
87
|
+
#
|
88
|
+
# @return [void]
|
89
|
+
#
|
90
|
+
def perform_textual_analysis
|
91
|
+
return unless @file
|
92
|
+
text = @file.read
|
93
|
+
error "`config.ios?' and `config.osx?' are deprecated." if text =~ /config\..?os.?/
|
94
|
+
error "clean_paths are deprecated (use preserve_paths)." if text =~ /clean_paths/
|
95
|
+
warning "Comments must be deleted." if text.scan(/^\s*#/).length > 24
|
96
|
+
end
|
97
|
+
|
98
|
+
# Checks that every root only attribute which is required has a value.
|
99
|
+
#
|
100
|
+
# @return [void]
|
101
|
+
#
|
102
|
+
def check_required_root_attributes
|
103
|
+
attributes = DSL.attributes.values.select(&:root_only?)
|
104
|
+
attributes.each do |attr|
|
105
|
+
# if spec.respond_to?(attr.name)
|
106
|
+
value = spec.send(attr.name)
|
107
|
+
next unless attr.required?
|
108
|
+
unless value && (!value.respond_to?(:empty?) || !value.empty?)
|
109
|
+
if attr.name == :license
|
110
|
+
warning("Missing required attribute `#{attr.name}`.")
|
111
|
+
else
|
112
|
+
error("Missing required attribute `#{attr.name}`.")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
# end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Runs the validation hook for root only attributes.
|
120
|
+
#
|
121
|
+
# @return [void]
|
122
|
+
#
|
123
|
+
def run_root_validation_hooks
|
124
|
+
attributes = DSL.attributes.values.select(&:root_only?)
|
125
|
+
attributes.each do |attr|
|
126
|
+
validation_hook = "_validate_#{attr.name}"
|
127
|
+
next unless respond_to?(validation_hook, true)
|
128
|
+
value = spec.send(attr.name)
|
129
|
+
next unless value
|
130
|
+
send(validation_hook, value)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Run validations for multi-platform attributes activating .
|
135
|
+
#
|
136
|
+
# @return [void]
|
137
|
+
#
|
138
|
+
def perform_all_specs_ananlysis
|
139
|
+
all_specs = [ spec, *spec.recursive_subspecs ]
|
140
|
+
all_specs.each do |current_spec|
|
141
|
+
current_spec.available_platforms.each do |platform|
|
142
|
+
@consumer = Specification::Consumer.new(current_spec, platform)
|
143
|
+
run_all_specs_valudation_hooks
|
144
|
+
validate_file_patterns
|
145
|
+
check_tmp_arc_not_nil
|
146
|
+
check_if_spec_is_empty
|
147
|
+
@consumer = nil
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# @return [Specification::Consumer] the current consumer.
|
153
|
+
#
|
154
|
+
attr_accessor :consumer
|
155
|
+
|
156
|
+
# Runs the validation hook for the attributes that are not root only.
|
157
|
+
#
|
158
|
+
# @return [void]
|
159
|
+
#
|
160
|
+
def run_all_specs_valudation_hooks
|
161
|
+
attributes = DSL.attributes.values.reject(&:root_only?)
|
162
|
+
attributes.each do |attr|
|
163
|
+
validation_hook = "_validate_#{attr.name}"
|
164
|
+
next unless respond_to?(validation_hook, true)
|
165
|
+
value = consumer.send(attr.name)
|
166
|
+
next unless value
|
167
|
+
send(validation_hook, value)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Runs the validation hook for each attribute.
|
172
|
+
#
|
173
|
+
# @note Hooks are called only if there is a value for the attribute as
|
174
|
+
# required attributes are already checked by the
|
175
|
+
# {#check_required_root_attributes} step.
|
176
|
+
#
|
177
|
+
# @return [void]
|
178
|
+
#
|
179
|
+
def run_validation_hooks(attributes)
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
#-----------------------------------------------------------------------#
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
# @!group Root spec validation helpers
|
188
|
+
|
189
|
+
# Performs validations related to the `name` attribute.
|
190
|
+
#
|
191
|
+
def _validate_name(n)
|
192
|
+
if spec.name && file
|
193
|
+
names_match = (file.basename.to_s == spec.root.name + '.podspec')
|
194
|
+
unless names_match
|
195
|
+
error "The name of the spec should match the name of the file."
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Performs validations related to the `summary` attribute.
|
201
|
+
#
|
202
|
+
def _validate_summary(s)
|
203
|
+
warning "The summary should be short use `description` (max 140 characters)." if s.length > 140
|
204
|
+
warning "The summary is not meaningful." if s =~ /A short description of/
|
205
|
+
warning "The summary should end with proper punctuation." if s !~ /(\.|\?|!)$/
|
206
|
+
end
|
207
|
+
|
208
|
+
# Performs validations related to the `description` attribute.
|
209
|
+
#
|
210
|
+
def _validate_description(d)
|
211
|
+
warning "The description is not meaningful." if d =~ /An optional longer description of/
|
212
|
+
warning "The description should end with proper punctuation." if d !~ /(\.|\?|!)$/
|
213
|
+
warning "The description is equal to the summary." if d == spec.summary
|
214
|
+
warning "The description is shorter than the summary." if d.length < spec.summary.length
|
215
|
+
end
|
216
|
+
|
217
|
+
# Performs validations related to the `license` attribute.
|
218
|
+
#
|
219
|
+
def _validate_license(l)
|
220
|
+
type = l[:type]
|
221
|
+
warning "Missing license type." if type.nil?
|
222
|
+
warning "Sample license type." if type && type =~ /\(example\)/
|
223
|
+
warning "Invalid license type." if type && type.gsub(' ', '').gsub("\n", '').empty?
|
224
|
+
end
|
225
|
+
|
226
|
+
# Performs validations related to the `source` attribute.
|
227
|
+
#
|
228
|
+
def _validate_source(s)
|
229
|
+
if git = s[:git]
|
230
|
+
tag, commit = s.values_at(:tag, :commit)
|
231
|
+
github = git.include?('github.com')
|
232
|
+
version = spec.version.to_s
|
233
|
+
|
234
|
+
error "Example source." if git =~ /http:\/\/EXAMPLE/
|
235
|
+
error 'The commit of a Git source cannot be `HEAD`.' if commit && commit.downcase =~ /head/
|
236
|
+
warning 'The version should be included in the Git tag.' if tag && !tag.include?(version)
|
237
|
+
warning "Github repositories should end in `.git`." if github && !git.end_with?('.git')
|
238
|
+
warning "Github repositories should use `https` link." if github && !git.start_with?('https://github.com') && !git.start_with?('git://gist.github.com')
|
239
|
+
|
240
|
+
if version == '0.0.1'
|
241
|
+
error 'Git sources should specify either a commit or a tag.' if commit.nil? && tag.nil?
|
242
|
+
else
|
243
|
+
warning 'Git sources should specify a tag.' if tag.nil?
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
#-----------------------------------------------------------------------#
|
249
|
+
|
250
|
+
# @!group All specs validation helpers
|
251
|
+
|
252
|
+
private
|
253
|
+
|
254
|
+
# Performs validations related to the `compiler_flags` attribute.
|
255
|
+
#
|
256
|
+
def _validate_compiler_flags(flags)
|
257
|
+
if flags.join(' ').split(' ').any? { |flag| flag.start_with?('-Wno') }
|
258
|
+
warning "Warnings must not be disabled (`-Wno' compiler flags)."
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Checks the attributes that represent file patterns.
|
263
|
+
#
|
264
|
+
# @todo Check the attributes hash directly.
|
265
|
+
#
|
266
|
+
def validate_file_patterns
|
267
|
+
attributes = DSL.attributes.values.select(&:file_patterns?)
|
268
|
+
attributes.each do |attrb|
|
269
|
+
patterns = consumer.send(attrb.name)
|
270
|
+
if patterns.is_a?(Hash)
|
271
|
+
patterns = patterns.values.flatten(1)
|
272
|
+
end
|
273
|
+
patterns.each do |pattern|
|
274
|
+
if pattern.is_a?(Rake::FileList)
|
275
|
+
error "Rake::FileList is deprecated, use `exclude_files` (#{attrb.name})."
|
276
|
+
else
|
277
|
+
if pattern.start_with?('/')
|
278
|
+
error "File patterns must be relative and cannot start with a slash (#{attrb.name})."
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
# @todo remove in 0.18 and switch the default to true.
|
286
|
+
#
|
287
|
+
def check_tmp_arc_not_nil
|
288
|
+
if consumer.requires_arc.nil?
|
289
|
+
warning "A value for `requires_arc` should be specified until the migration to a `true` default."
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# Check empty subspec attributes
|
294
|
+
#
|
295
|
+
def check_if_spec_is_empty
|
296
|
+
methods = %w[ source_files resources preserve_paths subspecs ]
|
297
|
+
empty = methods.all? { |m| consumer.send(m).empty? }
|
298
|
+
if empty
|
299
|
+
error "The spec appears to be empty (no source files, resources, or preserve paths)."
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
#-----------------------------------------------------------------------#
|
304
|
+
|
305
|
+
# !@group Result Helpers
|
306
|
+
|
307
|
+
private
|
308
|
+
|
309
|
+
# Adds an error result with the given message.
|
310
|
+
#
|
311
|
+
# @param [String] message
|
312
|
+
# The message of the result.
|
313
|
+
#
|
314
|
+
# @return [void]
|
315
|
+
#
|
316
|
+
def error(message)
|
317
|
+
add_result(:error, message)
|
318
|
+
end
|
319
|
+
|
320
|
+
# Adds an warning result with the given message.
|
321
|
+
#
|
322
|
+
# @param [String] message
|
323
|
+
# The message of the result.
|
324
|
+
#
|
325
|
+
# @return [void]
|
326
|
+
#
|
327
|
+
def warning(message)
|
328
|
+
add_result(:warning, message)
|
329
|
+
end
|
330
|
+
|
331
|
+
# Adds a result of the given type with the given message. If there is a
|
332
|
+
# current platform it is added to the result. If a result with the same
|
333
|
+
# type and the same message is already available the current platform is
|
334
|
+
# added to the existing result.
|
335
|
+
#
|
336
|
+
# @param [Symbol] type
|
337
|
+
# The type of the result (`:error`, `:warning`).
|
338
|
+
#
|
339
|
+
# @param [String] message
|
340
|
+
# The message of the result.
|
341
|
+
#
|
342
|
+
# @return [void]
|
343
|
+
#
|
344
|
+
def add_result(type, message)
|
345
|
+
result = results.find { |r| r.type == type && r.message == message }
|
346
|
+
unless result
|
347
|
+
result = Result.new(type, message)
|
348
|
+
results << result
|
349
|
+
end
|
350
|
+
result.platforms << consumer.platform_name if consumer
|
351
|
+
end
|
352
|
+
|
353
|
+
#-----------------------------------------------------------------------#
|
354
|
+
|
355
|
+
class Result
|
356
|
+
|
357
|
+
# @return [Symbol] the type of result.
|
358
|
+
#
|
359
|
+
attr_reader :type
|
360
|
+
|
361
|
+
# @return [String] the message associated with result.
|
362
|
+
#
|
363
|
+
attr_reader :message
|
364
|
+
|
365
|
+
# @param [Symbol] type @see type
|
366
|
+
# @param [String] message @see message
|
367
|
+
#
|
368
|
+
def initialize(type, message)
|
369
|
+
@type = type
|
370
|
+
@message = message
|
371
|
+
@platforms = []
|
372
|
+
end
|
373
|
+
|
374
|
+
# @return [Array<Platform>] the platforms where this result was
|
375
|
+
# generated.
|
376
|
+
#
|
377
|
+
attr_reader :platforms
|
378
|
+
|
379
|
+
# @return [String] a string representation suitable for UI output.
|
380
|
+
#
|
381
|
+
def to_s
|
382
|
+
r = "[#{type.to_s.upcase}] #{message}"
|
383
|
+
if platforms != Specification::PLATFORMS
|
384
|
+
platforms_names = platforms.uniq.map { |p| Platform.string_name(p) }
|
385
|
+
r << " [#{platforms_names * ' - '}]" unless platforms.empty?
|
386
|
+
end
|
387
|
+
r
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
#-----------------------------------------------------------------------#
|
392
|
+
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
# # TODO
|
398
|
+
# # Converts the resources file patterns to a hash defaulting to the
|
399
|
+
# # resource key if they are defined as an Array or a String.
|
400
|
+
# #
|
401
|
+
# # @param [String, Array, Hash] value.
|
402
|
+
# # The value of the attribute as specified by the user.
|
403
|
+
# #
|
404
|
+
# # @return [Hash] the resources.
|
405
|
+
# #
|
406
|
+
# def _prepare_deployment_target(deployment_target)
|
407
|
+
# unless @define_for_platforms.count == 1
|
408
|
+
# raise StandardError, "The deployment target must be defined per platform like `s.ios.deployment_target = '5.0'`."
|
409
|
+
# end
|
410
|
+
# Version.new(deployment_target)
|
411
|
+
# end
|
412
|
+
|
413
|
+
# # TODO
|
414
|
+
# # Converts the resources file patterns to a hash defaulting to the
|
415
|
+
# # resource key if they are defined as an Array or a String.
|
416
|
+
# #
|
417
|
+
# # @param [String, Array, Hash] value.
|
418
|
+
# # The value of the attribute as specified by the user.
|
419
|
+
# #
|
420
|
+
# # @return [Hash] the resources.
|
421
|
+
# #
|
422
|
+
# def _prepare_platform(name_and_deployment_target)
|
423
|
+
# return nil if name_and_deployment_target.nil?
|
424
|
+
# if name_and_deployment_target.is_a?(Array)
|
425
|
+
# name = name_and_deployment_target.first
|
426
|
+
# deployment_target = name_and_deployment_target.last
|
427
|
+
# else
|
428
|
+
# name = name_and_deployment_target
|
429
|
+
# deployment_target = nil
|
430
|
+
# end
|
431
|
+
# unless PLATFORMS.include?(name)
|
432
|
+
# raise StandardError, "Unsupported platform `#{name}`. The available " \
|
433
|
+
# "names are `#{PLATFORMS.inspect}`"
|
434
|
+
# end
|
435
|
+
# Platform.new(name, deployment_target)
|
436
|
+
# end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Pod
|
2
|
+
class Specification
|
3
|
+
module DSL
|
4
|
+
|
5
|
+
# Provides the accessors methods for the root attributes. Root attributes
|
6
|
+
# do not support multiplatform values and inheritance.
|
7
|
+
#
|
8
|
+
module RootAttributesAccessors
|
9
|
+
|
10
|
+
# @return [String] The name of the specification *not* including the
|
11
|
+
# names of the parents, in case of ‘sub-specifications’.
|
12
|
+
#
|
13
|
+
def base_name
|
14
|
+
attributes_hash["name"]
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [String] The name of the specification including the names of
|
18
|
+
# the parents, in case of ‘sub-specifications’.
|
19
|
+
#
|
20
|
+
def name
|
21
|
+
parent ? "#{parent.name}/#{base_name}" : base_name
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Version] The version of the Pod.
|
25
|
+
#
|
26
|
+
# @todo The version is memoized because the Resolvers sets the head
|
27
|
+
# state on it. This information should be stored in the
|
28
|
+
# specification instance and the lockfile should have a more
|
29
|
+
# robust handling of head versions (like a dedicated section).
|
30
|
+
#
|
31
|
+
def version
|
32
|
+
@version ||= root? ? Version.new(attributes_hash["version"]) : root.version
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Hash] a hash containing the authors as the keys and their
|
36
|
+
# email address as the values.
|
37
|
+
#
|
38
|
+
# @note The value is coherced to a hash with a nil email if needed.
|
39
|
+
#
|
40
|
+
# @example Possible values
|
41
|
+
#
|
42
|
+
# { 'Author' => 'email@host.com' }
|
43
|
+
# [ 'Author', { 'Author_2' => 'email@host.com' } ]
|
44
|
+
# [ 'Author', 'Author_2' ]
|
45
|
+
# 'Author'
|
46
|
+
#
|
47
|
+
def authors
|
48
|
+
authors = attributes_hash["authors"]
|
49
|
+
if authors.is_a?(Hash)
|
50
|
+
authors
|
51
|
+
elsif authors.is_a?(Array)
|
52
|
+
result = {}
|
53
|
+
authors.each do |name_or_hash|
|
54
|
+
if name_or_hash.is_a?(String)
|
55
|
+
result[name_or_hash] = nil
|
56
|
+
else
|
57
|
+
result.merge!(name_or_hash)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
result
|
61
|
+
elsif authors.is_a?(String)
|
62
|
+
{ authors => nil }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return [Hash] A hash containing the license information of the Pod.
|
67
|
+
#
|
68
|
+
# @note The indentation is stripped from the license text.
|
69
|
+
#
|
70
|
+
def license
|
71
|
+
license = attributes_hash["license"]
|
72
|
+
if license.is_a?(String)
|
73
|
+
{ :type => license }
|
74
|
+
elsif license.is_a?(Hash)
|
75
|
+
license = convert_keys_to_symbol(license)
|
76
|
+
license[:text] = license[:text].strip_heredoc if license[:text]
|
77
|
+
license
|
78
|
+
else
|
79
|
+
{}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# @return [String] The URL of the homepage of the Pod.
|
84
|
+
#
|
85
|
+
def homepage
|
86
|
+
attributes_hash["homepage"]
|
87
|
+
end
|
88
|
+
|
89
|
+
# @return [Hash{Symbol=>String}] The location from where the library
|
90
|
+
# should be retrieved.
|
91
|
+
#
|
92
|
+
def source
|
93
|
+
convert_keys_to_symbol(attributes_hash["source"])
|
94
|
+
end
|
95
|
+
|
96
|
+
# @return [String] A short description of the Pod.
|
97
|
+
#
|
98
|
+
def summary
|
99
|
+
attributes_hash["summary"]
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [String] A longer description of the Pod.
|
103
|
+
#
|
104
|
+
# @note The indentation is stripped from the description.
|
105
|
+
#
|
106
|
+
def description
|
107
|
+
description = attributes_hash["description"]
|
108
|
+
description.strip_heredoc if description
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Array<String>] The list of the URL for the screenshots of the
|
112
|
+
# Pod.
|
113
|
+
#
|
114
|
+
# @note The value is coherced to an array.
|
115
|
+
#
|
116
|
+
def screenshots
|
117
|
+
value = attributes_hash["screenshots"]
|
118
|
+
[*value]
|
119
|
+
end
|
120
|
+
|
121
|
+
# @return [Hash{Symbol=>Array<String>}] The options to pass to the
|
122
|
+
# appledoc tool.
|
123
|
+
#
|
124
|
+
def documentation
|
125
|
+
convert_keys_to_symbol(attributes_hash["documentation"])
|
126
|
+
end
|
127
|
+
|
128
|
+
#-----------------------------------------------------------------------#
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
# Converts the keys of the given hash to a string.
|
133
|
+
#
|
134
|
+
# @param [Object] value
|
135
|
+
# the value that needs to be stripped from the Symbols.
|
136
|
+
#
|
137
|
+
# @return [Hash] the hash with the strings instead of the keys.
|
138
|
+
#
|
139
|
+
def convert_keys_to_symbol(value)
|
140
|
+
return unless value
|
141
|
+
result = {}
|
142
|
+
value.each do |key, subvalue|
|
143
|
+
subvalue = convert_keys_to_symbol(subvalue) if subvalue.is_a?(Hash)
|
144
|
+
result[key.to_sym] = subvalue
|
145
|
+
end
|
146
|
+
result
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|