msgpack-jruby 1.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/.rspec +3 -0
- data/.rvmrc +1 -0
- data/Gemfile +11 -0
- data/Rakefile +22 -0
- data/ext/java/org/msgpack/jruby/MessagePack.java +156 -0
- data/lib/ext/msgpack-0.5.2-devel.jar +0 -0
- data/lib/ext/org/msgpack/jruby/MessagePack.class +0 -0
- data/lib/msgpack.rb +7 -0
- data/lib/msgpack/version.rb +3 -0
- data/msgpack-jruby.gemspec +24 -0
- data/spec/benchmark.rb +67 -0
- data/spec/msgpack_spec.rb +76 -0
- data/spec/spec_helper.rb +3 -0
- metadata +76 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm --create use jruby-1.6.2@msgpack-jruby
|
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
|
3
|
+
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
task :clean do
|
7
|
+
rm Dir['lib/ext/**/*.class']
|
8
|
+
end
|
9
|
+
|
10
|
+
task :compile do
|
11
|
+
exec %(javac -source 1.6 -target 1.6 -cp lib/ext/msgpack-0.5.2-devel.jar:$MY_RUBY_HOME/lib/jruby.jar -d lib/ext ext/java/org/msgpack/**/*.java)
|
12
|
+
end
|
13
|
+
|
14
|
+
BENCHMARK_RUBIES = ['1.9.2-p290', 'jruby-1.6.2', 'jruby-1.6.4']
|
15
|
+
BENCHMARK_GEMSET = 'msgpack-jruby-benchmarking'
|
16
|
+
|
17
|
+
task :benchmark do
|
18
|
+
rubies = BENCHMARK_RUBIES.map { |rb| "#{rb}@#{BENCHMARK_GEMSET}" }
|
19
|
+
cmd = %(rvm #{rubies.join(',')} exec viiite run spec/benchmark.rb | tee benchmark | viiite report --hierarchy --regroup=bench,ruby)
|
20
|
+
puts cmd
|
21
|
+
system cmd
|
22
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
package org.msgpack.jruby;
|
2
|
+
|
3
|
+
|
4
|
+
import java.io.IOException;
|
5
|
+
import java.io.ByteArrayOutputStream;
|
6
|
+
import java.math.BigInteger;
|
7
|
+
import java.util.Map;
|
8
|
+
import java.util.HashMap;
|
9
|
+
import java.lang.reflect.Field;
|
10
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
11
|
+
import org.jruby.Ruby;
|
12
|
+
import org.jruby.RubyObject;
|
13
|
+
import org.jruby.RubyString;
|
14
|
+
import org.jruby.RubySymbol;
|
15
|
+
import org.jruby.RubyArray;
|
16
|
+
import org.jruby.RubyHash;
|
17
|
+
import org.jruby.RubyBoolean;
|
18
|
+
import org.jruby.RubyInteger;
|
19
|
+
import org.jruby.RubyFixnum;
|
20
|
+
import org.jruby.RubyFloat;
|
21
|
+
import org.jruby.RubyBignum;
|
22
|
+
import org.jruby.RubyNil;
|
23
|
+
import org.msgpack.Packer;
|
24
|
+
import org.msgpack.Unpacker;
|
25
|
+
import org.msgpack.MessagePackObject;
|
26
|
+
import org.msgpack.MessageTypeException;
|
27
|
+
import org.msgpack.object.MapType;
|
28
|
+
|
29
|
+
|
30
|
+
public class MessagePack {
|
31
|
+
private static final MessagePack instance = new MessagePack();
|
32
|
+
|
33
|
+
public static RubyString pack(RubyObject o) throws IOException {
|
34
|
+
return instance.packObject(o);
|
35
|
+
}
|
36
|
+
|
37
|
+
public static RubyObject unpack(RubyString s) throws IOException {
|
38
|
+
return instance.unpackString(s);
|
39
|
+
}
|
40
|
+
|
41
|
+
public RubyString packObject(IRubyObject o) throws IOException {
|
42
|
+
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
43
|
+
_pack(o, new Packer(stream));
|
44
|
+
Ruby runtime = o == null ? Ruby.getGlobalRuntime() : o.getRuntime();
|
45
|
+
return RubyString.newString(runtime, stream.toByteArray());
|
46
|
+
}
|
47
|
+
|
48
|
+
private void _pack(IRubyObject o, Packer packer) throws IOException {
|
49
|
+
if (o == null || o instanceof RubyNil) {
|
50
|
+
packer.packNil();
|
51
|
+
} else if (o instanceof RubyBoolean) {
|
52
|
+
packer.packBoolean((Boolean) ((RubyBoolean) o).toJava(Boolean.class));
|
53
|
+
} else if (o instanceof RubyBignum) {
|
54
|
+
packer.packBigInteger(((RubyBignum) o).getBigIntegerValue());
|
55
|
+
} else if (o instanceof RubyInteger) {
|
56
|
+
packer.packLong(((RubyInteger) o).getLongValue());
|
57
|
+
} else if (o instanceof RubyFixnum) {
|
58
|
+
packer.packLong(((RubyFixnum) o).getLongValue());
|
59
|
+
} else if (o instanceof RubyFloat) {
|
60
|
+
packer.packDouble(((RubyFloat) o).getDoubleValue());
|
61
|
+
} else if (o instanceof RubyString) {
|
62
|
+
byte[] bytes = ((RubyString) o).getBytes();
|
63
|
+
packer.packRaw(bytes.length);
|
64
|
+
packer.packRawBody(bytes);
|
65
|
+
} else if (o instanceof RubySymbol) {
|
66
|
+
_pack((IRubyObject) ((RubySymbol) o).to_s(), packer);
|
67
|
+
} else if (o instanceof RubyArray) {
|
68
|
+
RubyArray array = (RubyArray) o;
|
69
|
+
int count = array.size();
|
70
|
+
packer.packArray(count);
|
71
|
+
for (int i = 0; i < count; i++) {
|
72
|
+
_pack(array.entry(i), packer);
|
73
|
+
}
|
74
|
+
} else if (o instanceof RubyHash) {
|
75
|
+
RubyHash hash = (RubyHash) o;
|
76
|
+
int count = hash.size();
|
77
|
+
packer.packMap(count);
|
78
|
+
RubyArray keys = hash.keys();
|
79
|
+
RubyArray values = hash.rb_values();
|
80
|
+
for (int i = 0; i < count; i++) {
|
81
|
+
_pack(keys.entry(i), packer);
|
82
|
+
_pack(values.entry(i), packer);
|
83
|
+
}
|
84
|
+
} else {
|
85
|
+
throw Ruby.getGlobalRuntime().newArgumentError(String.format("Cannot pack type: %s", o.getClass().getName()));
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
public RubyObject unpackString(RubyString blob) throws IOException {
|
90
|
+
RubyObject obj = null;
|
91
|
+
Unpacker unpacker = new Unpacker();
|
92
|
+
unpacker.wrap(blob.getBytes());
|
93
|
+
return _unpack(unpacker.iterator().next(), blob.getRuntime());
|
94
|
+
}
|
95
|
+
|
96
|
+
private static Field cachedMapField = null;
|
97
|
+
|
98
|
+
private RubyObject _unpack(MessagePackObject mpo, Ruby runtime) throws IOException {
|
99
|
+
if (mpo.isNil()) {
|
100
|
+
return null;
|
101
|
+
} else if (mpo.isBooleanType()) {
|
102
|
+
return RubyBoolean.newBoolean(runtime, mpo.asBoolean());
|
103
|
+
} else if (mpo.isIntegerType()) {
|
104
|
+
try {
|
105
|
+
return RubyFixnum.newFixnum(runtime, mpo.asLong());
|
106
|
+
} catch (MessageTypeException mte) {
|
107
|
+
return RubyBignum.newBignum(runtime, mpo.asBigInteger());
|
108
|
+
}
|
109
|
+
} else if (mpo.isFloatType()) {
|
110
|
+
return RubyFloat.newFloat(runtime, mpo.asDouble());
|
111
|
+
} else if (mpo.isArrayType()) {
|
112
|
+
MessagePackObject[] mpoElements = mpo.asArray();
|
113
|
+
RubyObject[] elements = new RubyObject[mpoElements.length];
|
114
|
+
int count = mpoElements.length;
|
115
|
+
for (int i = 0; i < count; i++ ) {
|
116
|
+
elements[i] = _unpack(mpoElements[i], runtime);
|
117
|
+
}
|
118
|
+
return RubyArray.newArray(runtime, elements);
|
119
|
+
} else if (mpo.isMapType()) {
|
120
|
+
// This is hackish, but the only way to make sure that hashes
|
121
|
+
// keep their order. MessagePack's unpacking subsystem does not
|
122
|
+
// expose the key/value pair array, only a Map constructed from
|
123
|
+
// that array. This code first attempts to get that array from a
|
124
|
+
// private field, and if that fails it falls back on using the
|
125
|
+
// unordered Map.
|
126
|
+
RubyHash hash = null;
|
127
|
+
try {
|
128
|
+
if (cachedMapField == null) {
|
129
|
+
cachedMapField = mpo.getClass().getDeclaredField("map");
|
130
|
+
cachedMapField.setAccessible(true);
|
131
|
+
}
|
132
|
+
MessagePackObject[] keyValuePairs = (MessagePackObject[]) cachedMapField.get(mpo);
|
133
|
+
int count = keyValuePairs.length;
|
134
|
+
hash = RubyHash.newHash(runtime);
|
135
|
+
for (int i = 0; i < count; i += 2) {
|
136
|
+
hash.put(_unpack(keyValuePairs[i], runtime), _unpack(keyValuePairs[i + 1], runtime));
|
137
|
+
}
|
138
|
+
} catch (IllegalAccessException iae) {
|
139
|
+
} catch (NoSuchFieldException nfe) {
|
140
|
+
}
|
141
|
+
if (hash == null) {
|
142
|
+
Map<MessagePackObject, MessagePackObject> mpoMap = mpo.asMap();
|
143
|
+
hash = RubyHash.newHash(runtime);
|
144
|
+
for (Map.Entry<MessagePackObject, MessagePackObject> entry : mpoMap.entrySet()) {
|
145
|
+
hash.put(_unpack(entry.getKey(), runtime), _unpack(entry.getValue(), runtime));
|
146
|
+
}
|
147
|
+
}
|
148
|
+
return hash;
|
149
|
+
|
150
|
+
} else if (mpo.isRawType()) {
|
151
|
+
return RubyString.newString(runtime, mpo.asByteArray());
|
152
|
+
} else {
|
153
|
+
throw runtime.newArgumentError(String.format("Cannot upack type: %s", mpo.getClass().getName()));
|
154
|
+
}
|
155
|
+
}
|
156
|
+
}
|
Binary file
|
Binary file
|
data/lib/msgpack.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
$:.push File.expand_path('../lib', __FILE__)
|
4
|
+
|
5
|
+
require 'msgpack/version'
|
6
|
+
|
7
|
+
|
8
|
+
Gem::Specification.new do |s|
|
9
|
+
s.name = 'msgpack-jruby'
|
10
|
+
s.version = MessagePack::VERSION
|
11
|
+
s.platform = 'java'
|
12
|
+
s.authors = ['Theo Hultberg']
|
13
|
+
s.email = ['theo@iconara.net']
|
14
|
+
s.homepage = 'http://github.com/iconara/msgpack-jruby'
|
15
|
+
s.summary = %q{MessagePack implementation for JRuby}
|
16
|
+
s.description = %q{JRuby compatible MessagePack implementation that does not use FFI}
|
17
|
+
|
18
|
+
s.rubyforge_project = 'msgpack-jruby'
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
# s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
# s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = %w(lib)
|
24
|
+
end
|
data/spec/benchmark.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
if RUBY_PLATFORM.include?('java')
|
4
|
+
# JRuby should use this library, MRI should use the standard gem
|
5
|
+
$: << File.expand_path('../../lib', __FILE__)
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'viiite'
|
9
|
+
require 'msgpack'
|
10
|
+
require 'json'
|
11
|
+
require 'bson'
|
12
|
+
|
13
|
+
|
14
|
+
OBJECT_STRUCTURE = {'x' => ['y', 34, 2**30 + 3, 2.1223423423356, {'hello' => 'world', '5' => [63, 'asjdl']}]}
|
15
|
+
ENCODED_MSGPACK = "\x81\xA1x\x95\xA1y\"\xCE@\x00\x00\x03\xCB@\x00\xFA\x8E\x9F9\xFA\xC1\x82\xA5hello\xA5world\xA15\x92?\xA5asjdl"
|
16
|
+
ENCODED_BSON = "d\x00\x00\x00\x04x\x00\\\x00\x00\x00\x020\x00\x02\x00\x00\x00y\x00\x101\x00\"\x00\x00\x00\x102\x00\x03\x00\x00@\x013\x00\xC1\xFA9\x9F\x8E\xFA\x00@\x034\x002\x00\x00\x00\x02hello\x00\x06\x00\x00\x00world\x00\x045\x00\x19\x00\x00\x00\x100\x00?\x00\x00\x00\x021\x00\x06\x00\x00\x00asjdl\x00\x00\x00\x00\x00"
|
17
|
+
ENCODED_JSON = '{"x":["y",34,1073741827,2.1223423423356,{"hello":"world","5":[63,"asjdl"]}]}'
|
18
|
+
ITERATIONS = 1_00_000
|
19
|
+
|
20
|
+
Viiite.bm do |b|
|
21
|
+
b.variation_point :ruby, Viiite.which_ruby
|
22
|
+
|
23
|
+
[:json, :msgpack].each do |lib|
|
24
|
+
b.variation_point :lib, lib
|
25
|
+
|
26
|
+
|
27
|
+
b.report(:pack) do
|
28
|
+
ITERATIONS.times do
|
29
|
+
case lib
|
30
|
+
when :msgpack then MessagePack.pack(OBJECT_STRUCTURE)
|
31
|
+
when :bson then BSON::BSON_JAVA.serialize(OBJECT_STRUCTURE).to_s
|
32
|
+
when :json then OBJECT_STRUCTURE.to_json
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
b.report(:unpack) do
|
38
|
+
ITERATIONS.times do
|
39
|
+
case lib
|
40
|
+
when :msgpack then MessagePack.unpack(ENCODED_MSGPACK)
|
41
|
+
when :bson then BSON::BSON_JAVA.deserialize(ENCODED_BSON)
|
42
|
+
when :json then JSON.parse(ENCODED_JSON)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
b.report(:pack_unpack) do
|
48
|
+
ITERATIONS.times do
|
49
|
+
case lib
|
50
|
+
when :msgpack then MessagePack.unpack(MessagePack.pack(OBJECT_STRUCTURE))
|
51
|
+
when :bson then BSON::BSON_JAVA.deserialize(BSON::BSON_JAVA.serialize(OBJECT_STRUCTURE).to_s)
|
52
|
+
when :json then JSON.parse(OBJECT_STRUCTURE.to_json)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
b.report(:unpack_pack) do
|
58
|
+
ITERATIONS.times do
|
59
|
+
case lib
|
60
|
+
when :msgpack then MessagePack.pack(MessagePack.unpack(ENCODED_MSGPACK))
|
61
|
+
when :bson then BSON::BSON_JAVA.serialize(BSON::BSON_JAVA.deserialize(ENCODED_BSON)).to_s
|
62
|
+
when :json then OBJECT_STRUCTURE.to_json(JSON.parse(ENCODED_JSON))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
require_relative 'spec_helper'
|
4
|
+
|
5
|
+
|
6
|
+
describe MessagePack do
|
7
|
+
tests = {
|
8
|
+
'constant values' => [
|
9
|
+
['true', true, "\xC3"],
|
10
|
+
['false', false, "\xC2"],
|
11
|
+
['nil', nil, "\xC0"]
|
12
|
+
],
|
13
|
+
'numbers' => [
|
14
|
+
['zero', 0, "\x00"],
|
15
|
+
['127', 127, "\x7F"],
|
16
|
+
['128', 128, "\xCC\x80"],
|
17
|
+
['256', 256, "\xCD\x01\x00"],
|
18
|
+
['-1', -1, "\xFF"],
|
19
|
+
['-33', -33, "\xD0\xDF"],
|
20
|
+
['-129', -129, "\xD1\xFF\x7F"],
|
21
|
+
['small integers', 42, "*"],
|
22
|
+
['medium integers', 333, "\xCD\x01M"],
|
23
|
+
['large integers', 2**31 - 1, "\xCE\x7F\xFF\xFF\xFF"],
|
24
|
+
['huge integers', 2**64 - 1, "\xCF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"],
|
25
|
+
['negative integers', -1, "\xFF"],
|
26
|
+
['1.0', 1.0, "\xcb\x3f\xf0\x00\x00\x00\x00\x00\x00"],
|
27
|
+
['small floats', 3.14, "\xCB@\t\x1E\xB8Q\xEB\x85\x1F"],
|
28
|
+
['big floats', Math::PI * 1_000_000_000_000_000_000, "\xCBC\xC5\xCC\x96\xEF\xD1\x19%"],
|
29
|
+
['negative floats', -2.1, "\xCB\xC0\x00\xCC\xCC\xCC\xCC\xCC\xCD"]
|
30
|
+
],
|
31
|
+
'strings' => [
|
32
|
+
['strings', 'hello world', "\xABhello world"],
|
33
|
+
['empty strings', '', "\xA0"]
|
34
|
+
],
|
35
|
+
'arrays' => [
|
36
|
+
['empty arrays', [], "\x90"],
|
37
|
+
['arrays with strings', ["hello", "world"], "\x92\xA5hello\xA5world"],
|
38
|
+
['arrays with mixed values', ["hello", "world", 42], "\x93\xA5hello\xA5world*"],
|
39
|
+
['arrays of arrays', [[[[1, 2], 3], 4]], "\x91\x92\x92\x92\x01\x02\x03\x04"],
|
40
|
+
['empty arrays', [], "\x90"]
|
41
|
+
],
|
42
|
+
'hashes' => [
|
43
|
+
['empty hashes', {}, "\x80"],
|
44
|
+
['hashes', {'foo' => 'bar'}, "\x81\xA3foo\xA3bar"],
|
45
|
+
['hashes with mixed keys and values', {'foo' => 'bar', 3 => 'three', 'four' => 4, 'x' => ['y'], 'a' => 'b'}, "\x85\xA3foo\xA3bar\x03\xA5three\xA4four\x04\xA1x\x91\xA1y\xA1a\xA1b"],
|
46
|
+
['hashes of hashes', {{'x' => {'y' => 'z'}} => 's'}, "\x81\x81\xA1x\x81\xA1y\xA1z\xA1s"],
|
47
|
+
['hashes with nils', {'foo' => nil}, "\x81\xA3foo\xC0"]
|
48
|
+
]
|
49
|
+
}
|
50
|
+
|
51
|
+
tests.each do |ctx, its|
|
52
|
+
context("with #{ctx}") do
|
53
|
+
its.each do |desc, unpacked, packed|
|
54
|
+
it("encodes #{desc}") do
|
55
|
+
MessagePack.pack(unpacked).should == packed
|
56
|
+
end
|
57
|
+
|
58
|
+
it "decodes #{desc}" do
|
59
|
+
MessagePack.unpack(packed).should == unpacked
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with symbols' do
|
66
|
+
it 'encodes symbols as strings' do
|
67
|
+
MessagePack.pack(:symbol).should == "\xA6symbol"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with other things' do
|
72
|
+
it 'raises an error on #pack' do
|
73
|
+
expect { MessagePack.pack(self) }.to raise_error(ArgumentError, /^Cannot pack type:/)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: msgpack-jruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: java
|
11
|
+
authors:
|
12
|
+
- Theo Hultberg
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-09-15 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: JRuby compatible MessagePack implementation that does not use FFI
|
22
|
+
email:
|
23
|
+
- theo@iconara.net
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- .rspec
|
33
|
+
- .rvmrc
|
34
|
+
- Gemfile
|
35
|
+
- Rakefile
|
36
|
+
- ext/java/org/msgpack/jruby/MessagePack.java
|
37
|
+
- lib/ext/msgpack-0.5.2-devel.jar
|
38
|
+
- lib/ext/org/msgpack/jruby/MessagePack.class
|
39
|
+
- lib/msgpack.rb
|
40
|
+
- lib/msgpack/version.rb
|
41
|
+
- msgpack-jruby.gemspec
|
42
|
+
- spec/benchmark.rb
|
43
|
+
- spec/msgpack_spec.rb
|
44
|
+
- spec/spec_helper.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/iconara/msgpack-jruby
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
rubyforge_project: msgpack-jruby
|
71
|
+
rubygems_version: 1.3.6
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: MessagePack implementation for JRuby
|
75
|
+
test_files: []
|
76
|
+
|