usamin 7.7.6 → 7.7.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,29 @@
1
+ #ifndef USAMIN_RB_USAMIN_ARRAY_HPP
2
+ #define USAMIN_RB_USAMIN_ARRAY_HPP
3
+
4
+ #include <ruby.h>
5
+ #include "rubynized_rapidjson.hpp"
6
+
7
+ void flatten_array(RubynizedValue &value, VALUE array, int level, VALUE root_document);
8
+
9
+ VALUE w_array_operator_indexer(const int argc, const VALUE *argv, const VALUE self);
10
+ VALUE w_array_at(const VALUE self, const VALUE nth);
11
+ VALUE w_array_compact(const VALUE self);
12
+ VALUE w_array_dig(const int argc, const VALUE *argv, const VALUE self);
13
+ VALUE w_array_each(const VALUE self);
14
+ VALUE w_array_each_index(const VALUE self);
15
+ VALUE w_array_isempty(const VALUE self);
16
+ VALUE w_array_fetch(const int argc, const VALUE *argv, const VALUE self);
17
+ VALUE w_array_find_index(const int argc, const VALUE *argv, const VALUE self);
18
+ VALUE w_array_flatten(const int argc, const VALUE *argv, const VALUE self);
19
+ VALUE w_array_first(const int argc, const VALUE *argv, const VALUE self);
20
+ VALUE w_array_include(const VALUE self, const VALUE val);
21
+ VALUE w_array_inspect(const VALUE self);
22
+ VALUE w_array_last(const int argc, const VALUE *argv, const VALUE self);
23
+ VALUE w_array_length(const VALUE self);
24
+ VALUE w_array_reverse(const VALUE self);
25
+ VALUE w_array_rindex(const int argc, const VALUE *argv, const VALUE self);
26
+ VALUE w_array_rotate(const int argc, const VALUE *argv, const VALUE self);
27
+ VALUE w_array_eval(const VALUE self);
28
+
29
+ #endif
@@ -0,0 +1,518 @@
1
+ #include "rb270_fix.hpp"
2
+ #include <rapidjson/document.h>
3
+ #include <ruby.h>
4
+ #include <ruby/version.h>
5
+ #include "rb_usamin_array.hpp"
6
+ #include "usamin_value.hpp"
7
+ #include "parser_helper.hpp"
8
+
9
+ /*
10
+ * @return [Object | nil]
11
+ *
12
+ * @note This method has linear time complexity.
13
+ */
14
+ VALUE w_hash_operator_indexer(const VALUE self, const VALUE key) {
15
+ UsaminValue *value = get_value(self);
16
+ check_object(value);
17
+ for (auto &m : value->value->GetObject())
18
+ if (str_compare_xx(key, m.name))
19
+ return eval(m.value, value->root_document);
20
+ return Qnil;
21
+ }
22
+
23
+ /*
24
+ * @return [::Array | nil]
25
+ *
26
+ * @note This method has linear time complexity.
27
+ */
28
+ VALUE w_hash_assoc(const VALUE self, const VALUE key) {
29
+ UsaminValue *value = get_value(self);
30
+ check_object(value);
31
+ for (auto &m : value->value->GetObject())
32
+ if (str_compare_xx(key, m.name))
33
+ return rb_assoc_new(eval_str(m.name), eval(m.value, value->root_document));
34
+ return Qnil;
35
+ }
36
+
37
+ /*
38
+ * @return [::Hash]
39
+ */
40
+ VALUE w_hash_compact(const VALUE self) {
41
+ UsaminValue *value = get_value(self);
42
+ check_object(value);
43
+ VALUE hash = rb_hash_new();
44
+ for (auto &m : value->value->GetObject())
45
+ if (!m.value.IsNull())
46
+ rb_hash_aset(hash, eval(m.name, value->root_document), eval(m.value, value->root_document));
47
+ return hash;
48
+ }
49
+
50
+ /*
51
+ * @return [::Hash]
52
+ */
53
+ VALUE w_hash_deconstruct_keys(const VALUE self, const VALUE keys) {
54
+ UsaminValue *value = get_value(self);
55
+ check_object(value);
56
+ if (NIL_P(keys))
57
+ return eval_object(*(value->value), value->root_document, 1);
58
+ VALUE hash_keys = rb_hash_new();
59
+ VALUE *key_iter = RARRAY_PTR(keys);
60
+ const VALUE *key_iter_end = key_iter + RARRAY_LEN(keys);
61
+ for (VALUE *k = key_iter; k < key_iter_end; k++)
62
+ rb_hash_aset(hash_keys, *k, Qtrue);
63
+ VALUE hash = rb_hash_new();
64
+ for (auto &m : value->value->GetObject()) {
65
+ VALUE name = rb_to_symbol(new_utf8_str(m.name.GetString(), m.name.GetStringLength()));
66
+ if (!NIL_P(rb_hash_lookup(hash_keys, name)))
67
+ rb_hash_aset(hash, name, eval(m.value, value->root_document));
68
+ }
69
+ return hash;
70
+ }
71
+
72
+ /*
73
+ * @return [Object | nil]
74
+ */
75
+ VALUE w_hash_dig(const int argc, const VALUE *argv, const VALUE self) {
76
+ rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
77
+ VALUE value = w_hash_operator_indexer(self, argv[0]);
78
+ if (argc == 1)
79
+ return value;
80
+ else if (value == Qnil)
81
+ return Qnil;
82
+ extern ID id_dig;
83
+ return rb_funcall3(value, id_dig, argc - 1, argv + 1);
84
+ }
85
+
86
+ static VALUE hash_enum_size(const VALUE self, const VALUE, const VALUE) {
87
+ return UINT2NUM(get_value(self)->value->MemberCount());
88
+ }
89
+
90
+ /*
91
+ * @yield [key, value]
92
+ * @yieldparam key [String]
93
+ * @yieldparam value [Object]
94
+ * @return [Enumerator | self]
95
+ */
96
+ VALUE w_hash_each(const VALUE self) {
97
+ UsaminValue *value = get_value(self);
98
+ check_object(value);
99
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
100
+ if (rb_proc_arity(rb_block_proc()) > 1) {
101
+ for (auto &m : value->value->GetObject()) {
102
+ VALUE args[] = {eval_str(m.name), eval(m.value, value->root_document)};
103
+ rb_yield_values2(2, args);
104
+ }
105
+ } else {
106
+ for (auto &m : value->value->GetObject())
107
+ rb_yield(rb_assoc_new(eval_str(m.name), eval(m.value, value->root_document)));
108
+ }
109
+ return self;
110
+ }
111
+
112
+ /*
113
+ * @yield [key]
114
+ * @yieldparam key [String]
115
+ * @return [Enumerator | self]
116
+ */
117
+ VALUE w_hash_each_key(const VALUE self) {
118
+ UsaminValue *value = get_value(self);
119
+ check_object(value);
120
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
121
+ for (auto &m : value->value->GetObject())
122
+ rb_yield(eval_str(m.name));
123
+ return self;
124
+ }
125
+
126
+ /*
127
+ * @yield [value]
128
+ * @return [Enumerator | self]
129
+ */
130
+ VALUE w_hash_each_value(const VALUE self) {
131
+ UsaminValue *value = get_value(self);
132
+ check_object(value);
133
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
134
+ for (auto &m : value->value->GetObject())
135
+ rb_yield(eval(m.value, value->root_document));
136
+ return self;
137
+ }
138
+
139
+ VALUE w_hash_isempty(const VALUE self) {
140
+ UsaminValue *value = get_value(self);
141
+ check_object(value);
142
+ return value->value->MemberCount() == 0 ? Qtrue : Qfalse;
143
+ }
144
+
145
+ /*
146
+ * @overload fetch(key, default = nil)
147
+ * @param [String] key
148
+ * @param [Object] default
149
+ * @return [Object]
150
+ *
151
+ * @overload fetch(key)
152
+ * @param [String] key
153
+ * @yield [key]
154
+ * @return [Object]
155
+ */
156
+ VALUE w_hash_fetch(const int argc, const VALUE *argv, const VALUE self) {
157
+ rb_check_arity(argc, 1, 2);
158
+ if (argc == 2 && rb_block_given_p())
159
+ rb_warn("block supersedes default value argument");
160
+ UsaminValue *value = get_value(self);
161
+ check_object(value);
162
+ for (auto &m : value->value->GetObject())
163
+ if (str_compare_xx(argv[0], m.name))
164
+ return eval(m.value, value->root_document);
165
+ return rb_block_given_p() ? rb_yield(argv[0]) : argc == 2 ? argv[1] : Qnil;
166
+ }
167
+
168
+ /*
169
+ * @param [String] key
170
+ * @return [::Array<Object>]
171
+ */
172
+ VALUE w_hash_fetch_values(const int argc, VALUE *argv, const VALUE self) {
173
+ UsaminValue *value = get_value(self);
174
+ check_object(value);
175
+ VALUE ret = rb_ary_new2(argc);
176
+ for (int i = 0; i < argc; i++) {
177
+ bool found = false;
178
+ for (auto &m : value->value->GetObject()) {
179
+ if (str_compare_xx(argv[i], m.name)) {
180
+ rb_ary_push(ret, eval(m.value, value->root_document));
181
+ found = true;
182
+ break;
183
+ }
184
+ }
185
+ if (!found) {
186
+ if (rb_block_given_p()) {
187
+ rb_ary_push(ret, rb_yield(argv[i]));
188
+ } else {
189
+ rb_ary_free(ret);
190
+ rb_raise(rb_eKeyError, "key not found: \"%s\"", StringValueCStr(argv[i]));
191
+ return Qnil;
192
+ }
193
+ }
194
+ }
195
+ return ret;
196
+ }
197
+
198
+ /*
199
+ * @overload flatten(level = 1)
200
+ * @return [::Array<Object>]
201
+ */
202
+ VALUE w_hash_flatten(const int argc, const VALUE *argv, const VALUE self) {
203
+ rb_check_arity(argc, 0, 1);
204
+ UsaminValue *value = get_value(self);
205
+ check_object(value);
206
+
207
+ int level = 1;
208
+ if (argc == 1 && !NIL_P(argv[0])) {
209
+ level = NUM2INT(argv[0]);
210
+ if (level < 0)
211
+ level = -1;
212
+ }
213
+
214
+ if (level == 0) {
215
+ VALUE ret = rb_ary_new2(value->value->MemberCount());
216
+ for (auto &m : value->value->GetObject())
217
+ rb_ary_push(ret, rb_ary_new3(2, eval_str(m.name), eval(m.value, value->root_document)));
218
+ return ret;
219
+ }
220
+
221
+ VALUE ret = rb_ary_new2(value->value->MemberCount() * 2);
222
+ if (level == 1) {
223
+ for (auto &m : value->value->GetObject()) {
224
+ rb_ary_push(ret, eval_str(m.name));
225
+ rb_ary_push(ret, eval(m.value, value->root_document));
226
+ }
227
+ } else {
228
+ for (auto &m : value->value->GetObject()) {
229
+ rb_ary_push(ret, eval_str(m.name));
230
+ if (m.value.IsArray())
231
+ flatten_array(m.value, ret, level > 0 ? level - 2 : level, value->root_document);
232
+ else
233
+ rb_ary_push(ret, eval(m.value, value->root_document));
234
+ }
235
+ }
236
+ return ret;
237
+ }
238
+
239
+ /*
240
+ * @note This method has linear time complexity.
241
+ */
242
+ VALUE w_hash_haskey(const VALUE self, const VALUE key) {
243
+ UsaminValue *value = get_value(self);
244
+ check_object(value);
245
+ for (auto &m : value->value->GetObject())
246
+ if (str_compare_xx(key, m.name))
247
+ return Qtrue;
248
+ return Qfalse;
249
+ }
250
+
251
+ VALUE w_hash_hasvalue(const VALUE self, const VALUE val) {
252
+ UsaminValue *value = get_value(self);
253
+ check_object(value);
254
+ for (auto &m : value->value->GetObject())
255
+ if (rb_equal(val, eval_r(m.value, 0)))
256
+ return Qtrue;
257
+ return Qfalse;
258
+ }
259
+
260
+ /*
261
+ * @return [String | nil]
262
+ */
263
+ VALUE w_hash_key(const VALUE self, const VALUE val) {
264
+ UsaminValue *value = get_value(self);
265
+ check_object(value);
266
+ for (auto &m : value->value->GetObject())
267
+ if (rb_equal(val, eval_r(m.value, 0)))
268
+ return eval_str(m.name);
269
+ return Qnil;
270
+ }
271
+
272
+ /*
273
+ * @return [String]
274
+ */
275
+ VALUE w_hash_inspect(const VALUE self) {
276
+ UsaminValue *value = get_value(self);
277
+ check_object(value);
278
+ VALUE ret = rb_str_new2("{");
279
+ bool first = true;
280
+ for (auto &m : value->value->GetObject()) {
281
+ if (!first)
282
+ ret = rb_str_cat2(ret, ", ");
283
+ ret = rb_str_append(ret, rb_inspect(eval_str(m.name)));
284
+ ret = rb_str_cat2(ret, "=>");
285
+ switch (m.value.GetType()) {
286
+ case rapidjson::kObjectType:
287
+ ret = rb_str_cat2(ret, "{...}");
288
+ break;
289
+ case rapidjson::kArrayType:
290
+ ret = rb_str_cat2(ret, "[...]");
291
+ break;
292
+ default:
293
+ ret = rb_str_append(ret, rb_inspect(eval(m.value, value->root_document)));
294
+ break;
295
+ }
296
+ first = false;
297
+ }
298
+ ret = rb_str_cat2(ret, "}");
299
+ return ret;
300
+ }
301
+
302
+ /*
303
+ * @return [::Hash]
304
+ */
305
+ VALUE w_hash_invert(const VALUE self) {
306
+ UsaminValue *value = get_value(self);
307
+ check_object(value);
308
+ VALUE ret = rb_hash_new();
309
+ for (auto &m : value->value->GetObject())
310
+ rb_hash_aset(ret, eval(m.value, value->root_document), eval_str(m.name));
311
+ return ret;
312
+ }
313
+
314
+ /*
315
+ * @return [::Array<String>]
316
+ */
317
+ VALUE w_hash_keys(const VALUE self) {
318
+ UsaminValue *value = get_value(self);
319
+ check_object(value);
320
+ VALUE ret = rb_ary_new2(value->value->MemberCount());
321
+ for (auto &m : value->value->GetObject())
322
+ rb_ary_push(ret, eval_str(m.name));
323
+ return ret;
324
+ }
325
+
326
+ /*
327
+ * @return [Integer]
328
+ */
329
+ VALUE w_hash_length(const VALUE self) {
330
+ UsaminValue *value = get_value(self);
331
+ check_object(value);
332
+ return UINT2NUM(value->value->MemberCount());
333
+ }
334
+
335
+ /*
336
+ * @return [::Array | nil]
337
+ */
338
+ VALUE w_hash_rassoc(const VALUE self, const VALUE val) {
339
+ UsaminValue *value = get_value(self);
340
+ check_object(value);
341
+ for (auto &m : value->value->GetObject())
342
+ if (rb_funcall(val, rb_intern("=="), 1, eval_r(m.value, 0)))
343
+ return rb_assoc_new(eval_str(m.name), eval(m.value, value->root_document));
344
+ return Qnil;
345
+ }
346
+
347
+ /*
348
+ * @yield [key, value]
349
+ * @yieldparam key [String]
350
+ * @yieldparam value [Object]
351
+ * @return [Enumerator | ::Hash]
352
+ */
353
+ VALUE w_hash_select(const VALUE self) {
354
+ UsaminValue *value = get_value(self);
355
+ check_object(value);
356
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
357
+ VALUE hash = rb_hash_new();
358
+ if (rb_proc_arity(rb_block_proc()) > 1) {
359
+ for (auto &m : value->value->GetObject()) {
360
+ VALUE args[] = {eval_str(m.name), eval(m.value, value->root_document)};
361
+ if (RTEST(rb_yield_values2(2, args)))
362
+ rb_hash_aset(hash, args[0], args[1]);
363
+ }
364
+ } else {
365
+ for (auto &m : value->value->GetObject()) {
366
+ VALUE key = eval_str(m.name);
367
+ VALUE val = eval(m.value, value->root_document);
368
+ if (RTEST(rb_yield(rb_assoc_new(key, val))))
369
+ rb_hash_aset(hash, key, val);
370
+ }
371
+ }
372
+ return hash;
373
+ }
374
+
375
+ /*
376
+ * @yield [key, value]
377
+ * @yieldparam key [String]
378
+ * @yieldparam value [Object]
379
+ * @return [Enumerator | ::Hash]
380
+ */
381
+ VALUE w_hash_reject(const VALUE self) {
382
+ UsaminValue *value = get_value(self);
383
+ check_object(value);
384
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
385
+ VALUE hash = rb_hash_new();
386
+ if (rb_proc_arity(rb_block_proc()) > 1) {
387
+ for (auto &m : value->value->GetObject()) {
388
+ VALUE args[] = {eval_str(m.name), eval(m.value, value->root_document)};
389
+ if (!RTEST(rb_yield_values2(2, args)))
390
+ rb_hash_aset(hash, args[0], args[1]);
391
+ }
392
+ } else {
393
+ for (auto &m : value->value->GetObject()) {
394
+ VALUE key = eval_str(m.name);
395
+ VALUE val = eval(m.value, value->root_document);
396
+ if (!RTEST(rb_yield(rb_assoc_new(key, val))))
397
+ rb_hash_aset(hash, key, val);
398
+ }
399
+ }
400
+ return hash;
401
+ }
402
+
403
+ /*
404
+ * @yield [key, value]
405
+ * @yieldparam key [String]
406
+ * @yieldparam value [Object]
407
+ * @return [Enumerator | ::Hash]
408
+ */
409
+ VALUE w_hash_slice(const int argc, const VALUE *argv, const VALUE self) {
410
+ UsaminValue *value = get_value(self);
411
+ check_object(value);
412
+ VALUE hash = rb_hash_new();
413
+ for (int i = 0; i < argc; i++)
414
+ for (auto &m : value->value->GetObject())
415
+ if (str_compare_xx(argv[i], m.name))
416
+ rb_hash_aset(hash, eval_str(m.name), eval(m.value, value->root_document));
417
+ return hash;
418
+ }
419
+
420
+ /*
421
+ * Convert to Ruby Hash. Same as {Value#eval}.
422
+ *
423
+ * @return [::Hash]
424
+ */
425
+ VALUE w_hash_eval(const VALUE self) {
426
+ UsaminValue *value = get_value(self);
427
+ check_object(value);
428
+ return eval_object(*(value->value), value->root_document, 0);
429
+ }
430
+
431
+ /*
432
+ * @return [::Hash]
433
+ */
434
+ VALUE w_hash_merge(const int argc, const VALUE *argv, const VALUE self) {
435
+ static ID s = rb_intern("merge");
436
+ VALUE args, block;
437
+ rb_scan_args(argc, argv, "*&", &args, &block);
438
+ return rb_funcall_with_block(w_hash_eval(self), s, RARRAY_LENINT(args), RARRAY_CONST_PTR(args), block);
439
+ }
440
+
441
+ /*
442
+ * @return [::Array<Object>]
443
+ */
444
+ VALUE w_hash_values(const VALUE self) {
445
+ UsaminValue *value = get_value(self);
446
+ check_object(value);
447
+ VALUE ret = rb_ary_new2(value->value->MemberCount());
448
+ for (auto &m : value->value->GetObject())
449
+ rb_ary_push(ret, eval(m.value, value->root_document));
450
+ return ret;
451
+ }
452
+
453
+ static VALUE hash_proc_call(RB_BLOCK_CALL_FUNC_ARGLIST(key, self)) {
454
+ rb_check_arity(argc, 1, 1);
455
+ return w_hash_operator_indexer(self, key);
456
+ }
457
+
458
+ /*
459
+ * @return [Proc]
460
+ */
461
+ VALUE w_hash_to_proc(const VALUE self) {
462
+ #if RUBY_API_VERSION_CODE < 20700
463
+ return rb_proc_new(RUBY_METHOD_FUNC(hash_proc_call), self);
464
+ #else
465
+ return rb_proc_new(hash_proc_call, self);
466
+ #endif
467
+ }
468
+
469
+ /*
470
+ * @yield [key]
471
+ * @yieldparam key [String]
472
+ * @return [Enumerator | ::Hash]
473
+ */
474
+ VALUE w_hash_transform_keys(const VALUE self) {
475
+ UsaminValue *value = get_value(self);
476
+ check_object(value);
477
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
478
+ VALUE hash = rb_hash_new();
479
+ for (auto &m : value->value->GetObject())
480
+ rb_hash_aset(hash, rb_yield(eval_str(m.name)), eval(m.value, value->root_document));
481
+ return hash;
482
+ }
483
+
484
+ /*
485
+ * @yield [value]
486
+ * @yieldparam value [Object]
487
+ * @return [Enumerator | ::Hash]
488
+ */
489
+ VALUE w_hash_transform_values(const VALUE self) {
490
+ UsaminValue *value = get_value(self);
491
+ check_object(value);
492
+ RETURN_SIZED_ENUMERATOR(self, 0, nullptr, hash_enum_size);
493
+ VALUE hash = rb_hash_new();
494
+ for (auto &m : value->value->GetObject())
495
+ rb_hash_aset(hash, eval_str(m.name), rb_yield(eval(m.value, value->root_document)));
496
+ return hash;
497
+ }
498
+
499
+ /*
500
+ * @param [String] keys
501
+ * @return [::Array<Object>]
502
+ */
503
+ VALUE w_hash_values_at(const int argc, const VALUE *argv, const VALUE self) {
504
+ UsaminValue *value = get_value(self);
505
+ check_object(value);
506
+ VALUE ret = rb_ary_new2(argc);
507
+ for (int i = 0; i < argc; i++) {
508
+ VALUE data = Qnil;
509
+ for (auto &m : value->value->GetObject()) {
510
+ if (str_compare_xx(argv[i], m.name)) {
511
+ data = eval(m.value, value->root_document);
512
+ break;
513
+ }
514
+ }
515
+ rb_ary_push(ret, data);
516
+ }
517
+ return ret;
518
+ }