cocoapods-core 0.30.0 → 1.15.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +7 -10
  3. data/lib/cocoapods-core/build_type.rb +121 -0
  4. data/lib/cocoapods-core/cdn_source.rb +501 -0
  5. data/lib/cocoapods-core/core_ui.rb +4 -3
  6. data/lib/cocoapods-core/dependency.rb +100 -73
  7. data/lib/cocoapods-core/gem_version.rb +1 -2
  8. data/lib/cocoapods-core/github.rb +32 -5
  9. data/lib/cocoapods-core/http.rb +86 -0
  10. data/lib/cocoapods-core/lockfile.rb +161 -56
  11. data/lib/cocoapods-core/metrics.rb +47 -0
  12. data/lib/cocoapods-core/platform.rb +99 -11
  13. data/lib/cocoapods-core/podfile/dsl.rb +623 -124
  14. data/lib/cocoapods-core/podfile/target_definition.rb +662 -109
  15. data/lib/cocoapods-core/podfile.rb +138 -65
  16. data/lib/cocoapods-core/requirement.rb +37 -8
  17. data/lib/cocoapods-core/source/acceptor.rb +16 -13
  18. data/lib/cocoapods-core/source/aggregate.rb +79 -103
  19. data/lib/cocoapods-core/source/health_reporter.rb +9 -18
  20. data/lib/cocoapods-core/source/manager.rb +488 -0
  21. data/lib/cocoapods-core/source/metadata.rb +79 -0
  22. data/lib/cocoapods-core/source.rb +241 -70
  23. data/lib/cocoapods-core/specification/consumer.rb +187 -47
  24. data/lib/cocoapods-core/specification/dsl/attribute.rb +49 -85
  25. data/lib/cocoapods-core/specification/dsl/attribute_support.rb +6 -8
  26. data/lib/cocoapods-core/specification/dsl/deprecations.rb +9 -126
  27. data/lib/cocoapods-core/specification/dsl/platform_proxy.rb +30 -20
  28. data/lib/cocoapods-core/specification/dsl.rb +943 -296
  29. data/lib/cocoapods-core/specification/json.rb +64 -23
  30. data/lib/cocoapods-core/specification/linter/analyzer.rb +218 -0
  31. data/lib/cocoapods-core/specification/linter/result.rb +128 -0
  32. data/lib/cocoapods-core/specification/linter.rb +310 -309
  33. data/lib/cocoapods-core/specification/root_attribute_accessors.rb +90 -39
  34. data/lib/cocoapods-core/specification/set/presenter.rb +35 -71
  35. data/lib/cocoapods-core/specification/set.rb +42 -96
  36. data/lib/cocoapods-core/specification.rb +368 -130
  37. data/lib/cocoapods-core/standard_error.rb +45 -24
  38. data/lib/cocoapods-core/trunk_source.rb +14 -0
  39. data/lib/cocoapods-core/vendor/requirement.rb +133 -53
  40. data/lib/cocoapods-core/vendor/version.rb +197 -156
  41. data/lib/cocoapods-core/vendor.rb +1 -5
  42. data/lib/cocoapods-core/version.rb +137 -42
  43. data/lib/cocoapods-core/yaml_helper.rb +334 -0
  44. data/lib/cocoapods-core.rb +10 -4
  45. metadata +100 -27
  46. data/lib/cocoapods-core/source/abstract_data_provider.rb +0 -71
  47. data/lib/cocoapods-core/source/file_system_data_provider.rb +0 -150
  48. data/lib/cocoapods-core/source/github_data_provider.rb +0 -143
  49. data/lib/cocoapods-core/specification/set/statistics.rb +0 -266
  50. data/lib/cocoapods-core/yaml_converter.rb +0 -192
@@ -1,8 +1,7 @@
1
- require 'active_support/core_ext/string/strip.rb'
1
+ require 'cocoapods-core/specification/root_attribute_accessors'
2
2
 
3
3
  module Pod
4
4
  class Specification
5
-
6
5
  # Allows to conveniently access a Specification programmatically.
7
6
  #
8
7
  # It takes care of:
@@ -10,6 +9,7 @@ module Pod
10
9
  # - standardizing the attributes
11
10
  # - handling multi-platform values
12
11
  # - handle default values
12
+ # - handle automatic container wrapping of values
13
13
  # - handle inherited values
