fjson 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|