diff --git a/.gitignore b/.gitignore index d468f44f..4d54c87c 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ tmp /nbproject/private/ ext/java/build ext/java/msgpack.jar +lib/msgpack/msgpack.jar diff --git a/Rakefile b/Rakefile index aab72f0d..7b9b32d8 100644 --- a/Rakefile +++ b/Rakefile @@ -8,13 +8,6 @@ require 'rspec/core' require 'rspec/core/rake_task' require 'yard' -RSpec::Core::RakeTask.new(:spec) do |t| - t.rspec_opts = ["-c", "-f progress"] - t.rspec_opts << "-Ilib" - t.pattern = 'spec/**/*_spec.rb' - t.verbose = true -end - task :spec => :compile desc 'Run RSpec code examples and measure coverage' @@ -37,21 +30,37 @@ if RUBY_PLATFORM =~ /java/ Rake::JavaExtensionTask.new('msgpack', spec) do |ext| ext.ext_dir = 'ext/java' - #jruby_home = RbConfig::CONFIG['prefix'] - #jars = ["#{jruby_home}/lib/jruby.jar"] + FileList['lib/*.jar'] - #ext.classpath = jars.map { |x| File.expand_path x }.join ':' + ext.lib_dir = File.join(*['lib', 'msgpack', ENV['FAT_DIR']].compact) + ext.classpath = Dir['lib/msgpack/java/*.jar'].map { |x| File.expand_path x }.join ':' + end + + RSpec::Core::RakeTask.new(:spec) do |t| + t.rspec_opts = ["-c", "-f progress"] + t.rspec_opts << "-Ilib" + t.pattern = 'spec/{,jruby/}*_spec.rb' + t.verbose = true end else require 'rake/extensiontask' Rake::ExtensionTask.new('msgpack', spec) do |ext| + ext.ext_dir = 'ext/msgpack' ext.cross_compile = true ext.lib_dir = File.join(*['lib', 'msgpack', ENV['FAT_DIR']].compact) #ext.cross_platform = 'i386-mswin32' end + + RSpec::Core::RakeTask.new(:spec) do |t| + t.rspec_opts = ["-c", "-f progress"] + t.rspec_opts << "-Ilib" + t.pattern = 'spec/{,cruby/}*_spec.rb' + t.verbose = true + end end +CLEAN.include('lib/msgpack/msgpack.*') + task :default => [:spec, :build, :doc] diff --git a/ext/java/MsgpackJrubyService.java b/ext/java/MsgpackJrubyService.java new file mode 100644 index 00000000..ca331ec4 --- /dev/null +++ b/ext/java/MsgpackJrubyService.java @@ -0,0 +1,15 @@ +import java.io.IOException; + +import org.jruby.Ruby; +import org.jruby.runtime.load.BasicLibraryService; + +import org.msgpack.jruby.MessagePackLibrary; + + +public class MsgpackJrubyService implements BasicLibraryService { + public boolean basicLoad(final Ruby runtime) throws IOException { + new MessagePackLibrary().load(runtime, false); + return true; + } +} + diff --git a/ext/java/org/msgpack/jruby/MessagePackLibrary.java b/ext/java/org/msgpack/jruby/MessagePackLibrary.java new file mode 100644 index 00000000..79233279 --- /dev/null +++ b/ext/java/org/msgpack/jruby/MessagePackLibrary.java @@ -0,0 +1,245 @@ +package org.msgpack.jruby; + + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.jruby.Ruby; +import org.jruby.RubyModule; +import org.jruby.RubyClass; +import org.jruby.RubyString; +import org.jruby.RubyObject; +import org.jruby.RubyHash; +import org.jruby.RubyIO; +import org.jruby.RubyStringIO; +import org.jruby.RubyNumeric; +import org.jruby.RubyEnumerator; +import org.jruby.runtime.load.Library; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.Arity; +import org.jruby.runtime.Block; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyModule; +import org.jruby.anno.JRubyMethod; +import org.jruby.util.IOInputStream; + +import static org.jruby.runtime.Visibility.*; + +import org.msgpack.MessagePack; +import org.msgpack.packer.BufferPacker; +import org.msgpack.packer.Packer; +import org.msgpack.unpacker.MessagePackBufferUnpacker; +import org.msgpack.unpacker.MessagePackUnpacker; +import org.msgpack.unpacker.UnpackerIterator; +import org.msgpack.type.Value; +import org.msgpack.io.Input; +import org.msgpack.io.LinkedBufferInput; +import org.msgpack.io.StreamInput; + + +public class MessagePackLibrary implements Library { + public void load(Ruby runtime, boolean wrap) throws IOException { + MessagePack msgPack = new MessagePack(); + RubyModule msgpackModule = runtime.defineModule("MessagePack"); + msgpackModule.defineAnnotatedMethods(MessagePackModule.class); + RubyClass standardErrorClass = runtime.getStandardError(); + RubyClass unpackErrorClass = msgpackModule.defineClassUnder("UnpackError", standardErrorClass, standardErrorClass.getAllocator()); + RubyClass unpackerClass = msgpackModule.defineClassUnder("Unpacker", runtime.getObject(), new UnpackerAllocator(msgPack)); + unpackerClass.defineAnnotatedMethods(Unpacker.class); + } + + @JRubyModule(name = "MessagePack") + public static class MessagePackModule { + private static MessagePack msgPack = new MessagePack(); + private static RubyObjectPacker packer = new RubyObjectPacker(msgPack); + private static RubyObjectUnpacker unpacker = new RubyObjectUnpacker(msgPack); + + @JRubyMethod(module = true, required = 1, optional = 1, alias = {"dump"}) + public static IRubyObject pack(ThreadContext ctx, IRubyObject recv, IRubyObject[] args) throws IOException { + RubyHash options = (args.length == 2) ? (RubyHash) args[1] : null; + return packer.pack(args[0], options); + } + + @JRubyMethod(module = true, required = 1, optional = 1, alias = {"load"}) + public static IRubyObject unpack(ThreadContext ctx, IRubyObject recv, IRubyObject[] args) throws IOException { + RubyHash options = (args.length == 2) ? (RubyHash) args[1] : null; + RubyString str = args[0].asString(); + return unpacker.unpack(str, options); + } + } + + private static class UnpackerAllocator implements ObjectAllocator { + private MessagePack msgPack; + + public UnpackerAllocator(MessagePack msgPack) { + this.msgPack = msgPack; + } + + public IRubyObject allocate(Ruby runtime, RubyClass klass) { + return new Unpacker(runtime, klass, msgPack); + } + } + + @JRubyClass(name="MessagePack::Unpacker") + public static class Unpacker extends RubyObject { + private MessagePack msgPack; + private RubyObjectUnpacker rubyObjectUnpacker; + private MessagePackBufferUnpacker bufferUnpacker; + private MessagePackUnpacker streamUnpacker; + private UnpackerIterator unpackerIterator; + private IRubyObject stream; + private IRubyObject data; + private RubyObjectUnpacker.CompiledOptions options; + + public Unpacker(Ruby runtime, RubyClass type, MessagePack msgPack) { + super(runtime, type); + this.msgPack = msgPack; + this.rubyObjectUnpacker = new RubyObjectUnpacker(msgPack); + this.bufferUnpacker = null; + this.streamUnpacker = null; + this.stream = null; + this.data = null; + } + + @JRubyMethod(name = "initialize", optional = 2, visibility = PRIVATE) + public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) { + if (args.length == 0) { + options = new RubyObjectUnpacker.CompiledOptions(ctx.getRuntime()); + } else if (args.length == 1 && args[0] instanceof RubyHash) { + options = new RubyObjectUnpacker.CompiledOptions(ctx.getRuntime(), (RubyHash) args[0]); + } else if (args.length > 0) { + setStream(ctx, args[0]); + if (args.length > 2) { + options = new RubyObjectUnpacker.CompiledOptions(ctx.getRuntime(), (RubyHash) args[1]); + } else { + options = new RubyObjectUnpacker.CompiledOptions(ctx.getRuntime()); + } + } + return this; + } + + @JRubyMethod(required = 2) + public IRubyObject execute(ThreadContext ctx, IRubyObject data, IRubyObject offset) { + return executeLimit(ctx, data, offset, null); + } + + @JRubyMethod(name = "execute_limit", required = 3) + public IRubyObject executeLimit(ThreadContext ctx, IRubyObject data, IRubyObject offset, IRubyObject limit) { + this.data = null; + try { + int jOffset = RubyNumeric.fix2int(offset); + int jLimit = -1; + if (limit != null) { + jLimit = RubyNumeric.fix2int(limit); + } + byte[] bytes = data.asString().getBytes(); + MessagePackBufferUnpacker localBufferUnpacker = new MessagePackBufferUnpacker(msgPack, bytes.length); + localBufferUnpacker.wrap(bytes, jOffset, jLimit == -1 ? bytes.length - jOffset : jLimit); + this.data = rubyObjectUnpacker.valueToRubyObject(ctx.getRuntime(), localBufferUnpacker.readValue(), options); + return ctx.getRuntime().newFixnum(jOffset + localBufferUnpacker.getReadByteCount()); + } catch (IOException ioe) { + // TODO: how to throw Ruby exceptions? + return ctx.getRuntime().getNil(); + } + } + + @JRubyMethod(name = "data") + public IRubyObject getData(ThreadContext ctx) { + if (data == null) { + return ctx.getRuntime().getNil(); + } else { + return data; + } + } + + @JRubyMethod(name = "finished?") + public IRubyObject finished_q(ThreadContext ctx) { + return data == null ? ctx.getRuntime().getFalse() : ctx.getRuntime().getTrue(); + } + + @JRubyMethod(required = 1) + public IRubyObject feed(ThreadContext ctx, IRubyObject data) { + streamUnpacker = null; + byte[] bytes = data.asString().getBytes(); + if (bufferUnpacker == null) { + bufferUnpacker = new MessagePackBufferUnpacker(msgPack); + unpackerIterator = bufferUnpacker.iterator(); + } + bufferUnpacker.feed(bytes); + return ctx.getRuntime().getNil(); + } + + @JRubyMethod(name = "feed_each", required = 1) + public IRubyObject feedEach(ThreadContext ctx, IRubyObject data, Block block) { + feed(ctx, data); + each(ctx, block); + return ctx.getRuntime().getNil(); + } + + @JRubyMethod + public IRubyObject each(ThreadContext ctx, Block block) { + MessagePackUnpacker localUnpacker = null; + if (bufferUnpacker == null && streamUnpacker != null) { + localUnpacker = streamUnpacker; + } else if (bufferUnpacker != null) { + localUnpacker = bufferUnpacker; + } else { + return ctx.getRuntime().getNil(); + } + if (block.isGiven()) { + while (unpackerIterator.hasNext()) { + Value value = unpackerIterator.next(); + IRubyObject rubyObject = rubyObjectUnpacker.valueToRubyObject(ctx.getRuntime(), value, options); + block.yield(ctx, rubyObject); + } + return ctx.getRuntime().getNil(); + } else { + return callMethod(ctx, "to_enum"); + } + } + + @JRubyMethod + public IRubyObject fill(ThreadContext ctx) { + return ctx.getRuntime().getNil(); + } + + @JRubyMethod + public IRubyObject reset(ThreadContext ctx) { + if (bufferUnpacker != null) { + bufferUnpacker.reset(); + } + if (streamUnpacker != null) { + streamUnpacker.reset(); + } + return ctx.getRuntime().getNil(); + } + + @JRubyMethod(name = "stream") + public IRubyObject getStream(ThreadContext ctx) { + if (stream == null) { + return ctx.getRuntime().getNil(); + } else { + return stream; + } + } + + @JRubyMethod(name = "stream=", required = 1) + public IRubyObject setStream(ThreadContext ctx, IRubyObject stream) { + bufferUnpacker = null; + this.stream = stream; + if (stream instanceof RubyStringIO) { + // TODO: RubyStringIO returns negative numbers when read through IOInputStream#read + IRubyObject str = ((RubyStringIO) stream).string(); + byte[] bytes = ((RubyString) str).getBytes(); + streamUnpacker = new MessagePackUnpacker(msgPack, new ByteArrayInputStream(bytes)); + } else { + streamUnpacker = new MessagePackUnpacker(msgPack, new IOInputStream(stream)); + } + unpackerIterator = streamUnpacker.iterator(); + return getStream(ctx); + } + } +} diff --git a/ext/java/org/msgpack/jruby/RubyObjectPacker.java b/ext/java/org/msgpack/jruby/RubyObjectPacker.java new file mode 100644 index 00000000..7944903c --- /dev/null +++ b/ext/java/org/msgpack/jruby/RubyObjectPacker.java @@ -0,0 +1,153 @@ +package org.msgpack.jruby; + + +import java.io.IOException; + +import org.jcodings.Encoding; + +import org.msgpack.MessagePack; +import org.msgpack.packer.BufferPacker; + +import org.jruby.Ruby; +import org.jruby.RubyObject; +import org.jruby.RubyNil; +import org.jruby.RubyBoolean; +import org.jruby.RubyBignum; +import org.jruby.RubyInteger; +import org.jruby.RubyFixnum; +import org.jruby.RubyFloat; +import org.jruby.RubyString; +import org.jruby.RubySymbol; +import org.jruby.RubyArray; +import org.jruby.RubyHash; +import org.jruby.RubyEncoding; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.encoding.EncodingService; + + +public class RubyObjectPacker { + private final MessagePack msgPack; + + public RubyObjectPacker(MessagePack msgPack) { + this.msgPack = msgPack; + } + + static class CompiledOptions { + public final Encoding encoding; + + public CompiledOptions(Ruby runtime, RubyHash options) { + EncodingService encodingService = runtime.getEncodingService(); + Encoding externalEncoding = null; + if (options != null) { + IRubyObject rubyEncoding = options.fastARef(runtime.newSymbol("encoding")); + externalEncoding = encodingService.getEncodingFromObject(rubyEncoding); + } + if (externalEncoding == null) { + externalEncoding = runtime.getDefaultExternalEncoding(); + } + encoding = (externalEncoding != encodingService.getAscii8bitEncoding()) ? externalEncoding : null; + } + } + + public RubyString pack(IRubyObject o, RubyHash options) throws IOException { + return RubyString.newStringNoCopy(o.getRuntime(), packRaw(o, new CompiledOptions(o.getRuntime(), options))); + } + + @Deprecated + public byte[] packRaw(IRubyObject o) throws IOException { + if (o == null) { + return new byte[] { -64 }; + } else { + return packRaw(o.getRuntime(), o); + } + } + + public byte[] packRaw(Ruby runtime, IRubyObject o) throws IOException { + return packRaw(runtime, o, null); + } + + public byte[] packRaw(Ruby runtime, IRubyObject o, RubyHash options) throws IOException { + return packRaw(o, new CompiledOptions(runtime, options)); + } + + byte[] packRaw(IRubyObject o, CompiledOptions options) throws IOException { + BufferPacker packer = msgPack.createBufferPacker(); + write(packer, o, options); + return packer.toByteArray(); + } + + private void write(BufferPacker packer, IRubyObject o, CompiledOptions options) throws IOException { + if (o == null || o instanceof RubyNil) { + packer.writeNil(); + } else if (o instanceof RubyBoolean) { + packer.write(((RubyBoolean) o).isTrue()); + } else if (o instanceof RubyBignum) { + write(packer, (RubyBignum) o); + } else if (o instanceof RubyInteger) { + write(packer, (RubyInteger) o); + } else if (o instanceof RubyFixnum) { + write(packer, (RubyFixnum) o); + } else if (o instanceof RubyFloat) { + write(packer, (RubyFloat) o); + } else if (o instanceof RubyString) { + write(packer, (RubyString) o, options); + } else if (o instanceof RubySymbol) { + write(packer, (RubySymbol) o, options); + } else if (o instanceof RubyArray) { + write(packer, (RubyArray) o, options); + } else if (o instanceof RubyHash) { + write(packer, (RubyHash) o, options); + } else { + throw o.getRuntime().newArgumentError(String.format("Cannot pack type: %s", o.getClass().getName())); + } + } + + private void write(BufferPacker packer, RubyBignum bignum) throws IOException { + packer.write(bignum.getBigIntegerValue()); + } + + private void write(BufferPacker packer, RubyInteger integer) throws IOException { + packer.write(integer.getLongValue()); + } + + private void write(BufferPacker packer, RubyFixnum fixnum) throws IOException { + packer.write(fixnum.getLongValue()); + } + + private void write(BufferPacker packer, RubyFloat flt) throws IOException { + packer.write(flt.getDoubleValue()); + } + + private void write(BufferPacker packer, RubyString str, CompiledOptions options) throws IOException { + if ((options.encoding != null) && (str.getEncoding() != options.encoding)) { + Ruby runtime = str.getRuntime(); + str = (RubyString) str.encode(runtime.getCurrentContext(), RubyEncoding.newEncoding(runtime, options.encoding)); + } + packer.write(str.getBytes()); + } + + private void write(BufferPacker packer, RubySymbol sym, CompiledOptions options) throws IOException { + write(packer, sym.asString(), options); + } + + private void write(BufferPacker packer, RubyArray array, CompiledOptions options) throws IOException { + int count = array.size(); + packer.writeArrayBegin(count); + for (int i = 0; i < count; i++) { + write(packer, (RubyObject) array.entry(i), options); + } + packer.writeArrayEnd(); + } + + private void write(BufferPacker packer, RubyHash hash, CompiledOptions options) throws IOException { + int count = hash.size(); + packer.writeMapBegin(count); + RubyArray keys = hash.keys(); + RubyArray values = hash.rb_values(); + for (int i = 0; i < count; i++) { + write(packer, (RubyObject) keys.entry(i), options); + write(packer, (RubyObject) values.entry(i), options); + } + packer.writeMapEnd(); + } +} diff --git a/ext/java/org/msgpack/jruby/RubyObjectUnpacker.java b/ext/java/org/msgpack/jruby/RubyObjectUnpacker.java new file mode 100644 index 00000000..30d8478f --- /dev/null +++ b/ext/java/org/msgpack/jruby/RubyObjectUnpacker.java @@ -0,0 +1,163 @@ +package org.msgpack.jruby; + + +import java.io.IOException; + +import org.msgpack.MessagePack; +import org.msgpack.MessageTypeException; +import org.msgpack.unpacker.MessagePackBufferUnpacker; +import org.msgpack.type.Value; +import org.msgpack.type.ValueType; +import org.msgpack.type.BooleanValue; +import org.msgpack.type.IntegerValue; +import org.msgpack.type.FloatValue; +import org.msgpack.type.ArrayValue; +import org.msgpack.type.MapValue; +import org.msgpack.type.RawValue; + +import org.jruby.Ruby; +import org.jruby.RubyObject; +import org.jruby.RubyNil; +import org.jruby.RubyBoolean; +import org.jruby.RubyBignum; +import org.jruby.RubyInteger; +import org.jruby.RubyFixnum; +import org.jruby.RubyFloat; +import org.jruby.RubyString; +import org.jruby.RubySymbol; +import org.jruby.RubyArray; +import org.jruby.RubyHash; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.encoding.EncodingService; +import org.jruby.runtime.ThreadContext; + +import org.jcodings.Encoding; + + +public class RubyObjectUnpacker { + private final MessagePack msgPack; + + public RubyObjectUnpacker(MessagePack msgPack) { + this.msgPack = msgPack; + } + + static class CompiledOptions { + public final boolean symbolizeKeys; + public final Encoding encoding; + + public CompiledOptions(Ruby runtime) { + this(runtime, null); + } + + public CompiledOptions(Ruby runtime, RubyHash options) { + EncodingService encodingService = runtime.getEncodingService(); + Encoding externalEncoding = null; + if (options == null) { + symbolizeKeys = false; + } else { + ThreadContext ctx = runtime.getCurrentContext(); + RubySymbol key = runtime.newSymbol("symbolize_keys"); + IRubyObject value = options.fastARef(key); + symbolizeKeys = value != null && value.isTrue(); + IRubyObject rubyEncoding = options.fastARef(runtime.newSymbol("encoding")); + externalEncoding = encodingService.getEncodingFromObject(rubyEncoding); + } + encoding = (externalEncoding != null) ? externalEncoding : runtime.getDefaultExternalEncoding(); + } + } + + public IRubyObject unpack(RubyString str, RubyHash options) throws IOException { + return unpack(str.getRuntime(), str.getBytes(), new CompiledOptions(str.getRuntime(), options)); + } + + public IRubyObject unpack(Ruby runtime, byte[] data) throws IOException { + return unpack(runtime, data, new CompiledOptions(runtime, null)); + } + + public IRubyObject unpack(Ruby runtime, byte[] data, RubyHash options) throws IOException { + return unpack(runtime, data, new CompiledOptions(runtime, options)); + } + + IRubyObject unpack(Ruby runtime, byte[] data, CompiledOptions options) throws IOException { + MessagePackBufferUnpacker unpacker = new MessagePackBufferUnpacker(msgPack); + unpacker.wrap(data); + return valueToRubyObject(runtime, unpacker.readValue(), options); + } + + IRubyObject valueToRubyObject(Ruby runtime, Value value, RubyHash options) throws IOException { + return valueToRubyObject(runtime, value, new CompiledOptions(runtime, options)); + } + + IRubyObject valueToRubyObject(Ruby runtime, Value value, CompiledOptions options) { + switch (value.getType()) { + case NIL: + return runtime.getNil(); + case BOOLEAN: + return convert(runtime, value.asBooleanValue()); + case INTEGER: + return convert(runtime, value.asIntegerValue()); + case FLOAT: + return convert(runtime, value.asFloatValue()); + case ARRAY: + return convert(runtime, value.asArrayValue(), options); + case MAP: + return convert(runtime, value.asMapValue(), options); + case RAW: + return convert(runtime, value.asRawValue(), options); + default: + throw runtime.newArgumentError(String.format("Unexpected value: %s", value.toString())); + } + } + + private IRubyObject convert(Ruby runtime, BooleanValue value) { + return RubyBoolean.newBoolean(runtime, value.asBooleanValue().getBoolean()); + } + + private IRubyObject convert(Ruby runtime, IntegerValue value) { + // TODO: is there any way of checking for bignums up front? + IntegerValue iv = value.asIntegerValue(); + try { + return RubyFixnum.newFixnum(runtime, iv.getLong()); + } catch (MessageTypeException mte) { + return RubyBignum.newBignum(runtime, iv.getBigInteger()); + } + } + + private IRubyObject convert(Ruby runtime, FloatValue value) { + return RubyFloat.newFloat(runtime, value.asFloatValue().getDouble()); + } + + private IRubyObject convert(Ruby runtime, ArrayValue value, CompiledOptions options) { + Value[] elements = value.asArrayValue().getElementArray(); + int elementCount = elements.length; + IRubyObject[] rubyObjects = new IRubyObject[elementCount]; + for (int i = 0; i < elementCount; i++) { + rubyObjects[i] = valueToRubyObject(runtime, elements[i], options); + } + return RubyArray.newArray(runtime, rubyObjects); + } + + private IRubyObject convert(Ruby runtime, MapValue value, CompiledOptions options) { + Value[] keysAndValues = value.asMapValue().getKeyValueArray(); + int kvCount = keysAndValues.length; + RubyHash hash = RubyHash.newHash(runtime); + for (int i = 0; i < kvCount; i += 2) { + Value k = keysAndValues[i]; + Value v = keysAndValues[i + 1]; + IRubyObject kk = valueToRubyObject(runtime, k, options); + IRubyObject vv = valueToRubyObject(runtime, v, options); + if (options.symbolizeKeys) { + kk = runtime.newSymbol(kk.asString().getByteList()); + } + hash.put(kk, vv); + } + return hash; + } + + private IRubyObject convert(Ruby runtime, RawValue value, CompiledOptions options) { + RubyString string = RubyString.newStringNoCopy(runtime, value.getByteArray()); + string.setEncoding(options.encoding); + string.callMethod(runtime.getCurrentContext(), "encode!"); + return string; + } +} diff --git a/lib/msgpack.rb b/lib/msgpack.rb index 6e6e7839..ff0d4f7e 100644 --- a/lib/msgpack.rb +++ b/lib/msgpack.rb @@ -1,4 +1,9 @@ require "msgpack/version" +if RUBY_PLATFORM =~ /java/ + require 'java' + require 'msgpack/java/javassist-3.15.0-GA' + require 'msgpack/java/msgpack-0.6.6' +end begin require "msgpack/#{RUBY_VERSION[/\d+.\d+/]}/msgpack" rescue LoadError diff --git a/lib/msgpack/java/javassist-3.15.0-GA.jar b/lib/msgpack/java/javassist-3.15.0-GA.jar new file mode 100644 index 00000000..5af8eaeb Binary files /dev/null and b/lib/msgpack/java/javassist-3.15.0-GA.jar differ diff --git a/lib/msgpack/java/msgpack-0.6.6.jar b/lib/msgpack/java/msgpack-0.6.6.jar new file mode 100644 index 00000000..1b87fdf9 Binary files /dev/null and b/lib/msgpack/java/msgpack-0.6.6.jar differ diff --git a/msgpack.gemspec b/msgpack.gemspec index ae740fc6..decf496d 100644 --- a/msgpack.gemspec +++ b/msgpack.gemspec @@ -17,6 +17,13 @@ Gem::Specification.new do |s| s.require_paths = ["lib"] s.extensions = ["ext/msgpack/extconf.rb"] + jars = Dir['lib/**/*.jar'] + if RUBY_PLATFORM =~ /java/ + s.files += jars + else + s.files -= jars + end + s.add_development_dependency 'bundler', ['~> 1.0'] s.add_development_dependency 'rake', ['~> 0.9.2'] s.add_development_dependency 'rake-compiler', ['~> 0.8.3']