xcodeproj 0.4.0 → 0.4.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.
@@ -21,13 +21,10 @@ static VALUE
21
21
  cfstr_to_str(const void *cfstr) {
22
22
  CFDataRef data = CFStringCreateExternalRepresentation(NULL, cfstr, kCFStringEncodingUTF8, 0);
23
23
  assert(data != NULL);
24
- long len = (long)CFDataGetLength(data);
25
- char *buf = (char *)malloc(len+1);
26
- assert(buf != NULL);
27
- CFDataGetBytes(data, CFRangeMake(0, len), buf);
24
+ long len = (long)CFDataGetLength(data);
25
+ char *buf = (char *)CFDataGetBytePtr(data);
28
26
 
29
27
  register VALUE str = rb_str_new(buf, len);
30
- free(buf);
31
28
 
32
29
  // force UTF-8 encoding in Ruby 1.9+
33
30
  ID forceEncodingId = rb_intern("force_encoding");
@@ -35,6 +32,7 @@ cfstr_to_str(const void *cfstr) {
35
32
  rb_funcall(str, forceEncodingId, 1, rb_str_new("UTF-8", 5));
36
33
  }
37
34
 
35
+ CFRelease(data);
38
36
  return str;
39
37
  }
40
38
 
data/lib/xcodeproj.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Xcodeproj
2
- VERSION = '0.4.0'
2
+ VERSION = '0.4.1'
3
3
 
4
4
  class PlainInformative < StandardError
5
5
  end
@@ -12,17 +12,17 @@ module Xcodeproj
12
12
  #
13
13
  attr_accessor :attributes
14
14
 
15
- # @return [Array<String>] The list of the frameworks required by this
15
+ # @return [Set<String>] The list of the frameworks required by this
16
16
  # settings file.
17
17
  #
18
18
  attr_accessor :frameworks
19
19
 
20
- # @return [Array<String>] The list of the *weak* frameworks required by
20
+ # @return [Set<String>] The list of the *weak* frameworks required by
21
21
  # this settings file.
22
22
  #
23
23
  attr_accessor :weak_frameworks
24
24
 
25
- # @return [Array<String>] The list of the libraries required by this
25
+ # @return [Set<String>] The list of the libraries required by this
26
26
  # settings file.
27
27
  #
28
28
  attr_accessor :libraries
@@ -43,19 +43,21 @@ module Xcodeproj
43
43
  merge!(extract_hash(xcconfig_hash_or_file))
44
44
  end
45
45
 
46
+ #-------------------------------------------------------------------------#
46
47
 
47
- #@! group Serialization
48
+ # @!group Serialization
48
49
 
49
- # Serializes the internal data in the xcconfig format.
50
+ # Sorts the internal data by setting name and serializes it in the xcconfig
51
+ # format.
50
52
  #
51
53
  # @example
52
54
  #
53
55
  # config = Config.new('PODS_ROOT' => '"$(SRCROOT)/Pods"', 'OTHER_LDFLAGS' => '-lxml2')
54
- # config.to_s # => "PODS_ROOT = \"$(SRCROOT)/Pods\"\nOTHER_LDFLAGS = -lxml2"
56
+ # config.to_s # => "OTHER_LDFLAGS = -lxml2\nPODS_ROOT = \"$(SRCROOT)/Pods\""
55
57
  #
56
58
  # @return [String] The serialized internal data.
57
59
  def to_s
58
- to_hash.map { |key, value| "#{key} = #{value}" }.join("\n")
60
+ to_hash.sort_by(&:first).map { |k, v| "#{k} = #{v}" }.join("\n")
59
61
  end
60
62
 
61
63
  # @return [void] Writes the serialized representation of the internal data
@@ -83,13 +85,13 @@ module Xcodeproj
83
85
  hash
84
86
  end
85
87
 
88
+ #-------------------------------------------------------------------------#
86
89
 
87
-
88
- #@! group Merging
90
+ # @!group Merging
89
91
 
90
92
  # Merges the given xcconfig hash or Config into the internal data.
91
93
  #
92
- # If a key in the given hash already exists, in the internal data, then its
94
+ # If a key in the given hash already exists in the internal data then its
93
95
  # value is appended to the value in the internal data.
94
96
  #
95
97
  # @example
@@ -103,41 +105,42 @@ module Xcodeproj
103
105
  def merge!(xcconfig)
104
106
  if xcconfig.is_a? Config
105
107
  @attributes.merge!(xcconfig.attributes) { |key, v1, v2| "#{v1} #{v2}" }
