Skip to content

Commit

Permalink
Multiple fixes for qualified message munger. (#676)
Browse files Browse the repository at this point in the history
* Fixes handling of content! and attributes!
* General cleanup.
  • Loading branch information
jmcnevin authored and pcai committed Aug 2, 2017
1 parent a638a16 commit fbe0d13
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 33 deletions.
57 changes: 29 additions & 28 deletions lib/savon/qualified_message.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,50 @@

module Savon
class QualifiedMessage

def initialize(types, used_namespaces, key_converter)
@types = types
@types = types
@used_namespaces = used_namespaces
@key_converter = key_converter
@key_converter = key_converter
end

def to_hash(hash, path)
return hash unless hash
return hash.map { |value| to_hash(value, path) } if hash.kind_of?(Array)
return hash.to_s unless hash.kind_of? Hash

hash.inject({}) do |newhash, (key, value)|
if key == :order!
add_namespaces_to_values(value, path)
newhash.merge(key => value)
return unless hash

This comment has been minimized.

Copy link
@swatosh

swatosh Aug 23, 2017

It seems like the first line changed here could be the cause of #826. It seems like it might inadvertently change a false to a nil. WDYT?

return hash.map { |value| to_hash(value, path) } if hash.is_a?(Array)
return hash.to_s unless hash.is_a?(Hash)

hash.each_with_object({}) do |(key, value), newhash|
case key
when :order!
newhash[key] = add_namespaces_to_values(value, path)
when :attributes!, :content!
newhash[key] = to_hash(value, path)
else
translated_key = Gyoku.xml_tag(key, :key_converter => @key_converter).to_s
translated_key << "!" if key[-1] == "!"
newpath = path + [translated_key]

if @used_namespaces[newpath]
newhash.merge(
"#{@used_namespaces[newpath]}:#{translated_key}" =>
to_hash(value, @types[newpath] ? [@types[newpath]] : newpath)
)
if key.to_s =~ /!$/
newhash[key] = value
else
newhash.merge(translated_key => value)
translated_key = translate_tag(key)
newkey = add_namespaces_to_values(key, path).first
newpath = path + [translated_key]
newhash[newkey] = to_hash(value, newpath)

This comment has been minimized.

Copy link
@fphilipe

fphilipe Sep 21, 2017

This is the cause of #830. It should still have the ternary operator to change the path, i.e. it should say:

to_hash(value, @types[newpath] ? [@types[newpath]] : newpath)

This comment has been minimized.

Copy link
@aledustet

aledustet Nov 10, 2017

👍 to that

end
end
newhash
end
end

private

def add_namespaces_to_values(values, path)
values.collect! { |value|
camelcased_value = Gyoku.xml_tag(value, :key_converter => @key_converter)
namespace_path = path + [camelcased_value.to_s]
namespace = @used_namespaces[namespace_path]
"#{namespace.blank? ? '' : namespace + ":"}#{camelcased_value}"
}
def translate_tag(key)
Gyoku.xml_tag(key, :key_converter => @key_converter).to_s
end

def add_namespaces_to_values(values, path)
Array(values).collect do |value|
translated_value = translate_tag(value)
namespace_path = path + [translated_value]
namespace = @used_namespaces[namespace_path]
namespace.blank? ? value : "#{namespace}:#{translated_value}"
end
end
end
end
58 changes: 53 additions & 5 deletions spec/savon/qualified_message_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,63 @@ module Savon
describe QualifiedMessage, "#to_hash" do

context "if a key ends with !" do
it "restores the ! in a key" do
used_namespaces = {}
key_converter = :camelcase
types = {}
let(:used_namespaces) { {} }
let(:key_converter) { :camelcase }
let(:types) { {} }

it "restores the ! in a key" do
message = described_class.new(types, used_namespaces, key_converter)
resulting_hash = message.to_hash({:Metal! => "<Nice/>"}, ["Rock"])

expect(resulting_hash).to eq({"Metal!" => "<Nice/>"})
expect(resulting_hash).to eq({ :Metal! => "<Nice/>" })
end

it "properly handles special keys when namespaces are present" do
used_namespaces = {
%w(tns Foo) => 'ns',
%w(tns Foo Bar) => 'ns'
}

hash = {
:foo => {
:bar => {
:zing => 'pow'
},
:cash => {
:@attr1 => 'val1',
:content! => 'Chunky Bacon'
},
:attributes! => {
:bar => { :attr2 => 'val2' },
},
:"self_closing/" => '',
:order! => [:cash, :bar, :"self_closing/"]
}
}

good_result = {
"ns:Foo" => {
'ns:Bar' => { :zing => "pow" },
:cash => {
:@attr1 => "val1",
:content! => "Chunky Bacon"
},
:attributes! => {
'ns:Bar' => { :attr2 => 'val2' }
},
:"self_closing/" => '',
:order! => [:cash, 'ns:Bar', :"self_closing/"]
}
}

good_xml = %(<ns:Foo><Cash attr1="val1">Chunky Bacon</Cash><ns:Bar attr2="val2"><Zing>pow</Zing></ns:Bar><SelfClosing/></ns:Foo>)

message = described_class.new(types, used_namespaces, key_converter)
resulting_hash = message.to_hash(hash, ['tns'])
xml = Gyoku.xml(resulting_hash, key_converter: key_converter)

expect(resulting_hash).to eq good_result
expect(xml).to eq good_xml
end
end

Expand Down

0 comments on commit fbe0d13

Please sign in to comment.