msgpack 0.7.4 → 1.3.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.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -1
  3. data/.rubocop.yml +3 -0
  4. data/.travis.yml +27 -14
  5. data/ChangeLog +89 -1
  6. data/Gemfile +6 -1
  7. data/README.rdoc +55 -1
  8. data/Rakefile +5 -1
  9. data/bench/pack_symbols.rb +28 -0
  10. data/bench/run_symbols.sh +26 -0
  11. data/doclib/msgpack.rb +2 -2
  12. data/doclib/msgpack/core_ext.rb +20 -20
  13. data/doclib/msgpack/factory.rb +33 -0
  14. data/doclib/msgpack/packer.rb +20 -0
  15. data/doclib/msgpack/time.rb +22 -0
  16. data/doclib/msgpack/timestamp.rb +44 -0
  17. data/ext/java/org/msgpack/jruby/Buffer.java +4 -0
  18. data/ext/java/org/msgpack/jruby/Encoder.java +48 -18
  19. data/ext/java/org/msgpack/jruby/ExtensionRegistry.java +67 -38
  20. data/ext/java/org/msgpack/jruby/Factory.java +20 -8
  21. data/ext/java/org/msgpack/jruby/MessagePackLibrary.java +0 -92
  22. data/ext/java/org/msgpack/jruby/Packer.java +114 -11
  23. data/ext/java/org/msgpack/jruby/Unpacker.java +15 -8
  24. data/ext/msgpack/buffer.h +14 -0
  25. data/ext/msgpack/buffer_class.c +1 -1
  26. data/ext/msgpack/compat.h +10 -0
  27. data/ext/msgpack/factory_class.c +24 -17
  28. data/ext/msgpack/factory_class.h +0 -2
  29. data/ext/msgpack/packer.c +5 -4
  30. data/ext/msgpack/packer.h +13 -1
  31. data/ext/msgpack/packer_class.c +130 -43
  32. data/ext/msgpack/packer_class.h +0 -2
  33. data/ext/msgpack/packer_ext_registry.c +2 -2
  34. data/ext/msgpack/packer_ext_registry.h +64 -25
  35. data/ext/msgpack/rbinit.c +0 -2
  36. data/ext/msgpack/unpacker.c +3 -3
  37. data/ext/msgpack/unpacker_class.c +25 -56
  38. data/ext/msgpack/unpacker_class.h +0 -2
  39. data/ext/msgpack/unpacker_ext_registry.c +2 -2
  40. data/ext/msgpack/unpacker_ext_registry.h +3 -3
  41. data/lib/msgpack.rb +36 -0
  42. data/lib/msgpack/core_ext.rb +139 -0
  43. data/lib/msgpack/factory.rb +21 -0
  44. data/lib/msgpack/symbol.rb +9 -0
  45. data/lib/msgpack/time.rb +29 -0
  46. data/lib/msgpack/timestamp.rb +76 -0
  47. data/lib/msgpack/version.rb +8 -1
  48. data/msgpack.gemspec +6 -7
  49. data/spec/cruby/buffer_spec.rb +6 -1
  50. data/spec/factory_spec.rb +134 -0
  51. data/spec/msgpack_spec.rb +52 -0
  52. data/spec/packer_spec.rb +200 -0
  53. data/spec/timestamp_spec.rb +121 -0
  54. data/spec/unpacker_spec.rb +29 -0
  55. metadata +29 -23
  56. data/ext/msgpack/core_ext.c +0 -144
  57. data/ext/msgpack/core_ext.h +0 -26
@@ -2,6 +2,7 @@ package org.msgpack.jruby;
2
2
 
3
3
 
4
4
  import org.jruby.Ruby;
5
+ import org.jruby.RubyModule;
5
6
  import org.jruby.RubyClass;
6
7
  import org.jruby.RubyObject;
7
8
  import org.jruby.RubyArray;
