java_testing_guff 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +27 -0
- data/README.txt +1 -0
- data/Rakefile +4 -0
- data/config/hoe.rb +73 -0
- data/config/requirements.rb +18 -0
- data/lib/java_testing_guff-0.0.1.jar +0 -0
- data/lib/java_testing_guff.rb +169 -0
- data/lib/java_testing_guff/guff_extensions.rb +20 -0
- data/lib/java_testing_guff/qdox_extensions.rb +477 -0
- data/lib/java_testing_guff/version.rb +9 -0
- data/log/debug.log +0 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +74 -0
- data/setup.rb +1585 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/test_builders_generation.rb +19 -0
- data/test/test_helper.rb +91 -0
- data/test/test_java_testing_guff.rb +25 -0
- data/website/index.html +294 -0
- data/website/index.txt +198 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.rhtml +48 -0
- metadata +94 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
desc 'Release the website and new gem version'
|
2
|
+
task :deploy => [:check_version, :website, :release] do
|
3
|
+
puts "Remember to create SVN tag:"
|
4
|
+
puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
|
5
|
+
"svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
|
6
|
+
puts "Suggested comment:"
|
7
|
+
puts "Tagging release #{CHANGES}"
|
8
|
+
end
|
9
|
+
|
10
|
+
desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
|
11
|
+
task :local_deploy => [:website_generate, :install_gem]
|
12
|
+
|
13
|
+
task :check_version do
|
14
|
+
unless ENV['VERSION']
|
15
|
+
puts 'Must pass a VERSION=x.y.z release version'
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
unless ENV['VERSION'] == VERS
|
19
|
+
puts "Please update your version.rb to match the release version, currently #{VERS}"
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
|
25
|
+
task :install_gem_no_doc => [:clean, :package] do
|
26
|
+
sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
|
27
|
+
end
|
28
|
+
|
29
|
+
namespace :manifest do
|
30
|
+
desc 'Recreate Manifest.txt to include ALL files'
|
31
|
+
task :refresh do
|
32
|
+
`rake check_manifest | patch -p0 > Manifest.txt`
|
33
|
+
end
|
34
|
+
end
|
data/tasks/website.rake
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
desc 'Generate website files'
|
2
|
+
task :website_generate => :ruby_env do
|
3
|
+
(Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
|
4
|
+
sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
desc 'Upload website files to rubyforge'
|
9
|
+
task :website_upload do
|
10
|
+
host = "#{rubyforge_username}@rubyforge.org"
|
11
|
+
remote_dir = "/var/www/gforge-projects/#{PATH}/"
|
12
|
+
local_dir = 'website'
|
13
|
+
sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate and upload website files'
|
17
|
+
task :website => [:website_generate, :website_upload, :publish_docs]
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestBuildersGeneration < AbstractGuffTestCase
|
4
|
+
|
5
|
+
def test_can_generate_concrete_builder_selector
|
6
|
+
|
7
|
+
generator(JavaTestingGuff::RealBuilderGuffGenerator).generate_selector_foreach(['org.rubyforge.Customer','org.rubyforge.Address'])
|
8
|
+
|
9
|
+
assert expected('GeneratedBuilderSelector').same_as(generated('GeneratedBuilderSelector'))
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_can_generate_jmock_builder_selector
|
13
|
+
|
14
|
+
generator(JavaTestingGuff::JMockGuffGenerator).generate_selector_foreach(['org.rubyforge.Customer','org.rubyforge.Address'])
|
15
|
+
|
16
|
+
assert expected('GeneratedJMockBuilderSelector').same_as(generated('GeneratedJMockBuilderSelector'))
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
class JavaFileForTests
|
4
|
+
def initialize(testcase,path)
|
5
|
+
@testcase = testcase
|
6
|
+
@path = path
|
7
|
+
end
|
8
|
+
|
9
|
+
def same_as(path)
|
10
|
+
me = File.new(@path,"r")
|
11
|
+
other_lines = read_lines(path)
|
12
|
+
line_count=0
|
13
|
+
me.each_line do |line|
|
14
|
+
@testcase.assert_equal(line, other_lines[line_count],"#{path}:#{line_count.to_s}")
|
15
|
+
line_count = line_count + 1
|
16
|
+
end
|
17
|
+
me.close
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def read_lines(path)
|
22
|
+
result = []
|
23
|
+
f = File.new(path,"r")
|
24
|
+
f.each_line do |line|
|
25
|
+
result << line
|
26
|
+
end
|
27
|
+
f.close
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class AbstractGuffTestCase < Test::Unit::TestCase
|
34
|
+
def test_default
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def setup
|
39
|
+
FileUtils::rm_rf(generated_dir)
|
40
|
+
end
|
41
|
+
|
42
|
+
def expected_files_dir
|
43
|
+
relative_dir('/src/expected_files')
|
44
|
+
end
|
45
|
+
|
46
|
+
def generated_dir
|
47
|
+
relative_dir('/src/generated')
|
48
|
+
end
|
49
|
+
|
50
|
+
def generated_package
|
51
|
+
'org.rubyforge.generated'
|
52
|
+
end
|
53
|
+
|
54
|
+
def relative_dir(p)
|
55
|
+
File.dirname(__FILE__) + p
|
56
|
+
end
|
57
|
+
|
58
|
+
def expected(class_name)
|
59
|
+
JavaFileForTests.new(self,expected_files_dir + "/" + generated_package.gsub(".","/") + "/" + class_name + ".java")
|
60
|
+
end
|
61
|
+
|
62
|
+
def generated(class_name)
|
63
|
+
generated_dir + "/" + generated_package.gsub(".","/") + "/" + class_name + ".java"
|
64
|
+
end
|
65
|
+
|
66
|
+
def generator(generator_type)
|
67
|
+
javadocBuilder = JavaDocBuilder.new
|
68
|
+
javadocBuilder.add_source_tree(JFile.new(relative_dir("/src/java")))
|
69
|
+
|
70
|
+
generator_type.new(javadocBuilder).save_in(generated_dir).use_package(generated_package)
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
module JavaSourceTestHelper
|
77
|
+
def tmp_dir
|
78
|
+
'.'
|
79
|
+
end
|
80
|
+
|
81
|
+
def prepared_file_for_tests(name)
|
82
|
+
JavaFileForTests.new(self,File.dirname(__FILE__) + "/files/#{name}.java")
|
83
|
+
end
|
84
|
+
|
85
|
+
def assert_source_file_equals(source, expected)
|
86
|
+
file_path = source.save_in(tmp_dir)
|
87
|
+
assert expected.same_as(file_path)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
require File.dirname(__FILE__) + '/../lib/java_testing_guff'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestJavaTestingGuff < AbstractGuffTestCase
|
4
|
+
|
5
|
+
def test_can_generate_concrete_builder
|
6
|
+
|
7
|
+
generator(JavaTestingGuff::RealBuilderGuffGenerator).generate_guff_foreach(['org.rubyforge.Customer'])
|
8
|
+
|
9
|
+
assert expected('GeneratedCustomerBuilder').same_as(generated('GeneratedCustomerBuilder'))
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_can_generate_eazymock_builder
|
13
|
+
|
14
|
+
generator(JavaTestingGuff::EasyMockGuffGenerator).generate_guff_foreach(['org.rubyforge.Customer'])
|
15
|
+
|
16
|
+
assert expected('GeneratedCustomerMockBuilder').same_as(generated('GeneratedCustomerMockBuilder'))
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_can_generate_jmock_builder
|
20
|
+
|
21
|
+
generator(JavaTestingGuff::JMockGuffGenerator).generate_guff_foreach(['org.rubyforge.Customer'])
|
22
|
+
|
23
|
+
assert expected('GeneratedCustomerJMockBuilder').same_as(generated('GeneratedCustomerJMockBuilder'))
|
24
|
+
end
|
25
|
+
end
|
data/website/index.html
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
+
<head>
|
5
|
+
<link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
7
|
+
<title>
|
8
|
+
Generate Java test classes
|
9
|
+
</title>
|
10
|
+
<script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
|
11
|
+
<style>
|
12
|
+
|
13
|
+
</style>
|
14
|
+
<script type="text/javascript">
|
15
|
+
window.onload = function() {
|
16
|
+
settings = {
|
17
|
+
tl: { radius: 10 },
|
18
|
+
tr: { radius: 10 },
|
19
|
+
bl: { radius: 10 },
|
20
|
+
br: { radius: 10 },
|
21
|
+
antiAlias: true,
|
22
|
+
autoPad: true,
|
23
|
+
validTags: ["div"]
|
24
|
+
}
|
25
|
+
var versionBox = new curvyCorners(settings, document.getElementById("version"));
|
26
|
+
versionBox.applyCornersToAll();
|
27
|
+
}
|
28
|
+
</script>
|
29
|
+
</head>
|
30
|
+
<body>
|
31
|
+
<div id="main">
|
32
|
+
|
33
|
+
<h1>Generate Java test classes</h1>
|
34
|
+
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/java_testing_guff"; return false'>
|
35
|
+
<p>Get Version</p>
|
36
|
+
<a href="http://rubyforge.org/projects/java_testing_guff" class="numbers">0.0.1</a>
|
37
|
+
</div>
|
38
|
+
<h1>→ ‘java_testing_guff’</h1>
|
39
|
+
|
40
|
+
|
41
|
+
<h2>What</h2>
|
42
|
+
|
43
|
+
|
44
|
+
<p>java_testing_guff consists of a number of Ruby classes that generate Java classes that enable
|
45
|
+
a fluent interface style specification of mock behaviours in tests. It also generates fluent interfaces for setting
|
46
|
+
up java objects in particular states. For example:</p>
|
47
|
+
|
48
|
+
|
49
|
+
<p><pre class='syntax'>mock().customer().withId(10).notLoggedIn().expectingNewAddress().build()</pre>
|
50
|
+
<pre class='syntax'>real().order().withId(2).withOrderLine(line).withCustomer(customer).build()</pre></p>
|
51
|
+
|
52
|
+
|
53
|
+
<p>It does this by parsing your production code and creating java classes that implement a sensible fluent interface.</p>
|
54
|
+
|
55
|
+
|
56
|
+
<p>Both JMock and EasyMock are supported.</p>
|
57
|
+
|
58
|
+
|
59
|
+
<p>The gem works only with JRuby.</p>
|
60
|
+
|
61
|
+
|
62
|
+
<h2>Installing</h2>
|
63
|
+
|
64
|
+
|
65
|
+
<p><pre class='syntax'><span class="ident">sudo</span> <span class="ident">gem</span> <span class="ident">install</span> <span class="ident">java_testing_guff</span></pre></p>
|
66
|
+
|
67
|
+
|
68
|
+
<p>java_guff_builder makes use of the gem ‘guff’ to generate nicely formatted java code. ‘guff’ will be installed as a dependent
|
69
|
+
gem while installing java_guff_builder.</p>
|
70
|
+
|
71
|
+
|
72
|
+
<p>Also, QDox
|
73
|
+
(currently qdox-1.7-20070527.154641-2.jar) is needed on the JRuby classpath, to parse your production java source
|
74
|
+
files. So make sure you download <a href="http://qdox.codehaus.org">QDox</a> and install it:</p>
|
75
|
+
|
76
|
+
|
77
|
+
<p><pre class='syntax'>cp qdox-1.7-20070527.154641-2.jar $JRUBY_HOME/lib</pre></p>
|
78
|
+
|
79
|
+
|
80
|
+
<h2>The basics</h2>
|
81
|
+
|
82
|
+
|
83
|
+
<p>To generate one of these fluent interfaces, write a jruby script that does the following:</p>
|
84
|
+
|
85
|
+
|
86
|
+
<ol>
|
87
|
+
<li>instantiates a QDox JavaDocBuilder</li>
|
88
|
+
<li>configures the builder with the path(s) that contain your production code</li>
|
89
|
+
<li>instantiate and configure a particular generator (EasyMock, JMock, Concrete object)</li>
|
90
|
+
<li>tell the generate to go to work on an array of class names</li>
|
91
|
+
</ol>
|
92
|
+
|
93
|
+
|
94
|
+
<p>Optionally bind the generated classes into a subclass of TestCase so the syntax flows naturally (see below).</p>
|
95
|
+
|
96
|
+
|
97
|
+
<h2>Demonstration of usage</h2>
|
98
|
+
|
99
|
+
|
100
|
+
<p>Lets say you have two production classes, Customer and Order, that you want to generate EasyMock builders and a ‘real’
|
101
|
+
builder for. And the source code for these classes sits in ‘src/java’.</p>
|
102
|
+
|
103
|
+
|
104
|
+
<p>All builders require a configured JavaDocBuilder. JavaDocBuilder may seem like a weird name in terms of what we are
|
105
|
+
trying to do here, but thats what QDox calls it, so pretend its called ‘ProductionCodeParser’ :-)</p>
|
106
|
+
|
107
|
+
|
108
|
+
<p><pre class='syntax'>
|
109
|
+
require 'rubygems'
|
110
|
+
require 'java_testing_guff'
|
111
|
+
|
112
|
+
javadocBuilder = JavaDocBuilder.new
|
113
|
+
javadocBuilder.add_source_tree(JFile.new('src/java'))
|
114
|
+
javadocBuilder.add_source_tree(JFile.new('maybe some other paths?'))
|
115
|
+
</pre></p>
|
116
|
+
|
117
|
+
|
118
|
+
<p>No we go ahead and use the EasyMockGuffGenerator combined with that JavaDocBuilder:</p>
|
119
|
+
|
120
|
+
|
121
|
+
<p><pre class='syntax'>
|
122
|
+
easyMockGuffGenerator=JavaTestingGuff::EasyMockGuffGenerator.new(javadocBuilder)
|
123
|
+
.save_in('src/test')
|
124
|
+
.use_package('org.rubyforge.generated.mockbuilders')
|
125
|
+
|
126
|
+
easyMockGuffGenerator.generate_guff_foreach(['org.rubyforge.Customer','org.rubyforge.Order'])
|
127
|
+
</pre></p>
|
128
|
+
|
129
|
+
|
130
|
+
<p>This will generate org.rubyforge.generated.mockbuilders.GeneratedCustomerMockBuilder.java
|
131
|
+
and org.rubyforge.generated.mockbuilders.GeneratedOrderMockBuilder.java in the directory src/test.</p>
|
132
|
+
|
133
|
+
|
134
|
+
<p>The same kind of thing works for JMock and “real” builders:</p>
|
135
|
+
|
136
|
+
|
137
|
+
<p><pre class='syntax'>
|
138
|
+
jMockGuffGenerator=JavaTestingGuff::JMockGuffGenerator.new(javadocBuilder)
|
139
|
+
.save_in('src/test')
|
140
|
+
.use_package('org.rubyforge.generated.mockbuilders')
|
141
|
+
|
142
|
+
jMockGuffGenerator.generate_guff_foreach(['org.rubyforge.Customer','org.rubyforge.Order'])
|
143
|
+
</pre></p>
|
144
|
+
|
145
|
+
|
146
|
+
<p><pre class='syntax'>
|
147
|
+
realMockGuffGenerator=JavaTestingGuff::RealBuilderGuffGenerator.new(javadocBuilder)
|
148
|
+
.save_in('src/test')
|
149
|
+
.use_package('org.rubyforge.generated.realbuilders')
|
150
|
+
|
151
|
+
realMockGuffGenerator.generate_guff_foreach(['org.rubyforge.Customer','org.rubyforge.Order'])
|
152
|
+
</pre></p>
|
153
|
+
|
154
|
+
|
155
|
+
<p>One hint: if you want to use more than one generator on your project, use the same JavaDocBuilder instance,
|
156
|
+
because it takes quite some time to build this class as it parses all your production code.</p>
|
157
|
+
|
158
|
+
|
159
|
+
<h3>A word about EasyMock and MockCreator</h3>
|
160
|
+
|
161
|
+
|
162
|
+
<p>EasyMock provides two ways of creating mock instances:</p>
|
163
|
+
|
164
|
+
|
165
|
+
<p><pre class='syntax'>Customer customer = EasyMock.createMock(Customer.class)</pre></p>
|
166
|
+
|
167
|
+
|
168
|
+
<p>and</p>
|
169
|
+
|
170
|
+
|
171
|
+
<p><pre class='syntax'>
|
172
|
+
IMocksControl strictControl = EasyMock.createStrictControl();
|
173
|
+
Customer customer = strictControl.createMock(Customer.class)
|
174
|
+
</pre></p>
|
175
|
+
|
176
|
+
|
177
|
+
<p>Strict controls allow you to be explicit about ordering of method calls on mocks. The generated classes support
|
178
|
+
strict and nice (non-strick) mock construction as follows:</p>
|
179
|
+
|
180
|
+
|
181
|
+
<p><pre class='syntax'>
|
182
|
+
Customer niceCustomer = new GeneratedCustomerMockBuilder(new NiceMockCreator()).build();
|
183
|
+
|
184
|
+
IMocksControl strictControl = EasyMock.createStrictControl();
|
185
|
+
Customer strictCustomer = new GeneratedCustomerMockBuilder(new StrictMockCreator(strictControl)).build();
|
186
|
+
Customer anotherStrictCustomer = new GeneratedCustomerMockBuilder(new StrictMockCreator(strictControl)).build();
|
187
|
+
</pre></p>
|
188
|
+
|
189
|
+
|
190
|
+
<h3>java_testing_guff Java classes</h3>
|
191
|
+
|
192
|
+
|
193
|
+
<p>Some of the generated code makes use of Java classes that are distributed as part of this gem. You will find
|
194
|
+
the jar (java_testing_guff-x.y.z.jar) in the lib of this gem. You will need to include this jar on your classpath
|
195
|
+
to use the generated classes.</p>
|
196
|
+
|
197
|
+
|
198
|
+
<h3>Integration of generated classes</h3>
|
199
|
+
|
200
|
+
|
201
|
+
<p>You can use the generated classes like this if you please:</p>
|
202
|
+
|
203
|
+
|
204
|
+
<p><pre class='syntax'>
|
205
|
+
Customer customer = new GeneratedCustomerBuilder().withId(10).notLoggedIn().expectingNewAddress().build()
|
206
|
+
</pre></p>
|
207
|
+
|
208
|
+
|
209
|
+
<p>But personally I find that increases the noise in a test, taking away from clarity of intent. So I prefer to integrate
|
210
|
+
the generated classes into my own testing super class and provide more fluency:</p>
|
211
|
+
|
212
|
+
|
213
|
+
<p><pre class='syntax'>
|
214
|
+
public class MyTestCase extends TestCase {
|
215
|
+
public RealBuilders real() {
|
216
|
+
return new RealBuilders();
|
217
|
+
}
|
218
|
+
|
219
|
+
public MockBuilders mock() {
|
220
|
+
return new MockBuilders(new NiceMockCreator());
|
221
|
+
}
|
222
|
+
|
223
|
+
public MockBuilders mock(IMocksControl control) {
|
224
|
+
return new MockBuilders(new StrictMockCreator(control));
|
225
|
+
}
|
226
|
+
|
227
|
+
public class RealBuilders {
|
228
|
+
public GeneratedCustomerBuilder customer() {
|
229
|
+
return new GeneratedCustomerBuilder();
|
230
|
+
}
|
231
|
+
}
|
232
|
+
|
233
|
+
public class MockBuilders {
|
234
|
+
private final MockCreator mockCreator;
|
235
|
+
|
236
|
+
public MockBuilders(MockCreator mockCreator) {
|
237
|
+
this.mockCreator = mockCreator;
|
238
|
+
}
|
239
|
+
|
240
|
+
public GeneratedCustomerMockBuilder customer() {
|
241
|
+
return new GeneratedCustomerMockBuilder(mockCreator);
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
</pre></p>
|
246
|
+
|
247
|
+
|
248
|
+
<p>and now anything that inherits from MyTestCase can do</p>
|
249
|
+
|
250
|
+
|
251
|
+
<p><pre class='syntax'>
|
252
|
+
Customer customer = real().customer().withId(10).notLoggedIn().build();
|
253
|
+
Customer mockCustomer = mock().customer().withId(10).notLoggedIn().expectingNewAddress().build();
|
254
|
+
</pre></p>
|
255
|
+
|
256
|
+
|
257
|
+
<p>Suits me!</p>
|
258
|
+
|
259
|
+
|
260
|
+
<h2>Forum</h2>
|
261
|
+
|
262
|
+
|
263
|
+
<p><a href="http://groups.google.com/group/java-testing-guff">http://groups.google.com/group/java-testing-guff</a></p>
|
264
|
+
|
265
|
+
|
266
|
+
<h2>How to submit patches</h2>
|
267
|
+
|
268
|
+
|
269
|
+
<p>Read the <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/">8 steps for fixing other people’s code</a> and for section <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8b-google-groups">8b: Submit patch to Google Groups</a>, use the Google Group above.</p>
|
270
|
+
|
271
|
+
|
272
|
+
<p>The trunk repository is <code>svn://rubyforge.org/var/svn/jbuilder-guff</code> for anonymous access.</p>
|
273
|
+
|
274
|
+
|
275
|
+
<h2>License</h2>
|
276
|
+
|
277
|
+
|
278
|
+
<p>This code is free to use under the terms of the <span class="caps">MIT</span> license.</p>
|
279
|
+
|
280
|
+
|
281
|
+
<h2>Contact</h2>
|
282
|
+
|
283
|
+
|
284
|
+
<p>Comments are welcome. Send a suggestion/question to the <a href="http://groups.google.com/group/java-testing-guff">forum</a></p>
|
285
|
+
<p class="coda">
|
286
|
+
<a href="me@mikehogan.net">Mike Hogan</a>, 7th February 2008<br>
|
287
|
+
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
288
|
+
</p>
|
289
|
+
</div>
|
290
|
+
|
291
|
+
<!-- insert site tracking codes here, like Google Urchin -->
|
292
|
+
|
293
|
+
</body>
|
294
|
+
</html>
|