io-segmenter 0.7.2 → 0.7.5

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: 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: {}