rxcode 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,80 @@
1
+ module RXCode
2
+
3
+ #
4
+ # Represents an XCode environment rooted at a particular path in a filesystem -- typically a project/workspace root
5
+ # directory.
6
+ #
7
+ class Environment
8
+
9
+ def initialize(root)
10
+ @root = root
11
+ @preferences = Preferences.new
12
+ end
13
+
14
+ # ===== ROOT =======================================================================================================
15
+
16
+ attr_reader :root
17
+
18
+ def name
19
+ File.basename(root)
20
+ end
21
+
22
+ # ===== PREFERENCES ================================================================================================
23
+
24
+ attr_reader :preferences
25
+
26
+ # ===== DERIVED DATA ===============================================================================================
27
+
28
+ def global_derived_data_location
29
+ self.preferences.derived_data_location unless preferences.derived_data_location_is_relative_to_workspace?
30
+ end
31
+
32
+ # ===== WORKSPACE ==================================================================================================
33
+
34
+ def workspace
35
+ @workspace ||=
36
+ if ws_path = self.workspace_path
37
+ Workspace.new(ws_path)
38
+ end
39
+ end
40
+
41
+ def workspace_path
42
+ workspace_paths = Dir[File.join(self.root, '*.xcworkspace')]
43
+ preferred_workspace_path = File.join(root, "#{name}.xcworkspace")
44
+
45
+ if workspace_paths.include?(preferred_workspace_path)
46
+
47
+ preferred_workspace_path
48
+
49
+ elsif workspace_paths.length == 1
50
+
51
+ workspace_paths.first
52
+
53
+ else
54
+ project_paths = Dir[File.join(self.root, '*.xcodeproj')]
55
+ preferred_project_path = File.join(root, "#{name}.xcodeproj")
56
+
57
+ project_path =
58
+ if project_paths.include?(preferred_project_path)
59
+ preferred_project_path
60
+ elsif project_paths.length == 1
61
+ project_paths.first
62
+ end
63
+
64
+ if project_path
65
+ project_workspace_path = File.join(project_path, 'project.xcworkspace')
66
+ if RXCode::Workspace.is_workspace_at_path?(project_workspace_path)
67
+ project_workspace_path
68
+ end
69
+ end
70
+
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ def self.env
77
+ @env ||= Environment.new(Dir.pwd)
78
+ end
79
+
80
+ end
@@ -0,0 +1,16 @@
1
+ module RXCode
2
+
3
+ def self.framework(framework_name)
4
+ if workspace = RXCode.env.workspace
5
+
6
+ framework_path = File.join(workspace.built_products_dir, 'Debug', "#{framework_name}.framework")
7
+ ::Kernel.framework(framework_path)
8
+
9
+ else
10
+
11
+ raise "Unable to determine current XCode workspace."
12
+
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,8 @@
1
+ require 'rxcode/models/archive'
2
+ require 'rxcode/models/archived_object'
3
+ require 'rxcode/models/model'
4
+ require 'rxcode/models/project'
5
+ require 'rxcode/models/target'
6
+ require 'rxcode/models/file_reference'
7
+ require 'rxcode/models/build_configuration'
8
+ require 'rxcode/models/build_configuration_list'
@@ -0,0 +1,78 @@
1
+ module RXCode
2
+
3
+ #
4
+ # Processes an NSKeyedArchive file into a set of Ruby objects
5
+ #
6
+ class Archive
7
+
8
+ def initialize(archive_path_or_hash, &object_mapper)
9
+ if archive_path_or_hash.is_a?(String)
10
+
11
+ if File.exist?(archive_path_or_hash)
12
+ @archive_path = archive_path_or_hash
13
+ @archive_hash = Plist::parse_xml(`plutil -convert xml1 -o - '#{archive_path_or_hash}'`)
14
+ else
15
+ @archive_hash = Plist::parse_xml(archive_path_or_hash)
16
+ end
17
+
18
+ elsif archive_path_or_hash.is_a?(Hash)
19
+
20
+ @archive_hash = archive_path_or_hash
21
+
22
+ end
23
+
24
+ @objects = {}
25
+ @object_mapper = object_mapper
26
+ end
27
+
28
+ # ===== ARCHIVE PATH ===============================================================================================
29
+
30
+ attr_reader :archive_path
31
+
32
+ attr_reader :archive_hash
33
+
34
+ attr_accessor :object_mapper
35
+
36
+ # ===== ROOT OBJECT ================================================================================================
37
+
38
+ def root_object_archive_id
39
+ @archive_hash['rootObject']
40
+ end
41
+
42
+ def root_object
43
+ object_with_id(root_object_archive_id)
44
+ end
45
+
46
+ # ===== OBJECTS ====================================================================================================
47
+
48
+ def object_with_id(object_id)
49
+ @objects[object_id] ||=
50
+ if object_hashes[object_id]
51
+ ArchivedObject.new(self, object_id)
52
+ end
53
+ end
54
+
55
+ def model_object_with_id(object_id)
56
+ if o = object_with_id(object_id)
57
+ o.model_object
58
+ end
59
+ end
60
+
61
+ def object_hashes
62
+ archive_hash['objects']
63
+ end
64
+
65
+ def self.archive_at_path(archive_path)
66
+ self.new(archive_path)
67
+ end
68
+
69
+ #
70
+ # Returns the object archived in the file identified by +archive_path+.
71
+ #
72
+ def self.object_at_path(archive_path)
73
+ archive_at_path(archive_path).root_object
74
+ end
75
+
76
+ end
77
+
78
+ end
@@ -0,0 +1,62 @@
1
+ module RXCode
2
+
3
+ class ArchivedObject
4
+
5
+ def initialize(archive, archived_object_id)
6
+ @archive = archive
7
+ @archived_object_id = archived_object_id
8
+ end
9
+
10
+ # ===== ARCHIVE ====================================================================================================
11
+
12
+ attr_reader :archive
13
+
14
+ # ===== ARCHIVE OBJECT ID ==========================================================================================
15
+
16
+ attr_reader :archived_object_id
17
+
18
+ # ===== DATA =======================================================================================================
19
+
20
+ def data
21
+ @data ||= archive.object_hashes[self.archived_object_id]
22
+ end
23
+
24
+ def [](key)
25
+ data[key]
26
+ end
27
+
28
+ def has_key?(key)
29
+ data.has_key?(key)
30
+ end
31
+
32
+ def object_for_key(key)
33
+ object_id = self[key]
34
+ archive.object_with_id(object_id)
35
+ end
36
+
37
+ def array_of_objects_for_key(key)
38
+ self[key].map { |object_id| archive.object_with_id(object_id) }
39
+ end
40
+
41
+ def model_object_for_key(key)
42
+ if o = object_for_key(key)
43
+ o.model_object
44
+ end
45
+ end
46
+
47
+ def array_of_model_objects_for_key(key)
48
+ array_of_objects_for_key(key).map { |o| o.model_object }
49
+ end
50
+
51
+ attr_accessor :model_object
52
+
53
+ def model_object
54
+ @model_object ||=
55
+ if archive.object_mapper
56
+ archive.object_mapper.call(self)
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,19 @@
1
+ module RXCode
2
+
3
+ class BuildConfiguration < Model
4
+
5
+ # ===== NAME =======================================================================================================
6
+
7
+ def name
8
+ archive_object['name']
9
+ end
10
+
11
+ # ===== BUILD SETTINGS =============================================================================================
12
+
13
+ def build_settings
14
+ archive_object['buildSettings']
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,15 @@
1
+ module RXCode
2
+
3
+ class BuildConfigurationList < Model
4
+
5
+ def default_configuration_name
6
+ archive_object['defaultConfigurationName']
7
+ end
8
+
9
+ def build_configurations
10
+ archive_object.array_of_model_objects_for_key('buildConfigurations')
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,23 @@
1
+ module RXCode
2
+
3
+ class FileReference < Model
4
+
5
+ def name
6
+ archive_object['name']
7
+ end
8
+
9
+ def path
10
+ archive_object['path']
11
+ end
12
+
13
+ def source_tree
14
+ archive_object['sourceTree']
15
+ end
16
+
17
+ def last_known_file_type
18
+ archive_object['lastKnownFileType']
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,66 @@
1
+ module RXCode
2
+
3
+ class Model
4
+
5
+ def initialize(source)
6
+ case source
7
+ when ArchivedObject, NilClass
8
+ @archive_object = source
9
+ when Archive
10
+ @archive_object = source.root_object
11
+ when String, Hash
12
+ archive = Archive.new(source)
13
+ @archive_object = archive.rootObject
14
+ else
15
+ raise "Unable to initialize #{self.class.name} from #{source.class.name}: #{source.inspect}"
16
+ end
17
+
18
+ if @archive_object
19
+ @archive_object.model_object = self
20
+ @archive_object.archive.object_mapper ||=
21
+ Proc.new { |archived_object| self.class.map_archived_object(archived_object) }
22
+ end
23
+ end
24
+
25
+ # ===== ARCHIVE ====================================================================================================
26
+
27
+ attr_reader :archive_object
28
+
29
+ def archive
30
+ archive_object.archive
31
+ end
32
+
33
+ def self.class_for_archived_object_type(type)
34
+ case type
35
+ when "PBXProject"
36
+ Project
37
+ when "PBXFileReference"
38
+ FileReference
39
+ when "PBXNativeTarget"
40
+ Target
41
+ when "XCConfigurationList"
42
+ BuildConfigurationList
43
+ when "XCBuildConfiguration"
44
+ BuildConfiguration
45
+ end
46
+ end
47
+
48
+ def self.map_archived_object(archived_object)
49
+ if klass = class_for_archived_object_type(archived_object['isa'])
50
+ klass.new(archived_object)
51
+ end
52
+ end
53
+
54
+ def self.object_at_path(archive_path)
55
+ Archive.new(archive_path).rootObject.model_object
56
+ end
57
+
58
+ # ===== ROOT =======================================================================================================
59
+
60
+ def root
61
+ self.archive.root_object.model_object
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,71 @@
1
+ module RXCode
2
+
3
+ class Project < Model
4
+
5
+ def initialize(path, options = nil)
6
+ raise "#{path.inspect} is not a valid XCode project path" unless self.class.is_project_at_path?(path)
7
+
8
+ super nil
9
+
10
+ @path = path
11
+
12
+ if options && options[:workspace]
13
+ @workspace = options[:workspace]
14
+ end
15
+ end
16
+
17
+ # ===== WORKSPACE ==================================================================================================
18
+
19
+ attr_reader :workspace
20
+
21
+ # ===== PROJECT DISCOVERY & LOOKUP =================================================================================
22
+
23
+ XCODE_PROJECT_EXTENSION = '.xcodeproj'.freeze
24
+
25
+ #
26
+ # Determines if the provided file path is an XCode project
27
+ #
28
+ def self.is_project_at_path?(project_path)
29
+ File.directory?(project_path) && File.extname(project_path) == XCODE_PROJECT_EXTENSION
30
+ end
31
+
32
+ # ===== PROJECT PATH ===============================================================================================
33
+
34
+ attr_reader :path
35
+
36
+ def project_archive_path
37
+ File.join(self.path, 'project.pbxproj')
38
+ end
39
+
40
+ def archive
41
+ @archive ||=
42
+ begin
43
+ a = Archive.new(project_archive_path) { |archived_object| Model.map_archived_object(archived_object) }
44
+ a.root_object.model_object = self
45
+ a
46
+ end
47
+ end
48
+
49
+ def archive_object
50
+ archive.root_object
51
+ end
52
+
53
+ # ===== TARGETS ====================================================================================================
54
+
55
+ def targets
56
+ archive_object.array_of_model_objects_for_key('targets')
57
+ end
58
+
59
+ def target_names
60
+ targets.map(&:name)
61
+ end
62
+
63
+ # ===== BUILD CONFIGURATIONS =======================================================================================
64
+
65
+ def build_configuration_list
66
+ archive_object.model_object_for_key('buildConfigurationList')
67
+ end
68
+
69
+ end
70
+
71
+ end