class Xcodeproj::Config

This class holds the data for a Xcode build settings file (xcconfig) and provides support for serialization.

Constants

INHERITED
INHERITED_REGEXP
KEY_VALUE_PATTERN

Attributes

attributes[RW]

@return [Hash{String => String}] The attributes of the settings file

excluding frameworks, weak_framework and libraries.
includes[RW]

@return [Array] The list of the configuration files included by this

configuration file (`#include "SomeConfig"`).
other_linker_flags[RW]

@return [Hash{Symbol => Set<String>}] The other linker flags by key.

Xcodeproj handles them in a dedicated way to prevent duplication
of the libraries and of the frameworks.

Public Class Methods

new(xcconfig_hash_or_file = {}) click to toggle source

@param [Hash, File, String] xcconfig_hash_or_file

The initial data.
# File lib/xcodeproj/config.rb, line 58
def initialize(xcconfig_hash_or_file = {})
  @attributes = {}
  @includes = []
  @other_linker_flags = {}
  [:simple, :frameworks, :weak_frameworks, :libraries, :arg_files, :force_load].each do |key|
    @other_linker_flags[key] = Set.new
  end
  merge!(extract_hash(xcconfig_hash_or_file))
end

Public Instance Methods

<<(xcconfig)
Alias for: merge!
==(other) click to toggle source
# File lib/xcodeproj/config.rb, line 72
def ==(other)
  other.attributes == attributes && other.other_linker_flags == other_linker_flags && other.includes == includes
end
arg_files() click to toggle source

@return [Set<String>] The list of the arg files required by this

settings file.
# File lib/xcodeproj/config.rb, line 188
def arg_files
  other_linker_flags[:arg_files]
end
dup() click to toggle source

@return [Config] A copy of the receiver.

# File lib/xcodeproj/config.rb, line 248
def dup
  Xcodeproj::Config.new(to_hash.dup)
end
frameworks() click to toggle source

@return [Set<String>] The list of the frameworks required by this

settings file.
# File lib/xcodeproj/config.rb, line 167
def frameworks
  other_linker_flags[:frameworks]
end
inspect() click to toggle source
# File lib/xcodeproj/config.rb, line 68
def inspect
  to_hash.inspect
end
libraries() click to toggle source

@return [Set<String>] The list of the libraries required by this

settings file.
# File lib/xcodeproj/config.rb, line 181
def libraries
  other_linker_flags[:libraries]
end
merge(config) click to toggle source

Creates a new #{Config} with the data of the receiver merged with the given xcconfig representation.

@param [Hash, Config] config

The xcconfig representation to merge.

@return [Config] the new xcconfig.

# File lib/xcodeproj/config.rb, line 242
def merge(config)
  dup.tap { |x| x.merge!(config) }
end
merge!(xcconfig) click to toggle source

Merges the given xcconfig representation in the receiver.

@example

