Class: EMDirWatcher::Invokers::SubprocessInvoker

Inherits:
Object
  • Object
show all
Defined in:
lib/em-dir-watcher/invokers/subprocess_invoker.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(subprocess, &input_handler) ⇒ SubprocessInvoker

Returns a new instance of SubprocessInvoker.



13
14
15
16
17
18
19
20
21
# File 'lib/em-dir-watcher/invokers/subprocess_invoker.rb', line 13

def initialize subprocess, &input_handler
    @subprocess = subprocess
    @input_handler = input_handler
    @active = true
    @ready_to_use = false
    @ready_to_use_handlers = []
    @additional_delay = 0.1
    start_subprocess
end

Instance Attribute Details

#activeObject (readonly)

Returns the value of attribute active.



9
10
11
# File 'lib/em-dir-watcher/invokers/subprocess_invoker.rb', line 9

def active
  @active
end

#additional_delayObject

Returns the value of attribute additional_delay.



11
12
13
# File 'lib/em-dir-watcher/invokers/subprocess_invoker.rb', line 11

def additional_delay
  @additional_delay
end

#input_handlerObject (readonly)

Returns the value of attribute input_handler.



10
11
12
# File 'lib/em-dir-watcher/invokers/subprocess_invoker.rb', line 10

def input_handler
  @input_handler
end

Instance Method Details

#killObject



47
48
49
50
51
52
53
# File 'lib/em-dir-watcher/invokers/subprocess_invoker.rb', line 47

def kill
    if @io
        Process.kill 'TERM', @io.pid 
        Process.waitpid @io.pid
        @io = nil
    end
end

#ready_to_use!Object

private methods



38
39
40
41
42
43
44
45
# File 'lib/em-dir-watcher/invokers/subprocess_invoker.rb', line 38

def ready_to_use!
    return if @ready_to_use
    @ready_to_use = true
    EM.add_timer @additional_delay do
        @ready_to_use_handlers.each { |handler| handler.call() }
        @ready_to_use_handlers = nil
    end
end

#start_subprocessObject



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/em-dir-watcher/invokers/subprocess_invoker.rb', line 55

def start_subprocess
    io = open('|-', 'r')
    if io.nil?
        $stdout.sync = true
        ready  = lambda { puts }
        output = lambda { |single_line_string| puts single_line_string.strip }
        @subprocess.call ready, output
        exit
    end
    @io = io
    @io.nonblock = true

    @connection = EM.watch io do |conn|
        class << conn
            attr_accessor :invoker
            
            def notify_readable
                @invoker.ready_to_use!
                @data_received ||= ""
                @data_received << @io.read
                while line = @data_received.slice!(/^[^\n]*[\n]/m)
                    @invoker.input_handler.call line.strip
                end
            rescue EOFError
                detach
                @invoker.kill  # waitpid to cleanup zombie
                if @invoker.active
                    EM.next_tick do
                        @invoker.start_subprocess
                    end
                end
            end

            def unbind
                @invoker.kill
            end
        end
        conn.invoker = self
        conn.notify_readable = true
    end
end

#stopObject



31
32
33
34
# File 'lib/em-dir-watcher/invokers/subprocess_invoker.rb', line 31

def stop
    @active = false
    kill
end

#when_ready_to_use(&ready_to_use_handler) ⇒ Object



23
24
25
26
27
28
29
# File 'lib/em-dir-watcher/invokers/subprocess_invoker.rb', line 23

def when_ready_to_use &ready_to_use_handler
  if @ready_to_use_handlers.nil?
      ready_to_use_handler.call()
  else
      @ready_to_use_handlers << ready_to_use_handler
  end
end