zerg_xcode 0.3.5 → 0.4.0

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.
Files changed (61) hide show
  1. data/.document +5 -0
  2. data/.project +17 -0
  3. data/Gemfile +10 -0
  4. data/Gemfile.lock +30 -0
  5. data/Rakefile +50 -23
  6. data/VERSION +1 -0
  7. data/lib/zerg_xcode/file_format/archiver.rb +0 -24
  8. data/lib/zerg_xcode/file_format/id_generator.rb +30 -0
  9. data/lib/zerg_xcode/file_format/lexer.rb +113 -56
  10. data/lib/zerg_xcode/file_format/parser.rb +28 -34
  11. data/lib/zerg_xcode/file_format/scan_buffer.rb +46 -0
  12. data/lib/zerg_xcode/objects/pbx_project.rb +1 -1
  13. data/lib/zerg_xcode/objects/xcode_object.rb +2 -1
  14. data/lib/zerg_xcode/{file_format/paths.rb → paths.rb} +5 -6
  15. data/lib/zerg_xcode/shortcuts.rb +2 -2
  16. data/lib/zerg_xcode.rb +7 -1
  17. data/spec/archiver_spec.rb +83 -0
  18. data/spec/builder/runner_spec.rb +27 -0
  19. data/spec/builder/sdk_spec.rb +11 -0
  20. data/spec/encoder_spec.rb +17 -0
  21. data/{test → spec}/fixtures/ClosedLib/ClosedLib.xcodeproj/project.pbxproj +0 -0
  22. data/{test → spec}/fixtures/ClosedLib/ClosedLib_Prefix.pch +0 -0
  23. data/{test → spec}/fixtures/ClosedLib/ClosedNative.c +0 -0
  24. data/{test → spec}/fixtures/ClosedLib/ClosedNative.h +0 -0
  25. data/{test → spec}/fixtures/FlatTestApp/FlatTestApp.xcodeproj/project.pbxproj +0 -0
  26. data/{test → spec}/fixtures/TestApp/TestApp.xcodeproj/project.pbxproj +0 -0
  27. data/{test → spec}/fixtures/TestApp30.xcodeproj/project.pbxproj +0 -0
  28. data/{test → spec}/fixtures/TestLib30.xcodeproj/project.pbxproj +0 -0
  29. data/{test → spec}/fixtures/ZergSupport.xcodeproj/project.pbxproj +0 -0
  30. data/{test → spec}/fixtures/project.pbxproj +0 -0
  31. data/{test → spec}/fixtures/project.pbxproj.compat +0 -0
  32. data/spec/id_generator_spec.rb +38 -0
  33. data/spec/lexer_spec.rb +111 -0
  34. data/spec/parser_spec.rb +34 -0
  35. data/spec/paths_spec.rb +75 -0
  36. data/spec/shortcuts_spec.rb +24 -0
  37. data/test/objects/pbx_build_file_test.rb +3 -3
  38. data/test/objects/pbx_build_phase_test.rb +1 -1
  39. data/test/objects/pbx_container_item_proxy_test.rb +1 -1
  40. data/test/objects/pbx_group_test.rb +1 -1
  41. data/test/objects/pbx_native_target_test.rb +2 -2
  42. data/test/objects/pbx_project_test.rb +9 -9
  43. data/test/objects/pbx_target_dependency_test.rb +1 -1
  44. data/test/objects/xc_configuration_list_test.rb +1 -1
  45. data/test/plugins/addlibrary_test.rb +2 -2
  46. data/test/plugins/core/core_test.rb +1 -1
  47. data/test/plugins/import_test.rb +71 -71
  48. data/test/plugins/irb_test.rb +3 -3
  49. data/test/plugins/ls_test.rb +3 -3
  50. data/test/plugins/lstargets_test.rb +3 -3
  51. data/test/plugins/retarget_test.rb +2 -2
  52. data/zerg_xcode.gemspec +112 -17
  53. metadata +115 -113
  54. data/test/builder/runner_test.rb +0 -35
  55. data/test/builder/sdk_test.rb +0 -17
  56. data/test/file_format/archiver_test.rb +0 -74
  57. data/test/file_format/encoder_test.rb +0 -15
  58. data/test/file_format/lexer_test.rb +0 -60
  59. data/test/file_format/parser_test.rb +0 -49
  60. data/test/file_format/path_test.rb +0 -47
  61. data/test/shortcuts_test.rb +0 -22
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.project ADDED
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projectDescription>
3
+ <name>zerg_xcode</name>
4
+ <comment></comment>
5
+ <projects>
6
+ </projects>
7
+ <buildSpec>
8
+ <buildCommand>
9
+ <name>org.rubypeople.rdt.core.rubybuilder</name>
10
+ <arguments>
11
+ </arguments>
12
+ </buildCommand>
13
+ </buildSpec>
14
+ <natures>
15
+ <nature>org.rubypeople.rdt.core.rubynature</nature>
16
+ </natures>
17
+ </projectDescription>
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source :rubygems
2
+
3
+ group :development do
4
+ gem 'bundler', '~> 1.0.0'
5
+ gem 'jeweler', '~> 1.6.4'
6
+ gem 'rcov', '>= 0'
7
+ gem 'rspec', '~> 2.7.0'
8
+
9
+ gem 'flexmock'
10
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.3)
5
+ flexmock (0.9.0)
6
+ git (1.2.5)
7
+ jeweler (1.6.4)
8
+ bundler (~> 1.0)
9
+ git (>= 1.2.5)
10
+ rake
11
+ rake (0.9.2.2)
12
+ rcov (0.9.11)
13
+ rspec (2.7.0)
14
+ rspec-core (~> 2.7.0)
15
+ rspec-expectations (~> 2.7.0)
16
+ rspec-mocks (~> 2.7.0)
17
+ rspec-core (2.7.1)
18
+ rspec-expectations (2.7.0)
19
+ diff-lcs (~> 1.1.2)
20
+ rspec-mocks (2.7.0)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ bundler (~> 1.0.0)
27
+ flexmock
28
+ jeweler (~> 1.6.4)
29
+ rcov
30
+ rspec (~> 2.7.0)
data/Rakefile CHANGED
@@ -5,29 +5,56 @@
5
5
  # License:: MIT
