This file is indexed.

/usr/lib/ruby/vendor_ruby/em/completion.rb is in ruby-eventmachine 1.0.3-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 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
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# = EM::Completion
#
# A completion is a callback container for various states of completion. In
# it's most basic form it has a start state and a finish state.
#
# This implementation includes some hold-back from the EM::Deferrable
# interface in order to be compatible - but it has a much cleaner
# implementation.
#
# In general it is preferred that this implementation be used as a state
# callback container than EM::DefaultDeferrable or other classes including
# EM::Deferrable. This is because it is generally more sane to keep this level
# of state in a dedicated state-back container. This generally leads to more
# malleable interfaces and software designs, as well as eradicating nasty bugs
# that result from abstraction leakage.
#
# == Basic Usage
#
# As already mentioned, the basic usage of a Completion is simply for its two
# final states, :succeeded and :failed.
#
# An asynchronous operation will complete at some future point in time, and
# users often want to react to this event. API authors will want to expose
# some common interface to react to these events.
#
# In the following example, the user wants to know when a short lived
# connection has completed its exchange with the remote server. The simple
# protocol just waits for an ack to its message.
#
#    class Protocol < EM::Connection
#      include EM::P::LineText2
#
#      def initialize(message, completion)
#        @message, @completion = message, completion
#        @completion.completion { close_connection }
#        @completion.timeout(1, :timeout)
#      end
#
#      def post_init
#        send_data(@message)
#      end
#
#      def receive_line(line)
#        case line
#        when /ACK/i
#          @completion.succeed line
#        when /ERR/i
#          @completion.fail :error, line
#        else
#          @completion.fail :unknown, line
#        end
#      end
#  
#      def unbind
#        @completion.fail :disconnected unless @completion.completed?
#      end
#    end
#
#    class API
#      attr_reader :host, :port
#
#      def initialize(host = 'example.org', port = 8000)
#        @host, @port = host, port
#      end
#
#      def request(message)
#        completion = EM::Deferrable::Completion.new
#        EM.connect(host, port, Protocol, message, completion)
#        completion
#      end
#    end
#
#    api = API.new
#    completion = api.request('stuff')
#    completion.callback do |line|
#      puts "API responded with: #{line}"
#    end
#    completion.errback do |type, line|
#      case type
#      when :error
#        puts "API error: #{line}"
#      when :unknown
#        puts "API returned unknown response: #{line}"
#      when :disconnected
#        puts "API server disconnected prematurely"
#      when :timeout
#        puts "API server did not respond in a timely fashion"
#      end
#    end
#
# == Advanced Usage
#
# This completion implementation also supports more state callbacks and
# arbitrary states (unlike the original Deferrable API). This allows for basic
# stateful process encapsulation. One might use this to setup state callbacks
# for various states in an exchange like in the basic usage example, except
# where the applicaiton could be made to react to "connected" and
# "disconnected" states additionally.
#
#    class Protocol < EM::Connection
#      def initialize(completion)
#        @response = []
#        @completion = completion
#        @completion.stateback(:disconnected) do
#          @completion.succeed @response.join
#        end
#      end
#
#      def connection_completed
#        @host, @port = Socket.unpack_sockaddr_in get_peername
#        @completion.change_state(:connected, @host, @port)
#        send_data("GET http://example.org/ HTTP/1.0\r\n\r\n")
#      end
#
#      def receive_data(data)
#        @response << data
#      end
#
#      def unbind
#        @completion.change_state(:disconnected, @host, @port)
#      end
#    end
#
#    completion = EM::Deferrable::Completion.new
#    completion.stateback(:connected) do |host, port|
#      puts "Connected to #{host}:#{port}"
#    end
#    completion.stateback(:disconnected) do |host, port|
#      puts "Disconnected from #{host}:#{port}"
#    end
#    completion.callback do |response|
#      puts response
#    end
#
#    EM.connect('example.org', 80, Protocol, completion)
#
# == Timeout
#
# The Completion also has a timeout. The timeout is global and is not aware of
# states apart from completion states. The timeout is only engaged if #timeout
# is called, and it will call fail if it is reached.
#
# == Completion states
#
# By default there are two completion states, :succeeded and :failed. These
# states can be modified by subclassing and overrding the #completion_states
# method. Completion states are special, in that callbacks for all completion
# states are explcitly cleared when a completion state is entered. This
# prevents errors that could arise from accidental unterminated timeouts, and
# other such user errors.
#
# == Other notes
#
# Several APIs have been carried over from EM::Deferrable for compatibility
# reasons during a transitionary period. Specifically cancel_errback and
# cancel_callback are implemented, but their usage is to be strongly
# discouraged. Due to the already complex nature of reaction systems, dynamic
# callback deletion only makes the problem much worse. It is always better to
# add correct conditionals to the callback code, or use more states, than to
# address such implementaiton issues with conditional callbacks.