106
- @libraries.merge xcconfig.libraries
107
- @frameworks.merge xcconfig.frameworks
108
- @weak_frameworks.merge xcconfig.weak_frameworks
108
+ @libraries.merge(xcconfig.libraries)
109
+ @frameworks.merge(xcconfig.frameworks)
110
+ @weak_frameworks.merge(xcconfig.weak_frameworks)
109
111
  else
110
- @attributes.merge!(xcconfig.to_hash) { |key, v1, v2| "#{v1} #{v2}" }
111
- # Parse frameworks and libraries. Then remove the from the linker flags
112
- flags = @attributes['OTHER_LDFLAGS']
113
- return unless flags
114
-
115
- frameworks = flags.scan(/-framework\s+([^\s]+)/).map { |m| m[0] }
116
- weak_frameworks = flags.scan(/-weak_framework\s+([^\s]+)/).map { |m| m[0] }
117
- libraries = flags.scan(/-l ?([^\s]+)/).map { |m| m[0] }
118
- @frameworks.merge frameworks
119
- @weak_frameworks.merge weak_frameworks
120
- @libraries.merge libraries
121
-
122
- new_flags = flags.dup
123
- frameworks.each {|f| new_flags.gsub!("-framework #{f}", "") }
124
- weak_frameworks.each {|f| new_flags.gsub!("-weak_framework #{f}", "") }
125
- libraries.each {|l| new_flags.gsub!("-l#{l}", ""); new_flags.gsub!("-l #{l}", "") }
126
- @attributes['OTHER_LDFLAGS'] = new_flags.gsub("\w*", ' ').strip
112
+ @attributes.merge!(xcconfig.to_hash) { |key, v1, v2| "#{v1} #{v2}" }
113
+ # Parse frameworks and libraries. Then remove the from the linker flags
114
+ flags = @attributes['OTHER_LDFLAGS']
115
+ return unless flags
116
+
117
+ frameworks = flags.scan(/-framework\s+([^\s]+)/).map { |m| m[0] }
118
+ weak_frameworks = flags.scan(/-weak_framework\s+([^\s]+)/).map { |m| m[0] }
119
+ libraries = flags.scan(/-l ?([^\s]+)/).map { |m| m[0] }
120
+ @frameworks.merge frameworks
121
+ @weak_frameworks.merge weak_frameworks
122
+ @libraries.merge libraries
123
+
124
+ new_flags = flags.dup
125
+ frameworks.each {|f| new_flags.gsub!("-framework #{f}", "") }
126
+ weak_frameworks.each {|f| new_flags.gsub!("-weak_framework #{f}", "") }
127
+ libraries.each {|l| new_flags.gsub!("-l#{l}", ""); new_flags.gsub!("-l #{l}", "") }
128
+ @attributes['OTHER_LDFLAGS'] = new_flags.gsub("\w*", ' ').strip
127
129
  end
128
130
  end
129
131
  alias_method :<<, :merge!
130
132
 
131
133
  def merge(config)
132
- self.dup.tap { |x|x.merge!(config) }
134
+ self.dup.tap { |x| x.merge!(config) }
133
135
  end
134
136
 
135
137
  def dup
136
138
  Xcodeproj::Config.new(self.to_hash.dup)
137
139
  end
138
140
 
141
+ #-------------------------------------------------------------------------#
139
142
 
140
- #@! group Object methods
143
+ # @!group Object methods
141
144
 
142
145
  def inspect
143
146
  to_hash.inspect
@@ -147,6 +150,10 @@ module Xcodeproj
147
150
  other.respond_to?(:to_hash) && other.to_hash == self.to_hash
148
151
  end
149
152
 
153
+ #-------------------------------------------------------------------------#
154
+
155
+ # @!group Private Helpers
156
+
150
157
  private
151
158
 
152
159
  def extract_hash(argument)
@@ -4,6 +4,14 @@ module Xcodeproj
4
4
  #
5
5
  module Constants
6
6
 
7
+ # The last known iOS SDK (stable).
8
+ #
9
+ LAST_KNOWN_IOS_SDK = '6.0'
10
+
11
+ # The last known OS X SDK (stable).
12
+ #
13
+ LAST_KNOWN_OSX_SDK = '10.8'
14
+
7
15
  # The last known archive version to Xcodeproj.
8
16
  #
9
17
  LAST_KNOWN_ARCHIVE_VERSION = 1