6
6
 
7
7
  require 'rubygems'
8
- require 'echoe'
9
-
10
- Echoe.new('zerg_xcode') do |p|
11
- p.project = 'zerglings' # rubyforge project
12
-
13
- p.author = 'Victor Costan'
14
- p.email = 'victor@zergling.net'
15
- p.summary = 'Automated modifications for Xcode project files'
16
- p.url = 'http://www.zergling.net/'
17
- p.runtime_dependencies = []
18
- p.dependencies = []
19
- # remove echoe, because it becomes a runtime dependency for rubygems < 1.2
20
- p.development_dependencies = []
21
- p.eval = proc do |p|
22
- p.default_executable = 'bin/zerg-xcode'
23
- end
24
-
25
- p.need_tar_gz = true
26
- p.need_zip = true
27
- p.rdoc_pattern = /^(lib|bin|tasks|ext)|^BUILD|^README|^CHANGELOG|^LICENSE$/
8
+ require 'bundler'
9
+ begin
10
+ Bundler.setup(:default, :development)
11
+ rescue Bundler::BundlerError => e
12
+ $stderr.puts e.message
13
+ $stderr.puts "Run `bundle install` to install missing gems"
14
+ exit e.status_code
15
+ end
16
+ require 'rake'
17
+
18
+ require 'jeweler'
19
+ Jeweler::Tasks.new do |gem|
20
+ gem.name = 'zerg_xcode'
21
+ gem.homepage = "http://github.com/zerglings/zerg_xcode"
22
+ gem.authors = ['Victor Costan']
23
+ gem.email = 'victor@zergling.net'
24
+ gem.summary = 'Automated modifications for Xcode project files'
28
25
  end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ require 'rspec/core/rake_task'
36
+ RSpec::Core::RakeTask.new(:spec)
29
37
 
