Skip to content

Commit 0d1709f

Browse files
committed
impl with_path
1 parent e5fcad2 commit 0d1709f

File tree

4 files changed

+70
-12
lines changed

4 files changed

+70
-12
lines changed

.rubocop.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,12 @@ RSpec/ExampleLength:
3030
Metrics/BlockLength:
3131
Exclude:
3232
- "spec/**/*"
33+
34+
Style/TrailingCommaInArguments:
35+
EnforcedStyleForMultiline: consistent_comma
36+
37+
Style/TrailingCommaInArrayLiteral:
38+
EnforcedStyleForMultiline: consistent_comma
39+
40+
Style/TrailingCommaInHashLiteral:
41+
EnforcedStyleForMultiline: consistent_comma

ext/json_scanner/json_scanner.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,10 @@ typedef enum
240240
} value_type;
241241

242242
// noexcept
243-
void create_point(VALUE *point, scan_ctx *sctx, value_type type, size_t length, size_t curr_pos)
243+
VALUE create_point(scan_ctx *sctx, value_type type, size_t length, size_t curr_pos)
244244
{
245245
VALUE values[3];
246-
*point = rb_ary_new_capa(3);
246+
VALUE point = rb_ary_new_capa(3);
247247
// noexcept
248248
values[1] = RB_ULONG2NUM(curr_pos);
249249
switch (type)
@@ -275,14 +275,37 @@ void create_point(VALUE *point, scan_ctx *sctx, value_type type, size_t length,
275275
break;
276276
}
277277
// rb_ary_cat raise only in case of a frozen array or if len is too long
278-
rb_ary_cat(*point, values, 3);
278+
rb_ary_cat(point, values, 3);
279+
return point;
280+
}
281+
282+
// noexcept
283+
VALUE create_path(scan_ctx *sctx)
284+
{
285+
VALUE path = rb_ary_new_capa(sctx->current_path_len);
286+
for (int i = 0; i < sctx->current_path_len; i++)
287+
{
288+
VALUE entry;
289+
switch (sctx->current_path[i].type)
290+
{
291+
case PATH_KEY:
292+
entry = rb_str_new(sctx->current_path[i].value.key.val, sctx->current_path[i].value.key.len);
293+
break;
294+
case PATH_INDEX:
295+
entry = RB_ULONG2NUM(sctx->current_path[i].value.index);
296+
break;
297+
}
298+
rb_ary_push(path, entry);
299+
}
300+
return path;
279301
}
280302

281303
// noexcept
282304
void save_point(scan_ctx *sctx, value_type type, size_t length)
283305
{
284306
// TODO: Abort parsing if all paths are matched and no more mathces are possible: only trivial key/index matchers at the current level
285307
// TODO: Don't re-compare already matched prefixes; hard to invalidate, though
308+
// TODO: Might fail in case of no memory
286309
VALUE point = Qundef;
287310
int match;
288311
for (int i = 0; i < sctx->paths_len; i++)
@@ -320,7 +343,10 @@ void save_point(scan_ctx *sctx, value_type type, size_t length)
320343
{
321344
if (point == Qundef)
322345
{
323-
create_point(&point, sctx, type, length, yajl_get_bytes_consumed(sctx->handle));
346+
point = create_point(sctx, type, length, yajl_get_bytes_consumed(sctx->handle));
347+
if (sctx->with_path) {
348+
point = rb_ary_new_from_args(2, create_path(sctx), point);
349+
}
324350
}
325351
// rb_ary_push raises only in case of a frozen array, which is not the case
326352
// rb_ary_entry is safe

json_scanner.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
2424
File.basename(__FILE__)
2525
spec.files = [
2626
*(Dir["{lib,sig,spec}/**/*"] - Dir["lib/**/*.{so,dylib,dll}"]),
27-
*Dir["ext/json_scanner/{extconf.rb,json_scanner.c,json_scanner.h}"], "README.md"
27+
*Dir["ext/json_scanner/{extconf.rb,json_scanner.c,json_scanner.h}"], "README.md",
2828
].reject { |f| File.directory?(f) }
2929
spec.require_paths = ["lib"]
3030
spec.extensions = ["ext/json_scanner/extconf.rb"]

spec/json_scanner_spec.rb

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
expect(result).to eq([[[1, 4, :string]], [[12, 13, :number]], [[0, 15, :array]]])
1313
expect(described_class.scan('"2"', [[]])).to eq([[[0, 3, :string]]])
1414
expect(
15-
described_class.scan("[0,1,2,3,4,5,6,7]", [[(0..2)], [(4...6)]])
15+
described_class.scan("[0,1,2,3,4,5,6,7]", [[(0..2)], [(4...6)]]),
1616
).to eq(
17-
[[[1, 2, :number], [3, 4, :number], [5, 6, :number]], [[9, 10, :number], [11, 12, :number]]]
17+
[[[1, 2, :number], [3, 4, :number], [5, 6, :number]], [[9, 10, :number], [11, 12, :number]]],
1818
)
1919
expect(described_class.scan('{"a": 1}', [["a"], []])).to eq(
20-
[[[6, 7, :number]], [[0, 8, :object]]]
20+
[[[6, 7, :number]], [[0, 8, :object]]],
2121
)
2222
end
2323

@@ -40,14 +40,14 @@
4040

4141
it "allows to select ranges" do
4242
expect(
43-
described_class.scan("[[1,2],[3,4]]", [[described_class::ANY_INDEX, described_class::ANY_INDEX]])
43+
described_class.scan("[[1,2],[3,4]]", [[described_class::ANY_INDEX, described_class::ANY_INDEX]]),
4444
).to eq(
45-
[[[2, 3, :number], [4, 5, :number], [8, 9, :number], [10, 11, :number]]]
45+
[[[2, 3, :number], [4, 5, :number], [8, 9, :number], [10, 11, :number]]],
4646
)
4747
expect(
48-
described_class.scan("[[1,2],[3,4]]", [[described_class::ANY_INDEX, (0...1)]])
48+
described_class.scan("[[1,2],[3,4]]", [[described_class::ANY_INDEX, (0...1)]]),
4949
).to eq(
50-
[[[2, 3, :number], [8, 9, :number]]]
50+
[[[2, 3, :number], [8, 9, :number]]],
5151
)
5252
end
5353

@@ -74,4 +74,27 @@
7474
described_class.scan "{1}", [], verbose_error: true
7575
end.to raise_error described_class::ParseError, /invalid object key(?=.*\(right here\))/m
7676
end
77+
78+
it "allows to return an actual path to the element" do
79+
expect(
80+
described_class.scan(
81+
"[[1,2],[3,4]]",
82+
[
83+
[described_class::ANY_INDEX],
84+
[described_class::ANY_INDEX, described_class::ANY_INDEX],
85+
],
86+
with_path: true,
87+
),
88+
).to eq(
89+
[
90+
# result for first mathcer, each element array of two items:
91+
# array of path elements and 3-element array start,end,type
92+
[[[0], [1, 6, :array]], [[1], [7, 12, :array]]],
93+
[
94+
[[0, 0], [2, 3, :number]], [[0, 1], [4, 5, :number]],
95+
[[1, 0], [8, 9, :number]], [[1, 1], [10, 11, :number]],
96+
],
97+
],
98+
)
99+
end
77100
end

0 commit comments

Comments
 (0)