scout 5.6.7 → 5.6.8.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. data/CHANGELOG.markdown +4 -0
  2. data/lib/scout/version.rb +1 -1
  3. data/vendor/json_pure/.gitignore +12 -0
  4. data/vendor/json_pure/.travis.yml +20 -0
  5. data/vendor/json_pure/CHANGES +120 -0
  6. data/vendor/json_pure/COPYING-json-jruby +57 -0
  7. data/vendor/json_pure/Gemfile +11 -0
  8. data/vendor/json_pure/README-json-jruby.markdown +33 -0
  9. data/vendor/json_pure/{README → README.rdoc} +7 -7
  10. data/vendor/json_pure/Rakefile +305 -185
  11. data/vendor/json_pure/VERSION +1 -1
  12. data/vendor/json_pure/diagrams/.keep +0 -0
  13. data/vendor/json_pure/ext/json/ext/fbuffer/fbuffer.h +181 -0
  14. data/vendor/json_pure/ext/json/ext/generator/depend +1 -0
  15. data/vendor/json_pure/ext/json/ext/generator/extconf.rb +4 -6
  16. data/vendor/json_pure/ext/json/ext/generator/generator.c +463 -369
  17. data/vendor/json_pure/ext/json/ext/generator/generator.h +44 -66
  18. data/vendor/json_pure/ext/json/ext/parser/depend +1 -0
  19. data/vendor/json_pure/ext/json/ext/parser/extconf.rb +3 -5
  20. data/vendor/json_pure/ext/json/ext/parser/parser.c +580 -311
  21. data/vendor/json_pure/ext/json/ext/parser/parser.h +14 -8
  22. data/vendor/json_pure/ext/json/ext/parser/parser.rl +242 -107
  23. data/vendor/json_pure/install.rb +8 -11
  24. data/vendor/json_pure/java/src/json/ext/ByteListTranscoder.java +167 -0
  25. data/vendor/json_pure/java/src/json/ext/Generator.java +444 -0
  26. data/vendor/json_pure/java/src/json/ext/GeneratorMethods.java +232 -0
  27. data/vendor/json_pure/java/src/json/ext/GeneratorService.java +43 -0
  28. data/vendor/json_pure/java/src/json/ext/GeneratorState.java +543 -0
  29. data/vendor/json_pure/java/src/json/ext/OptionsReader.java +114 -0
  30. data/vendor/json_pure/java/src/json/ext/Parser.java +2644 -0
  31. data/vendor/json_pure/java/src/json/ext/Parser.rl +968 -0
  32. data/vendor/json_pure/java/src/json/ext/ParserService.java +35 -0
  33. data/vendor/json_pure/java/src/json/ext/RuntimeInfo.java +121 -0
  34. data/vendor/json_pure/java/src/json/ext/StringDecoder.java +167 -0
  35. data/vendor/json_pure/java/src/json/ext/StringEncoder.java +106 -0
  36. data/vendor/json_pure/java/src/json/ext/Utils.java +89 -0
  37. data/vendor/json_pure/json-java.gemspec +23 -0
  38. data/vendor/json_pure/json.gemspec +37 -0
  39. data/vendor/json_pure/json_pure.gemspec +39 -0
  40. data/vendor/json_pure/lib/json.rb +52 -0
  41. data/vendor/json_pure/lib/json/add/bigdecimal.rb +28 -0
  42. data/vendor/json_pure/lib/json/add/complex.rb +22 -0
  43. data/vendor/json_pure/lib/json/add/core.rb +9 -146
  44. data/vendor/json_pure/lib/json/add/date.rb +34 -0
  45. data/vendor/json_pure/lib/json/add/date_time.rb +50 -0
  46. data/vendor/json_pure/lib/json/add/exception.rb +31 -0
  47. data/vendor/json_pure/lib/json/add/ostruct.rb +31 -0
  48. data/vendor/json_pure/lib/json/add/range.rb +29 -0
  49. data/vendor/json_pure/lib/json/add/rational.rb +22 -0
  50. data/vendor/json_pure/lib/json/add/regexp.rb +30 -0
  51. data/vendor/json_pure/lib/json/add/struct.rb +30 -0
  52. data/vendor/json_pure/lib/json/add/symbol.rb +25 -0
  53. data/vendor/json_pure/lib/json/add/time.rb +38 -0
  54. data/vendor/json_pure/lib/json/common.rb +157 -67
  55. data/vendor/json_pure/lib/json/ext.rb +8 -2
  56. data/vendor/json_pure/lib/json/ext/.keep +0 -0
  57. data/vendor/json_pure/lib/json/generic_object.rb +70 -0
  58. data/vendor/json_pure/lib/json/pure.rb +8 -64
  59. data/vendor/json_pure/lib/json/pure/generator.rb +183 -113
  60. data/vendor/json_pure/lib/json/pure/parser.rb +118 -66
  61. data/vendor/json_pure/lib/json/version.rb +1 -1
  62. data/vendor/json_pure/tests/fixtures/fail18.json +1 -1
  63. data/vendor/json_pure/tests/setup_variant.rb +11 -0
  64. data/vendor/json_pure/tests/test_json.rb +233 -28
  65. data/vendor/json_pure/tests/test_json_addition.rb +68 -34
  66. data/vendor/json_pure/tests/test_json_encoding.rb +11 -14
  67. data/vendor/json_pure/tests/test_json_fixtures.rb +11 -10
  68. data/vendor/json_pure/tests/test_json_generate.rb +207 -7
  69. data/vendor/json_pure/tests/test_json_generic_object.rb +75 -0
  70. data/vendor/json_pure/tests/test_json_string_matching.rb +39 -0
  71. data/vendor/json_pure/tests/test_json_unicode.rb +3 -7
  72. data/vendor/json_pure/tools/fuzz.rb +1 -1
  73. data/vendor/json_pure/tools/server.rb +1 -0
  74. metadata +87 -94
  75. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkComparison.log +0 -52
  76. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast-autocorrelation.dat +0 -1000
  77. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_fast.dat +0 -1001
  78. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty-autocorrelation.dat +0 -900
  79. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_pretty.dat +0 -901
  80. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe-autocorrelation.dat +0 -1000
  81. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt#generator_safe.dat +0 -1001
  82. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkExt.log +0 -261
  83. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast-autocorrelation.dat +0 -1000
  84. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_fast.dat +0 -1001
  85. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty-autocorrelation.dat +0 -1000
  86. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_pretty.dat +0 -1001
  87. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe-autocorrelation.dat +0 -1000
  88. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure#generator_safe.dat +0 -1001
  89. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkPure.log +0 -262
  90. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator-autocorrelation.dat +0 -1000
  91. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails#generator.dat +0 -1001
  92. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/GeneratorBenchmarkRails.log +0 -82
  93. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkComparison.log +0 -34
  94. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser-autocorrelation.dat +0 -900
  95. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt#parser.dat +0 -901
  96. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkExt.log +0 -81
  97. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser-autocorrelation.dat +0 -1000
  98. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure#parser.dat +0 -1001
  99. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkPure.log +0 -82
  100. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser-autocorrelation.dat +0 -1000
  101. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails#parser.dat +0 -1001
  102. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkRails.log +0 -82
  103. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser-autocorrelation.dat +0 -1000
  104. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML#parser.dat +0 -1001
  105. data/vendor/json_pure/benchmarks/data-p4-3GHz-ruby18/ParserBenchmarkYAML.log +0 -82
  106. data/vendor/json_pure/benchmarks/generator2_benchmark.rb +0 -222
  107. data/vendor/json_pure/benchmarks/generator_benchmark.rb +0 -224
  108. data/vendor/json_pure/benchmarks/ohai.json +0 -1216
  109. data/vendor/json_pure/benchmarks/ohai.ruby +0 -1
  110. data/vendor/json_pure/benchmarks/parser2_benchmark.rb +0 -251
  111. data/vendor/json_pure/benchmarks/parser_benchmark.rb +0 -259
  112. data/vendor/json_pure/bin/edit_json.rb +0 -9
  113. data/vendor/json_pure/bin/prettify_json.rb +0 -75
  114. data/vendor/json_pure/lib/json/Array.xpm +0 -21
  115. data/vendor/json_pure/lib/json/FalseClass.xpm +0 -21
  116. data/vendor/json_pure/lib/json/Hash.xpm +0 -21
  117. data/vendor/json_pure/lib/json/Key.xpm +0 -73
  118. data/vendor/json_pure/lib/json/NilClass.xpm +0 -21
  119. data/vendor/json_pure/lib/json/Numeric.xpm +0 -28
  120. data/vendor/json_pure/lib/json/String.xpm +0 -96
  121. data/vendor/json_pure/lib/json/TrueClass.xpm +0 -21
  122. data/vendor/json_pure/lib/json/add/rails.rb +0 -58
  123. data/vendor/json_pure/lib/json/editor.rb +0 -1371
  124. data/vendor/json_pure/lib/json/json.xpm +0 -1499
  125. data/vendor/json_pure/tests/test_json_rails.rb +0 -144
