Skip to content

Commit 7ff3dc5

Browse files
committed
Reduce complexity of do_parse
1 parent b909e0f commit 7ff3dc5

3 files changed

Lines changed: 35 additions & 26 deletions

File tree

lib/json_sequence/parser.rb

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,35 +18,31 @@ def parse(chunk, &block)
1818
# Takes a String buffer to parse and returns String containing any
1919
# text remaining to parse when more data is available.
2020
def do_parse(buffer)
21-
records = buffer.split(RS, -1) # -1 stops suppression of trailing null fields
22-
23-
records.each_with_index do |record, i|
24-
# RFC7464 2.1 Multiple consecutive RS octets do not denote empty
25-
# sequence elements between them and can be ignored.
26-
next if record == ''
27-
28-
is_last_record = i == records.size - 1
29-
30-
# Try to decode the record
31-
begin
32-
value = MultiJson.load(record)
33-
if truncated?(record, value)
34-
return record if is_last_record
35-
36-
yield JsonSequence::Result::MaybeTruncated.new(value)
37-
else
38-
yield JsonSequence::Result::Json.new(value)
39-
end
40-
rescue MultiJson::ParseError => err
41-
return record if is_last_record
42-
43-
yield JsonSequence::Result::ParseError.new(record, err)
44-
end
45-
end
21+
# RFC7464 2.1 Multiple consecutive RS octets do not denote empty
22+
# sequence elements between them and can be ignored.
23+
records = buffer.split(RS).reject(&:empty?)
24+
25+
# Every record except the last is guaranteed to be completed
26+
records[0...-1].each { |record| yield decode_record(record) }
27+
28+
last_result = decode_record(records.last)
29+
30+
# If we have an incomplete record and run out of valid json early, return it to the buffer
31+
return records.last if !buffer.end_with?(RS) && partial_result?(last_result)
32+
yield last_result
4633

4734
''
4835
end
4936

37+
def decode_record(record)
38+
value = MultiJson.load(record)
39+
return JsonSequence::Result::MaybeTruncated.new(value) if truncated?(record, value)
40+
41+
JsonSequence::Result::Json.new(value)
42+
rescue MultiJson::ParseError => e
43+
JsonSequence::Result::ParseError.new(record, e)
44+
end
45+
5046
def truncated?(record, value)
5147
case value
5248
when Numeric, TrueClass, FalseClass, NilClass
@@ -57,5 +53,9 @@ def truncated?(record, value)
5753
false
5854
end
5955
end
56+
57+
def partial_result?(result)
58+
!result.is_a?(JsonSequence::Result::Json)
59+
end
6060
end
6161
end

lib/json_sequence/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module JsonSequence
2-
VERSION = "0.2.0"
2+
VERSION = "0.2.1"
33
end

spec/json_sequence/parser_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@
6666
)
6767
end
6868

69+
it 'process records when ending with a RS token' do
70+
expect { |b| parser.parse(%|\x1E123\x0A\x1E|, &b) }.to yield_successive_args(
71+
JsonSequence::Result::Json.new(123),
72+
)
73+
expect { |b| parser.parse(%|123\x0A|, &b) }.to yield_successive_args(
74+
JsonSequence::Result::Json.new(123),
75+
)
76+
end
77+
6978
it 'parses formatted json' do
7079
expect { |b| parser.parse(%|\x1E{"some": "json",\n"more": 1,\n"even more": []}\x0A|, &b) }.to yield_successive_args(
7180
JsonSequence::Result::Json.new('some' => 'json', 'more' => 1, 'even more' => [])

0 commit comments

Comments
 (0)