diff --git a/CHANGELOG.md b/CHANGELOG.md
index e5af3fba..2fa81a37 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,9 @@
* Added Savon::SOAP::XML#env_namespace to configure the SOAP envelope namespace. It defaults to :env
but can also be set to an empty String for SOAP envelope tags without a namespace.
+* Replaced quite a lot of core extensions by moving the Hash to XML translation into a new gem called
+ Gyoku (http://rubygems.org/gems/gyoku).
+
## 0.8.0.beta.4 (2010-11-20)
* Fix for issue #107 (Soap Fault regex not working for API I connect).
diff --git a/lib/savon/core_ext/array.rb b/lib/savon/core_ext/array.rb
deleted file mode 100644
index 6397394d..00000000
--- a/lib/savon/core_ext/array.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-require "builder"
-
-require "savon/core_ext/object"
-require "savon/core_ext/string"
-require "savon/core_ext/hash"
-require "savon/core_ext/datetime"
-
-module Savon
- module CoreExt
- module Array
-
- # Translates the Array into SOAP compatible XML. See: Hash.to_soap_xml.
- def to_soap_xml(key, escape_xml = true, attributes = {})
- xml = Builder::XmlMarkup.new
-
- each_with_index do |item, index|
- attrs = tag_attributes attributes, index
- case item
- when ::Hash then xml.tag!(key, attrs) { xml << item.to_soap_xml }
- when NilClass then xml.tag!(key, "xsi:nil" => "true")
- else xml.tag!(key, attrs) { xml << (escape_xml ? item.to_soap_value : item.to_soap_value!) }
- end
- end
-
- xml.target!
- end
-
- private
-
- # Takes a Hash of +attributes+ and the +index+ for which to return attributes
- # for duplicate tags.
- def tag_attributes(attributes, index)
- return {} if attributes.empty?
-
- attributes.inject({}) do |hash, (key, value)|
- value = value[index] if value.kind_of? ::Array
- hash.merge key => value
- end
- end
-
- end
- end
-end
-
-Array.send :include, Savon::CoreExt::Array
diff --git a/lib/savon/core_ext/datetime.rb b/lib/savon/core_ext/datetime.rb
deleted file mode 100644
index 8744227f..00000000
--- a/lib/savon/core_ext/datetime.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require "date"
-require "savon/soap"
-
-module Savon
- module CoreExt
- module DateTime
-
- # Returns the DateTime as an xs:dateTime formatted String.
- def to_soap_value
- strftime Savon::SOAP::DateTimeFormat
- end
-
- alias_method :to_soap_value!, :to_soap_value
-
- end
- end
-end
-
-DateTime.send :include, Savon::CoreExt::DateTime
diff --git a/lib/savon/core_ext/hash.rb b/lib/savon/core_ext/hash.rb
index fb02c2a7..bec27c8e 100644
--- a/lib/savon/core_ext/hash.rb
+++ b/lib/savon/core_ext/hash.rb
@@ -3,9 +3,6 @@
require "savon"
require "savon/core_ext/object"
require "savon/core_ext/string"
-require "savon/core_ext/symbol"
-require "savon/core_ext/array"
-require "savon/core_ext/datetime"
module Savon
module CoreExt
@@ -19,74 +16,6 @@ def find_soap_body
body_key ? envelope[body_key].map_soap_response : {}
end
- # Translates the Hash into SOAP request compatible XML.
- #
- # { :find_user => { :id => 123, "wsdl:Key" => "api" } }.to_soap_xml
- # # => "123api"
- #
- # ==== Mapping
- #
- # * Hash keys specified as Symbols are converted to lowerCamelCase Strings
- # * Hash keys specified as Strings are not converted and may contain namespaces
- # * DateTime values are converted to xs:dateTime Strings
- # * Objects responding to to_datetime (except Strings) are converted to xs:dateTime Strings
- # * TrueClass and FalseClass objects are converted to "true" and "false" Strings
- # * All other objects are expected to be converted to Strings using to_s
- #
- # An example:
- #
- # { :magic_request => {
- # :perform_move => true,
- # "perform_at" => DateTime.new(2010, 11, 22, 11, 22, 33)
- # }
- # }.to_soap_xml
- #
- #
- # true
- # 2012-06-11T10:42:21
- #
- #
- # ==== Escaped XML values
- #
- # By default, special characters in XML String values are escaped.
- #
- # ==== Fixed order of XML tags
- #
- # In case your service requires the tags to be in a specific order (parameterOrder), you have two
- # options. The first is to specify your body as an XML string. The second is to specify the order
- # through an additional array stored under the +:order!+ key.
- #
- # { :name => "Eve", :id => 123, :order! => [:id, :name] }.to_soap_xml
- # # => "123Eve"
- #
- # ==== XML attributes
- #
- # If you need attributes, you could either go with an XML string or add another hash under the
- # +:attributes!+ key.
- #
- # { :person => "Eve", :attributes! => { :person => { :id => 666 } } }.to_soap_xml
- # # => 'Eve'
- def to_soap_xml
- xml = Builder::XmlMarkup.new
- attributes = delete(:attributes!) || {}
-
- order.each do |key|
- attrs = attributes[key] || {}
- value = self[key]
- escape_xml = key.to_s[-1, 1] != "!"
- key = key.to_soap_key
-
- case value
- when ::Array then xml << value.to_soap_xml(key, escape_xml, attrs)
- when ::Hash then xml.tag!(key, attrs) { xml << value.to_soap_xml }
- when NilClass then xml.tag!(key, "xsi:nil" => "true")
- else xml.tag!(key, attrs) { xml << (escape_xml ? value.to_soap_value : value.to_soap_value!) }
- end
- end
-
- xml.target!
- end
-
# Maps keys and values of a Hash created from SOAP response XML to more convenient Ruby Objects.
def map_soap_response
inject({}) do |hash, (key, value)|
@@ -112,22 +41,6 @@ def map_soap_response
end
end
- private
-
- # Deletes and returns an Array of keys stored under the :order! key. Defaults to return the actual
- # keys of this Hash if no :order! key could be found. Raises an ArgumentError in case the :order!
- # Array does not match the Hash keys.
- def order
- order = delete :order!
- order = keys unless order.kind_of? ::Array
-
- missing, spurious = keys - order, order - keys
- raise ArgumentError, "Missing elements in :order! #{missing.inspect}" unless missing.empty?
- raise ArgumentError, "Spurious elements in :order! #{spurious.inspect}" unless spurious.empty?
-
- order
- end
-
end
end
end
diff --git a/lib/savon/core_ext/object.rb b/lib/savon/core_ext/object.rb
index 48e792d9..d8b60ddd 100644
--- a/lib/savon/core_ext/object.rb
+++ b/lib/savon/core_ext/object.rb
@@ -1,5 +1,3 @@
-require "savon/core_ext/datetime"
-
module Savon
module CoreExt
module Object
@@ -9,14 +7,6 @@ def blank?
respond_to?(:empty?) ? empty? : !self
end unless defined? blank?
- # Returns the Object as a SOAP request compliant value.
- def to_soap_value
- return to_s unless respond_to? :to_datetime
- to_datetime.to_soap_value
- end
-
- alias_method :to_soap_value!, :to_soap_value
-
end
end
end
diff --git a/lib/savon/core_ext/string.rb b/lib/savon/core_ext/string.rb
index b8b5b9c8..2fbe0775 100644
--- a/lib/savon/core_ext/string.rb
+++ b/lib/savon/core_ext/string.rb
@@ -1,5 +1,3 @@
-require "cgi"
-
require "savon/soap"
module Savon
@@ -52,21 +50,6 @@ def map_soap_response
self
end
- # Returns the Object as a SOAP request compliant key.
- def to_soap_key
- self[-1, 1] == "!" ? chop : self
- end
-
- # Returns the String as a SOAP value. Escapes special characters for XML.
- def to_soap_value
- CGI.escapeHTML self
- end
-
- # Convert the String into a SOAP value without escaping special characters.
- def to_soap_value!
- self
- end
-
end
end
end
diff --git a/lib/savon/core_ext/symbol.rb b/lib/savon/core_ext/symbol.rb
deleted file mode 100644
index 72692b24..00000000
--- a/lib/savon/core_ext/symbol.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require "savon/core_ext/string"
-
-module Savon
- module CoreExt
- module Symbol
-
- # Returns the Symbol as a lowerCamelCase String.
- def to_soap_key
- to_s.to_soap_key.lower_camelcase
- end
-
- end
- end
-end
-
-Symbol.send :include, Savon::CoreExt::Symbol
diff --git a/lib/savon/soap/xml.rb b/lib/savon/soap/xml.rb
index 81247a7b..8b0c3f83 100644
--- a/lib/savon/soap/xml.rb
+++ b/lib/savon/soap/xml.rb
@@ -87,7 +87,7 @@ def namespace_identifier
# Accessor for the Savon::WSSE object.
attr_accessor :wsse
- # Accessor for the SOAP +body+. Expected to be a Hash that can be translated to XML via Hash.to_soap_xml
+ # Accessor for the SOAP +body+. Expected to be a Hash that can be translated to XML via Gyoku.xml
# or any other Object responding to to_s.
attr_accessor :body
@@ -132,7 +132,7 @@ def complete_namespaces
# Returns the SOAP header as an XML String.
def header_for_xml
- @header_for_xml ||= header.to_soap_xml + wsse_header
+ @header_for_xml ||= Gyoku.xml(header) + wsse_header
end
# Returns the WSSE header or an empty String in case WSSE was not set.
@@ -142,7 +142,7 @@ def wsse_header
# Returns the SOAP body as an XML String.
def body_to_xml
- body.respond_to?(:to_soap_xml) ? body.to_soap_xml : body.to_s
+ body.kind_of?(Hash) ? Gyoku.xml(body) : body.to_s
end
end
diff --git a/savon.gemspec b/savon.gemspec
index 82a42513..21315cfe 100644
--- a/savon.gemspec
+++ b/savon.gemspec
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
s.add_dependency "builder", "~> 2.1.2"
s.add_dependency "crack", "~> 0.1.8"
s.add_dependency "httpi", ">= 0.7.1"
+ s.add_dependency "gyoku", ">= 0.1.0"
s.add_development_dependency "rspec", "~> 2.0.0"
s.add_development_dependency "mocha", "~> 0.9.7"
diff --git a/spec/savon/core_ext/array_spec.rb b/spec/savon/core_ext/array_spec.rb
deleted file mode 100644
index c5255f1c..00000000
--- a/spec/savon/core_ext/array_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-require "spec_helper"
-
-describe Array do
-
- describe "to_soap_xml" do
- it "should return the XML for an Array of Hashes" do
- array = [{ :name => "adam" }, { :name => "eve" }]
- result = "adameve"
-
- array.to_soap_xml("user").should == result
- end
-
- it "should return the XML for an Array of different Objects" do
- array = [:symbol, "string", 123]
- result = "symbolstring123"
-
- array.to_soap_xml("value").should == result
- end
-
- it "should default to escape special characters" do
- array = ["", "adam & eve"]
- result = "<tag />adam & eve"
-
- array.to_soap_xml("value").should == result
- end
-
- it "should not escape special characters when told to" do
- array = ["", "adam & eve"]
- result = "adam & eve"
-
- array.to_soap_xml("value", false).should == result
- end
-
- it "should add attributes to a given tag" do
- array = ["adam", "eve"]
- result = 'adameve'
-
- array.to_soap_xml("value", :escape_xml, :active => true).should == result
- end
-
- it "should add attributes to duplicate tags" do
- array = ["adam", "eve"]
- result = 'adameve'
-
- array.to_soap_xml("value", :escape_xml, :id => [1, 2]).should == result
- end
- end
-
-end
\ No newline at end of file
diff --git a/spec/savon/core_ext/datetime_spec.rb b/spec/savon/core_ext/datetime_spec.rb
deleted file mode 100644
index f8c3d830..00000000
--- a/spec/savon/core_ext/datetime_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require "spec_helper"
-
-describe DateTime do
- before do
- @datetime = DateTime.new 2012, 03, 22, 16, 22, 33
- @datetime_string = "2012-03-22T16:22:33+00:00"
- end
-
- describe "to_soap_value" do
- it "should return an xs:dateTime compliant String" do
- @datetime.to_soap_value.should == @datetime_string
- end
- end
-
- describe "to_soap_value!" do
- it "should act like :to_soap_value" do
- @datetime.to_soap_value.should == @datetime_string
- end
- end
-
-end
diff --git a/spec/savon/core_ext/hash_spec.rb b/spec/savon/core_ext/hash_spec.rb
index d120bc6a..5dd9e49b 100644
--- a/spec/savon/core_ext/hash_spec.rb
+++ b/spec/savon/core_ext/hash_spec.rb
@@ -14,132 +14,6 @@
end
end
- describe "to_soap_xml" do
- describe "should return SOAP request compatible XML" do
- it "for a simple Hash" do
- hash, result = { :some => "user" }, "user"
- hash.to_soap_xml.should == result
- end
-
- it "for a nested Hash" do
- hash, result = { :some => { :new => "user" } }, "user"
- hash.to_soap_xml.should == result
- end
-
- it "for a Hash with multiple keys" do
- hash = { :all => "users", :before => "whatever" }
- hash.to_soap_xml.should include("users", "whatever")
- end
-
- it "for a Hash containing an Array" do
- hash, result = { :some => ["user", "gorilla"] }, "usergorilla"
- hash.to_soap_xml.should == result
- end
-
- it "for a Hash containing an Array of Hashes" do
- hash = { :some => [{ :new => "user" }, { :old => "gorilla" }] }
- result = "usergorilla"
-
- hash.to_soap_xml.should == result
- end
- end
-
- it "should convert Hash key Symbols to lowerCamelCase" do
- hash, result = { :find_or_create => "user" }, "user"
- hash.to_soap_xml.should == result
- end
-
- it "should not convert Hash key Strings" do
- hash, result = { "find_or_create" => "user" }, "user"
- hash.to_soap_xml.should == result
- end
-
- it "should convert DateTime objects to xs:dateTime compliant Strings" do
- hash = { :before => DateTime.new(2012, 03, 22, 16, 22, 33) }
- result = "2012-03-22T16:22:33+00:00"
-
- hash.to_soap_xml.should == result
- end
-
- it "should convert Objects responding to to_datetime to xs:dateTime compliant Strings" do
- singleton = Object.new
- def singleton.to_datetime
- DateTime.new(2012, 03, 22, 16, 22, 33)
- end
-
- hash, result = { :before => singleton }, "2012-03-22T16:22:33+00:00"
- hash.to_soap_xml.should == result
- end
-
- it "should call to_s on Strings even if they respond to to_datetime" do
- object = "gorilla"
- object.expects(:to_datetime).never
-
- hash, result = { :name => object }, "gorilla"
- hash.to_soap_xml.should == result
- end
-
- it "should properly serialize nil values" do
- { :some => nil }.to_soap_xml.should == ''
- end
-
- it "should call to_s on any other Object" do
- [666, true, false].each do |object|
- { :some => object }.to_soap_xml.should == "#{object}"
- end
- end
-
- it "should default to escape special characters" do
- result = { :some => { :nested => "" }, :tag => "" }.to_soap_xml
- result.should include("<tag />")
- result.should include("<tag />")
- end
-
- it "should not escape special characters for keys marked with an exclamation mark" do
- result = { :some => { :nested! => "" }, :tag! => "" }.to_soap_xml
- result.should include("")
- result.should include("")
- end
-
- it "should preserve the order of Hash keys and values specified through :order!" do
- hash = { :find_user => { :name => "Lucy", :id => 666, :order! => [:id, :name] } }
- result = "666Lucy"
- hash.to_soap_xml.should == result
-
- hash = { :find_user => { :mname => "in the", :lname => "Sky", :fname => "Lucy", :order! => [:fname, :mname, :lname] } }
- result = "Lucyin theSky"
- hash.to_soap_xml.should == result
- end
-
- it "should raise an error if the :order! Array does not match the Hash keys" do
- hash = { :name => "Lucy", :id => 666, :order! => [:name] }
- lambda { hash.to_soap_xml }.should raise_error(ArgumentError)
-
- hash = { :by_name => { :name => "Lucy", :lname => "Sky", :order! => [:mname, :name] } }
- lambda { hash.to_soap_xml }.should raise_error(ArgumentError)
- end
-
- it "should add attributes to Hash keys specified through :attributes!" do
- hash = { :find_user => { :person => "Lucy", :attributes! => { :person => { :id => 666 } } } }
- result = 'Lucy'
- hash.to_soap_xml.should == result
-
- hash = { :find_user => { :person => "Lucy", :attributes! => { :person => { :id => 666, :city => "Hamburg" } } } }
- soap_xml = hash.to_soap_xml
- soap_xml.should include('id="666"', 'city="Hamburg"')
- end
-
- it "should add attributes to duplicate Hash keys specified through :attributes!" do
- hash = { :find_user => { :person => ["Lucy", "Anna"], :attributes! => { :person => { :id => [1, 3] } } } }
- result = 'LucyAnna'
- hash.to_soap_xml.should == result
-
- hash = { :find_user => { :person => ["Lucy", "Anna"], :attributes! => { :person => { :active => "true" } } } }
- result = 'LucyAnna'
- hash.to_soap_xml.should == result
- end
- end
-
describe "map_soap_response" do
it "should convert Hash key Strings to snake_case Symbols" do
soap_response = { "userResponse" => { "accountStatus" => "active" } }
diff --git a/spec/savon/core_ext/object_spec.rb b/spec/savon/core_ext/object_spec.rb
index 6a3d7e42..d982a9fb 100644
--- a/spec/savon/core_ext/object_spec.rb
+++ b/spec/savon/core_ext/object_spec.rb
@@ -16,19 +16,4 @@
end
end
- describe "to_soap_value" do
- it "returns an xs:dateTime compliant String for Objects responding to to_datetime" do
- singleton = Object.new
- def singleton.to_datetime
- DateTime.new(2012, 03, 22, 16, 22, 33)
- end
-
- singleton.to_soap_value.should == "2012-03-22T16:22:33+00:00"
- end
-
- it "calls to_s unless the Object responds to to_datetime" do
- "value".to_soap_value.should == "value".to_s
- end
- end
-
end
diff --git a/spec/savon/core_ext/string_spec.rb b/spec/savon/core_ext/string_spec.rb
index d00388e0..0958838a 100644
--- a/spec/savon/core_ext/string_spec.rb
+++ b/spec/savon/core_ext/string_spec.rb
@@ -62,26 +62,4 @@
end
end
- describe "to_soap_key" do
- it "removes exclamation marks from the end of the String" do
- "value".to_soap_key.should == "value"
- "value!".to_soap_key.should == "value"
- end
- end
-
- describe "to_soap_value" do
- it "should return the String value and escape special characters" do
- "string".to_soap_value.should == "string"
- "".to_soap_value.should == "<tag>"
- "at&t".to_soap_value.should == "at&t"
- '"quotes"'.to_soap_value.should == ""quotes""
- end
- end
-
- describe "to_soap_value!" do
- it "should just return the String value without escaping special characters" do
- "".to_soap_value!.should == ""
- end
- end
-
end
diff --git a/spec/savon/core_ext/symbol_spec.rb b/spec/savon/core_ext/symbol_spec.rb
deleted file mode 100644
index 4d1859ec..00000000
--- a/spec/savon/core_ext/symbol_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require "spec_helper"
-
-describe Symbol do
-
- describe "to_soap_key" do
- it "converts the Symbol from snake_case to a lowerCamelCase String" do
- :lower_camel_case.to_soap_key.should == "lowerCamelCase"
- :lower_camel_case!.to_soap_key.should == "lowerCamelCase"
- end
- end
-
-end