module Laundry # = Savon::Model # # Model for SOAP service oriented applications. module SOAPModel def self.extended(base) base.setup end def setup class_action_module instance_action_module end # Accepts one or more SOAP actions and generates both class and instance methods named # after the given actions. Each generated method accepts an optional SOAP body Hash and # a block to be passed to Savon::Client#request and executes a SOAP request. def actions(*actions) actions.each do |action| define_class_action(action) define_instance_action(action) end end private # Defines a class-level SOAP action method. def define_class_action(action) class_action_module.module_eval %{ def #{action.to_s.snakecase}(body = nil, &block) client_request #{action.inspect}, :body => body, &block end } end # Defines an instance-level SOAP action method. def define_instance_action(action) instance_action_module.module_eval %{ def #{action.to_s.snakecase}(body = nil, &block) self.class.#{action.to_s.snakecase} merged_default_body(body), &block end } end # Class methods. def class_action_module @class_action_module ||= Module.new do # Returns the memoized Savon::Client. def client(&block) @client ||= Savon::Client.new(&block) end # Sets the SOAP endpoint to the given +uri+. def endpoint(uri) client.wsdl.endpoint = uri end # Sets the target namespace. def namespace(uri) client.wsdl.namespace = uri end # Sets the WSDL document to the given +uri+. def document(uri) client.wsdl.document = uri end # Sets the HTTP headers. def headers(headers) client.http.headers = headers end def client_request(action, body, &block) client.request :wsdl, action, body, &block end # Sets basic auth +login+ and +password+. def basic_auth(login, password) client.http.auth.basic(login, password) end # Sets WSSE auth credentials. def wsse_auth(*args) client.wsse.credentials(*args) end end.tap { |mod| extend(mod) } end # Instance methods. def instance_action_module @instance_action_module ||= Module.new do # Returns the Savon::Client from the class instance. def client(&block) self.class.client(&block) end private def merged_default_body(body = {}) default = self.respond_to?(:default_body) ? self.default_body : nil (default || {}).merge (body || {}) end end.tap { |mod| include(mod) } end end end