Class: Ruck::CallccShred

Inherits:
Object
  • Object
show all
Defined in:
lib/ruck/shred.rb

Overview

A resumable Proc implemented using continuation. If the given block calls #pause during its execution, its execution is paused and the caller resumed. The second time the Shred is called, it resumes where it left off.

If #pause is called anywhere but inside the given block, I can almost guarantee that strange things will happen.

Constant Summary collapse

@@current_shreds =
[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(&block) ⇒ CallccShred

Returns a new instance of CallccShred.



28
29
30
# File 'lib/ruck/shred.rb', line 28

def initialize(&block)
  @proc = block || Proc.new{}
end

Instance Attribute Details

#procObject (readonly) Also known as: running?

I don’t mean to actually expose @proc. I noticed that Ruby 1.8’s garbage collection cycles become much longer when @proc (a Continuation) is returned from a custom method, but not if returned from an attr_reader. I use attr_reader and alias it to running? to avoid this cost.



18
19
20
# File 'lib/ruck/shred.rb', line 18

def proc
  @proc
end

Class Method Details

.currentObject

the currently executing shred



24
25
26
# File 'lib/ruck/shred.rb', line 24

def self.current
  @@current_shreds.last
end

Instance Method Details

#[](*args) ⇒ Object

alias for call. It takes arguments, but ignores them.



63
64
65
# File 'lib/ruck/shred.rb', line 63

def [](*args)
  call(*args)
end

#call(*args) ⇒ Object

begin or resume execution



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/ruck/shred.rb', line 46

def call(*args)
  return unless @proc
  
  callcc do |cont|
    @caller = cont
    
    @@current_shreds << self
    @proc.call
    
    # if we made it here, we're done
    @@current_shreds.pop
    @proc = nil
    @caller.call
  end
end

#finished?Boolean

returns true if calling this Shred again will have no effect

Returns:

  • (Boolean)


68
69
70
# File 'lib/ruck/shred.rb', line 68

def finished?
  !running?
end

#killObject

makes it so calling this Shred in the future will have no effect



73
74
75
# File 'lib/ruck/shred.rb', line 73

def kill
  @proc = nil
end

#pauseObject

pause execution by saving this execution point and returning to the point where go was called



34
35
36
37
38
39
40
41
42
43
# File 'lib/ruck/shred.rb', line 34

def pause
  return unless Shred.current == self
  
  @@current_shreds.pop
  
  callcc do |cont|
    @proc = cont
    @caller.call
  end
end