Savon/Ruby question: Variable context in block when initializing Client WSDL
I am creating a class to wrap around a Savon SOAP connection, as follows:
class SOAPConnection
attr_reader :url, :namespace
def initialize(url, namespace)
@url = url
@namespace = namespace
@client = Savon::Client.new do
wsdl.endpoint =开发者_C百科 @url
wsdl.namespace = @namespace
end
end
end
This code does not work. The wsdl document that gets initialized has a nil endpoint and a nil namespace.
To make the code work, I have to use the following:
class SOAPConnection
attr_reader :url, :namespace
def initialize(url, namespace)
@url = url
@namespace = namespace
@client = Savon::Client.new do
wsdl.endpoint = url # <=== use local variable
wsdl.namespace = namespace # <=== use local variable
end
end
end
Note that when setting up the wsdl.endpoint and wsdl.namespace I am using the local url and namespace variables, not the @url and @namespace instance variables.
So it seems that when passing in the block to initialize the wsdl document, the context of local variables is preserved while the context of instance variables is not. Is this a fundamental behaviour of Ruby?
Luckily this is not "a fundamental behaviour of Ruby", but related to how Savon evaluates the block passed to Savon::Client.new
.
If you don't pass any arguments to the block, Savon uses instance_eval with delegation to evaluate the block which unfortunately doesn't work with instance variables, but can access local variables and also methods from your class.
As an alternative, you can pass between 1 and 3 arguments to the block and receive the objects available to you in the following order:
[wsdl, http, wsse]
In your case, you would only need the first object, so your code would look like:
@client = Savon::Client.new do |wsdl| # <= one argument
wsdl.endpoint = @url
wsdl.namespace = @namespace
end
Please take a look at the documentation for Savon for more information.
精彩评论