5 # A module to implement the Linda distributed computing paradigm in Ruby.
7 # Rinda is part of DRb (dRuby).
11 # See the sample/drb/ directory in the Ruby distribution, from 1.8.2 onwards.
15 # == Introduction to Linda/rinda?
17 # == Why is this library separate from DRb?
22 # Rinda error base class
24 class RindaError < RuntimeError; end
27 # Raised when a hash-based tuple has an invalid key.
29 class InvalidHashTupleKey < RindaError; end
32 # Raised when trying to use a canceled tuple.
34 class RequestCanceledError < ThreadError; end
37 # Raised when trying to use an expired tuple.
39 class RequestExpiredError < ThreadError; end
42 # A tuple is the elementary object in Rinda programming.
43 # Tuples may be matched against templates if the tuple and
44 # the template are the same size.
49 # Creates a new Tuple from +ary_or_hash+ which must be an Array or Hash.
51 def initialize(ary_or_hash)
53 init_with_hash(ary_or_hash)
55 init_with_ary(ary_or_hash)
60 # The number of elements in the tuple.
67 # Accessor method for elements of the tuple.
74 # Fetches item +k+ from the tuple.
81 # Iterate through the tuple, yielding the index or key, and the
82 # value, thus ensuring arrays are iterated similarly to hashes.
86 @tuple.each { |k, v| yield(k, v) }
88 @tuple.each_with_index { |v, k| yield(k, v) }
93 # Return the tuple itself
100 def hash?(ary_or_hash)
101 ary_or_hash.respond_to?(:keys)
105 # Munges +ary+ into a valid Tuple.
107 def init_with_ary(ary)
108 @tuple = Array.new(ary.size)
109 @tuple.size.times do |i|
115 # Ensures +hash+ is a valid Tuple.
117 def init_with_hash(hash)
120 raise InvalidHashTupleKey unless String === k
128 # Templates are used to match tuples in Rinda.
130 class Template < Tuple
133 # Matches this template against +tuple+. The +tuple+ must be the same
134 # size as the template. An element with a +nil+ value in a template acts
135 # as a wildcard, matching any value in the corresponding position in the
136 # tuple. Elements of the template match the +tuple+ if the are #== or
139 # Template.new([:foo, 5]).match Tuple.new([:foo, 5]) # => true
140 # Template.new([:foo, nil]).match Tuple.new([:foo, 5]) # => true
141 # Template.new([String]).match Tuple.new(['hello']) # => true
143 # Template.new([:foo]).match Tuple.new([:foo, 5]) # => false
144 # Template.new([:foo, 6]).match Tuple.new([:foo, 5]) # => false
145 # Template.new([:foo, nil]).match Tuple.new([:foo]) # => false
146 # Template.new([:foo, 6]).match Tuple.new([:foo]) # => false
149 return false unless tuple.respond_to?(:size)
150 return false unless tuple.respond_to?(:fetch)
151 return false unless self.size == tuple.size
176 # <i>Documentation?</i>
178 class DRbObjectTemplate
181 # Creates a new DRbObjectTemplate that will match against +uri+ and +ref+.
183 def initialize(uri=nil, ref=nil)
189 # This DRbObjectTemplate matches +ro+ if the remote object's drburi and
190 # drbref are the same. +nil+ is used as a wildcard.
193 return true if super(ro)
195 return false unless (@drb_uri === ro.__drburi rescue false)
198 return false unless (@drb_ref === ro.__drbref rescue false)
206 # TupleSpaceProxy allows a remote Tuplespace to appear as local.
208 class TupleSpaceProxy
211 # Creates a new TupleSpaceProxy to wrap +ts+.
218 # Adds +tuple+ to the proxied TupleSpace. See TupleSpace#write.
220 def write(tuple, sec=nil)
221 @ts.write(tuple, sec)
225 # Takes +tuple+ from the proxied TupleSpace. See TupleSpace#take.
227 def take(tuple, sec=nil, &block)
229 @ts.move(DRbObject.new(port), tuple, sec, &block)
234 # Reads +tuple+ from the proxied TupleSpace. See TupleSpace#read.
236 def read(tuple, sec=nil, &block)
237 @ts.read(tuple, sec, &block)
241 # Reads all tuples matching +tuple+ from the proxied TupleSpace. See
242 # TupleSpace#read_all.
249 # Registers for notifications of event +ev+ on the proxied TupleSpace.
250 # See TupleSpace#notify
252 def notify(ev, tuple, sec=nil)
253 @ts.notify(ev, tuple, sec)
259 # An SimpleRenewer allows a TupleSpace to check if a TupleEntry is still
267 # Creates a new SimpleRenewer that keeps an object alive for another +sec+
270 def initialize(sec=180)
275 # Called by the TupleSpace to check if the object is still alive.