jsoncons 0.1.0 → 0.1.1

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