Skip to content

Commit c94b136

Browse files
committed
Merge pull request #34 from nate/hotfix/remove-ability-to-parse-symbols-and-yaml
Remove ability to parse symbols and yaml
2 parents c760063 + 78ea359 commit c94b136

5 files changed

Lines changed: 68 additions & 17 deletions

File tree

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Ideally, a bug report should include a pull request with failing specs.
3939
7. Run `open coverage/index.html`. If your changes are not completely covered
4040
by your tests, return to step 3.
4141
8. Add documentation for your feature or bug fix.
42-
9. Run `bundle exec rake yard`. If your changes are not 100% documented, go
42+
9. Run `bundle exec rake doc:yard`. If your changes are not 100% documented, go
4343
back to step 8.
4444
10. Add, commit, and push your changes.
4545
11. [Submit a pull request.][pr]

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,20 @@ use it like so:
2020
```ruby
2121
require 'multi_xml'
2222

23-
MultiXml.parser = :ox MultiXml.parser = MultiXml::Parsers::Ox # Same as above
23+
MultiXml.parser = :ox
24+
MultiXml.parser = MultiXml::Parsers::Ox # Same as above
2425
MultiXml.parse('<tag>This is the contents</tag>') # Parsed using Ox
2526

26-
MultiXml.parser = :libxml MultiXml.parser = MultiXml::Parsers::Libxml # Same as above
27+
MultiXml.parser = :libxml
28+
MultiXml.parser = MultiXml::Parsers::Libxml # Same as above
2729
MultiXml.parse('<tag>This is the contents</tag>') # Parsed using LibXML
2830

29-
MultiXml.parser = :nokogiri MultiXml.parser = MultiXml::Parsers::Nokogiri # Same as above
31+
MultiXml.parser = :nokogiri
32+
MultiXml.parser = MultiXml::Parsers::Nokogiri # Same as above
3033
MultiXml.parse('<tag>This is the contents</tag>') # Parsed using Nokogiri
3134

32-
MultiXml.parser = :rexml MultiXml.parser = MultiXml::Parsers::Rexml # Same as above
35+
MultiXml.parser = :rexml
36+
MultiXml.parser = MultiXml::Parsers::Rexml # Same as above
3337
MultiXml.parse('<tag>This is the contents</tag>') # Parsed using REXML
3438
```
3539
The `parser` setter takes either a symbol or a class (to allow for custom XML

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ task :default => :spec
1010
namespace :doc do
1111
require 'yard'
1212
YARD::Rake::YardocTask.new do |task|
13-
task.files = ['LICENSE.md', 'lib/**/*.rb']
13+
task.files = ['lib/**/*.rb', '-', 'LICENSE.md']
1414
task.options = [
1515
'--no-private',
1616
'--protected',

lib/multi_xml.rb

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77

88
module MultiXml
99
class ParseError < StandardError; end
10+
class DisallowedTypeError < StandardError
11+
def initialize(type)
12+
super "Disallowed type attribute: #{type.inspect}"
13+
end
14+
end
1015

1116
REQUIREMENT_MAP = [
1217
['ox', :ox],
@@ -54,6 +59,8 @@ class ParseError < StandardError; end
5459
'Hash' => 'hash'
5560
} unless defined?(TYPE_NAMES)
5661

62+
DISALLOWED_XML_TYPES = %w(symbol yaml)
63+
5764
class << self
5865
# Get the current parser class.
5966
def parser
@@ -105,6 +112,8 @@ def parser=(new_parser)
105112
# <b>Options</b>
106113
#
107114
# <tt>:symbolize_keys</tt> :: If true, will use symbols instead of strings for the keys.
115+
#
116+
# <tt>:disallowed_types</tt> :: Types to disallow from being typecasted. Defaults to `['yaml', 'symbol']`. Use `[]` to allow all types.
108117
def parse(xml, options={})
109118
xml ||= ''
110119

@@ -116,7 +125,9 @@ def parse(xml, options={})
116125
return {} if char.nil?
117126
xml.ungetc(char)
118127

119-
hash = typecast_xml_value(undasherize_keys(parser.parse(xml))) || {}
128+
hash = typecast_xml_value(undasherize_keys(parser.parse(xml)), options[:disallowed_types]) || {}
129+
rescue DisallowedTypeError
130+
raise
120131
rescue parser.parse_error => error
121132
raise ParseError, error.to_s, error.backtrace
122133
end
@@ -191,9 +202,15 @@ def undasherize_keys(params)
191202
end
192203
end
193204

194-
def typecast_xml_value(value)
205+
def typecast_xml_value(value, disallowed_types=nil)
206+
disallowed_types ||= DISALLOWED_XML_TYPES
207+
195208
case value
196209
when Hash
210+
if value.include?('type') && !value['type'].is_a?(Hash) && disallowed_types.include?(value['type'])
211+
raise DisallowedTypeError, value['type']
212+
end
213+
197214
if value['type'] == 'array'
198215

199216
# this commented-out suggestion helps to avoid the multiple attribute
@@ -216,9 +233,9 @@ def typecast_xml_value(value)
216233
else
217234
case entries
218235
when Array
219-
entries.map {|entry| typecast_xml_value(entry)}
236+
entries.map {|entry| typecast_xml_value(entry, disallowed_types)}
220237
when Hash
221-
[typecast_xml_value(entries)]
238+
[typecast_xml_value(entries, disallowed_types)]
222239
else
223240
raise "can't typecast #{entries.class.name}: #{entries.inspect}"
224241
end
@@ -252,7 +269,7 @@ def typecast_xml_value(value)
252269
nil
253270
else
254271
xml_value = value.inject({}) do |hash, (k, v)|
255-
hash[k] = typecast_xml_value(v)
272+
hash[k] = typecast_xml_value(v, disallowed_types)
256273
hash
257274
end
258275

@@ -261,7 +278,7 @@ def typecast_xml_value(value)
261278
xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value
262279
end
263280
when Array
264-
value.map!{|i| typecast_xml_value(i)}
281+
value.map!{|i| typecast_xml_value(i, disallowed_types)}
265282
value.length > 1 ? value : value.first
266283
when String
267284
value

spec/parser_shared_example.rb

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -323,12 +323,26 @@
323323
@xml = "<tag type=\"yaml\">--- \n1: returns an integer\n:message: Have a nice day\narray: \n- has-dashes: true\n has_underscores: true\n</tag>"
324324
end
325325

326-
it "returns a Hash" do
327-
expect(MultiXml.parse(@xml)['tag']).to be_a(Hash)
326+
it "raises MultiXML::DisallowedTypeError by default" do
327+
expect{ MultiXml.parse(@xml)['tag'] }.to raise_error(MultiXml::DisallowedTypeError)
328328
end
329329

330-
it "returns the correctly parsed YAML" do
331-
expect(MultiXml.parse(@xml)['tag']).to eq({:message => "Have a nice day", 1 => "returns an integer", "array" => [{"has-dashes" => true, "has_underscores" => true}]})
330+
it "returns the correctly parsed YAML when the type is allowed" do
331+
expect(MultiXml.parse(@xml, :disallowed_types => [])['tag']).to eq({:message => "Have a nice day", 1 => "returns an integer", "array" => [{"has-dashes" => true, "has_underscores" => true}]})
332+
end
333+
end
334+
335+
context "with an attribute type=\"symbol\"" do
336+
before do
337+
@xml = "<tag type=\"symbol\">my_symbol</tag>"
338+
end
339+
340+
it "raises MultiXML::DisallowedTypeError" do
341+
expect{ MultiXml.parse(@xml)['tag'] }.to raise_error(MultiXml::DisallowedTypeError)
342+
end
343+
344+
it "returns the correctly parsed Symbol when the type is allowed" do
345+
expect(MultiXml.parse(@xml, :disallowed_types => [])['tag']).to eq(:my_symbol)
332346
end
333347
end
334348

@@ -418,7 +432,7 @@
418432
end
419433
end
420434

421-
%w(integer boolean date datetime yaml file).each do |type|
435+
%w(integer boolean date datetime file).each do |type|
422436
context "with an empty attribute type=\"#{type}\"" do
423437
before do
424438
@xml = "<tag type=\"#{type}\"/>"
@@ -430,6 +444,22 @@
430444
end
431445
end
432446

447+
%w{yaml symbol}.each do |type|
448+
context "with an empty attribute type=\"#{type}\"" do
449+
before do
450+
@xml = "<tag type=\"#{type}\"/>"
451+
end
452+
453+
it "raises MultiXml::DisallowedTypeError by default" do
454+
expect{ MultiXml.parse(@xml)['tag']}.to raise_error(MultiXml::DisallowedTypeError)
455+
end
456+
457+
it "returns nil when the type is allowed" do
458+
expect(MultiXml.parse(@xml, :disallowed_types => [])['tag']).to be_nil
459+
end
460+
end
461+
end
462+
433463
context "with an empty attribute type=\"array\"" do
434464
before do
435465
@xml = '<tag type="array"/>'

0 commit comments

Comments
 (0)