Class: Xcode::Resource

Inherits:
Object
  • Object
show all
Defined in:
lib/xcode/resource.rb

Overview

Resources are not represented as a true entity within an Xcode project. However when traversing through groups, targets, configurations, etc. you will find yourself interacting with these objects. As they represent a class that acts as a shim around their hash data.

The goal of the Resource is to aid in the navigation through the project and provide a flexible system to allow for Xcoder to adapt to changes to the Xcode project format.

A Resource requires an identifier and an instance of the Registry. Based on the supplied identifier, it peforms a look up of it’s properties or hash of data. With that hash it then proceeds to create methods that allow for easy read/write access to those property elements. This is similar to Ruby’s OpenStruct.

In the above example, you can still gain access to the internal properties through the #properties method. However, the Resource provides for you additional ruby friendly methods to access the properties.

To provide additional convenience when traversing through the various objects, the getter methods will check to see if the value being returned matches that of a unique identifier. If it does, instead of providing that identifier, it will instead look in the Registry for the object that matches and return a new Resource automatically.

In this example when accessing the first element of children instead of an identifier string being returned the child resource is returned. This functionality is in place to allow Xcoder to flexibly conform to new relationships that may exist or come to exist.

Lastly, a Resource is simply not enough to describe most of the objects within an Xcode project as each object has unique functionality that needs to be able to perform. So each resource when it is created will query the Xcode::Registry.isa_to_module hash to determine the functionality that it needs to additionally extend into the Resource.

This ‘isa` property mapped to Ruby modules allows for the easy expansion of new objects or for changes to be made to existing ones as needed.

Examples:

Accessing the contents of a file reference


file = project.file('IOSApp/IOSAppDelegate.m').properties # => 

{ 'isa' => 'PBXFileReference',
  'lastKnownFileType' => 'sourcecode.c.h',
  'path' => IOSAppDelegate.h', 
  'sourceTree' => "<group>" }

file.isa # => 'PBXFileReference'
file.last_known_file_type # => 'sourcecode.c.h'
file.path # => 'IOSAppDelegate.m'
file.path = "NewIOSAppDelegate.m" # => 'NewIOSAppDeleget.m'
file.source_tree # => "<group>"

Magically accessing resources through resources


group = project.groups
group.properties # =>

{ "children"=>["7165D45A146B4EA100DE2F0E", 
               "7165D472146B4EA100DE2F0E", 
               "7165D453146B4EA100DE2F0E", 
               "7165D451146B4EA100DE2F0E"], 
  "isa"=>"PBXGroup", 
  "sourceTree"=>"<group>"}

group.children.first # => 

PBXGroup 7165D45A146B4EA100DE2F0E {"children"=>["7165D463146B4EA100DE2F0E", 
                                                "7165D464146B4EA100DE2F0E", 
                                                "7165D45B146B4EA100DE2F0E"], 
                                   "isa"=>"PBXGroup", 
                                   "path"=>"TestProject", 
                                   "sourceTree"=>"<group>"} 

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(identifier, registry) ⇒ Resource

A Resource is created during Project#initialize, when the project is first parsed. Afterwards each Resource is usually generated through the special getter method defined through #define_property.

Parameters:

  • identifier (String)

    the unique identifier for this resource.

  • registry (Registry)

    the core registry for the system.

See Also:



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/xcode/resource.rb', line 180

def initialize identifier, registry
  @registry = registry
  @properties = {}
  @identifier = identifier
  
  # Create property methods for all of the key-value pairs found in the
  # registry for specified identifier.
  
  Array(registry.properties(@identifier)).each do |key,value| 
    send :define_property, key, value
  end
  
  #  
  # Based on the `isa` property find if there are constants within
  # the Xcode module that matches and if it does, then we want to 
  # automatically include those modules into the Resource object.
  # 
  constants = Registry.isa_to_module(isa)
  
  constants.each do |constant|
    self.extend(constant) if constant
  end
  
end

Instance Attribute Details

#identifierString

Returns the unique identifier for this resource.

Returns:

  • (String)

    the unique identifier for this resource



85
86
87
# File 'lib/xcode/resource.rb', line 85

def identifier
  @identifier
end

#propertiesHash

The raw properties hash that is known about the resource. This is the best way to manipulate the raw values of the resource.

Returns:

  • (Hash)

    the raw properties hash for the object



91
92
93
# File 'lib/xcode/resource.rb', line 91

def properties
  @properties
end

#registryRegistry (readonly)

The registry of all objects within the project file which all resources have a reference to so that they can retrieve any items they may own that are simply referenced by identifiers. This registry is used to convert identifier keys to resource objects. It is also passed to any resources that are created.

Returns:

  • (Registry)

    the registry for the entire project.



100
101
102
# File 'lib/xcode/resource.rb', line 100

def registry
  @registry
end

Instance Method Details

#define_property(name, value) ⇒ Object

Note:

This is used internally by the resource when it is created to create the getter/setter methods.

Definiing a property allows the creation of an alias to the actual value. This level of indirection allows for the replacement of values which are identifiers with a resource representation of it.

Parameters:

  • name (String)

    of the property

  • value (String)

    of the property



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/xcode/resource.rb', line 113

def define_property name, value
  
  # Save the properties within the resource within a custom hash. This 
  # provides access to them without the indirection that we are about to
  # set up.
  
  @properties[name] = value
  
  # Generate a getter method for this property based on the given name.
  
  self.class.send :define_method, name.underscore do
    
    # Retrieve the value that is current stored for this name.
    
    raw_value = @properties[name]
    
    # If the value is an array then we want to examine each element within
    # the array to see if any of them are identifiers that we should replace
    # finally returning all of the items as their resource representations
    # or as their raw values.
    # 
    # If the value is not an array then we want to examine that item and
    # return the resource representation or the raw value.
    
    if raw_value.is_a?(Array)
      
      Array(raw_value).map do |sub_value|
        
        if Registry.is_identifier? sub_value 
          Resource.new sub_value, @registry
        else
          sub_value
        end
      end
      
    else 
      
      if Registry.is_identifier? raw_value
        Resource.new raw_value, @registry
      else 
        raw_value
      end
      
    end

  end
  
  # Generate a setter method for this property based on the given name.
  
  self.class.send :define_method, "#{name.underscore}=" do |new_value|
    @properties[name] = new_value
  end
  
  
end

#save!Resource

Saves the current resource back to the registry. This is necessary as any changes made are not automatically saved back into the registry.

Examples:

group adding a files and then saving itself


group = project.groups
group.create_file 'name' => 'AppDelegate.m', 'path' => 'AppDelegate.m'
group.save!

Returns:

  • (Resource)

    the object that is being saved.



217
218
219
220
# File 'lib/xcode/resource.rb', line 217

def save!
  @registry.set_object(self)
  self
end

#to_sString

Returns a representation with the identifier and the properties for this resource.

Returns:

  • (String)

    a representation with the identifier and the properties for this resource.



226
227
228
# File 'lib/xcode/resource.rb', line 226

def to_s
  "#{isa} #{@identifier} #{@properties}"
end

#to_xcplistString

This will generate the resource in the format that is supported by the Xcode project file. Which requires each key value pair to be represented.

Returns:

  • (String)

    a string representation of the object so that it can be persisted to an Xcode project file.



237
238
239
240
241
# File 'lib/xcode/resource.rb', line 237

def to_xcplist
  %{
    #{@identifier} = { #{ @properties.map {|k,v| "#{k} = \"#{v.to_xcplist}\"" }.join("; ") } }
  }
end