blob: 4002880957e84e0945e6fad066562b85735b2472 [file] [log] [blame]
module SassListen
module Event
class Processor
def initialize(config, reasons)
@config = config
@reasons = reasons
_reset_no_unprocessed_events
end
# TODO: implement this properly instead of checking the state at arbitrary
# points in time
def loop_for(latency)
@latency = latency
loop do
_wait_until_events
_wait_until_events_calm_down
_wait_until_no_longer_paused
_process_changes
end
rescue Stopped
SassListen::Logger.debug('Processing stopped')
end
private
class Stopped < RuntimeError
end
def _wait_until_events_calm_down
loop do
now = _timestamp
# Assure there's at least latency between callbacks to allow
# for accumulating changes
diff = _deadline - now
break if diff <= 0
# give events a bit of time to accumulate so they can be
# compressed/optimized
_sleep(:waiting_until_latency, diff)
end
end
def _wait_until_no_longer_paused
# TODO: may not be a good idea?
_sleep(:waiting_for_unpause) while config.paused?
end
def _check_stopped
return unless config.stopped?
_flush_wakeup_reasons
raise Stopped
end
def _sleep(_local_reason, *args)
_check_stopped
sleep_duration = config.sleep(*args)
_check_stopped
_flush_wakeup_reasons do |reason|
next unless reason == :event
_remember_time_of_first_unprocessed_event unless config.paused?
end
sleep_duration
end
def _remember_time_of_first_unprocessed_event
@first_unprocessed_event_time ||= _timestamp
end
def _reset_no_unprocessed_events
@first_unprocessed_event_time = nil
end
def _deadline
@first_unprocessed_event_time + @latency
end
def _wait_until_events
# TODO: long sleep may not be a good idea?
_sleep(:waiting_for_events) while config.event_queue.empty?
@first_unprocessed_event_time ||= _timestamp
end
def _flush_wakeup_reasons
reasons = @reasons
until reasons.empty?
reason = reasons.pop
yield reason if block_given?
end
end
def _timestamp
config.timestamp
end
# for easier testing without sleep loop
def _process_changes
_reset_no_unprocessed_events
changes = []
changes << config.event_queue.pop until config.event_queue.empty?
callable = config.callable?
return unless callable
hash = config.optimize_changes(changes)
result = [hash[:modified], hash[:added], hash[:removed]]
return if result.all?(&:empty?)
block_start = _timestamp
config.call(*result)
SassListen::Logger.debug "Callback took #{_timestamp - block_start} sec"
end
attr_reader :config
end
end
end