30
- if $0 == __FILE__
31
- Rake.application = Rake::Application.new
32
- Rake.application.run
38
+ require 'rcov/rcovtask'
39
+ Rcov::RcovTask.new do |test|
40
+ test.libs << 'test'
41
+ test.pattern = 'test/**/test_*.rb'
42
+ test.verbose = true
43
+ test.rcov_opts << '--exclude "gems/*"'
44
+ end
45
+
46
+ task :default => [:spec, :test]
47
+
48
+ begin
49
+ require 'rdoc/task'
50
+ RDoc::Task.new do |rdoc|
51
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
52
+
53
+ rdoc.rdoc_dir = 'rdoc'
54
+ rdoc.title = "zerg_xcode #{version}"
55
+ rdoc.rdoc_files.include('README*')
56
+ rdoc.rdoc_files.include('lib/**/*.rb')
57
+ end
58
+ rescue LoadError => e
59
+ # Rdoc compatible with 1.8 doesn't have rdoc/task
33
60
  end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.0
@@ -71,30 +71,6 @@ module Archiver
71
71
  'objects' => objects }
72
72
  end
73
73
 
74
- # Generates archive IDs for objects.
75
- class IdGenerator
76
- def initialize
77
- @assigned_ids = Set.new
78
- end
79
-
80
- def new_id
81
- loop do
82
- id = (0...24).map { '%02X' % rand(256) }.join
83
- next if @assigned_ids.include? id
84
- @assigned_ids << id
85
- return id
86
- end
87
- end
88
-
89
- def id_for(object)
90
- if object.archive_id && !@assigned_ids.include?(object.archive_id)
91
- @assigned_ids << object.archive_id
92
- return object.archive_id
93
- else
94
- return new_id
95
- end
96
- end
97
- end
98
74
  end # module ZergXcode::Archiver
99
75
 
100
76
  end # namespace ZergXcode
@@ -0,0 +1,30 @@
1
+
2
+ # :nodoc: namespace
3
+ module ZergXcode
4
+
5
+ # Generates archive IDs for objects.
6
+ class IdGenerator
7
+ def initialize
8
+ @assigned_ids = Set.new
9
+ end
10
+
11
+ def new_id
12
+ loop do
13
+ id = (0...24).map { '%02X' % rand(256) }.join
14
+ next if @assigned_ids.include? id
15
+ @assigned_ids << id
16
+ return id
17
+ end
18
+ end
19
+
20
+ def id_for(object)
21
+ if object.archive_id && !@assigned_ids.include?(object.archive_id)
22
+ @assigned_ids << object.archive_id
23
+ return object.archive_id
24
+ else
25
+ return new_id
26
+ end
27
+ end
28
+ end
29
+
30
+ end
@@ -9,65 +9,122 @@ module ZergXcode
9
9
 
10
10
 
11
11
  # Lexer for flattened object graphs stored in .xcodeproj files.