14
14
  #
15
15
  # This class allows to store the values of the attributes in the
@@ -18,7 +18,6 @@ module Pod
18
18
  # serializing a specification back exactly as defined in a file.
19
19
  #
20
20
  class Consumer
21
-
22
21
  # @return [Specification] The specification to consume.
23
22
  #
24
23
  attr_reader :spec
@@ -55,11 +54,21 @@ module Pod
55
54
  end
56
55
  end
57
56
 
57
+ DSL::RootAttributesAccessors.instance_methods.each do |root_accessor|
58
+ define_method(root_accessor) do
59
+ spec.root.send(root_accessor)
60
+ end
61
+ end
62
+
58
63
  #-----------------------------------------------------------------------#
59
64
 
60
65
  # @!group Regular attributes
61
66
 
62
- # @return [Bool] Whether the source files of the specification require to
67
+ # @return [String] The name of the specification.
68
+ #
69
+ spec_attr_accessor :name
70
+
71
+ # @return [Boolean] Whether the source files of the specification require to
63
72
  # be compiled with ARC.
64
73
  #
65
74
  spec_attr_accessor :requires_arc
@@ -86,9 +95,24 @@ module Pod
86
95
  spec_attr_accessor :compiler_flags
87
96
 
88
97
  # @return [Hash{String => String}] the xcconfig flags for the current
89
- # specification.
98
+ # specification for the pod target.
99
+ #
100
+ def pod_target_xcconfig
101
+ attr = Specification::DSL.attributes[:pod_target_xcconfig]
102
+ merge_values(attr, value_for_attribute(:xcconfig), value_for_attribute(:pod_target_xcconfig))
103
+ end
104
+
105
+ # @return [Hash{String => String}] the xcconfig flags for the current
106
+ # specification for the user target.
107
+ #
108
+ def user_target_xcconfig
109
+ attr = Specification::DSL.attributes[:user_target_xcconfig]
110
+ merge_values(attr, value_for_attribute(:xcconfig), value_for_attribute(:user_target_xcconfig))
111
+ end
112
+
113
+ # @return [Hash{String => String}] the Info.plist values for the current specification
90
114
  #
91
- spec_attr_accessor :xcconfig
115
+ spec_attr_accessor :info_plist
92
116
 
93
117
  # @return [String] The contents of the prefix header.
94
118
  #
@@ -98,6 +122,14 @@ module Pod
98
122
  #
99
123
  spec_attr_accessor :prefix_header_file
100
124
 
125
+ # @return [String] the module name.
126
+ #
127
+ spec_attr_accessor :module_name
128
+
129
+ # @return [String] the path of the module map file.
130
+ #
131
+ spec_attr_accessor :module_map
132
+
101
133
  # @return [String] the headers directory.
102
134
  #
103
135
  spec_attr_accessor :header_dir
@@ -109,6 +141,23 @@ module Pod
109
141
 
110
142
  #-----------------------------------------------------------------------#
111
143
 
144
+ # @!group Test Support
145
+
146
+ # @return [Boolean] Whether this test specification requires an app host.
147
+ #
148
+ spec_attr_accessor :requires_app_host
149
+ alias_method :requires_app_host?, :requires_app_host
150
+
151
+ # @return [String] Name of the app host this spec requires
152
+ #
153
+ spec_attr_accessor :app_host_name
154
+
155
+ # @return [Symbol] the test type supported by this specification.
156
+ #
157
+ spec_attr_accessor :test_type
158
+
159
+ #-----------------------------------------------------------------------#
160
+
112
161
  # @!group File patterns
113
162
 
114
163
  # @return [Array<String>] the source files of the Pod.
@@ -119,6 +168,10 @@ module Pod
119
168
  #
120
169
  spec_attr_accessor :public_header_files
121
170
 
171
+ # @return [Array<String>] the project headers of the Pod.
172
+ #
173
+ spec_attr_accessor :project_header_files
174
+
122
175
  # @return [Array<String>] the private headers of the Pod.
123
176
  #
124
177
  spec_attr_accessor :private_header_files
@@ -133,12 +186,27 @@ module Pod
133
186
  #
134
187
  spec_attr_accessor :vendored_libraries
135
188
 
