2
* This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
4
* Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
9
import java.lang.ref.WeakReference;
10
import org.jruby.Ruby;
11
import org.jruby.RubyArray;
12
import org.jruby.RubyBoolean;
13
import org.jruby.RubyFixnum;
14
import org.jruby.RubyFloat;
15
import org.jruby.RubyHash;
16
import org.jruby.RubyInteger;
17
import org.jruby.RubyModule;
18
import org.jruby.RubyNumeric;
19
import org.jruby.RubyString;
20
import org.jruby.anno.JRubyMethod;
21
import org.jruby.runtime.ThreadContext;
22
import org.jruby.runtime.builtin.IRubyObject;
23
import org.jruby.util.ByteList;
26
* A class that populates the
27
* <code>Json::Ext::Generator::GeneratorMethods</code> module.
31
class GeneratorMethods {
33
* Populates the given module with all modules and their methods
35
* @param generatorMethodsModule The module to populate
36
* (normally <code>JSON::Generator::GeneratorMethods</code>)
38
static void populate(RuntimeInfo info, RubyModule module) {
39
defineMethods(module, "Array", RbArray.class);
40
defineMethods(module, "FalseClass", RbFalse.class);
41
defineMethods(module, "Float", RbFloat.class);
42
defineMethods(module, "Hash", RbHash.class);
43
defineMethods(module, "Integer", RbInteger.class);
44
defineMethods(module, "NilClass", RbNil.class);
45
defineMethods(module, "Object", RbObject.class);
46
defineMethods(module, "String", RbString.class);
47
defineMethods(module, "TrueClass", RbTrue.class);
49
info.stringExtendModule = new WeakReference<RubyModule>(module.defineModuleUnder("String")
50
.defineModuleUnder("Extend"));
51
info.stringExtendModule.get().defineAnnotatedMethods(StringExtend.class);
55
* Convenience method for defining methods on a submodule.
57
* @param submoduleName
60
private static void defineMethods(RubyModule parentModule,
61
String submoduleName, Class klass) {
62
RubyModule submodule = parentModule.defineModuleUnder(submoduleName);
63
submodule.defineAnnotatedMethods(klass);
67
public static class RbHash {
68
@JRubyMethod(rest=true)
69
public static IRubyObject to_json(ThreadContext context,
70
IRubyObject vSelf, IRubyObject[] args) {
71
return Generator.generateJson(context, (RubyHash)vSelf,
72
Generator.HASH_HANDLER, args);
76
public static class RbArray {
77
@JRubyMethod(rest=true)
78
public static IRubyObject to_json(ThreadContext context,
79
IRubyObject vSelf, IRubyObject[] args) {
80
return Generator.generateJson(context, (RubyArray)vSelf,
81
Generator.ARRAY_HANDLER, args);
85
public static class RbInteger {
86
@JRubyMethod(rest=true)
87
public static IRubyObject to_json(ThreadContext context,
88
IRubyObject vSelf, IRubyObject[] args) {
89
return Generator.generateJson(context, vSelf, args);
93
public static class RbFloat {
94
@JRubyMethod(rest=true)
95
public static IRubyObject to_json(ThreadContext context,
96
IRubyObject vSelf, IRubyObject[] args) {
97
return Generator.generateJson(context, (RubyFloat)vSelf,
98
Generator.FLOAT_HANDLER, args);
102
public static class RbString {
103
@JRubyMethod(rest=true)
104
public static IRubyObject to_json(ThreadContext context,
105
IRubyObject vSelf, IRubyObject[] args) {
106
return Generator.generateJson(context, (RubyString)vSelf,
107
Generator.STRING_HANDLER, args);
111
* <code>{@link RubyString String}#to_json_raw(*)</code>
113
* <p>This method creates a JSON text from the result of a call to
114
* {@link #to_json_raw_object} of this String.
116
@JRubyMethod(rest=true)
117
public static IRubyObject to_json_raw(ThreadContext context,
118
IRubyObject vSelf, IRubyObject[] args) {
119
RubyHash obj = toJsonRawObject(context, Utils.ensureString(vSelf));
120
return Generator.generateJson(context, obj,
121
Generator.HASH_HANDLER, args);
125
* <code>{@link RubyString String}#to_json_raw_object(*)</code>
127
* <p>This method creates a raw object Hash, that can be nested into
128
* other data structures and will be unparsed as a raw string. This
129
* method should be used if you want to convert raw strings to JSON
130
* instead of UTF-8 strings, e.g. binary data.
132
@JRubyMethod(rest=true)
133
public static IRubyObject to_json_raw_object(ThreadContext context,
134
IRubyObject vSelf, IRubyObject[] args) {
135
return toJsonRawObject(context, Utils.ensureString(vSelf));
138
private static RubyHash toJsonRawObject(ThreadContext context,
140
Ruby runtime = context.getRuntime();
141
RubyHash result = RubyHash.newHash(runtime);
143
IRubyObject createId = RuntimeInfo.forRuntime(runtime)
144
.jsonModule.get().callMethod(context, "create_id");
145
result.op_aset(context, createId, self.getMetaClass().to_s());
147
ByteList bl = self.getByteList();
148
byte[] uBytes = bl.unsafeBytes();
149
RubyArray array = runtime.newArray(bl.length());
150
for (int i = bl.begin(), t = bl.begin() + bl.length(); i < t; i++) {
151
array.store(i, runtime.newFixnum(uBytes[i] & 0xff));
154
result.op_aset(context, runtime.newString("raw"), array);
158
@JRubyMethod(required=1, module=true)
159
public static IRubyObject included(ThreadContext context,
160
IRubyObject vSelf, IRubyObject module) {
161
RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime());
162
return module.callMethod(context, "extend", info.stringExtendModule.get());
166
public static class StringExtend {
168
* <code>{@link RubyString String}#json_create(o)</code>
170
* <p>Raw Strings are JSON Objects (the raw bytes are stored in an
171
* array for the key "raw"). The Ruby String can be created by this
174
@JRubyMethod(required=1)
175
public static IRubyObject json_create(ThreadContext context,
176
IRubyObject vSelf, IRubyObject vHash) {
177
Ruby runtime = context.getRuntime();
178
RubyHash o = vHash.convertToHash();
179
IRubyObject rawData = o.fastARef(runtime.newString("raw"));
180
if (rawData == null) {
181
throw runtime.newArgumentError("\"raw\" value not defined "
182
+ "for encoded String");
184
RubyArray ary = Utils.ensureArray(rawData);
185
byte[] bytes = new byte[ary.getLength()];
186
for (int i = 0, t = ary.getLength(); i < t; i++) {
187
IRubyObject element = ary.eltInternal(i);
188
if (element instanceof RubyFixnum) {
189
bytes[i] = (byte)RubyNumeric.fix2long(element);
191
throw runtime.newTypeError(element, runtime.getFixnum());
194
return runtime.newString(new ByteList(bytes, false));
198
public static class RbTrue {
199
@JRubyMethod(rest=true)
200
public static IRubyObject to_json(ThreadContext context,
201
IRubyObject vSelf, IRubyObject[] args) {
202
return Generator.generateJson(context, (RubyBoolean)vSelf,
203
Generator.TRUE_HANDLER, args);
207
public static class RbFalse {
208
@JRubyMethod(rest=true)
209
public static IRubyObject to_json(ThreadContext context,
210
IRubyObject vSelf, IRubyObject[] args) {
211
return Generator.generateJson(context, (RubyBoolean)vSelf,
212
Generator.FALSE_HANDLER, args);
216
public static class RbNil {
217
@JRubyMethod(rest=true)
218
public static IRubyObject to_json(ThreadContext context,
219
IRubyObject vSelf, IRubyObject[] args) {
220
return Generator.generateJson(context, vSelf,
221
Generator.NIL_HANDLER, args);
225
public static class RbObject {
226
@JRubyMethod(rest=true)
227
public static IRubyObject to_json(ThreadContext context,
228
IRubyObject self, IRubyObject[] args) {
229
return RbString.to_json(context, self.asString(), args);