12
- module Lexer
13
- def self.tokenize(string)
14
-
15
- encoding_match = string.match(/^\/\/ \!\$\*(.*?)\*\$\!/)
16
- raise "No encoding - #{string[0, 20]}" unless encoding_match
17
-
18
- i = encoding_match[0].length
19
- tokens = [[:encoding, encoding_match[1]]]
20
- while i < string.length
21
- # skip comments
22
- if string[i, 2] == '/*'
23
- i += 2
24
- i += 1 while string[i, 2] != '*/'
25
- i += 2
26
- next
27
- end
28
-
29
- case string[i, 1]
30
- when /\s/
31
- i += 1
32
- when '(', ')', '{', '}', '=', ';', ','
33
- tokens << {'(' => :begin_array, ')' => :end_array,
34
- '{' => :begin_hash, '}' => :end_hash,
35
- '=' => :assign, ';' => :stop, ',' => :comma}[string[i, 1]]
36
- i += 1
37
- when '"'
38
- # string
39
- i += 1
40
- token = ''
41
- while string[i, 1] != '"'
42
- if string[i, 1] == '\\'
43
- i += 1
44
- case string[i, 1]
45
- when 'n', 'r', 't'
46
- token << { 'n' => "\n", 't' => "\t", 'r' => "\r" }[string[i, 1]]
47
- i += 1
48
- when '"', "'", '\\'
49
- token << string[i]
50
- i += 1
51
- else
52
- raise "Uknown escape sequence \\#{string[i, 20]}"
53
- end
54
- else
55
- token << string[i]
56
- i += 1
57
- end
12
+ class Lexer
13
+
14
+ SIMPLE_TOKENS = [ '(', ')', '{', '}', '=', ';', ',' ]
15
+
16
+ def initialize(string)
17
+ @scan_buffer = ScanBuffer.new(string)
18
+ end
19
+
20
+ def tokenize
21
+ tokens, token = [], nil
22
+ tokens << token until (token = scan_token).nil?
23
+ tokens
24
+ end
25
+
26
+ def scan_token
27
+ skip_encodings_comments_and_whitespace
28
+
29
+ return nil if at_end_of_buffer?
30
+ return scan_simple_token if at_simple_token?
31
+ return scan_quoted_string if at_quoted_string?
32
+ return scan_bare_string
33
+ end
34
+ private :scan_token
35
+
36
+ def skip_encodings_comments_and_whitespace
37
+ nil while skip_encoding_comment_or_whitespace
38
+ end
39
+ private :skip_encodings_comments_and_whitespace
40
+
41
+ def skip_encoding_comment_or_whitespace
42
+ if at_encoding?
43
+ skip_encoding
44
+ true
45
+ elsif @scan_buffer.peek =~ /\s/
46
+ @scan_buffer.advance
47
+ true
48
+ elsif @scan_buffer.at?('/*')
49
+ skip_comment
50
+ true
51
+ else
52
+ false
53
+ end
54
+ end
55
+ private :skip_encoding_comment_or_whitespace
56
+
57
+ def skip_comment
58
+ @scan_buffer.advance(2)
59
+ @scan_buffer.advance until @scan_buffer.at?('*/')
60
+ @scan_buffer.advance(2)
61
+ end
62
+ private :skip_comment
63
+
64
+ def at_end_of_buffer?
65
+ @scan_buffer.at_end?
66
+ end
67
+ private :at_end_of_buffer?
68
+
69
+ def at_encoding?
70
+ @scan_buffer.at?('// !$*')
71
+ end
72
+ private :at_encoding?
73
+
74
+ def skip_encoding
75
+ @scan_buffer.match_and_advance(/^\/\/ \!\$\*(.*?)\*\$\!/)
76
+ end
77
+ private :skip_encoding
78
+
79
+ def at_quoted_string?
80
+ @scan_buffer.at?('"')
81
+ end
82
+ private :at_quoted_string?
83
+
84
+ def scan_quoted_string
85
+ @scan_buffer.advance
86
+ token = ''
87
+ until @scan_buffer.at?('"')
88
+ if @scan_buffer.at?('\\')
89
+ @scan_buffer.advance
90
+ case @scan_buffer.peek
91
+ when 'n', 'r', 't'
92
+ token << { 'n' => "\n", 't' => "\t", 'r' => "\r" }[@scan_buffer.take]
93
+ when '"', "'", '\\'
94
+ token << @scan_buffer.take
95
+ else
96
+ raise "Uknown escape sequence \\#{@scan_buffer.peek 20}"
58
97
  end
59
- tokens << [:string, token]
60
- i += 1
61
98
  else
62
- # something
63
- len = 0
64
- len += 1 while /[^\s\t\r\n\f(){}=;,]/ =~ string[i + len, 1]
65
- tokens << [:symbol, string[i, len]]
66
- i += len
99
+ token << @scan_buffer.take
67
100
  end
68
101
  end
