javaobjs 0.3
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/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
|
+
|