Class: Archipelago::Treasure::Dubloon

Inherits:
Object
  • Object
show all
Defined in:
lib/archipelago/treasure.rb

Overview

A proxy to something in the chest.

This will do a very efficient masquerade as the object it proxies. When asked for its class or any other attribute it will forward the query to the proxied object.

It can also be a part of a transaction, either because it was fetched from the chest within a transaction, or because it is the return value of a Dubloon#join call.

In this case all forwarded methods will also be within the same transaction, and any change to the proxied object will be inside that transaction.

If the proxied object itself needs to handle transaction semantics it can implement the with_transaction(transaction, &block) method, which will wrap the method call itself within the home Chest of the proxied object.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, chest, transaction, chest_id) ⇒ Dubloon

Initialize us with knowledge of our chest, the key to our target in the chest, the known public_methods of our target and any transaction we are associated with.



146
147
148
149
150
151
# File 'lib/archipelago/treasure.rb', line 146

def initialize(key, chest, transaction, chest_id)
  @key = key
  @chest = chest
  @transaction = transaction
  @chest_id = chest_id
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &block) ⇒ Object

Call meth with args and block on our target if it responds to it.



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/archipelago/treasure.rb', line 211

def method_missing(meth, *args, &block)
  begin
    return @chest.call_instance_method(@key, meth, @transaction, *args, &block)
  rescue DRb::DRbConnError => e
    if defined?(Archipelago::Disco::MC)
      possible_replacements = Archipelago::Disco::MC.lookup(Archipelago::Disco::Query.new({:service_id => @chest_id}))
      raise e if possible_replacements.empty?
      
      @chest = possible_replacements[@chest_id][:service]
      CHEST_BY_SERVICE_ID[@chest_id] = @chest
      
      retry
    else
      raise e
    end
  end
end

Class Method Details

._load(s) ⇒ Object

Load some instance variables and replace @chest if we know that it actually is not correct.



167
168
169
170
171
172
173
174
# File 'lib/archipelago/treasure.rb', line 167

def self._load(s)
  key, chest, transaction, chest_id = Marshal.load(s)
  if CHEST_BY_SERVICE_ID.include?(chest_id)
    chest = CHEST_BY_SERVICE_ID[chest_id]
  end

  return self.new(key, chest, transaction, chest_id)
end

Instance Method Details

#==(o) ⇒ Object

If o is a Dubloon, will return true if it has the same Dubloon#object_id.

Otherwise will defer to Dubloon#method_missing.



135
136
137
138
139
140
# File 'lib/archipelago/treasure.rb', line 135

def ==(o)
  if Dubloon === o
    return true if self.object_id == o.object_id
  end
  return self.method_missing(:==, o)
end

#_dump(dummy_levels) ⇒ Object

A more or less normal dump of all our instance variables.



155
156
157
158
159
160
161
162
# File 'lib/archipelago/treasure.rb', line 155

def _dump(dummy_levels)
  Marshal.dump([
                @key, 
                @chest, 
                @transaction, 
                @chest_id
               ])
end

#assert_transaction(transaction) ⇒ Object

Raises exception if the given transaction is not the same as our own.



187
188
189
# File 'lib/archipelago/treasure.rb', line 187

def assert_transaction(transaction)
  raise UnknownTransactionException.new(self, transaction) unless transaction == @transaction
end

#eql?(o) ⇒ Boolean

Defers to Dubloon#==.



127
128
129
# File 'lib/archipelago/treasure.rb', line 127

def eql?(o)
  self.==(o)
end

#hashObject

This Dubloon will always have the same hash, based on object_id.



121
122
123
# File 'lib/archipelago/treasure.rb', line 121

def hash
  self.object_id.hash
end

#join(transaction) ⇒ Object

Return a clone of myself that is joined to the transaction.



179
180
181
182
# File 'lib/archipelago/treasure.rb', line 179

def join(transaction)
  @chest.join!(transaction) if transaction
  return Dubloon.new(@key, @chest, transaction, @chest_id)
end

#object_idObject

This Dubloon will always have the same object_id, based on



194
195
196
197
198
# File 'lib/archipelago/treasure.rb', line 194

def object_id
  id = "#{@chest_id}:#{@key}"
  id << ":#{@transaction.transaction_id}" if @transaction
  return id
end

#respond_to?(meth) ⇒ Boolean

Does our target respond to meth?



202
203
204
205
206
# File 'lib/archipelago/treasure.rb', line 202

def respond_to?(meth)
  # This one will be called far too often, and it seems safe to ignore it.
  return false if meth == :marshal_dump
  return super(meth) || self.method_missing(:respond_to?, meth)
end