linedump 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0e4178abce450d405b7d4aaa896396dc7cb4adc2
4
+ data.tar.gz: 785a239c2e41e6ff3b0cd3d683fcdad1ef1489b8
5
+ SHA512:
6
+ metadata.gz: 6c43e82bc03b8109687e5a4c47f57b666a5da1598cf0854a4bb03e607f1e3c6e31874346f3d7bf9e9d720fa330ae42f1e67bbff43e57a063a4a4265c30374782
7
+ data.tar.gz: 3ddd976ec104f39325fd7208ae5cb87b45b7156276c31df3ef656b6565d7f7521fbd74096c7b7a4dbbe0276b4b4669b3d1844876da2e8a21f3cb5d59282cd453
@@ -0,0 +1,101 @@
1
+ require "thwait"
2
+ require "linedump/stream_wrapper"
3
+
4
+ module Linedump
5
+
6
+ class Consumer
7
+
8
+ class StopSignal < Exception; end
9
+
10
+ class ReloadSignal < Exception; end
11
+
12
+ def initialize
13
+ @streams = []
14
+ @lock = Mutex.new
15
+ @worker = nil
16
+ end
17
+
18
+ def register_stream(_stream, &_block)
19
+ # TODO: locking for non-GIL platforms
20
+ @streams << StreamWrapper.new(_stream, _block)
21
+ end
22
+
23
+ def is_registered?(_stream)
24
+ not find_stream_wrapper(_stream).nil?
25
+ end
26
+
27
+ def reload
28
+ @lock.synchronize do
29
+ if @worker and @worker.alive?
30
+ @worker.raise ReloadSignal # signal worker to reload streams
31
+ else
32
+ @worker = load_worker
33
+ end
34
+ end
35
+ end
36
+
37
+ def stop
38
+ @lock.synchronize do
39
+ if @worker and @worker.alive?
40
+ @worker.raise StopSignal
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def load_worker
48
+ Thread.new do
49
+ looped = 0
50
+ begin
51
+ while @streams.count > 0
52
+ read_streams = load_monitored_streams
53
+ result = IO.select(read_streams, [], read_streams)
54
+ if result
55
+ process_ready_streams result[0]
56
+ discard_errored_streams result[2]
57
+ end
58
+ looped += 1
59
+ end
60
+ rescue ReloadSignal
61
+ retry
62
+ rescue StopSignal, SystemExit
63
+ # nothing
64
+ end
65
+ end
66
+ end
67
+
68
+ def process_ready_streams(_streams)
69
+ _streams.each do |stream|
70
+ wrapper = find_stream_wrapper stream
71
+ if wrapper
72
+ wrapper.process_lines
73
+ remove_wrapper wrapper, :eof if wrapper.eof?
74
+ end
75
+ end
76
+ end
77
+
78
+ def discard_errored_streams(_streams)
79
+ _streams.each do |stream|
80
+ wrapper = find_stream_wrapper stream
81
+ remove_wrapper wrapper, :error if wrapper
82
+ end
83
+ end
84
+
85
+ def find_stream_wrapper(_stream)
86
+ @streams.find { |s| s.stream == _stream }
87
+ end
88
+
89
+ def remove_wrapper(_wrapper, _reason)
90
+ # TODO: locking for non-GIL platforms
91
+ @streams.delete _wrapper
92
+ end
93
+
94
+ def load_monitored_streams
95
+ # include stdin to prevent console enabled apps from locking
96
+ @streams.map(&:stream) << $stdin
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -0,0 +1,55 @@
1
+ module Linedump
2
+
3
+ class StreamWrapper
4
+
5
+ MAX_LENGTH = 2048
6
+
7
+ attr_reader :stream
8
+
9
+ def initialize(_stream, _block)
10
+ @stream = _stream
11
+ @block = _block
12
+ @buffer = []
13
+ @eof = false
14
+ end
15
+
16
+ def eof?
17
+ @eof
18
+ end
19
+
20
+ def process_lines
21
+ begin
22
+ loop do
23
+ chunk = @stream.read_nonblock(MAX_LENGTH)
24
+ process_chunk chunk
25
+ end
26
+ rescue IO::WaitReadable
27
+ # nothing, just stop looping
28
+ rescue EOFError, IOError
29
+ @eof = true
30
+ rescue Exception => exc
31
+ puts "Error in stream consumer: #{exc.class}" # TODO: not sure where to send this error
32
+ @eof = true
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def process_chunk(_chunk)
39
+ index = _chunk.index $/
40
+
41
+ unless index.nil?
42
+ head = _chunk[0..index-1]
43
+ tail = _chunk[index+1..-1]
44
+
45
+ @block.call(@buffer.join + head)
46
+ @buffer.clear
47
+
48
+ process_chunk tail
49
+ else
50
+ @buffer << _chunk
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,3 @@
1
+ module Linedump
2
+ VERSION = "0.1.0"
3
+ end
data/lib/linedump.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "linedump/version"
2
+ require "linedump/consumer"
3
+
4
+ module Linedump
5
+
6
+ def self.consumer
7
+ @@consumer ||= Consumer.new
8
+ end
9
+
10
+ def self.each_line(_stream, &_block)
11
+ consumer.register_stream _stream, &_block
12
+ consumer.reload
13
+ nil
14
+ end
15
+
16
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: linedump
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ignacio Baixas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-nc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.11'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.11'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '4.5'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '4.5'
97
+ - !ruby/object:Gem::Dependency
98
+ name: terminal-notifier-guard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.6'
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: 1.6.1
107
+ type: :development
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - "~>"
112
+ - !ruby/object:Gem::Version
113
+ version: '1.6'
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 1.6.1
117
+ description: linedump allows you to register blocks to consume live output streams,
118
+ line by line.
119
+ email:
120
+ - ignacio@platan.us
121
+ executables: []
122
+ extensions: []
123
+ extra_rdoc_files: []
124
+ files:
125
+ - lib/linedump.rb
126
+ - lib/linedump/consumer.rb
127
+ - lib/linedump/stream_wrapper.rb
128
+ - lib/linedump/version.rb
129
+ homepage: https://github.com/platanus/linedump-gem
130
+ licenses:
131
+ - MIT
132
+ metadata: {}
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 2.4.5
150
+ signing_key:
151
+ specification_version: 4
152
+ summary: Process output stream listener helper
153
+ test_files: []