Class: Debouncer

Inherits:
Object
  • Object
show all
Defined in:
lib/debouncer.rb,
lib/debouncer/version.rb,
lib/debouncer/debounceable.rb

Defined Under Namespace

Modules: Debounceable

Constant Summary collapse

VERSION =
'0.1.0'

Instance Method Summary collapse

Constructor Details

#initialize(delay, &block) ⇒ Debouncer

Returns a new instance of Debouncer.

Raises:

  • (ArgumentError)


4
5
6
7
8
9
10
11
12
# File 'lib/debouncer.rb', line 4

def initialize(delay, &block)
  raise ArgumentError, 'Expected a number' unless delay.is_a? Numeric
  @delay    = delay
  @timeouts = {}
  @threads  = []
  @lock     = Mutex.new
  @rescuers = {}
  block.arity.zero? ? instance_exec(&block) : yield(self) if block
end

Instance Method Details

#debounce(id = nil, *args, &block) ⇒ Object

Raises:

  • (ArgumentError)


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/debouncer.rb', line 29

def debounce(id = nil, *args, &block)
  raise ArgumentError, 'Expected a block' unless block
  exclusively do
    thread = @timeouts[id] ||= new_thread { begin_delay id, &block }
    @flush = [id]
    args   = reduce_args(thread, args, id)
    if (@limiter && !@limiter[*args]) || @flush == true
      thread.kill
      @timeouts.delete id
      @threads.delete thread
      @flush = false
    else
      thread[:args]   = args
      thread[:run_at] = Time.now + @delay
    end
  end or
      yield *args
  self
end

#flush(*args) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/debouncer.rb', line 49

def flush(*args)
  if args.empty?
    if @lock.owned?
      @flush = true
    else
      flush @timeouts.keys.first while @timeouts.any?
    end
  else
    id = args.first
    if @lock.owned? && @flush == [id]
      @flush = true
    else
      dead = exclusively do
        if (thread = @timeouts.delete(id))
          thread.kill
          @threads.delete thread
        end
      end
      dead[:block].call *dead[:args] if dead
    end
  end
  self
end

#inspectObject



86
87
88
# File 'lib/debouncer.rb', line 86

def inspect
  "#<#{self.class}:0x#{'%014x' % (object_id << 1)} delay: #{@delay} timeouts: #{@timeouts.count} threads: #{@threads.count}>"
end

#join(kill_first = false) ⇒ Object



73
74
75
76
77
78
79
80
# File 'lib/debouncer.rb', line 73

def join(kill_first = false)
  while (thread = exclusively { @threads.find &:alive? })
    thread.kill if kill_first
    thread.join
  end
  exclusively { [@threads, @timeouts].each &:clear } if kill_first
  self
end

#killObject



82
83
84
# File 'lib/debouncer.rb', line 82

def kill
  join true
end

#limiter(&block) ⇒ Object



19
20
21
22
# File 'lib/debouncer.rb', line 19

def limiter(&block)
  @limiter = block
  self
end

#reducer(*initial, &block) ⇒ Object



14
15
16
17
# File 'lib/debouncer.rb', line 14

def reducer(*initial, &block)
  @reducer = [initial, block]
  self
end

#rescuer(kind = StandardError, &block) ⇒ Object



24
25
26
27
# File 'lib/debouncer.rb', line 24

def rescuer(kind = StandardError, &block)
  @rescuers[kind] = block
  self
end