69
- return tokens
102
+ @scan_buffer.advance
103
+ return [token]
104
+ end
105
+ private :scan_quoted_string
106
+
107
+ def at_simple_token?
108
+ SIMPLE_TOKENS.include?(@scan_buffer.peek)
109
+ end
110
+ private :at_simple_token?
111
+
112
+ def scan_simple_token
113
+ @scan_buffer.take
114
+ end
115
+ private :scan_simple_token
116
+
117
+ def scan_bare_string
118
+ text = ""
119
+ text << @scan_buffer.take while @scan_buffer.peek(1) =~ /[^\s\t\r\n\f(){}=;,]/
120
+ return [text]
70
121
  end
71
- end # module ZergXcode::Lexer
122
+ private :scan_bare_string
123
+
124
+ def self.tokenize(string)
125
+ Lexer.new(string).tokenize
126
+ end
127
+
128
+ end
72
129
 
73
- end # namespace ZergXcode
130
+ end
@@ -13,47 +13,41 @@ module Parser
13
13
  def self.parse(project_string)
14
14
  tokens = ZergXcode::Lexer.tokenize project_string
15
15
 
16
- context = [[]]
17
- last_token = nil
16
+ stack = [[]]
18
17
  tokens.each do |token|
19
18
  case token
20
- when :begin_array
21
- context << Array.new
22
- when :begin_hash
23
- context << Hash.new
24
- when :end_array, :end_hash
25
- last_object = context.pop
26
- if context.last.kind_of? Array
27
- context.last << last_object
28
- elsif context.last.kind_of? String
29
- hash_key = context.pop
30
- context.last[hash_key] = last_object
19
+ when '('
20
+ stack << Array.new
21
+ when '{'
22
+ stack << Hash.new
23
+ when ')', '}'
24
+ last_object = stack.pop
25
+ if stack.last.kind_of? Array
26
+ stack.last << last_object
27
+ elsif stack.last.kind_of? String
28
+ hash_key = stack.pop
29
+ stack.last[hash_key] = last_object
31
30
  end
32
- when :assign, :stop, :comma
33
-
34
31
  when Array
35
- case token.first
36
- when :encoding
37
- when :string, :symbol
38
- token_string = token.last
39
- if context.last.kind_of? Hash
40
- context << token_string
41
- elsif context.last.kind_of? Array
42
- context.last << token_string
43
- elsif context.last.kind_of? String
44
- key = context.pop
45
- context.last[key] = token_string
46
- else
47
- p context
48
- raise 'WTFed'
49
- end
50
- end
32
+ token_string = token.first
33
+ if stack.last.kind_of? Hash
34
+ stack << token_string
35
+ elsif stack.last.kind_of? Array
36
+ stack.last << token_string
37
+ elsif stack.last.kind_of? String
38
+ key = stack.pop
39
+ stack.last[key] = token_string
40
+ else
41
+ p stack
42
+ raise 'WTFed'
43
+ end
44
+ when '=', ';', ','
51
45
  else
52
46
  raise "Unknown token #{token}"
53
47
  end
54
48
  end
55
- return context[0][0]
49
+ return stack[0][0]
56
50
  end
57
- end # module ZergXcode::Parser
51
+ end
58
52
 
59
- end # namespace ZergXcode
53
+ end
@@ -0,0 +1,46 @@
1
+ module ZergXcode
2
+
3
+ class ScanBuffer
4
+ def initialize(string)
5
+ @string = string
6
+ @i = 0
7
+ end
8
+
9
+ def at_beginning?
10
+ @i == 0
11
+ end
12
+
13
+ def at_end?
14
+ @i == @string.length
15
+ end
16
+
17
+ def at?(literal)
18
+ peek(literal.length) == literal
19
+ end
20
+
21
+ def unconsumed
22
+ @string[@i..-1]
23
+ end
24
+
25
+ def advance(n=1)
26
+ @i += n
27
+ end
28
+
29
+ def peek(n=1)
30
+ @string[@i, n]
31
+ end
32
+
33
+ def take(n=1)
34
+ result = peek(n)
35
+ advance(n)
36
+ result
37
+ end
38
+
39
+ def match_and_advance(pattern)
40
+ match = @string[@i..-1].match(pattern)
41
+ @i += match[0].length if match
42
+ match
43
+ end
44
+ end
45
+
46
+ end
@@ -27,7 +27,7 @@ class PBXProject < ZergXcode::XcodeObject
27
27
 
