io-segmenter 0.7.2 → 0.7.5

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: 41882b615cb02ee0e614e868104006e98fafb0ba0b96adb0d55431b13d285116
4
- data.tar.gz: 86655c3225adc2bb178d3a31cb4b4cd37f37d538b419316eddd56e24b3059f1a
3
+ metadata.gz: eeada66a82cb120e8da0241a2847545e7579a2f297dd4e11647a15f118bb95e4
4
+ data.tar.gz: 128a87fe89da4ff96f55654aaf9da152b40dc3aca4d9be3d8ee76655bb4b76d6
5
5
  SHA512:
6
- metadata.gz: cac57f6a5ac8b5e345867452acc553f184980541bc0328291eca69261c05471dd9631a5585540eed1bbf4512d062a4abc6b1c97d7f84e901c8cb5049e3b4c722
7
- data.tar.gz: 478d2436eb58f002019125135351adaa69eb2c1611cbf610ace311d2ee715f76beb7b25b81b578eea271beeee31c122b1881c88a1664afe1813b5aad659b1b0a
6
+ metadata.gz: 281e984a75b8f827f7b631b19a26f6bb2522808e97a2727a07829e4d637afaf7949c659238b6311c1e85b3aa6c5a9e753b95b722eb8d5d905770935e2802e531
7
+ data.tar.gz: 9ecf8b025de77ca0e7ecfc870af16e0b57fd1b2ad8260a42967e8edea514b65e3315a608cfa350e68767b060f61f5b7acd379b20c7783b1db0a3c6b68b0c7b93
data/lib/io-segmenter.rb CHANGED
@@ -1,97 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # IO iterator for parsing segments of streams
4
- class IOSegmenter
5
- include Enumerable
6
-
7
- DEFAULT_READ_SIZE = 8192
8
-
9
- attr_reader :buffer
10
-
11
- def initialize(io, starting_char, ending_char, quote_char, escape_char, max_read_size=DEFAULT_READ_SIZE)
12
- @io = io
13
- @starting_char = starting_char
14
- @ending_char = ending_char
15
- @quote_char = quote_char
16
- @escape_char = escape_char
17
- @max_read_size = max_read_size
18
-
19
- terms = [
20
- @starting_char,
21
- @ending_char,
22
- @quote_char,
23
- @escape_char
24
- ]
25
- terms.compact!
26
- terms.map! { |str| Regexp.escape(str) }
27
-
28
- @search = Regexp.new('(:?' + terms.join('|') + ')')
29
- @buffer = String.new
30
- end
31
-
32
- def each
33
- until @io.eof?
34
- unpack(@io.read(@max_read_size)) do |segment|
35
- yield segment
36
- end
37
- end
38
- end
39
-
40
- def unpack(str)
41
- @buffer << str
42
- each_segment(@buffer) do |segment|
43
- yield segment
44
- end
45
- end
46
-
47
- def self.foreach(*args, &block)
48
- new(*args).each(&block)
49
- end
50
-
51
- private
52
-
53
- def each_segment(buffer)
54
- return unless (start_offset = buffer.index(@starting_char))
55
-
56
- brackets = 1
57
- offset = start_offset
58
-
59
- opened_quote = false
60
-
61
- while (offset = buffer.index(@search, offset + 1))
62
- case buffer[offset]
63
- when @ending_char
64
- next if opened_quote
65
- brackets -= 1
66
- when @starting_char
67
- next if opened_quote
68
- brackets += 1
69
- when @quote_char
70
- opened_quote = !opened_quote
71
- next
72
- when @escape_char
73
- offset += @escape_char.size
74
- next
75
- else
76
- if @ending_char == buffer[offset, @ending_char.size]
77
- next if opened_quote
78
- brackets -= 1
79
- elsif @starting_char == buffer[offset, @starting_char.size]
80
- next if opened_quote
81
- brackets += 1
82
- else
83
- raise("unhandled offset #{offset}, at #{buffer[offset, 20]}...")
84
- end
85
- end
86
-
87
- next unless brackets.zero?
88
-
89
- len = (offset + @ending_char.size) - start_offset
90
- yield buffer[start_offset, len]
91
- buffer.slice!(0, offset + @ending_char.size)
92
- return unless (start_offset = buffer.index(@starting_char))
93
- offset = start_offset
94
- brackets = 1
95
- end
96
- end
3
+ module IOSegmenter
4
+ autoload :Parser, 'io-segmenter/parser'
5
+ autoload :Reader, 'io-segmenter/reader'
6
+ autoload :Writer, 'io-segmenter/writer'
97
7
  end
@@ -1,7 +1,7 @@
1
1
  class File
2
- def self.each_segment(file, *args, &block)
2
+ def self.each_segment(file, *args, max_read_size, &block)
3
3
  handle = open(file, 'rb')
4
- IOSegmenter.new(handle, *args).each(&block)
4
+ IOSegmenter::Reader.new(handle, IOSegmenter::Parser.new(*args), max_read_size).each(&block)
5
5
  ensure
6
6
  handle && handle.close
7
7
  end
@@ -1,5 +1,5 @@
1
1
  class IO
2
- def each_segment(*args, &block)
3
- IOSegmenter.new(self, *args).each(&block)
2
+ def each_segment(*args, max_read_size, &block)
3
+ IOSegmenter::Reader.new(self, IOSegmenter::Parser.new(*args), max_read_size).each(&block)
4
4
  end
5
5
  end
@@ -1,21 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSON
4
- def self.each_object(io, max_read_size=IOSegmenter::DEFAULT_READ_SIZE, &block)
5
- IOSegmenter.new(io, '{', '}', '"', '\\', max_read_size).each do |segement|
4
+ def self.each_object(io, max_read_size=nil, &block)
5
+ IOSegmenter::Reader.new(io, IOSegmenter::Parser.new('{', '}', '"', '\\'), max_read_size || IOSegmenter::Reader::DEFAULT_READ_SIZE).each do |segement|
6
6
  yield parse(segement)
