fjson 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +5 -5
- data/README +7 -8
- data/Rakefile +56 -17
- data/TODO +1 -0
- data/ext/extensions/array_ext/array_ext.c +118 -0
- data/ext/extensions/array_ext/array_ext.h +12 -0
- data/ext/extensions/array_ext/extconf.rb +7 -0
- data/ext/extensions/false_class_ext/extconf.rb +5 -0
- data/ext/extensions/false_class_ext/false_class_ext.c +19 -0
- data/ext/extensions/false_class_ext/false_class_ext.h +4 -0
- data/ext/extensions/float_ext/extconf.rb +5 -0
- data/ext/extensions/float_ext/float_ext.c +19 -0
- data/ext/extensions/float_ext/float_ext.h +4 -0
- data/ext/extensions/hash_ext/extconf.rb +7 -0
- data/ext/extensions/hash_ext/hash_ext.c +128 -0
- data/ext/extensions/hash_ext/hash_ext.h +13 -0
- data/ext/extensions/integer_ext/extconf.rb +5 -0
- data/ext/extensions/integer_ext/integer_ext.c +19 -0
- data/ext/extensions/integer_ext/integer_ext.h +4 -0
- data/ext/extensions/nil_class_ext/extconf.rb +5 -0
- data/ext/extensions/nil_class_ext/nil_class_ext.c +19 -0
- data/ext/extensions/nil_class_ext/nil_class_ext.h +4 -0
- data/ext/extensions/object_ext/extconf.rb +5 -0
- data/ext/extensions/object_ext/object_ext.c +21 -0
- data/ext/extensions/object_ext/object_ext.h +4 -0
- data/ext/extensions/string_ext/extconf.rb +5 -0
- data/ext/extensions/string_ext/string_ext.c +27 -0
- data/ext/extensions/string_ext/string_ext.h +4 -0
- data/ext/extensions/true_class_ext/extconf.rb +5 -0
- data/ext/extensions/true_class_ext/true_class_ext.c +19 -0
- data/ext/extensions/true_class_ext/true_class_ext.h +4 -0
- data/ext/json_ext/extconf.rb +5 -0
- data/ext/json_ext/json_ext.c +180 -0
- data/ext/json_ext/json_ext.h +9 -0
- data/ext/state_ext/extconf.rb +5 -0
- data/ext/state_ext/state_ext.c +169 -0
- data/ext/state_ext/state_ext.h +14 -0
- data/hash_benchmark.rb +15 -0
- data/install.rb +21 -0
- data/rake_helper.rb +34 -0
- metadata +52 -20
- data/VERSION +0 -1
- data/lib/extensions/array_ext.so +0 -0
- data/lib/extensions/false_class_ext.so +0 -0
- data/lib/extensions/float_ext.so +0 -0
- data/lib/extensions/hash_ext.so +0 -0
- data/lib/extensions/integer_ext.so +0 -0
- data/lib/extensions/nil_class_ext.so +0 -0
- data/lib/extensions/object_ext.so +0 -0
- data/lib/extensions/string_ext.so +0 -0
- data/lib/extensions/true_class_ext.so +0 -0
- data/lib/json_ext.so +0 -0
- data/lib/state_ext.so +0 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include <string.h>
|
3
|
+
#include "../../state_ext/state_ext.h"
|
4
|
+
#include "../../state_ext/state_ext.c"
|
5
|
+
|
6
|
+
static VALUE json_shift(VALUE, VALUE, VALUE, VALUE);
|
7
|
+
static VALUE generate_key_value_json(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE);
|
8
|
+
static VALUE process_internal_json(VALUE, VALUE, VALUE, VALUE, VALUE);
|
9
|
+
static VALUE json_transform(VALUE, VALUE, VALUE);
|
10
|
+
static VALUE json_check_circular_and_transform_call(VALUE);
|
11
|
+
static VALUE json_check_circular_and_transform_ensure(VALUE);
|
12
|
+
static VALUE json_check_circular_and_transform(VALUE, VALUE, VALUE);
|
13
|
+
static VALUE to_json(int, VALUE*, VALUE);
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#include "integer_ext.h"
|
2
|
+
|
3
|
+
static VALUE cInteger;
|
4
|
+
|
5
|
+
void Init_integer_ext() {
|
6
|
+
cInteger = rb_const_get(rb_cObject, rb_intern("Integer"));
|
7
|
+
rb_define_method(cInteger, "to_json", (VALUE(*)(ANYARGS)) &to_json, -1);
|
8
|
+
}
|
9
|
+
|
10
|
+
/**
|
11
|
+
* Returns a JSON string representation for this Integer number.
|
12
|
+
*/
|
13
|
+
static VALUE to_json(argc, argv, self)
|
14
|
+
int argc;
|
15
|
+
VALUE *argv;
|
16
|
+
VALUE self;
|
17
|
+
{
|
18
|
+
return rb_funcall(self, rb_intern("to_s"), 0);
|
19
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#include "nil_class_ext.h"
|
2
|
+
|
3
|
+
static VALUE cNilClass;
|
4
|
+
|
5
|
+
void Init_nil_class_ext() {
|
6
|
+
cNilClass = rb_const_get(rb_cObject, rb_intern("NilClass"));
|
7
|
+
rb_define_method(cNilClass, "to_json", (VALUE(*)(ANYARGS)) &to_json, -1);
|
8
|
+
}
|
9
|
+
|
10
|
+
/**
|
11
|
+
* Returns a JSON string for nil: 'null'.
|
12
|
+
*/
|
13
|
+
static VALUE to_json(argc, argv, self)
|
14
|
+
int argc;
|
15
|
+
VALUE *argv;
|
16
|
+
VALUE self;
|
17
|
+
{
|
18
|
+
return rb_str_new2("null");
|
19
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#include "object_ext.h"
|
2
|
+
|
3
|
+
void Init_object_ext() {
|
4
|
+
rb_define_method(rb_cObject, "to_json", (VALUE(*)(ANYARGS)) &to_json, -1);
|
5
|
+
}
|
6
|
+
|
7
|
+
/**
|
8
|
+
* Converts this object to a string (calling #to_s), converts
|
9
|
+
* it to a JSON string, and returns the result. This is a fallback, if no
|
10
|
+
* special method #to_json was defined for some object.
|
11
|
+
* _state_ is a JSON::State object, that can also be used
|
12
|
+
* to configure the produced JSON string output further.
|
13
|
+
*/
|
14
|
+
static VALUE to_json(argc, argv, self)
|
15
|
+
int argc;
|
16
|
+
VALUE *argv;
|
17
|
+
VALUE self;
|
18
|
+
{
|
19
|
+
VALUE self_string = rb_funcall(self, rb_intern("to_s"), 0);
|
20
|
+
return rb_funcall(self_string, rb_intern("to_json"), 0);
|
21
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#include "string_ext.h"
|
2
|
+
|
3
|
+
static VALUE cString;
|
4
|
+
|
5
|
+
void Init_string_ext() {
|
6
|
+
cString = rb_const_get(rb_cObject, rb_intern("String"));
|
7
|
+
rb_define_method(cString, "to_json", (VALUE(*)(ANYARGS)) &to_json, -1);
|
8
|
+
}
|
9
|
+
|
10
|
+
/**
|
11
|
+
* This string should be encoded with UTF-8 (if JSON unicode support is
|
12
|
+
* enabled). A call to this method returns a JSON string
|
13
|
+
* encoded with UTF16 big endian characters as \u????. If
|
14
|
+
* JSON.support_unicode? is false only control characters are encoded this
|
15
|
+
* way, all 8-bit bytes are just passed through.
|
16
|
+
*/
|
17
|
+
static VALUE to_json(argc, argv, self)
|
18
|
+
int argc;
|
19
|
+
VALUE *argv;
|
20
|
+
VALUE self;
|
21
|
+
{
|
22
|
+
VALUE mJSON = rb_const_get(rb_cObject, rb_intern("JSON"));
|
23
|
+
VALUE json = rb_str_new2("\"");
|
24
|
+
rb_str_append(json, rb_funcall(mJSON, rb_intern("utf8_to_json"), 1, self));
|
25
|
+
rb_str_append(json, rb_str_new2("\""));
|
26
|
+
return json;
|
27
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#include "true_class_ext.h"
|
2
|
+
|
3
|
+
static VALUE cTrueClass;
|
4
|
+
|
5
|
+
void Init_true_class_ext() {
|
6
|
+
cTrueClass = rb_const_get(rb_cObject, rb_intern("TrueClass"));
|
7
|
+
rb_define_method(cTrueClass, "to_json", (VALUE(*)(ANYARGS)) &to_json, -1);
|
8
|
+
}
|
9
|
+
|
10
|
+
/**
|
11
|
+
* Returns a JSON string for true: 'true'.
|
12
|
+
*/
|
13
|
+
static VALUE to_json(argc, argv, self)
|
14
|
+
int argc;
|
15
|
+
VALUE *argv;
|
16
|
+
VALUE self;
|
17
|
+
{
|
18
|
+
return rb_funcall(self, rb_intern("to_s"), 0);
|
19
|
+
}
|
@@ -0,0 +1,180 @@
|
|
1
|
+
#include "json_ext.h"
|
2
|
+
|
3
|
+
static VALUE mJSON;
|
4
|
+
static VALUE mJSONModuleMethods;
|
5
|
+
static VALUE cStandardError;
|
6
|
+
static VALUE cJSONError;
|
7
|
+
static VALUE cParserError;
|
8
|
+
static VALUE cUnparserError;
|
9
|
+
static VALUE cCircularDatastructure;
|
10
|
+
|
11
|
+
void Init_json_ext() {
|
12
|
+
mJSON = rb_define_module("JSON");
|
13
|
+
mJSONModuleMethods = rb_define_module_under(mJSON, "ModuleMethods");
|
14
|
+
|
15
|
+
_begin_setup_iconv();
|
16
|
+
|
17
|
+
rb_define_method(mJSONModuleMethods, "utf8_to_json", utf8_to_json, 1);
|
18
|
+
rb_define_method(mJSONModuleMethods, "utf8_to_utf16", utf8_to_utf16, 1);
|
19
|
+
|
20
|
+
cStandardError = rb_const_get(rb_cObject,rb_intern("StandardError"));
|
21
|
+
/**
|
22
|
+
* The base exception for JSON errors.
|
23
|
+
*/
|
24
|
+
cJSONError = rb_define_class_under(mJSON, "JSONError", cStandardError);
|
25
|
+
|
26
|
+
/**
|
27
|
+
* This exception is raise, if a parser error occurs.
|
28
|
+
*/
|
29
|
+
cParserError = rb_define_class_under(mJSON, "ParserError", cJSONError);
|
30
|
+
|
31
|
+
/**
|
32
|
+
* This exception is raise, if a unparser error occurs.
|
33
|
+
*/
|
34
|
+
cUnparserError = rb_define_class_under(mJSON, "UnparserError", cJSONError);
|
35
|
+
|
36
|
+
/**
|
37
|
+
* If a circular data structure is encountered while unparsing this exception is raised.
|
38
|
+
*/
|
39
|
+
cCircularDatastructure = rb_define_class_under(mJSON, "CircularDatastructure", cUnparserError);
|
40
|
+
}
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Convert _string_ from UTF8 encoding to UTF16 (big endian) encoding and return it.
|
44
|
+
*/
|
45
|
+
static VALUE utf8_to_utf16(self, string)
|
46
|
+
VALUE self, string;
|
47
|
+
{
|
48
|
+
VALUE mUTF8toUTF16 = rb_const_get(mJSON, rb_intern("UTF8toUTF16"));
|
49
|
+
VALUE packed_bytes = rb_funcall(mUTF8toUTF16, rb_intern("iconv"), 1, string);
|
50
|
+
VALUE unpacked_bytes = rb_funcall(packed_bytes, rb_intern("unpack"), 1, rb_str_new2("H*"));
|
51
|
+
return rb_ary_entry(unpacked_bytes, 0);
|
52
|
+
}
|
53
|
+
|
54
|
+
static VALUE utf8_to_json(self, input)
|
55
|
+
VALUE self, input;
|
56
|
+
{
|
57
|
+
VALUE length = rb_funcall(input, rb_intern("length"), 0);
|
58
|
+
long c_length = NUM2LONG(length);
|
59
|
+
|
60
|
+
VALUE result = rb_str_new2("");
|
61
|
+
|
62
|
+
int c_increment_length;
|
63
|
+
size_t i = 0;
|
64
|
+
while(i < c_length) {
|
65
|
+
c_increment_length = _convert_utf8_char(input, i, result);
|
66
|
+
i += c_increment_length;
|
67
|
+
}
|
68
|
+
|
69
|
+
return result;
|
70
|
+
}
|
71
|
+
|
72
|
+
/** private **/
|
73
|
+
|
74
|
+
static void _begin_setup_iconv() {
|
75
|
+
rb_require("iconv");
|
76
|
+
VALUE mIconv = rb_const_get(rb_cObject, rb_intern("Iconv"));
|
77
|
+
|
78
|
+
VALUE mUTF8toUTF16 = rb_funcall(mIconv, rb_intern("new"), 2, rb_str_new2("utf-8"), rb_str_new2("utf-16be"));
|
79
|
+
rb_const_set(
|
80
|
+
mJSON,
|
81
|
+
rb_intern("UTF16toUTF8"),
|
82
|
+
mUTF8toUTF16
|
83
|
+
);
|
84
|
+
|
85
|
+
VALUE mUTF16toUTF8 = rb_funcall(mIconv, rb_intern("new"), 2, rb_str_new2("utf-16be"), rb_str_new2("utf-8"));
|
86
|
+
rb_const_set(
|
87
|
+
mJSON,
|
88
|
+
rb_intern("UTF8toUTF16"),
|
89
|
+
mUTF16toUTF8
|
90
|
+
);
|
91
|
+
|
92
|
+
rb_funcall(mUTF16toUTF8, rb_intern("iconv"), 1, rb_str_new2("no bom"));
|
93
|
+
}
|
94
|
+
|
95
|
+
static long _convert_utf8_char(input, i, result)
|
96
|
+
VALUE input;
|
97
|
+
long i;
|
98
|
+
VALUE result;
|
99
|
+
{
|
100
|
+
long c_increment_length = 1;
|
101
|
+
if (i < 0 || RSTRING(input)->len <= i) {
|
102
|
+
return Qnil;
|
103
|
+
}
|
104
|
+
char c_current = (RSTRING(input)->ptr[i] & 0xff);
|
105
|
+
|
106
|
+
if(c_current == 0x08) {
|
107
|
+
rb_str_cat2(result, "\\b");
|
108
|
+
}
|
109
|
+
else if(c_current == 0x09) {
|
110
|
+
rb_str_cat2(result, "\\t");
|
111
|
+
}
|
112
|
+
else if(c_current == 0x0A) {
|
113
|
+
rb_str_cat2(result, "\\n");
|
114
|
+
}
|
115
|
+
else if(c_current == 0x0C) {
|
116
|
+
rb_str_cat2(result, "\\f");
|
117
|
+
}
|
118
|
+
else if(c_current == 0x0D) {
|
119
|
+
rb_str_cat2(result, "\\r");
|
120
|
+
}
|
121
|
+
else if(c_current == '"') {
|
122
|
+
rb_str_cat2(result, "\\\"");
|
123
|
+
}
|
124
|
+
else if(c_current == '\\') {
|
125
|
+
rb_str_cat2(result, "\\\\");
|
126
|
+
}
|
127
|
+
else if(0x00 <= c_current && c_current <= 0x1f) {
|
128
|
+
VALUE format_string = rb_str_new2("\\u%04x");
|
129
|
+
rb_str_append(result, rb_funcall(format_string, rb_intern("%"), 1, LONG2NUM(c_current)));
|
130
|
+
}
|
131
|
+
else if(0x20 <= c_current && c_current <= 0x7f) {
|
132
|
+
rb_str_concat(result, LONG2NUM(c_current));
|
133
|
+
}
|
134
|
+
else if(
|
135
|
+
!(
|
136
|
+
rb_funcall(mJSON, rb_intern("support_unicode?"), 0) == Qtrue &&
|
137
|
+
rb_equal(rb_gv_get("KCODE"), rb_str_new2("UTF8"))
|
138
|
+
)) {
|
139
|
+
VALUE current = rb_funcall(input, rb_intern("[]"), 1, LONG2NUM(i));
|
140
|
+
rb_str_concat(result, current);
|
141
|
+
}
|
142
|
+
// else if((c_current & 0xe0) == 0xc0) {
|
143
|
+
// c_increment_length = 2;
|
144
|
+
// _convert_utf_8_string_part(result, input, i, c_increment_length);
|
145
|
+
// }
|
146
|
+
// else if((c_current & 0xf0) == 0xe0) {
|
147
|
+
// c_increment_length = 3;
|
148
|
+
// _convert_utf_8_string_part(result, input, i, c_increment_length);
|
149
|
+
// }
|
150
|
+
// else if((c_current & 0xf8) == 0xf0) {
|
151
|
+
// c_increment_length = 4;
|
152
|
+
// _convert_utf_8_string_part(result, input, i, c_increment_length);
|
153
|
+
// }
|
154
|
+
// // TODO: See if these next two steps are valid unicode.
|
155
|
+
// else if((c_current & 0xf8) == 0xf8) {
|
156
|
+
// c_increment_length = 5;
|
157
|
+
// _convert_utf_8_string_part(result, input, i, c_increment_length);
|
158
|
+
// }
|
159
|
+
// else if((c_current & 0xf8) == 0xfc) {
|
160
|
+
// c_increment_length = 6;
|
161
|
+
// _convert_utf_8_string_part(result, input, i, c_increment_length);
|
162
|
+
// }
|
163
|
+
else {
|
164
|
+
VALUE current = rb_funcall(input, rb_intern("[]"), 1, LONG2NUM(i));
|
165
|
+
rb_str_concat(result, current);
|
166
|
+
}
|
167
|
+
|
168
|
+
return c_increment_length;
|
169
|
+
}
|
170
|
+
|
171
|
+
static VALUE _convert_utf_8_string_part(result, input, i, length)
|
172
|
+
VALUE result, input;
|
173
|
+
long i, length;
|
174
|
+
{
|
175
|
+
rb_str_cat2(result, "\\u");
|
176
|
+
VALUE utf_header = rb_funcall(input, rb_intern("[]"), 2, LONG2NUM(i), LONG2NUM(length));
|
177
|
+
rb_str_append(result, utf8_to_utf16(mJSON, utf_header));
|
178
|
+
|
179
|
+
return Qnil;
|
180
|
+
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include <string.h>
|
3
|
+
|
4
|
+
static VALUE utf8_to_utf16(VALUE, VALUE);
|
5
|
+
static VALUE _convert_utf_8_string_part(VALUE, VALUE, long, long);
|
6
|
+
static long _convert_utf8_char(VALUE, long, VALUE);
|
7
|
+
static VALUE utf8_to_json(VALUE, VALUE);
|
8
|
+
static void _begin_setup_iconv();
|
9
|
+
void Init_json_ext();
|
@@ -0,0 +1,169 @@
|
|
1
|
+
#include "state_ext.h"
|
2
|
+
|
3
|
+
static VALUE cState;
|
4
|
+
static VALUE mClassMethods;
|
5
|
+
static VALUE mJSON;
|
6
|
+
|
7
|
+
/**
|
8
|
+
* This class is used to create State instances, that are used to hold data
|
9
|
+
* while unparsing a Ruby data structure into a JSON string.
|
10
|
+
*/
|
11
|
+
void Init_state_ext() {
|
12
|
+
mJSON = rb_const_get(rb_cObject, rb_intern("JSON"));
|
13
|
+
cState = rb_define_class_under(mJSON, "State", rb_cObject);
|
14
|
+
mClassMethods = rb_define_module_under(cState, "ClassMethods");
|
15
|
+
|
16
|
+
rb_define_method(mClassMethods, "from_state", from_state, 1);
|
17
|
+
rb_extend_object(cState, mClassMethods);
|
18
|
+
|
19
|
+
rb_define_method(cState, "initialize", initialize, -1);
|
20
|
+
rb_define_method(cState, "seen?", seen, 1);
|
21
|
+
rb_define_method(cState, "remember", remember, 1);
|
22
|
+
rb_define_method(cState, "forget", forget, 1);
|
23
|
+
|
24
|
+
/*
|
25
|
+
* This string is used to indent levels in the JSON string.
|
26
|
+
*/
|
27
|
+
rb_define_method(cState, "indent", get_indent, 0);
|
28
|
+
rb_define_method(cState, "indent=", set_indent, 1);
|
29
|
+
|
30
|
+
/*
|
31
|
+
* This string is used to include a space between the tokens in a JSON string.
|
32
|
+
*/
|
33
|
+
rb_define_attr(cState, "space", 1, 1);
|
34
|
+
|
35
|
+
/*
|
36
|
+
* This string is put at the end of a line that holds a JSON object (or Hash).
|
37
|
+
*/
|
38
|
+
rb_define_attr(cState, "object_nl", 1, 1);
|
39
|
+
|
40
|
+
/*
|
41
|
+
* This string is put at the end of a line that holds a JSON array.
|
42
|
+
*/
|
43
|
+
rb_define_attr(cState, "array_nl", 1, 1);
|
44
|
+
}
|
45
|
+
|
46
|
+
void rb_json_state_indent(state, json, depth)
|
47
|
+
VALUE state, json;
|
48
|
+
long depth;
|
49
|
+
{
|
50
|
+
VALUE indent = rb_funcall(state, rb_intern("indent"), 0);
|
51
|
+
char* c_indent = StringValueCStr(indent);
|
52
|
+
// Incrementing the depth
|
53
|
+
char* full_indent;
|
54
|
+
long i;
|
55
|
+
for(i=0; i<depth; i++) {
|
56
|
+
strcat(full_indent, c_indent);
|
57
|
+
}
|
58
|
+
rb_str_cat2(json, full_indent);
|
59
|
+
}
|
60
|
+
|
61
|
+
/** Static **/
|
62
|
+
|
63
|
+
/**
|
64
|
+
* Instantiates a new State object, configured by _opts_.
|
65
|
+
*/
|
66
|
+
static VALUE initialize(argc, argv, self)
|
67
|
+
int argc;
|
68
|
+
VALUE *argv;
|
69
|
+
VALUE self;
|
70
|
+
{
|
71
|
+
VALUE opts;
|
72
|
+
rb_scan_args(argc, argv, "01", &opts);
|
73
|
+
|
74
|
+
VALUE indent, space, object_nl, array_nl;
|
75
|
+
if(opts == Qnil) {
|
76
|
+
indent = rb_str_new2("");
|
77
|
+
space = rb_str_new2("");
|
78
|
+
object_nl = rb_str_new2("");
|
79
|
+
array_nl = rb_str_new2("");
|
80
|
+
}
|
81
|
+
else {
|
82
|
+
indent = hash_value_or_empty_string_default(opts, "indent");
|
83
|
+
space = hash_value_or_empty_string_default(opts, "space");
|
84
|
+
object_nl = hash_value_or_empty_string_default(opts, "object_nl");
|
85
|
+
array_nl = hash_value_or_empty_string_default(opts, "array_nl");
|
86
|
+
}
|
87
|
+
|
88
|
+
rb_ivar_set(self, rb_intern("@indent"), indent);
|
89
|
+
rb_ivar_set(self, rb_intern("@space"), space);
|
90
|
+
rb_ivar_set(self, rb_intern("@object_nl"), object_nl);
|
91
|
+
rb_ivar_set(self, rb_intern("@array_nl"), array_nl);
|
92
|
+
rb_ivar_set(self, rb_intern("@seen"), rb_hash_new());
|
93
|
+
}
|
94
|
+
|
95
|
+
static VALUE get_indent(self)
|
96
|
+
VALUE self;
|
97
|
+
{
|
98
|
+
return rb_ivar_get(self, rb_intern("@indent"));
|
99
|
+
}
|
100
|
+
|
101
|
+
static VALUE set_indent(self, indent)
|
102
|
+
VALUE self, indent;
|
103
|
+
{
|
104
|
+
rb_ivar_set(self, rb_intern("@indent"), indent);
|
105
|
+
}
|
106
|
+
|
107
|
+
/**
|
108
|
+
* Creates a State object from _opts_, which ought to be Hash to create a
|
109
|
+
* new State instance configured by opts, something else to create an
|
110
|
+
* unconfigured instance. If _opts_ is a State object, it is just returned.
|
111
|
+
*/
|
112
|
+
static VALUE from_state(self, opts)
|
113
|
+
VALUE self, opts;
|
114
|
+
{
|
115
|
+
if(rb_obj_is_kind_of(opts, cState)) {
|
116
|
+
return opts;
|
117
|
+
}
|
118
|
+
else if(rb_obj_is_kind_of(opts, rb_cHash)) {
|
119
|
+
return rb_funcall(self, rb_intern("new"), 1, opts);
|
120
|
+
}
|
121
|
+
else {
|
122
|
+
return rb_funcall(self, rb_intern("new"), 0);
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
/**
|
127
|
+
* Returns _true_, if _object_ was already seen during this Unparsing run.
|
128
|
+
*/
|
129
|
+
static VALUE seen(self, object)
|
130
|
+
VALUE self, object;
|
131
|
+
{
|
132
|
+
VALUE seen_ivar = rb_ivar_get(self, rb_intern("@seen"));
|
133
|
+
return rb_hash_aref(seen_ivar, rb_obj_id(object));
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
* Remember _object_, to find out if it was already encountered (to find out
|
138
|
+
* if a cyclic data structure is unparsed).
|
139
|
+
*/
|
140
|
+
static VALUE remember(self, object)
|
141
|
+
VALUE self, object;
|
142
|
+
{
|
143
|
+
VALUE seen_ivar = rb_ivar_get(self, rb_intern("@seen"));
|
144
|
+
rb_hash_aset(seen_ivar, rb_obj_id(object), Qtrue);
|
145
|
+
}
|
146
|
+
|
147
|
+
/**
|
148
|
+
* Forget _object_ for this Unparsing run.
|
149
|
+
*/
|
150
|
+
static VALUE forget(self, object)
|
151
|
+
VALUE self, object;
|
152
|
+
{
|
153
|
+
VALUE seen_ivar = rb_ivar_get(self, rb_intern("@seen"));
|
154
|
+
rb_hash_delete(seen_ivar, rb_obj_id(object));
|
155
|
+
}
|
156
|
+
|
157
|
+
/** private **/
|
158
|
+
static VALUE hash_value_or_empty_string_default(hash, cKey)
|
159
|
+
VALUE hash;
|
160
|
+
const char* cKey;
|
161
|
+
{
|
162
|
+
VALUE hash_value = rb_hash_aref(hash, ID2SYM(rb_intern(cKey)));
|
163
|
+
if(hash_value == Qnil) {
|
164
|
+
return rb_str_new2("");
|
165
|
+
}
|
166
|
+
else {
|
167
|
+
return hash_value;
|
168
|
+
}
|
169
|
+
}
|