@@ -24,11 +25,13 @@ import static org.jruby.runtime.Visibility.PRIVATE;
24
25
  public class Factory extends RubyObject {
25
26
  private final Ruby runtime;
26
27
  private final ExtensionRegistry extensionRegistry;
28
+ private boolean hasSymbolExtType;
27
29
 
28
30
  public Factory(Ruby runtime, RubyClass type) {
29
31
  super(runtime, type);
30
32
  this.runtime = runtime;
31
33
  this.extensionRegistry = new ExtensionRegistry();
34
+ this.hasSymbolExtType = false;
32
35
  }
33
36
 
34
37
  static class FactoryAllocator implements ObjectAllocator {
@@ -48,10 +51,10 @@ public class Factory extends RubyObject {
48
51
 
49
52
  @JRubyMethod(name = "packer", optional = 1)
50
53
  public Packer packer(ThreadContext ctx, IRubyObject[] args) {
51
- return Packer.newPacker(ctx, extensionRegistry(), args);
54
+ return Packer.newPacker(ctx, extensionRegistry(), hasSymbolExtType, args);
52
55
  }
53
56
 
54
- @JRubyMethod(name = "unpacker", optional = 1)
57
+ @JRubyMethod(name = "unpacker", optional = 2)
55
58
  public Unpacker unpacker(ThreadContext ctx, IRubyObject[] args) {
56
59
  return Unpacker.newUnpacker(ctx, extensionRegistry(), args);
57
60
  }
@@ -68,10 +71,15 @@ public class Factory extends RubyObject {
68
71
  public IRubyObject registerType(ThreadContext ctx, IRubyObject[] args) {
69
72
  Ruby runtime = ctx.getRuntime();
70
73
  IRubyObject type = args[0];
71
- IRubyObject klass = args[1];
74
+ IRubyObject mod = args[1];
72
75
 
73
76
  IRubyObject packerArg;
74
77
  IRubyObject unpackerArg;
78
+
79
+ if (isFrozen()) {
80
+ throw runtime.newRuntimeError("can't modify frozen Factory");
81
+ }
82
+
75
83
  if (args.length == 2) {
76
84
  packerArg = runtime.newSymbol("to_msgpack_ext");
77
85
  unpackerArg = runtime.newSymbol("from_msgpack_ext");
@@ -92,10 +100,10 @@ public class Factory extends RubyObject {
92
100
  throw runtime.newRangeError(String.format("integer %d too big to convert to `signed char'", typeId));
93
101
  }
94
102
 
95
- if (!(klass instanceof RubyClass)) {
96
- throw runtime.newArgumentError(String.format("expected Class but found %s.", klass.getType().getName()));
103
+ if (!(mod instanceof RubyModule)) {
104
+ throw runtime.newArgumentError(String.format("expected Module/Class but found %s.", mod.getType().getName()));
97
105
  }
98
- RubyClass extClass = (RubyClass) klass;
106
+ RubyModule extModule = (RubyModule) mod;
99
107
 
100
108
  IRubyObject packerProc = runtime.getNil();
101
109
  IRubyObject unpackerProc = runtime.getNil();
@@ -104,13 +112,17 @@ public class Factory extends RubyObject {
104
112
  }
105
113
  if (unpackerArg != null) {
106
114
  if (unpackerArg instanceof RubyString || unpackerArg instanceof RubySymbol) {
107
- unpackerProc = extClass.method(unpackerArg.callMethod(ctx, "to_sym"));
115
+ unpackerProc = extModule.method(unpackerArg.callMethod(ctx, "to_sym"));
108
116
  } else {
109
117
  unpackerProc = unpackerArg.callMethod(ctx, "method", runtime.newSymbol("call"));
110
118
  }
111
119
  }
112
120
 
113
- extensionRegistry.put(extClass, (int) typeId, packerProc, packerArg, unpackerProc, unpackerArg);
121
+ extensionRegistry.put(extModule, (int) typeId, packerProc, packerArg, unpackerProc, unpackerArg);
122
+
123
+ if (extModule == runtime.getSymbol()) {
124
+ hasSymbolExtType = true;
125
+ }
114
126
 
115
127
  return runtime.getNil();
116
128
  }
@@ -20,11 +20,8 @@ import org.jruby.internal.runtime.methods.DynamicMethod;
20
20
 
21
21
 
22
22
  public class MessagePackLibrary implements Library {
23
- public static Factory defaultFactory;
24
-
25
23
  public void load(Ruby runtime, boolean wrap) {
26
24
  RubyModule msgpackModule = runtime.defineModule("MessagePack");
27
- msgpackModule.defineAnnotatedMethods(MessagePackModule.class);
28
25
  RubyClass standardErrorClass = runtime.getStandardError();
29
26
  RubyClass unpackErrorClass = msgpackModule.defineClassUnder("UnpackError", standardErrorClass, standardErrorClass.getAllocator());
30
27
  RubyClass underflowErrorClass = msgpackModule.defineClassUnder("UnderflowError", unpackErrorClass, unpackErrorClass.getAllocator());
@@ -44,94 +41,5 @@ public class MessagePackLibrary implements Library {
44
41
  bufferClass.defineAnnotatedMethods(Buffer.class);
45
42
  RubyClass factoryClass = msgpackModule.defineClassUnder("Factory", runtime.getObject(), new Factory.FactoryAllocator());
46
43
  factoryClass.defineAnnotatedMethods(Factory.class);
47
- defaultFactory = new Factory(runtime, factoryClass);
48
- defaultFactory.initialize(runtime.getCurrentContext());
49
- msgpackModule.defineConstant("DefaultFactory", defaultFactory);
50
- installCoreExtensions(runtime);
51
- }
52
-
53
- private void installCoreExtensions(Ruby runtime) {
54
- RubyClass extensionValueClass = runtime.getModule("MessagePack").getClass("ExtensionValue");
55
- installCoreExtensions(
56
- runtime,
57
- runtime.getNilClass(),
58
- runtime.getTrueClass(),
59
- runtime.getFalseClass(),
60
- runtime.getFixnum(),
61
- runtime.getBignum(),
62
- runtime.getFloat(),
63
- runtime.getString(),
64
- runtime.getArray(),
65
- runtime.getHash(),
66
- runtime.getSymbol(),
67
- extensionValueClass
68
- );
69
- }
70
-
71
- private void installCoreExtensions(Ruby runtime, RubyClass... classes) {
72
- for (RubyClass cls : classes) {
73
- cls.addMethod("to_msgpack", createToMsgpackMethod(runtime, cls));
74
- }
75
- }
76
-
77
- private DynamicMethod createToMsgpackMethod(final Ruby runtime, RubyClass cls) {
78
- return new DynamicMethod(cls, Visibility.PUBLIC, CallConfiguration.FrameNoneScopeNone) {
79
- @Override
80
- public IRubyObject call(ThreadContext context, IRubyObject recv, RubyModule clazz, String name, IRubyObject[] args, Block block) {
81
- if (args.length == 0) {
82
- IRubyObject[] allArgs = { recv };
83
- return MessagePackModule.pack(runtime.getCurrentContext(), null, allArgs);
84
- } else if (args.length == 1 && args[0] instanceof Packer) {
85
- Packer packer = (Packer)args[0];
86
- return packer.write(runtime.getCurrentContext(), recv);
87
- } else if (args.length == 1) {
88
- IRubyObject[] allArgs = { recv, args[0] };
89
- return MessagePackModule.pack(runtime.getCurrentContext(), null, allArgs);
90
- } else {
91
- throw runtime.newArgumentError(String.format("wrong number of arguments (%d for 0..1)", args.length));
92
- }
93
- }
94
-
95
- @Override
96
- public DynamicMethod dup() {
97
- return this;
98
- }
99
- };
100
- }
101
-
102
- @JRubyModule(name = "MessagePack")
103
- public static class MessagePackModule {
104
- @JRubyMethod(module = true, required = 1, optional = 1, alias = {"dump"})
105
- public static IRubyObject pack(ThreadContext ctx, IRubyObject recv, IRubyObject[] args) {
106
- IRubyObject[] extraArgs = null;
107
- if (args.length == 0) {
108
- extraArgs = new IRubyObject[] {};
109
- } else {
110
- extraArgs = new IRubyObject[args.length - 1];
111
- System.arraycopy(args, 1, extraArgs, 0, args.length - 1);
112
- }
113
- Packer packer = MessagePackLibrary.defaultFactory.packer(ctx, extraArgs);
114
- packer.write(ctx, args[0]);
115
- return packer.toS(ctx);
116
- }
117
-
118
- @JRubyMethod(module = true, required = 1, optional = 1, alias = {"load"})
119
- public static IRubyObject unpack(ThreadContext ctx, IRubyObject recv, IRubyObject[] args) {
120
- ExtensionRegistry registry = MessagePackLibrary.defaultFactory.extensionRegistry();
121
-
122
- boolean symbolizeKeys = false;
123
- boolean allowUnknownExt = false;
124
- if (args.length > 1 && !args[args.length - 1].isNil()) {
125
- RubyHash hash = args[args.length - 1].convertToHash();
126
- IRubyObject symbolizeKeysVal = hash.fastARef(ctx.getRuntime().newSymbol("symbolize_keys"));
127
- symbolizeKeys = symbolizeKeysVal != null && symbolizeKeysVal.isTrue();
128
- IRubyObject allowUnknownExtVal = hash.fastARef(ctx.getRuntime().newSymbol("allow_unknown_ext"));
129
- allowUnknownExt = (allowUnknownExtVal != null && allowUnknownExtVal.isTrue());
130
- }
131
- byte[] bytes = args[0].asString().getBytes();
132
- Decoder decoder = new Decoder(ctx.getRuntime(), registry, bytes, 0, bytes.length, symbolizeKeys, allowUnknownExt);
133
-
134
- return decoder.next();
135
- }
136
44
  }
137
45
  }
@@ -2,6 +2,7 @@ package org.msgpack.jruby;
2
2
 
3
3
 
4
4
  import org.jruby.Ruby;
5
+ import org.jruby.RubyModule;
5
6
  import org.jruby.RubyClass;
6
7
  import org.jruby.RubyObject;
7
8
  import org.jruby.RubyArray;
@@ -17,6 +18,10 @@ import org.jruby.anno.JRubyMethod;
17
18
  import org.jruby.runtime.ThreadContext;
18
19
  import org.jruby.runtime.ObjectAllocator;
19
20
  import org.jruby.util.ByteList;
21
+ import org.jruby.util.TypeConverter;
22
+ import org.msgpack.jruby.ExtensionValue;
23
+
24
+ import org.jcodings.Encoding;
20
25
 
21
26
  import static org.jruby.runtime.Visibility.PRIVATE;
22
27
 
@@ -25,15 +30,18 @@ public class Packer extends RubyObject {
25
30
  public ExtensionRegistry registry;
26
31
  private Buffer buffer;
27
32
  private Encoder encoder;
33
+ private boolean hasSymbolExtType;
34
+ private Encoding binaryEncoding;
28
35
 
29
- public Packer(Ruby runtime, RubyClass type, ExtensionRegistry registry) {
36
+ public Packer(Ruby runtime, RubyClass type, ExtensionRegistry registry, boolean hasSymbolExtType) {
30
37
  super(runtime, type);
31
38
  this.registry = registry;
39
+ this.hasSymbolExtType = hasSymbolExtType;
32
40
  }
33
41
 
34
42
  static class PackerAllocator implements ObjectAllocator {
35
43
  public IRubyObject allocate(Ruby runtime, RubyClass type) {
36
- return new Packer(runtime, type, null);
44
+ return new Packer(runtime, type, null, false);
37
45
  }
38
46
  }
39
47
 
@@ -45,15 +53,20 @@ public class Packer extends RubyObject {
45
53
  IRubyObject mode = options.fastARef(ctx.getRuntime().newSymbol("compatibility_mode"));
46
54
  compatibilityMode = (mode != null) && mode.isTrue();
47
55
  }
48
- this.encoder = new Encoder(ctx.getRuntime(), compatibilityMode, registry);
56
+ if (registry == null) {
57
+ // registry is null when allocate -> initialize
58
+ // registry is already initialized (and somthing might be registered) when newPacker from Factory
59
+ this.registry = new ExtensionRegistry();
60
+ }
61
+ this.encoder = new Encoder(ctx.getRuntime(), compatibilityMode, registry, hasSymbolExtType);
49
62
  this.buffer = new Buffer(ctx.getRuntime(), ctx.getRuntime().getModule("MessagePack").getClass("Buffer"));
50
63
  this.buffer.initialize(ctx, args);
51
- this.registry = new ExtensionRegistry();
64
+ this.binaryEncoding = ctx.getRuntime().getEncodingService().getAscii8bitEncoding();
52
65
  return this;
53
66
  }
54
67
 
55
- public static Packer newPacker(ThreadContext ctx, ExtensionRegistry extRegistry, IRubyObject[] args) {
56
- Packer packer = new Packer(ctx.getRuntime(), ctx.getRuntime().getModule("MessagePack").getClass("Packer"), extRegistry);
68
+ public static Packer newPacker(ThreadContext ctx, ExtensionRegistry extRegistry, boolean hasSymbolExtType, IRubyObject[] args) {
69
+ Packer packer = new Packer(ctx.getRuntime(), ctx.getRuntime().getModule("MessagePack").getClass("Packer"), extRegistry, hasSymbolExtType);
57
70
  packer.initialize(ctx, args);
58
71
  return packer;
59
72
  }
@@ -72,7 +85,7 @@ public class Packer extends RubyObject {
72
85
  public IRubyObject registerType(ThreadContext ctx, IRubyObject[] args, final Block block) {
73
86
  Ruby runtime = ctx.getRuntime();
74
87
  IRubyObject type = args[0];
75
- IRubyObject klass = args[1];
88
+ IRubyObject mod = args[1];
76
89
 
77
90
  IRubyObject arg;
78
91
  IRubyObject proc;
@@ -94,12 +107,17 @@ public class Packer extends RubyObject {
94
107
  throw runtime.newRangeError(String.format("integer %d too big to convert to `signed char'", typeId));
95
108
  }
96
109
 
97
- if (!(klass instanceof RubyClass)) {
98
- throw runtime.newArgumentError(String.format("expected Class but found %s.", klass.getType().getName()));
110
+ if (!(mod instanceof RubyModule)) {
111
+ throw runtime.newArgumentError(String.format("expected Module/Class but found %s.", mod.getType().getName()));
112
+ }
113
+ RubyModule extModule = (RubyModule) mod;
114
+
115
+ registry.put(extModule, (int) typeId, proc, arg, null, null);
116
+
117
+ if (extModule == runtime.getSymbol()) {
118
+ encoder.hasSymbolExtType = true;
99
119
  }
100
- RubyClass extClass = (RubyClass) klass;
101
120
 
102
- registry.put(extClass, (int) typeId, proc, arg, null, null);
103
121
  return runtime.getNil();
104
122
  }
105
123
 
@@ -109,6 +127,69 @@ public class Packer extends RubyObject {
109
127
  return this;
110
128
  }
111
129
 
130
+ @JRubyMethod(name = "write_float")
131
+ public IRubyObject writeFloat(ThreadContext ctx, IRubyObject obj) {
132
+ checkType(ctx, obj, org.jruby.RubyFloat.class);
133
+ return write(ctx, obj);
134
+ }
135
+
136
+ @JRubyMethod(name = "write_array")
137
+ public IRubyObject writeArray(ThreadContext ctx, IRubyObject obj) {
138
+ checkType(ctx, obj, org.jruby.RubyArray.class);
139
+ return write(ctx, obj);
140
+ }
141
+
142
+ @JRubyMethod(name = "write_string")
143
+ public IRubyObject writeString(ThreadContext ctx, IRubyObject obj) {
144
+ checkType(ctx, obj, org.jruby.RubyString.class);
145
+ return write(ctx, obj);
146
+ }
147
+
148
+ @JRubyMethod(name = "write_bin")
149
+ public IRubyObject writeBin(ThreadContext ctx, IRubyObject obj) {
150
+ checkType(ctx, obj, org.jruby.RubyString.class);
151
+ obj = ((org.jruby.RubyString) obj).encode(ctx, ctx.runtime.getEncodingService().getEncoding(binaryEncoding));
152
+ return write(ctx, obj);
153
+ }
154
+
155
+ @JRubyMethod(name = "write_hash")
156
+ public IRubyObject writeHash(ThreadContext ctx, IRubyObject obj) {
157
+ checkType(ctx, obj, org.jruby.RubyHash.class);
158
+ return write(ctx, obj);
159
+ }
160
+
161
+ @JRubyMethod(name = "write_symbol")
162
+ public IRubyObject writeSymbol(ThreadContext ctx, IRubyObject obj) {
163
+ checkType(ctx, obj, org.jruby.RubySymbol.class);
164
+ return write(ctx, obj);
165
+ }
166
+
167
+ @JRubyMethod(name = "write_int")
168
+ public IRubyObject writeInt(ThreadContext ctx, IRubyObject obj) {
169
+ if (!(obj instanceof RubyFixnum)) {
170
+ checkType(ctx, obj, org.jruby.RubyBignum.class);
171
+ }
172
+ return write(ctx, obj);
173
+ }
174
+
175
+ @JRubyMethod(name = "write_extension")
176
+ public IRubyObject writeExtension(ThreadContext ctx, IRubyObject obj) {
177
+ if (!(obj instanceof ExtensionValue)) {
178
+ throw ctx.runtime.newTypeError("Expected extension");
179
+ }
180
+ return write(ctx, obj);
181
+ }
182
+
183
+ @JRubyMethod(name = "write_true")
184
+ public IRubyObject writeTrue(ThreadContext ctx) {
185
+ return write(ctx, ctx.getRuntime().getTrue());
186
+ }
187
+
188
+ @JRubyMethod(name = "write_false")
189
+ public IRubyObject writeFalse(ThreadContext ctx) {
190
+ return write(ctx, ctx.getRuntime().getFalse());
191
+ }
192
+
112
193
  @JRubyMethod(name = "write_nil")
113
194
  public IRubyObject writeNil(ThreadContext ctx) {
114
195
  write(ctx, null);
@@ -139,6 +220,21 @@ public class Packer extends RubyObject {
139
220
  return this;
140
221
  }
141
222
 
223
+ @JRubyMethod(name = "write_bin_header")
224
+ public IRubyObject writeBinHeader(ThreadContext ctx, IRubyObject size) {
225
+ int s = (int) size.convertToInteger().getLongValue();
226
+ buffer.write(ctx, encoder.encodeBinHeader(s));
227
+ return this;
228
+ }
229
+
230
+ @JRubyMethod(name = "full_pack")
231
+ public IRubyObject fullPack(ThreadContext ctx) {
232
+ if (buffer.hasIo()) {
233
+ return null;
234
+ }
235
+ return toS(ctx);
236
+ }
237
+
142
238
  @JRubyMethod(name = "to_s", alias = { "to_str" })
143
239
  public IRubyObject toS(ThreadContext ctx) {
144
240
  return buffer.toS(ctx);
@@ -163,4 +259,11 @@ public class Packer extends RubyObject {
163
259
  public IRubyObject clear(ThreadContext ctx) {
164
260
  return buffer.clear(ctx);
165
261
  }
262
+
263
+ private void checkType(ThreadContext ctx, IRubyObject obj, Class<? extends IRubyObject> expectedType) {
264
+ if (!expectedType.isInstance(obj)) {
265
+ String expectedName = expectedType.getName().substring("org.jruby.Ruby".length());
266
+ throw ctx.runtime.newTypeError(String.format("wrong argument type %s (expected %s)", obj.getMetaClass().toString(), expectedName));
267
+ }
268
+ }
166
269
  }
@@ -3,6 +3,7 @@ package org.msgpack.jruby;
3
3
  import java.util.Arrays;
4
4
 
5
5
  import org.jruby.Ruby;
6
+ import org.jruby.RubyModule;
6
7
  import org.jruby.RubyClass;
7
8
  import org.jruby.RubyString;
8
9
  import org.jruby.RubyObject;
@@ -51,7 +52,7 @@ public class Unpacker extends RubyObject {
51
52
  }
52
53
  }
53
54
 
54
- @JRubyMethod(name = "initialize", optional = 1, visibility = PRIVATE)
55
+ @JRubyMethod(name = "initialize", optional = 2, visibility = PRIVATE)
55
56
  public IRubyObject initialize(ThreadContext ctx, IRubyObject[] args) {
56
57
  symbolizeKeys = false;
57
58
  allowUnknownExt = false;
@@ -66,7 +67,8 @@ public class Unpacker extends RubyObject {
66
67
  if (au != null) {
67
68
  allowUnknownExt = au.isTrue();
68
69
  }
69
- } else if (!(args[0] instanceof RubyHash)) {
70
+ }
71
+ if (args[0] != ctx.getRuntime().getNil() && !(args[0] instanceof RubyHash)) {
70
72
  setStream(ctx, args[0]);
71
73
  }
72
74
  }
@@ -99,7 +101,7 @@ public class Unpacker extends RubyObject {
99
101
  Ruby runtime = ctx.getRuntime();
100
102
  IRubyObject type = args[0];
101
103
 
102
- RubyClass extClass;
104
+ RubyModule extModule;
103
105
  IRubyObject arg;
104
106
  IRubyObject proc;
105
107
  if (args.length == 1) {
@@ -110,11 +112,11 @@ public class Unpacker extends RubyObject {
110
112
  if (proc == null)
111
113
  System.err.println("proc from Block is null");
112
114
  arg = proc;
113
- extClass = null;
115
+ extModule = null;
114
116
  } else if (args.length == 3) {
115
- extClass = (RubyClass) args[1];
117
+ extModule = (RubyModule) args[1];
116
118
  arg = args[2];
117
- proc = extClass.method(arg);
119
+ proc = extModule.method(arg);
118
120
  } else {
119
121
  throw runtime.newArgumentError(String.format("wrong number of arguments (%d for 1 or 3)", 2 + args.length));
120
122
  }
@@ -124,7 +126,7 @@ public class Unpacker extends RubyObject {
124
126
  throw runtime.newRangeError(String.format("integer %d too big to convert to `signed char'", typeId));
125
127
  }
126
128
 
127
- registry.put(extClass, (int) typeId, null, null, proc, arg);
129
+ registry.put(extModule, (int) typeId, null, null, proc, arg);
128
130
  return runtime.getNil();
129
131
  }
130
132
 
@@ -168,7 +170,7 @@ public class Unpacker extends RubyObject {
168
170
  return data == null ? ctx.getRuntime().getFalse() : ctx.getRuntime().getTrue();
169
171
  }
170
172
 
171
- @JRubyMethod(required = 1)
173
+ @JRubyMethod(required = 1, name = "feed", alias = { "feed_reference" })
172
174
  public IRubyObject feed(ThreadContext ctx, IRubyObject data) {
173
175
  ByteList byteList = data.asString().getByteList();
174
176
  if (decoder == null) {
@@ -179,6 +181,11 @@ public class Unpacker extends RubyObject {
179
181
  return this;
180
182
  }
181
183
 
184
+ @JRubyMethod(name = "full_unpack")
185
+ public IRubyObject fullUnpack(ThreadContext ctx) {
186
+ return decoder.next();
187
+ }
188
+
182
189
  @JRubyMethod(name = "feed_each", required = 1)
183
190
  public IRubyObject feedEach(ThreadContext ctx, IRubyObject data, Block block) {
184
191
  feed(ctx, data);