javaobjs 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/install.rb +42 -0
- data/lib/CVS/Entries +2 -0
- data/lib/CVS/Repository +1 -0
- data/lib/CVS/Root +1 -0
- data/lib/javaobs.rb +686 -0
- data/rakefile +176 -0
- data/test/CVS/Entries +4 -0
- data/test/CVS/Repository +1 -0
- data/test/CVS/Root +1 -0
- data/test/Test.java +62 -0
- data/test/Test2.java +40 -0
- data/test/test.rb +111 -0
- metadata +58 -0
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/CVS/Entries
ADDED
data/lib/CVS/Repository
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
trunk/lib
|
data/lib/CVS/Root
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
:ext:wsobel@rubyforge.org:/var/cvs/javaobs
|
data/lib/javaobs.rb
ADDED
@@ -0,0 +1,686 @@
|
|
1
|
+
|
2
|
+
require 'delegate'
|
3
|
+
|
4
|
+
# Java Objects namespace to read and write Java serialized objects to streams.
|
5
|
+
# Any Java serialized object can be read from a stream. To write a Java object,
|
6
|
+
# the meta class must be primed with a sample input serialized object. The is
|
7
|
+
# required because Java uses a UUID to identify classes and it is generated using
|
8
|
+
# a complex hashing scheme of data and method signatures. Since this system does
|
9
|
+
# not have access to that information, it needs to get it from a serialized object.
|
10
|
+
#
|
11
|
+
# Objects that have custom serialization methods can be read and written by
|
12
|
+
# creating a class as we have for the Date class:
|
13
|
+
# module Java
|
14
|
+
# module Util
|
15
|
+
# class Date < SimpleDelegator
|
16
|
+
# extend JavaObject
|
17
|
+
#
|
18
|
+
# def initialize
|
19
|
+
# super(Time)
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # Set the time with a Time object.
|
23
|
+
# def time=(time)
|
24
|
+
# __setobj__(time)
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# def _readJavaData(stream)
|
28
|
+
# data = stream.readBlockData
|
29
|
+
# t, = data.unpack("Q")
|
30
|
+
# __setobj__(Time.at(t / 1000, (t % 1000) * 1000))
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# # Get the data in the form needed for the Java date serialization.
|
34
|
+
# def _writeJavaData(stream)
|
35
|
+
# t = __getobj__.tv_sec * 1000 + __getobj__.tv_usec / 1000
|
36
|
+
# stream.writeBlockData([t].pack("Q"))
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# The important methods are the data method that is used for writing the
|
43
|
+
# the object to a stream.
|
44
|
+
#
|
45
|
+
# All other classes will be auto-generated when the stream is read and persisted.
|
46
|
+
# A Java Meta Class is added to the Ruby Class that contains all the Java field
|
47
|
+
# information needed to serialize the objects.
|
48
|
+
|
49
|
+
module Java
|
50
|
+
|
51
|
+
# An error thrown when a serialization error occurs.
|
52
|
+
class SerializationError < RuntimeError
|
53
|
+
end
|
54
|
+
|
55
|
+
# An representation of a Java instance variable used to serialize
|
56
|
+
# data to and from a stream.
|
57
|
+
class JavaField
|
58
|
+
attr_reader :name, :type
|
59
|
+
attr_accessor :subtype
|
60
|
+
|
61
|
+
# Create a java instance variable with a name and data type.
|
62
|
+
def initialize(name, type)
|
63
|
+
@name = name
|
64
|
+
@type = type
|
65
|
+
@subtype = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def inspect
|
69
|
+
"<JavaField: #{@name}:#{@type.chr}:#{@subtype}>"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# The Java meta class with all the information needed for
|
74
|
+
# serialization of the Ruby class to the stream. This class
|
75
|
+
# is attached to the Ruby class.
|
76
|
+
class JavaClass
|
77
|
+
attr_accessor :superClass, :rubyClass
|
78
|
+
attr_reader :name, :uid, :fields, :javaName, :flags, :arrayType
|
79
|
+
|
80
|
+
def initialize(name, uid, flags)
|
81
|
+
@name = @javaName = name
|
82
|
+
ind = name.rindex('.')
|
83
|
+
@name = name.slice(ind + 1..name.length) if ind
|
84
|
+
@flags = flags
|
85
|
+
@uid = uid
|
86
|
+
@fields = []
|
87
|
+
@arrayType = name[1] if name[0] == ?[
|
88
|
+
end
|
89
|
+
|
90
|
+
# Add a field to the class.
|
91
|
+
def addField(field)
|
92
|
+
@fields << field
|
93
|
+
end
|
94
|
+
|
95
|
+
def to_s
|
96
|
+
@name
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# A small mixin to extend a Ruby class with the associated
|
101
|
+
# JavaClass.
|
102
|
+
module JavaObject
|
103
|
+
def javaClass
|
104
|
+
@javaClass
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# The custom serialization of the Java Date class
|
109
|
+
module Util
|
110
|
+
class Date < SimpleDelegator
|
111
|
+
extend JavaObject
|
112
|
+
|
113
|
+
def initialize
|
114
|
+
super(Time)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Set the time with a Time object.
|
118
|
+
def time=(time)
|
119
|
+
__setobj__(time)
|
120
|
+
end
|
121
|
+
|
122
|
+
def _readJavaData(stream)
|
123
|
+
data = stream.readBlockData
|
124
|
+
t, = data.unpack("Q")
|
125
|
+
__setobj__(Time.at(t / 1000, (t % 1000) * 1000))
|
126
|
+
end
|
127
|
+
|
128
|
+
# Get the data in the form needed for the Java date serialization.
|
129
|
+
def _writeJavaData(stream)
|
130
|
+
t = __getobj__.tv_sec * 1000 + __getobj__.tv_usec / 1000
|
131
|
+
stream.writeBlockData([t].pack("Q"))
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class HashMap < SimpleDelegator
|
136
|
+
extend JavaObject
|
137
|
+
|
138
|
+
def initialize
|
139
|
+
super(Hash)
|
140
|
+
@loadFactor = 0.75
|
141
|
+
@threshold = 12
|
142
|
+
end
|
143
|
+
|
144
|
+
def _readJavaData(stream)
|
145
|
+
# Read loadFactor and threshold.
|
146
|
+
stream.defaultReadObject(self)
|
147
|
+
stream.readBlockStart
|
148
|
+
len = stream.readInt
|
149
|
+
size = stream.readInt
|
150
|
+
|
151
|
+
h = Hash.new
|
152
|
+
size.times do
|
153
|
+
k = stream.readObject
|
154
|
+
v = stream.readObject
|
155
|
+
h[k] = v
|
156
|
+
end
|
157
|
+
stream.readBlockEnd
|
158
|
+
__setobj__(h)
|
159
|
+
end
|
160
|
+
|
161
|
+
def _writeJavaData(stream)
|
162
|
+
obj = __getobj__;
|
163
|
+
stream.defaultWriteObject(self)
|
164
|
+
stream.writeBlockStart(8)
|
165
|
+
l = 16
|
166
|
+
len = obj.length
|
167
|
+
while l < len
|
168
|
+
l << 1
|
169
|
+
end
|
170
|
+
stream.writeInt(l)
|
171
|
+
stream.writeInt(len)
|
172
|
+
obj.each do |k, v|
|
173
|
+
stream.writeObject(k)
|
174
|
+
stream.writeObject(v)
|
175
|
+
end
|
176
|
+
stream.writeBlockEnd
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# The Java Array wrapper using an Ruby Array.
|
182
|
+
class JavaArray < Array
|
183
|
+
extend JavaObject
|
184
|
+
end
|
185
|
+
|
186
|
+
# Container for the Java serialization constants.
|
187
|
+
module ObjectStream
|
188
|
+
STREAM_MAGIC = 0xACED
|
189
|
+
STREAM_VERSION = 5
|
190
|
+
|
191
|
+
TC_NULL = 0x70
|
192
|
+
TC_REFERENCE = 0x71
|
193
|
+
TC_CLASSDESC = 0x72
|
194
|
+
TC_OBJECT = 0x73
|
195
|
+
TC_STRING = 0x74
|
196
|
+
TC_ARRAY = 0x75
|
197
|
+
TC_CLASS = 0x76
|
198
|
+
TC_BLOCKDATA = 0x77
|
199
|
+
TC_ENDBLOCKDATA = 0x78
|
200
|
+
TC_RESET = 0x79
|
201
|
+
TC_BLOCKDATALONG = 0x7A
|
202
|
+
TC_EXCEPTION = 0x7B
|
203
|
+
TC_LONGSTRING = 0x7C
|
204
|
+
TC_PROXYCLASSDESC = 0x7D
|
205
|
+
|
206
|
+
SC_WRITE_METHOD = 0x01
|
207
|
+
SC_SERIALIZABLE = 0x02
|
208
|
+
SC_EXTERNALIZABLE = 0x04
|
209
|
+
SC_BLOCKDATA = 0x08
|
210
|
+
|
211
|
+
PRIM_BYTE = 66 # 'B'
|
212
|
+
PRIM_CHAR = 67 # 'C'
|
213
|
+
PRIM_DOUBLE = 68 # 'D'
|
214
|
+
PRIM_FLOAT = 70 # 'F'
|
215
|
+
PRIM_INT = 73 # 'I'
|
216
|
+
PRIM_LONG = 74 # 'J'
|
217
|
+
PRIM_SHORT = 83 # 'S'
|
218
|
+
PRIM_BOOL = 90 # 'Z'
|
219
|
+
|
220
|
+
PRIM_ARRAY = 91 # '['
|
221
|
+
PRIM_OBJECT = 76 # 'L'
|
222
|
+
end
|
223
|
+
|
224
|
+
# The Ruby version of the Java ObjectInputStream. Creates a Ruby
|
225
|
+
# proxy class for each Java Class.
|
226
|
+
class ObjectInputStream
|
227
|
+
include ObjectStream
|
228
|
+
|
229
|
+
def readByte; @str.read(1)[0]; end
|
230
|
+
def readUShort; @str.read(2).unpack("n")[0]; end
|
231
|
+
def readShort; @str.read(2).unpack("s")[0]; end
|
232
|
+
def readInt; @str.read(4).unpack("i")[0]; end
|
233
|
+
def readDouble; @str.read(8).unpack("G")[0]; end
|
234
|
+
def readFloat; @str.read(4).unpack("g")[0]; end
|
235
|
+
def readString; @str.read(readShort); end
|
236
|
+
def readBool; @str.read(1)[0] != 0; end
|
237
|
+
def readUID; @str.read(8); end
|
238
|
+
def readLong; @str.read(8).unpack("Q").first; end
|
239
|
+
|
240
|
+
def readBlockStart
|
241
|
+
byte = readByte
|
242
|
+
size = nil
|
243
|
+
case byte
|
244
|
+
when TC_BLOCKDATA
|
245
|
+
size = readByte
|
246
|
+
|
247
|
+
when TC_BLOCKDATALONG
|
248
|
+
size = readInt
|
249
|
+
|
250
|
+
else
|
251
|
+
raise SerializationError, "Expecting TC_BLOCKDATA, got #{'0x%X' % byte}" unless byte == TC_BLOCKDATA
|
252
|
+
end
|
253
|
+
size
|
254
|
+
end
|
255
|
+
|
256
|
+
def readBlockEnd
|
257
|
+
byte = readByte
|
258
|
+
raise SerializationError, "Unexpected byte #{byte}" unless byte == TC_ENDBLOCKDATA
|
259
|
+
end
|
260
|
+
|
261
|
+
# Read a Java block of data with a size and then the following data.
|
262
|
+
def readBlockData
|
263
|
+
size = readBlockStart
|
264
|
+
data = @str.read(size)
|
265
|
+
readBlockEnd
|
266
|
+
data
|
267
|
+
end
|
268
|
+
|
269
|
+
|
270
|
+
# Read all the fields from the stream and add them to the class.
|
271
|
+
def readFields(klass)
|
272
|
+
fieldCount = readShort
|
273
|
+
1.upto(fieldCount) do
|
274
|
+
type = readByte
|
275
|
+
name = readString
|
276
|
+
field = JavaField.new(name, type)
|
277
|
+
|
278
|
+
# Check for array and object types
|
279
|
+
if type == PRIM_OBJECT || type == PRIM_ARRAY
|
280
|
+
field.subtype = readObject
|
281
|
+
end
|
282
|
+
klass.addField(field)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
# Read the class annotation. We do not currently handle annotations.
|
287
|
+
def readClassAnnotation
|
288
|
+
ebd = readByte
|
289
|
+
raise SerializationError, "We do not handle annotations!" unless ebd == TC_ENDBLOCKDATA
|
290
|
+
end
|
291
|
+
|
292
|
+
# Gets or creates a corresponding Ruby class for the Java class. This
|
293
|
+
# will drop leading com or java and transform the rest of the dotted
|
294
|
+
# names to modules.
|
295
|
+
def rubyClassFor(name, super_name)
|
296
|
+
context = name.split('.')
|
297
|
+
f, = context
|
298
|
+
context.shift if f == 'java' or f == 'com'
|
299
|
+
context.map! { |n| n.capitalize! if n !~ /^[A-Z]/o; n }
|
300
|
+
kname = context.pop
|
301
|
+
|
302
|
+
mod = Java
|
303
|
+
context.each do |m|
|
304
|
+
unless mod.constants.include?(m)
|
305
|
+
mod = mod.module_eval "#{m} = Module.new"
|
306
|
+
else
|
307
|
+
mod = mod.const_get(m)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
unless mod.constants.include?(kname)
|
312
|
+
rclass = mod.module_eval "#{kname} = Class.new(#{super_name})"
|
313
|
+
else
|
314
|
+
rclass = mod.const_get(kname)
|
315
|
+
end
|
316
|
+
rclass
|
317
|
+
end
|
318
|
+
|
319
|
+
# Read the Java class description and create a Ruby class to proxy it
|
320
|
+
# in this name-space. Added special handling for the Date class.
|
321
|
+
def readClassDesc
|
322
|
+
name = readString
|
323
|
+
uid = readUID
|
324
|
+
flags = readByte
|
325
|
+
klass = JavaClass.new(name, uid, flags)
|
326
|
+
|
327
|
+
@objects << klass
|
328
|
+
|
329
|
+
readFields(klass)
|
330
|
+
readClassAnnotation
|
331
|
+
|
332
|
+
klass.superClass = readObject
|
333
|
+
|
334
|
+
# Create Ruby object representing class
|
335
|
+
if name =~ /^[A-Z.]+/i
|
336
|
+
# Create the class within the correct module.
|
337
|
+
rclass = rubyClassFor(name, klass.superClass.to_s)
|
338
|
+
|
339
|
+
unless rclass.methods.index('javaClass')
|
340
|
+
rclass.class_eval "extend JavaObject"
|
341
|
+
end
|
342
|
+
|
343
|
+
rclass.class_eval "@javaClass = klass"
|
344
|
+
vars = klass.fields.map do |f|
|
345
|
+
':' + f.name
|
346
|
+
end
|
347
|
+
rclass.class_eval "attr_accessor #{vars.join(',')}"
|
348
|
+
klass.rubyClass = rclass
|
349
|
+
else
|
350
|
+
# Arrays
|
351
|
+
newName = 'JavaArray' + klass.name[1..klass.name.length]
|
352
|
+
unless Java.constants.index(newName)
|
353
|
+
rclass = Java.module_eval "#{newName} = Class.new(JavaArray)"
|
354
|
+
else
|
355
|
+
rclass = Java.const_get(newName)
|
356
|
+
end
|
357
|
+
rclass.class_eval "@javaClass = klass"
|
358
|
+
klass.rubyClass = rclass
|
359
|
+
end
|
360
|
+
|
361
|
+
klass
|
362
|
+
end
|
363
|
+
|
364
|
+
# Read an array of objects.
|
365
|
+
def readArray(klass)
|
366
|
+
size = readInt
|
367
|
+
a = klass.rubyClass.new
|
368
|
+
type = klass.arrayType
|
369
|
+
1.upto(size) do
|
370
|
+
a << readType(type)
|
371
|
+
end
|
372
|
+
a
|
373
|
+
end
|
374
|
+
|
375
|
+
# Read a primitive data type.
|
376
|
+
def readType(type, arrayType = nil, field = nil)
|
377
|
+
case type
|
378
|
+
when PRIM_BYTE
|
379
|
+
readByte
|
380
|
+
|
381
|
+
when PRIM_CHAR
|
382
|
+
readByte
|
383
|
+
|
384
|
+
when PRIM_DOUBLE
|
385
|
+
readDouble
|
386
|
+
|
387
|
+
when PRIM_FLOAT
|
388
|
+
readFloat
|
389
|
+
|
390
|
+
when PRIM_INT
|
391
|
+
readInt
|
392
|
+
|
393
|
+
when PRIM_LONG
|
394
|
+
readLong
|
395
|
+
|
396
|
+
when PRIM_SHORT
|
397
|
+
readShort
|
398
|
+
|
399
|
+
when PRIM_BOOL
|
400
|
+
readBool
|
401
|
+
|
402
|
+
when PRIM_OBJECT, PRIM_ARRAY
|
403
|
+
readObject
|
404
|
+
|
405
|
+
else
|
406
|
+
raise SerializationError, "Unknown type #{type}"
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
# Cover method for java method.
|
411
|
+
def defaultReadObject(object)
|
412
|
+
readObjectFields(object.class.javaClass, object)
|
413
|
+
end
|
414
|
+
|
415
|
+
# Reads the object fields from the stream.
|
416
|
+
def readObjectFields(klass, object)
|
417
|
+
klass.fields.each do |f|
|
418
|
+
v = readType(f.type, f.subtype, f)
|
419
|
+
object.send((f.name + '=').intern, v)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
# Read class data and recursively read parent classes.
|
424
|
+
def readClassData(klass, object = nil)
|
425
|
+
if object == nil
|
426
|
+
object = klass.rubyClass.new()
|
427
|
+
@objects << object
|
428
|
+
end
|
429
|
+
|
430
|
+
readClassData(klass.superClass, object) if (klass.superClass)
|
431
|
+
|
432
|
+
if klass.flags == SC_SERIALIZABLE
|
433
|
+
readObjectFields(klass, object)
|
434
|
+
else
|
435
|
+
object._readJavaData(self)
|
436
|
+
end
|
437
|
+
|
438
|
+
object
|
439
|
+
end
|
440
|
+
|
441
|
+
# Read an object from the stream.
|
442
|
+
def readObject
|
443
|
+
object = nil
|
444
|
+
byte = readByte
|
445
|
+
case byte
|
446
|
+
when TC_OBJECT
|
447
|
+
klass = readObject
|
448
|
+
object = readClassData(klass)
|
449
|
+
|
450
|
+
when TC_REFERENCE
|
451
|
+
readShort
|
452
|
+
object = @objects[readShort]
|
453
|
+
|
454
|
+
when TC_ARRAY
|
455
|
+
klass = readObject
|
456
|
+
object = readArray(klass)
|
457
|
+
@objects << object
|
458
|
+
|
459
|
+
when TC_STRING
|
460
|
+
object = readString
|
461
|
+
@objects << object
|
462
|
+
|
463
|
+
when TC_CLASSDESC
|
464
|
+
object = readClassDesc
|
465
|
+
|
466
|
+
when TC_NULL
|
467
|
+
object = nil
|
468
|
+
|
469
|
+
else
|
470
|
+
raise SerializationError, "Unexpected byte #{byte} at #{@str.pos}"
|
471
|
+
end
|
472
|
+
|
473
|
+
object
|
474
|
+
end
|
475
|
+
|
476
|
+
# Initialize from a stream.
|
477
|
+
def initialize(str)
|
478
|
+
@str = str
|
479
|
+
magic = readUShort
|
480
|
+
streamVersion = readShort
|
481
|
+
@objects = []
|
482
|
+
|
483
|
+
raise "Bad stream #{magic.to_s(16)}:#{streamVersion.to_s(16)}" if magic != STREAM_MAGIC ||
|
484
|
+
streamVersion != STREAM_VERSION
|
485
|
+
|
486
|
+
end
|
487
|
+
|
488
|
+
# Read all objects in the stream. Calls readObject until the stream
|
489
|
+
# eof is reached.
|
490
|
+
def readObjects
|
491
|
+
objs = []
|
492
|
+
until (@str.eof)
|
493
|
+
objs << readObject
|
494
|
+
end
|
495
|
+
objs
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
# A Ruby version of the Java ObjectOutputStream. The Ruby classes must
|
500
|
+
# have attached Java meta classes to attach UUID.
|
501
|
+
class ObjectOutputStream
|
502
|
+
include ObjectStream
|
503
|
+
|
504
|
+
def writeByte(b); @str.putc b; end
|
505
|
+
def writeUShort(s); @str.write [s].pack("n"); end
|
506
|
+
def writeShort(s); @str.write [s].pack("s"); end
|
507
|
+
def writeInt(i); @str.write [i].pack("i"); end
|
508
|
+
def writeDouble(d); @str.write [d].pack("G"); end
|
509
|
+
def writeFloat(f); @str.write [f].pack("g"); end
|
510
|
+
def writeString(s); writeShort(s.length); @str.write s; end
|
511
|
+
def writeBool(b); writeByte(b ? 1 : 0); end
|
512
|
+
def writeUID(u); @str.write u; end
|
513
|
+
def writeLong(l); @str.write [l].pack("Q"); end
|
514
|
+
|
515
|
+
# Creates object reference handles.
|
516
|
+
def nextHandle
|
517
|
+
h = @nextHandle
|
518
|
+
@nextHandle += 1
|
519
|
+
h
|
520
|
+
end
|
521
|
+
|
522
|
+
# Write an array of objects.
|
523
|
+
def writeArray(klass, v)
|
524
|
+
type = klass.arrayType
|
525
|
+
writeInt(v.length)
|
526
|
+
v.each do |e|
|
527
|
+
writeType(type, e)
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
def writeBlockStart(size)
|
532
|
+
if (size <= 255)
|
533
|
+
writeByte(TC_BLOCKDATA)
|
534
|
+
writeByte(size)
|
535
|
+
else
|
536
|
+
writeByte(TC_BLOCKDATALONG)
|
537
|
+
writeInt(size)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
def writeBlockEnd
|
542
|
+
writeByte(TC_ENDBLOCKDATA)
|
543
|
+
end
|
544
|
+
|
545
|
+
# Writes a block of data to the stream.
|
546
|
+
def writeBlockData(data)
|
547
|
+
writeBlockStart(data.length)
|
548
|
+
@str.write data
|
549
|
+
writeBlockEnd
|
550
|
+
end
|
551
|
+
|
552
|
+
# Reads a Java primitive type.
|
553
|
+
def writeType(type, v)
|
554
|
+
case type
|
555
|
+
when PRIM_BYTE
|
556
|
+
writeByte(v)
|
557
|
+
|
558
|
+
when PRIM_CHAR
|
559
|
+
writeByte(v)
|
560
|
+
|
561
|
+
when PRIM_DOUBLE
|
562
|
+
writeDouble(v)
|
563
|
+
|
564
|
+
when PRIM_FLOAT
|
565
|
+
writeFloat(v)
|
566
|
+
|
567
|
+
when PRIM_INT
|
568
|
+
writeInt(v)
|
569
|
+
|
570
|
+
when PRIM_LONG
|
571
|
+
writeLong(v)
|
572
|
+
|
573
|
+
when PRIM_SHORT
|
574
|
+
writeShort(v)
|
575
|
+
|
576
|
+
when PRIM_BOOL
|
577
|
+
writeBool(v)
|
578
|
+
|
579
|
+
when PRIM_OBJECT, PRIM_ARRAY
|
580
|
+
writeObject(v)
|
581
|
+
|
582
|
+
else
|
583
|
+
raise SerializationError, "Unknown type #{type}"
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
# Writes the class description to the stream.
|
588
|
+
def writeClassDesc(klass)
|
589
|
+
@handles[klass] = nextHandle
|
590
|
+
|
591
|
+
writeString klass.javaName
|
592
|
+
writeUID klass.uid
|
593
|
+
writeByte klass.flags
|
594
|
+
|
595
|
+
writeShort(klass.fields.length)
|
596
|
+
klass.fields.each do |f|
|
597
|
+
writeByte(f.type)
|
598
|
+
writeString(f.name)
|
599
|
+
writeObject(f.subtype) if f.subtype
|
600
|
+
end
|
601
|
+
|
602
|
+
writeByte(TC_ENDBLOCKDATA) # Annotations
|
603
|
+
writeObject(klass.superClass)
|
604
|
+
end
|
605
|
+
|
606
|
+
def defaultWriteObject(object)
|
607
|
+
writeObjectFields(object.class.javaClass, object)
|
608
|
+
end
|
609
|
+
|
610
|
+
def writeObjectFields(klass, object)
|
611
|
+
klass.fields.each do |f|
|
612
|
+
v = object.send(f.name.intern)
|
613
|
+
writeType(f.type, v)
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
# Write the object and class to the stream.
|
618
|
+
def writeObjectData(klass, obj)
|
619
|
+
writeObjectData(klass.superClass, obj) if klass.superClass
|
620
|
+
|
621
|
+
if klass.flags == SC_SERIALIZABLE
|
622
|
+
writeObjectFields(klass, obj)
|
623
|
+
else
|
624
|
+
obj._writeJavaData(self)
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
# Writes the object and class data to the stream. Will
|
629
|
+
# write a reference if the object has already been written
|
630
|
+
# once.
|
631
|
+
def writeObject(obj)
|
632
|
+
unless obj
|
633
|
+
writeByte(TC_NULL)
|
634
|
+
else
|
635
|
+
handle = @handles[obj]
|
636
|
+
if (handle)
|
637
|
+
writeByte(TC_REFERENCE)
|
638
|
+
writeShort(0x007E)
|
639
|
+
writeShort(handle)
|
640
|
+
else
|
641
|
+
case obj
|
642
|
+
when JavaClass
|
643
|
+
writeByte(TC_CLASSDESC)
|
644
|
+
writeClassDesc(obj)
|
645
|
+
|
646
|
+
when JavaArray
|
647
|
+
writeByte(TC_ARRAY)
|
648
|
+
writeObject(obj.class.javaClass)
|
649
|
+
writeArray(obj.class.javaClass, obj)
|
650
|
+
@handles[obj] = nextHandle
|
651
|
+
|
652
|
+
when String
|
653
|
+
writeByte(TC_STRING)
|
654
|
+
writeString(obj)
|
655
|
+
@handles[obj] = nextHandle
|
656
|
+
|
657
|
+
else
|
658
|
+
writeByte(TC_OBJECT)
|
659
|
+
klass = obj.class.javaClass
|
660
|
+
writeObject(klass)
|
661
|
+
@handles[obj] = nextHandle
|
662
|
+
writeObjectData(klass, obj)
|
663
|
+
end
|
664
|
+
end
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
668
|
+
# Write an array of objects to the stream.
|
669
|
+
def writeObjects(objs)
|
670
|
+
objs.each do |o|
|
671
|
+
writeObject o
|
672
|
+
end
|
673
|
+
end
|
674
|
+
|
675
|
+
# Create an o writer on with a stream.
|
676
|
+
def initialize(str)
|
677
|
+
@str = str
|
678
|
+
@handles = {}
|
679
|
+
@nextHandle = 0
|
680
|
+
|
681
|
+
writeUShort(STREAM_MAGIC)
|
682
|
+
writeShort(STREAM_VERSION)
|
683
|
+
end
|
684
|
+
end
|
685
|
+
end
|
686
|
+
|
data/rakefile
ADDED
@@ -0,0 +1,176 @@
|
|
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 = '3'
|
10
|
+
PKG_NAME = 'javaobjs'
|
11
|
+
PKG_VERSION = '0.3'
|
12
|
+
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
13
|
+
|
14
|
+
RELEASE_NAME = "REL #{PKG_VERSION}"
|
15
|
+
RUBY_FORGE_PROJECT = "javaobs"
|
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.main = 'README.rdoc'
|
31
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
32
|
+
rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
33
|
+
rdoc.rdoc_files.include('README.rdoc', 'lib/**/*.rb')
|
34
|
+
end
|
35
|
+
|
36
|
+
dist_dirs = [ "lib", "test", "examples" ]
|
37
|
+
|
38
|
+
spec = Gem::Specification.new do |s|
|
39
|
+
s.platform = Gem::Platform::RUBY
|
40
|
+
s.name = PKG_NAME
|
41
|
+
s.version = PKG_VERSION
|
42
|
+
s.summary = "Decode Java Serialized Objects to Ruby Objects."
|
43
|
+
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.}
|
44
|
+
|
45
|
+
s.author = "William Sobel"
|
46
|
+
s.email = "willsobel@mac.com"
|
47
|
+
s.rubyforge_project = "javaobj"
|
48
|
+
s.homepage = "http://www.rubyforge.org"
|
49
|
+
|
50
|
+
s.has_rdoc = true
|
51
|
+
s.requirements << 'none'
|
52
|
+
|
53
|
+
s.require_path = 'lib'
|
54
|
+
|
55
|
+
s.files = [ "rakefile", "install.rb" ]
|
56
|
+
dist_dirs.each do |dir|
|
57
|
+
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Rake::GemPackageTask.new(spec) do |p|
|
62
|
+
p.gem_spec = spec
|
63
|
+
p.need_tar = true
|
64
|
+
p.need_zip = true
|
65
|
+
end
|
66
|
+
|
67
|
+
task :release => [:repackage] do
|
68
|
+
files = ["gem", "zip", "tgz"].map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }
|
69
|
+
|
70
|
+
if RUBY_FORGE_PROJECT then
|
71
|
+
require 'net/http'
|
72
|
+
require 'open-uri'
|
73
|
+
|
74
|
+
project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"
|
75
|
+
project_data = open(project_uri) { |data| data.read }
|
76
|
+
puts project_data
|
77
|
+
group_id = project_data[/[?&]group_id=(\d+)/, 1]
|
78
|
+
raise "Couldn't get group id" unless group_id
|
79
|
+
|
80
|
+
# This echos password to shell which is a bit sucky
|
81
|
+
if ENV["RUBY_FORGE_PASSWORD"]
|
82
|
+
password = ENV["RUBY_FORGE_PASSWORD"]
|
83
|
+
else
|
84
|
+
print "#{RUBY_FORGE_USER}@rubyforge.org's password: "
|
85
|
+
password = STDIN.gets.chomp
|
86
|
+
end
|
87
|
+
|
88
|
+
login_response = Net::HTTP.post_form(URI.parse('http://rubyforge.org/account/login.php'),
|
89
|
+
{'form_loginname'=> RUBY_FORGE_USER,
|
90
|
+
'form_pw'=> password, 'login' => 1})
|
91
|
+
|
92
|
+
cookie = login_response["set-cookie"]
|
93
|
+
raise "Login failed" unless cookie
|
94
|
+
headers = { "Cookie" => cookie }
|
95
|
+
|
96
|
+
release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"
|
97
|
+
release_data = open(release_uri, headers) { |data| data.read }
|
98
|
+
package_id = release_data[/[?&]package_id=(\d+)/, 1]
|
99
|
+
raise "Couldn't get package id" unless package_id
|
100
|
+
|
101
|
+
first_file = true
|
102
|
+
release_id = ""
|
103
|
+
|
104
|
+
|
105
|
+
files.each do |filename|
|
106
|
+
basename = File.basename(filename)
|
107
|
+
file_ext = File.extname(filename)
|
108
|
+
file_data = File.open(filename, "rb") { |file| file.read }
|
109
|
+
|
110
|
+
puts "Releasing #{basename}..."
|
111
|
+
|
112
|
+
release_response = Net::HTTP.start("rubyforge.org", 80) do |http|
|
113
|
+
release_date = Time.now.strftime("%Y-%m-%d %H:%M")
|
114
|
+
type_map = {
|
115
|
+
".zip" => "3000",
|
116
|
+
".tgz" => "3110",
|
117
|
+
".gz" => "3110",
|
118
|
+
".gem" => "1400"
|
119
|
+
}; type_map.default = "9999"
|
120
|
+
type = type_map[file_ext]
|
121
|
+
boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
|
122
|
+
|
123
|
+
query_hash = if first_file then
|
124
|
+
{
|
125
|
+
"group_id" => group_id,
|
126
|
+
"package_id" => package_id,
|
127
|
+
"release_name" => RELEASE_NAME,
|
128
|
+
"release_date" => release_date,
|
129
|
+
"type_id" => type,
|
130
|
+
"processor_id" => "8000", # Any
|
131
|
+
"release_notes" => "",
|
132
|
+
"release_changes" => "",
|
133
|
+
"preformatted" => "1",
|
134
|
+
"submit" => "1"
|
135
|
+
}
|
136
|
+
else
|
137
|
+
{
|
138
|
+
"group_id" => group_id,
|
139
|
+
"release_id" => release_id,
|
140
|
+
"package_id" => package_id,
|
141
|
+
"step2" => "1",
|
142
|
+
"type_id" => type,
|
143
|
+
"processor_id" => "8000", # Any
|
144
|
+
"submit" => "Add This File"
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
query = "?" + query_hash.map do |(name, value)|
|
149
|
+
[name, URI.encode(value)].join("=")
|
150
|
+
end.join("&")
|
151
|
+
|
152
|
+
data = [
|
153
|
+
"--" + boundary,
|
154
|
+
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",
|
155
|
+
"Content-Type: application/octet-stream",
|
156
|
+
"Content-Transfer-Encoding: binary",
|
157
|
+
"", file_data, ""
|
158
|
+
].join("\x0D\x0A")
|
159
|
+
|
160
|
+
release_headers = headers.merge(
|
161
|
+
"Content-Type" => "multipart/form-data; boundary=#{boundary}"
|
162
|
+
)
|
163
|
+
|
164
|
+
target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
|
165
|
+
http.post(target + query, data, release_headers)
|
166
|
+
end
|
167
|
+
|
168
|
+
if first_file then
|
169
|
+
release_id = release_response.body[/release_id=(\d+)/, 1]
|
170
|
+
raise("Couldn't get release id") unless release_id
|
171
|
+
end
|
172
|
+
|
173
|
+
first_file = false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
data/test/CVS/Entries
ADDED
data/test/CVS/Repository
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
trunk/test
|
data/test/CVS/Root
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
:ext:wsobel@rubyforge.org:/var/cvs/javaobs
|
data/test/Test.java
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
import java.io.*;
|
2
|
+
import java.util.Date;
|
3
|
+
import java.util.Calendar;
|
4
|
+
import java.util.HashMap;
|
5
|
+
import java.util.Map;
|
6
|
+
|
7
|
+
public class Test implements Serializable
|
8
|
+
{
|
9
|
+
int a;
|
10
|
+
int b;
|
11
|
+
long c;
|
12
|
+
String d;
|
13
|
+
int e[];
|
14
|
+
Date date;
|
15
|
+
Map map;
|
16
|
+
|
17
|
+
|
18
|
+
public void setA(int x) { a = x; }
|
19
|
+
public void setB(int x) { b = x; }
|
20
|
+
public void setC(long l) { c = l; }
|
21
|
+
public void setD(String s) { d = s; }
|
22
|
+
public void setE(int x[]) { e = x; }
|
23
|
+
public void setDate(Date d) { date = d; }
|
24
|
+
public void setMap(Map m) { map = m; }
|
25
|
+
|
26
|
+
public static void main(String args[])
|
27
|
+
{
|
28
|
+
Test t = new Test();
|
29
|
+
t.setA(1);
|
30
|
+
t.setB(2);
|
31
|
+
t.setC(1000000000000000L);
|
32
|
+
t.setD("Hello");
|
33
|
+
int a[] = new int[20];
|
34
|
+
for (int i = 0; i < 20; i++)
|
35
|
+
{
|
36
|
+
a[i] = i;
|
37
|
+
}
|
38
|
+
|
39
|
+
t.setE(a);
|
40
|
+
Calendar cal = Calendar.getInstance();
|
41
|
+
cal.set(2006, 5, 5, 13, 20, 00);
|
42
|
+
cal.set(Calendar.MILLISECOND, 0);
|
43
|
+
t.setDate(cal.getTime());
|
44
|
+
|
45
|
+
try
|
46
|
+
{
|
47
|
+
FileOutputStream fos = new FileOutputStream("t.tmp");
|
48
|
+
ObjectOutputStream oos = new ObjectOutputStream(fos);
|
49
|
+
|
50
|
+
oos.writeObject(t);
|
51
|
+
oos.writeObject(new Date());
|
52
|
+
oos.close();
|
53
|
+
}
|
54
|
+
|
55
|
+
catch (Throwable x)
|
56
|
+
{
|
57
|
+
System.err.println(x);
|
58
|
+
}
|
59
|
+
|
60
|
+
System.exit(0);
|
61
|
+
}
|
62
|
+
}
|
data/test/Test2.java
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
import java.io.*;
|
2
|
+
import java.util.Date;
|
3
|
+
import java.util.Calendar;
|
4
|
+
import java.util.HashMap;
|
5
|
+
import java.util.Map;
|
6
|
+
|
7
|
+
public class Test2 implements Serializable
|
8
|
+
{
|
9
|
+
Map map;
|
10
|
+
public void setMap(Map m) { map = m; }
|
11
|
+
|
12
|
+
public static void main(String args[])
|
13
|
+
{
|
14
|
+
Test2 t = new Test2();
|
15
|
+
t.map = new HashMap();
|
16
|
+
t.map.put("One", new Integer(1));
|
17
|
+
t.map.put("Two", new Integer(2));
|
18
|
+
t.map.put("Three", new Integer(3));
|
19
|
+
t.map.put("Four", new Integer(4));
|
20
|
+
t.map.put("Five", new Integer(5));
|
21
|
+
t.map.put("Six", new Integer(6));
|
22
|
+
t.map.put("Seven", new Integer(7));
|
23
|
+
|
24
|
+
try
|
25
|
+
{
|
26
|
+
FileOutputStream fos = new FileOutputStream("t2.tmp");
|
27
|
+
ObjectOutputStream oos = new ObjectOutputStream(fos);
|
28
|
+
|
29
|
+
oos.writeObject(t);
|
30
|
+
oos.close();
|
31
|
+
}
|
32
|
+
|
33
|
+
catch (Throwable x)
|
34
|
+
{
|
35
|
+
System.err.println(x);
|
36
|
+
}
|
37
|
+
|
38
|
+
System.exit(0);
|
39
|
+
}
|
40
|
+
}
|
data/test/test.rb
ADDED
@@ -0,0 +1,111 @@
|
|
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
|
+
system("javac #{$testdir}/Test2.java")
|
14
|
+
system("java -classpath #{$testdir} Test2")
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
File.unlink('t.tmp') rescue nil
|
19
|
+
File.unlink('t2.tmp') rescue nil
|
20
|
+
File.unlink('t.tmp.new') rescue nil
|
21
|
+
File.unlink("#{$testdir}/Test.class") rescue nil
|
22
|
+
File.unlink("#{$testdir}/Test2.class") rescue nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_read
|
26
|
+
orig = ''
|
27
|
+
objs = nil
|
28
|
+
File.open("t.tmp") do |f|
|
29
|
+
f.binmode
|
30
|
+
|
31
|
+
orig = f.read
|
32
|
+
f.seek(0)
|
33
|
+
|
34
|
+
os = Java::ObjectInputStream.new(f)
|
35
|
+
assert os
|
36
|
+
objs = os.readObjects
|
37
|
+
assert objs
|
38
|
+
end
|
39
|
+
|
40
|
+
obj1, obj2 = objs
|
41
|
+
assert_equal obj1.a, 1
|
42
|
+
assert_equal obj1.b, 2
|
43
|
+
assert_equal obj1.c, 1000000000000000
|
44
|
+
assert_equal obj1.d, "Hello"
|
45
|
+
obj1.e.each_with_index { |v, i| assert_equal v, i }
|
46
|
+
assert_kind_of Java::Util::Date, obj1.date
|
47
|
+
assert_equal obj1.date, Time.local(2006, 06, 05, 13, 20, 0)
|
48
|
+
|
49
|
+
assert_equal obj2.class, Java::Util::Date
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_read_map
|
53
|
+
orig = ''
|
54
|
+
objs = nil
|
55
|
+
File.open("t2.tmp") do |f|
|
56
|
+
f.binmode
|
57
|
+
|
58
|
+
orig = f.read
|
59
|
+
f.seek(0)
|
60
|
+
|
61
|
+
os = Java::ObjectInputStream.new(f)
|
62
|
+
assert os
|
63
|
+
objs = os.readObjects
|
64
|
+
assert objs
|
65
|
+
end
|
66
|
+
|
67
|
+
obj1, = objs
|
68
|
+
map = obj1.map
|
69
|
+
assert_equal ["Five", "Four", "One", "Seven", "Six", "Three", "Two"], map.keys.sort
|
70
|
+
{"One" => 1, "Two" => 2, "Three" => 3, "Four" => 4,
|
71
|
+
"Five" => 5, "Six" => 6, "Seven" => 7}.each do |k, v|
|
72
|
+
assert_equal v, map[k].value
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_write
|
77
|
+
orig = ''
|
78
|
+
objs = nil
|
79
|
+
File.open("t.tmp") do |f|
|
80
|
+
f.binmode
|
81
|
+
|
82
|
+
orig = f.read
|
83
|
+
f.seek(0)
|
84
|
+
|
85
|
+
os = Java::ObjectInputStream.new(f)
|
86
|
+
assert os
|
87
|
+
objs = os.readObjects
|
88
|
+
assert objs
|
89
|
+
end
|
90
|
+
|
91
|
+
File.open('t.tmp.new', 'w') do |f|
|
92
|
+
f.binmode
|
93
|
+
|
94
|
+
os = Java::ObjectOutputStream.new(f)
|
95
|
+
os.writeObjects(objs)
|
96
|
+
end
|
97
|
+
|
98
|
+
mine = File.open('t.tmp.new').read
|
99
|
+
assert_equal mine, orig
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
if $0 == __FILE__
|
105
|
+
suite = Test::Unit::TestSuite.new('DataSource')
|
106
|
+
ObjectSpace.each_object(Class) do |klass|
|
107
|
+
suite << klass.suite if (Test::Unit::TestCase > klass)
|
108
|
+
end
|
109
|
+
require 'test/unit/ui/console/testrunner'
|
110
|
+
Test::Unit::UI::Console::TestRunner.run(suite).passed?
|
111
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
!ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: javaobjs
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.3"
|
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/CVS
|
34
|
+
- lib/javaobs.rb
|
35
|
+
- lib/CVS/Entries
|
36
|
+
- lib/CVS/Repository
|
37
|
+
- lib/CVS/Root
|
38
|
+
- test/CVS
|
39
|
+
- test/Test.java
|
40
|
+
- test/test.rb
|
41
|
+
- test/Test2.java
|
42
|
+
- test/CVS/Entries
|
43
|
+
- test/CVS/Repository
|
44
|
+
- test/CVS/Root
|
45
|
+
test_files: []
|
46
|
+
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
extra_rdoc_files: []
|
50
|
+
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
requirements:
|
56
|
+
- none
|
57
|
+
dependencies: []
|
58
|
+
|