module EventMachine

  class Completion
    # This is totally not used (re-implemented), it's here in case people check
    # for kind_of?
    include EventMachine::Deferrable

    attr_reader :state, :value

    def initialize
      @state = :unknown
      @callbacks = Hash.new { |h,k| h[k] = [] }
      @value = []
      @timeout_timer = nil
    end

    # Enter the :succeeded state, setting the result value if given.
    def succeed(*args)
      change_state(:succeeded, *args)
    end
    # The old EM method:
    alias set_deferred_success succeed

    # Enter the :failed state, setting the result value if given.
    def fail(*args)
      change_state(:failed, *args)
    end
    # The old EM method:
    alias set_deferred_failure fail

    # Statebacks are called when you enter (or are in) the named state.
    def stateback(state, *a, &b)
      # The following is quite unfortunate special casing for :completed
      # statebacks, but it's a necessary evil for latent completion
      # definitions.

      if :completed == state || !completed? || @state == state
        @callbacks[state] << EM::Callback(*a, &b)
      end
      execute_callbacks
      self
    end

    # Callbacks are called when you enter (or are in) a :succeeded state.
    def callback(*a, &b)
      stateback(:succeeded, *a, &b)
    end

    # Errbacks are called when you enter (or are in) a :failed state.
    def errback(*a, &b)
      stateback(:failed, *a, &b)
    end

    # Completions are called when you enter (or are in) either a :failed or a
    # :succeeded state. They are stored as a special (reserved) state called
    # :completed.
    def completion(*a, &b)
      stateback(:completed, *a, &b)
    end

    # Enter a new state, setting the result value if given. If the state is one
    # of :succeeded or :failed, then :completed callbacks will also be called.
    def change_state(state, *args)
      @value = args
      @state = state

      EM.schedule { execute_callbacks }
    end

    # The old EM method:
    alias set_deferred_status change_state

    # Indicates that we've reached some kind of completion state, by default
    # this is :succeeded or :failed. Due to these semantics, the :completed
    # state is reserved for internal use.
    def completed?
      completion_states.any? { |s| state == s }
    end

    # Completion states simply returns a list of completion states, by default
    # this is :succeeded and :failed.
    def completion_states
      [:succeeded, :failed]
    end

    # Schedule a time which if passes before we enter a completion state, this
    # deferrable will be failed with the given arguments.
    def timeout(time, *args)
      cancel_timeout
      @timeout_timer = EM::Timer.new(time) do
        fail(*args) unless completed?
      end
    end

    # Disable the timeout
    def cancel_timeout
      if @timeout_timer
        @timeout_timer.cancel
        @timeout_timer = nil
      end
    end

    # Remove an errback. N.B. Some errbacks cannot be deleted. Usage is NOT
    # recommended, this is an anti-pattern.
    def cancel_errback(*a, &b)
      @callbacks[:failed].delete(EM::Callback(*a, &b))
    end

    # Remove a callback. N.B. Some callbacks cannot be deleted. Usage is NOT
    # recommended, this is an anti-pattern.
    def cancel_callback(*a, &b)
      @callbacks[:succeeded].delete(EM::Callback(*a, &b))
    end

    private
    # Execute all callbacks for the current state. If in a completed state, then
    # call any statebacks associated with the completed state.
    def execute_callbacks
      execute_state_callbacks(state)
      if completed?
        execute_state_callbacks(:completed)
        clear_dead_callbacks
        cancel_timeout
      end
    end

    # Iterate all callbacks for a given state, and remove then call them.
    def execute_state_callbacks(state)
      while callback = @callbacks[state].shift
        callback.call(*value)
      end
    end

    # If we enter a completion state, clear other completion states after all
    # callback chains are completed. This means that operation specific
    # callbacks can't be dual-called, which is most common user error.
    def clear_dead_callbacks
      completion_states.each do |state|
        @callbacks[state].clear
      end
    end
  end
end