java_testing_guff 0.0.2
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.
- 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>
|