@@ -309,7 +309,7 @@ module Xcodeproj
309
309
  @available_uuids += uniques
310
310
  end
311
311
 
312
- ## CONVENIENCE METHODS #####################################################
312
+ #-------------------------------------------------------------------------#
313
313
 
314
314
  # @!group Convenience accessors
315
315
 
@@ -352,7 +352,7 @@ module Xcodeproj
352
352
  # frameworks.name #=> 'Frameworks'
353
353
  # main_group.children.include? frameworks #=> True
354
354
  #
355
- # @param [String] group_path
355
+ # @param [String] group_path @see MobileCoreServices
356
356
  #
357
357
  # @return [PBXGroup] the group at the given subpath.
358
358
  #
@@ -411,7 +411,7 @@ module Xcodeproj
411
411
 
412
412
 
413
413
 
414
- # @!group Convenience methods for generating objects
414
+ # @!group Helpers for generating objects
415
415
 
416
416
  # Creates a new file reference at the given subpath of the main group.
417
417
  #
@@ -438,55 +438,81 @@ module Xcodeproj
438
438
  # The file reference can then be added to the build files of a
439
439
  # {PBXFrameworksBuildPhase}.
440
440
  #
441
- # @example
441
+ # @example Adding QuartzCore
442
442
  #
443
- # framework = project.add_system_framework('QuartzCore')
443
+ # framework = project.add_system_framework('QuartzCore', :ios)
444
444
  #
445
445
  # target = project.targets.first
446
446
  # build_phase = target.frameworks_build_phases.first
447
447
  # build_phase.files << framework.buildFiles.new
448
448
  #
449
- # @param [String] name The name of a framework in the SDK System
450
- # directory.
451
- # @return [PBXFileReference] The file reference object.
449
+ # @param [String] name
450
+ # The name of a framework.
451
+ #
452
+ # @param [PBXNativeTarget] target
453
+ # The target for which to add the framework.
454
+ #
455
+ # @note This method adds a reference to the highest know SDK for the
456
+ # given platform.
457
+ #
458
+ # @return [PBXFileReference] The generated file reference.
452
459
  #
453
- def add_system_framework(name)
454
- path = "System/Library/Frameworks/#{name}.framework"
455
- if file = frameworks_group.files.first { |f| f.path == path }
460
+ def add_system_framework(name, target)
461
+ sdk = target.sdk
462
+ raise "Unable to find and SDK for the target `#{target.name}`" unless sdk
463
+ if sdk.include?('iphoneos')
464
+ if sdk == 'iphoneos'
465
+ base_dir = "Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS#{Constants::LAST_KNOWN_IOS_SDK}.sdk/"
466
+ else
467
+ base_dir = "Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS#{sdk.gsub('iphoneos', '')}.sdk/"
468
+ end
469
+ elsif sdk.include?('macosx')
470
+ if sdk == 'macosx'
471
+ base_dir = "Platforms/MacOSX.platform/Developer/SDKs/MacOSX#{Constants::LAST_KNOWN_OSX_SDK}.sdk/"
472
+ else
473
+ base_dir = "Platforms/MacOSX.platform/Developer/SDKs/MacOSX#{sdk.gsub('iphoneos', '')}.sdk/"
474
+ end
475
+ end
476
+ path = base_dir + "System/Library/Frameworks/#{name}.framework"
477
+
478
+ if file = frameworks_group.files.find { |f| f.path == path }
456
479
  file
457
480
  else
458
481
  framework_ref = frameworks_group.new_file(path)
459
482
  framework_ref.name = "#{name}.framework"
460
- framework_ref.source_tree = 'SDKROOT'
483
+ framework_ref.source_tree = 'DEVELOPER_DIR'
484
+ framework_ref.last_known_file_type = "wrapper.framework"
461
485
  framework_ref
462
486
  end
463
487
  end
464
488
 
465
- # @return [PBXNativeTarget] Creates a new target and adds it to the
466
- # project.
489
+ # Creates a new target and adds it to the project.
490
+ #
491
+ # The target is configured for the given platform and its file reference it
492
+ # is added to the {products_group}.
467
493
  #
468
- # The target is configured for the given platform and its file reference
469
- # it is added to the {products_group}.
494
+ # The target is pre-populated with common build phases, and all the
495
+ # Frameworks of the project are added to to its Frameworks phase.
470
496
  #
471
- # The target is pre-populated with common build phases, and all the
472
- # Frameworks of the project are added to to its Frameworks phase.
497
+ # @todo Adding all the Frameworks is required by CocoaPods and should be
498
+ # performed there.
473
499
  #
