yaji 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ *.so
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
6
+ tmp/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in ijson.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
data/README.markdown ADDED
@@ -0,0 +1,84 @@
1
+ Yet another JSON iterator
2
+ =========================
3
+
4
+ YAJI is a ruby wrapper to YAJL providing iterator interface to streaming JSON parser.
5
+
6
+ USAGE
7
+ -----
8
+
9
+ YAJI::Parser initializer accepts `IO` instance or `String`.
10
+
11
+ require 'yaji'
12
+
13
+ YAJI::Parser.new('{"foo":"bar"}')
14
+ YAJI::Parser.new(File.open('data.json'))
15
+
16
+ Parser instance provides two iterators to get JSON data: event-oriented
17
+ and object-oriented. `YAJI::Parser#parse` yields tuple `[path, event,
18
+ value] describing some parser event. For example, this code
19
+
20
+ parser = YAJI::Parser.new('{"foo":[1, {"bar":"baz"}]}')
21
+ parser.parse do |path, event, value|
22
+ puts [path, event, value].inspect
23
+ end
24
+
25
+ prints all parser events
26
+
27
+ ["", :start_hash, nil]
28
+ ["", :hash_key, "foo"]
29
+ ["foo", :start_array, nil]
30
+ ["foo/", :number, 1]
31
+ ["foo/", :start_hash, nil]
32
+ ["foo/", :hash_key, "bar"]
33
+ ["foo//bar", :string, "baz"]
34
+ ["foo/", :end_hash, nil]
35
+ ["foo", :end_array, nil]
36
+ ["", :end_hash, nil]
37
+
38
+ You can call `#parse` method without block and it will return
39
+ `Enumerator` object.
40
+
41
+ The another approach is to use `YAJI::Parser#each` method to iterate
42
+ over JSON objects. It accepts optional filter parameter if you'd like to
43
+ iterated sub-objects. Here is the example
44
+
45
+ parser = YAJI::Parser.new('{"size":2,"items":[{"id":1}, {"id":2}]}')
46
+ parser.each do |obj|
47
+ puts obj.inspect
48
+ end
49
+
50
+ will print only one line:
51
+
52
+ {"size"=>2, "items"=>[{"id"=>1}, {"id"=>2}]}
53
+
54
+ But it might be more useful to yield items from inner array:
55
+
56
+ parser = YAJI::Parser.new('{"size":2,"items":[{"id":1}, {"id":2}]}')
57
+ parser.each("items/") do |obj|
58
+ puts obj.inspect
59
+ end
60
+
61
+ code above will print two lines:
62
+
63
+ {"id"=>1}
64
+ {"id"=>2}
65
+
66
+ You can use this iterator when the data is huge and you'd like to allow
67
+ GC to collect yielded object before parser finish its job.
68
+
69
+ LICENSE
70
+ -------
71
+
72
+ Copyright 2011 Couchbase, Inc.
73
+
74
+ Licensed under the Apache License, Version 2.0 (the "License");
75
+ you may not use this file except in compliance with the License.
76
+ You may obtain a copy of the License at
77
+
78
+ http://www.apache.org/licenses/LICENSE-2.0
79
+
80
+ Unless required by applicable law or agreed to in writing, software
81
+ distributed under the License is distributed on an "AS IS" BASIS,
82
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
83
+ See the License for the specific language governing permissions and
84
+ limitations under the License.
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/gem_tasks"
2
+ Dir['tasks/*.rake'].sort.each { |f| load f }
3
+
@@ -0,0 +1,16 @@
1
+ # encoding: UTF-8
2
+ require 'mkmf'
3
+ require 'rbconfig'
4
+
5
+ def define(macro, value = nil)
6
+ $defs.push("-D #{[macro.upcase, value].compact.join('=')}")
7
+ end
8
+
9
+ $CFLAGS << ' -Wall -funroll-loops'
10
+ $CFLAGS << ' -Wextra -O0 -ggdb3' if ENV['DEBUG']
11
+
12
+ have_library('yajl', 'yajl_parse', 'yajl/yajl_parse.h')
13
+ define("READ_BUFSIZE", "8192")
14
+
15
+ create_header("yaji_config.h")
16
+ create_makefile("parser_ext")
@@ -0,0 +1,370 @@
1
+ /*
2
+ * Author:: Couchbase <info@couchbase.com>
3
+ * Copyright:: 2011 Couchbase, Inc.
4
+ * License:: Apache License, Version 2.0
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ #include "parser_ext.h"
20
+
21
+ #define STATUS_CONTINUE 1
22
+
23
+ #define RB_P(OBJ) \
24
+ rb_funcall(rb_stderr, rb_intern("print"), 1, rb_funcall(OBJ, rb_intern("object_id"), 0)); \
25
+ rb_funcall(rb_stderr, rb_intern("puts"), 1, rb_funcall(OBJ, rb_intern("inspect"), 0));
26
+
27
+ static int yaji_null(void *ctx)
28
+ {
29
+ yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
30
+ VALUE rv = rb_ary_new3(3, p->path_str, sym_null, Qnil);
31
+ rb_ary_push(p->events, rv);
32
+ return STATUS_CONTINUE;
33
+ }
34
+
35
+ static int yaji_boolean(void *ctx, int val)
36
+ {
37
+ yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
38
+ VALUE rv = rb_ary_new3(3, p->path_str, sym_boolean, val ? Qtrue : Qfalse);
39
+ rb_ary_push(p->events, rv);
40
+ return STATUS_CONTINUE;
41
+ }
42
+
43
+ static int yaji_number(void *ctx, const char *val, unsigned int len)
44
+ {
45
+ yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
46
+ char buf[len+1];
47
+ buf[len] = 0;
48
+ memcpy(buf, val, len);
49
+ VALUE rv;
50
+
51
+ if (memchr(buf, '.', len) || memchr(buf, 'e', len) || memchr(buf, 'E', len)) {
52
+ rv = rb_ary_new3(3, p->path_str, sym_number, rb_float_new(strtod(buf, NULL)));
53
+ } else {
54
+ rv = rb_ary_new3(3, p->path_str, sym_number, rb_cstr2inum(buf, 10));
55
+ }
56
+ rb_ary_push(p->events, rv);
57
+ return STATUS_CONTINUE;
58
+ }
59
+
60
+ #ifdef HAVE_RUBY_ENCODING_H
61
+ #define YAJI_TO_STR(val, len, str) \
62
+ str = rb_str_new((const char *)val, len); \
63
+ rb_encoding *default_internal_enc = rb_default_internal_encoding(); \
64
+ rb_enc_associate(str, utf8_encoding); \
65
+ if (default_internal_enc) { \
66
+ str = rb_str_export_to_enc(str, default_internal_enc); \
67
+ }
68
+ #else
69
+ #define YAJI_TO_STR(val, len, str) \
70
+ str = rb_str_new((const char *)val, len);
71
+ #endif
72
+
73
+ static int yaji_string(void *ctx, const unsigned char *val, unsigned int len)
74
+ {
75
+ yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
76
+ VALUE str, rv;
77
+ YAJI_TO_STR((const char *)val, len, str);
78
+ rv = rb_ary_new3(3, p->path_str, sym_string, str);
79
+ rb_ary_push(p->events, rv);
80
+ return STATUS_CONTINUE;
81
+ }
82
+
83
+ static int yaji_hash_key(void *ctx, const unsigned char *val, unsigned int len)
84
+ {
85
+ yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
86
+ VALUE key, rv;
87
+ YAJI_TO_STR((const char *)val, len, key);
88
+ key = p->symbolize_keys ? ID2SYM(rb_to_id(key)) : key;
89
+ if (p->key_in_use) {
90
+ rb_ary_pop(p->path);
91
+ } else {
92
+ p->key_in_use = 1;
93
+ }
94
+ p->path_str = rb_ary_join(p->path, rb_str_new_cstr("/"));
95
+ rb_str_freeze(p->path_str);
96
+ rv = rb_ary_new3(3, p->path_str, sym_hash_key, key);
97
+ rb_ary_push(p->events, rv);
98
+ rb_ary_push(p->path, key);
99
+ p->path_str = rb_ary_join(p->path, rb_str_new_cstr("/"));
100
+ rb_str_freeze(p->path_str);
101
+ return STATUS_CONTINUE;
102
+ }
103
+
104
+ static int yaji_start_hash(void *ctx)
105
+ {
106
+ yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
107
+ p->key_in_use = 0;
108
+ VALUE rv = rb_ary_new3(3, p->path_str, sym_start_hash, Qnil);
109
+ rb_ary_push(p->events, rv);
110
+ return STATUS_CONTINUE;
111
+ }
112
+
113
+ static int yaji_end_hash(void *ctx)
114
+ {
115
+ yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
116
+ rb_ary_pop(p->path);
117
+ p->path_str = rb_ary_join(p->path, rb_str_new_cstr("/"));
118
+ VALUE rv = rb_ary_new3(3, p->path_str, sym_end_hash, Qnil);
119
+ rb_ary_push(p->events, rv);
120
+ return STATUS_CONTINUE;
121
+ }
122
+
123
+ static int yaji_start_array(void *ctx)
124
+ {
125
+ yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
126
+ VALUE rv = rb_ary_new3(3, p->path_str, sym_start_array, Qnil);
127
+ rb_ary_push(p->path, rb_str_new_cstr(""));
128
+ p->path_str = rb_ary_join(p->path, rb_str_new_cstr("/"));
129
+ rb_str_freeze(p->path_str);
130
+ rb_ary_push(p->events, rv);
131
+ return STATUS_CONTINUE;
132
+ }
133
+
134
+ static int yaji_end_array(void *ctx)
135
+ {
136
+ yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
137
+
138
+ rb_ary_pop(p->path);
139
+ p->path_str = rb_ary_join(p->path, rb_str_new_cstr("/"));
140
+
141
+ VALUE rv = rb_ary_new3(3, p->path_str, sym_end_array, Qnil);
142
+ rb_ary_push(p->events, rv);
143
+ return STATUS_CONTINUE;
144
+ }
145
+
146
+ static VALUE rb_yaji_parser_new(int argc, VALUE *argv, VALUE klass)
147
+ {
148
+ yaji_parser* p;
149
+ VALUE opts, obj;
150
+
151
+ obj = Data_Make_Struct(klass, yaji_parser, rb_yaji_parser_mark, rb_yaji_parser_free, p);
152
+ p->handle = NULL;
153
+ p->config.allowComments = 1;
154
+ p->config.checkUTF8 = 1;
155
+ p->symbolize_keys = 0;
156
+ p->rbufsize = Qnil;
157
+ p->input = Qnil;
158
+
159
+ rb_scan_args(argc, argv, "11", &p->input, &opts);
160
+ if (TYPE(p->input) == T_STRING) {
161
+ p->input = rb_class_new_instance(1, &p->input, c_stringio);
162
+ } else if (!rb_respond_to(p->input, id_read)) {
163
+ rb_raise(c_parse_error, "input must be a String or IO");
164
+ }
165
+ if (!NIL_P(opts)) {
166
+ Check_Type(opts, T_HASH);
167
+ if (rb_hash_aref(opts, sym_allow_comments) == Qfalse) {
168
+ p->config.allowComments = 0;
169
+ }
170
+ if (rb_hash_aref(opts, sym_check_utf8) == Qfalse) {
171
+ p->config.checkUTF8 = 0;
172
+ }
173
+ if (rb_hash_aref(opts, sym_symbolize_keys) == Qtrue) {
174
+ p->symbolize_keys = 1;
175
+ }
176
+ p->rbufsize = rb_hash_aref(opts, sym_read_buffer_size);
177
+ }
178
+ if (NIL_P(p->rbufsize)) {
179
+ p->rbufsize = INT2FIX(READ_BUFSIZE);
180
+ } else {
181
+ Check_Type(p->rbufsize, T_FIXNUM);
182
+ }
183
+ p->handle = yajl_alloc(&callbacks, &p->config, NULL, (void *)obj);
184
+ rb_obj_call_init(obj, 0, 0);
185
+ return obj;
186
+ }
187
+
188
+ static VALUE rb_yaji_parser_init(int argc, VALUE *argv, VALUE self)
189
+ {
190
+ return self;
191
+ }
192
+
193
+ #define RERAISE_PARSER_ERROR(parser, chunk, len) \
194
+ { \
195
+ unsigned char* emsg = yajl_get_error(parser, 1, chunk, len); \
196
+ VALUE errobj = rb_exc_new2(c_parse_error, (const char*) emsg); \
197
+ yajl_free_error(parser, emsg); \
198
+ rb_exc_raise(errobj); \
199
+ }
200
+
201
+ static VALUE rb_yaji_parser_parse(int argc, VALUE* argv, VALUE self)
202
+ {
203
+ yajl_status rc;
204
+ int i;
205
+ yaji_parser* p = (yaji_parser*) DATA_PTR(self);
206
+ VALUE rbuf, proc;
207
+ const char* chunk = NULL;
208
+ unsigned int len = 0;
209
+
210
+ rb_scan_args(argc, argv, "00&", &proc);
211
+ RETURN_ENUMERATOR(self, argc, argv);
212
+
213
+ rbuf = rb_str_new(NULL, 0);
214
+ p->path = rb_ary_new();
215
+ p->path_str = rb_str_new("", 0);
216
+ while (rb_funcall(p->input, id_read, 2, p->rbufsize, rbuf) != Qnil) {
217
+ chunk = RSTRING_PTR(rbuf);
218
+ len = RSTRING_LEN(rbuf);
219
+
220
+ p->events = rb_ary_new();
221
+ rc = yajl_parse(p->handle, (const unsigned char*)chunk, len);
222
+ if (rc == yajl_status_error) {
223
+ RERAISE_PARSER_ERROR(p->handle, (const unsigned char*)chunk, len);
224
+ }
225
+ for (i=0; i<RARRAY_LEN(p->events); i++) {
226
+ rb_funcall(proc, id_call, 1, RARRAY_PTR(p->events)[i]);
227
+ }
228
+ }
229
+
230
+ p->events = rb_ary_new();
231
+ rc = yajl_parse_complete(p->handle);
232
+ if (rc == yajl_status_insufficient_data || rc == yajl_status_error) {
233
+ RERAISE_PARSER_ERROR(p->handle, (const unsigned char*)chunk, len);
234
+ }
235
+ for (i=0; i<RARRAY_LEN(p->events); i++) {
236
+ rb_funcall(proc, id_call, 1, RARRAY_PTR(p->events)[i]);
237
+ }
238
+
239
+ return Qnil;
240
+ }
241
+
242
+ #define YAJI_STR_START_WITH(str, head) \
243
+ (RSTRING_LEN(head) <= RSTRING_LEN(str) && memcmp(RSTRING_PTR(head), RSTRING_PTR(str), RSTRING_LEN(head)) == 0)
244
+
245
+ static VALUE rb_yaji_each_iter(VALUE chunk, VALUE* params_p)
246
+ {
247
+ VALUE* params = (VALUE*)params_p;
248
+ VALUE path = rb_ary_shift(chunk);
249
+ VALUE event = rb_ary_shift(chunk);
250
+ VALUE value = rb_ary_shift(chunk);
251
+ VALUE proc = params[0];
252
+ VALUE stack = params[1];
253
+ VALUE query = params[2];
254
+ VALUE last_entry, object, container, key, hash;
255
+
256
+ if (NIL_P(query) || YAJI_STR_START_WITH(path, query)) {
257
+ if (event == sym_hash_key) {
258
+ rb_ary_push(stack, value);
259
+ } else if (event == sym_start_hash || event == sym_start_array) {
260
+ container = (event == sym_start_hash) ? rb_hash_new() : rb_ary_new();
261
+ last_entry = rb_ary_entry(stack, -1);
262
+ switch(TYPE(last_entry)) {
263
+ case T_STRING:
264
+ key = rb_ary_pop(stack);
265
+ hash = rb_ary_entry(stack, -1);
266
+ rb_hash_aset(hash, key, container);
267
+ break;
268
+ case T_ARRAY:
269
+ rb_ary_push(last_entry, container);
270
+ }
271
+ rb_ary_push(stack, container);
272
+ } else if (event == sym_end_hash || event == sym_end_array) {
273
+ object = rb_ary_pop(stack);
274
+ if (RARRAY_LEN(stack) == 0) {
275
+ rb_funcall(proc, id_call, 1, object);
276
+ }
277
+ } else {
278
+ last_entry = rb_ary_entry(stack, -1);
279
+ switch(TYPE(last_entry)) {
280
+ case T_STRING:
281
+ key = rb_ary_pop(stack);
282
+ hash = rb_ary_entry(stack, -1);
283
+ rb_hash_aset(hash, key, value);
284
+ break;
285
+ case T_ARRAY:
286
+ rb_ary_push(last_entry, value);
287
+ break;
288
+ case T_NIL:
289
+ rb_funcall(proc, id_call, 1, value);
290
+ break;
291
+ }
292
+ }
293
+ }
294
+ return Qnil;
295
+ }
296
+
297
+ static VALUE rb_yaji_parser_each(int argc, VALUE* argv, VALUE self)
298
+ {
299
+ VALUE query, proc, params[3];
300
+ rb_scan_args(argc, argv, "01&", &query, &proc);
301
+ RETURN_ENUMERATOR(self, argc, argv);
302
+ params[0] = proc; // callback
303
+ params[1] = rb_ary_new(); // stack
304
+ params[2] = query;
305
+ rb_block_call(self, id_parse, 0, NULL, rb_yaji_each_iter, (VALUE)params);
306
+ return Qnil;
307
+ }
308
+
309
+ static void rb_yaji_parser_free(void *parser)
310
+ {
311
+ yaji_parser* p = parser;
312
+ if (p) {
313
+ if (p->handle) {
314
+ yajl_free(p->handle);
315
+ }
316
+ free(p);
317
+ }
318
+ }
319
+
320
+ static void rb_yaji_parser_mark(void *parser)
321
+ {
322
+ yaji_parser* p = parser;
323
+ if (p) {
324
+ rb_gc_mark(p->input);
325
+ rb_gc_mark(p->rbufsize);
326
+ rb_gc_mark(p->events);
327
+ rb_gc_mark(p->path);
328
+ rb_gc_mark(p->path_str);
329
+ }
330
+ }
331
+
332
+ /* Ruby Extension initializer */
333
+ void Init_parser_ext() {
334
+ m_yaji = rb_define_module("YAJI");
335
+
336
+ c_parse_error = rb_define_class_under(m_yaji, "ParseError", rb_eStandardError);
337
+
338
+ c_yaji_parser = rb_define_class_under(m_yaji, "Parser", rb_cObject);
339
+ rb_define_const(c_yaji_parser, "READ_BUFFER_SIZE", INT2FIX(READ_BUFSIZE));
340
+ rb_define_singleton_method(c_yaji_parser, "new", rb_yaji_parser_new, -1);
341
+ rb_define_method(c_yaji_parser, "initialize", rb_yaji_parser_init, -1);
342
+ rb_define_method(c_yaji_parser, "parse", rb_yaji_parser_parse, -1);
343
+ rb_define_method(c_yaji_parser, "each", rb_yaji_parser_each, -1);
344
+
345
+ id_call = rb_intern("call");
346
+ id_read = rb_intern("read");
347
+ id_parse = rb_intern("parse");
348
+ id_rewind = rb_intern("rewind");
349
+
350
+ sym_allow_comments = ID2SYM(rb_intern("allow_comments"));
351
+ sym_check_utf8 = ID2SYM(rb_intern("check_utf8"));
352
+ sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
353
+ sym_read_buffer_size = ID2SYM(rb_intern("read_buffer_size"));
354
+ sym_null = ID2SYM(rb_intern("null"));
355
+ sym_boolean = ID2SYM(rb_intern("boolean"));
356
+ sym_number = ID2SYM(rb_intern("number"));
357
+ sym_string = ID2SYM(rb_intern("string"));
358
+ sym_hash_key = ID2SYM(rb_intern("hash_key"));
359
+ sym_start_hash = ID2SYM(rb_intern("start_hash"));
360
+ sym_end_hash = ID2SYM(rb_intern("end_hash"));
361
+ sym_start_array = ID2SYM(rb_intern("start_array"));
362
+ sym_end_array = ID2SYM(rb_intern("end_array"));
363
+
364
+ #ifdef HAVE_RUBY_ENCODING_H
365
+ utf8_encoding = rb_utf8_encoding();
366
+ #endif
367
+
368
+ rb_require("stringio");
369
+ c_stringio = rb_const_get(rb_cObject, rb_intern("StringIO"));
370
+ }
@@ -0,0 +1,92 @@
1
+ /*
2
+ * Author:: Couchbase <info@couchbase.com>
3
+ * Copyright:: 2011 Couchbase, Inc.
4
+ * License:: Apache License, Version 2.0
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ #include <yajl/yajl_parse.h>
20
+
21
+ #include <ruby.h>
22
+
23
+ #ifdef HAVE_RUBY_ENCODING_H
24
+ #include <ruby/encoding.h>
25
+ static rb_encoding *utf8_encoding;
26
+ #endif
27
+
28
+ /* Older versions of Ruby (< 1.8.6) need these */
29
+ #ifndef RSTRING_PTR
30
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
31
+ #endif
32
+ #ifndef RSTRING_LEN
33
+ #define RSTRING_LEN(s) (RSTRING(s)->len)
34
+ #endif
35
+ #ifndef RARRAY_PTR
36
+ #define RARRAY_PTR(s) (RARRAY(s)->ptr)
37
+ #endif
38
+ #ifndef RARRAY_LEN
39
+ #define RARRAY_LEN(s) (RARRAY(s)->len)
40
+ #endif
41
+
42
+ static VALUE m_yaji, c_yaji_parser, c_parse_error, c_stringio;
43
+
44
+ static ID id_call, id_read, id_parse, id_rewind;
45
+ static ID sym_allow_comments, sym_check_utf8, sym_symbolize_keys,
46
+ sym_read_buffer_size, sym_null, sym_boolean, sym_number, sym_string,
47
+ sym_hash_key, sym_start_hash, sym_end_hash, sym_start_array,
48
+ sym_end_array;
49
+
50
+ static int yaji_null(void *ctx);
51
+ static int yaji_boolean(void *ctx, int val);
52
+ static int yaji_number(void *ctx, const char *val, unsigned int len);
53
+ static int yaji_string(void *ctx, const unsigned char *val, unsigned int len);
54
+ static int yaji_hash_key(void *ctx, const unsigned char *val, unsigned int len);
55
+ static int yaji_start_hash(void *ctx);
56
+ static int yaji_end_hash(void *ctx);
57
+ static int yaji_start_array(void *ctx);
58
+ static int yaji_end_array(void *ctx);
59
+
60
+ static yajl_callbacks callbacks = {
61
+ yaji_null,
62
+ yaji_boolean,
63
+ NULL,
64
+ NULL,
65
+ yaji_number,
66
+ yaji_string,
67
+ yaji_start_hash,
68
+ yaji_hash_key,
69
+ yaji_end_hash,
70
+ yaji_start_array,
71
+ yaji_end_array
72
+ };
73
+
74
+ typedef struct {
75
+ int symbolize_keys;
76
+ int key_in_use;
77
+ VALUE input;
78
+ VALUE rbufsize;
79
+ VALUE events;
80
+ VALUE path;
81
+ VALUE path_str;
82
+ yajl_handle handle;
83
+ yajl_parser_config config;
84
+ } yaji_parser;
85
+
86
+ static VALUE rb_yaji_parser_new(int argc, VALUE *argv, VALUE klass);
87
+ static VALUE rb_yaji_parser_init(int argc, VALUE *argv, VALUE self);
88
+ static VALUE rb_yaji_parser_parse(int argc, VALUE *argv, VALUE self);
89
+ static void rb_yaji_parser_free(void *parser);
90
+ static void rb_yaji_parser_mark(void *parser);
91
+
92
+ void Init_parser_ext();
data/lib/yaji.rb ADDED
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Couchbase <info@couchbase.com>
4
+ # Copyright:: 2011 Couchbase, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require "yaji/version"
21
+ require "yaji/parser_ext"
22
+
23
+ module YAJI
24
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Couchbase <info@couchbase.com>
4
+ # Copyright:: 2011 Couchbase, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ module YAJI
21
+ VERSION = "0.0.1"
22
+ end
@@ -0,0 +1,14 @@
1
+ gem 'rake-compiler', '>= 0.7.5'
2
+ require "rake/extensiontask"
3
+
4
+ def gemspec
5
+ @clean_gemspec ||= eval(File.read(File.expand_path('../../yaji.gemspec', __FILE__)))
6
+ end
7
+
8
+ Rake::ExtensionTask.new("parser_ext", gemspec) do |ext|
9
+ ext.ext_dir = File.join('ext', 'yaji')
10
+ ext.lib_dir = File.join('lib', 'yaji')
11
+
12
+ # clean compiled extension
13
+ CLEAN.include "#{ext.lib_dir}/*.#{RbConfig::CONFIG['DLEXT']}"
14
+ end
data/tasks/test.rake ADDED
@@ -0,0 +1,7 @@
1
+ require 'rake/testtask'
2
+ Rake::TestTask.new do |test|
3
+ test.libs << "test" << "."
4
+ test.ruby_opts << "-rruby-debug" if ENV['DEBUG']
5
+ test.pattern = 'test/test_*.rb'
6
+ test.verbose = true
7
+ end
data/tasks/util.rake ADDED
@@ -0,0 +1,4 @@
1
+ desc 'Start an irb session and load the library.'
2
+ task :console do
3
+ exec "irb -I lib -rruby-debug -ryaji"
4
+ end
data/test/fixture.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "total_rows": 4,
3
+ "offset": 0,
4
+ "rows": [
5
+ {
6
+ "id": "3e8ceb5873cf91fa418c2ab5a0000386",
7
+ "key": "3e8ceb5873cf91fa418c2ab5a0000386",
8
+ "value": {
9
+ "_id": "3e8ceb5873cf91fa418c2ab5a0000386",
10
+ "_rev": "1-967a00dff5e02add41819138abb3284d"
11
+ }
12
+ },
13
+ {
14
+ "id": "biking",
15
+ "key": "biking",
16
+ "value": {
17
+ "_id": "biking",
18
+ "_rev": "2-d4b43fd051e693a5191db2eaba89903c",
19
+ "title": "Biking2",
20
+ "body": "My biggest hobby is mountainbiking. The other day...",
21
+ "date": "2009/01/30 18:04:11"
22
+ }
23
+ },
24
+ {
25
+ "id": "bought-a-cat",
26
+ "key": "bought-a-cat",
27
+ "value": {
28
+ "_id": "bought-a-cat",
29
+ "_rev": "1-ccd0a7e95ade7eb2d29cc02ffa582b30",
30
+ "title": "Bought a Cat",
31
+ "body": "I went to the the pet store earlier and brought home a little kitty...",
32
+ "date": "2009/02/17 21:13:39"
33
+ }
34
+ },
35
+ {
36
+ "id": "hello-world",
37
+ "key": "hello-world",
38
+ "value": {
39
+ "_id": "hello-world",
40
+ "_rev": "1-97dd85b06c25328a300f3f4041def370",
41
+ "title": "Hello World",
42
+ "body": "Well hello and welcome to my new blog...",
43
+ "date": "2009/01/15 15:52:20"
44
+ }
45
+ }
46
+ ]
47
+ }
@@ -0,0 +1,166 @@
1
+ require 'minitest/autorun'
2
+ require 'yaji'
3
+
4
+ class TestParser < MiniTest::Unit::TestCase
5
+
6
+ def test_it_generates_events
7
+ events = []
8
+ parser = YAJI::Parser.new(toys_json_str)
9
+ parser.parse do |p, e, v|
10
+ events << [p, e, v]
11
+ end
12
+ expected = [
13
+ ["", :start_hash, nil],
14
+ ["", :hash_key, "total_rows"],
15
+ ["total_rows", :number, 2],
16
+ ["", :hash_key, "rows"],
17
+ ["rows", :start_array, nil],
18
+ ["rows/", :start_hash, nil],
19
+ ["rows/", :hash_key, "id"],
20
+ ["rows//id", :string, "buzz"],
21
+ ["rows/", :hash_key, "props"],
22
+ ["rows//props", :start_hash, nil],
23
+ ["rows//props", :hash_key, "humanoid"],
24
+ ["rows//props/humanoid", :boolean, true],
25
+ ["rows//props", :hash_key, "armed"],
26
+ ["rows//props/armed", :boolean, true],
27
+ ["rows//props", :end_hash, nil],
28
+ ["rows/", :hash_key, "movies"],
29
+ ["rows//movies", :start_array, nil],
30
+ ["rows//movies/", :number, 1],
31
+ ["rows//movies/", :number, 2],
32
+ ["rows//movies/", :number, 3],
33
+ ["rows//movies", :end_array, nil],
34
+ ["rows/", :end_hash, nil],
35
+ ["rows/", :start_hash, nil],
36
+ ["rows/", :hash_key, "id"],
37
+ ["rows//id", :string, "barbie"],
38
+ ["rows/", :hash_key, "props"],
39
+ ["rows//props", :start_hash, nil],
40
+ ["rows//props", :hash_key, "humanoid"],
41
+ ["rows//props/humanoid", :boolean, true],
42
+ ["rows//props", :hash_key, "armed"],
43
+ ["rows//props/armed", :boolean, false],
44
+ ["rows//props", :end_hash, nil],
45
+ ["rows/", :hash_key, "movies"],
46
+ ["rows//movies", :start_array, nil],
47
+ ["rows//movies/", :number, 2],
48
+ ["rows//movies/", :number, 3],
49
+ ["rows//movies", :end_array, nil],
50
+ ["rows/", :end_hash, nil],
51
+ ["rows", :end_array, nil],
52
+ ["", :end_hash, nil]
53
+ ]
54
+ assert_equal expected, events
55
+ end
56
+
57
+ def test_it_yields_enumerator
58
+ parser = YAJI::Parser.new('{"hello":"world"}')
59
+ e = parser.parse
60
+ assert_equal ["", :start_hash, nil], e.next
61
+ assert_equal ["", :hash_key, "hello"], e.next
62
+ assert_equal ["hello", :string, "world"], e.next
63
+ assert_equal ["", :end_hash, nil], e.next
64
+ assert_raises(StopIteration) { e.next }
65
+ end
66
+
67
+ def test_it_symbolizes_keys
68
+ parser = YAJI::Parser.new('{"hello":"world"}', :symbolize_keys => true)
69
+ e = parser.parse
70
+ expected = [
71
+ ["", :start_hash, nil],
72
+ ["", :hash_key, :hello],
73
+ ["hello", :string, "world"],
74
+ ["", :end_hash, nil]
75
+ ]
76
+ assert_equal expected, e.to_a
77
+ end
78
+
79
+ def test_it_build_ruby_objects
80
+ parser = YAJI::Parser.new(toys_json_str)
81
+ objects = []
82
+ parser.each do |o|
83
+ objects << o
84
+ end
85
+ expected = [{"total_rows" => 2,
86
+ "rows" => [
87
+ {
88
+ "id" => "buzz",
89
+ "props" => { "humanoid"=> true, "armed"=> true },
90
+ "movies" => [1,2,3]
91
+ },
92
+ {
93
+ "id" => "barbie",
94
+ "props" => { "humanoid"=> true, "armed"=> false },
95
+ "movies" => [2,3]
96
+ }
97
+ ]}]
98
+ assert expected, objects
99
+ end
100
+
101
+ def test_it_yields_whole_array
102
+ parser = YAJI::Parser.new(toys_json_str)
103
+ objects = []
104
+ parser.each("rows") do |o|
105
+ objects << o
106
+ end
107
+ expected = [[{
108
+ "id" => "buzz",
109
+ "props" => { "humanoid"=> true, "armed"=> true },
110
+ "movies" => [1,2,3]
111
+ },
112
+ {
113
+ "id" => "barbie",
114
+ "props" => { "humanoid"=> true, "armed"=> false },
115
+ "movies" => [2,3]
116
+ }]]
117
+ assert expected, objects
118
+ end
119
+
120
+ def test_it_yeilds_array_contents_row_by_row
121
+ parser = YAJI::Parser.new(toys_json_str)
122
+ objects = []
123
+ parser.each("rows/") do |o|
124
+ objects << o
125
+ end
126
+ expected = [{
127
+ "id" => "buzz",
128
+ "props" => { "humanoid"=> true, "armed"=> true },
129
+ "movies" => [1,2,3]
130
+ },
131
+ {
132
+ "id" => "barbie",
133
+ "props" => { "humanoid"=> true, "armed"=> false },
134
+ "movies" => [2,3]
135
+ }]
136
+ assert expected, objects
137
+ end
138
+
139
+ protected
140
+
141
+ def toys_json_str
142
+ <<-JSON
143
+ {
144
+ "total_rows": 2,
145
+ "rows": [
146
+ {
147
+ "id": "buzz",
148
+ "props": {
149
+ "humanoid": true,
150
+ "armed": true
151
+ },
152
+ "movies": [1,2,3]
153
+ },
154
+ {
155
+ "id": "barbie",
156
+ "props": {
157
+ "humanoid": true,
158
+ "armed": false
159
+ },
160
+ "movies": [2,3]
161
+ }
162
+ ]
163
+ }
164
+ JSON
165
+ end
166
+ end
data/yaji.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "yaji/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "yaji"
7
+ s.version = YAJI::VERSION
8
+ s.author = 'Couchbase'
9
+ s.email = 'info@couchbase.com'
10
+ s.license = 'ASL-2'
11
+ s.homepage = "https://github.com/avsej/yaji"
12
+ s.summary = %q{Yet another JSON iterator}
13
+ s.description = %q{YAJI is a ruby wrapper to YAJL providing iterator interface to streaming JSON parser}
14
+
15
+ s.rubyforge_project = "yaji"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.extensions = `git ls-files -- ext/**/extconf.rb`.split("\n")
21
+ s.require_paths = ["lib"]
22
+
23
+ s.add_development_dependency 'rake-compiler'
24
+ s.add_development_dependency 'minitest'
25
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yaji
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Couchbase
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-19 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake-compiler
16
+ requirement: &21823240 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *21823240
25
+ - !ruby/object:Gem::Dependency
26
+ name: minitest
27
+ requirement: &21822680 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *21822680
36
+ description: YAJI is a ruby wrapper to YAJL providing iterator interface to streaming
37
+ JSON parser
38
+ email: info@couchbase.com
39
+ executables: []
40
+ extensions:
41
+ - ext/yaji/extconf.rb
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - Gemfile
46
+ - LICENSE
47
+ - README.markdown
48
+ - Rakefile
49
+ - ext/yaji/extconf.rb
50
+ - ext/yaji/parser_ext.c
51
+ - ext/yaji/parser_ext.h
52
+ - lib/yaji.rb
53
+ - lib/yaji/version.rb
54
+ - tasks/compile.rake
55
+ - tasks/test.rake
56
+ - tasks/util.rake
57
+ - test/fixture.json
58
+ - test/test_parser.rb
59
+ - yaji.gemspec
60
+ homepage: https://github.com/avsej/yaji
61
+ licenses:
62
+ - ASL-2
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project: yaji
81
+ rubygems_version: 1.8.7
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Yet another JSON iterator
85
+ test_files:
86
+ - test/fixture.json
87
+ - test/test_parser.rb