xcoder 0.0.21 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +4 -1
- data/Guardfile +13 -0
- data/README.md +2 -0
- data/Rakefile +15 -0
- data/lib/xcode/build_file.rb +22 -0
- data/lib/xcode/build_phase.rb +46 -0
- data/lib/xcode/builder.rb +2 -0
- data/lib/xcode/configuration.rb +108 -30
- data/lib/xcode/core_ext/array.rb +23 -0
- data/lib/xcode/core_ext/boolean.rb +21 -0
- data/lib/xcode/core_ext/fixnum.rb +5 -0
- data/lib/xcode/core_ext/hash.rb +27 -0
- data/lib/xcode/core_ext/string.rb +11 -0
- data/lib/xcode/file_reference.rb +29 -0
- data/lib/xcode/group.rb +118 -0
- data/lib/xcode/info_plist.rb +4 -0
- data/lib/xcode/parsers/plutil_project_parser.rb +20 -0
- data/lib/xcode/project.rb +133 -34
- data/lib/xcode/registry.rb +120 -0
- data/lib/xcode/resource.rb +187 -0
- data/lib/xcode/target.rb +81 -15
- data/lib/xcode/variant_group.rb +8 -0
- data/lib/xcode/version.rb +1 -1
- data/lib/xcoder.rb +6 -0
- data/spec/TestProject/TestProject.xcodeproj/{xcuserdata/ray.xcuserdatad → xcshareddata}/xcschemes/TestProject.xcscheme +0 -0
- data/spec/build_phase_spec.rb +86 -0
- data/spec/builder_spec.rb +128 -0
- data/spec/configuration_spec.rb +63 -22
- data/spec/group_spec.rb +80 -0
- data/spec/project_spec.rb +92 -35
- data/spec/scheme_spec.rb +1 -16
- data/spec/spec_helper.rb +1 -0
- data/spec/target_spec.rb +71 -15
- data/spec/xcode_spec.rb +57 -0
- metadata +38 -16
- data/spec/TestProject/TestProject.xcodeproj/xcuserdata/ray.xcuserdatad/xcschemes/xcschememanagement.plist +0 -27
data/lib/xcode/info_plist.rb
CHANGED
@@ -2,6 +2,10 @@ require 'plist'
|
|
2
2
|
require 'pp'
|
3
3
|
|
4
4
|
module Xcode
|
5
|
+
|
6
|
+
#
|
7
|
+
# @see https://developer.apple.com/library/ios/#documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html
|
8
|
+
#
|
5
9
|
class InfoPlist
|
6
10
|
def initialize(config, plist_location)
|
7
11
|
@config = config
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'plist'
|
3
|
+
|
4
|
+
module Xcode
|
5
|
+
|
6
|
+
module PLUTILProjectParser
|
7
|
+
extend self
|
8
|
+
|
9
|
+
#
|
10
|
+
# Using the sytem tool plutil, the specified project file is parsed and
|
11
|
+
# converted to XML, and then converted into a ruby hash object.
|
12
|
+
#
|
13
|
+
def parse path
|
14
|
+
xml = `plutil -convert xml1 -o - "#{path}"`
|
15
|
+
Plist::parse_xml(xml)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/lib/xcode/project.rb
CHANGED
@@ -1,43 +1,132 @@
|
|
1
|
-
require '
|
1
|
+
require 'plist'
|
2
|
+
require 'xcode/parsers/plutil_project_parser'
|
3
|
+
require 'xcode/resource'
|
2
4
|
require 'xcode/target'
|
3
5
|
require 'xcode/configuration'
|
4
6
|
require 'xcode/scheme'
|
5
|
-
require '
|
7
|
+
require 'xcode/group'
|
8
|
+
require 'xcode/file_reference'
|
9
|
+
require 'xcode/registry'
|
10
|
+
require 'xcode/build_phase'
|
11
|
+
require 'xcode/variant_group'
|
6
12
|
|
7
13
|
module Xcode
|
8
14
|
class Project
|
9
|
-
|
15
|
+
|
16
|
+
attr_reader :name, :sdk, :path, :schemes, :registry
|
17
|
+
|
18
|
+
#
|
19
|
+
# Initialized with a specific path and sdk.
|
20
|
+
#
|
21
|
+
# This initialization is not often used. Instead projects are generated
|
22
|
+
# through the Xcode#project method.
|
23
|
+
#
|
24
|
+
# @see Xcode
|
25
|
+
#
|
26
|
+
# @param [String] path of the project to open.
|
27
|
+
# @param [String] sdk the sdk value of the project. This will default to
|
28
|
+
# `iphoneos`.
|
29
|
+
#
|
10
30
|
def initialize(path, sdk=nil)
|
11
31
|
@sdk = sdk || "iphoneos" # FIXME: should support OSX/simulator too
|
12
32
|
@path = File.expand_path path
|
13
|
-
@targets = []
|
14
33
|
@schemes = []
|
15
34
|
@groups = []
|
16
35
|
@name = File.basename(@path).gsub(/\.xcodeproj/,'')
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
36
|
+
|
37
|
+
# Parse the Xcode project file and create the registry
|
38
|
+
|
39
|
+
@registry = parse_pbxproj
|
40
|
+
@project = Xcode::Resource.new registry.root, @registry
|
41
|
+
|
42
|
+
@schemes = parse_schemes
|
21
43
|
end
|
22
44
|
|
23
|
-
|
24
|
-
|
45
|
+
#
|
46
|
+
# Returns the main group of the project where all the files reside.
|
47
|
+
#
|
48
|
+
# @return [PBXGroup]
|
49
|
+
# @see PBXGroup
|
50
|
+
#
|
51
|
+
def groups
|
52
|
+
@project.mainGroup
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Save the current project at the current path that it exists.
|
57
|
+
#
|
58
|
+
def save!
|
59
|
+
save @path
|
25
60
|
end
|
26
61
|
|
27
|
-
|
28
|
-
|
62
|
+
#
|
63
|
+
# Saves the current project at the specified path.
|
64
|
+
#
|
65
|
+
# @note currently this does not support saving the workspaces associated
|
66
|
+
# with the project to their new location.
|
67
|
+
#
|
68
|
+
# @param [String] path the path to save the project
|
69
|
+
#
|
70
|
+
def save(path)
|
71
|
+
Dir.mkdir(path) unless File.exists?(path)
|
72
|
+
|
73
|
+
project_filepath = "#{path}/project.pbxproj"
|
74
|
+
|
75
|
+
# @toodo Save the workspace when the project is saved
|
76
|
+
# FileUtils.cp_r "#{path}/project.xcworkspace", "#{path}/project.xcworkspace"
|
77
|
+
|
78
|
+
File.open(project_filepath,'w') do |file|
|
79
|
+
|
80
|
+
# The Hash#to_xcplist saves a semi-colon at the end which needs to be removed
|
81
|
+
# to ensure the project file can be opened.
|
82
|
+
|
83
|
+
file.puts %{// !$*UTF8*$!"\n#{@registry.to_xcplist.gsub(/\};\s*\z/,'}')}}
|
84
|
+
|
85
|
+
end
|
29
86
|
end
|
30
87
|
|
88
|
+
|
89
|
+
#
|
90
|
+
# Return the scheme with the specified name. Raises an error if no schemes
|
91
|
+
# match the specified name.
|
92
|
+
#
|
93
|
+
# @note if two schemes match names, the first matching scheme is return.
|
94
|
+
#
|
95
|
+
# @param [String] name of the specific scheme
|
96
|
+
# @return [Scheme] the specific scheme that matches the name specified
|
97
|
+
#
|
31
98
|
def scheme(name)
|
32
99
|
scheme = @schemes.select {|t| t.name == name.to_s}.first
|
33
100
|
raise "No such scheme #{name}, available schemes are #{@schemes.map {|t| t.name}.join(', ')}" if scheme.nil?
|
34
101
|
yield scheme if block_given?
|
35
102
|
scheme
|
36
103
|
end
|
37
|
-
|
104
|
+
|
105
|
+
#
|
106
|
+
# All the targets specified within the project.
|
107
|
+
#
|
108
|
+
# @return [Array<PBXNativeTarget>] an array of all the available targets for
|
109
|
+
# the specific project.
|
110
|
+
#
|
111
|
+
def targets
|
112
|
+
@project.targets.map do |target|
|
113
|
+
target.project = self
|
114
|
+
target
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Return the target with the specified name. Raises an error if no targets
|
120
|
+
# match the specified name.
|
121
|
+
#
|
122
|
+
# @note if two targets match names, the first matching target is returned.
|
123
|
+
#
|
124
|
+
# @param [String] name of the specific target
|
125
|
+
# @return [PBXNativeTarget] the specific target that matches the name specified
|
126
|
+
#
|
38
127
|
def target(name)
|
39
|
-
target =
|
40
|
-
raise "No such target #{name}, available targets are #{
|
128
|
+
target = targets.select {|t| t.name == name.to_s}.first
|
129
|
+
raise "No such target #{name}, available targets are #{targets.map {|t| t.name}.join(', ')}" if target.nil?
|
41
130
|
yield target if block_given?
|
42
131
|
target
|
43
132
|
end
|
@@ -59,32 +148,42 @@ module Xcode
|
|
59
148
|
|
60
149
|
private
|
61
150
|
|
151
|
+
#
|
152
|
+
# Parse all the scheme files that can be found within the project. Schemes
|
153
|
+
# can be defined as `shared` schemes and then `user` specific schemes. Parsing
|
154
|
+
# the schemes will load the shared ones and then the current acting user's
|
155
|
+
# schemes.
|
156
|
+
#
|
62
157
|
def parse_schemes
|
63
|
-
|
64
|
-
Dir["#{@path}
|
65
|
-
|
158
|
+
shared_schemes = Dir["#{@path}/xcshareddata/xcschemes/*.xcscheme"]
|
159
|
+
user_specific_schemes = Dir["#{@path}/xcuserdata/#{ENV['USER']}.xcuserdatad/xcschemes/*.xcscheme"]
|
160
|
+
|
161
|
+
(shared_schemes + user_specific_schemes).map do |scheme|
|
162
|
+
Xcode::Scheme.new(self, scheme)
|
66
163
|
end
|
67
164
|
end
|
68
165
|
|
166
|
+
#
|
167
|
+
# Using the sytem tool plutil, the specified project file is parsed and
|
168
|
+
# converted to JSON, which is then converted to a hash object.
|
169
|
+
#
|
170
|
+
# This content contains all the data within the project file and is used
|
171
|
+
# to create the Registry.
|
172
|
+
#
|
173
|
+
# @return [Resource] a resource mapped to the root resource within the project
|
174
|
+
# this is generally the project file which contains details about the main
|
175
|
+
# group, targets, etc.
|
176
|
+
#
|
177
|
+
# @see Registry
|
178
|
+
#
|
69
179
|
def parse_pbxproj
|
70
|
-
|
71
|
-
# json = JSON.parse()
|
72
|
-
json = Plist::parse_xml(xml)
|
180
|
+
registry = Xcode::PLUTILProjectParser.parse "#{@path}/project.pbxproj"
|
73
181
|
|
74
|
-
|
75
|
-
|
76
|
-
root['targets'].each do |target_id|
|
77
|
-
target = Xcode::Target.new(self, json['objects'][target_id])
|
78
|
-
|
79
|
-
buildConfigurationList = json['objects'][target_id]['buildConfigurationList']
|
80
|
-
buildConfigurations = json['objects'][buildConfigurationList]['buildConfigurations']
|
81
|
-
|
82
|
-
buildConfigurations.each do |buildConfiguration|
|
83
|
-
target.configs << Xcode::Configuration.new(target, json['objects'][buildConfiguration])
|
84
|
-
end
|
85
|
-
|
86
|
-
@targets << target
|
182
|
+
class << registry
|
183
|
+
include Xcode::Registry
|
87
184
|
end
|
185
|
+
|
186
|
+
registry
|
88
187
|
end
|
89
188
|
|
90
189
|
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module Xcode
|
2
|
+
|
3
|
+
#
|
4
|
+
# The Registry represents the parsed data from the Xcode Project file. Namely
|
5
|
+
# the registry is a Hash that provides additional functionality to allow the
|
6
|
+
# the ability to query, add, and remove resources from the object hash.
|
7
|
+
#
|
8
|
+
# Opening the Xcode project file in a text-editor you'll notice that it is a
|
9
|
+
# big hash/plist with a file core keys. The most important key is the 'objects'
|
10
|
+
# dictionary which maintains the master-list of Identifiers to properties. All
|
11
|
+
# objects are represented here and all other resources use the reference
|
12
|
+
# to make the connection to the objects.
|
13
|
+
#
|
14
|
+
# @see Project
|
15
|
+
#
|
16
|
+
module Registry
|
17
|
+
|
18
|
+
#
|
19
|
+
# This method is used internally to determine if the value that is being
|
20
|
+
# retrieved is an identifier.
|
21
|
+
#
|
22
|
+
# @todo this should likely be moved to the Regsitry which knows much more
|
23
|
+
# about identifiers and what makes them valid.
|
24
|
+
# @param [String] value is the specified value in the form of an identifier
|
25
|
+
#
|
26
|
+
def self.is_identifier? value
|
27
|
+
value =~ /^[0-9A-F]{24}$/
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Objects within the registry contain an `isa` property, which translates
|
32
|
+
# to modules which can be mixed in to provide additional functionality.
|
33
|
+
#
|
34
|
+
# @param [String] isa the type of the object.
|
35
|
+
#
|
36
|
+
def self.isa_to_module isa
|
37
|
+
|
38
|
+
{ 'XCBuildConfiguration' => Configuration,
|
39
|
+
'PBXFileReference' => FileReference,
|
40
|
+
'PBXGroup' => Group,
|
41
|
+
'PBXNativeTarget' => Target,
|
42
|
+
'PBXAggregateTarget' => Target,
|
43
|
+
'PBXFrameworksBuildPhase' => BuildPhase,
|
44
|
+
'PBXSourcesBuildPhase' => BuildPhase,
|
45
|
+
'PBXResourcesBuildPhase' => BuildPhase,
|
46
|
+
'PBXBuildFile' => BuildFile,
|
47
|
+
'PBXVariantGroup' => VariantGroup }[isa]
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# This is the root object of the project. This is generally an identifier
|
53
|
+
# pointing to a project.
|
54
|
+
#
|
55
|
+
def root
|
56
|
+
self['rootObject']
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
#
|
61
|
+
# This is a hash of all the objects within the project. The keys are the
|
62
|
+
# unique identifiers which are 24 length hexadecimal strings. The values
|
63
|
+
# are the objects that the keys represent.
|
64
|
+
#
|
65
|
+
# @return [Hash] that contains all the objects in the project.
|
66
|
+
#
|
67
|
+
def objects
|
68
|
+
self['objects']
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
#
|
73
|
+
# @return [String] the object associated with this identifier; nil if no
|
74
|
+
# object matches the identifier.
|
75
|
+
#
|
76
|
+
def object(identifier)
|
77
|
+
objects[identifier]
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Provides a method to generically add objects to the registry. This will
|
82
|
+
# create a unqiue identifier and add the specified parameters to the
|
83
|
+
# registry. As all objecst within a the project maintain a reference to this
|
84
|
+
# registry they can immediately query for newly created items.
|
85
|
+
#
|
86
|
+
# @note generally this method should not be called directly and instead
|
87
|
+
# resources should provide the ability to assist with generating the
|
88
|
+
# correct objects for the registry.
|
89
|
+
#
|
90
|
+
# @param [Hash] object_properties a hash that contains all the properties
|
91
|
+
# that are known for the particular item.
|
92
|
+
#
|
93
|
+
def add_object(object_properties)
|
94
|
+
# define a new group within the object list
|
95
|
+
# add it as a child
|
96
|
+
|
97
|
+
range = ('A'..'F').to_a + (0..9).to_a
|
98
|
+
|
99
|
+
new_identifier = 24.times.inject("") {|ident| "#{ident}#{range.sample}" }
|
100
|
+
|
101
|
+
# TODO ensure identifier does not collide with other identifiers
|
102
|
+
|
103
|
+
objects[new_identifier] = object_properties
|
104
|
+
|
105
|
+
new_identifier
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# @note removing an item from the regitry does not remove all references
|
110
|
+
# to the item within the project. At this time, this could leave resources
|
111
|
+
# with references to resources that are invalid.
|
112
|
+
#
|
113
|
+
# @param [String] identifier of the object to remove from the registry.
|
114
|
+
#
|
115
|
+
def remove_object(identifier)
|
116
|
+
objects.delete identifier
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
|
2
|
+
module Xcode
|
3
|
+
|
4
|
+
#
|
5
|
+
# Resources are not represented as a true entity within an Xcode project.
|
6
|
+
# When traversing through groups, targets, configurations, etc. you will find
|
7
|
+
# yourself interacting with these objects. As they represent a class that
|
8
|
+
# acts as a shim around the hash data is parsed from the project.
|
9
|
+
#
|
10
|
+
# A resource do some things that should be explained:
|
11
|
+
#
|
12
|
+
# When a resource is created it requires an identifier and an instance of
|
13
|
+
# of the Registry. It finds the properties hash of that given identifier
|
14
|
+
# within the registry and creates a bunch of read-only methods that allow for
|
15
|
+
# easy access to those elements. This is not unlike an OpenStruct.
|
16
|
+
#
|
17
|
+
# @example of accessing the contents of a file reference
|
18
|
+
#
|
19
|
+
# file_resource.properties # =>
|
20
|
+
#
|
21
|
+
# { 'isa' => 'PBXFileReference',
|
22
|
+
# 'lastKnownFileType' => 'sourcecode.c.h',
|
23
|
+
# 'path' => IOSAppDelegate.h',
|
24
|
+
# 'sourceTree' => "<group>" }
|
25
|
+
#
|
26
|
+
# file_resource.isa # => 'PBXFileReference'
|
27
|
+
# file_resource.sourceTree # => "<group>"
|
28
|
+
#
|
29
|
+
#
|
30
|
+
# To provide additional convenience when traversing through the
|
31
|
+
# various objects, the read-only method will check to see if the value
|
32
|
+
# being returned matches that of a unique identifier. If it does, instead of
|
33
|
+
# providing that identifier as a result and then having additional code to
|
34
|
+
# perform the look up, it does it automatically.
|
35
|
+
#
|
36
|
+
# @example of how this would have to been done without this indirection
|
37
|
+
#
|
38
|
+
# project = Xcode.project('MyProject')
|
39
|
+
# main_group = project.groups
|
40
|
+
# child_identifier = group.children.first
|
41
|
+
# subgroup = project.registry['objects'][child_identifier]
|
42
|
+
#
|
43
|
+
# @example of hot this works currently because of this indirection
|
44
|
+
#
|
45
|
+
# group = Xcode.project('MyProject.xcodeproj').mainGroup
|
46
|
+
# subgroup = group.group('Models')
|
47
|
+
#
|
48
|
+
#
|
49
|
+
# Next, as most every one of these objects is a Hash that contain the properties
|
50
|
+
# instead of objects it would likely be better to encapsulate these resources
|
51
|
+
# within specific classes that provide additional functionality. So that when
|
52
|
+
# a group resource or a file resource is returned you can perform unique
|
53
|
+
# functionality with it automatically.
|
54
|
+
#
|
55
|
+
# This is done by using the 'isa' property field which contains the type of
|
56
|
+
# content object. Instead of creating an object and encapsulating if a module
|
57
|
+
# that matches the name of the 'isa', that module of functionality is
|
58
|
+
# automatically mixed-in to provide that functionality.
|
59
|
+
#
|
60
|
+
class Resource
|
61
|
+
|
62
|
+
# The unique identifier for this resource
|
63
|
+
attr_accessor :identifier
|
64
|
+
|
65
|
+
# The properties hash that is known about the resource
|
66
|
+
attr_accessor :properties
|
67
|
+
|
68
|
+
# The registry of all objects within the project file which all resources
|
69
|
+
# have a reference to so that they can retrieve any items they may own that
|
70
|
+
# are simply referenced by identifiers.
|
71
|
+
attr_accessor :registry
|
72
|
+
|
73
|
+
#
|
74
|
+
# Definiing a property allows the creation of an alias to the actual value.
|
75
|
+
# This level of indirection allows for the replacement of values which are
|
76
|
+
# identifiers with a resource representation of it.
|
77
|
+
#
|
78
|
+
# @note This is used internally by the resource when it is created.
|
79
|
+
#
|
80
|
+
# @param [String] name of the property
|
81
|
+
# @param [String] value of the property
|
82
|
+
#
|
83
|
+
def define_property name, value
|
84
|
+
|
85
|
+
# Save the properties within the resource within a custom hash. This
|
86
|
+
# provides access to them without the indirection that we are about to
|
87
|
+
# set up.
|
88
|
+
|
89
|
+
@properties[name] = value
|
90
|
+
|
91
|
+
# Generate a getter method for this property based on the given name.
|
92
|
+
|
93
|
+
self.class.send :define_method, name do
|
94
|
+
|
95
|
+
# Retrieve the value that is current stored for this name.
|
96
|
+
|
97
|
+
raw_value = @properties[name]
|
98
|
+
|
99
|
+
# If the value is an array then we want to examine each element within
|
100
|
+
# the array to see if any of them are identifiers that we should replace
|
101
|
+
# finally returning all of the items as their resource representations
|
102
|
+
# or as their raw values.
|
103
|
+
#
|
104
|
+
# If the value is not an array then we want to examine that item and
|
105
|
+
# return the resource representation or the raw value.
|
106
|
+
|
107
|
+
if raw_value.is_a?(Array)
|
108
|
+
|
109
|
+
Array(raw_value).map do |sub_value|
|
110
|
+
|
111
|
+
if Registry.is_identifier? sub_value
|
112
|
+
Resource.new sub_value, @registry
|
113
|
+
else
|
114
|
+
sub_value
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
else
|
119
|
+
|
120
|
+
if Registry.is_identifier? raw_value
|
121
|
+
Resource.new raw_value, @registry
|
122
|
+
else
|
123
|
+
raw_value
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# Within the code, a single resource is created and that is with the root
|
134
|
+
# projet object. All other resources are created through the indirecation of
|
135
|
+
# the above property methods.
|
136
|
+
#
|
137
|
+
# @param [String] identifier the unique identifier for this resource.
|
138
|
+
# @param [Types] details Description
|
139
|
+
#
|
140
|
+
def initialize identifier, details
|
141
|
+
@registry = details
|
142
|
+
@properties = {}
|
143
|
+
@identifier = identifier
|
144
|
+
|
145
|
+
# Create property methods for all of the key-value pairs found in the
|
146
|
+
# registry for specified identifier.
|
147
|
+
|
148
|
+
Array(details.object(@identifier)).each do |key,value|
|
149
|
+
send :define_property, key, value
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# Based on the `isa` property find if there is a constant within
|
154
|
+
# the Xcode module that matches and if it does, then we want to
|
155
|
+
# automatically include module into the Resource object.
|
156
|
+
#
|
157
|
+
constant = Registry.isa_to_module(isa)
|
158
|
+
|
159
|
+
self.extend(constant) if constant
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# @return [String] a representation with the identifier and the properties
|
165
|
+
# for this resource.
|
166
|
+
#
|
167
|
+
def to_s
|
168
|
+
"#{isa} #{@identifier} #{@properties}"
|
169
|
+
end
|
170
|
+
|
171
|
+
#
|
172
|
+
# This will generate the resource in the format that is supported by the
|
173
|
+
# Xcode project file. Which requires each key value pair to be represented.
|
174
|
+
#
|
175
|
+
# @return [String] a string representation of the object so that it can
|
176
|
+
# be persisted to an Xcode project file.
|
177
|
+
#
|
178
|
+
def to_xcplist
|
179
|
+
%{
|
180
|
+
#{@identifier} = { #{ @properties.map {|k,v| "#{k} = \"#{v}\"" }.join("; ") } }
|
181
|
+
|
182
|
+
}
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|