iconara-java_tools 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile ADDED
@@ -0,0 +1,51 @@
1
+ h1. Java Tools
2
+
3
+ Ruby wrappers for javac and jar that don't just exec.
4
+
5
+ Ant is a nice tool for writing Java build scripts, but Rake is nicer. The only thing missing from Rake is a way to run javac and jar, and although it's easy to run these with exec you have to wait for the JVM to start for each invocation. In combination with JRuby this gem lets you run @javac@ and @jar@ in your Rake scripts without exec'ing, by using the programmatic interface to Javac and Java's ZIP file creation capabilities.
6
+
7
+ h2. Example
8
+
9
+ <pre><code>
10
+ require 'java_tools'
11
+
12
+
13
+ task :compile do
14
+ javac FileList['src/**/*.java'], :destination => 'build, :class_path => FileList['lib/*.jar']
15
+ end
16
+
17
+ task :dist => :compile do
18
+ jar 'dist/my-awsome-app.jar', FileList['build/**/*.class'], :base_dir => 'build'
19
+ end
20
+ </code></pre>
21
+
22
+ There are more examples in the @examples@ directory.
23
+
24
+ h2. Command style
25
+
26
+ Many Rake add-ons look like this:
27
+
28
+ <pre><code>
29
+ Spec::Rake::SpecTask.new(:spec) do |spec|
30
+ spec.spec_opts << '--options' << 'spec/spec.opts'
31
+ # ...
32
+ end
33
+ </code></pre>
34
+
35
+ I think it ruins the DSL illusion, and I prefer to write tasks that contain commands, more like how @cp@, @rm@ and @sh@ work in Rake.
36
+
37
+ h2. Nailgun
38
+
39
+ Don't forget that since JRuby 1.3 you can minimize the startup by using the built-in Nailgun support. Run
40
+
41
+ @jruby --ng-server &@
42
+
43
+ to start a Nailgun server and then run Rake with this command
44
+
45
+ @jruby --ng -S rake@
46
+
47
+ you'll notice that the startup time decreases significantly the second time you run it. To avoid having to write all that every time you want to build create an alias, I call mine @jrk@.
48
+
49
+ h2. Upcomming
50
+
51
+ Even though the whole rationale behind Java Tools is to avoid exec it wouldn't be much effort to support non-JRuby runtimes since at least the @javac@ command needs to build the command string anyway.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require 'rake/clean'
2
+
3
+
4
+ task :default => :spec
5
+
6
+
7
+ # Import all .rake-files in the tasks directory
8
+ Dir['tasks/*.rake'].each do |tasks_file|
9
+ begin
10
+ load tasks_file
11
+ rescue Exception => e
12
+ $stderr.puts e.message
13
+ end
14
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.2
@@ -0,0 +1,16 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/java_tools')
2
+
3
+ require 'rake/clean'
4
+
5
+
6
+ CLOBBER.include('build')
7
+
8
+
9
+ task :default => :compile
10
+
11
+ desc "Compile all classes"
12
+ task :compile => 'build' do
13
+ javac FileList['src/**/*.java'], :destination => 'build', :verbose => true
14
+ end
15
+
16
+ directory 'build'
@@ -0,0 +1,10 @@
1
+ package com.example;
2
+
3
+
4
+ public class HelloWorld {
5
+
6
+ public static void main( String[] args ) {
7
+ System.out.println("Hello world");
8
+ }
9
+
10
+ }
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../lib/java_tools')
2
+
3
+ require 'rake/clean'
4
+
5
+
6
+ CLOBBER.include('build')
7
+ CLOBBER.include('dist')
8
+
9
+
10
+ task :default => :package
11
+
12
+ task :package => [:compile, 'dist'] do
13
+ jar 'dist/package.jar', FileList['build/**/*.class'], :base_dir => 'build',
14
+ :main_class => 'com.example.HelloWorld',
15
+ :manifest => {'X-Test', 'foo'},
16
+ :verbose => true
17
+ end
18
+
19
+ task :compile => 'build' do
20
+ javac FileList['src/**/*.java'], :destination => 'build', :verbose => true
21
+ end
22
+
23
+ directory 'build'
24
+ directory 'dist'
@@ -0,0 +1,10 @@
1
+ package com.example;
2
+
3
+
4
+ public class HelloWorld {
5
+
6
+ public static void main( String[] args ) {
7
+ System.out.println("Hello world");
8
+ }
9
+
10
+ }
@@ -0,0 +1,58 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{java_tools}
5
+ s.version = "0.1.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Theo Hultberg"]
9
+ s.date = %q{2009-08-05}
10
+ s.description = %q{Ant is a nice tool for writing Java build scripts, but Rake is nicer. The only thing missing from Rake is a way to run javac and jar, and although it's easy to run these as shell scripts you have to wait for the JVM to start. In combination with JRuby this gem lets you run javac and jar in your Rake scripts without exec'ing.}
11
+ s.email = %q{theo@iconara.net}
12
+ s.extra_rdoc_files = [
13
+ "README.textile"
14
+ ]
15
+ s.files = [
16
+ "README.textile",
17
+ "Rakefile",
18
+ "VERSION",
19
+ "examples/compile/Rakefile",
20
+ "examples/compile/src/com/example/HelloWorld.java",
21
+ "examples/package/Rakefile",
22
+ "examples/package/src/com/example/HelloWorld.java",
23
+ "java_tools.gemspec",
24
+ "lib/java_tools.rb",
25
+ "lib/java_tools/jar.rb",
26
+ "lib/java_tools/javac.rb",
27
+ "spec/jar_cmd_spec.rb",
28
+ "spec/jar_spec.rb",
29
+ "spec/javac_cmd_spec.rb",
30
+ "spec/javac_spec.rb",
31
+ "spec/spec.opts",
32
+ "spec/spec_helper.rb",
33
+ "tasks/gem.rake",
34
+ "tasks/spec.rake"
35
+ ]
36
+ s.homepage = %q{http://github.com/iconara/java_tools}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.3}
40
+ s.summary = %q{Ruby wrappers for javac and jar that don't just exec}
41
+ s.test_files = [
42
+ "spec/jar_cmd_spec.rb",
43
+ "spec/jar_spec.rb",
44
+ "spec/javac_cmd_spec.rb",
45
+ "spec/javac_spec.rb",
46
+ "spec/spec_helper.rb"
47
+ ]
48
+
49
+ if s.respond_to? :specification_version then
50
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
51
+ s.specification_version = 3
52
+
53
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
54
+ else
55
+ end
56
+ else
57
+ end
58
+ end
@@ -0,0 +1,147 @@
1
+ require 'java'
2
+
3
+
4
+ module JavaTools
5
+
6
+ include_class 'java.io.FileOutputStream'
7
+ include_class 'java.util.zip.ZipOutputStream'
8
+ include_class 'java.util.zip.ZipEntry'
9
+
10
+
11
+ class Jar
12
+
13
+ attr_accessor :base_dir, # string
14
+ :compression, # number (0-9)
15
+ :verbose # boolean
16
+
17
+ attr_reader :output
18
+
19
+ def initialize( output, files = nil, base_dir = nil )
20
+ @output = output
21
+ @base_dir = base_dir
22
+ @entries = { } # archive_path => JarEntry
23
+ @verbose = false
24
+ @compression = 1
25
+
26
+ self.manifest = { }
27
+
28
+ add_files(files) unless files.nil? || files.empty?
29
+ end
30
+
31
+ def manifest=( manifest_hash )
32
+ @manifest = default_manifest
33
+
34
+ manifest_hash.each do |key, value|
35
+ raise ArgumentError, "Malformed attribute name #{key}" if key !~ /^[\w\d][\w\d\-_]*$/
36
+
37
+ remove_manifest_attribute(key)
38
+
39
+ @manifest[key] = value
40
+ end
41
+ end
42
+
43
+ def remove_manifest_attribute( name )
44
+ @manifest.delete_if do |key, value|
45
+ key.downcase == name.downcase
46
+ end
47
+ end
48
+
49
+ def main_class=( class_name )
50
+ if class_name
51
+ @manifest['Main-Class'] = class_name
52
+ else
53
+ remove_manifest_attribute('Main-Class')
54
+ end
55
+ end
56
+
57
+ def default_manifest
58
+ {
59
+ 'Built-By' => "JavaTools v#{JavaTools::version}",
60
+ 'Manifest-Version' => '1.0'
61
+ }
62
+ end
63
+
64
+ def manifest_string
65
+ @manifest.keys.inject("") do |str, key|
66
+ str + "#{key}: #{@manifest[key]}\n"
67
+ end
68
+ end
69
+
70
+ def commit_manifest
71
+ add_blob(manifest_string, 'META-INF/MANIFEST.MF')
72
+ end
73
+
74
+ def add_file( file_path, archive_path = nil )
75
+ archive_path = find_archive_path(file_path, @base_dir) unless archive_path
76
+
77
+ if File.directory?(file_path)
78
+ raise ArgumentError, "\"#{file_path}\" is a directory"
79
+ elsif ! File.exists?(file_path)
80
+ raise ArgumentError, "\"#{file_path}\" does not exist"
81
+ end
82
+
83
+ @entries[archive_path || file_path] = File.new(file_path)
84
+ end
85
+
86
+ def add_files( files, base_dir = nil )
87
+ files.each do |file|
88
+ add_file(file, find_archive_path(file, base_dir || @base_dir))
89
+ end
90
+ end
91
+
92
+ def add_blob( str, archive_path )
93
+ @entries[archive_path] = StringIO.new(str)
94
+ end
95
+
96
+ def remove_entry( archive_path )
97
+ @entries.delete(archive_path)
98
+ end
99
+
100
+ def entries
101
+ @entries.keys
102
+ end
103
+
104
+ def execute( io = $stderr )
105
+ raise "Output not set" unless @output
106
+
107
+ compression_flag = @compression == 0 ? '0' : ''
108
+
109
+ io.puts "jar -c#{compression_flag}f #{@output} …" if @verbose
110
+
111
+ commit_manifest
112
+ create_zipfile
113
+ end
114
+
115
+ def create_zipfile
116
+ buffer_size = 65536
117
+
118
+ zipstream = ZipOutputStream.new(FileOutputStream.new(@output))
119
+
120
+ @entries.each do |path, io|
121
+ while buffer = io.read(buffer_size)
122
+ zipstream.put_next_entry(ZipEntry.new(path))
123
+ zipstream.write(buffer.to_java_bytes, 0, buffer.length)
124
+ zipstream.close_entry
125
+ end
126
+
127
+ io.close
128
+ end
129
+
130
+ zipstream.close
131
+ end
132
+
133
+ def find_archive_path( path, base_dir )
134
+ if base_dir
135
+ prefix = base_dir + (base_dir =~ /\/$/ ? '' : '/')
136
+
137
+ if 0 == path.index(prefix)
138
+ return path.slice(prefix.length, path.length - prefix.length)
139
+ end
140
+ end
141
+
142
+ path
143
+ end
144
+
145
+ end
146
+
147
+ end
@@ -0,0 +1,79 @@
1
+ require 'java'
2
+
3
+
4
+ module JavaTools
5
+
6
+ # must use include_class instead of import because import interferes with Rake's import
7
+ include_class 'java.io.PrintWriter'
8
+ include_class 'java.io.StringWriter'
9
+
10
+
11
+ class Javac
12
+
13
+ attr_accessor :source_files, # array
14
+ :source_path, # array
15
+ :destination, # string
16
+ :class_path, # array
17
+ :deprecation_warnings, # boolean
18
+ :warnings, # boolean
19
+ :encoding, # string
20
+ :verbose # boolean
21
+
22
+ def initialize( *source_files )
23
+ @source_files = source_files || [ ]
24
+
25
+ @source_path = [ ]
26
+ @destination = 'build'
27
+ @class_path = [ ]
28
+ @deprecation_warnings = true
29
+ @warnings = true
30
+ @encoding = nil
31
+ @verbose = false
32
+ end
33
+
34
+ def command_args
35
+ args = [ ]
36
+ args << '-sourcepath' << @source_path.join(':') unless @source_path.empty?
37
+ args << '-d' << @destination unless (@destination.nil? || @destination =~ /^\s*$/)
38
+ args << '-classpath' << @class_path.join(':') unless @class_path.empty?
39
+ args << '-deprecation' unless @deprecation_warnings
40
+ args << '-nowarn' unless @warnings
41
+ args << '-encoding' << @encoding if @encoding
42
+ args + @source_files
43
+ end
44
+
45
+ def command_string
46
+ args = [ ]
47
+ args << '-sourcepath' << @source_path.join(':') unless @source_path.empty?
48
+ args << '-d' << @destination unless (@destination.nil? || @destination =~ /^\s*$/)
49
+ args << '-classpath' << @class_path.join(':') unless @class_path.empty?
50
+ args << '-deprecation' unless @deprecation_warnings
51
+ args << '-nowarn' unless @warnings
52
+ args << '-encoding' << @encoding if @encoding
53
+
54
+ "javac #{args.join(' ')} …"
55
+ end
56
+
57
+ def execute( io = $stderr )
58
+ output_writer = StringWriter.new
59
+
60
+ args = command_args.to_java(java.lang.String)
61
+
62
+ result = com.sun.tools.javac.Main.compile(args, PrintWriter.new(output_writer))
63
+
64
+ io.puts command_string if @verbose
65
+
66
+ output_str = output_writer.to_s
67
+
68
+ io.puts output_str if output_str !~ /^\s*$/
69
+
70
+ if 0 == result
71
+ true
72
+ else
73
+ false
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ end
data/lib/java_tools.rb ADDED
@@ -0,0 +1,60 @@
1
+ raise "JavaTools requires JRuby" unless RUBY_PLATFORM =~ /\bjava\b/
2
+
3
+
4
+ require File.expand_path(File.dirname(__FILE__)) + '/java_tools/javac'
5
+ require File.expand_path(File.dirname(__FILE__)) + '/java_tools/jar'
6
+
7
+
8
+ module JavaTools
9
+
10
+ def self.version
11
+ version_file = File.join(File.dirname(__FILE__), '..', 'VERSION')
12
+
13
+ File.open(version_file) do |f|
14
+ f.readline.strip
15
+ end
16
+ end
17
+
18
+ def self.configure_command( command, options )
19
+ options.each do |option, value|
20
+ setter_name = "#{option}="
21
+
22
+ if command.respond_to? setter_name
23
+ command.send(setter_name, value)
24
+ else
25
+ raise ArgumentError, "Invalid option: #{option}"
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ def javac( source_files, options = nil )
33
+ obj = JavaTools::Javac.new(*source_files)
34
+
35
+ if block_given?
36
+ yield obj
37
+ elsif options
38
+ JavaTools::configure_command(obj, options)
39
+ end
40
+
41
+ obj.execute
42
+ end
43
+
44
+ def jar( output, files = nil, options = nil )
45
+ base_dir = nil
46
+
47
+ if options && options[:base_dir]
48
+ base_dir = options[:base_dir]
49
+ end
50
+
51
+ obj = JavaTools::Jar.new(output, files, base_dir)
52
+
53
+ if block_given?
54
+ yield obj
55
+ elsif options
56
+ JavaTools::configure_command(obj, options)
57
+ end
58
+
59
+ obj.execute
60
+ end
@@ -0,0 +1,112 @@
1
+ describe "jar command" do
2
+
3
+ it "should pass the first argument to the constructor of Jar" do
4
+ output = 'archive.jar'
5
+
6
+ instance = create_non_exec_jar(output)
7
+
8
+ Jar.should_receive(:new).with(output, nil, nil).and_return(instance)
9
+
10
+ jar output
11
+ end
12
+
13
+ it "should pass the first and second arguments to the constructor of Jar" do
14
+ output = 'archive.jar'
15
+ files = ['one/two.class', 'three/four.txt']
16
+
17
+ Jar.should_receive(:new).with(output, files, nil).and_return do
18
+ instance = mock('JarInstance')
19
+ instance.should_receive(:execute)
20
+ instance
21
+ end
22
+
23
+ jar output, files
24
+ end
25
+
26
+ it "should yield a Jar object if a block is given" do
27
+ instance = create_non_exec_jar('archive.jar')
28
+
29
+ Jar.should_receive(:new).and_return(instance)
30
+
31
+ jar('archive.jar') do |conf|
32
+ conf.should be_instance_of(Jar)
33
+ end
34
+ end
35
+
36
+ it "should set properties on the yielded Jar instance" do
37
+ base_dir = 'build'
38
+ compression = 3
39
+
40
+ instance = create_non_exec_jar('archive.jar')
41
+
42
+ Jar.should_receive(:new).and_return do
43
+ instance.should_receive(:base_dir=).with(base_dir)
44
+ instance.should_receive(:compression=).with(compression)
45
+ instance
46
+ end
47
+
48
+ jar('archive.jar') do |conf|
49
+ conf.base_dir = base_dir
50
+ conf.compression = compression
51
+ end
52
+ end
53
+
54
+ it "should call #execute after yielding" do
55
+ Jar.should_receive(:new).and_return do
56
+ instance = mock('JarInstance')
57
+ instance.should_receive(:execute)
58
+ instance
59
+ end
60
+
61
+ jar('archive.jar') { }
62
+ end
63
+
64
+ it "should call #execute in non-yield mode" do
65
+ instance = create_non_exec_jar('archive.jar')
66
+
67
+ Jar.should_receive(:new).and_return(instance)
68
+
69
+ jar 'archive.jar', :compression => 4
70
+ end
71
+
72
+ it "should set the properties specified in the options parameter" do
73
+ base_dir = 'build'
74
+ compression = 4
75
+
76
+ Jar.should_receive(:new).and_return do
77
+ instance = mock('JarInstance')
78
+ instance.should_receive(:base_dir=).with(base_dir)
79
+ instance.should_receive(:compression=).with(compression)
80
+ instance.should_receive(:verbose=).with(false)
81
+ instance.should_receive(:execute)
82
+ instance
83
+ end
84
+
85
+ jar 'archive.jar', ['build/two/three.class'], :base_dir => base_dir, :compression => compression, :verbose => false
86
+ end
87
+
88
+ it "should raise an exception for an invalid option" do
89
+ lambda {
90
+ jar 'archive.jar', ['Main.class'], :bogus => 'option'
91
+ }.should raise_error(ArgumentError)
92
+ end
93
+
94
+ it "should pass the base_dir option straight to the constructor" do
95
+ output = 'output.jar'
96
+ files = [__FILE__]
97
+ base_dir = File.dirname(__FILE__)
98
+
99
+ instance = create_non_exec_jar(output, files)
100
+
101
+ Jar.should_receive(:new).with(output, files, base_dir).and_return(instance)
102
+
103
+ jar output, files, :base_dir => base_dir
104
+ end
105
+
106
+ def create_non_exec_jar( output, files = nil )
107
+ instance = Jar.new(output, files)
108
+ instance.should_receive(:execute) # stop the real #execute from being called
109
+ instance
110
+ end
111
+
112
+ end
data/spec/jar_spec.rb ADDED
@@ -0,0 +1,259 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+
4
+ describe Jar do
5
+
6
+ before(:each) do
7
+ @output = 'archive.jar'
8
+ @jar = Jar.new(@output)
9
+ end
10
+
11
+ describe " defaults" do
12
+
13
+ it "should set the output file specified in the constructor" do
14
+ @jar.output.should == @output
15
+ end
16
+
17
+ it "should have a default compression rate between 0 and 9" do
18
+ (@jar.compression >= 0).should be_true
19
+ (@jar.compression <= 9).should be_true
20
+ end
21
+
22
+ it "should have a default manifest" do
23
+ @jar.manifest_string.should_not be_nil
24
+ end
25
+
26
+ it "should have no entries" do
27
+ @jar.entries.should be_empty
28
+ end
29
+
30
+ end
31
+
32
+ describe "#initialize" do
33
+
34
+ it "should take a path to the output file as parameters" do
35
+ output = 'path/to/output.jar'
36
+
37
+ jar = Jar.new(output)
38
+
39
+ jar.output.should == output
40
+ end
41
+
42
+ it "should take a path to the output and a list of files as parameters" do
43
+ output = 'output.jar'
44
+ files = [__FILE__]
45
+
46
+ jar = Jar.new(output, files)
47
+
48
+ jar.output.should == output
49
+ jar.entries.should == [__FILE__]
50
+ end
51
+
52
+ end
53
+
54
+ describe "#archive_path" do
55
+
56
+ it "should remove the base dir path from the archive path" do
57
+ @jar.find_archive_path('build/com/example/HelloWorld.class', 'build').should == 'com/example/HelloWorld.class'
58
+ end
59
+
60
+ it "should not remove anything from a file not in the base dir path" do
61
+ @jar.find_archive_path('some/other/path', 'build').should == 'some/other/path'
62
+ end
63
+
64
+ it "should not remove anything from a file path if the base dir path is nil" do
65
+ @jar.find_archive_path('some/other/path', nil).should == 'some/other/path'
66
+ end
67
+
68
+ end
69
+
70
+ describe " manifest" do
71
+
72
+ it "should include the Built-By key" do
73
+ @jar.manifest_string.include?('Built-By').should be_true
74
+ end
75
+
76
+ it "should include added attributes" do
77
+ @jar.manifest = {'abc' => '123'}
78
+
79
+ @jar.manifest_string.include?('abc: 123').should be_true
80
+ end
81
+
82
+ it "should write the attributes on the right format" do
83
+ @jar.manifest = {'one' => '1', 'two' => '2', 'three' => '3'}
84
+
85
+ @jar.manifest_string.include?("one: 1\n").should be_true
86
+ @jar.manifest_string.include?("two: 2\n").should be_true
87
+ @jar.manifest_string.include?("three: 3\n").should be_true
88
+ end
89
+
90
+ it "should not begin with whitespace" do
91
+ @jar.manifest_string[0..1].should_not match(/\s/)
92
+ end
93
+
94
+ it "should reject an empty attribute name" do
95
+ lambda {
96
+ @jar.manifest = {'' => '432'}
97
+ }.should raise_error(ArgumentError)
98
+ end
99
+
100
+ it "should reject nil as attribute name" do
101
+ lambda {
102
+ @jar.manifest = {nil => 'Hello world'}
103
+ }.should raise_error(ArgumentError)
104
+ end
105
+
106
+ it "should reject an attribute name containing a space" do
107
+ lambda {
108
+ @jar.manifest = {'Hello World' => 'foo'}
109
+ }.should raise_error(ArgumentError)
110
+ end
111
+
112
+ it "should reject an attribute name containing a colon" do
113
+ lambda {
114
+ @jar.manifest = {'Hello:World' => 'foo'}
115
+ }.should raise_error(ArgumentError)
116
+ end
117
+
118
+ it "should accept a variety of legal attribute names" do
119
+ lambda {
120
+ @jar.manifest = {
121
+ 'Manifest-Version' => 'foo',
122
+ 'Created-By' => 'foo',
123
+ 'Signature-Version' => 'foo',
124
+ 'Class-Path' => 'foo'
125
+ }
126
+ }.should_not raise_error
127
+ end
128
+
129
+ it "should ignore case when setting attributes" do
130
+ @jar.manifest = {'Hello' => 'World', 'hello' => 'Theo'}
131
+
132
+ @jar.manifest_string.include?('Hello: World').should be_false
133
+ @jar.manifest_string.include?('hello: Theo').should be_true
134
+ end
135
+
136
+ end
137
+
138
+ describe "#main_class=" do
139
+
140
+ it "should set the Main-Class attribute" do
141
+ @jar.main_class = 'com.example.Main'
142
+
143
+ @jar.manifest_string.include?('Main-Class: com.example.Main').should be_true
144
+ end
145
+
146
+ end
147
+
148
+ describe "#add_file" do
149
+
150
+ it "should add an entry" do
151
+ path = __FILE__
152
+
153
+ @jar.add_file(path)
154
+
155
+ @jar.entries.include?(path).should be_true
156
+ end
157
+
158
+ it "should add an entry at the specified archive path" do
159
+ path = __FILE__
160
+ archive_path = 'some/other/path.rb'
161
+
162
+ @jar.add_file(path, archive_path)
163
+
164
+ @jar.entries.include?(path).should be_false
165
+ @jar.entries.include?(archive_path).should be_true
166
+ end
167
+
168
+ it "should raise an exception if the file doesn't exist" do
169
+ lambda {
170
+ @jar.add_file('some/bogus/path')
171
+ }.should raise_error(ArgumentError)
172
+ end
173
+
174
+ it "should raise an exception if the argument is a directory" do
175
+ lambda {
176
+ @jar.add_file(File.dirname(__FILE__))
177
+ }.should raise_error(ArgumentError)
178
+ end
179
+
180
+ end
181
+
182
+ describe "#add_blob" do
183
+
184
+ it "should add an entry" do
185
+ archive_path = 'some/path/to/a/file.txt'
186
+
187
+ @jar.add_blob('one two three', archive_path)
188
+
189
+ @jar.entries.include?(archive_path).should be_true
190
+ end
191
+
192
+ end
193
+
194
+ describe "#add_files" do
195
+
196
+ it "should add all files" do
197
+ files = Dir.glob(File.dirname(__FILE__) + '/*.rb')
198
+
199
+ @jar.add_files(files)
200
+
201
+ files.each do |file|
202
+ @jar.entries.include?(file).should be_true
203
+ end
204
+ end
205
+
206
+ it "should remove the base dir from all file paths" do
207
+ files = Dir.glob(File.dirname(__FILE__) + '/*.rb').map { |f| File.expand_path(f) }
208
+ base_dir = File.expand_path(File.dirname(__FILE__ + '/..'))
209
+
210
+ @jar.add_files(files, base_dir)
211
+
212
+ files.each do |file|
213
+ @jar.entries.include?(file.gsub(base_dir + '/', '')).should be_true
214
+ end
215
+ end
216
+
217
+ it "should raise an exception if any of the files is a directory" do
218
+ files = [__FILE__, File.dirname(__FILE__)]
219
+
220
+ lambda {
221
+ @jar.add_files(files)
222
+ }.should raise_error(ArgumentError)
223
+ end
224
+
225
+ it "should raise an exception if any file doesn't exist" do
226
+ files = [__FILE__, 'some/bogus/path.txt']
227
+
228
+ lambda {
229
+ @jar.add_files(files)
230
+ }.should raise_error(ArgumentError)
231
+ end
232
+
233
+ end
234
+
235
+ describe "#remove_entry" do
236
+
237
+ it "should remove an added file" do
238
+ @jar.add_file(__FILE__)
239
+ @jar.remove_entry(__FILE__)
240
+
241
+ @jar.entries.include?(__FILE__).should be_false
242
+ end
243
+
244
+ it "should remove an added blob" do
245
+ @jar.add_blob('foobar', 'foo/bar')
246
+ @jar.remove_entry('foo/bar')
247
+
248
+ @jar.entries.include?('foo/bar').should be_false
249
+ end
250
+
251
+ it "should not do anything when removing an entry that does not exist" do
252
+ lambda {
253
+ @jar.remove_entry('non/existent/entry')
254
+ }.should_not change(@jar, :entries)
255
+ end
256
+
257
+ end
258
+
259
+ end
@@ -0,0 +1,92 @@
1
+ describe "javac command" do
2
+
3
+ it "should pass the first argument to the constructor of Javac" do
4
+ files = ['one/two.java', 'three/four.java']
5
+
6
+ instance = Javac.new(*files)
7
+ instance.should_receive(:execute) # stop the real execute from being called
8
+
9
+ Javac.should_receive(:new).with(*files).and_return(instance)
10
+
11
+ javac files
12
+ end
13
+
14
+ it "should yield a Javac object if a block is given" do
15
+ # prepare a stub that prevents the real #execute being called
16
+ instance = Javac.new
17
+ instance.should_receive(:execute)
18
+
19
+ Javac.should_receive(:new).and_return(instance)
20
+
21
+ javac('Main.java') do |conf|
22
+ conf.should be_instance_of(Javac)
23
+ end
24
+ end
25
+
26
+ it "should set properties on the yielded Javac instance" do
27
+ destination = 'build'
28
+ source_path = ['xyz', 'abc']
29
+
30
+ instance = Javac.new('Main.java')
31
+
32
+ Javac.should_receive(:new).and_return do
33
+ instance.should_receive(:destination=).with(destination)
34
+ instance.should_receive(:source_path=).with(source_path)
35
+ instance.should_receive(:execute) # stop the real execute from being called
36
+ instance
37
+ end
38
+
39
+ javac('Main.java') do |conf|
40
+ conf.destination = destination
41
+ conf.source_path = source_path
42
+ end
43
+ end
44
+
45
+ it "should call #execute after yielding" do
46
+ Javac.should_receive(:new).and_return do
47
+ instance = mock('JavacInstance')
48
+ instance.should_receive(:execute)
49
+ instance
50
+ end
51
+
52
+ javac('Main.java') { }
53
+ end
54
+
55
+ it "should call #execute in non-yield mode" do
56
+ files = ['one/two.java', 'three/four.java']
57
+
58
+ instance = Javac.new(*files)
59
+
60
+ Javac.should_receive(:new).with(*files).and_return do
61
+ instance.should_receive(:execute)
62
+ instance
63
+ end
64
+
65
+ javac files, :destination => 'build'
66
+ end
67
+
68
+ it "should set the properties specified in the options parameter" do
69
+ files = ['one/two.java', 'three/four.java']
70
+ destination = 'build'
71
+ source_path = ['src', 'common/src']
72
+
73
+ instance = mock('JavacInstance')
74
+
75
+ Javac.should_receive(:new).with(*files).and_return do
76
+ instance.should_receive(:destination=).with(destination)
77
+ instance.should_receive(:source_path=).with(source_path)
78
+ instance.should_receive(:warnings=).with(false)
79
+ instance.should_receive(:execute) # stop the real execute from being called
80
+ instance
81
+ end
82
+
83
+ javac files, :destination => destination, :source_path => source_path, :warnings => false
84
+ end
85
+
86
+ it "should raise an exception for an invalid option" do
87
+ lambda {
88
+ javac ['Main.java'], :bogus => 'option'
89
+ }.should raise_error(ArgumentError)
90
+ end
91
+
92
+ end
@@ -0,0 +1,157 @@
1
+ describe Javac do
2
+
3
+ before(:each) do
4
+ @javac = Javac.new
5
+ end
6
+
7
+ describe " defaults" do
8
+
9
+ it "should default to an empty array as source path" do
10
+ @javac.source_path.should be_empty
11
+ end
12
+
13
+ it "should default to using 'build' as destination" do
14
+ @javac.destination.should == 'build'
15
+ end
16
+
17
+ it "should have an empty source files list" do
18
+ @javac.source_files.should be_empty
19
+ end
20
+
21
+ it "should have an empty classpath" do
22
+ @javac.class_path.should be_empty
23
+ end
24
+
25
+ it "should compile with deprecation warnings" do
26
+ @javac.deprecation_warnings.should be_true
27
+ end
28
+
29
+ it "should have no specified encoding" do
30
+ @javac.encoding.should be_nil
31
+ end
32
+
33
+ it "should show warnings" do
34
+ @javac.warnings.should be_true
35
+ end
36
+
37
+ end
38
+
39
+ describe '#initialize' do
40
+
41
+ it "should take the source files as arguments to the constructor" do
42
+ f1 = 'one/two/three.java'
43
+ f2 = 'four/five/six.java'
44
+
45
+ javac = Javac.new(f1, f2)
46
+
47
+ javac.source_files.include?(f1).should be_true
48
+ javac.source_files.include?(f2).should be_true
49
+ end
50
+
51
+ end
52
+
53
+ describe "#command_string" do
54
+
55
+ it "should include all named source files in the command args" do
56
+ source_files = ['Main.java', 'com/example/Something.java']
57
+
58
+ @javac.source_files = source_files
59
+
60
+ source_files.each do |file_name|
61
+ @javac.command_args.include?(file_name)
62
+ end
63
+ end
64
+
65
+ it "should set the sourcepath to include the specified directory" do
66
+ @javac.source_path = ['path/to/src']
67
+
68
+ @javac.command_string.should include('-sourcepath path/to/src')
69
+ end
70
+
71
+ it "should set the sourcepath to include the specified directories" do
72
+ @javac.source_path = ['path/to/src', 'another/path', 'sources']
73
+
74
+ @javac.command_string.should include('-sourcepath path/to/src:another/path:sources')
75
+ end
76
+
77
+ it "should not add the sourcepath flag if source_path is empty" do
78
+ @javac.source_path = [ ]
79
+
80
+ @javac.command_string.should_not include('-sourcepath')
81
+ end
82
+
83
+ it "should set the destination directory to the specified directory" do
84
+ @javac.destination = 'path/to/build'
85
+
86
+ @javac.command_string.should include('-d path/to/build')
87
+ end
88
+
89
+ it "should not add the d flag if destination is nil" do
90
+ @javac.destination = nil
91
+
92
+ @javac.command_string.should_not include('-d')
93
+ end
94
+
95
+ it "should not add the d flag if destination is an empty string" do
96
+ @javac.destination = ""
97
+
98
+ @javac.command_string.should_not include('-d')
99
+ end
100
+
101
+ it "should not add the d flag if destination is only whitespace" do
102
+ @javac.destination = " \t"
103
+
104
+ @javac.command_string.should_not include('-d')
105
+ end
106
+
107
+ it "should set the deprecation flag when deprecation_warnings is false" do
108
+ @javac.deprecation_warnings = false
109
+
110
+ @javac.command_string.should include('-deprecation')
111
+ end
112
+
113
+ it "should not set the deprecation flag when deprecation_warnings is true" do
114
+ @javac.deprecation_warnings = true
115
+
116
+ @javac.command_string.should_not include('-deprecation')
117
+ end
118
+
119
+ it "should set the classpath to the specified directory" do
120
+ @javac.class_path = ['path/to/classes']
121
+
122
+ @javac.command_string.should include('-classpath path/to/classes')
123
+ end
124
+
125
+ it "should set the classpath to the specified directories and files" do
126
+ @javac.class_path = ['path/to/classes', 'lib/dependency.jar']
127
+
128
+ @javac.command_string.should include('-classpath path/to/classes:lib/dependency.jar')
129
+ end
130
+
131
+ it "should not set the encoding flag if encoding is nil" do
132
+ @javac.encoding = nil
133
+
134
+ @javac.command_string.should_not include('-encoding')
135
+ end
136
+
137
+ it "should set the encoding flag when encoding is set" do
138
+ @javac.encoding = 'Shift_JIS'
139
+
140
+ @javac.command_string.should include('-encoding Shift_JIS')
141
+ end
142
+
143
+ it "should set the nowarn flag when warnings is false" do
144
+ @javac.warnings = false
145
+
146
+ @javac.command_string.should include('-nowarn')
147
+ end
148
+
149
+ it "should not set the nowarn flag when warnings is true" do
150
+ @javac.warnings = true
151
+
152
+ @javac.command_string.should_not include('-nowarn')
153
+ end
154
+
155
+ end
156
+
157
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec/spec_helper
3
+ --format specdoc
@@ -0,0 +1 @@
1
+ include JavaTools
data/tasks/gem.rake ADDED
@@ -0,0 +1,15 @@
1
+ require 'jeweler'
2
+
3
+
4
+ Jeweler::Tasks.new do |gemspec|
5
+ gemspec.name = "java_tools"
6
+ gemspec.summary = "Ruby wrappers for javac and jar that don't just exec"
7
+ gemspec.description = "Ant is a nice tool for writing Java build scripts, but Rake is nicer. The only thing missing from Rake is a way to run javac and jar, and although it's easy to run these as shell scripts you have to wait for the JVM to start. In combination with JRuby this gem lets you run javac and jar in your Rake scripts without exec'ing."
8
+ gemspec.email = "theo@iconara.net"
9
+ gemspec.homepage = "http://github.com/iconara/java_tools"
10
+ gemspec.authors = ["Theo Hultberg"]
11
+ gemspec.files.exclude '**/.gitignore'
12
+ # gemspec.platform = 'java'
13
+ end
14
+
15
+ CLEAN.include('pkg')
data/tasks/spec.rake ADDED
@@ -0,0 +1,9 @@
1
+ require 'spec/rake/spectask'
2
+
3
+
4
+ Spec::Rake::SpecTask.new(:spec) do |spec|
5
+ spec.spec_opts << '--options' << 'spec/spec.opts'
6
+ spec.libs << 'lib'
7
+ spec.ruby_opts << '-rjava_tools'
8
+ spec.warning = true
9
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: iconara-java_tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Theo Hultberg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-05 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Ant is a nice tool for writing Java build scripts, but Rake is nicer. The only thing missing from Rake is a way to run javac and jar, and although it's easy to run these as shell scripts you have to wait for the JVM to start. In combination with JRuby this gem lets you run javac and jar in your Rake scripts without exec'ing.
17
+ email: theo@iconara.net
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.textile
24
+ files:
25
+ - README.textile
26
+ - Rakefile
27
+ - VERSION
28
+ - examples/compile/Rakefile
29
+ - examples/compile/src/com/example/HelloWorld.java
30
+ - examples/package/Rakefile
31
+ - examples/package/src/com/example/HelloWorld.java
32
+ - java_tools.gemspec
33
+ - lib/java_tools.rb
34
+ - lib/java_tools/jar.rb
35
+ - lib/java_tools/javac.rb
36
+ - spec/jar_cmd_spec.rb
37
+ - spec/jar_spec.rb
38
+ - spec/javac_cmd_spec.rb
39
+ - spec/javac_spec.rb
40
+ - spec/spec.opts
41
+ - spec/spec_helper.rb
42
+ - tasks/gem.rake
43
+ - tasks/spec.rake
44
+ has_rdoc: false
45
+ homepage: http://github.com/iconara/java_tools
46
+ licenses:
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --charset=UTF-8
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.3.5
68
+ signing_key:
69
+ specification_version: 3
70
+ summary: Ruby wrappers for javac and jar that don't just exec
71
+ test_files:
72
+ - spec/jar_cmd_spec.rb
73
+ - spec/jar_spec.rb
74
+ - spec/javac_cmd_spec.rb
75
+ - spec/javac_spec.rb
76
+ - spec/spec_helper.rb