lib/aqua/object/stub.rb in aqua-0.1.6 vs lib/aqua/object/stub.rb in aqua-0.2.0

- old
+ new

@@ -1,122 +1,87 @@ -# NOTES: I just checked and Delegator does all its delegation through method missing, so -# it probably makes sense to make this all one class, with method_missing doing the work. -# It might be faster, but harder, to pass a reference to the parent object and the way that -# the stub is accessed as a way to replace self with the actual object instead of stubbing. -# Not sure how that would work, but I am looking for something like self = something_else, -# which isn't kosher. - -module Aqua - class TempStub - def initialize( method_hash ) - method_hash.each do |method_name, value| - self.class.class_eval(" - def #{method_name} - #{value.inspect} - end - ") - end - end - end - - module StubDelegate - def __getobj__ - @_sd_obj # return object we are delegating to - end - - def __setobj__(obj) - @_sd_obj = obj # change delegation object - end - end +module Aqua + class Stub + attr_accessor :delegate, :delegate_class, :delegate_id, + :parent_object, :path_from_parent - class Stub < Delegator - include StubDelegate - # Builds a new stub object which returns cached/stubbed methods until such a time as a non-cached method # is requested. # # @param [Hash] # @option opts [Array] :methods A hash of method names and values # @option opts [String] :class The class of the object being stubbed # @option opts [String] :id The id of the object being stubbed # + # @todo pass in information about parent, and path to the stub such that method missing replaces stub + # with actual object being stubbed and delegated to. # @api semi-public - def initialize( opts ) - meths = opts[:methods] || {} - temp_stub = TempStub.new( meths ) - super( temp_stub ) - @_sd_obj = temp_stub - self.delegate_class = opts[:class] - self.delegate_id = opts[:id] - end + def initialize(opts) + stub_methods( opts[:methods] || {} ) + + self.delegate_class = opts[:class] + self.delegate_id = opts[:id] + self.parent_object = opts[:parent] + self.path_from_parent = opts[:path] + end - def method_missing( method, *args ) - if __getobj__.class.to_s != delegate_class.to_s - load_delegate - # resend! - if (args.size == 1 && !args.first.nil?) - __getobj__.send( method.to_sym, eval(args.map{|value| "'#{value}'"}.join(', ')) ) + def self.aqua_init( init, opts=Translator::Opts.new ) + new( init ) + end + + protected + + def stub_methods( stubbed_methods ) + stubbed_methods.each do |method_name, value| + self.class.class_eval(" + def #{method_name} + #{value.inspect} + end + ") + end + end + + def missing_delegate_error + raise ObjectNotFound, "Object of class '#{delegate_class}' and id '#{delegate_id}' not found" + end + + def method_missing( method, *args, &block ) + load_delegate if delegate.nil? + if delegate + delegate.send( method, *args, &block ) else - __getobj__.send( method.to_sym ) + missing_delegate_error end - else - raise NoMethodError end - end - - protected - attr_accessor :delegate_class, :delegate_id - - def load_delegate - __setobj__( delegate_class.constantize.load( delegate_id ) ) + def load_delegate + self.delegate = delegate_class.constantize.load( delegate_id ) end - public - - end + end - class FileStub < Delegator - include StubDelegate - - # Builds a new stub object which returns cached/stubbed methods until such a time as a non-cached method - # is requested. - # - # @param [Hash] - # @option opts [Array] :methods A hash of method names and values - # @option opts [String] :class The class of the object being stubbed - # @option opts [String] :id The id of the object being stubbed - # - # @api semi-public + class FileStub < Stub + attr_accessor :base_class, :base_id, :attachment_id + def initialize( opts ) - meths = opts[:methods] || {} - temp_stub = TempStub.new( meths ) - super( temp_stub ) - @_sd_obj = temp_stub - self.parent = opts[:parent] + super( opts ) + self.base_class = opts[:base_object].class + self.base_id = opts[:base_id] self.attachment_id = opts[:id] end - def method_missing( method, *args ) - if load_attempt != true - load_delegate - self.load_attempt = true - # resend! - if (args.size == 1 && !args.first.nil?) - __getobj__.send( method.to_sym, eval(args.map{|value| "'#{value}'"}.join(', ')) ) - else - __getobj__.send( method.to_sym ) - end - else - raise NoMethodError - end + # This is what is actually called in the Aqua unpack process + def self.aqua_init( init, opts ) + init['base_object'] = opts.base_object + init['base_id'] = opts.base_id || opts.base_object.id # this is needed when an object is loaded, not reloaded + super end - - protected - attr_accessor :parent, :attachment_id, :load_attempt + protected + def missing_delegate_error + raise ObjectNotFound, "Attachment '#{attachment_id}' for '#{base_class}' with id='#{base_id}' not found." + end def load_delegate - __setobj__( parent.class::Storage.attachment( parent.id, attachment_id ) ) + self.delegate = base_class::Storage.attachment( base_id, attachment_id ) end - public - end + end + end \ No newline at end of file