136
- # @return [Hash{String=>String}]] hash where the keys are the names of
189
+ # @return [Hash{String => Array<String>}] hash where the keys are the tags of
190
+ # the on demand resources and the values are their relative file
191
+ # patterns.
192
+ #
193
+ spec_attr_accessor :on_demand_resources
194
+
195
+ # @return [Hash{String=>String}]] hash where the keys are the names of
137
196
  # the resource bundles and the values are their relative file
138
197
  # patterns.
139
198
  #
140
199
  spec_attr_accessor :resource_bundles
141
200
 
201
+ # @return [Array<Hash{Symbol=>String}>] An array of hashes where each hash
202
+ # represents a script phase.
203
+ #
204
+ spec_attr_accessor :script_phases
205
+
206
+ # @return [Hash] A hash that contains the scheme configuration.
207
+ #
208
+ spec_attr_accessor :scheme
209
+
142
210
  # @return [Array<String>] A hash where the key represents the
143
211
  # paths of the resources to copy and the values the paths of
144
212
  # the resources that should be copied.
@@ -157,8 +225,6 @@ module Pod
157
225
 
158
226
  #-----------------------------------------------------------------------#
159
227
 
160
- # @!group Dependencies
161
-
162
228
  # @return [Array<Dependency>] the dependencies on other Pods.
163
229
  #
164
230
  def dependencies
@@ -168,10 +234,10 @@ module Pod
168
234
  end
169
235
  end
170
236
 
237
+ # Raw values need to be prepared as soon as they are read so they can be
238
+ # safely merged to support multi platform attributes and inheritance
171
239
  #-----------------------------------------------------------------------#
172
240
 
173
- private
174
-
175
241
  # Returns the value for the attribute with the given name for the
176
242
  # specification. It takes into account inheritance, multi-platform
177
243
  # attributes and default values.
@@ -184,8 +250,8 @@ module Pod
184
250
  def value_for_attribute(attr_name)
185
251
  attr = Specification::DSL.attributes[attr_name]
186
252
  value = value_with_inheritance(spec, attr)
187
- value ||= attr.default(platform_name)
188
- value ||= attr.container.new if attr.container
253
+ value = attr.default(platform_name) if value.nil?
254
+ value = attr.container.new if value.nil? && attr.container
189
255
  value
190
256
  end
191
257
 
@@ -261,12 +327,7 @@ module Pod
261
327
  r.compact
262
328
  elsif attr.container == Hash
263
329
  existing_value.merge(new_value) do |_, old, new|
264
- if new.is_a?(Array) || old.is_a?(Array)
265
- r = [*old] + [*new]
266
- r.compact
267
- else
268
- old + ' ' + new
269
- end
330
+ merge_hash_value(attr, old, new)
270
331
  end
271
332
  else
272
333
  new_value
@@ -285,49 +346,53 @@ module Pod
285
346
  # prepare hook was defined.
286
347
  #
287
348
  def prepare_value(attr, value)
288
- if attr.container == Array
289
- value = [*value].compact
349
+ if attr.container == Array
350
+ value = if value.is_a?(Hash)
351
+ [value]
352
+ else
353
+ [*value].compact
354
+ end
290
355
  end
291
356
 
292
357
  hook_name = prepare_hook_name(attr)
293
358
  if self.respond_to?(hook_name, true)
294
- value = send(hook_name, value)
359
+ send(hook_name, value)
295
360
  else
296
361
  value
297
362
  end
298
363
  end
299
364
 
300
- #-----------------------------------------------------------------------#
301
-
302
365
  private
303
366
 
304
- # Converts the keys of the given hash to a string.
367
+ # Merges two values in a hash together based on the needs of the attribute
305
368
  #
306
- # @todo Removed if not used by `resources_bundle`
369
+ # @param [Specification::DSL::Attribute] attr
370
+ # the attribute for which that value is needed.
307
371
  #
308
- # @param [Object] value
309
- # the value that needs to be stripped from the Symbols.
372
+ # @param [Object] old the value from the original hash
310
373
  #
311
- # @return [Hash] the hash with the strings instead of the keys.
374
+ # @param [Object] new the value from the new hash
312
375
  #