@@ -1,26 +1,23 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'rbconfig'
4
3
  require 'fileutils'
5
4
  include FileUtils::Verbose
5
+ require 'rbconfig'
6
+ include\
7
+ begin
8
+ RbConfig
9
+ rescue NameError
10
+ Config
11
+ end
6
12
 
7
- include Config
8
-
9
- bindir = CONFIG["bindir"]
10
- cd 'bin' do
11
- filename = 'edit_json.rb'
12
- #install(filename, bindir)
13
- end
14
13
  sitelibdir = CONFIG["sitelibdir"]
15
14
  cd 'lib' do
16
15
  install('json.rb', sitelibdir)
17
16
  mkdir_p File.join(sitelibdir, 'json')
18
- for file in Dir['json/**/*.{rb,xpm}']
17
+ for file in Dir['json/**/*}']
19
18
  d = File.join(sitelibdir, file)
20
19
  mkdir_p File.dirname(d)
21
20
  install(file, d)
22
21
  end
23
- install(File.join('json', 'editor.rb'), File.join(sitelibdir,'json'))
24
- install(File.join('json', 'json.xpm'), File.join(sitelibdir,'json'))
25
22
  end
26
23
  warn " *** Installed PURE ruby library."
@@ -0,0 +1,167 @@
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 org.jruby.exceptions.RaiseException;
10
+ import org.jruby.runtime.ThreadContext;
11
+ import org.jruby.util.ByteList;
12
+
13
+ /**
14
+ * A class specialized in transcoding a certain String format into another,
15
+ * using UTF-8 ByteLists as both input and output.
16
+ */
17
+ abstract class ByteListTranscoder {
18
+ protected final ThreadContext context;
19
+
20
+ protected ByteList src;
21
+ protected int srcEnd;
22
+ /** Position where the last read character started */
23
+ protected int charStart;
24
+ /** Position of the next character to read */
25
+ protected int pos;
26
+
27
+ private ByteList out;
28
+ /**
29
+ * When a character that can be copied straight into the output is found,
30
+ * its index is stored on this variable, and copying is delayed until
31
+ * the sequence of characters that can be copied ends.
32
+ *
33
+ * <p>The variable stores -1 when not in a plain sequence.
34
+ */
35
+ private int quoteStart = -1;
36
+
37
+ protected ByteListTranscoder(ThreadContext context) {
38
+ this.context = context;
39
+ }
40
+
41
+ protected void init(ByteList src, ByteList out) {
42
+ this.init(src, 0, src.length(), out);
43
+ }
44
+
45
+ protected void init(ByteList src, int start, int end, ByteList out) {
46
+ this.src = src;
47
+ this.pos = start;
48
+ this.charStart = start;
49
+ this.srcEnd = end;
50
+ this.out = out;
51
+ }
52
+
53
+ /**
54
+ * Returns whether there are any characters left to be read.
55
+ */
56
+ protected boolean hasNext() {
57
+ return pos < srcEnd;
58
+ }
59
+
60
+ /**
61
+ * Returns the next character in the buffer.
62
+ */
63
+ private char next() {
64
+ return src.charAt(pos++);
65
+ }
66
+
67
+ /**
68
+ * Reads an UTF-8 character from the input and returns its code point,
69
+ * while advancing the input position.
70
+ *
71
+ * <p>Raises an {@link #invalidUtf8()} exception if an invalid byte
72
+ * is found.
73
+ */
74
+ protected int readUtf8Char() {
75
+ charStart = pos;
76
+ char head = next();
77
+ if (head <= 0x7f) { // 0b0xxxxxxx (ASCII)
78
+ return head;
79
+ }
80
+ if (head <= 0xbf) { // 0b10xxxxxx
81
+ throw invalidUtf8(); // tail byte with no head
82
+ }
83
+ if (head <= 0xdf) { // 0b110xxxxx
84
+ ensureMin(1);
85
+ int cp = ((head & 0x1f) << 6)
86
+ | nextPart();
87
+ if (cp < 0x0080) throw invalidUtf8();
88
+ return cp;
89
+ }
90
+ if (head <= 0xef) { // 0b1110xxxx
91
+ ensureMin(2);
92
+ int cp = ((head & 0x0f) << 12)
93
+ | (nextPart() << 6)
94
+ | nextPart();
95
+ if (cp < 0x0800) throw invalidUtf8();
96
+ return cp;
97
+ }
98
+ if (head <= 0xf7) { // 0b11110xxx
99
+ ensureMin(3);
100
+ int cp = ((head & 0x07) << 18)
101
+ | (nextPart() << 12)
102
+ | (nextPart() << 6)
103
+ | nextPart();
104
+ if (!Character.isValidCodePoint(cp)) throw invalidUtf8();
105
+ return cp;
106
+ }
107
+ // 0b11111xxx?
108
+ throw invalidUtf8();
109
+ }
110
+
111
+ /**
112
+ * Throws a GeneratorError if the input list doesn't have at least this
113
+ * many bytes left.
114
+ */
115
+ protected void ensureMin(int n) {
116
+ if (pos + n > srcEnd) throw incompleteUtf8();
117
+ }
118
+
119
+ /**
120
+ * Reads the next byte of a multi-byte UTF-8 character and returns its
121
+ * contents (lower 6 bits).
122
+ *
123
+ * <p>Throws a GeneratorError if the byte is not a valid tail.
124
+ */
125
+ private int nextPart() {
126
+ char c = next();
127
+ // tail bytes must be 0b10xxxxxx
128
+ if ((c & 0xc0) != 0x80) throw invalidUtf8();
129
+ return c & 0x3f;
130
+ }
131
+
132
+
133
+ protected void quoteStart() {
134
+ if (quoteStart == -1) quoteStart = charStart;
135
+ }
136
+
137
+ /**
138
+ * When in a sequence of characters that can be copied directly,
139
+ * interrupts the sequence and copies it to the output buffer.
140
+ *
141
+ * @param endPos The offset until which the direct character quoting should
142
+ * occur. You may pass {@link #pos} to quote until the most
143
+ * recently read character, or {@link #charStart} to quote
144
+ * until the character before it.
145
+ */
146
+ protected void quoteStop(int endPos) {
147
+ if (quoteStart != -1) {
148
+ out.append(src, quoteStart, endPos - quoteStart);
149
+ quoteStart = -1;
150
+ }
151
+ }
152
+
153
+ protected void append(int b) {
154
+ out.append(b);
155
+ }
156
+
157
+ protected void append(byte[] origin, int start, int length) {
158
+ out.append(origin, start, length);
159
+ }
160
+
161
+
162
+ protected abstract RaiseException invalidUtf8();
163
+
164
+ protected RaiseException incompleteUtf8() {
165
+ return invalidUtf8();
166
+ }
167
+ }
@@ -0,0 +1,444 @@
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 org.jruby.Ruby;
10
+ import org.jruby.RubyArray;
11
+ import org.jruby.RubyBignum;
12
+ import org.jruby.RubyBoolean;
13
+ import org.jruby.RubyClass;
14
+ import org.jruby.RubyFixnum;
15
+ import org.jruby.RubyFloat;
16
+ import org.jruby.RubyHash;
17
+ import org.jruby.RubyNumeric;
18
+ import org.jruby.RubyString;
19
+ import org.jruby.runtime.ThreadContext;
20
+ import org.jruby.runtime.builtin.IRubyObject;
21
+ import org.jruby.util.ByteList;
22
+
23
+ public final class Generator {
24
+ private Generator() {
25
+ throw new RuntimeException();
26
+ }
27
+
28
+ /**
29
+ * Encodes the given object as a JSON string, using the given handler.
30
+ */
31
+ static <T extends IRubyObject> RubyString
32
+ generateJson(ThreadContext context, T object,
33
+ Handler<? super T> handler, IRubyObject[] args) {
34
+ Session session = new Session(context, args.length > 0 ? args[0]
35
+ : null);
36
+ return session.infect(handler.generateNew(session, object));
37
+ }
38
+
39
+ /**
40
+ * Encodes the given object as a JSON string, detecting the appropriate handler
41
+ * for the given object.
42
+ */
43
+ static <T extends IRubyObject> RubyString
44
+ generateJson(ThreadContext context, T object, IRubyObject[] args) {
45
+ Handler<? super T> handler = getHandlerFor(context.getRuntime(), object);
46
+ return generateJson(context, object, handler, args);
47
+ }
48
+
49
+ /**
50
+ * Encodes the given object as a JSON string, using the appropriate
51
+ * handler if one is found or calling #to_json if not.
52
+ */
53
+ public static <T extends IRubyObject> RubyString
54
+ generateJson(ThreadContext context, T object,
55
+ GeneratorState config) {
56
+ Session session = new Session(context, config);
57
+ Handler<? super T> handler = getHandlerFor(context.getRuntime(), object);
58
+ return handler.generateNew(session, object);
59
+ }
60
+
61
+ /**
62
+ * Returns the best serialization handler for the given object.
63
+ */
64
+ // Java's generics can't handle this satisfactorily, so I'll just leave
65
+ // the best I could get and ignore the warnings
66
+ @SuppressWarnings("unchecked")
67
+ private static <T extends IRubyObject>
68
+ Handler<? super T> getHandlerFor(Ruby runtime, T object) {
69
+ RubyClass metaClass = object.getMetaClass();
70
+ if (metaClass == runtime.getString()) return (Handler)STRING_HANDLER;
71
+ if (metaClass == runtime.getFixnum()) return (Handler)FIXNUM_HANDLER;
72
+ if (metaClass == runtime.getHash()) return (Handler)HASH_HANDLER;
73
+ if (metaClass == runtime.getArray()) return (Handler)ARRAY_HANDLER;
74
+ if (object.isNil()) return (Handler)NIL_HANDLER;
75
+ if (object == runtime.getTrue()) return (Handler)TRUE_HANDLER;
76
+ if (object == runtime.getFalse()) return (Handler)FALSE_HANDLER;
77
+ if (metaClass == runtime.getFloat()) return (Handler)FLOAT_HANDLER;
78
+ if (metaClass == runtime.getBignum()) return (Handler)BIGNUM_HANDLER;
79
+ return GENERIC_HANDLER;
80
+ }
81
+
82
+
83
+ /* Generator context */
84
+
85
+ /**
86
+ * A class that concentrates all the information that is shared by
87
+ * generators working on a single session.
88
+ *
89
+ * <p>A session is defined as the process of serializing a single root
90
+ * object; any handler directly called by container handlers (arrays and
91
+ * hashes/objects) shares this object with its caller.
92
+ *
93
+ * <p>Note that anything called indirectly (via {@link GENERIC_HANDLER})
94
+ * won't be part of the session.
95
+ */
96
+ static class Session {
97
+ private final ThreadContext context;
98
+ private GeneratorState state;
99
+ private IRubyObject possibleState;
100
+ private RuntimeInfo info;
101
+ private StringEncoder stringEncoder;
102
+
103
+ private boolean tainted = false;
104
+ private boolean untrusted = false;
105
+
106
+ Session(ThreadContext context, GeneratorState state) {
107
+ this.context = context;
108
+ this.state = state;
109
+ }
110
+
111
+ Session(ThreadContext context, IRubyObject possibleState) {
112
+ this.context = context;
113
+ this.possibleState = possibleState == null || possibleState.isNil()
114
+ ? null : possibleState;
115
+ }
116
+
117
+ public ThreadContext getContext() {
118
+ return context;
119
+ }
120
+
121
+ public Ruby getRuntime() {
122
+ return context.getRuntime();
123
+ }
124
+
125
+ public GeneratorState getState() {
126
+ if (state == null) {
127
+ state = GeneratorState.fromState(context, getInfo(), possibleState);
128
+ }
129
+ return state;
130
+ }
131
+
132
+ public RuntimeInfo getInfo() {
133
+ if (info == null) info = RuntimeInfo.forRuntime(getRuntime());
134
+ return info;
135
+ }
136
+
137
+ public StringEncoder getStringEncoder() {
138
+ if (stringEncoder == null) {
139
+ stringEncoder = new StringEncoder(context, getState().asciiOnly());
140
+ }
141
+ return stringEncoder;
142
+ }
143
+
144
+ public void infectBy(IRubyObject object) {
145
+ if (object.isTaint()) tainted = true;
146
+ if (object.isUntrusted()) untrusted = true;
147
+ }
148
+
149
+ public <T extends IRubyObject> T infect(T object) {
150
+ if (tainted) object.setTaint(true);
151
+ if (untrusted) object.setUntrusted(true);
152
+ return object;
153
+ }
154
+ }
155
+
156
+
157
+ /* Handler base classes */
158
+
159
+ private static abstract class Handler<T extends IRubyObject> {
160
+ /**
161
+ * Returns an estimative of how much space the serialization of the
162
+ * given object will take. Used for allocating enough buffer space
163
+ * before invoking other methods.
164
+ */
165
+ int guessSize(Session session, T object) {
166
+ return 4;
167
+ }
168
+
169
+ RubyString generateNew(Session session, T object) {
170
+ RubyString result;
171
+ ByteList buffer = new ByteList(guessSize(session, object));
172
+ generate(session, object, buffer);
173
+ result = RubyString.newString(session.getRuntime(), buffer);
174
+ ThreadContext context = session.getContext();
175
+ RuntimeInfo info = session.getInfo();
176
+ if (info.encodingsSupported()) {
177
+ result.force_encoding(context, info.utf8.get());
178
+ }
179
+ return result;
180
+ }
181
+
182
+ abstract void generate(Session session, T object, ByteList buffer);
183
+ }
184
+
185
+ /**
186
+ * A handler that returns a fixed keyword regardless of the passed object.
187
+ */
188
+ private static class KeywordHandler<T extends IRubyObject>
189
+ extends Handler<T> {
190
+ private final ByteList keyword;
191
+
192
+ private KeywordHandler(String keyword) {
193
+ this.keyword = new ByteList(ByteList.plain(keyword), false);
194
+ }
195
+
196
+ @Override
197
+ int guessSize(Session session, T object) {
198
+ return keyword.length();
199
+ }
200
+
201
+ @Override
202
+ RubyString generateNew(Session session, T object) {
203
+ return RubyString.newStringShared(session.getRuntime(), keyword);
204
+ }
205
+
206
+ @Override
207
+ void generate(Session session, T object, ByteList buffer) {
208
+ buffer.append(keyword);
209
+ }
210
+ }
211
+
212
+
213
+ /* Handlers */
214
+
215
+ static final Handler<RubyBignum> BIGNUM_HANDLER =
216
+ new Handler<RubyBignum>() {
217
+ @Override
218
+ void generate(Session session, RubyBignum object, ByteList buffer) {
219
+ // JRUBY-4751: RubyBignum.to_s() returns generic object
220
+ // representation (fixed in 1.5, but we maintain backwards
221
+ // compatibility; call to_s(IRubyObject[]) then
222
+ buffer.append(((RubyString)object.to_s(IRubyObject.NULL_ARRAY)).getByteList());
223
+ }
224
+ };
225
+
226
+ static final Handler<RubyFixnum> FIXNUM_HANDLER =
227
+ new Handler<RubyFixnum>() {
228
+ @Override
229
+ void generate(Session session, RubyFixnum object, ByteList buffer) {
230
+ buffer.append(object.to_s().getByteList());
231
+ }
232
+ };
233
+
234
+ static final Handler<RubyFloat> FLOAT_HANDLER =
235
+ new Handler<RubyFloat>() {
236
+ @Override
237
+ void generate(Session session, RubyFloat object, ByteList buffer) {
238
+ double value = RubyFloat.num2dbl(object);
239
+
240
+ if (Double.isInfinite(value) || Double.isNaN(value)) {
241
+ if (!session.getState().allowNaN()) {
242
+ throw Utils.newException(session.getContext(),
243
+ Utils.M_GENERATOR_ERROR,
244
+ object + " not allowed in JSON");
245
+ }
246
+ }
247
+ buffer.append(((RubyString)object.to_s()).getByteList());
248
+ }
249
+ };
250
+
251
+ static final Handler<RubyArray> ARRAY_HANDLER =
252
+ new Handler<RubyArray>() {
253
+ @Override
254
+ int guessSize(Session session, RubyArray object) {
255
+ GeneratorState state = session.getState();
256
+ int depth = state.getDepth();
257
+ int perItem =
258
+ 4 // prealloc
259
+ + (depth + 1) * state.getIndent().length() // indent
260
+ + 1 + state.getArrayNl().length(); // ',' arrayNl
261
+ return 2 + object.size() * perItem;
262
+ }
263
+
264
+ @Override
265
+ void generate(Session session, RubyArray object, ByteList buffer) {
266
+ ThreadContext context = session.getContext();
267
+ Ruby runtime = context.getRuntime();
268
+ GeneratorState state = session.getState();
269
+ int depth = state.increaseDepth();
270
+
271
+ ByteList indentUnit = state.getIndent();
272
+ byte[] shift = Utils.repeat(indentUnit, depth);
273
+
274
+ ByteList arrayNl = state.getArrayNl();
275
+ byte[] delim = new byte[1 + arrayNl.length()];
276
+ delim[0] = ',';
277
+ System.arraycopy(arrayNl.unsafeBytes(), arrayNl.begin(), delim, 1,
278
+ arrayNl.length());
279
+
280
+ session.infectBy(object);
281
+
282
+ buffer.append((byte)'[');
283
+ buffer.append(arrayNl);
284
+ boolean firstItem = true;
285
+ for (int i = 0, t = object.getLength(); i < t; i++) {
286
+ IRubyObject element = object.eltInternal(i);
287
+ session.infectBy(element);
288
+ if (firstItem) {
289
+ firstItem = false;
290
+ } else {
291
+ buffer.append(delim);
292
+ }
293
+ buffer.append(shift);
294
+ Handler<IRubyObject> handler = getHandlerFor(runtime, element);
295
+ handler.generate(session, element, buffer);
296
+ }
297
+
298
+ state.decreaseDepth();
299
+ if (arrayNl.length() != 0) {
300
+ buffer.append(arrayNl);
301
+ buffer.append(shift, 0, state.getDepth() * indentUnit.length());
302
+ }
303
+
304
+ buffer.append((byte)']');
305
+ }
306
+ };
307
+
308
+ static final Handler<RubyHash> HASH_HANDLER =
309
+ new Handler<RubyHash>() {
310
+ @Override
311
+ int guessSize(Session session, RubyHash object) {
312
+ GeneratorState state = session.getState();
313
+ int perItem =
314
+ 12 // key, colon, comma
315
+ + (state.getDepth() + 1) * state.getIndent().length()
316
+ + state.getSpaceBefore().length()
317
+ + state.getSpace().length();
318
+ return 2 + object.size() * perItem;
319
+ }
320
+
321
+ @Override
322
+ void generate(final Session session, RubyHash object,
323
+ final ByteList buffer) {
324
+ ThreadContext context = session.getContext();
325
+ final Ruby runtime = context.getRuntime();
326
+ final GeneratorState state = session.getState();
327
+ final int depth = state.increaseDepth();
328
+
329
+ final ByteList objectNl = state.getObjectNl();
330
+ final byte[] indent = Utils.repeat(state.getIndent(), depth);
331
+ final ByteList spaceBefore = state.getSpaceBefore();
332
+ final ByteList space = state.getSpace();
333
+
334
+ buffer.append((byte)'{');
335
+ buffer.append(objectNl);
336
+ object.visitAll(new RubyHash.Visitor() {
337
+ private boolean firstPair = true;
338
+
339
+ @Override
340
+ public void visit(IRubyObject key, IRubyObject value) {
341
+ if (firstPair) {
342
+ firstPair = false;
343
+ } else {
344
+ buffer.append((byte)',');
345
+ buffer.append(objectNl);
346
+ }
347
+ if (objectNl.length() != 0) buffer.append(indent);
348
+
349
+ STRING_HANDLER.generate(session, key.asString(), buffer);
350
+ session.infectBy(key);
351
+
352
+ buffer.append(spaceBefore);
353
+ buffer.append((byte)':');
354
+ buffer.append(space);
355
+
356
+ Handler<IRubyObject> valueHandler = getHandlerFor(runtime, value);
357
+ valueHandler.generate(session, value, buffer);
358
+ session.infectBy(value);
359
+ }
360
+ });
361
+ state.decreaseDepth();
362
+ if (objectNl.length() != 0) {
363
+ buffer.append(objectNl);
364
+ buffer.append(Utils.repeat(state.getIndent(), state.getDepth()));
365
+ }
366
+ buffer.append((byte)'}');
367
+ }
368
+ };
369
+
370
+ static final Handler<RubyString> STRING_HANDLER =
371
+ new Handler<RubyString>() {
372
+ @Override
373
+ int guessSize(Session session, RubyString object) {
374
+ // for most applications, most strings will be just a set of
375
+ // printable ASCII characters without any escaping, so let's
376
+ // just allocate enough space for that + the quotes
377
+ return 2 + object.getByteList().length();
378
+ }
379
+
380
+ @Override
381
+ void generate(Session session, RubyString object, ByteList buffer) {
382
+ RuntimeInfo info = session.getInfo();
383
+ RubyString src;
384
+
385
+ if (info.encodingsSupported() &&
386
+ object.encoding(session.getContext()) != info.utf8.get()) {
387
+ src = (RubyString)object.encode(session.getContext(),
388
+ info.utf8.get());
389
+ } else {
390
+ src = object;
391
+ }
392
+
393
+ session.getStringEncoder().encode(src.getByteList(), buffer);
394
+ }
395
+ };
396
+
397
+ static final Handler<RubyBoolean> TRUE_HANDLER =
398
+ new KeywordHandler<RubyBoolean>("true");
399
+ static final Handler<RubyBoolean> FALSE_HANDLER =
400
+ new KeywordHandler<RubyBoolean>("false");
401
+ static final Handler<IRubyObject> NIL_HANDLER =
402
+ new KeywordHandler<IRubyObject>("null");
403
+
404
+ /**
405
+ * The default handler (<code>Object#to_json</code>): coerces the object
406
+ * to string using <code>#to_s</code>, and serializes that string.
407
+ */
408
+ static final Handler<IRubyObject> OBJECT_HANDLER =
409
+ new Handler<IRubyObject>() {
410
+ @Override
411
+ RubyString generateNew(Session session, IRubyObject object) {
412
+ RubyString str = object.asString();
413
+ return STRING_HANDLER.generateNew(session, str);
414
+ }
415
+
416
+ @Override
417
+ void generate(Session session, IRubyObject object, ByteList buffer) {
418
+ RubyString str = object.asString();
419
+ STRING_HANDLER.generate(session, str, buffer);
420
+ }
421
+ };
422
+
423
+ /**
424
+ * A handler that simply calls <code>#to_json(state)</code> on the
425
+ * given object.
426
+ */
427
+ static final Handler<IRubyObject> GENERIC_HANDLER =
428
+ new Handler<IRubyObject>() {
429
+ @Override
430
+ RubyString generateNew(Session session, IRubyObject object) {
431
+ IRubyObject result =
432
+ object.callMethod(session.getContext(), "to_json",
433
+ new IRubyObject[] {session.getState()});
434
+ if (result instanceof RubyString) return (RubyString)result;
435
+ throw session.getRuntime().newTypeError("to_json must return a String");
436
+ }
437
+
438
+ @Override
439
+ void generate(Session session, IRubyObject object, ByteList buffer) {
440
+ RubyString result = generateNew(session, object);
441
+ buffer.append(result.getByteList());
442
+ }
443
+ };
444
+ }