xcodeproj 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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