474
- # @todo Adding all the Frameworks is required by CocoaPods and should be
475
- # performed there.
500
+ # @param [Symbol] type
501
+ # the type of target. Can be `:application`, `:dynamic_library` or
502
+ # `:static_library`.
476
503
  #
477
- # @param [Symbol] type
478
- # the type of target.
479
- # Can be `:application`, `:dynamic_library` or `:static_library`.
504
+ # @param [String] name
505
+ # the name of the static library product.
480
506
  #
481
- # @param [String] name
482
- # the name of the static library product.
507
+ # @param [Symbol] platform
508
+ # the platform of the static library. Can be `:ios` or `:osx`.
483
509
  #
484
- # @param [Symbol] platform
485
- # the platform of the static library.
486
- # Can be `:ios` or `:osx`.
510
+ # @param [String] deployment_target
511
+ # the deployment target for the platform.
487
512
  #
488
- def new_target(type, name, platform)
489
- add_system_framework(platform == :ios ? 'Foundation' : 'Cocoa')
513
+ # @return [PBXNativeTarget] the target.
514
+ #
515
+ def new_target(type, name, platform, deployment_target = nil)
490
516
 
491
517
  # Target
492
518
  target = new(PBXNativeTarget)
@@ -494,16 +520,20 @@ module Xcodeproj
494
520
  target.name = name
495
521
  target.product_name = name
496
522
  target.product_type = Constants::PRODUCT_TYPE_UTI[type]
497
- target.build_configuration_list = configuration_list(platform)
523
+ target.build_configuration_list = configuration_list(platform, deployment_target)
498
524
 
499
525
  # Product
500
526
  product = products_group.new_static_library(name)
501
527
  target.product_reference = product
502
528
 
529
+ # Frameworks
530
+ framework_name = (platform == :ios) ? 'Foundation' : 'Cocoa'
531
+ framework_ref = add_system_framework(framework_name, target)
532
+
503
533
  # Build phases
504
534
  target.build_phases << new(PBXSourcesBuildPhase)
505
535
  frameworks_phase = new(PBXFrameworksBuildPhase)
506
- frameworks_group.files.each { |framework| frameworks_phase.add_file_reference(framework) }
536
+ frameworks_phase.add_file_reference(framework_ref)
507
537
  target.build_phases << frameworks_phase
508
538
 
509
539
  target
@@ -512,23 +542,26 @@ module Xcodeproj
512
542
  # Returns a new configuration list, populated with release and debug
513
543
  # configurations with common build settings for the given platform.
514
544
  #
515
- # @param [Symbol] platform
516
- # the platform for the configuration list, can be `:ios` or `:osx`.
545
+ # @param [Symbol] platform
546
+ # the platform for the configuration list, can be `:ios` or `:osx`.
547
+ #
548
+ # @param [String] deployment_target
549
+ # the deployment target for the platform.
517
550
  #
518
551
  # @return [XCConfigurationList] the generated configuration list.
519
552
  #
520
- def configuration_list(platform)
553
+ def configuration_list(platform, deployment_target = nil)
521
554
  cl = new(XCConfigurationList)
522
555
  cl.default_configuration_is_visible = '0'
523
556
  cl.default_configuration_name = 'Release'
524
557
 
525
558
  release_conf = new(XCBuildConfiguration)
526
559
  release_conf.name = 'Release'
527
- release_conf.build_settings = configuration_list_settings(platform, :release)
560
+ release_conf.build_settings = common_build_settings(:release, platform, deployment_target)
528
561
 
529
562
  debug_conf = new(XCBuildConfiguration)
530
563
  debug_conf.name = 'Debug'
531
- debug_conf.build_settings = configuration_list_settings(platform, :debug)
564
+ debug_conf.build_settings = common_build_settings(:debug, platform, deployment_target)
532
565
 
533
566
  cl.build_configurations << release_conf
534
567
  cl.build_configurations << debug_conf
@@ -538,21 +571,32 @@ module Xcodeproj
538
571
  # Returns the common build settings for a given platform and configuration
539
572
  # name.
540
573
  #
541
- # @param [Symbol] platform
542
- # the platform for the build settings, can be `:ios` or `:osx`.
574
+ # @param [Symbol] type
575
+ # the type of the build configuration, can be `:release` or
576
+ # `:debug`.
577
+ #
578
+ # @param [Symbol] platform
579
+ # the platform for the build settings, can be `:ios` or `:osx`.
543
580
  #
