msgpack 0.7.4 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
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);