jsoncons 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10b43faedc8965c2cd6e67f32d231fdb9c948eac6b8dcf0b947234a4000f35bb
4
- data.tar.gz: 754df3b74e8c2c122067e200d5511b448cd995efceee344526e9b66cc133b67b
3
+ metadata.gz: ab31d9df587fe4d899295ca8f8e19e354993ec6b7f5f013a534c714a169757c6
4
+ data.tar.gz: d3726fc0abbdd8a11946e953e368de393097ad3072f804ba1a7d08ca7f148bee
5
5
  SHA512:
6
- metadata.gz: ad1d02c59ec7fd103c2fd708ef42e768a5647a8f111b807546c0ccf95ba4c44aa87daeb56d88e4bfbeb6dc271c20b94779d50e568d1773a9efb7bcbe05502543
7
- data.tar.gz: 2cde180c82a272da1d585acdf922b255a9d2872983824eb07668a2de448b6858d7436ab4d11af6dbb13469f4c73ac323df42e24880abf227eaf9646786f8a216
6
+ metadata.gz: ff2a73dc4420cf05b778a1f9d15e36ca454587a34bc32b01d58ff6165c2c138cb9b4775a3748624f1b7fd252158c79fe66e2fb8545ce139e052b731f095846a2
7
+ data.tar.gz: 615561775db0a13861f2130d18b898c0f35b75004b5e3a34cbe0e4b96846b7f60fec822edc5cfe8a80c58cf99052a708e89a32e0a24cebea6056f37ee4e7a0b9
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ -e yard_extensions.rb --markup=markdown
@@ -2,9 +2,9 @@
2
2
 
3
3
  using namespace Rice;
4
4
 
5
- typedef /* jsoncons::wojson */ jsoncons::ojson json_class_type;
5
+ using json_class_type = /* jsoncons::wojson */ jsoncons::ojson;
6
6
  // wchar_t is not defined with Rice
7
- typedef /* std::wstring */ std::string json_string_type;
7
+ using json_string_type = /* std::wstring */ std::string;
8
8
 
9
9
  Module rb_mJsoncons;
10
10
  Data_Type<json_class_type> rb_cJsoncons_Json;
@@ -31,9 +31,37 @@ static auto json_query(const json_class_type &self, const json_string_type &path
31
31
  else return jsoncons::jsonpath::json_query(self, path);
32
32
  }
33
33
 
34
+ static auto &json_at(const json_class_type &self, const VALUE value) {
35
+ switch (rb_type(value)) {
36
+ case RUBY_T_STRING:
37
+ return self.at(Rice::detail::From_Ruby<json_string_type>().convert(value));
38
+ case RUBY_T_SYMBOL:
39
+ return self.at(Symbol(value).str());
40
+ case RUBY_T_FIXNUM:
41
+ case RUBY_T_BIGNUM:
42
+ return self.at(Rice::detail::From_Ruby<std::size_t>().convert(value));
43
+ default: {
44
+ throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
45
+ detail::protect(rb_obj_classname, value), "String|Symbol|Integer");
46
+ }
47
+ }
48
+ }
49
+
34
50
  extern "C"
