javaobj 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/install.rb ADDED
@@ -0,0 +1,42 @@
1
+ require 'rbconfig'
2
+ require 'find'
3
+ require 'ftools'
4
+
5
+ include Config
6
+
7
+ $ruby = CONFIG['ruby_install_name']
8
+
9
+ $sitedir = CONFIG["sitelibdir"]
10
+ unless $sitedir
11
+ version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
12
+ $libdir = File.join(CONFIG["libdir"], "ruby", version)
13
+ $sitedir = $:.find {|x| x =~ /site_ruby/}
14
+ if !$sitedir
15
+ $sitedir = File.join($libdir, "site_ruby")
16
+ elsif $sitedir !~ Regexp.quote(version)
17
+ $sitedir = File.join($sitedir, version)
18
+ end
19
+ end
20
+
21
+ if (destdir = ENV['DESTDIR'])
22
+ $sitedir = destdir + $sitedir
23
+ File::makedirs($sitedir)
24
+ end
25
+
26
+ rake_dest = File.join($sitedir, "rake")
27
+ File::makedirs(rake_dest, true)
28
+ File::chmod(0755, rake_dest)
29
+
30
+ # The library files
31
+
32
+ files = Dir.chdir('lib') { Dir['**/*.rb'] }
33
+
34
+ for fn in files
35
+ fn_dir = File.dirname(fn)
36
+ target_dir = File.join($sitedir, fn_dir)
37
+ if ! File.exist?(target_dir)
38
+ File.makedirs(target_dir)
39
+ end
40
+ File::install(File.join('lib', fn), File.join($sitedir, fn), 0644, true)
41
+ end
42
+
data/lib/javaobs.rb ADDED
@@ -0,0 +1,502 @@
1
+
2
+ require 'delegate'
3
+
4
+ module Java
5
+ class JavaField
6
+ attr_reader :name, :type
7
+ attr_accessor :subtype
8
+
9
+ def initialize(name, type)
10
+ @name = name
11
+ @type = type
12
+ @subtype = nil
13
+ end
14
+
15
+ def inspect
16
+ "<JavaField: #{@name}:#{@type.chr}:#{@subtype}>"
17
+ end
18
+ end
19
+
20
+ class JavaClass
21
+ attr_accessor :superClass, :rubyClass
22
+ attr_reader :name, :uid, :fields, :javaName, :flags, :arrayType
23
+
24
+ def initialize(name, uid, flags)
25
+ @name = @javaName = name
26
+ ind = name.rindex('.')
27
+ @name = name.slice(ind + 1..name.length) if ind
28
+ @flags = flags
29
+ @uid = uid
30
+ @fields = []
31
+ @arrayType = name[1] if name[0] == ?[
32
+ end
33
+
34
+ def addField(field)
35
+ @fields << field
36
+ end
37
+
38
+ def to_s
39
+ @name
40
+ end
41
+ end
42
+
43
+ module JavaObject
44
+ def javaClass
45
+ @javaClass
46
+ end
47
+ end
48
+
49
+ class Date < SimpleDelegator
50
+ extend JavaObject
51
+
52
+ def initialize
53
+ super(Time)
54
+ end
55
+
56
+ def time=(time)
57
+ case time
58
+ when Time
59
+ __setobj__(time)
60
+
61
+ when String
62
+ t, = time.unpack("Q")
63
+ __setobj__(Time.at(t / 1000, (t % 1000) * 1000))
64
+ end
65
+ end
66
+
67
+ def data
68
+ t = __getobj__.tv_sec * 1000 + __getobj__.tv_usec / 1000
69
+ [t].pack("Q")
70
+ end
71
+ end
72
+
73
+ class JavaArray < Array
74
+ extend JavaObject
75
+ end
76
+
77
+ module ObjectStream
78
+ STREAM_MAGIC = 0xACED
79
+ STREAM_VERSION = 5
80
+
81
+ TC_NULL = 0x70
82
+ TC_REFERENCE = 0x71
83
+ TC_CLASSDESC = 0x72
84
+ TC_OBJECT = 0x73
85
+ TC_STRING = 0x74
86
+ TC_ARRAY = 0x75
87
+ TC_CLASS = 0x76
88
+ TC_BLOCKDATA = 0x77
89
+ TC_ENDBLOCKDATA = 0x78
90
+ TC_RESET = 0x79
91
+ TC_BLOCKDATALONG = 0x7A
92
+ TC_EXCEPTION = 0x7B
93
+ TC_LONGSTRING = 0x7C
94
+ TC_PROXYCLASSDESC = 0x7D
95
+
96
+ SC_WRITE_METHOD = 0x01
97
+ SC_SERIALIZABLE = 0x02
98
+ SC_EXTERNALIZABLE = 0x04
99
+ SC_BLOCKDATA = 0x08
100
+
101
+ PRIM_BYTE = 66 # 'B'
102
+ PRIM_CHAR = 67 # 'C'
103
+ PRIM_DOUBLE = 68 # 'D'
104
+ PRIM_FLOAT = 70 # 'F'
105
+ PRIM_INT = 73 # 'I'
106
+ PRIM_LONG = 74 # 'J'
107
+ PRIM_SHORT = 83 # 'S'
108
+ PRIM_BOOL = 90 # 'Z'
109
+
110
+ PRIM_ARRAY = 91 # '['
111
+ PRIM_OBJECT = 76 # 'L'
112
+ end
113
+
114
+ class ObjectInputStream
115
+ include ObjectStream
116
+
117
+ def readByte; @str.read(1)[0]; end
118
+ def readUShort; @str.read(2).unpack("n")[0]; end
119
+ def readShort; @str.read(2).unpack("s")[0]; end
120
+ def readInt; @str.read(4).unpack("i")[0]; end
121
+ def readDouble; @str.read(8).unpack("G")[0]; end
122
+ def readFloat; @str.read(4).unpack("g")[0]; end
123
+ def readString; @str.read(readShort); end
124
+ def readBool; @str.read(1)[0] != 0; end
125
+ def readUID; @str.read(8); end
126
+ def readLong; @str.read(8).unpack("Q").first; end
127
+
128
+ def readBlockData
129
+ byte = readByte
130
+ size = nil
131
+ case byte
132
+ when TC_BLOCKDATA
133
+ size = readByte
134
+
135
+ when TC_BLOCKDATALONG
136
+ size = readInt
137
+
138
+ else
139
+ raise "Expecting TC_BLOCKDATA" unless byte == TC_BLOCKDATA
140
+ end
141
+
142
+ data = @str.read(size)
143
+ byte = readByte
144
+ raise "Unexpected byte #{byte}" unless byte == TC_ENDBLOCKDATA
145
+ data
146
+ end
147
+
148
+ def readFields(klass)
149
+ fieldCount = readShort
150
+ 1.upto(fieldCount) do
151
+ type = readByte
152
+ name = readString
153
+ field = JavaField.new(name, type)
154
+
155
+ # Check for array and object types
156
+ if type == PRIM_OBJECT || type == PRIM_ARRAY
157
+ field.subtype = readObject
158
+ end
159
+ klass.addField(field)
160
+ end
161
+ end
162
+
163
+ def readClassAnnotation
164
+ ebd = readByte
165
+ raise "We do not handle annotations!" unless ebd == TC_ENDBLOCKDATA
166
+ end
167
+
168
+ def readClassDesc
169
+ name = readString
170
+ uid = readUID
171
+ flags = readByte
172
+ klass = JavaClass.new(name, uid, flags)
173
+
174
+ @objects << klass
175
+
176
+ readFields(klass)
177
+ readClassAnnotation
178
+
179
+ klass.superClass = readObject
180
+
181
+ # Create Ruby object representing class
182
+ if name == 'java.util.Date'
183
+ rclass = Java::Date
184
+ rclass.class_eval "@javaClass = klass"
185
+ klass.rubyClass = rclass
186
+ elsif name =~ /^[A-Z.]+/i
187
+ unless Java.constants.index(klass.name)
188
+ rclass = Java.module_eval "#{klass.name} = Class.new(#{klass.superClass.to_s})"
189
+ else
190
+ rclass = Java.const_get(klass.name)
191
+ end
192
+
193
+ unless rclass.methods.index('javaClass')
194
+ rclass.class_eval "extend JavaObject"
195
+ end
196
+
197
+ rclass.class_eval "@javaClass = klass"
198
+ vars = klass.fields.map do |f|
199
+ ':' + f.name
200
+ end
201
+ rclass.class_eval "attr_accessor #{vars.join(',')}"
202
+ klass.rubyClass = rclass
203
+ else
204
+ # Arrays
205
+ newName = 'JavaArray' + klass.name[1..klass.name.length]
206
+ unless Java.constants.index(newName)
207
+ rclass = Java.module_eval "#{newName} = Class.new(JavaArray)"
208
+ else
209
+ rclass = Java.const_get(newName)
210
+ end
211
+ rclass.class_eval "@javaClass = klass"
212
+ klass.rubyClass = rclass
213
+ end
214
+
215
+ klass
216
+ end
217
+
218
+ def readArray(klass)
219
+ size = readInt
220
+ a = klass.rubyClass.new
221
+ type = klass.arrayType
222
+ 1.upto(size) do
223
+ a << readType(type)
224
+ end
225
+ a
226
+ end
227
+
228
+ def readType(type, arrayType = nil, field = nil)
229
+ case type
230
+ when PRIM_BYTE
231
+ readByte
232
+
233
+ when PRIM_CHAR
234
+ readByte
235
+
236
+ when PRIM_DOUBLE
237
+ readDouble
238
+
239
+ when PRIM_FLOAT
240
+ readFloat
241
+
242
+ when PRIM_INT
243
+ readInt
244
+
245
+ when PRIM_LONG
246
+ readLong
247
+
248
+ when PRIM_SHORT
249
+ readShort
250
+
251
+ when PRIM_BOOL
252
+ readBool
253
+
254
+ when PRIM_OBJECT, PRIM_ARRAY
255
+ readObject
256
+
257
+ else
258
+ raise "Unknown type #{type}"
259
+ end
260
+ end
261
+
262
+ def readClassData(klass, object = nil)
263
+ # Handle special case for Date
264
+ if object == nil
265
+ if (klass.javaName == 'java.util.Date')
266
+ object = Java::Date.new
267
+ else
268
+ object = klass.rubyClass.new()
269
+ end
270
+ @objects << object
271
+ end
272
+
273
+ readClassData(klass.superClass, object) if (klass.superClass)
274
+
275
+ if klass.flags == SC_SERIALIZABLE
276
+ klass.fields.each do |f|
277
+ v = readType(f.type, f.subtype, f)
278
+ object.send((f.name + '=').intern, v)
279
+ end
280
+ else
281
+ data = readBlockData
282
+ object.time = data
283
+ end
284
+
285
+ object
286
+ end
287
+
288
+ def readObject
289
+ object = nil
290
+ byte = readByte
291
+ case byte
292
+ when TC_OBJECT
293
+ klass = readObject
294
+ object = readClassData(klass)
295
+
296
+ when TC_REFERENCE
297
+ readShort
298
+ object = @objects[readShort]
299
+
300
+ when TC_ARRAY
301
+ klass = readObject
302
+ object = readArray(klass)
303
+ @objects << object
304
+
305
+ when TC_STRING
306
+ object = readString
307
+ @objects << object
308
+
309
+ when TC_CLASSDESC
310
+ object = readClassDesc
311
+
312
+ when TC_NULL
313
+ object = nil
314
+
315
+ else
316
+ raise "Unexpected byte #{byte} at #{@str.pos}"
317
+ end
318
+
319
+ object
320
+ end
321
+
322
+ def initialize(str)
323
+ @str = str
324
+ magic = readUShort
325
+ streamVersion = readShort
326
+ @objects = []
327
+
328
+ raise "Bad stream #{magic.to_s(16)}:#{streamVersion.to_s(16)}" if magic != STREAM_MAGIC ||
329
+ streamVersion != STREAM_VERSION
330
+
331
+ end
332
+
333
+ def readObjects
334
+ objs = []
335
+ until (@str.eof)
336
+ objs << readObject
337
+ end
338
+ objs
339
+ end
340
+ end
341
+
342
+ class ObjectOutputStream
343
+ include ObjectStream
344
+
345
+ def writeByte(b); @str.putc b; end
346
+ def writeUShort(s); @str.write [s].pack("n"); end
347
+ def writeShort(s); @str.write [s].pack("s"); end
348
+ def writeInt(i); @str.write [i].pack("i"); end
349
+ def writeDouble(d); @str.write [d].pack("G"); end
350
+ def writeFloat(f); @str.write [f].pack("g"); end
351
+ def writeString(s); writeShort(s.length); @str.write s; end
352
+ def writeBool(b); writeByte(b ? 1 : 0); end
353
+ def writeUID(u); @str.write u; end
354
+ def writeLong(l); @str.write [l].pack("Q"); end
355
+
356
+ def nextHandle
357
+ h = @nextHandle
358
+ @nextHandle += 1
359
+ h
360
+ end
361
+
362
+ def writeArray(klass, v)
363
+ type = klass.arrayType
364
+ writeInt(v.length)
365
+ v.each do |e|
366
+ writeType(type, e)
367
+ end
368
+ end
369
+
370
+ def writeBlockData(data)
371
+ if (data.length <= 255)
372
+ writeByte(TC_BLOCKDATA)
373
+ writeByte(data.length)
374
+ else
375
+ writeByte(TC_BLOCKDATALONG)
376
+ writeInt(data.length)
377
+ end
378
+
379
+ @str.write data
380
+ writeByte(TC_ENDBLOCKDATA)
381
+ end
382
+
383
+ def writeType(type, v)
384
+ case type
385
+ when PRIM_BYTE
386
+ writeByte(v)
387
+
388
+ when PRIM_CHAR
389
+ writeByte(v)
390
+
391
+ when PRIM_DOUBLE
392
+ writeDouble(v)
393
+
394
+ when PRIM_FLOAT
395
+ writeFloat(v)
396
+
397
+ when PRIM_INT
398
+ writeInt(v)
399
+
400
+ when PRIM_LONG
401
+ writeLong(v)
402
+
403
+ when PRIM_SHORT
404
+ writeShort(v)
405
+
406
+ when PRIM_BOOL
407
+ writeBool(v)
408
+
409
+ when PRIM_OBJECT, PRIM_ARRAY
410
+ writeObject(v)
411
+
412
+ else
413
+ raise "Unknown type #{type}"
414
+ end
415
+ end
416
+
417
+ def writeClassDesc(klass)
418
+ @handles[klass] = nextHandle
419
+
420
+ writeString klass.javaName
421
+ writeUID klass.uid
422
+ writeByte klass.flags
423
+
424
+ writeShort(klass.fields.length)
425
+ klass.fields.each do |f|
426
+ writeByte(f.type)
427
+ writeString(f.name)
428
+ writeObject(f.subtype) if f.subtype
429
+ end
430
+
431
+ writeByte(TC_ENDBLOCKDATA) # Annotations
432
+ writeObject(klass.superClass)
433
+ end
434
+
435
+ def writeObjectData(klass, obj)
436
+ writeObjectData(klass.superClass, obj) if klass.superClass
437
+
438
+ if klass.flags == SC_SERIALIZABLE
439
+ klass.fields.each do |f|
440
+ v = obj.send(f.name.intern)
441
+ writeType(f.type, v)
442
+ end
443
+ else
444
+ writeBlockData(obj.data)
445
+ end
446
+ end
447
+
448
+ def writeObject(obj)
449
+ unless obj
450
+ writeByte(TC_NULL)
451
+ else
452
+ handle = @handles[obj]
453
+ if (handle)
454
+ writeByte(TC_REFERENCE)
455
+ writeShort(0x007E)
456
+ writeShort(handle)
457
+ else
458
+ case obj
459
+ when JavaClass
460
+ writeByte(TC_CLASSDESC)
461
+ writeClassDesc(obj)
462
+
463
+ when JavaArray
464
+ writeByte(TC_ARRAY)
465
+ writeObject(obj.class.javaClass)
466
+ writeArray(obj.class.javaClass, obj)
467
+ @handles[obj] = nextHandle
468
+
469
+ when String
470
+ writeByte(TC_STRING)
471
+ writeString(obj)
472
+ @handles[obj] = nextHandle
473
+
474
+ else
475
+ writeByte(TC_OBJECT)
476
+ klass = obj.class.javaClass
477
+ writeObject(klass)
478
+ @handles[obj] = nextHandle
479
+ writeObjectData(klass, obj)
480
+
481
+ end
482
+ end
483
+ end
484
+ end
485
+
486
+ def writeObjects(objs)
487
+ objs.each do |o|
488
+ writeObject o
489
+ end
490
+ end
491
+
492
+ def initialize(str)
493
+ @str = str
494
+ @handles = {}
495
+ @nextHandle = 0
496
+
497
+ writeUShort(STREAM_MAGIC)
498
+ writeShort(STREAM_VERSION)
499
+ end
500
+ end
501
+ end
502
+
data/rakefile ADDED
@@ -0,0 +1,64 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/contrib/rubyforgepublisher'
8
+
9
+ PKG_BUILD = '1'
10
+ PKG_NAME = 'javaobj'
11
+ PKG_VERSION = '0.1'
12
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
13
+
14
+ RELEASE_NAME = "REL #{PKG_VERSION}"
15
+ RUBY_FORGE_PROJECT = "javaobj"
16
+ RUBY_FORGE_USER = "wsobel"
17
+
18
+ desc "Default Task"
19
+ task :default => [ :test ]
20
+
21
+ Rake::TestTask.new do |t|
22
+ t.libs << "test"
23
+ t.test_files = Dir.glob( "test/test.rb" )
24
+ t.verbose = true
25
+ end
26
+
27
+ Rake::RDocTask.new do |rdoc|
28
+ rdoc.rdoc_dir = 'doc'
29
+ rdoc.title = "Java Objects"
30
+ rdoc.options << '--line-numbers' << '--inline-source'
31
+ rdoc.template = "#{ENV['template']}.rb" if ENV['template']
32
+ rdoc.rdoc_files.include('lib/**/*.rb')
33
+ end
34
+
35
+ dist_dirs = [ "lib", "test", "examples" ]
36
+
37
+ spec = Gem::Specification.new do |s|
38
+ s.platform = Gem::Platform::RUBY
39
+ s.name = PKG_NAME
40
+ s.version = PKG_VERSION
41
+ s.summary = "Decode Java Serialized Objects to Ruby Objects."
42
+ s.description = %q{Takes Java serialized objects in a file or stream and creates Ruby wrapper objects and decodes. The package can also write Java objects once UUID is read from sample.}
43
+
44
+ s.author = "William Sobel"
45
+ s.email = "willsobel@mac.com"
46
+ s.rubyforge_project = "javaobj"
47
+ s.homepage = "http://www.rubyforge.org"
48
+
49
+ s.has_rdoc = true
50
+ s.requirements << 'none'
51
+
52
+ s.require_path = 'lib'
53
+
54
+ s.files = [ "rakefile", "install.rb" ]
55
+ dist_dirs.each do |dir|
56
+ s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
57
+ end
58
+ end
59
+
60
+ Rake::GemPackageTask.new(spec) do |p|
61
+ p.gem_spec = spec
62
+ p.need_tar = true
63
+ p.need_zip = true
64
+ end
data/test/Test.class ADDED
Binary file
data/test/Test.java ADDED
@@ -0,0 +1,50 @@
1
+ import java.io.*;
2
+ import java.util.Date;
3
+
4
+ public class Test implements Serializable
5
+ {
6
+ int a;
7
+ int b;
8
+ long c;
9
+ String d;
10
+ int e[];
11
+
12
+ public void setA(int x) { a = x; }
13
+ public void setB(int x) { b = x; }
14
+ public void setC(long l) { c = l; }
15
+ public void setD(String s) { d = s; }
16
+ public void setE(int x[]) { e = x; }
17
+
18
+ public static void main(String args[])
19
+ {
20
+ Test t = new Test();
21
+ t.setA(1);
22
+ t.setB(2);
23
+ t.setC(1000000000000000L);
24
+ t.setD("Hello");
25
+ int a[] = new int[20];
26
+ for (int i = 0; i < 20; i++)
27
+ {
28
+ a[i] = i;
29
+ }
30
+
31
+ t.setE(a);
32
+
33
+ try
34
+ {
35
+ FileOutputStream fos = new FileOutputStream("t.tmp");
36
+ ObjectOutputStream oos = new ObjectOutputStream(fos);
37
+
38
+ oos.writeObject(t);
39
+ oos.writeObject(new Date());
40
+ oos.close();
41
+ }
42
+
43
+ catch (Throwable x)
44
+ {
45
+ System.err.println(x);
46
+ }
47
+
48
+ System.exit(0);
49
+ }
50
+ }
data/test/test.rb ADDED
@@ -0,0 +1,79 @@
1
+
2
+ $testdir = File.dirname(__FILE__)
3
+ $: << "#{$testdir}/../lib"
4
+
5
+ require 'javaobs'
6
+ require 'test/unit'
7
+
8
+ class JavaTest < Test::Unit::TestCase
9
+
10
+ def setup
11
+ system("javac #{$testdir}/Test.java")
12
+ system("java -classpath #{$testdir} Test")
13
+ end
14
+
15
+ def teardown
16
+ File.unlink('t.tmp')
17
+ File.unlink('t.tmp.new')
18
+ end
19
+
20
+ def test_read
21
+ orig = ''
22
+ objs = nil
23
+ File.open("t.tmp") do |f|
24
+ f.binmode
25
+
26
+ orig = f.read
27
+ f.seek(0)
28
+
29
+ os = Java::ObjectInputStream.new(f)
30
+ assert os
31
+ objs = os.readObjects
32
+ assert objs
33
+ end
34
+
35
+ obj1, obj2 = objs
36
+ assert_equal obj1.a, 1
37
+ assert_equal obj1.b, 2
38
+ assert_equal obj1.c, 1000000000000000
39
+ assert_equal obj1.d, "Hello"
40
+ obj1.e.each_with_index { |v, i| assert_equal v, i }
41
+ assert_equal obj2.class, Java::Date
42
+ end
43
+
44
+ def test_write
45
+ orig = ''
46
+ objs = nil
47
+ File.open("t.tmp") do |f|
48
+ f.binmode
49
+
50
+ orig = f.read
51
+ f.seek(0)
52
+
53
+ os = Java::ObjectInputStream.new(f)
54
+ assert os
55
+ objs = os.readObjects
56
+ assert objs
57
+ end
58
+
59
+ File.open('t.tmp.new', 'w') do |f|
60
+ f.binmode
61
+
62
+ os = Java::ObjectOutputStream.new(f)
63
+ os.writeObjects(objs)
64
+ end
65
+
66
+ mine = File.open('t.tmp.new').read
67
+ assert_equal mine, orig
68
+ end
69
+ end
70
+
71
+
72
+ if $0 == __FILE__
73
+ suite = Test::Unit::TestSuite.new('DataSource')
74
+ ObjectSpace.each_object(Class) do |klass|
75
+ suite << klass.suite if (Test::Unit::TestCase > klass)
76
+ end
77
+ require 'test/unit/ui/console/testrunner'
78
+ Test::Unit::UI::Console::TestRunner.run(suite).passed?
79
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: javaobj
5
+ version: !ruby/object:Gem::Version
6
+ version: "0.1"
7
+ date: 2006-04-16 00:00:00 -07:00
8
+ summary: Decode Java Serialized Objects to Ruby Objects.
9
+ require_paths:
10
+ - lib
11
+ email: willsobel@mac.com
12
+ homepage: http://www.rubyforge.org
13
+ rubyforge_project: javaobj
14
+ description: Takes Java serialized objects in a file or stream and creates Ruby wrapper objects and decodes. The package can also write Java objects once UUID is read from sample.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - William Sobel
30
+ files:
31
+ - rakefile
32
+ - install.rb
33
+ - lib/javaobs.rb
34
+ - test/Test.class
35
+ - test/Test.java
36
+ - test/test.rb
37
+ test_files: []
38
+
39
+ rdoc_options: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ executables: []
44
+
45
+ extensions: []
46
+
47
+ requirements:
48
+ - none
49
+ dependencies: []
50
+