config = Config.new('PODS_ROOT' => '"$(SRCROOT)/Pods"', 'OTHER_LDFLAGS' => '-lxml2')
config.merge!('OTHER_LDFLAGS' => '-lz', 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers"')
config.to_hash # => { 'PODS_ROOT' => '"$(SRCROOT)/Pods"', 'OTHER_LDFLAGS' => '-lxml2 -lz', 'HEADER_SEARCH_PATHS' => '"$(PODS_ROOT)/Headers"' }

@note If a key in the given hash already exists in the internal data

then its value is appended.

@param [Hash, Config] config

The xcconfig representation to merge.

@todo The logic to normalize an hash should be extracted and the

initializer should not call this method.

@return [void]

# File lib/xcodeproj/config.rb, line 216
def merge!(xcconfig)
  if xcconfig.is_a? Config
    merge_attributes!(xcconfig.attributes)
    other_linker_flags.keys.each do |key|
      other_linker_flags[key].merge(xcconfig.other_linker_flags[key])
    end
  else
    merge_attributes!(xcconfig.to_hash)
    if flags = attributes.delete('OTHER_LDFLAGS')
      flags_by_key = OtherLinkerFlagsParser.parse(flags)
      other_linker_flags.keys.each do |key|
        other_linker_flags[key].merge(flags_by_key[key])
      end
    end
  end
end
Also aliased as: <<
save_as(pathname, prefix = nil) click to toggle source

Writes the serialized representation of the internal data to the given path.

@param [Pathname] pathname

The file where the data should be written to.

@return [void]

# File lib/xcodeproj/config.rb, line 105
def save_as(pathname, prefix = nil)
  if File.exist?(pathname)
    return if Config.new(pathname) == self
  end

  pathname.open('w') { |file| file << to_s(prefix) }
end
to_h(prefix = nil)
Alias for: to_hash
to_hash(prefix = nil) click to toggle source

The hash representation of the xcconfig. The hash includes the frameworks, the weak frameworks, the libraries and the simple other linker flags in the ‘Other Linker Flags` (`OTHER_LDFLAGS`).

@note All the values are sorted to have a consistent output in Ruby

1.8.7.

@return [Hash] The hash representation

# File lib/xcodeproj/config.rb, line 122
def to_hash(prefix = nil)
  list = []
  list += other_linker_flags[:simple].to_a.sort
  modifiers = {
    :frameworks => '-framework ',
    :weak_frameworks => '-weak_framework ',
    :libraries => '-l',
    :arg_files => '@',
    :force_load => '-force_load',
  }
  [:libraries, :frameworks, :weak_frameworks, :arg_files, :force_load].each do |key|
    modifier = modifiers[key]
    sorted = other_linker_flags[key].to_a.sort
    if key == :force_load
      list += sorted.map { |l| %(#{modifier} #{l}) }
    else
      list += sorted.map { |l| %(#{modifier}"#{l}") }
    end
  end

  result = attributes.dup
  result['OTHER_LDFLAGS'] = list.join(' ') unless list.empty?
  result.reject! { |_, v| INHERITED.any? { |i| i == v.to_s.strip } }

  result = @includes.map do |incl|
    path = File.expand_path(incl, @filepath.dirname)
    if File.readable? path
      Xcodeproj::Config.new(path).to_hash
    else
      {}
    end
  end.inject(&:merge).merge(result) unless @filepath.nil? || @includes.empty?

  if prefix
    Hash[result.map { |k, v| [prefix + k, v] }]
  else
    result
  end
end
Also aliased as: to_h
to_s(prefix = nil) click to toggle source

Sorts the internal data by setting name and serializes it in the xcconfig format.

@example

config = Config.new('PODS_ROOT' => '"$(SRCROOT)/Pods"', 'OTHER_LDFLAGS' => '-lxml2')
config.to_s # => "OTHER_LDFLAGS = -lxml2\nPODS_ROOT = \"$(SRCROOT)/Pods\""

@return [String] The serialized internal data.

# File lib/xcodeproj/config.rb, line 91
def to_s(prefix = nil)
  include_lines = includes.map { |path| "#include \"#{normalized_xcconfig_path(path)}\"" }
  settings = to_hash(prefix).sort_by(&:first).map { |k, v| "#{k} = #{v}".strip }
  (include_lines + settings).join("\n") << "\n"
end
weak_frameworks() click to toggle source

@return [Set<String>] The list of the weak frameworks required by

this settings file.
# File lib/xcodeproj/config.rb, line 174
def weak_frameworks
  other_linker_flags[:weak_frameworks]
end

Private Instance Methods

extract_hash(argument) click to toggle source

Returns a hash from the given argument reading it from disk if necessary.

@param [String, Pathname, Hash] argument

The source from where the hash should be extracted.

@return [Hash]

# File lib/xcodeproj/config.rb, line 265
def extract_hash(argument)
  return argument if argument.is_a?(Hash)
  if argument.respond_to? :read
    @filepath = Pathname.new(argument.to_path)
    hash_from_file_content(argument.read)
  elsif File.readable?(argument.to_s)
    @filepath = Pathname.new(argument.to_s)
    hash_from_file_content(File.read(argument))
  else
    argument
  end
end
extract_include(line) click to toggle source

Returns the file included by a line of an xcconfig string if present.

@param [String] line

the line to process.

@return [String] the included file. @return [Nil] if no include was found in the line.

# File lib/xcodeproj/config.rb, line 343
def extract_include(line)
  regexp = /#include\??\s*"(.+)"/
  match = line.match(regexp)
  match[1] if match
end
extract_key_value(line) click to toggle source

Returns the key and the value described by the given line of an xcconfig.

@param [String] line

the line to process.

@return [Array] A tuple where the first entry is the key and the second

entry is the value.
# File lib/xcodeproj/config.rb, line 357
def extract_key_value(line)
  match = line.match(KEY_VALUE_PATTERN)
  if match
    key = match[1]
    value = match[2]
    [key.strip, value.strip]
  else
    []
  end
end
hash_from_file_content(string) click to toggle source

Returns a hash from the string representation of an Xcconfig file.

@param [String] string

The string representation of an xcconfig file.

@return [Hash] the hash containing the xcconfig data.

# File lib/xcodeproj/config.rb, line 285
def hash_from_file_content(string)
  hash = {}
  string.split("\n").each do |line|
    uncommented_line = strip_comment(line)
    if include = extract_include(uncommented_line)
      @includes.push normalized_xcconfig_path(include)
    else
      key, value = extract_key_value(uncommented_line)
      next unless key
      value.gsub!(INHERITED_REGEXP) { |m| hash.fetch(key, m) }
      hash[key] = value
    end
  end
  hash
end
merge_attributes!(attributes) click to toggle source

Merges the given attributes hash while ensuring values are not duplicated.

@param [Hash] attributes

The attributes hash to merge into @attributes.

@return [void]

# File lib/xcodeproj/config.rb, line 308
def merge_attributes!(attributes)
  @attributes.merge!(attributes) do |_, v1, v2|
    v1 = v1.strip
    v2 = v2.strip
    v1_split = v1.shellsplit
    v2_split = v2.shellsplit
    if (v2_split - v1_split).empty? || v1_split.first(v2_split.size) == v2_split
      v1
    elsif v2_split.first(v1_split.size) == v1_split
      v2
    else
      "#{v1} #{v2}"
    end
  end
end
normalized_xcconfig_path(path) click to toggle source

Normalizes the given path to an xcconfing file to be used in includes, appending the extension if necessary.

@param [String] path

The path of the file which will be included in the xcconfig.

@return [String] The normalized path.

# File lib/xcodeproj/config.rb, line 376
def normalized_xcconfig_path(path)
  if File.extname(path) == '.xcconfig'
    path
  else
    "#{path}.xcconfig"
  end
end
strip_comment(line) click to toggle source

Strips the comments from a line of an xcconfig string.

@param [String] line

the line to process.

@return [String] the uncommented line.

# File lib/xcodeproj/config.rb, line 331
def strip_comment(line)
  line.partition('//').first
end