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,284 @@
|
|
1
|
+
require 'cocoapods-core/source/validator'
|
2
|
+
|
3
|
+
module Pod
|
4
|
+
|
5
|
+
# The Source class is responsible to manage a collection of podspecs.
|
6
|
+
#
|
7
|
+
# The backing store of the podspecs collection is an implementation detail
|
8
|
+
# abstracted from the rest of CocoaPods.
|
9
|
+
#
|
10
|
+
# The default implementation uses a git repo as a backing store, where the
|
11
|
+
# podspecs are namespaced as:
|
12
|
+
#
|
13
|
+
# "#{SPEC_NAME}/#{VERSION}/#{SPEC_NAME}.podspec"
|
14
|
+
#
|
15
|
+
class Source
|
16
|
+
|
17
|
+
# @return [Pathname] the location of the repo of the source.
|
18
|
+
#
|
19
|
+
attr_reader :repo
|
20
|
+
|
21
|
+
# @param [Pathname] repo @see #repo.
|
22
|
+
#
|
23
|
+
def initialize(repo)
|
24
|
+
@repo = repo
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [String] the name of the source.
|
28
|
+
#
|
29
|
+
def name
|
30
|
+
@repo.basename.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method :to_s, :name
|
34
|
+
|
35
|
+
|
36
|
+
# @return [Integer] compares a source with another one for sorting
|
37
|
+
# purposes.
|
38
|
+
#
|
39
|
+
# @note Source are compared by the alphabetical order of their name, and
|
40
|
+
# this convention should be used in any case where sources need to
|
41
|
+
# be disambiguated.
|
42
|
+
#
|
43
|
+
def <=> (other)
|
44
|
+
name <=> other.name
|
45
|
+
end
|
46
|
+
|
47
|
+
#---------------------------------------------------------------------------#
|
48
|
+
|
49
|
+
# @!group Queering the source
|
50
|
+
|
51
|
+
# @return [Array<String>] the list of the name of all the Pods.
|
52
|
+
#
|
53
|
+
def pods
|
54
|
+
@repo.children.map do |child|
|
55
|
+
child.basename.to_s if child.directory? && child.basename.to_s != '.git'
|
56
|
+
end.compact
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Array<Sets>] the sets of all the Pods.
|
60
|
+
#
|
61
|
+
def pod_sets
|
62
|
+
pods.map { |pod| Specification::Set.new(pod, self) }
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Array<Version>] all the available versions for the Pod, sorted
|
66
|
+
# from highest to lowest.
|
67
|
+
#
|
68
|
+
# @param [String] name
|
69
|
+
# the name of the Pod.
|
70
|
+
#
|
71
|
+
def versions(name)
|
72
|
+
pod_dir = repo + name
|
73
|
+
return unless pod_dir.exist?
|
74
|
+
pod_dir.children.map do |v|
|
75
|
+
basename = v.basename.to_s
|
76
|
+
Version.new(basename) if v.directory? && basename[0,1] != '.'
|
77
|
+
end.compact.sort.reverse
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [Specification] the specification for a given version of Pod.
|
81
|
+
#
|
82
|
+
# @param [String] name
|
83
|
+
# the name of the Pod.
|
84
|
+
#
|
85
|
+
# @param [Version,String] version
|
86
|
+
# the version for the specification.
|
87
|
+
#
|
88
|
+
def specification(name, version)
|
89
|
+
path = repo + name + version.to_s
|
90
|
+
specification_path = path + "#{name}.podspec.yaml"
|
91
|
+
unless specification_path.exist?
|
92
|
+
specification_path = path + "#{name}.podspec"
|
93
|
+
end
|
94
|
+
Specification.from_file(specification_path)
|
95
|
+
end
|
96
|
+
|
97
|
+
# @return [Array<Specification>] all the specifications contained by the
|
98
|
+
# source.
|
99
|
+
#
|
100
|
+
def all_specs
|
101
|
+
specs = pods.map do |name|
|
102
|
+
begin
|
103
|
+
versions(name).map { |version| specification(name, version) }
|
104
|
+
rescue DSLError => e
|
105
|
+
CoreUI.warn "Skipping `#{name}` because the podspec contains errors."
|
106
|
+
next
|
107
|
+
end
|
108
|
+
end
|
109
|
+
specs.flatten.compact
|
110
|
+
end
|
111
|
+
|
112
|
+
#---------------------------------------------------------------------------#
|
113
|
+
|
114
|
+
# @!group Searching the source
|
115
|
+
|
116
|
+
# @return [Set] a set for a given dependency. The set is identified by the
|
117
|
+
# name of the dependency and takes into account subspecs.
|
118
|
+
#
|
119
|
+
def search(dependency)
|
120
|
+
pod_sets.find do |set|
|
121
|
+
# First match the (top level) name, which does not yet load the spec from disk
|
122
|
+
set.name == dependency.root_name &&
|
123
|
+
# Now either check if it's a dependency on the top level spec, or if it's not
|
124
|
+
# check if the requested subspec exists in the top level spec.
|
125
|
+
set.specification.subspec_by_name(dependency.name)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# @return [Array<Set>] The list of the sets that contain the search term.
|
130
|
+
#
|
131
|
+
# @param [String] query
|
132
|
+
# the search term.
|
133
|
+
#
|
134
|
+
# @param [Bool] full_text_search
|
135
|
+
# whether the search should be limited to the name of the Pod or
|
136
|
+
# should include also the author, the summary, and the description.
|
137
|
+
#
|
138
|
+
# @note full text search requires to load the specification for each pod,
|
139
|
+
# hence is considerably slower.
|
140
|
+
#
|
141
|
+
def search_by_name(query, full_text_search = false)
|
142
|
+
pod_sets.map do |set|
|
143
|
+
if full_text_search
|
144
|
+
begin
|
145
|
+
s = set.specification
|
146
|
+
text = "#{s.name} #{s.authors} #{s.summary} #{s.description}"
|
147
|
+
rescue
|
148
|
+
CoreUI.warn "Skipping `#{set.name}` because the podspec contains errors."
|
149
|
+
end
|
150
|
+
else
|
151
|
+
text = set.name
|
152
|
+
end
|
153
|
+
set if text && text.downcase.include?(query.downcase)
|
154
|
+
end.compact
|
155
|
+
end
|
156
|
+
|
157
|
+
#---------------------------------------------------------------------------#
|
158
|
+
|
159
|
+
# @!group Representations
|
160
|
+
|
161
|
+
# @return [Hash{String=>{String=>Specification}}] the static representation
|
162
|
+
# of all the specifications grouped first by name and then by
|
163
|
+
# version.
|
164
|
+
#
|
165
|
+
def to_hash
|
166
|
+
hash = {}
|
167
|
+
all_specs.each do |spec|
|
168
|
+
print '.'
|
169
|
+
hash[spec.name] ||= {}
|
170
|
+
hash[spec.name][spec.version.version] = spec.to_hash
|
171
|
+
end
|
172
|
+
hash
|
173
|
+
end
|
174
|
+
|
175
|
+
# @return [String] the YAML encoded {to_hash} representation.
|
176
|
+
#
|
177
|
+
def to_yaml
|
178
|
+
require 'yaml'
|
179
|
+
to_hash.to_yaml
|
180
|
+
end
|
181
|
+
|
182
|
+
# @return [String] the JSON encoded {to_hash} representation.
|
183
|
+
#
|
184
|
+
def to_json
|
185
|
+
require 'json'
|
186
|
+
to_hash.to_json
|
187
|
+
end
|
188
|
+
|
189
|
+
#-------------------------------------------------------------------------#
|
190
|
+
|
191
|
+
# The Aggregate manages a directory of sources repositories.
|
192
|
+
#
|
193
|
+
class Aggregate
|
194
|
+
|
195
|
+
# @return [Pathname] the directory were the repositories are stored.
|
196
|
+
#
|
197
|
+
attr_reader :repos_dir
|
198
|
+
|
199
|
+
# @param [Pathname] repos_dir @see repos_dir.
|
200
|
+
#
|
201
|
+
def initialize(repos_dir)
|
202
|
+
@repos_dir = repos_dir
|
203
|
+
end
|
204
|
+
|
205
|
+
# @return [Array<Source>] all the sources.
|
206
|
+
#
|
207
|
+
def all
|
208
|
+
@sources ||= dirs.map { |repo| Source.new(repo) }.sort_by(&:name)
|
209
|
+
end
|
210
|
+
|
211
|
+
# @return [Array<String>] the names of all the pods available.
|
212
|
+
#
|
213
|
+
def all_pods
|
214
|
+
all.map(&:pods).flatten.uniq
|
215
|
+
end
|
216
|
+
|
217
|
+
# @return [Array<Set>] the sets for all the pods available.
|
218
|
+
#
|
219
|
+
# @note Implementation detail: The sources don't cache their values
|
220
|
+
# because they might change in response to an update. Therefore
|
221
|
+
# this method to prevent slowness caches the values before
|
222
|
+
# processing them.
|
223
|
+
#
|
224
|
+
def all_sets
|
225
|
+
pods_by_source = {}
|
226
|
+
all.each do |source|
|
227
|
+
pods_by_source[source] = source.pods
|
228
|
+
end
|
229
|
+
sources = pods_by_source.keys
|
230
|
+
pods = pods_by_source.values.flatten.uniq
|
231
|
+
|
232
|
+
pods.map do |pod|
|
233
|
+
pod_sources = sources.select{ |s| pods_by_source[s].include?(pod) }.compact
|
234
|
+
Specification::Set.new(pod, pod_sources)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# @return [Set, nil] a set for a given dependency including all the
|
239
|
+
# {Source} that contain the Pod. If no sources containing the
|
240
|
+
# Pod where found it returns nil.
|
241
|
+
#
|
242
|
+
# @raise If no source including the set can be found.
|
243
|
+
#
|
244
|
+
# @see Source#search
|
245
|
+
#
|
246
|
+
def search(dependency)
|
247
|
+
sources = all.select { |s| !s.search(dependency).nil? }
|
248
|
+
Specification::Set.new(dependency.root_name, sources) unless sources.empty?
|
249
|
+
end
|
250
|
+
|
251
|
+
# @return [Array<Set>] the sets that contain the search term.
|
252
|
+
#
|
253
|
+
# @raise If no source including the set can be found.
|
254
|
+
#
|
255
|
+
# @see Source#search_by_name
|
256
|
+
#
|
257
|
+
def search_by_name(query, full_text_search = false)
|
258
|
+
pods_by_source = {}
|
259
|
+
result = []
|
260
|
+
all.each { |s| pods_by_source[s] = s.search_by_name(query, full_text_search).map(&:name) }
|
261
|
+
root_spec_names = pods_by_source.values.flatten.uniq
|
262
|
+
root_spec_names.each do |pod|
|
263
|
+
sources = []
|
264
|
+
pods_by_source.each{ |source, pods| sources << source if pods.include?(pod) }
|
265
|
+
result << Specification::Set.new(pod, sources)
|
266
|
+
end
|
267
|
+
if result.empty?
|
268
|
+
extra = ", author, summary, or description" if full_text_search
|
269
|
+
raise(Informative, "Unable to find a pod with name" \
|
270
|
+
"#{extra} matching `#{query}'")
|
271
|
+
end
|
272
|
+
result
|
273
|
+
end
|
274
|
+
|
275
|
+
# @return [Array<Pathname>] the directories where the sources are stored.
|
276
|
+
#
|
277
|
+
# @raise If the repos dir doesn't exits.
|
278
|
+
#
|
279
|
+
def dirs
|
280
|
+
repos_dir.children.select(&:directory?)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
@@ -0,0 +1,356 @@
|
|
1
|
+
require 'active_support/core_ext/string/strip.rb'
|
2
|
+
|
3
|
+
module Pod
|
4
|
+
class Specification
|
5
|
+
|
6
|
+
# Allows to conveniently access a Specification programmatically.
|
7
|
+
#
|
8
|
+
# It takes care of:
|
9
|
+
#
|
10
|
+
# - standardizing the attributes
|
11
|
+
# - handling multi-platform values
|
12
|
+
# - handle default values
|
13
|
+
# - handle inherited values
|
14
|
+
#
|
15
|
+
# This class allows to store the values of the attributes in the
|
16
|
+
# Specification as specified in the DSL. The benefits is reduced reliance
|
17
|
+
# on meta programming to access the attributes and the possibility of
|
18
|
+
# serializing a specification back exactly as defined in a file.
|
19
|
+
#
|
20
|
+
class Consumer
|
21
|
+
|
22
|
+
# @return [Specification] The specification to consume.
|
23
|
+
#
|
24
|
+
attr_reader :spec
|
25
|
+
|
26
|
+
# @return [Symbol] The name of the platform for which the specification
|
27
|
+
# needs to be consumed.
|
28
|
+
#
|
29
|
+
attr_reader :platform_name
|
30
|
+
|
31
|
+
# @param [Specification] spec @see spec
|
32
|
+
# @param [Symbol, Platform] platform
|
33
|
+
# The platform for which the specification needs to be consumed.
|
34
|
+
#
|
35
|
+
def initialize(spec, platform)
|
36
|
+
@spec = spec
|
37
|
+
@platform_name = platform.is_a?(Symbol) ? platform : platform.name
|
38
|
+
|
39
|
+
unless spec.supported_on_platform?(platform)
|
40
|
+
raise StandardError, "#{to_s} is not compatible with #{platform}."
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Creates a method to access the contents of the attribute.
|
45
|
+
#
|
46
|
+
# @param [Symbol] name
|
47
|
+
# the name of the attribute.
|
48
|
+
#
|
49
|
+
# @macro [attach]
|
50
|
+
# @!method $1
|
51
|
+
#
|
52
|
+
def self.spec_attr_accessor(name)
|
53
|
+
define_method(name) do
|
54
|
+
value_for_attribute(name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
#-----------------------------------------------------------------------#
|
59
|
+
|
60
|
+
# @!group Regular attributes
|
61
|
+
|
62
|
+
# @return [Bool] Whether the source files of the specification require to
|
63
|
+
# be compiled with ARC.
|
64
|
+
#
|
65
|
+
spec_attr_accessor :requires_arc
|
66
|
+
alias_method :requires_arc?, :requires_arc
|
67
|
+
|
68
|
+
# @return [Array<String>] A list of frameworks that the user’s target
|
69
|
+
# needs to link against
|
70
|
+
#
|
71
|
+
spec_attr_accessor :frameworks
|
72
|
+
|
73
|
+
# @return [Array<String>] A list of frameworks that the user’s target
|
74
|
+
# needs to **weakly** link against
|
75
|
+
#
|
76
|
+
spec_attr_accessor :weak_frameworks
|
77
|
+
|
78
|
+
# @return [Array<String>] A list of libraries that the user’s target
|
79
|
+
# needs to link against
|
80
|
+
#
|
81
|
+
spec_attr_accessor :libraries
|
82
|
+
|
83
|
+
# @return [Array<String>] the list of compiler flags needed by the
|
84
|
+
# specification files.
|
85
|
+
#
|
86
|
+
spec_attr_accessor :compiler_flags
|
87
|
+
|
88
|
+
# @return [Hash{String => String}] the xcconfig flags for the current
|
89
|
+
# specification.
|
90
|
+
#
|
91
|
+
spec_attr_accessor :xcconfig
|
92
|
+
|
93
|
+
# @return [String] The contents of the prefix header.
|
94
|
+
#
|
95
|
+
spec_attr_accessor :prefix_header_contents
|
96
|
+
|
97
|
+
# @return [String] The path of the prefix header file.
|
98
|
+
#
|
99
|
+
spec_attr_accessor :prefix_header_file
|
100
|
+
|
101
|
+
# @return [String] the headers directory.
|
102
|
+
#
|
103
|
+
spec_attr_accessor :header_dir
|
104
|
+
|
105
|
+
# @return [String] the directory from where to preserve the headers
|
106
|
+
# namespacing.
|
107
|
+
#
|
108
|
+
spec_attr_accessor :header_mappings_dir
|
109
|
+
|
110
|
+
#-----------------------------------------------------------------------#
|
111
|
+
|
112
|
+
# @!group File patterns
|
113
|
+
|
114
|
+
# @return [Array<String>] the source files of the Pod.
|
115
|
+
#
|
116
|
+
spec_attr_accessor :source_files
|
117
|
+
|
118
|
+
# @return [Array<String>] the public headers of the Pod.
|
119
|
+
#
|
120
|
+
spec_attr_accessor :public_header_files
|
121
|
+
|
122
|
+
# @return [Array<String>] A hash where the key represents the
|
123
|
+
# paths of the resources to copy and the values the paths of
|
124
|
+
# the resources that should be copied.
|
125
|
+
#
|
126
|
+
spec_attr_accessor :resources
|
127
|
+
|
128
|
+
# @return [Array<String>] The file patterns that the
|
129
|
+
# Pod should ignore.
|
130
|
+
#
|
131
|
+
spec_attr_accessor :exclude_files
|
132
|
+
|
133
|
+
# @return [Array<String>] The paths that should be not
|
134
|
+
# cleaned.
|
135
|
+
#
|
136
|
+
spec_attr_accessor :preserve_paths
|
137
|
+
|
138
|
+
#-----------------------------------------------------------------------#
|
139
|
+
|
140
|
+
# @!group Dependencies
|
141
|
+
|
142
|
+
# @return [Array<Dependency>] the dependencies on other Pods.
|
143
|
+
#
|
144
|
+
def dependencies
|
145
|
+
value = value_for_attribute(:dependencies)
|
146
|
+
value.map do |name, requirements|
|
147
|
+
Dependency.new(name, requirements)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
#-----------------------------------------------------------------------#
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
# Returns the value for the attribute with the given name for the
|
156
|
+
# specification. It takes into account inheritance, multi-platform
|
157
|
+
# attributes and default values.
|
158
|
+
#
|
159
|
+
# @param [Symbol] attr_name
|
160
|
+
# The name of the attribute.
|
161
|
+
#
|
162
|
+
# @return [String, Array, Hash] the value for the attribute.
|
163
|
+
#
|
164
|
+
def value_for_attribute(attr_name)
|
165
|
+
attr = Specification::DSL.attributes[attr_name]
|
166
|
+
value = value_with_inheritance(spec, attr)
|
167
|
+
value ||= attr.default(platform_name)
|
168
|
+
value ||= attr.container.new if attr.container
|
169
|
+
value
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns the value of a given attribute taking into account inheritance.
|
173
|
+
#
|
174
|
+
# @param [Specification] the_spec
|
175
|
+
# the specification for which the value is needed.
|
176
|
+
#
|
177
|
+
# @param [Specification::DSL::Attribute] attr
|
178
|
+
# the attribute for which that value is needed.
|
179
|
+
#
|
180
|
+
# @return [String, Array, Hash] the value for the attribute.
|
181
|
+
#
|
182
|
+
def value_with_inheritance(the_spec, attr)
|
183
|
+
value = raw_value_for_attribute(the_spec, attr)
|
184
|
+
if the_spec.root? || !attr.inherited?
|
185
|
+
return value
|
186
|
+
end
|
187
|
+
|
188
|
+
parent_value = value_with_inheritance(the_spec.parent, attr)
|
189
|
+
merge_values(attr, parent_value, value)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Returns the value of a given attribute taking into account multi
|
193
|
+
# platform values.
|
194
|
+
#
|
195
|
+
# @param [Specification] the_spec
|
196
|
+
# the specification for which the value is needed.
|
197
|
+
#
|
198
|
+
# @param [Specification::DSL::Attribute] attr
|
199
|
+
# the attribute for which that value is needed.
|
200
|
+
#
|
201
|
+
# @return [String, Array, Hash] The value for an attribute.
|
202
|
+
#
|
203
|
+
def raw_value_for_attribute(the_spec, attr)
|
204
|
+
value = the_spec.attributes_hash[attr.name.to_s]
|
205
|
+
value = prepare_value(attr, value)
|
206
|
+
|
207
|
+
if attr.multi_platform? && the_spec.attributes_hash[platform_name.to_s]
|
208
|
+
platform_value = the_spec.attributes_hash[platform_name.to_s][attr.name.to_s]
|
209
|
+
platform_value = prepare_value(attr, platform_value)
|
210
|
+
value = merge_values(attr, value, platform_value)
|
211
|
+
end
|
212
|
+
value
|
213
|
+
end
|
214
|
+
|
215
|
+
# Merges the values of an attribute, either because the attribute is
|
216
|
+
# multi platform or because it is inherited.
|
217
|
+
#
|
218
|
+
# @param [Specification::DSL::Attribute] attr
|
219
|
+
# the attribute for which that value is needed.
|
220
|
+
#
|
221
|
+
# @param [String, Array, Hash] existing_value
|
222
|
+
# the current value (the value of the parent or non-multiplatform
|
223
|
+
# value).
|
224
|
+
#
|
225
|
+
# @param [String, Array, Hash] new_value
|
226
|
+
# the value to append (the value of the spec or the
|
227
|
+
# multi-platform value).
|
228
|
+
#
|
229
|
+
# @return [String, Array, Hash] The merged value.
|
230
|
+
#
|
231
|
+
def merge_values(attr, existing_value, new_value)
|
232
|
+
return existing_value if new_value.nil?
|
233
|
+
return new_value if existing_value.nil?
|
234
|
+
|
235
|
+
if attr.types.include?(TrueClass)
|
236
|
+
new_value.nil? ? existing_value : new_value
|
237
|
+
elsif attr.container == Array
|
238
|
+
r = [*existing_value] + [*new_value]
|
239
|
+
r.compact
|
240
|
+
elsif attr.container == Hash
|
241
|
+
existing_value = existing_value.merge(new_value) do |_, old, new|
|
242
|
+
if new.is_a?(Array) || old.is_a?(Array)
|
243
|
+
r = [*old] + [*new]
|
244
|
+
r.compact
|
245
|
+
else
|
246
|
+
old + ' ' + new
|
247
|
+
end
|
248
|
+
end
|
249
|
+
else
|
250
|
+
value
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# Wraps a value in an Array if needed and calls the prepare hook to
|
255
|
+
# allow further customization of a value before storing it in the
|
256
|
+
# instance variable.
|
257
|
+
#
|
258
|
+
# @note Only array containers are wrapped. To automatically wrap
|
259
|
+
# values for attributes with hash containers a prepare hook
|
260
|
+
# should be used.
|
261
|
+
#
|
262
|
+
# @return [Object] the customized value of the original one if no
|
263
|
+
# prepare hook was defined.
|
264
|
+
#
|
265
|
+
def prepare_value(attr, value)
|
266
|
+
if attr.container == Array
|
267
|
+
if value.class == Rake::FileList
|
268
|
+
value = [value]
|
269
|
+
else
|
270
|
+
value = [*value].compact
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
hook_name = prepare_hook_name(attr)
|
275
|
+
if self.respond_to?(hook_name, true)
|
276
|
+
value = self.send(hook_name, value)
|
277
|
+
else
|
278
|
+
value
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
#-----------------------------------------------------------------------#
|
283
|
+
|
284
|
+
private
|
285
|
+
|
286
|
+
# Converts the keys of the given hash to a string.
|
287
|
+
#
|
288
|
+
# @todo Removed if not used by `resources_bundle`
|
289
|
+
#
|
290
|
+
# @param [Object] value
|
291
|
+
# the value that needs to be stripped from the Symbols.
|
292
|
+
#
|
293
|
+
# @return [Hash] the hash with the strings instead of the keys.
|
294
|
+
#
|
295
|
+
# def convert_keys_to_symbol(value)
|
296
|
+
# return unless value
|
297
|
+
# result = {}
|
298
|
+
# value.each do |key, subvalue|
|
299
|
+
# subvalue = convert_keys_to_symbol(subvalue) if subvalue.is_a?(Hash)
|
300
|
+
# result[key.to_sym] = subvalue
|
301
|
+
# end
|
302
|
+
# result
|
303
|
+
# end
|
304
|
+
|
305
|
+
#-----------------------------------------------------------------------#
|
306
|
+
|
307
|
+
private
|
308
|
+
|
309
|
+
# @!group Preparing Values
|
310
|
+
#
|
311
|
+
# Raw values need to be prepared as soon as they are read so they can be
|
312
|
+
# safely merged to support multi platform attributes and inheritance
|
313
|
+
|
314
|
+
# @return [String] the name of the prepare hook for this attribute.
|
315
|
+
#
|
316
|
+
# @note The hook is called after the value has been wrapped in an
|
317
|
+
# array (if needed according to the container) but before
|
318
|
+
# validation.
|
319
|
+
#
|
320
|
+
def prepare_hook_name(attr)
|
321
|
+
"_prepare_#{attr.name}"
|
322
|
+
end
|
323
|
+
|
324
|
+
# Converts the prefix header to a string if specified as an array.
|
325
|
+
#
|
326
|
+
# @param [String, Array] value.
|
327
|
+
# The value of the attribute as specified by the user.
|
328
|
+
#
|
329
|
+
# @return [String] the prefix header.
|
330
|
+
#
|
331
|
+
def _prepare_prefix_header_contents(value)
|
332
|
+
value.is_a?(Array) ? value * "\n" : value
|
333
|
+
end
|
334
|
+
|
335
|
+
# Converts the resources file patterns to a hash defaulting to the
|
336
|
+
# resource key if they are defined as an Array or a String.
|
337
|
+
#
|
338
|
+
# @param [String, Array, Hash] value.
|
339
|
+
# The value of the attribute as specified by the user.
|
340
|
+
#
|
341
|
+
# @return [Hash] the resources.
|
342
|
+
#
|
343
|
+
# def _prepare_resources_bundle(value)
|
344
|
+
# value = { :resources => value } unless value.is_a?(Hash)
|
345
|
+
# result = {}
|
346
|
+
# value.each do |key, patterns|
|
347
|
+
# result[key] = [*patterns].compact
|
348
|
+
# end
|
349
|
+
# result
|
350
|
+
# end
|
351
|
+
|
352
|
+
#-----------------------------------------------------------------------#
|
353
|
+
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|