class Xcodeproj::Workspace

Provides support for generating, reading and serializing Xcode Workspace documents.

Attributes

document[R]

@return [REXML::Document] the parsed XML model for the workspace contents

schemes[R]

@return [Hash<String => String>] a mapping from scheme name to project full path

containing the scheme

Public Class Methods

from_s(xml, workspace_path = '') click to toggle source

Returns a workspace generated by reading the contents of the given XML representation.

@param [String] xml

the XML representation of the workspace.

@return [Workspace] the generated workspace.

# File lib/xcodeproj/workspace.rb, line 82
def self.from_s(xml, workspace_path = '')
  document = REXML::Document.new(xml)
  instance = new(document)
  instance.load_schemes(workspace_path)
  instance
end
new(document, *file_references) click to toggle source

@param [REXML::Document] document @see document @param [Array<FileReference>] file_references additional projects to add

@note The document parameter is passed to the << operator if it is not a

valid REXML::Document. It is optional, but may also be passed as nil
# File lib/xcodeproj/workspace.rb, line 43
def initialize(document, *file_references)
  @schemes = {}
  if document.nil?
    @document = REXML::Document.new(root_xml(''))
  elsif document.is_a?(REXML::Document)
    @document = document
  else
    @document = REXML::Document.new(root_xml(''))
    self << document
  end
  file_references.each { |ref| self << ref }
end
new_from_xcworkspace(path) click to toggle source

Returns a workspace generated by reading the contents of the given path.

@param [String] path

the path of the `xcworkspace` file.

@return [Workspace] the generated workspace.

# File lib/xcodeproj/workspace.rb, line 65
def self.new_from_xcworkspace(path)
  from_s(File.read(File.join(path, 'contents.xcworkspacedata')),
         File.expand_path(path))
rescue Errno::ENOENT
  new(nil)
end

Public Instance Methods

<<(path_or_reference) click to toggle source

Adds a new path to the list of the of projects contained in the workspace. @param [String, Xcodeproj::Workspace::FileReference] path_or_reference

A string or Xcode::Workspace::FileReference containing a path to an Xcode project

@raise [ArgumentError] Raised if the input is neither a String nor a FileReference

@return [void]

# File lib/xcodeproj/workspace.rb, line 98
def <<(path_or_reference)
  return unless @document && @document.respond_to?(:root)

  case path_or_reference
  when String
    project_file_reference = Xcodeproj::Workspace::FileReference.new(path_or_reference)
  when Xcodeproj::Workspace::FileReference
    project_file_reference = path_or_reference
    projpath = nil
  else
    raise ArgumentError, "Input to the << operator must be a file path or FileReference, got #{path_or_reference.inspect}"
  end
  unless file_references.any? { |ref| project_file_reference.eql? ref }
    @document.root.add_element(project_file_reference.to_node)
  end
  load_schemes_from_project File.expand_path(projpath || project_file_reference.path)
end
add_group(name) { |group, elem| ... } click to toggle source

Adds a new group container to the workspace workspace.

@param [String] name The name of the group

@yield [Xcodeproj::Workspace::GroupReference, REXML::Element]

Yields the GroupReference and underlying XML element for mutation

@return [Xcodeproj::Workspace::GroupReference] The added group reference

# File lib/xcodeproj/workspace.rb, line 128
def add_group(name)
  return nil unless @document
  group = Xcodeproj::Workspace::GroupReference.new(name)
  elem = @document.root.add_element(group.to_node)
  yield group, elem if block_given?
  group
end
file_references() click to toggle source

@return [Array<FileReference>] the paths of the projects contained in the

workspace.
# File lib/xcodeproj/workspace.rb, line 21
def file_references
  return [] unless @document
  @document.get_elements('/Workspace//FileRef').map do |node|
    FileReference.from_node(node)
  end
end
group_references() click to toggle source

@return [Array<GroupReference>] the groups contained in the workspace

# File lib/xcodeproj/workspace.rb, line 30
def group_references
  return [] unless @document
  @document.get_elements('/Workspace//Group').map do |node|
    GroupReference.from_node(node)
  end
end
include?(file_reference) click to toggle source

Checks if the workspace contains the project with the given file reference.

@param [FileReference] file_reference