313
- # def convert_keys_to_symbol(value)
314
- # return unless value
315
- # result = {}
316
- # value.each do |key, subvalue|
317
- # subvalue = convert_keys_to_symbol(subvalue) if subvalue.is_a?(Hash)
318
- # result[key.to_sym] = subvalue
319
- # end
320
- # result
321
- # end
322
-
323
- #-----------------------------------------------------------------------#
324
-
325
- private
376
+ # @return [Object] the merged value
377
+ #
378
+ def merge_hash_value(attr, old, new)
379
+ case attr.name
380
+ when :info_plist
381
+ new
382
+ when ->(name) { spec.non_library_specification? && [:pod_target_xcconfig, :user_target_xcconfig, :xcconfig].include?(name) }
383
+ new
384
+ else
385
+ if new.is_a?(Array) || old.is_a?(Array)
386
+ r = Array(old) + Array(new)
387
+ r.compact
388
+ else
389
+ old + ' ' + new
390
+ end
391
+ end
392
+ end
326
393
 
327
394
  # @!group Preparing Values
328
- #
329
- # Raw values need to be prepared as soon as they are read so they can be
330
- # safely merged to support multi platform attributes and inheritance
395
+ #-----------------------------------------------------------------------#
331
396
 
332
397
  # @return [String] the name of the prepare hook for this attribute.
333
398
  #
@@ -347,7 +412,83 @@ module Pod
347
412
  # @return [String] the prefix header.
348
413
  #
349
414
  def _prepare_prefix_header_contents(value)
350
- value.is_a?(Array) ? value * "\n" : value
415
+ if value
416
+ value = value.join("\n") if value.is_a?(Array)
417
+ value.strip_heredoc.chomp
418
+ end
419
+ end
420
+
421
+ # Converts the test type value from a string to a symbol.
422
+ #
423
+ # @param [String, Symbol] value.
424
+ # The value of the test type attributed as specified by the user.
425
+ #
426
+ # @return [Symbol] the test type as a symbol.
427
+ #
428
+ def _prepare_test_type(value)
429
+ if value
430
+ value.to_sym
431
+ end
432
+ end
433
+
434
+ # Converts the array of hashes (script phases) where keys are strings into symbols.
435
+ #
436
+ # @param [Array<Hash{String=>String}>] value.
437
+ # The value of the attribute as specified by the user.
438
+ #
439
+ # @return [Array<Hash{Symbol=>String}>] the script phases array with symbols for each hash instead of strings.
440
+ #
441
+ def _prepare_script_phases(value)
442
+ if value
443
+ value.map do |script_phase|
444
+ if script_phase.is_a?(Hash)
445
+ phase = Specification.convert_keys_to_symbol(script_phase)
446
+ phase[:execution_position] = if phase.key?(:execution_position)
447
+ phase[:execution_position].to_sym
448
+ else
449
+ :any
450
+ end
451
+ phase
452
+ end
453
+ end.compact
454
+ end
455
+ end
456
+
457
+ # Converts the a scheme where keys are strings into symbols.
458
+ #
459
+ # @param [Hash] value.
460
+ # The value of the attribute as specified by the user.
461
+ #
462
+ # @return [Hash] the scheme with symbols as keys instead of strings or `nil` if the value is not a hash.
463
+ #
464
+ def _prepare_scheme(value)
465
+ Specification.convert_keys_to_symbol(value, :recursive => false) if value && value.is_a?(Hash)
466
+ end
467
+
468
+ # Ensures that the file patterns of the on demand resources are contained in
469
+ # an array.
470
+ #
471
+ # @param [String, Array, Hash] value.
472
+ # The value of the attribute as specified by the user.
473
+ #
474
+ # @return [Hash] the on demand resources.
475
+ #
476
+ def _prepare_on_demand_resources(value)
477
+ result = {}
478
+ if value
479
+ value.each do |key, patterns|
480
+ case patterns
481
+ when String, Array
482
+ result[key] = { :paths => [*patterns].compact, :category => :download_on_demand }
483
+ when Hash
484
+ patterns = Specification.convert_keys_to_symbol(patterns, :recursive => false)
485
+ result[key] = { :paths => [*patterns[:paths]].compact, :category => patterns.fetch(:category, :download_on_demand).to_sym }
486
+ else
487
+ raise StandardError, "Unknown on demand resource value type `#{patterns}`."
488
+ end
489
+ end
490
+ end
491
+ result
351
492
  end
352
493
 
353
494
  # Ensures that the file patterns of the resource bundles are contained in
@@ -369,7 +510,6 @@ module Pod
369
510
  end
370
511
 
