plasmo_xcodeproj 1.21.1
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 +19 -0
- data/README.md +95 -0
- data/bin/xcodeproj +10 -0
- data/lib/xcodeproj/command/config_dump.rb +91 -0
- data/lib/xcodeproj/command/project_diff.rb +56 -0
- data/lib/xcodeproj/command/show.rb +60 -0
- data/lib/xcodeproj/command/sort.rb +44 -0
- data/lib/xcodeproj/command/target_diff.rb +43 -0
- data/lib/xcodeproj/command.rb +63 -0
- data/lib/xcodeproj/config/other_linker_flags_parser.rb +73 -0
- data/lib/xcodeproj/config.rb +386 -0
- data/lib/xcodeproj/constants.rb +465 -0
- data/lib/xcodeproj/differ.rb +239 -0
- data/lib/xcodeproj/gem_version.rb +5 -0
- data/lib/xcodeproj/helper.rb +30 -0
- data/lib/xcodeproj/plist.rb +94 -0
- data/lib/xcodeproj/project/case_converter.rb +90 -0
- data/lib/xcodeproj/project/object/build_configuration.rb +255 -0
- data/lib/xcodeproj/project/object/build_file.rb +84 -0
- data/lib/xcodeproj/project/object/build_phase.rb +369 -0
- data/lib/xcodeproj/project/object/build_rule.rb +109 -0
- data/lib/xcodeproj/project/object/configuration_list.rb +117 -0
- data/lib/xcodeproj/project/object/container_item_proxy.rb +116 -0
- data/lib/xcodeproj/project/object/file_reference.rb +338 -0
- data/lib/xcodeproj/project/object/group.rb +506 -0
- data/lib/xcodeproj/project/object/helpers/build_settings_array_settings_by_object_version.rb +72 -0
- data/lib/xcodeproj/project/object/helpers/file_references_factory.rb +245 -0
- data/lib/xcodeproj/project/object/helpers/groupable_helper.rb +260 -0
- data/lib/xcodeproj/project/object/native_target.rb +751 -0
- data/lib/xcodeproj/project/object/reference_proxy.rb +86 -0
- data/lib/xcodeproj/project/object/root_object.rb +100 -0
- data/lib/xcodeproj/project/object/swift_package_product_dependency.rb +29 -0
- data/lib/xcodeproj/project/object/swift_package_remote_reference.rb +33 -0
- data/lib/xcodeproj/project/object/target_dependency.rb +94 -0
- data/lib/xcodeproj/project/object.rb +534 -0
- data/lib/xcodeproj/project/object_attributes.rb +522 -0
- data/lib/xcodeproj/project/object_dictionary.rb +210 -0
- data/lib/xcodeproj/project/object_list.rb +223 -0
- data/lib/xcodeproj/project/project_helper.rb +341 -0
- data/lib/xcodeproj/project/uuid_generator.rb +132 -0
- data/lib/xcodeproj/project.rb +874 -0
- data/lib/xcodeproj/scheme/abstract_scheme_action.rb +100 -0
- data/lib/xcodeproj/scheme/analyze_action.rb +19 -0
- data/lib/xcodeproj/scheme/archive_action.rb +59 -0
- data/lib/xcodeproj/scheme/build_action.rb +298 -0
- data/lib/xcodeproj/scheme/buildable_product_runnable.rb +55 -0
- data/lib/xcodeproj/scheme/buildable_reference.rb +129 -0
- data/lib/xcodeproj/scheme/command_line_arguments.rb +162 -0
- data/lib/xcodeproj/scheme/environment_variables.rb +170 -0
- data/lib/xcodeproj/scheme/execution_action.rb +86 -0
- data/lib/xcodeproj/scheme/launch_action.rb +179 -0
- data/lib/xcodeproj/scheme/location_scenario_reference.rb +49 -0
- data/lib/xcodeproj/scheme/macro_expansion.rb +34 -0
- data/lib/xcodeproj/scheme/profile_action.rb +57 -0
- data/lib/xcodeproj/scheme/remote_runnable.rb +92 -0
- data/lib/xcodeproj/scheme/send_email_action_content.rb +84 -0
- data/lib/xcodeproj/scheme/shell_script_action_content.rb +77 -0
- data/lib/xcodeproj/scheme/test_action.rb +394 -0
- data/lib/xcodeproj/scheme/xml_element_wrapper.rb +82 -0
- data/lib/xcodeproj/scheme.rb +375 -0
- data/lib/xcodeproj/user_interface.rb +22 -0
- data/lib/xcodeproj/workspace/file_reference.rb +79 -0
- data/lib/xcodeproj/workspace/group_reference.rb +67 -0
- data/lib/xcodeproj/workspace/reference.rb +40 -0
- data/lib/xcodeproj/workspace.rb +277 -0
- data/lib/xcodeproj/xcodebuild_helper.rb +108 -0
- data/lib/xcodeproj.rb +29 -0
- metadata +208 -0
@@ -0,0 +1,239 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
# Computes the recursive diff of Hashes, Array and other objects.
|
3
|
+
#
|
4
|
+
# Useful to compare two projects. Inspired from
|
5
|
+
# 'active_support/core_ext/hash/diff'.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# h1 = { :common => 'value', :changed => 'v1' }
|
9
|
+
# h2 = { :common => 'value', :changed => 'v2', :addition => 'new_value' }
|
10
|
+
# h1.recursive_diff(h2) == {
|
11
|
+
# :changed => {
|
12
|
+
# :self => 'v1',
|
13
|
+
# :other => 'v2'
|
14
|
+
# },
|
15
|
+
# :addition => {
|
16
|
+
# :self => nil,
|
17
|
+
# :other => 'new_value'
|
18
|
+
# }
|
19
|
+
# } #=> true
|
20
|
+
#
|
21
|
+
#
|
22
|
+
#
|
23
|
+
#
|
24
|
+
module Differ
|
25
|
+
# Computes the recursive difference of two given values.
|
26
|
+
#
|
27
|
+
# @param [Object] value_1
|
28
|
+
# The first value to compare.
|
29
|
+
#
|
30
|
+
# @param [Object] value_2
|
31
|
+
# The second value to compare.
|
32
|
+
#
|
33
|
+
# @param [Object] key_1
|
34
|
+
# The key for the diff of value_1.
|
35
|
+
#
|
36
|
+
# @param [Object] key_2
|
37
|
+
# The key for the diff of value_2.
|
38
|
+
#
|
39
|
+
# @param [Object] id_key
|
40
|
+
# The key used to identify correspondent hashes in an array.
|
41
|
+
#
|
42
|
+
# @return [Hash] The diff
|
43
|
+
# @return [Nil] if the given values are equal.
|
44
|
+
#
|
45
|
+
def self.diff(value_1, value_2, options = {})
|
46
|
+
options[:key_1] ||= 'value_1'
|
47
|
+
options[:key_2] ||= 'value_2'
|
48
|
+
options[:id_key] ||= nil
|
49
|
+
|
50
|
+
method = if value_1.class == value_2.class
|
51
|
+
case value_1
|
52
|
+
when Hash then :hash_diff
|
53
|
+
when Array then :array_diff
|
54
|
+
else :generic_diff
|
55
|
+
end
|
56
|
+
else
|
57
|
+
:generic_diff
|
58
|
+
end
|
59
|
+
send(method, value_1, value_2, options)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Optimized for reducing the noise from the tree hash of projects
|
63
|
+
#
|
64
|
+
def self.project_diff(project_1, project_2, key_1 = 'project_1', key_2 = 'project_2')
|
65
|
+
project_1 = project_1.to_tree_hash unless project_1.is_a?(Hash)
|
66
|
+
project_2 = project_2.to_tree_hash unless project_2.is_a?(Hash)
|
67
|
+
options = {
|
68
|
+
:key_1 => key_1,
|
69
|
+
:key_2 => key_2,
|
70
|
+
:id_key => 'displayName',
|
71
|
+
}
|
72
|
+
diff(project_1, project_2, options)
|
73
|
+
end
|
74
|
+
|
75
|
+
#-------------------------------------------------------------------------#
|
76
|
+
|
77
|
+
public
|
78
|
+
|
79
|
+
# @!group Type specific handlers
|
80
|
+
|
81
|
+
# Computes the recursive difference of two hashes.
|
82
|
+
#
|
83
|
+
# @see diff
|
84
|
+
#
|
85
|
+
def self.hash_diff(value_1, value_2, options)
|
86
|
+
ensure_class(value_1, Hash)
|
87
|
+
ensure_class(value_2, Hash)
|
88
|
+
return nil if value_1 == value_2
|
89
|
+
|
90
|
+
result = {}
|
91
|
+
all_keys = (value_1.keys + value_2.keys).uniq
|
92
|
+
all_keys.each do |key|
|
93
|
+
key_value_1 = value_1[key]
|
94
|
+
key_value_2 = value_2[key]
|
95
|
+
diff = diff(key_value_1, key_value_2, options)
|
96
|
+
if diff
|
97
|
+
result[key] = diff if diff
|
98
|
+
end
|
99
|
+
end
|
100
|
+
if result.empty?
|
101
|
+
nil
|
102
|
+
else
|
103
|
+
result
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns the recursive diff of two arrays.
|
108
|
+
#
|
109
|
+
# @see diff
|
110
|
+
#
|
111
|
+
def self.array_diff(value_1, value_2, options)
|
112
|
+
ensure_class(value_1, Array)
|
113
|
+
ensure_class(value_2, Array)
|
114
|
+
return nil if value_1 == value_2
|
115
|
+
|
116
|
+
new_objects_value_1 = (value_1 - value_2)
|
117
|
+
new_objects_value_2 = (value_2 - value_1)
|
118
|
+
return nil if value_1.empty? && value_2.empty?
|
119
|
+
|
120
|
+
matched_diff = {}
|
121
|
+
if id_key = options[:id_key]
|
122
|
+
matched_value_1 = []
|
123
|
+
matched_value_2 = []
|
124
|
+
new_objects_value_1.each do |entry_value_1|
|
125
|
+
if entry_value_1.is_a?(Hash)
|
126
|
+
id_value = entry_value_1[id_key]
|
127
|
+
entry_value_2 = new_objects_value_2.find do |entry|
|
128
|
+
entry[id_key] == id_value
|
129
|
+
end
|
130
|
+
if entry_value_2
|
131
|
+
matched_value_1 << entry_value_1
|
132
|
+
matched_value_2 << entry_value_2
|
133
|
+
diff = diff(entry_value_1, entry_value_2, options)
|
134
|
+
matched_diff[id_value] = diff if diff
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
new_objects_value_1 -= matched_value_1
|
140
|
+
new_objects_value_2 -= matched_value_2
|
141
|
+
end
|
142
|
+
|
143
|
+
if new_objects_value_1.empty? && new_objects_value_2.empty?
|
144
|
+
if matched_diff.empty?
|
145
|
+
nil
|
146
|
+
else
|
147
|
+
matched_diff
|
148
|
+
end
|
149
|
+
else
|
150
|
+
result = {}
|
151
|
+
result[options[:key_1]] = new_objects_value_1 unless new_objects_value_1.empty?
|
152
|
+
result[options[:key_2]] = new_objects_value_2 unless new_objects_value_2.empty?
|
153
|
+
result[:diff] = matched_diff unless matched_diff.empty?
|
154
|
+
result
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns the diff of two generic objects.
|
159
|
+
#
|
160
|
+
# @see diff
|
161
|
+
#
|
162
|
+
def self.generic_diff(value_1, value_2, options)
|
163
|
+
return nil if value_1 == value_2
|
164
|
+
|
165
|
+
{
|
166
|
+
options[:key_1] => value_1,
|
167
|
+
options[:key_2] => value_2,
|
168
|
+
}
|
169
|
+
end
|
170
|
+
|
171
|
+
#-------------------------------------------------------------------------#
|
172
|
+
|
173
|
+
public
|
174
|
+
|
175
|
+
# @!group Cleaning
|
176
|
+
|
177
|
+
# Returns a copy of the hash where the given key is removed recursively.
|
178
|
+
#
|
179
|
+
# @param [Hash] hash
|
180
|
+
# The hash to clean
|
181
|
+
#
|
182
|
+
# @param [Object] key
|
183
|
+
# The key to remove.
|
184
|
+
#
|
185
|
+
# @return [Hash] A copy of the hash without the key.
|
186
|
+
#
|
187
|
+
def self.clean_hash(hash, key)
|
188
|
+
new_hash = hash.dup
|
189
|
+
self.clean_hash!(new_hash, key)
|
190
|
+
new_hash
|
191
|
+
end
|
192
|
+
|
193
|
+
# Recursively cleans a key from the given hash.
|
194
|
+
#
|
195
|
+
# @param [Hash] hash
|
196
|
+
# The hash to clean
|
197
|
+
#
|
198
|
+
# @param [Object] key
|
199
|
+
# The key to remove.
|
200
|
+
#
|
201
|
+
# @return [void]
|
202
|
+
#
|
203
|
+
def self.clean_hash!(hash, key)
|
204
|
+
hash.delete(key)
|
205
|
+
hash.each do |_, value|
|
206
|
+
case value
|
207
|
+
when Hash
|
208
|
+
clean_hash!(value, key)
|
209
|
+
when Array
|
210
|
+
value.each { |entry| clean_hash!(entry, key) if entry.is_a?(Hash) }
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
#-------------------------------------------------------------------------#
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
# @! Helpers
|
220
|
+
|
221
|
+
# Ensures that the given object belongs to the given class.
|
222
|
+
#
|
223
|
+
# @param [Object] object
|
224
|
+
# The object to check.
|
225
|
+
#
|
226
|
+
# @param [Class] klass
|
227
|
+
# the expected class of the object.
|
228
|
+
#
|
229
|
+
# @raise If the object doesn't belong to the given class.
|
230
|
+
#
|
231
|
+
# @return [void]
|
232
|
+
#
|
233
|
+
def self.ensure_class(object, klass)
|
234
|
+
raise "Wrong type `#{object.inspect}`" unless object.is_a?(klass)
|
235
|
+
end
|
236
|
+
|
237
|
+
#-------------------------------------------------------------------------#
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
module Helper
|
3
|
+
class TargetDiff
|
4
|
+
attr_reader :project, :target1, :target2
|
5
|
+
|
6
|
+
def initialize(project, target1_name, target2_name)
|
7
|
+
@project = project
|
8
|
+
unless @target1 = @project.targets.find { |target| target.name == target1_name }
|
9
|
+
raise ArgumentError, "Target 1 by name `#{target1_name}' not found in the project."
|
10
|
+
end
|
11
|
+
unless @target2 = @project.targets.find { |target| target.name == target2_name }
|
12
|
+
raise ArgumentError, "Target 1 by name `#{target2_name}' not found in the project."
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Array<PBXBuildFile>] A list of source files (that will be
|
17
|
+
# compiled) which are in ‘target 2’ but not in ‘target 1’. The
|
18
|
+
# list is sorted by file path.
|
19
|
+
#
|
20
|
+
def new_source_build_files
|
21
|
+
new = @target2.source_build_phase.files.reject do |target2_build_file|
|
22
|
+
@target1.source_build_phase.files.any? do |target1_build_file|
|
23
|
+
target1_build_file.file_ref.path == target2_build_file.file_ref.path
|
24
|
+
end
|
25
|
+
end
|
26
|
+
new.sort_by { |build_file| build_file.file_ref.path }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
autoload :Nanaimo, 'nanaimo'
|
2
|
+
autoload :CFPropertyList, 'cfpropertylist'
|
3
|
+
|
4
|
+
module Xcodeproj
|
5
|
+
# Provides support for loading and serializing property list files.
|
6
|
+
#
|
7
|
+
module Plist
|
8
|
+
# @return [Hash] Returns the native objects loaded from a property list
|
9
|
+
# file.
|
10
|
+
#
|
11
|
+
# @param [#to_s] path
|
12
|
+
# The path of the file.
|
13
|
+
#
|
14
|
+
def self.read_from_path(path)
|
15
|
+
path = path.to_s
|
16
|
+
unless File.exist?(path)
|
17
|
+
raise Informative, "The plist file at path `#{path}` doesn't exist."
|
18
|
+
end
|
19
|
+
contents = File.read(path)
|
20
|
+
if file_in_conflict?(contents)
|
21
|
+
raise Informative, "The file `#{path}` is in a merge conflict."
|
22
|
+
end
|
23
|
+
case Nanaimo::Reader.plist_type(contents)
|
24
|
+
when :xml, :binary
|
25
|
+
CFPropertyList.native_types(CFPropertyList::List.new(:data => contents).value)
|
26
|
+
else
|
27
|
+
Nanaimo::Reader.new(contents).parse!.as_ruby
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Serializes a hash as an XML property list file.
|
32
|
+
#
|
33
|
+
# @param [#to_hash] hash
|
34
|
+
# The hash to store.
|
35
|
+
#
|
36
|
+
# @param [#to_s] path
|
37
|
+
# The path of the file.
|
38
|
+
#
|
39
|
+
def self.write_to_path(hash, path)
|
40
|
+
if hash.respond_to?(:to_hash)
|
41
|
+
hash = hash.to_hash
|
42
|
+
else
|
43
|
+
raise TypeError, "The given `#{hash.inspect}` must respond " \
|
44
|
+
"to #to_hash'."
|
45
|
+
end
|
46
|
+
|
47
|
+
unless path.is_a?(String) || path.is_a?(Pathname)
|
48
|
+
raise TypeError, "The given `#{path}` must be a string or 'pathname'."
|
49
|
+
end
|
50
|
+
path = path.to_s
|
51
|
+
raise IOError, 'Empty path.' if path.empty?
|
52
|
+
|
53
|
+
File.open(path, 'w') do |f|
|
54
|
+
plist = Nanaimo::Plist.new(hash, :xml)
|
55
|
+
Nanaimo::Writer::XMLWriter.new(plist, :pretty => true, :output => f, :strict => false).write
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# The known modules that can serialize plists.
|
60
|
+
#
|
61
|
+
KNOWN_IMPLEMENTATIONS = []
|
62
|
+
|
63
|
+
class << self
|
64
|
+
# @deprecated This method will be removed in 2.0
|
65
|
+
#
|
66
|
+
# @return [Nil]
|
67
|
+
#
|
68
|
+
attr_accessor :implementation
|
69
|
+
end
|
70
|
+
|
71
|
+
# @deprecated This method will be removed in 2.0
|
72
|
+
#
|
73
|
+
# @return [Nil]
|
74
|
+
#
|
75
|
+
def self.autoload_implementation
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [Bool] Checks whether there are merge conflicts in the file.
|
79
|
+
#
|
80
|
+
# @param [#to_s] contents
|
81
|
+
# The contents of the file.
|
82
|
+
#
|
83
|
+
def self.file_in_conflict?(contents)
|
84
|
+
conflict_regex = /
|
85
|
+
^<{7}(?!<) # Exactly 7 left arrows at the beginning of the line
|
86
|
+
[\w\W]* # Anything
|
87
|
+
^={7}(?!=) # Exactly 7 equality symbols at the beginning of the line
|
88
|
+
[\w\W]* # Anything
|
89
|
+
^>{7}(?!>) # Exactly 7 right arrows at the beginning of the line
|
90
|
+
/xm
|
91
|
+
contents.match(conflict_regex)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Xcodeproj
|
2
|
+
class Project
|
3
|
+
module Object
|
4
|
+
# Converts between camel case names used in the xcodeproj plist files
|
5
|
+
# and the ruby symbols used to represent them.
|
6
|
+
#
|
7
|
+
module CaseConverter
|
8
|
+
# @return [String] The plist equivalent of the given Ruby name.
|
9
|
+
#
|
10
|
+
# @param [Symbol, String] name
|
11
|
+
# The name to convert
|
12
|
+
#
|
13
|
+
# @param [Symbol, Nil] type
|
14
|
+
# The type of conversion. Pass `nil` for normal camel case and
|
15
|
+
# `:lower` for camel case starting with a lower case letter.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# CaseConverter.convert_to_plist(:project_ref) #=> ProjectRef
|
19
|
+
#
|
20
|
+
def self.convert_to_plist(name, type = nil)
|
21
|
+
case name
|
22
|
+
when :remote_global_id_string
|
23
|
+
'remoteGlobalIDString'
|
24
|
+
else
|
25
|
+
if type == :lower
|
26
|
+
cache = plist_cache[:lower] ||= {}
|
27
|
+
cache[name] ||= camelize(name, :uppercase_first_letter => false)
|
28
|
+
else
|
29
|
+
cache = plist_cache[:normal] ||= {}
|
30
|
+
cache[name] ||= camelize(name)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# The following two methods are taken from activesupport,
|
36
|
+
# https://github.com/rails/rails/blob/v5.0.2/activesupport/lib/active_support/inflector/methods.rb
|
37
|
+
# all credit for them goes to the original authors.
|
38
|
+
#
|
39
|
+
# The code is used under the MIT license.
|
40
|
+
|
41
|
+
def self.camelize(term, uppercase_first_letter: true)
|
42
|
+
string = term.to_s
|
43
|
+
string = if uppercase_first_letter
|
44
|
+
string.sub(/^[a-z\d]*/, &:capitalize)
|
45
|
+
else
|
46
|
+
string.sub(/^(?:(?=a)b(?=\b|[A-Z_])|\w)/, &:downcase)
|
47
|
+
end
|
48
|
+
string.gsub!(%r{(?:_|(/))([a-z\d]*)}i) { "#{Regexp.last_match(1)}#{Regexp.last_match(2).capitalize}" }
|
49
|
+
string.gsub!('/'.freeze, '::'.freeze)
|
50
|
+
string
|
51
|
+
end
|
52
|
+
private_class_method :camelize
|
53
|
+
|
54
|
+
def self.underscore(camel_cased_word)
|
55
|
+
return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/
|
56
|
+
word = camel_cased_word.to_s.gsub('::'.freeze, '/'.freeze)
|
57
|
+
word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)((?=a)b)(?=\b|[^a-z])/) { "#{Regexp.last_match(1) && '_'.freeze}#{Regexp.last_match(2).downcase}" }
|
58
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
|
59
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
|
60
|
+
word.tr!('-'.freeze, '_'.freeze)
|
61
|
+
word.downcase!
|
62
|
+
word
|
63
|
+
end
|
64
|
+
private_class_method :underscore
|
65
|
+
|
66
|
+
# @return [Symbol] The Ruby equivalent of the given plist name.
|
67
|
+
#
|
68
|
+
# @param [String] name
|
69
|
+
# The name to convert
|
70
|
+
#
|
71
|
+
# @example
|
72
|
+
# CaseConverter.convert_to_ruby('ProjectRef') #=> :project_ref
|
73
|
+
#
|
74
|
+
def self.convert_to_ruby(name)
|
75
|
+
underscore(name.to_s).to_sym
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [Hash] A cache for the conversion to the Plist format.
|
79
|
+
#
|
80
|
+
# @note A cache is used because this operation is performed for each
|
81
|
+
# attribute of the project when it is saved and caching it has
|
82
|
+
# an important performance benefit.
|
83
|
+
#
|
84
|
+
def self.plist_cache
|
85
|
+
@plist_cache ||= {}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|