The file_reference to the project.

@return [Boolean] whether the project is contained in the workspace.

# File lib/xcodeproj/workspace.rb, line 144
def include?(file_reference)
  file_references.include?(file_reference)
end
load_schemes(workspace_dir_path) click to toggle source

Load all schemes from all projects in workspace or in the workspace container itself

@param [String] workspace_dir_path

path of workspaces dir

@return [void]

# File lib/xcodeproj/workspace.rb, line 196
def load_schemes(workspace_dir_path)
  # Normalizes path to directory of workspace needed for file_reference.absolute_path
  workspaces_dir = workspace_dir_path
  if File.extname(workspace_dir_path) == '.xcworkspace'
    workspaces_dir = File.expand_path('..', workspaces_dir)
  end

  file_references.each do |file_reference|
    project_full_path = file_reference.absolute_path(workspaces_dir)
    load_schemes_from_project(project_full_path)
  end

  # Load schemes that are in the workspace container.
  workspace_abs_path = File.absolute_path(workspace_dir_path)
  Dir[File.join(workspace_dir_path, 'xcshareddata', 'xcschemes', '*.xcscheme')].each do |scheme|
    scheme_name = File.basename(scheme, '.xcscheme')
    @schemes[scheme_name] = workspace_abs_path
  end
end
save_as(path) click to toggle source

Saves the workspace at the given ‘xcworkspace` path.

@param [String] path

the path where to save the project.

@return [void]

# File lib/xcodeproj/workspace.rb, line 180
def save_as(path)
  FileUtils.mkdir_p(path)
  File.open(File.join(path, 'contents.xcworkspacedata'), 'w') do |out|
    out << to_s
  end
end
to_s() click to toggle source

@return [String] the XML representation of the workspace.

# File lib/xcodeproj/workspace.rb, line 150
def to_s
  contents = ''
  stack = []
  @document.root.each_recursive do |elem|
    until stack.empty?
      last = stack.last
      break if last == elem.parent
      contents += xcworkspace_element_end_xml(stack.length, last)
      stack.pop
    end

    stack << elem
    contents += xcworkspace_element_start_xml(stack.length, elem)
  end

  until stack.empty?
    contents += xcworkspace_element_end_xml(stack.length, stack.last)
    stack.pop
  end

  root_xml(contents)
end

Private Instance Methods

load_schemes_from_project(project_full_path) click to toggle source

Load all schemes from project

@param [String] project_full_path

project full path

@return [void]

# File lib/xcodeproj/workspace.rb, line 225
def load_schemes_from_project(project_full_path)
  schemes = Xcodeproj::Project.schemes project_full_path
  schemes.each do |scheme_name|
    @schemes[scheme_name] = project_full_path
  end
end
root_xml(contents) click to toggle source

@return [String] The template of the workspace XML as formated by Xcode.

@param [String] contents The XML contents of the workspace.

# File lib/xcodeproj/workspace.rb, line 236
    def root_xml(contents)
      <<-DOC

<Workspace
   version = "1.0">
#{contents.rstrip}
</Workspace>
DOC
    end
xcworkspace_element_end_xml(depth, elem) click to toggle source

@param [Integer] depth The depth of the element in the tree @param [REXML::Document::Element] elem The XML element to format.

@return [String] The Xcode-specific XML formatting of an element end

# File lib/xcodeproj/workspace.rb, line 271
def xcworkspace_element_end_xml(depth, elem)
  "#{'   ' * depth}</#{elem.name}>\n"
end
xcworkspace_element_start_xml(depth, elem) click to toggle source

@param [Integer] depth The depth of the element in the tree @param [REXML::Document::Element] elem The XML element to format.

@return [String] The Xcode-specific XML formatting of an element start

# File lib/xcodeproj/workspace.rb, line 252
def xcworkspace_element_start_xml(depth, elem)
  attributes = case elem.name
               when 'Group'
                 %w(location name)
               when 'FileRef'
                 %w(location)
               end
  contents = "<#{elem.name}"
  indent = '   ' * depth
  attributes.each { |name| contents += "\n   #{name} = \"#{elem.attribute(name)}\"" }
  contents.split("\n").map { |line| "#{indent}#{line}" }.join("\n") + ">\n"
end