544
- # @param [Symbol] name
545
- # the name of the build configuration, can be `:release` or `:debug`.
581
+ # @param [String] deployment_target
582
+ # the deployment target for the platform.
546
583
  #
547
584
  # @return [Hash] The common build settings
548
585
  #
549
- def configuration_list_settings(platform, name)
586
+ def common_build_settings(type, platform, deployment_target = nil)
550
587
  common_settings = Constants::COMMON_BUILD_SETTINGS
551
- bs = common_settings[:all].dup
552
- bs = bs.merge(common_settings[name])
553
- bs = bs.merge(common_settings[platform])
554
- bs = bs.merge(common_settings[[platform, name]])
555
- bs
588
+ settings = common_settings[:all].dup
589
+ settings.merge!(common_settings[type])
590
+ settings.merge!(common_settings[platform])
591
+ settings.merge!(common_settings[[platform, type]])
592
+ if deployment_target
593
+ if platform == :ios
594
+ settings['IPHONEOS_DEPLOYMENT_TARGET'] = deployment_target
595
+ elsif platform == :osx
596
+ settings['MACOSX_DEPLOYMENT_TARGET'] = deployment_target
597
+ end
598
+ end
599
+ settings
556
600
  end
557
601
 
558
602
  end
@@ -35,7 +35,9 @@ module Xcodeproj
35
35
  #
36
36
  class AbstractObject
37
37
 
38
- # @return [String] the isa of the class.
38
+ # @!group AbstractObject
39
+
40
+ # @return [String] the ISA of the class.
39
41
  #
40
42
  def self.isa
41
43
  @isa ||= name.split('::').last
@@ -57,6 +59,8 @@ module Xcodeproj
57
59
  # @param [String] uuid
58
60
  # the UUID of the new object.
59
61
  #
62
+ # @visibility private
63
+ #
60
64
  def initialize(project, uuid)
61
65
  @project, @uuid = project, uuid
62
66
  @isa = self.class.isa
@@ -67,11 +71,13 @@ module Xcodeproj
67
71
  # Initializes the object with the default values of simple attributes.
68
72
  #
69
73
  # This method is called by the {Project#new} and is not performed on
70
- # initialization to prevet adding defaults to objects generated by a
74
+ # initialization to prevent adding defaults to objects generated by a
71
75
  # plist.
72
76
  #
73
77
  # @return [void]
74
78
  #
79
+ # @visibility private
80
+ #
75
81
  def initialize_defaults
76
82
  simple_attributes.each { |a| a.set_default(self) }
77
83
  end
@@ -116,6 +122,8 @@ module Xcodeproj
116
122
  # @return [Array<ObjectList>] The list of the objects that have a
117
123
  # reference to this object.
118
124
  #
125
+ # @visibility private
126
+ #
119
127
  attr_reader :referrers
120
128
 
121
129
  # Informs the object that another object is referencing it. If the
@@ -124,6 +132,8 @@ module Xcodeproj
124
132
  #
125
133
  # @return [void]
126
134
  #
135
+ # @visibility private
136
+ #
127
137
  def add_referrer(referrer)
128
138
  @referrers << referrer
129
139
  @project.objects_by_uuid[uuid] = self
@@ -135,6 +145,8 @@ module Xcodeproj
135
145
  #
136
146
  # @return [void]
137
147
  #
148
+ # @visibility private
149
+ #
138
150
  def remove_referrer(referrer)
139
151
  @referrers.delete(referrer)
140
152
  if @referrers.count == 0
@@ -146,6 +158,8 @@ module Xcodeproj
146
158
  #
147
159
  # @return [void]
148
160
  #
161
+ # @visibility private
162
+ #
149
163
  def remove_reference(object)
150
164
  to_one_attributes.each do |attrb|
151
165
  value = attrb.get_value(self)
@@ -163,6 +177,8 @@ module Xcodeproj
163
177
  end
164
178
  end
165
179
 
180
+ #---------------------------------------------------------------------#
181
+
166
182
  # @!group Plist related methods
167
183
 
168
184
  # Configures the object with the objects hash from a plist.
@@ -173,6 +189,8 @@ module Xcodeproj
173
189
  #
174
190
  # @return [void]
175
191
  #
192
+ # @visibility private
193
+ #
176
194
  def configure_with_plist(objects_by_uuid_plist)
177
195
  object_plist = objects_by_uuid_plist[uuid].dup
