637b57965df57272a36621af6c79e260626a0598
[packages/precise/mcollective.git] / lib / mcollective / vendor / json / java / src / json / ext / GeneratorMethods.java
1 /*
2  * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3  *
4  * Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
5  * for details.
6  */
7 package json.ext;
8
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;
24
25 /**
26  * A class that populates the
27  * <code>Json::Ext::Generator::GeneratorMethods</code> module.
28  *
29  * @author mernen
30  */
31 class GeneratorMethods {
32     /**
33      * Populates the given module with all modules and their methods
34      * @param info
35      * @param generatorMethodsModule The module to populate
36      * (normally <code>JSON::Generator::GeneratorMethods</code>)
37      */
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);
48
49         info.stringExtendModule = new WeakReference<RubyModule>(module.defineModuleUnder("String")
50                                             .defineModuleUnder("Extend"));
51         info.stringExtendModule.get().defineAnnotatedMethods(StringExtend.class);
52     }
53
54     /**
55      * Convenience method for defining methods on a submodule.
56      * @param parentModule
57      * @param submoduleName
58      * @param klass
59      */
60     private static void defineMethods(RubyModule parentModule,
61             String submoduleName, Class klass) {
62         RubyModule submodule = parentModule.defineModuleUnder(submoduleName);
63         submodule.defineAnnotatedMethods(klass);
64     }
65
66
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);
73         }
74     }
75
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);
82         }
83     }
84
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);
90         }
91     }
92
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);
99         }
100     }
101
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);
108         }
109
110         /**
111          * <code>{@link RubyString String}#to_json_raw(*)</code>
112          *
113          * <p>This method creates a JSON text from the result of a call to
114          * {@link #to_json_raw_object} of this String.
115          */
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);
122         }
123
124         /**
125          * <code>{@link RubyString String}#to_json_raw_object(*)</code>
126          *
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.
131          */
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));
136         }
137
138         private static RubyHash toJsonRawObject(ThreadContext context,
139                                                 RubyString self) {
140             Ruby runtime = context.getRuntime();
141             RubyHash result = RubyHash.newHash(runtime);
142
143             IRubyObject createId = RuntimeInfo.forRuntime(runtime)
144                     .jsonModule.get().callMethod(context, "create_id");
145             result.op_aset(context, createId, self.getMetaClass().to_s());
146
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));
152             }
153
154             result.op_aset(context, runtime.newString("raw"), array);
155             return result;
156         }
157
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());
163         }
164     }
165
166     public static class StringExtend {
167         /**
168          * <code>{@link RubyString String}#json_create(o)</code>
169          *
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
172          * module method.
173          */
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");
183             }
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);
190                 } else {
191                     throw runtime.newTypeError(element, runtime.getFixnum());
192                 }
193             }
194             return runtime.newString(new ByteList(bytes, false));
195         }
196     }
197
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);
204         }
205     }
206
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);
213         }
214     }
215
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);
222         }
223     }
224
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);
230         }
231     }
232 }