371
512
  #-----------------------------------------------------------------------#
372
-
373
513
  end
374
514
  end
375
515
  end
@@ -1,14 +1,16 @@
1
1
  module Pod
2
2
  class Specification
3
3
  module DSL
4
-
5
4
  # A Specification attribute stores the information of an attribute. It
6
5
  # also provides logic to implement any required logic.
7
6
  #
8
7
  class Attribute
9
-
10
8
  require 'active_support/inflector/inflections'
11
9
 
10
+ # Spec types currently supported.
11
+ #
12
+ SUPPORTED_SPEC_TYPES = [:library, :app, :test].freeze
13
+
12
14
  # @return [Symbol] the name of the attribute.
13
15
  #
14
16
  attr_reader :name
@@ -31,22 +33,26 @@ module Pod
31
33
  def initialize(name, options)
32
34
  @name = name
33
35
 
34
- @multi_platform = options.delete(:multi_platform) { true }
35
- @inherited = options.delete(:inherited) { false }
36
- @root_only = options.delete(:root_only) { false }
37
- @required = options.delete(:required) { false }
38
- @singularize = options.delete(:singularize) { false }
39
- @file_patterns = options.delete(:file_patterns) { false }
40
- @container = options.delete(:container) { nil }
41
- @keys = options.delete(:keys) { nil }
42
- @default_value = options.delete(:default_value) { nil }
43
- @ios_default = options.delete(:ios_default) { nil }
44
- @osx_default = options.delete(:osx_default) { nil }
45
- @types = options.delete(:types) { [String] }
36
+ @multi_platform = options.delete(:multi_platform) { true }
37
+ @root_only = options.delete(:root_only) { false }
38
+ @spec_types = options.delete(:spec_types) { SUPPORTED_SPEC_TYPES }
39
+ @inherited = options.delete(:inherited) { @root_only }
40
+ @required = options.delete(:required) { false }
41
+ @singularize = options.delete(:singularize) { false }
42
+ @file_patterns = options.delete(:file_patterns) { false }
43
+ @container = options.delete(:container) { nil }
44
+ @keys = options.delete(:keys) { nil }
45
+ @default_value = options.delete(:default_value) { nil }
46
+ @ios_default = options.delete(:ios_default) { nil }
47
+ @osx_default = options.delete(:osx_default) { nil }
48
+ @types = options.delete(:types) { [String] }
46
49
 
47
50
  unless options.empty?
48
51
  raise StandardError, "Unrecognized options: #{options} for #{self}"
49
52
  end
53
+ unless (@spec_types - SUPPORTED_SPEC_TYPES).empty?
54
+ raise StandardError, "Unrecognized spec type option: #{@spec_types} for #{self}"
55
+ end
50
56
  end
51
57
 
52
58
  # @return [String] A string representation suitable for UI.
@@ -109,39 +115,56 @@ module Pod
109
115
  #
110
116
  attr_reader :osx_default
111
117
 
112
- # @return [Bool] whether the specification should be considered invalid
118
+ # @return [Boolean] whether the specification should be considered invalid
113
119
  # if a value for the attribute is not specified.
114
120
  #
115
- def required?; @required; end
121
+ def required?
122
+ @required
123
+ end
116
124
 
117
- # @return [Bool] whether the attribute should be specified only on the
125
+ # @return [Boolean] whether the attribute should be specified only on the
118
126
  # root specification.
119
127
  #
120
- def root_only?; @root_only; end
128
+ def root_only?
129
+ @root_only
130
+ end
131
+
132
+ # @return [Boolean] whether the attribute should be specified only on
133
+ # test specifications.
134
+ #
135
+ def test_only?
136
+ @spec_types == [:test]
137
+ end
121
138
 
122
- # @return [Bool] whether the attribute is multi-platform and should
139
+ # @return [Boolean] whether the attribute is multi-platform and should
123
140
  # work in conjunction with #{PlatformProxy}.
124
141
  #
125
- def multi_platform?; @multi_platform; end
142
+ def multi_platform?
143
+ @multi_platform
144
+ end
126
145
 
127
- # @return [Bool] whether there should be a singular alias for the
146
+ # @return [Boolean] whether there should be a singular alias for the
128
147
  # attribute writer.
129
148
  #
130
- def singularize?; @singularize; end
149
+ def singularize?
150
+ @singularize
151
+ end
131
152
 