28
28
  # The root path of the project.
29
29
  def root_path
30
- ZergXcode::Paths.project_root_at source_filename
30
+ ZergXcode.project_root_at source_filename
31
31
  end
32
32
 
33
33
  # All the files referenced by the project.
@@ -36,7 +36,8 @@ class XcodeObject
36
36
  def self.new(*args)
37
37
  return super unless self == ZergXcode::XcodeObject
38
38
  if hash_isa = args.first['isa']
39
- classes = ZergXcode::Objects.constants
39
+ hash_isa = hash_isa.to_sym
40
+ classes = ZergXcode::Objects.constants.map(&:to_sym)
40
41
  if classes.include? hash_isa
41
42
  return ZergXcode::Objects.const_get(hash_isa).new(*args)
42
43
  end
@@ -7,11 +7,10 @@
7
7
  # :nodoc: namespace
8
8
  module ZergXcode
9
9
 
10
-
11
- # Finds the .pbxproj file inside an Xcode project.
12
10
  module Paths
11
+
13
12
  # The most likely project file name for the given path.
14
- def self.project_file_at(base_path)
13
+ def project_file_at(base_path)
15
14
  return base_path if File.exist?(base_path) and File.file?(base_path)
16
15
  pbxfile = 'project.pbxproj'
17
16
 
@@ -48,10 +47,10 @@ module Paths
48
47
  end
49
48
 
50
49
  # The most likely project root dir for the given path.
51
- def self.project_root_at(base_path)
50
+ def project_root_at(base_path)
52
51
  file = project_file_at base_path
53
52
  File.dirname File.dirname(file)
54
53
  end
55
- end # module ZergXcode::Paths
54
+ end
56
55
 
57
- end # module ZergXcode
56
+ end
@@ -9,7 +9,7 @@
9
9
  module ZergXcode
10
10
  # Reads an Xcode project from the filesystem.
11
11
  def self.load(path)
12
- file = ZergXcode::Paths.project_file_at path
12
+ file = ZergXcode.project_file_at path
13
13
  pbx_contents = File.read file
14
14
  project = Archiver.unarchive pbx_contents
15
15
  project.source_filename = file
@@ -18,7 +18,7 @@ module ZergXcode
18
18
 
19
19
  # Dumps an Xcode project to the filesystem.
20
20
  def self.dump(project, path)
21
- file = ZergXcode::Paths.project_file_at path
21
+ file = ZergXcode.project_file_at path
22
22
  pbx_contents = Archiver.archive project
23
23
  File.open(file, 'w') { |f| f.write pbx_contents }
24
24
  end
data/lib/zerg_xcode.rb CHANGED
@@ -6,9 +6,10 @@
6
6
 
7
7
  require 'zerg_xcode/file_format/archiver.rb'
8
8
  require 'zerg_xcode/file_format/encoder.rb'
9
+ require 'zerg_xcode/file_format/id_generator.rb'
9
10
  require 'zerg_xcode/file_format/lexer.rb'
10
11
  require 'zerg_xcode/file_format/parser.rb'
11
- require 'zerg_xcode/file_format/paths.rb'
12
+ require 'zerg_xcode/file_format/scan_buffer.rb'
12
13
 
13
14
  require 'zerg_xcode/builder/runner.rb'
14
15
  require 'zerg_xcode/builder/sdks.rb'
@@ -24,4 +25,9 @@ require 'zerg_xcode/objects/pbx_target_dependency.rb'
24
25
  require 'zerg_xcode/objects/xc_configuration_list.rb'
25
26
  require 'zerg_xcode/plugins/core/core.rb'
26
27
 
28
+ require 'zerg_xcode/paths.rb'
27
29
  require 'zerg_xcode/shortcuts.rb'
30
+
31
+ module ZergXcode
32
+ extend ZergXcode::Paths
33
+ end