178
196
 
@@ -188,7 +206,7 @@ module Xcodeproj
188
206
  ref_uuid = object_plist[attrb.plist_name]
189
207
  if ref_uuid
190
208
  ref = object_with_uuid(ref_uuid, objects_by_uuid_plist, attrb)
191
- attrb.set_value(self, ref)
209
+ attrb.set_value(self, ref) if ref
192
210
  end
193
211
  object_plist.delete(attrb.plist_name)
194
212
  end
@@ -197,7 +215,8 @@ module Xcodeproj
197
215
  ref_uuids = object_plist[attrb.plist_name] || []
198
216
  list = attrb.get_value(self)
199
217
  ref_uuids.each do |uuid|
200
- list << object_with_uuid(uuid, objects_by_uuid_plist, attrb)
218
+ ref = object_with_uuid(uuid, objects_by_uuid_plist, attrb)
219
+ list << ref if ref
201
220
  end
202
221
  object_plist.delete(attrb.plist_name)
203
222
  end
@@ -208,7 +227,8 @@ module Xcodeproj
208
227
  hashes.each do |hash|
209
228
  dictionary = ObjectDictionary.new(attrb, self)
210
229
  hash.each do |key, uuid|
211
- dictionary[key] = object_with_uuid(uuid, objects_by_uuid_plist, attrb)
230
+ ref = object_with_uuid(uuid, objects_by_uuid_plist, attrb)
231
+ dictionary[key] = ref if ref
212
232
  end
213
233
  list << dictionary
214
234
  end
@@ -222,7 +242,7 @@ module Xcodeproj
222
242
  end
223
243
  end
224
244
 
225
- # Initializes and returns the object with the given uuid.
245
+ # Initializes and returns the object with the given UUID.
226
246
  #
227
247
  # @param [String] uuid
228
248
  # The UUID of the object that should be initialized.
@@ -237,15 +257,18 @@ module Xcodeproj
237
257
  #
238
258
  # @raise If the hash for the given UUID contains an unknown ISA.
239
259
  #
240
- # @raise If the UUID can't be found in the objects hash.
241
- #
242
260
  # @return [AbstractObject] the initialized object.
261
+ # @return [Nil] if the UUID could not be found in the objects hash. In
262
+ # this case a warning is printed to STDERR.
263
+ #
264
+ # @visibility private
243
265
  #
244
266
  def object_with_uuid(uuid, objects_by_uuid_plist, attribute)
245
267
  unless object = project.objects_by_uuid[uuid] || project.new_from_plist(uuid, objects_by_uuid_plist)
246
- raise "`#{inspect}` attempted to initialize an object with an unknown UUID: "\
247
- "`#{uuid}` for attribute: `#{attribute.name}`\n" \
248
- "Please file and issue: https://github.com/CocoaPods/Xcodeproj/issues/new"
268
+ STDERR.puts "`#{inspect}` attempted to initialize an object with "\
269
+ "an unknown UUID. `#{uuid}` for attribute: `#{attribute.name}`."\
270
+ " This can be the result of a merge and the unkonw UUID is " \
271
+ "being discarded."
249
272
  end
250
273
  object
251
274
  rescue NameError => exception
@@ -289,14 +312,16 @@ module Xcodeproj
289
312
 
290
313
  # Returns a cascade representation of the object without UUIDs.
291
314
  #
292
- # This method is designed to work in conjuction with {Hash#recursive_diff}
293
- # to provie a complete, yet redable, diff of two projects *not* affected by
294
- # isa differences.
315
+ # This method is designed to work in conjunction with
316
+ # {Hash#recursive_diff} to provide a complete, yet readable, diff of
317
+ # two projects *not* affected by ISA differences.
318
+ #
319
+ # @todo The current implementation might lead to infinite loops.
295
320
  #
296
- # @todo current implementation might cause infinite loops.
321
+ # @return [Hash] a hash representation of the project different from
322
+ # the plist one.
297
323
  #
298
- # @return [Hash] a hash reppresentation of the project different from the
299
- # plist one.
324
+ # @visibility private
300
325
  #
301
326
  def to_tree_hash
302
327
  hash = {}
@@ -326,7 +351,7 @@ module Xcodeproj
326
351
  hash
327
352
  end
328
353
 
329
- # !@group Object methods
354
+ # @!group Object methods
330
355
 
331
356
  def ==(other)
332
357
  other.is_a?(AbstractObject) && self.to_plist == other.to_plist