132
- # @return [Bool] whether the attribute describes file patterns.
153
+ # @return [Boolean] whether the attribute describes file patterns.
133
154
  #
134
155
  # @note This is mostly used by the linter.
135
156
  #
136
- def file_patterns?; @file_patterns; end
157
+ def file_patterns?
158
+ @file_patterns
159
+ end
137
160
 
138
- # @return [Bool] defines whether the attribute reader should join the
161
+ # @return [Boolean] defines whether the attribute reader should join the
139
162
  # values with the parent.
140
163
  #
141
164
  # @note Attributes stored in wrappers are always inherited.
142
165
  #
143
166
  def inherited?
144
- !root_only? && @inherited
167
+ @inherited
145
168
  end
146
169
 
147
170
  #---------------------------------------------------------------------#
@@ -177,66 +200,7 @@ module Pod
177
200
  def writer_singular_form
178
201
  "#{name.to_s.singularize}=" if singularize?
179
202
  end
180
-
181
- #---------------------------------------------------------------------#
182
-
183
- # @!group Values validation
184
-
185
- # Validates the value for an attribute. This validation should be
186
- # performed before the value is prepared or wrapped.
187
- #
188
- # @note The this is called before preparing the value.
189
- #
190
- # @raise If the type is not in the allowed list.
191
- #
192
- # @return [void]
193
- #
194
- def validate_type(value)
195
- return if value.nil?
196
- unless supported_types.any? { |klass| value.class == klass }
197
- raise StandardError, "Non acceptable type `#{value.class}` for "\
198
- "#{self}. Allowed values: `#{types.inspect}`"
199
- end
200
- end
201
-
202
- # Validates a value before storing.
203
- #
204
- # @raise If a root only attribute is set in a subspec.
205
- #
206
- # @raise If a unknown key is added to a hash.
207
- #
208
- # @return [void]
209
- #
210
- def validate_for_writing(spec, value)
211
- if root_only? && !spec.root?
212
- raise StandardError, "Can't set `#{name}` attribute for " \
213
- "subspecs (in `#{spec.name}`)."
214
- end
215
-
216
- if keys
217
- value.keys.each do |key|
218
- unless allowed_keys.include?(key)
219
- raise StandardError, "Unknown key `#{key}` for "\
220
- "#{self}. Allowed keys: `#{allowed_keys.inspect}`"
221
- end
222
- end
223
- end
224
-
225
- # @return [Array] the flattened list of the allowed keys for the
226
- # hash of a given specification.
227
- #
228
- def allowed_keys
229
- if keys.is_a?(Hash)
230
- keys.keys.concat(keys.values.flatten.compact)
231
- else
232
- keys
233
- end
234
- end
235
- end
236
203
  end
237
-
238
- #-----------------------------------------------------------------------#
239
-
240
204
  end
241
205
  end
242
206
  end
@@ -1,25 +1,23 @@
1
1
  module Pod
2
2
  class Specification
3
3
  module DSL
4
-
5
4
  # @return [Array<Attribute>] The attributes of the class.
6
5
  #
7
- def self.attributes
8
- @attributes
6
+ class << self
7
+ attr_reader :attributes
9
8
  end
10
9
 
11
10
  # This module provides support for storing the runtime information of the
12
11
  # {Specification} DSL.
13
12
  #
14
13
  module AttributeSupport
15
-
16
14
  # Defines a root attribute for the extended class.
17
15
  #
18
16
  # Root attributes make sense only in root specification, they never are
19
- # multiplatform, they don't have inheritance, and they never have a
17
+ # multi-platform, they don't have inheritance, and they never have a
20
18
  # default value.
21
19
  #
22
- # @param [String] name
20
+ # @param [Symbol, String] name
23
21
  # The name of the attribute.
24
22
  #
25
23
  # @param [Hash] options
@@ -35,10 +33,10 @@ module Pod
35
33
 
36
34
  # Defines an attribute for the extended class.
37
35
  #
38
- # Regular attributes in general support inheritance and multi platform
36
+ # Regular attributes in general support inheritance and multi-platform
39
37
  # values, so resolving them for a given specification is not trivial.
40
38
  #
41
- # @param [String] name
39
+ # @param [Symbol, String] name
42
40
  # The name of the attribute.
43
41
  #
44
42
  # @param [Hash] options