diff --git a/CHANGELOG.md b/CHANGELOG.md index de16013d..f8b53931 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,10 @@ client.request :wsdl, "GetUser" # Input tag: client.request :get_user :active => true # Input tag: +* Savon's new #request method respects the given namespace. If you don't give it a namespace, + Savon will set the target namespace to "xmlns:wsdl". But if you do specify a namespace, it will + be set to the given Symbol. + * Refactored Savon to use the new HTTPI (http://rubygems.org/gems/httpi) gem. HTTPI::Request replaces the Savon::Request, so please make sure to have a look at the HTTPI library and let me know about any problems. Using HTTPI actually diff --git a/lib/savon/client.rb b/lib/savon/client.rb index f7a95457..86eacc07 100644 --- a/lib/savon/client.rb +++ b/lib/savon/client.rb @@ -30,7 +30,7 @@ class Client # wsdl.namespace = "http://users.example.com" # end def initialize(&block) - process &block if block + process 1, &block if block wsdl.request = http end @@ -99,6 +99,7 @@ def extract_options(args) # Expects and Array of +options+ and preconfigures the system. def preconfigure(options) soap.endpoint = wsdl.endpoint + soap.namespace_identifier = options[0] soap.namespace = wsdl.namespace soap.body = options[2].delete :body @@ -122,14 +123,14 @@ def set_soap_input(namespace, input, attributes) # Processes a given +block+. Yields objects if the block expects any arguments. # Otherwise evaluates the block in the context of this object. - def process(&block) - block.arity > 0 ? yield_objects(&block) : evaluate(&block) + def process(offset = 0, &block) + block.arity > 0 ? yield_objects(offset, &block) : evaluate(&block) end # Yields a number of objects to a given +block+ depending on how many arguments # the block is expecting. - def yield_objects(&block) - yield *[soap, http, wsse, wsdl][0, block.arity] + def yield_objects(offset, &block) + yield *[soap, wsdl, http, wsse][offset, block.arity] end # Evaluates a given +block+ inside this object. Stores the original block binding. diff --git a/lib/savon/soap/xml.rb b/lib/savon/soap/xml.rb index 084366b8..284c60b3 100644 --- a/lib/savon/soap/xml.rb +++ b/lib/savon/soap/xml.rb @@ -62,11 +62,17 @@ def namespaces @namespaces ||= { "xmlns:env" => SOAP::Namespace[version] } end - # Convenience method for setting the xmlns:wsdl namespace. - def namespace=(namespace) - namespaces["xmlns:wsdl"] = namespace + # Sets the default namespace identifier. + attr_writer :namespace_identifier + + # Returns the default namespace identifier. + def namespace_identifier + @namespace_identifier ||= :wsdl end + # Accessor for the default namespace URI. + attr_accessor :namespace + # Accessor for the Savon::WSSE object. attr_accessor :wsse @@ -84,7 +90,7 @@ def xml # Returns the XML for a SOAP request. def to_xml - @xml ||= builder.env :Envelope, SchemaTypes.merge(namespaces) do |xml| + @xml ||= builder.env :Envelope, complete_namespaces do |xml| xml.env(:Header) { xml << header_for_xml } unless header_for_xml.empty? xml.env(:Body) { xml.tag!(*input) { xml << body_to_xml } } end @@ -99,6 +105,13 @@ def builder builder end + # Returns the complete Hash of namespaces. + def complete_namespaces + defaults = SchemaTypes.dup + defaults["xmlns:#{namespace_identifier}"] = namespace if namespace + defaults.merge namespaces + end + # Returns the SOAP header as an XML String. def header_for_xml header.to_soap_xml + wsse_header diff --git a/spec/savon/client_spec.rb b/spec/savon/client_spec.rb index 6d914244..8a00a82f 100644 --- a/spec/savon/client_spec.rb +++ b/spec/savon/client_spec.rb @@ -3,6 +3,47 @@ describe Savon::Client do let(:client) { Savon::Client.new { wsdl.document = Endpoint.wsdl } } + describe ".new" do + context "with a block expecting one argument" do + it "should yield the WSDL object" do + Savon::Client.new { |wsdl| wsdl.should be_a(Savon::WSDL::Document) } + end + end + + context "with a block expecting two arguments" do + it "should yield the WSDL and HTTP objects" do + Savon::Client.new do |wsdl, http| + wsdl.should be_an(Savon::WSDL::Document) + http.should be_an(HTTPI::Request) + end + end + end + + context "with a block expecting three arguments" do + it "should yield the WSDL, HTTP and WSSE objects" do + Savon::Client.new do |wsdl, http, wsse| + wsdl.should be_an(Savon::WSDL::Document) + http.should be_an(HTTPI::Request) + wsse.should be_an(Savon::WSSE) + end + end + end + + context "with a block expecting no arguments" do + it "should let you access the WSDL object" do + Savon::Client.new { wsdl.should be_a(Savon::WSDL::Document) } + end + + it "should let you access the HTTP object" do + Savon::Client.new { http.should be_an(HTTPI::Request) } + end + + it "should let you access the WSSE object" do + Savon::Client.new { wsse.should be_a(Savon::WSSE) } + end + end + end + describe "#wsdl" do it "should return the Savon::WSDL::Document" do client.wsdl.should be_a(Savon::WSDL::Document) @@ -22,8 +63,6 @@ end describe "#request" do - let(:client) { Savon::Client.new { wsdl.document = Endpoint.wsdl } } - before do HTTPI.stubs(:get).returns(new_response(:body => WSDLFixture.load)) HTTPI.stubs(:post).returns(new_response) @@ -39,6 +78,20 @@ it "should set the input tag to result in " do client.request(:get_user) { soap.input.should == [:getUser, {}] } end + + it "should set the target namespace with the default identifier" do + namespace = 'xmlns:wsdl="http://v1_0.ws.auth.order.example.com/"' + HTTPI::Request.any_instance.expects(:body=).with { |value| value.include? namespace } + + client.request :get_user + end + + it "should not set the target namespace if soap.namespace was set to nil" do + namespace = "http://v1_0.ws.auth.order.example.com/" + HTTPI::Request.any_instance.expects(:body=).with { |value| !value.include?(namespace) } + + client.request(:get_user) { soap.namespace = nil } + end end context "with a single argument (String)" do @@ -55,7 +108,21 @@ context "with two Symbols" do it "should set the input tag to result in " do - client.request(:wsdl, :get_user) { soap.input.should == [:wsdl, :getUser, {}] } + client.request(:v1, :get_user) { soap.input.should == [:v1, :getUser, {}] } + end + + it "should set the target namespace with the given identifier" do + namespace = 'xmlns:v1="http://v1_0.ws.auth.order.example.com/"' + HTTPI::Request.any_instance.expects(:body=).with { |value| value.include? namespace } + + client.request :v1, :get_user + end + + it "should not set the target namespace if soap.namespace was set to nil" do + namespace = "http://v1_0.ws.auth.order.example.com/" + HTTPI::Request.any_instance.expects(:body=).with { |value| !value.include?(namespace) } + + client.request(:v1, :get_user) { soap.namespace = nil } end end @@ -72,31 +139,31 @@ end context "with a block expecting two arguments" do - it "should yield the SOAP and HTTP objects" do - client.request(:authenticate) do |soap, http| + it "should yield the SOAP and WSDL objects" do + client.request(:authenticate) do |soap, wsdl| soap.should be_a(Savon::SOAP::XML) - http.should be_an(HTTPI::Request) + wsdl.should be_an(Savon::WSDL::Document) end end end context "with a block expecting three arguments" do - it "should yield the SOAP, HTTP and WSSE objects" do - client.request(:authenticate) do |soap, http, wsse| + it "should yield the SOAP, WSDL and HTTP objects" do + client.request(:authenticate) do |soap, wsdl, http| soap.should be_a(Savon::SOAP::XML) + wsdl.should be_an(Savon::WSDL::Document) http.should be_an(HTTPI::Request) - wsse.should be_a(Savon::WSSE) end end end context "with a block expecting four arguments" do - it "should yield the SOAP, HTTP, WSSE and WSDL objects" do - client.request(:authenticate) do |soap, http, wsse, wsdl| + it "should yield the SOAP, WSDL, HTTP and WSSE objects" do + client.request(:authenticate) do |soap, wsdl, http, wsse| soap.should be_a(Savon::SOAP::XML) + wsdl.should be_a(Savon::WSDL::Document) http.should be_an(HTTPI::Request) wsse.should be_a(Savon::WSSE) - wsdl.should be_a(Savon::WSDL::Document) end end end diff --git a/spec/savon/soap/xml_spec.rb b/spec/savon/soap/xml_spec.rb index 2467d6bc..c84dc978 100644 --- a/spec/savon/soap/xml_spec.rb +++ b/spec/savon/soap/xml_spec.rb @@ -98,13 +98,6 @@ end end - describe "#namespace" do - it "should set the 'xmlns:wsdl' namespace" do - xml.namespace = "http://example.com" - xml.namespaces["xmlns:wsdl"].should == "http://example.com" - end - end - describe "#wsse" do it "should set the Savon::WSSE object" do xml.wsse = Savon::WSSE.new @@ -194,8 +187,9 @@ end end - context "using the #namespace shortcut" do - it "should contain the 'xmlns:wsdl' namespace" do + context "using the #namespace and #namespace_identifier" do + it "should contain the specified namespace" do + xml.namespace_identifier = :wsdl xml.namespace = "http://example.com" xml.to_xml.should include('xmlns:wsdl="http://example.com"') end