Name | Total Lines | Lines of Code | Total Coverage | Code Coverage |
---|---|---|---|---|
lib/asir/channel.rb | 129 | 95 | 40.31%
|
21.05%
|
Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.
1 require 'asir' |
2 require 'asir/retry_behavior' |
3 |
4 module ASIR |
5 # Generic I/O Channel abstraction. |
6 # Handles stream per Thread and forked child processes. |
7 class Channel |
8 include Initialization, RetryBehavior |
9 |
10 attr_accessor :on_connect, :on_close, :on_retry, :on_error |
11 |
12 ON_ERROR = lambda do | channel, exc, action, stream | |
13 channel.close rescue nil if stream |
14 raise exc |
15 end |
16 ON_CLOSE = lambda do | channel, stream | |
17 stream.close |
18 end |
19 ON_RETRY = lambda do | channel, exc, action | |
20 end |
21 |
22 def initialize opts = nil |
23 @on_close = ON_CLOSE |
24 @on_error = ON_ERROR |
25 # @on_retry = ON_RETRY |
26 self.try_max = 10 |
27 self.try_sleep = 0.1 |
28 self.try_sleep_increment = 0.1 |
29 self.try_sleep_max = 10 |
30 super |
31 end |
32 |
33 # Returns IO stream for current Thread. |
34 # Automatically calls #connect! if stream is created. |
35 def stream |
36 _streams[self] ||= |
37 connect! |
38 end |
39 |
40 # Invokes @on_connect.call(self). |
41 # On Exception, invokes @on_error.call(self, exc, :connect, nil). |
42 def connect! |
43 n_try = nil |
44 with_retry do | action, data | |
45 case action |
46 when :try |
47 n_try = data |
48 @on_connect.call(self) |
49 when :retry #, exc |
50 $stderr.puts "RETRY: #{n_try}: ERROR : #{data.inspect} \n#{data.backtrace * "\n "}" |
51 @on_retry.call(self, exc, :connect) if @on_retry |
52 when :failed |
53 exc = data |
54 $stderr.puts "FAILED: #{n_try}: ERROR : #{exc.inspect} \n#{exc.backtrace * "\n "}" |
55 handle_error!(exc, :connect, nil) |
56 end |
57 end |
58 end |
59 |
60 # Invokes @on_close.call(self, stream). |
61 # On Exception, invokes @on_error.call(self, exc, :close, stream). |
62 def close |
63 if stream = _stream |
64 self.stream = nil |
65 @on_close.call(self, stream) if @on_close |
66 end |
67 rescue ::Exception => exc |
68 handle_error!(exc, :close, stream) |
69 end |
70 |
71 # Yield #stream to block. |
72 # On Exception, invokes @on_error.call(self, exc, :with_stream, stream). |
73 def with_stream! |
74 x = stream |
75 begin |
76 yield x |
77 rescue ::Exception => exc |
78 handle_error!(exc, :with_stream, x) |
79 end |
80 end |
81 |
82 # Delegate to actual stream. |
83 def method_missing sel, *args, &blk |
84 with_stream! do | obj | |
85 obj.__send__(sel, *args, &blk) |
86 end |
87 end |
88 |
89 # Dispatches exception and arguments if @on_error is defined. |
90 # Otherwise, reraise exception. |
91 def handle_error! exc, action, stream |
92 if @on_error |
93 @on_error.call(self, exc, action, stream) |
94 else |
95 raise exc |
96 end |
97 end |
98 |
99 # Returns a Thread-specific mapping, unique to this process id. |
100 # Maps from Channel objects to actual stream. |
101 def _streams |
102 streams = Thread.current[:'ASIR::Channel._streams'] ||= { } |
103 if ! @owning_process || |
104 @owning_process != $$ || # child process? |
105 @owning_process > $$ # PIDs wrapped around? |
106 @owning_process = $$ |
107 streams.clear |
108 end |
109 streams |
110 end |
111 |
112 # Returns the stream for this Channel, or nil. |
113 def _stream |
114 _streams[self] |
115 end |
116 |
117 # Sets the stream for this Channel, or nil. |
118 def stream= x |
119 if x == nil |
120 _streams.delete(self) |
121 else |
122 _streams[self] = x |
123 end |
124 end |
125 |
126 end # class Channel |
127 end # module |
128 |
129 |
Generated on Fri Jan 27 17:37:46 -0600 2012 with rcov 0.9.8