7
7
  end
8
8
  end
9
9
 
10
- def self.each_string(io, max_read_size=IOSegmenter::DEFAULT_READ_SIZE)
11
- IOSegmenter.new(io, '"', '"', nil, '\\', max_read_size).each do |segement|
10
+ def self.each_string(io, max_read_size=nil)
11
+ IOSegmenter::Reader.new(io, IOSegmenter::Parser.new('"', '"', nil, '\\'), max_read_size || IOSegmenter::Reader::DEFAULT_READ_SIZE).each do |segement|
12
12
  yield segement[1, segement.size-2]
13
13
  end
14
14
  end
15
15
 
16
- def self.each_item(io, max_read_size=IOSegmenter::DEFAULT_READ_SIZE)
16
+ def self.each_list(io, max_read_size=nil)
17
17
  io.read(1)
18
- IOSegmenter.new(io, '[', ']', '"', '\\', max_read_size).each do |segement|
18
+ IOSegmenter::Reader.new(io, IOSegmenter::Parser.new('[', ']', '"', '\\'), max_read_size || IOSegmenter::Reader::DEFAULT_READ_SIZE).each do |segement|
19
19
  yield parse(segement)
20
20
  end
21
21
  end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IOSegmenter
4
+ class Parser
5
+ attr_reader :buffer
6
+
7
+ def initialize(starting_char, ending_char, quote_char, escape_char)
8
+ @starting_char = starting_char
9
+ @ending_char = ending_char
10
+ @quote_char = quote_char
11
+ @escape_char = escape_char
12
+
13
+ terms = [
14
+ @starting_char,
15
+ @ending_char,
16
+ @quote_char,
17
+ @escape_char
18
+ ]
19
+ terms.compact!
20
+ terms.map! { |str| Regexp.escape(str) }
21
+
22
+ @search = Regexp.new('(:?' + terms.join('|') + ')')
23
+ @buffer = String.new
24
+ end
25
+
26
+ def unpack(str)
27
+ @buffer << str
28
+ each_segment(@buffer) do |segment|
29
+ yield segment
30
+ end
31
+ end
32
+
33
+ def each_segment(buffer)
34
+ return unless (start_offset = buffer.index(@starting_char))
35
+
36
+ brackets = 1
37
+ offset = start_offset
38
+
39
+ opened_quote = false
40
+
41
+ while (offset = buffer.index(@search, offset + 1))
42
+ case buffer[offset]
43
+ when @ending_char
44
+ next if opened_quote
45
+ brackets -= 1
46
+ when @starting_char
47
+ next if opened_quote
48
+ brackets += 1
49
+ when @quote_char
50
+ opened_quote = !opened_quote
51
+ next
52
+ when @escape_char
53
+ offset += @escape_char.size
54
+ next
55
+ else
56
+ if @ending_char == buffer[offset, @ending_char.size]
57
+ next if opened_quote
58
+ brackets -= 1
59
+ elsif @starting_char == buffer[offset, @starting_char.size]
60
+ next if opened_quote
61
+ brackets += 1
62
+ else
63
+ raise("unhandled offset #{offset}, at #{buffer[offset, 20]}...")
64
+ end
65
+ end
66
+
67
+ next unless brackets.zero?
68
+
69
+ len = (offset + @ending_char.size) - start_offset
70
+ yield buffer[start_offset, len]
71
+ buffer.slice!(0, offset + @ending_char.size)
72
+ return unless (start_offset = buffer.index(@starting_char))
73
+ offset = start_offset
74
+ brackets = 1
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IOSegmenter
4
+ class Reader
5
+ include Enumerable
6
+
7
+ DEFAULT_READ_SIZE = 8192
8
+
9
+ def initialize(io, parser, max_read_size=DEFAULT_READ_SIZE)
10
+ @io = io
11
+ @parser = parser
12
+ @max_read_size = max_read_size
13
+ end
14
+
15
+ def each
16
+ until @io.eof?
17
+ @parser.unpack(@io.read(@max_read_size)) do |segment|
18
+ yield segment
19
+ end
20
+ end
21
+ end
22
+
23
+ def self.foreach(*args, &block)
24
+ new(*args).each(&block)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IOSegmenter
4
+ # Used to add a separator after the first write call
5
+ class Writer
6
+ def self.write(io, header, footer, separator)
7
+ io.write(header) if header
8
+ yield new(io, separator)
9
+ io.write(footer) if footer
10
+ end
11
+
12
+ def initialize(io, separator)
13
+ @io = io
14
+ @separator = separator
15
+ @add_separator = false
16
+ end
17
+
18
+ def write(str)
19
+ @io.write(@separator) if @separator && @add_separator
20
+ @io.write(str)
21
+ @add_separator = true
22
+ end
23
+ end
24
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: io-segmenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.7.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Doug Youch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-09 00:00:00.000000000 Z
11
+ date: 2018-09-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Used to iterate over segments of data in IO objects
14
14
  email: dyouch5@yahoo.com
@@ -20,6 +20,9 @@ files:
20
20
  - lib/io-segmenter/core_ext/file.rb
21
21
  - lib/io-segmenter/core_ext/io.rb
22
22
  - lib/io-segmenter/core_ext/json.rb
23
+ - lib/io-segmenter/parser.rb
24
+ - lib/io-segmenter/reader.rb
25
+ - lib/io-segmenter/writer.rb
23
26
  homepage: https://github.com/dougyouch/io-segemnter
24
27
  licenses: []
25
28
  metadata: {}