35
- void Init_jsoncons() {
51
+ [[maybe_unused]] void Init_jsoncons() {
36
52
  rb_mJsoncons = define_module("Jsoncons");
53
+
54
+
55
+ /*
56
+ * Document-class: Jsoncons::Json
57
+ *
58
+ * A wrapper for +jsoncons::ojson+ type;
59
+ * +o+ stands for +order_preserving+, this type was chosen as more familiar for Ruby programmes than
60
+ * sorted +jsoncons::json+.
61
+ * And here is the only place where strategy for converting names from C++ to Ruby, according to which
62
+ * +jsoncons::jsonpath::jsonpath_expression+ becomes +Jsoncons::JsonPath::Expression+,
63
+ * is not followed for convenience
64
+ */
37
65
  rb_cJsoncons_Json =
38
66
  define_class_under<json_class_type>(rb_mJsoncons, "Json")
39
67
  .define_constructor(Constructor<json_class_type>());
@@ -75,29 +103,21 @@ void Init_jsoncons() {
75
103
  rb_define_alias(rb_cJsoncons_Json, "to_s", "to_string");
76
104
  rb_define_alias(rb_cJsoncons_Json, "inspect", "to_string");
77
105
 
78
- // also has_member
79
106
  rb_cJsoncons_Json.define_method("contains",
80
107
  [](const json_class_type &self, const json_string_type &key) {
81
108
  return self.contains(key);
82
109
  });
83
- // rb_cJsoncons_Json.define_method("[]", &key_or_index, Arg("arg").isValue());
84
110
 
85
- rb_cJsoncons_Json.define_method("at_key", [](const json_class_type &self,
86
- const json_string_type &key) {
87
- return self.at(key);
88
- });
89
- rb_cJsoncons_Json.define_method("at_index", [](const json_class_type &self,
90
- const std::size_t &i) {
91
- return self.at(i);
92
- });
111
+ rb_cJsoncons_Json.define_method("at", &json_at, Arg("value").isValue(), Return().keepAlive());
112
+ rb_define_alias(rb_cJsoncons_Json, "[]", "at");
93
113
  rb_cJsoncons_Json.define_method("query", &json_query,
94
114
  Arg("options") = (std::optional<int>) std::nullopt);
95
115
 
96
116
  rb_cJsoncons_Json
97
117
  .define_method("size", &json_class_type::size)
98
118
  .define_method("empty", &json_class_type::empty)
99
- .define_method("clear", &json_class_type::clear) // Doesn't work like that # data["arr"].clear
100
- .define_method("swap", &json_class_type::swap) // Doesn't work like that # data["arr"].swap(other_arr)
119
+ .define_method("clear", &json_class_type::clear)
120
+ .define_method("swap", &json_class_type::swap)
101
121
  // .define_method("remove", &json_class_type::remove) // erase
102
122
  // .define_method("insert", &json_class_type::insert) // add
103
123
  // .define_method("insert_or_assign", &json_class_type::insert_or_assign) // set
@@ -144,11 +164,28 @@ void Init_jsoncons() {
144
164
  // .define_method("at_or_null", &json_class_type::at_or_null) // Type is not defined with Rice
145
165
  // .define_method("get_value_or", &json_class_type::get_value_or)
146
166
  // .define_method("get_with_default", &json_class_type::get_with_default) // get
147
- // .define_method("is_datetime", &json_class_type::is_datetime) // Tags
148
- // .define_method("is_epoch_time", &json_class_type::is_epoch_time) // Tags
149
- // .define_method("compare", &json_class_type::compare) // "to_json not implemented"
150
- // rb_define_alias(rb_cJsoncons_Json, "<=>", "compare");
151
-
167
+ rb_cJsoncons_Json.define_method("is_datetime", [](const json_class_type &self) {
168
+ return self.tag() ==
169
+ jsoncons::semantic_tag::datetime; // TODO: implement semantic_tag enum instead
170
+ })
171
+ .define_method("is_epoch_time", [](const json_class_type &self) {
172
+ return self.tag() ==
173
+ jsoncons::semantic_tag::epoch_second; // TODO: implement semantic_tag enum instead
174
+ })
175
+ .define_method("is_integer", [](const json_class_type &self) {
176
+ return self.is_integer<size_t>();
177
+ });
178
+ // Data_Object<json_class_type> rhs(value);
179
+ /**
180
+ * @!parse [c]
181
+ * rb_define_method(rb_cJsoncons_Json, "compare", compare, 1);
182
+ */
183
+ rb_cJsoncons_Json.define_method("compare", [](const json_class_type &self,
184
+ json_class_type &rhs) {
185
+ return self.compare(rhs);
186
+ });
187
+ rb_define_alias(rb_cJsoncons_Json, "<=>", "compare");
188
+ rb_define_alias(rb_cJsoncons_Json, "empty?", "empty");
152
189
 
153
190
  // rb_cJsoncons_Json.define_method("to_a", [](const json_class_type &self) {
154
191
  // std::vector<json_class_type> res(self.size());
@@ -4,6 +4,7 @@
4
4
  #include <rice/rice.hpp>
5
5
  #include <rice/stl.hpp>
6
6
  #undef isfinite
7
+ #define JSONCONS_NO_DEPRECATED 1
7
8
  #include "jsoncons/json.hpp"
8
9
  #include "jsoncons_ext/jsonpath/jsonpath.hpp"
9
10
 
data/jsoncons.gemspec CHANGED
@@ -8,22 +8,27 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["uvlad7"]
9
9
  spec.email = ["uvlad7@gmail.com"]
10
10
 
11
- spec.summary = "Ruby wrapper for https://github.com/danielaparker/jsoncons"
11
+ spec.summary = "Ruby wrapper for jsoncons library and jsonpath"
12
+ spec.description = "Ruby wrapper for a part of [jsoncons](https://github.com/danielaparker/jsoncons) library," \
13
+ "mostly for its jsonpath implementation"
12
14
  spec.homepage = "https://github.com/uvlad7/ruby-jsoncons"
13
15
  spec.license = "MIT"
14
- spec.required_ruby_version = ">= 2.6.0"
16
+ spec.required_ruby_version = ">= 2.5"
15
17
 
16
18
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
17
19
 
18
20
  spec.metadata["homepage_uri"] = spec.homepage
19
21
  spec.metadata["source_code_uri"] = "https://github.com/uvlad7/ruby-jsoncons"
20
22
  spec.metadata["changelog_uri"] = "https://github.com/uvlad7/ruby-jsoncons"
23
+ spec.metadata["documentation_uri"] = "https://rubydoc.info/gems/jsoncons/frames"
24
+ spec.metadata["library_uri"] = "https://github.com/danielaparker/jsoncons"
21
25
 
22
26
  # Specify which files should be added to the gem when it is released.
23
27
  spec.files = [
24
28
  *Dir["lib/jsoncons/jsoncons/include/**/*"].reject { |f| File.directory?(f) },
25
29
  "ext/jsoncons/jsoncons.cpp", "ext/jsoncons/jsoncons.h", "jsoncons.gemspec", "lib/jsoncons.rb",
26
- "lib/jsoncons/version.rb"
30
+ "lib/jsoncons/version.rb",
31
+ "yard_extensions.rb", ".yardopts"
27
32
  ]
28
33
  spec.test_files = [
29
34
  *Dir["lib/jsoncons/jsoncons/examples/input/**/*"].reject { |f| File.directory?(f) },
@@ -38,6 +43,7 @@ Gem::Specification.new do |spec|
38
43
  spec.add_development_dependency "get_process_mem"
39
44
  spec.add_development_dependency "pry"
40
45
  spec.add_development_dependency "pry-byebug"
46
+ spec.add_development_dependency "yard"
41
47
 
42
48
  # For more information and examples about making a new gem, checkout our
43
49
  # guide at: https://bundler.io/guides/creating_gem.html
@@ -0,0 +1,816 @@
1
+ #ifndef JSONCONS_BSON_BSON_DECIMAL128_HPP
2
+ #define JSONCONS_BSON_BSON_DECIMAL128_HPP
3
+
4
+ /*
5
+ * Copyright 2015 MongoDB, Inc.
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
+ #include <stdlib.h>
21
+ #include <string.h>
22
+ #include <ctype.h>
23
+ #include <system_error>
24
+ #include <jsoncons/config/jsoncons_config.hpp>
25
+
26
+ namespace jsoncons { namespace bson {
27
+
28
+ struct decimal128_to_chars_result
29
+ {
30
+ char* ptr;
31
+ std::errc ec;
32
+ };
33
+
34
+ struct decimal128_from_chars_result
35
+ {
36
+ const char* ptr;
37
+ std::errc ec;
38
+ };
39
+
40
+ /**
41
+ * BSON_DECIMAL128_STRING:
42
+ *
43
+ * The length of a decimal128 string (with null terminator).
44
+ *
45
+ * 1 for the sign
46
+ * 35 for digits and radix
47
+ * 2 for exponent indicator and sign
48
+ * 4 for exponent digits
49
+ */
50
+ #define BSON_DECIMAL128_STRING 43
51
+ #define BSON_DECIMAL128_INF "Infinity"
52
+ #define BSON_DECIMAL128_NAN "NaN"
53
+
54
+ struct TP1
55
+ {
56
+ uint64_t low;
57
+ uint64_t high;
58
+
59
+ constexpr TP1() : low(0), high(0) {}
60
+ constexpr TP1(uint64_t hi, uint64_t lo) : low(lo), high(hi) {}
61
+ };
62
+ struct TP2
63
+ {
64
+ uint64_t high;
65
+ uint64_t low;
66
+
67
+ constexpr TP2() : high(0), low(0) {}
68
+ constexpr TP2(uint64_t hi, uint64_t lo) : high(hi), low(lo) {}
69
+ };
70
+
71
+ typedef typename std::conditional<
72
+ jsoncons::endian::native == jsoncons::endian::little,
73
+ TP1,
74
+ TP2
75
+ >::type decimal128_t;
76
+
77
+ inline
78
+ bool operator==(const decimal128_t& lhs, const decimal128_t& rhs)
79
+ {
80
+ return lhs.high == rhs.high && lhs.low == rhs.low;
81
+ }
82
+
83
+ inline
84
+ bool operator!=(const decimal128_t& lhs, const decimal128_t& rhs)
85
+ {
86
+ return !(lhs == rhs);
87
+ }
88
+
89
+ struct decimal128_limits
90
+ {
91
+ // The length of a decimal128 string (without null terminator).
92
+ //
93
+ // 1 for the sign
94
+ // 35 for digits and radix
95
+ // 2 for exponent indicator and sign
96
+ // 4 for exponent digits
97
+ static constexpr int recommended_buffer_size = 42;
98
+ static constexpr decimal128_t nan = decimal128_t(0x7c00000000000000ull, 0);
99
+ static constexpr decimal128_t infinity = decimal128_t(0x7800000000000000ull, 0);
100
+ static constexpr decimal128_t neg_infinity = decimal128_t(0x7800000000000000ull + 0x8000000000000000ull, 0);
101
+ static constexpr int exponent_max = 6111;
102
+ static constexpr int exponent_min = -6176;
103
+ static constexpr int exponent_bias = 6176;
104
+ static constexpr int max_digits = 34;
105
+ };
106
+
107
+ /**
108
+ * bson_uint128_t:
109
+ *
110
+ * This struct represents a 128 bit integer.
111
+ */
112
+ typedef struct {
113
+ uint32_t parts[4]; /* 32-bit words stored high to low. */
114
+ } bson_uint128_t;
115
+
116
+ typedef struct {
117
+ uint64_t high, low;
118
+ } bson_uint128_6464_t;
119
+
120
+ namespace detail {
121
+
122
+ /**
123
+ *------------------------------------------------------------------------------
124
+ *
125
+ * bson_uint128_divide1B --
126
+ *
127
+ * This function divides a #bson_uint128_t by 1000000000 (1 billion) and
128
+ * computes the quotient and remainder.
129
+ *
130
+ * The remainder will contain 9 decimal digits for conversion to string.
131
+ *
132
+ * @value The #bson_uint128_t operand.
133
+ * @quotient A pointer to store the #bson_uint128_t quotient.
134
+ * @rem A pointer to store the #uint64_t remainder.
135
+ *
136
+ * Returns:
137
+ * The quotient at @quotient and the remainder at @rem.
138
+ *
139
+ * Side effects:
140
+ * None.
141
+ *
142
+ *------------------------------------------------------------------------------
143
+ */
144
+
145
+ inline
146
+ void bson_uint128_divide1B (bson_uint128_t value, /* IN */
147
+ bson_uint128_t *quotient, /* OUT */
148
+ uint32_t *rem) /* OUT */
149
+ {
150
+ const uint32_t DIVISOR = 1000 * 1000 * 1000;
151
+ uint64_t _rem = 0;
152
+ int i = 0;
153
+
154
+ if (!value.parts[0] && !value.parts[1] && !value.parts[2] &&
155
+ !value.parts[3]) {
156
+ *quotient = value;
157
+ *rem = 0;
158
+ return;
159
+ }
160
+
161
+ for (i = 0; i <= 3; i++) {
162
+ _rem <<= 32; /* Adjust remainder to match value of next dividend */
163
+ _rem += value.parts[i]; /* Add the divided to _rem */
164
+ value.parts[i] = (uint32_t) (_rem / DIVISOR);
165
+ _rem %= DIVISOR; /* Store the remainder */
166
+ }
167
+
168
+ *quotient = value;
169
+ *rem = (uint32_t) _rem;
170
+ }
171
+
172
+ /**
173
+ *-------------------------------------------------------------------------
174
+ *
175
+ * mul64x64 --
176
+ *
177
+ * This function multiplies two &uint64_t into a &bson_uint128_6464_t.
178
+ *
179
+ * Returns:
180
+ * The product of @left and @right.
181
+ *
182
+ * Side Effects:
183
+ * None.
184
+ *
185
+ *-------------------------------------------------------------------------
186
+ */
187
+
188
+ inline
189
+ void mul_64x64 (uint64_t left, /* IN */
190
+ uint64_t right, /* IN */
191
+ bson_uint128_6464_t *product) /* OUT */
192
+ {
193
+ uint64_t left_high, left_low, right_high, right_low, product_high,
194
+ product_mid, product_mid2, product_low;
195
+ bson_uint128_6464_t rt = {0};
196
+
197
+ if (!left && !right) {
198
+ *product = rt;
199
+ return;
200
+ }
201
+
202
+ left_high = left >> 32;
203
+ left_low = (uint32_t) left;
204
+ right_high = right >> 32;
205
+ right_low = (uint32_t) right;
206
+
207
+ product_high = left_high * right_high;
208
+ product_mid = left_high * right_low;
209
+ product_mid2 = left_low * right_high;
210
+ product_low = left_low * right_low;
211
+
212
+ product_high += product_mid >> 32;
213
+ product_mid = (uint32_t) product_mid + product_mid2 + (product_low >> 32);
214
+
215
+ product_high = product_high + (product_mid >> 32);
216
+ product_low = (product_mid << 32) + (uint32_t) product_low;
217
+
218
+ rt.high = product_high;
219
+ rt.low = product_low;
220
+ *product = rt;
221
+ }
222
+
223
+ /**
224
+ *------------------------------------------------------------------------------
225
+ *
226
+ * dec128_tolower --
227
+ *
228
+ * This function converts the ASCII character @c to lowercase. It is locale
229
+ * insensitive (unlike the stdlib tolower).
230
+ *
231
+ * Returns:
232
+ * The lowercased character.
233
+ */
234
+
235
+ inline
236
+ char dec128_tolower (char c)
237
+ {
238
+ if (isupper (c)) {
239
+ c += 32;
240
+ }
241
+
242
+ return c;
243
+ }
244
+
245
+ /**
246
+ *------------------------------------------------------------------------------
247
+ *
248
+ * dec128_istreq --
249
+ *
250
+ * This function compares the null-terminated *ASCII* strings @a and @b
251
+ * for case-insensitive equality.
252
+ *
253
+ * Returns:
254
+ * true if the strings are equal, false otherwise.
255
+ */
256
+
257
+ inline
258
+ bool dec128_istreq (const char* a, /* IN */
259
+ const char* b /* IN */)
260
+ {
261
+ while (*a != '\0' || *b != '\0') {
262
+ /* strings are different lengths. */
263
+ if (*a == '\0' || *b == '\0') {
264
+ return false;
265
+ }
266
+
267
+ if (dec128_tolower (*a) != dec128_tolower (*b)) {
268
+ return false;
269
+ }
270
+
271
+ a++;
272
+ b++;
273
+ }
274
+
275
+ return true;
276
+ }
277
+
278
+ } // namespace detail
279
+
280
+
281
+ /**
282
+ *------------------------------------------------------------------------------
283
+ *
284
+ * decimal128_to_chars --
285
+ *
286
+ * This function converts a BID formatted decimal128 value to string,
287
+ * accepting a &decimal128_t as @dec. The string is stored at @str.
288
+ *
289
+ * @dec : The BID formatted decimal to convert.
290
+ * @str : The output decimal128 string. At least %BSON_DECIMAL128_STRING
291
+ *characters.
292
+ *
293
+ * Returns:
294
+ * None.
295
+ *
296
+ * Side effects:
297
+ * None.
298
+ *
299
+ *------------------------------------------------------------------------------
300
+ */
301
+
302
+ inline
303
+ void decimal128_to_chars(char* first, char* last, const decimal128_t& dec)
304
+ {
305
+ uint32_t COMBINATION_MASK = 0x1f; /* Extract least significant 5 bits */
306
+ uint32_t EXPONENT_MASK = 0x3fff; /* Extract least significant 14 bits */
307
+ uint32_t COMBINATION_INFINITY = 30; /* Value of combination field for Inf */
308
+ uint32_t COMBINATION_NAN = 31; /* Value of combination field for NaN */
309
+ uint32_t EXPONENT_BIAS = 6176; /* decimal128 exponent bias */
310
+
311
+ char* str_out = first; /* output pointer in string */
312
+ char significand_str[35]; /* decoded significand digits */
313
+
314
+
315
+ /* Note: bits in this routine are referred to starting at 0, */
316
+ /* from the sign bit, towards the coefficient. */
317
+ uint32_t high; /* bits 0 - 31 */
318
+ uint32_t midh; /* bits 32 - 63 */
319
+ uint32_t midl; /* bits 64 - 95 */
320
+ uint32_t low; /* bits 96 - 127 */
321
+ uint32_t combination; /* bits 1 - 5 */
322
+ uint32_t biased_exponent; /* decoded biased exponent (14 bits) */
323
+ uint32_t significand_digits = 0; /* the number of significand digits */
324
+ uint32_t significand[36] = {0}; /* the base-10 digits in the significand */
325
+ uint32_t *significand_read = significand; /* read pointer into significand */
326
+ int32_t exponent; /* unbiased exponent */
327
+ int32_t scientific_exponent; /* the exponent if scientific notation is
328
+ * used */
329
+ bool is_zero = false; /* true if the number is zero */
330
+
331
+ uint8_t significand_msb; /* the most signifcant significand bits (50-46) */
332
+ bson_uint128_t
333
+ significand128; /* temporary storage for significand decoding */
334
+ size_t i; /* indexing variables */
335
+ int j, k;
336
+
337
+ memset (significand_str, 0, sizeof (significand_str));
338
+
339
+ if ((int64_t) dec.high < 0) { /* negative */
340
+ *(str_out++) = '-';
341
+ }
342
+
343
+ low = (uint32_t) dec.low, midl = (uint32_t) (dec.low >> 32),
344
+ midh = (uint32_t) dec.high, high = (uint32_t) (dec.high >> 32);
345
+
346
+ /* Decode combination field and exponent */
347
+ combination = (high >> 26) & COMBINATION_MASK;
348
+
349
+ if (JSONCONS_UNLIKELY ((combination >> 3) == 3)) {
350
+ /* Check for 'special' values */
351
+ if (combination == COMBINATION_INFINITY) { /* Infinity */
352
+ strcpy (str_out, BSON_DECIMAL128_INF);
353
+ return;
354
+ } else if (combination == COMBINATION_NAN) { /* NaN */
355
+ /* first, not str_out, to erase the sign */
356
+ strcpy (first, BSON_DECIMAL128_NAN);
357
+ /* we don't care about the NaN payload. */
358
+ return;
359
+ } else {
360
+ biased_exponent = (high >> 15) & EXPONENT_MASK;
361
+ significand_msb = 0x8 + ((high >> 14) & 0x1);
362
+ }
363
+ } else {
364
+ significand_msb = (high >> 14) & 0x7;
365
+ biased_exponent = (high >> 17) & EXPONENT_MASK;
366
+ }
367
+
368
+ exponent = biased_exponent - EXPONENT_BIAS;
369
+ /* Create string of significand digits */
370
+
371
+ /* Convert the 114-bit binary number represented by */
372
+ /* (high, midh, midl, low) to at most 34 decimal */
373
+ /* digits through modulo and division. */
374
+ significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14);
375
+ significand128.parts[1] = midh;
376
+ significand128.parts[2] = midl;
377
+ significand128.parts[3] = low;
378
+
379
+ if (significand128.parts[0] == 0 && significand128.parts[1] == 0 &&
380
+ significand128.parts[2] == 0 && significand128.parts[3] == 0) {
381
+ is_zero = true;
382
+ } else if (significand128.parts[0] >= (1 << 17)) {
383
+ /* The significand is non-canonical or zero.
384
+ * In order to preserve compatibility with the densely packed decimal
385
+ * format, the maximum value for the significand of decimal128 is
386
+ * 1e34 - 1. If the value is greater than 1e34 - 1, the IEEE 754
387
+ * standard dictates that the significand is interpreted as zero.
388
+ */
389
+ is_zero = true;
390
+ } else {
391
+ for (k = 3; k >= 0; k--) {
392
+ uint32_t least_digits = 0;
393
+ detail::bson_uint128_divide1B (
394
+ significand128, &significand128, &least_digits);
395
+
396
+ /* We now have the 9 least significant digits (in base 2). */
397
+ /* Convert and output to string. */
398
+ if (!least_digits) {
399
+ continue;
400
+ }
401
+
402
+ for (j = 8; j >= 0; j--) {
403
+ significand[k * 9 + j] = least_digits % 10;
404
+ least_digits /= 10;
405
+ }
406
+ }
407
+ }
408
+
409
+ /* Output format options: */
410
+ /* Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd */
411
+ /* Regular - ddd.ddd */
412
+
413
+ if (is_zero) {
414
+ significand_digits = 1;
415
+ *significand_read = 0;
416
+ } else {
417
+ significand_digits = 36;
418
+ while (!(*significand_read)) {
419
+ significand_digits--;
420
+ significand_read++;
421
+ }
422
+ }
423
+
424
+ scientific_exponent = significand_digits - 1 + exponent;
425
+
426
+ /* The scientific exponent checks are dictated by the string conversion
427
+ * specification and are somewhat arbitrary cutoffs.
428
+ *
429
+ * We must check exponent > 0, because if this is the case, the number
430
+ * has trailing zeros. However, we *cannot* output these trailing zeros,
431
+ * because doing so would change the precision of the value, and would
432
+ * change stored data if the string converted number is round tripped.
433
+ */
434
+ if (scientific_exponent < -6 || exponent > 0) {
435
+ /* Scientific format */
436
+ *(str_out++) = *(significand_read++) + '0';
437
+ significand_digits--;
438
+
439
+ if (significand_digits) {
440
+ *(str_out++) = '.';
441
+ }
442
+
443
+ for (i = 0; i < significand_digits && (str_out - first) < 36; i++) {
444
+ *(str_out++) = *(significand_read++) + '0';
445
+ }
446
+ /* Exponent */
447
+ *(str_out++) = 'E';
448
+ snprintf (str_out, 6, "%+d", scientific_exponent);
449
+ } else {
450
+ /* Regular format with no decimal place */
451
+ if (exponent >= 0) {
452
+ for (i = 0; i < significand_digits && (str_out - first) < 36; i++) {
453
+ *(str_out++) = *(significand_read++) + '0';
454
+ }
455
+ *str_out = '\0';
456
+ } else {
457
+ int32_t radix_position = significand_digits + exponent;
458
+
459
+ if (radix_position > 0) { /* non-zero digits before radix */
460
+ for (i = 0;
461
+ i < radix_position && (str_out < last);
462
+ i++) {
463
+ *(str_out++) = *(significand_read++) + '0';
464
+ }
465
+ } else { /* leading zero before radix point */
466
+ *(str_out++) = '0';
467
+ }
468
+
469
+ *(str_out++) = '.';
470
+ while (radix_position++ < 0) { /* add leading zeros after radix */
471
+ *(str_out++) = '0';
472
+ }
473
+
474
+ for (i = 0;
475
+ (i < significand_digits - (std::max) (radix_position - 1, 0)) &&
476
+ (str_out < last);
477
+ i++) {
478
+ *(str_out++) = *(significand_read++) + '0';
479
+ }
480
+ *str_out = '\0';
481
+ }
482
+ }
483
+ }
484
+
485
+
486
+
487
+ /**
488
+ *------------------------------------------------------------------------------
489
+ *
490
+ * bson_decimal128_from_string_w_len --
491
+ *
492
+ * This function converts @string in the format [+-]ddd[.]ddd[E][+-]dddd to
493
+ * decimal128. Out of range values are converted to +/-Infinity. Invalid
494
+ * strings are converted to NaN. @len is the length of the string, or -1
495
+ * meaning the string is null-terminated.
496
+ *
497
+ * If more digits are provided than the available precision allows,
498
+ * round to the nearest expressable decimal128 with ties going to even will
499
+ * occur.
500
+ *
501
+ * Note: @string must be ASCII only!
502
+ *
503
+ * Returns:
504
+ * true on success, or false on failure. @dec will be NaN if @str was invalid
505
+ * The &decimal128_t converted from @string at @dec.
506
+ *
507
+ * Side effects:
508
+ * None.
509
+ *
510
+ *------------------------------------------------------------------------------
511
+ */
512
+
513
+ inline
514
+ bool decimal128_from_chars(const char* first, const char* last, decimal128_t& dec)
515
+ {
516
+ int len = last - first;
517
+
518
+ bson_uint128_6464_t significand = {0};
519
+
520
+ const char* str_read = first; /* Read pointer for consuming str. */
521
+
522
+ /* Parsing state tracking */
523
+ bool is_negative = false;
524
+ bool saw_radix = false;
525
+ bool includes_sign = false; /* True if the input first contains a sign. */
526
+ bool found_nonzero = false;
527
+
528
+ size_t significant_digits = 0; /* Total number of significant digits
529
+ * (no leading or trailing zero) */
530
+ size_t ndigits_read = 0; /* Total number of significand digits read */
531
+ size_t ndigits = 0; /* Total number of digits (no leading zeros) */
532
+ size_t radix_position = 0; /* The number of the digits after radix */
533
+ size_t first_nonzero = 0; /* The index of the first non-zero in *str* */
534
+
535
+ uint16_t digits[decimal128_limits::max_digits] = {0};
536
+ uint16_t ndigits_stored = 0; /* The number of digits in digits */
537
+ uint16_t *digits_insert = digits; /* Insertion pointer for digits */
538
+ size_t first_digit = 0; /* The index of the first non-zero digit */
539
+ size_t last_digit = 0; /* The index of the last digit */
540
+
541
+ int32_t exponent = 0;
542
+ uint64_t significand_high = 0; /* The high 17 digits of the significand */
543
+ uint64_t significand_low = 0; /* The low 17 digits of the significand */
544
+ uint16_t biased_exponent = 0; /* The biased exponent */
545
+
546
+ dec.high = 0;
547
+ dec.low = 0;
548
+
549
+ if (*str_read == '+' || *str_read == '-') {
550
+ is_negative = *(str_read++) == '-';
551
+ includes_sign = true;
552
+ }
553
+
554
+ /* Check for Infinity or NaN */
555
+ if (!isdigit (*str_read) && *str_read != '.') {
556
+ if (detail::dec128_istreq (str_read, "inf") ||
557
+ detail::dec128_istreq (str_read, "infinity")) {
558
+ dec = is_negative ? decimal128_limits::neg_infinity : decimal128_limits::infinity;
559
+ return true;
560
+ } else if (detail::dec128_istreq (str_read, "nan")) {
561
+ dec = decimal128_limits::nan;
562
+ return true;
563
+ }
564
+
565
+ dec = decimal128_limits::nan;
566
+ return false;
567
+ }
568
+
569
+ /* Read digits */
570
+ while (((isdigit (*str_read) || *str_read == '.')) &&
571
+ (len == -1 || str_read < first + len)) {
572
+ if (*str_read == '.') {
573
+ if (saw_radix) {
574
+ dec = decimal128_limits::nan;
575
+ return false;
576
+ }
577
+
578
+ saw_radix = true;
579
+ str_read++;
580
+ continue;
581
+ }
582
+
583
+ if (ndigits_stored < 34) {
584
+ if (*str_read != '0' || found_nonzero) {
585
+ if (!found_nonzero) {
586
+ first_nonzero = ndigits_read;
587
+ }
588
+
589
+ found_nonzero = true;
590
+ *(digits_insert++) = *(str_read) - '0'; /* Only store 34 digits */
591
+ ndigits_stored++;
592
+ }
593
+ }
594
+
595
+ if (found_nonzero) {
596
+ ndigits++;
597
+ }
598
+
599
+ if (saw_radix) {
600
+ radix_position++;
601
+ }
602
+
603
+ ndigits_read++;
604
+ str_read++;
605
+ }
606
+
607
+ if (saw_radix && !ndigits_read) {
608
+ dec = decimal128_limits::nan;
609
+ return false;
610
+ }
611
+
612
+ /* Read exponent if exists */
613
+ if (*str_read == 'e' || *str_read == 'E') {
614
+ int nread = 0;
615
+ #ifdef _MSC_VER
616
+ #define SSCANF sscanf_s
617
+ #else
618
+ #define SSCANF sscanf
619
+ #endif
620
+ int read_exponent = SSCANF (++str_read, "%d%n", &exponent, &nread);
621
+ str_read += nread;
622
+
623
+ if (!read_exponent || nread == 0) {
624
+ dec = decimal128_limits::nan;
625
+ return false;
626
+ }
627
+
628
+ #undef SSCANF
629
+ }
630
+
631
+ if ((len == -1 || str_read < first + len) && *str_read) {
632
+ dec = decimal128_limits::nan;
633
+ return false;
634
+ }
635
+
636
+ /* Done reading input. */
637
+ /* Find first non-zero digit in digits */
638
+ first_digit = 0;
639
+
640
+ if (!ndigits_stored) { /* value is zero */
641
+ first_digit = 0;
642
+ last_digit = 0;
643
+ digits[0] = 0;
644
+ ndigits = 1;
645
+ ndigits_stored = 1;
646
+ significant_digits = 0;
647
+ } else {
648
+ last_digit = ndigits_stored - 1;
649
+ significant_digits = ndigits;
650
+ /* Mark trailing zeros as non-significant */
651
+ while (first[first_nonzero + significant_digits - 1 + includes_sign +
652
+ saw_radix] == '0') {
653
+ significant_digits--;
654
+ }
655
+ }
656
+
657
+
658
+ /* Normalization of exponent */
659
+ /* Correct exponent based on radix position, and shift significand as needed
660
+ */
661
+ /* to represent user input */
662
+
663
+ /* Overflow prevention */
664
+ if (exponent <= radix_position && radix_position - exponent > (1 << 14)) {
665
+ exponent = decimal128_limits::exponent_min;
666
+ } else {
667
+ exponent -= radix_position;
668
+ }
669
+
670
+ /* Attempt to normalize the exponent */
671
+ while (exponent > decimal128_limits::exponent_max) {
672
+ /* Shift exponent to significand and decrease */
673
+ last_digit++;
674
+
675
+ if (last_digit - first_digit > decimal128_limits::max_digits) {
676
+ /* The exponent is too great to shift into the significand. */
677
+ if (significant_digits == 0) {
678
+ /* Value is zero, we are allowed to clamp the exponent. */
679
+ exponent = decimal128_limits::exponent_max;
680
+ break;
681
+ }
682
+
683
+ /* Overflow is not permitted, error. */
684
+ dec = decimal128_limits::nan;
685
+ return false;
686
+ }
687
+
688
+ exponent--;
689
+ }
690
+
691
+ while (exponent < decimal128_limits::exponent_min || ndigits_stored < ndigits) {
692
+ /* Shift last digit */
693
+ if (last_digit == 0) {
694
+ /* underflow is not allowed, but zero clamping is */
695
+ if (significant_digits == 0) {
696
+ exponent = decimal128_limits::exponent_min;
697
+ break;
698
+ }
699
+
700
+ dec = decimal128_limits::nan;
701
+ return false;
702
+ }
703
+
704
+ if (ndigits_stored < ndigits) {
705
+ if (first[ndigits - 1 + includes_sign + saw_radix] - '0' != 0 &&
706
+ significant_digits != 0) {
707
+ dec = decimal128_limits::nan;
708
+ return false;
709
+ }
710
+
711
+ ndigits--; /* adjust to match digits not stored */
712
+ } else {
713
+ if (digits[last_digit] != 0) {
714
+ /* Inexact rounding is not allowed. */
715
+ dec = decimal128_limits::nan;
716
+ return false;
717
+ }
718
+
719
+
720
+ last_digit--; /* adjust to round */
721
+ }
722
+
723
+ if (exponent < decimal128_limits::exponent_max) {
724
+ exponent++;
725
+ } else {
726
+ dec = decimal128_limits::nan;
727
+ return false;
728
+ }
729
+ }
730
+
731
+ /* Round */
732
+ /* We've normalized the exponent, but might still need to round. */
733
+ if (last_digit - first_digit + 1 < significant_digits) {
734
+ uint8_t round_digit;
735
+
736
+ /* There are non-zero digits after last_digit that need rounding. */
737
+ /* We round to nearest, ties to even */
738
+ round_digit =
739
+ first[first_nonzero + last_digit + includes_sign + saw_radix + 1] -
740
+ '0';
741
+
742
+ if (round_digit != 0) {
743
+ /* Inexact (non-zero) rounding is not allowed */
744
+ dec = decimal128_limits::nan;
745
+ return false;
746
+ }
747
+ }
748
+
749
+ /* Encode significand */
750
+ significand_high = 0, /* The high 17 digits of the significand */
751
+ significand_low = 0; /* The low 17 digits of the significand */
752
+
753
+ if (significant_digits == 0) { /* read a zero */
754
+ significand_high = 0;
755
+ significand_low = 0;
756
+ } else if (last_digit - first_digit < 17) {
757
+ size_t d_idx = first_digit;
758
+ significand_low = digits[d_idx++];
759
+
760
+ for (; d_idx <= last_digit; d_idx++) {
761
+ significand_low *= 10;
762
+ significand_low += digits[d_idx];
763
+ significand_high = 0;
764
+ }
765
+ } else {
766
+ size_t d_idx = first_digit;
767
+ significand_high = digits[d_idx++];
768
+
769
+ for (; d_idx <= last_digit - 17; d_idx++) {
770
+ significand_high *= 10;
771
+ significand_high += digits[d_idx];
772
+ }
773
+
774
+ significand_low = digits[d_idx++];
775
+
776
+ for (; d_idx <= last_digit; d_idx++) {
777
+ significand_low *= 10;
778
+ significand_low += digits[d_idx];
779
+ }
780
+ }
781
+
782
+ detail::mul_64x64 (significand_high, 100000000000000000ull, &significand);
783
+ significand.low += significand_low;
784
+
785
+ if (significand.low < significand_low) {
786
+ significand.high += 1;
787
+ }
788
+
789
+
790
+ biased_exponent = (exponent + (int16_t) decimal128_limits::exponent_bias);
791
+
792
+ /* Encode combination, exponent, and significand. */
793
+ if ((significand.high >> 49) & 1) {
794
+ /* Encode '11' into bits 1 to 3 */
795
+ dec.high |= (0x3ull << 61);
796
+ dec.high |= (biased_exponent & 0x3fffull) << 47;
797
+ dec.high |= significand.high & 0x7fffffffffffull;
798
+ } else {
799
+ dec.high |= (biased_exponent & 0x3fffull) << 49;
800
+ dec.high |= significand.high & 0x1ffffffffffffull;
801
+ }
802
+
803
+ dec.low = significand.low;
804
+
805
+ /* Encode sign */
806
+ if (is_negative) {
807
+ dec.high |= 0x8000000000000000ull;
808
+ }
809
+
810
+ return true;
811
+ }
812
+
813
+ } // namespace bson
814
+ } // namespace jsoncons
815
+
816
+ #endif
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Jsoncons
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/jsoncons.rb CHANGED
@@ -3,31 +3,18 @@
3
3
  require_relative "jsoncons/version"
4
4
  require_relative "jsoncons/jsoncons"
5
5
 
6
+ # A wrapper for a part of {https://github.com/danielaparker/jsoncons jsoncons} library,
7
+ # mostly for its jsonpath implementation
6
8
  module Jsoncons
7
9
  class JsonconsError < StandardError; end
8
10
 
9
- # A wrapper for [jsoncons](https://github.com/danielaparker/jsoncons)
10
- # jsoncons::json class
11
+ # A wrapper for +jsoncons::ojson+ type;
12
+ # +o+ stands for +order_preserving+, this type was chosen as more familiar for Ruby programmes than
13
+ # sorted +jsoncons::json+.
14
+ # And here is the only place where strategy for converting names from C++ to Ruby, according to which
15
+ # +jsoncons::jsonpath::jsonpath_expression+ becomes +Jsoncons::JsonPath::Expression+,
16
+ # is not followed for convenience
11
17
  class Json
12
- # TODO: Implement in cpp
13
- # @raise [RangeError] bignum too big to convert into `unsigned long'
14
- # @raise [RangeError] Invalid array subscript
15
- # @raise [FloatDomainError] Index on non-array value not supported
16
- # @raise [RangeError] Key not found
17
- # @raise [RuntimeError] Attempting to access a member of a value that is not an object
18
- # @param [String|Symbol|Integer] arg
19
- # @return [Jsoncons::Json]
20
- def [](arg)
21
- case arg
22
- when String
23
- at_key(arg)
24
- when Symbol
25
- at_key(arg.to_s)
26
- when Integer
27
- at_index(arg)
28
- else
29
- raise TypeError, "wrong argument type #{arg.class} (expected %String|Symbol|Integer)"
30
- end
31
- end
18
+ include Comparable
32
19
  end
33
20
  end
@@ -2,12 +2,11 @@
2
2
 
3
3
  require "test_helper"
4
4
 
5
- Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(color: true)]
6
-
7
5
  class JsonconsTest < Minitest::Test
8
6
  def test_that_it_has_a_version_number
9
7
  refute_nil ::Jsoncons::VERSION
10
8
  end
9
+
11
10
  # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
12
11
 
13
12
  def test_single_values_parsing
@@ -39,13 +38,13 @@ class JsonconsTest < Minitest::Test
39
38
  assert_equal(data[1].to_s, "2")
40
39
  end
41
40
 
42
- def test_ruby_wrappers_for_method_result_are_different_every_time
41
+ def test_ruby_wrappers_for_method_result_are_different_every_time_but_equal
43
42
  data = Jsoncons::Json.parse('{"first":1,"second":2,"fourth":3,"fifth":4}')
44
- assert(data[1] != data["second"])
43
+ assert(data[1] == data["second"])
45
44
  assert(data[1].object_id != data["second"].object_id)
46
45
  # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
47
46
  assert(data["second"].object_id != data["second"].object_id)
48
- assert(data["second"] != data["second"])
47
+ assert(data["second"] == data["second"])
49
48
  # rubocop:enable Lint/BinaryOperatorWithIdenticalOperands:
50
49
  end
51
50
 
@@ -58,51 +57,18 @@ class JsonconsTest < Minitest::Test
58
57
  assert_equal('{"street_number":"100","street_name":"Queen St W","city":"Toronto","country":"Canada"}', data.to_s)
59
58
  end
60
59
 
61
- def test_jsonpath
62
- # https://github.com/danielaparker/jsoncons/blob/master/doc/ref/jsonpath/jsonpath.md
63
- # https://github.com/danielaparker/jsoncons/blob/master/doc/ref/jsonpath/json_query.md
64
- data = load_json("books")
65
- res = data.query("$.books[1,1,3].title")
66
- assert_instance_of(Jsoncons::Json, res)
67
- assert_equal('["The Night Watch","The Night Watch","The Night Watch"]', res.to_s)
68
- assert_equal(
69
- '["The Night Watch","The Night Watch"]',
70
- # yeah, that's strange
71
- data.query("$.books[1,1,3].title", Jsoncons::JsonPath::ResultOptions::NoDups.to_i).to_s
72
- )
73
- paths = data.query("$.books[1,1,3].title", Jsoncons::JsonPath::ResultOptions::Path.to_i)
74
- assert_instance_of(Jsoncons::Json, paths)
75
- assert_instance_of(Jsoncons::Json, paths[0])
76
- assert_equal(%q(["$['books'][1]['title']","$['books'][1]['title']","$['books'][3]['title']"]), paths.to_s)
77
- assert_equal(
78
- %q(["$['books'][1]['title']","$['books'][3]['title']"]),
79
- data.query(
80
- "$.books[1,1,3].title",
81
- Jsoncons::JsonPath::ResultOptions::Path.to_i | Jsoncons::JsonPath::ResultOptions::NoDups.to_i
82
- ).to_s
83
- )
84
- end
85
-
86
- def test_make_expression
87
- # https://github.com/danielaparker/jsoncons/blob/master/doc/ref/jsonpath/make_expression.md
88
- data = load_json("books")
89
- expr = Jsoncons::JsonPath::Expression.make("$.books[?(@.price > avg($.books[*].price))].title")
90
- assert_instance_of(Jsoncons::JsonPath::Expression, expr)
91
- res = expr.evaluate(data)
92
- assert_equal('["The Night Watch"]', res.to_s)
93
- expr = Jsoncons::JsonPath::Expression.make("$.books[1,1,3].title")
94
- assert_equal('["The Night Watch","The Night Watch","The Night Watch"]', expr.evaluate(data).to_s)
95
- assert_equal(
96
- %q(["$['books'][1]['title']","$['books'][3]['title']"]),
97
- expr.evaluate(
98
- data,
99
- Jsoncons::JsonPath::ResultOptions::Path.to_i | Jsoncons::JsonPath::ResultOptions::NoDups.to_i
100
- ).to_s
101
- )
60
+ def test_square_brakes_return_original_content
61
+ data = Jsoncons::Json.parse('{"data":[1,2,3,4]}')
62
+ arr = data["data"]
63
+ assert_equal("[1,2,3,4]", arr.to_s)
64
+ arr.clear
65
+ assert_equal('{"data":[]}', data.to_s)
66
+ # rubocop:disable Lint/UselessAssignment
67
+ data = nil
68
+ # rubocop:enable Lint/UselessAssignment
69
+ GC.start
70
+ # SIGSEGV if written incorrectly
71
+ assert arr.to_s
102
72
  end
103
73
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
104
-
105
- def load_json(name)
106
- Jsoncons::Json.parse(File.read("lib/jsoncons/jsoncons/examples/input/#{name}.json"))
107
- end
108
74
  end
data/test/test_helper.rb CHANGED
@@ -5,3 +5,9 @@ require "jsoncons"
5
5
 
6
6
  require "minitest/autorun"
7
7
  require "minitest/reporters"
8
+
9
+ Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(color: true)]
10
+
11
+ def load_json(name)
12
+ Jsoncons::Json.parse(File.read("lib/jsoncons/jsoncons/examples/input/#{name}.json"))
13
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ unless defined?(RICE_EXT_LOADED)
4
+ RICE_EXT_LOADED = true
5
+ # handle rice classes
6
+ class RiceClassHandler < YARD::Handlers::C::Base
7
+ MATCH = /(rb_c[\w.]+)\s* = \s*(?:Rice::)?define_class<.+?>\s*
8
+ \(
9
+ \s*"(\w[\wd:]+)"\s*
10
+ (?:,\s*(\w[\wd]*)\s*)?
11
+ \)/mx.freeze
12
+
13
+ MATCH_UNDER = /(rb_c[\w.]+)\s* = \s*(?:Rice::)?define_class_under<.+?>\s*
14
+ \(
15
+ \s*([\w.]+)\s*,
16
+ \s*"(\w[\wd]+)"
17
+ (?:\s*,\s*(\w[\wd]*)\s*)?
18
+ \s*\)/mx.freeze
19
+ handles MATCH
20
+ handles MATCH_UNDER
21
+ statement_class BodyStatement
22
+
23
+ process do
24
+ statement.source.scan(MATCH) do |var_name, class_name, parent|
25
+ handle_class(var_name, class_name, parent&.strip || "rb_cObject")
26
+ end
27
+ statement.source.scan(MATCH_UNDER) do |var_name, in_module, class_name, parent|
28
+ handle_class(var_name, class_name, parent&.strip || "rb_cObject", in_module)
29
+ end
30
+ end
31
+ end
32
+
33
+ # handle rice modules
34
+ class RiceModuleHandler < YARD::Handlers::C::Base
35
+ MATCH = /(rb_m[\w.]+)\s* = \s*(?:Rice::)?define_module\s*
36
+ \(
37
+ \s*"(\w[\wd:]+)"\s*
38
+ \)/mx.freeze
39
+
40
+ MATCH_UNDER = /(rb_m[\w.]+)\s* = \s*(?:Rice::)?define_module_under\s*
41
+ \(
42
+ \s*([\w.]+)\s*,
43
+ \s*"(\w[\wd]+)"
44
+ \s*\)/mx.freeze
45
+ handles MATCH
46
+ handles MATCH_UNDER
47
+ statement_class BodyStatement
48
+
49
+ process do
50
+ statement.source.scan(MATCH) do |var_name, module_name|
51
+ handle_module(var_name, module_name)
52
+ end
53
+ statement.source.scan(MATCH_UNDER) do |var_name, in_module, module_name|
54
+ handle_module(var_name, module_name, in_module)
55
+ end
56
+ end
57
+ end
58
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsoncons
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - uvlad7
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-06 00:00:00.000000000 Z
11
+ date: 2023-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rice
@@ -66,7 +66,22 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- description:
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Ruby wrapper for a part of [jsoncons](https://github.com/danielaparker/jsoncons)
84
+ library,mostly for its jsonpath implementation
70
85
  email:
71
86
  - uvlad7@gmail.com
72
87
  executables: []
@@ -74,6 +89,7 @@ extensions:
74
89
  - ext/jsoncons/extconf.rb
75
90
  extra_rdoc_files: []
76
91
  files:
92
+ - ".yardopts"
77
93
  - ext/jsoncons/extconf.rb
78
94
  - ext/jsoncons/jsoncons.cpp
79
95
  - ext/jsoncons/jsoncons.h
@@ -147,6 +163,7 @@ files:
147
163
  - lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson.hpp
148
164
  - lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_cursor.hpp
149
165
  - lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_decimal128.hpp
166
+ - lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_decimal128.hpp.bak
150
167
  - lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_encoder.hpp
151
168
  - lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_error.hpp
152
169
  - lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_oid.hpp
@@ -227,6 +244,7 @@ files:
227
244
  - lib/jsoncons/version.rb
228
245
  - test/jsoncons_test.rb
229
246
  - test/test_helper.rb
247
+ - yard_extensions.rb
230
248
  homepage: https://github.com/uvlad7/ruby-jsoncons
231
249
  licenses:
232
250
  - MIT
@@ -235,6 +253,8 @@ metadata:
235
253
  homepage_uri: https://github.com/uvlad7/ruby-jsoncons
236
254
  source_code_uri: https://github.com/uvlad7/ruby-jsoncons
237
255
  changelog_uri: https://github.com/uvlad7/ruby-jsoncons
256
+ documentation_uri: https://rubydoc.info/gems/jsoncons/frames
257
+ library_uri: https://github.com/danielaparker/jsoncons
238
258
  post_install_message:
239
259
  rdoc_options: []
240
260
  require_paths:
@@ -243,7 +263,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
243
263
  requirements:
244
264
  - - ">="
245
265
  - !ruby/object:Gem::Version
246
- version: 2.6.0
266
+ version: '2.5'
247
267
  required_rubygems_version: !ruby/object:Gem::Requirement
248
268
  requirements:
249
269
  - - ">="
@@ -253,7 +273,7 @@ requirements: []
253
273
  rubygems_version: 3.3.5
254
274
  signing_key:
255
275
  specification_version: 4
256
- summary: Ruby wrapper for https://github.com/danielaparker/jsoncons
276
+ summary: Ruby wrapper for jsoncons library and jsonpath
257
277
  test_files:
258
278
  - lib/jsoncons/jsoncons/examples/input/sales.csv
259
279
  - lib/jsoncons/jsoncons/examples/input/store.json