Class: Seatbelt::Proxy

Inherits:
Object
  • Object
show all
Defined in:
lib/seatbelt/core/proxy.rb

Overview

Public: A Seatbelt::Proxy class is a shadow of any class that includes Seatbelt::Gate. It provides access to the API class or instance of the API class and implements the DynamicProxy pattern.

A Proxy class provides a private dynamic accessor #klass that changes with the implementation scope of the API methods implementation.

Let’s show this by example:

class ApiClass

include Seatbelt::Ghost

api_method :an_instance_method_to_implement
api_method :a_class_method_to_implement
def helper(a,b,c)
  #....
end

def self.c_helper(options={})
  # ...
end

end

class ApiClassImplementation

def instance_implementation
  local = proxy.call(:helper, 1,2,4) # proxy scope is instance of ApiClass
end
implement :instance_implementation,
          :as => "ApiClass#an_instance_method_to_implement"

def class_implementation
  local = proxy.call(:c_helper, {:foo => 19})
  # proxy scope is ApiClass
end
implement :class_implementation,
          :as => "ApiClass.a_class_method_to_implement"

end

Constant Summary collapse

NOT_ALLOWABLE_CALLS_ON_OBJECT =
%w{ call object klass tunnel }

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

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

Public: Delegates a method message to the #object receiver if the message is not included in NOT_ALLOWABLE_CALLS_ON_OBJECT or the class responds to.



125
126
127
128
129
130
131
132
# File 'lib/seatbelt/core/proxy.rb', line 125

def method_missing(method_name, *args, &block)
  unless method_name.to_s.in?(NOT_ALLOWABLE_CALLS_ON_OBJECT) &&
    (not self.respond_to?(method_name))
    self.call(method_name, *args, &block)
  else
    super
  end
end

Instance Method Details

#call(method_name, *args, &block) ⇒ Object

Public: Send a method message to the current #klass scope receiver. See class documentation section for further informations about #klass.

method_name - The method to call *args - The methods argument list &block - An optional block that should be passed to the callable

method

Returns the return value of the callable method or raises a NoMethodError.



56
57
58
# File 'lib/seatbelt/core/proxy.rb', line 56

def call(method_name, *args, &block)
  object.send(method_name,*args,&block)
end

#objectObject



60
61
62
# File 'lib/seatbelt/core/proxy.rb', line 60

def object
  self.send(:klass)
end

#tunnel(chain) ⇒ Object

Public: Calls a private API attribute or method of an object defined in a API class.

It is only working on a second level.

chain - The attribute call chain as String.

Example:

class ApiA

include Seatbelt::Document
include Seatbelt::Ghost

has :b, "Models::B"

end

class Models::B

include Seatbelt::Document
include Seatbelt::Ghost

# definitions

end

class ImplementationB

field :name, :type => String

end

In a implementation method of ApiA

proxy.tunnel(“b.name”)

Returns the duplicated String.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/seatbelt/core/proxy.rb', line 99

def tunnel(chain)
  proxy_associated_object,object_method = chain.split(".")
  unless object.respond_to?(proxy_associated_object) 
    raise Seatbelt::Errors::ObjectDoesNotExistError 
  else
    tunneled_object = object.send(proxy_associated_object)
    callees         = tunneled_object.eigenmethods.map do |eigenmethod|
      eigenmethod.send(:callee)
    end
  
    callee = callees.uniq.first
    unless callee.nil?
      unless object_method
        warn "You called a single object. Use #call instead." 
        object_method = proxy_associated_object
      end
      return callee.send(object_method)
    else
      raise Seatbelt::Errors::MethodNotImplementedError
    end
  end
end