multi_xml 0.5.5 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: add5ff8df4d736d143b1d83c38c5f1b8b35d21cd
4
+ data.tar.gz: ec8e8a3657ff340a9a4abefa2561e44dfee8371d
5
+ SHA512:
6
+ metadata.gz: 1cb437e88276aa09e33c5b10a1e32bbf181ecae9543976ab13acc4ca458b00b1315a59f1e3e1cd95fd24e47559a85058585578ba16441ac83c98ffa81c5ee902
7
+ data.tar.gz: 1931768faabe059174c01e24d12f9b1c8bcc0c9717891ec9ba9098f55c98535ad2a0efab7dcc4bfd756a569f137bf86e4b45b652a182652e6a468393103de9f5
@@ -16,8 +16,10 @@ Here are some ways *you* can contribute:
16
16
  * by refactoring code
17
17
  * by resolving [issues][]
18
18
  * by reviewing patches
19
+ * [financially][gittip]
19
20
 
20
21
  [issues]: https://github.com/sferik/multi_xml/issues
22
+ [gittip]: https://www.gittip.com/sferik/
21
23
 
22
24
  ## Submitting an Issue
23
25
  We use the [GitHub issue tracker][issues] to track bugs and features. Before
@@ -35,12 +37,12 @@ Ideally, a bug report should include a pull request with failing specs.
35
37
  3. Add specs for your unimplemented feature or bug fix.
36
38
  4. Run `bundle exec rake spec`. If your specs pass, return to step 3.
37
39
  5. Implement your feature or bug fix.
38
- 6. Run `bundle exec rake spec`. If your specs fail, return to step 5.
40
+ 6. Run `bundle exec rake`. If your specs fail, return to step 5.
39
41
  7. Run `open coverage/index.html`. If your changes are not completely covered
40
42
  by your tests, return to step 3.
41
43
  8. Add documentation for your feature or bug fix.
42
- 9. Run `bundle exec rake doc:yard`. If your changes are not 100% documented, go
43
- back to step 8.
44
+ 9. Run `bundle exec rake verify_measurements`. If your changes are not 100%
45
+ documented, go back to step 8.
44
46
  10. Add, commit, and push your changes.
45
47
  11. [Submit a pull request.][pr]
46
48
 
data/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # MultiXML
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/multi_xml.png)][gem]
4
- [![Build Status](https://secure.travis-ci.org/sferik/multi_xml.png?branch=master)][travis]
5
- [![Dependency Status](https://gemnasium.com/sferik/multi_xml.png?travis)][gemnasium]
6
- [![Code Climate](https://codeclimate.com/github/sferik/multi_xml.png)][codeclimate]
7
- [![Coverage Status](https://coveralls.io/repos/sferik/multi_xml/badge.png?branch=master)][coveralls]
3
+ [![Gem Version](http://img.shields.io/gem/v/multi_xml.svg)][gem]
4
+ [![Build Status](http://img.shields.io/travis/sferik/multi_xml.svg)][travis]
5
+ [![Dependency Status](http://img.shields.io/gemnasium/sferik/multi_xml.svg)][gemnasium]
6
+ [![Code Climate](http://img.shields.io/codeclimate/github/sferik/multi_xml.svg)][codeclimate]
7
+ [![Coverage Status](http://img.shields.io/coveralls/sferik/multi_xml.svg)][coveralls]
8
8
 
9
9
  [gem]: https://rubygems.org/gems/multi_xml
10
10
  [travis]: http://travis-ci.org/sferik/multi_xml
@@ -17,16 +17,6 @@ A generic swappable back-end for XML parsing
17
17
  ## Installation
18
18
  gem install multi_xml
19
19
 
20
- To ensure the code you're installing hasn't been tampered with, it's
21
- recommended that you verify the signature. To do this, you need to add my
22
- public key as a trusted certificate (you only need to do this once):
23
-
24
- gem cert --add <(curl -Ls https://raw.github.com/sferik/multi_xml/master/certs/sferik.pem)
25
-
26
- Then, install the gem with the high security trust policy:
27
-
28
- gem install multi_xml -P HighSecurity
29
-
30
20
  ## Documentation
31
21
  [http://rdoc.info/gems/multi_xml][documentation]
32
22
 
@@ -55,6 +45,10 @@ MultiXml.parse('<tag>This is the contents</tag>') # Parsed using Nokogiri
55
45
  MultiXml.parser = :rexml
56
46
  MultiXml.parser = MultiXml::Parsers::Rexml # Same as above
57
47
  MultiXml.parse('<tag>This is the contents</tag>') # Parsed using REXML
48
+
49
+ MultiXml.parser = :oga
50
+ MultiXml.parser = MultiXml::Parsers::Oga # Same as above
51
+ MultiXml.parse('<tag>This is the contents</tag>') # Parsed using Oga
58
52
  ```
59
53
  The `parser` setter takes either a symbol or a class (to allow for custom XML
60
54
  parsers) that responds to `.parse` at the class level.
@@ -68,10 +62,14 @@ then Nokogiri, and finally REXML.
68
62
  This library aims to support and is [tested against][travis] the following Ruby
69
63
  implementations:
70
64
 
71
- * Ruby 1.8.7
72
- * Ruby 1.9.2
73
65
  * Ruby 1.9.3
74
66
  * Ruby 2.0.0
67
+ * Ruby 2.1
68
+ * Ruby 2.2
69
+ * Ruby 2.3
70
+ * [JRuby 9000][jruby]
71
+
72
+ [jruby]: http://jruby.org/
75
73
 
76
74
  If something doesn't work on one of these interpreters, it's a bug.
77
75
 
@@ -5,73 +5,78 @@ require 'stringio'
5
5
  require 'time'
6
6
  require 'yaml'
7
7
 
8
- module MultiXml
8
+ module MultiXml # rubocop:disable ModuleLength
9
9
  class ParseError < StandardError; end
10
+ class NoParserError < StandardError; end
10
11
  class DisallowedTypeError < StandardError
11
12
  def initialize(type)
12
13
  super "Disallowed type attribute: #{type.inspect}"
13
14
  end
14
15
  end
15
16
 
16
- REQUIREMENT_MAP = [
17
- ['ox', :ox],
18
- ['libxml', :libxml],
19
- ['nokogiri', :nokogiri],
20
- ['rexml/document', :rexml]
21
- ] unless defined?(REQUIREMENT_MAP)
17
+ unless defined?(REQUIREMENT_MAP)
18
+ REQUIREMENT_MAP = [
19
+ ['ox', :ox],
20
+ ['libxml', :libxml],
21
+ ['nokogiri', :nokogiri],
22
+ ['rexml/document', :rexml],
23
+ ['oga', :oga],
24
+ ].freeze
25
+ end
22
26
 
23
27
  CONTENT_ROOT = '__content__'.freeze unless defined?(CONTENT_ROOT)
24
28
 
25
29
  unless defined?(PARSING)
30
+ float_proc = proc { |float| float.to_f }
31
+ datetime_proc = proc { |time| Time.parse(time).utc rescue DateTime.parse(time).utc } # rubocop:disable RescueModifier
32
+
26
33
  PARSING = {
27
- 'symbol' => Proc.new{|symbol| symbol.to_sym},
28
- 'date' => Proc.new{|date| Date.parse(date)},
29
- 'datetime' => Proc.new{|time| Time.parse(time).utc rescue DateTime.parse(time).utc},
30
- 'integer' => Proc.new{|integer| integer.to_i},
31
- 'float' => Proc.new{|float| float.to_f},
32
- 'decimal' => Proc.new{|number| BigDecimal(number)},
33
- 'boolean' => Proc.new{|boolean| !%w(0 false).include?(boolean.strip)},
34
- 'string' => Proc.new{|string| string.to_s},
35
- 'yaml' => Proc.new{|yaml| YAML::load(yaml) rescue yaml},
36
- 'base64Binary' => Proc.new{|binary| ::Base64.decode64(binary)},
37
- 'binary' => Proc.new{|binary, entity| parse_binary(binary, entity)},
38
- 'file' => Proc.new{|file, entity| parse_file(file, entity)},
39
- }
40
-
41
- PARSING.update(
42
- 'double' => PARSING['float'],
43
- 'dateTime' => PARSING['datetime']
44
- )
34
+ 'symbol' => proc { |symbol| symbol.to_sym },
35
+ 'date' => proc { |date| Date.parse(date) },
36
+ 'datetime' => datetime_proc,
37
+ 'dateTime' => datetime_proc,
38
+ 'integer' => proc { |integer| integer.to_i },
39
+ 'float' => float_proc,
40
+ 'double' => float_proc,
41
+ 'decimal' => proc { |number| BigDecimal(number) },
42
+ 'boolean' => proc { |boolean| !%w(0 false).include?(boolean.strip) },
43
+ 'string' => proc { |string| string.to_s },
44
+ 'yaml' => proc { |yaml| YAML.load(yaml) rescue yaml }, # rubocop:disable RescueModifier
45
+ 'base64Binary' => proc { |binary| ::Base64.decode64(binary) },
46
+ 'binary' => proc { |binary, entity| parse_binary(binary, entity) },
47
+ 'file' => proc { |file, entity| parse_file(file, entity) },
48
+ }.freeze
49
+ end
50
+
51
+ unless defined?(TYPE_NAMES)
52
+ TYPE_NAMES = {
53
+ 'Symbol' => 'symbol',
54
+ 'Integer' => 'integer',
55
+ 'BigDecimal' => 'decimal',
56
+ 'Float' => 'float',
57
+ 'TrueClass' => 'boolean',
58
+ 'FalseClass' => 'boolean',
59
+ 'Date' => 'date',
60
+ 'DateTime' => 'datetime',
61
+ 'Time' => 'datetime',
62
+ 'Array' => 'array',
63
+ 'Hash' => 'hash',
64
+ }.freeze
45
65
  end
46
66
 
47
- TYPE_NAMES = {
48
- 'Symbol' => 'symbol',
49
- 'Fixnum' => 'integer',
50
- 'Bignum' => 'integer',
51
- 'BigDecimal' => 'decimal',
52
- 'Float' => 'float',
53
- 'TrueClass' => 'boolean',
54
- 'FalseClass' => 'boolean',
55
- 'Date' => 'date',
56
- 'DateTime' => 'datetime',
57
- 'Time' => 'datetime',
58
- 'Array' => 'array',
59
- 'Hash' => 'hash'
60
- } unless defined?(TYPE_NAMES)
61
-
62
- DISALLOWED_XML_TYPES = %w(symbol yaml)
67
+ DISALLOWED_XML_TYPES = %w(symbol yaml).freeze
63
68
 
64
69
  DEFAULT_OPTIONS = {
65
70
  :typecast_xml_value => true,
66
71
  :disallowed_types => DISALLOWED_XML_TYPES,
67
- :symbolize_keys => false
68
- }
72
+ :symbolize_keys => false,
73
+ }.freeze
69
74
 
70
75
  class << self
71
76
  # Get the current parser class.
72
77
  def parser
73
78
  return @parser if defined?(@parser)
74
- self.parser = self.default_parser
79
+ self.parser = default_parser
75
80
  @parser
76
81
  end
77
82
 
@@ -83,6 +88,7 @@ module MultiXml
83
88
  return :ox if defined?(::Ox)
84
89
  return :libxml if defined?(::LibXML)
85
90
  return :nokogiri if defined?(::Nokogiri)
91
+ return :oga if defined?(::Oga)
86
92
 
87
93
  REQUIREMENT_MAP.each do |library, parser|
88
94
  begin
@@ -92,6 +98,7 @@ module MultiXml
92
98
  next
93
99
  end
94
100
  end
101
+ raise(NoParserError.new("No XML parser detected. If you're using Rubinius and Bundler, try adding an XML parser to your Gemfile (e.g. libxml-ruby, nokogiri, or rubysl-rexml). For more information, see https://github.com/sferik/multi_xml/issues/42."))
95
102
  end
96
103
 
97
104
  # Set the XML parser utilizing a symbol, string, or class.
@@ -101,15 +108,16 @@ module MultiXml
101
108
  # * <tt>:nokogiri</tt>
102
109
  # * <tt>:ox</tt>
103
110
  # * <tt>:rexml</tt>
111
+ # * <tt>:oga</tt>
104
112
  def parser=(new_parser)
105
113
  case new_parser
106
114
  when String, Symbol
107
115
  require "multi_xml/parsers/#{new_parser.to_s.downcase}"
108
- @parser = MultiXml::Parsers.const_get("#{new_parser.to_s.split('_').map{|s| s.capitalize}.join('')}")
116
+ @parser = MultiXml::Parsers.const_get(new_parser.to_s.split('_').collect(&:capitalize).join('').to_s)
109
117
  when Class, Module
110
118
  @parser = new_parser
111
119
  else
112
- raise "Did not recognize your parser specification. Please specify either a symbol or a class."
120
+ raise('Did not recognize your parser specification. Please specify either a symbol or a class.')
113
121
  end
114
122
  end
115
123
 
@@ -122,12 +130,12 @@ module MultiXml
122
130
  # <tt>:disallowed_types</tt> :: Types to disallow from being typecasted. Defaults to `['yaml', 'symbol']`. Use `[]` to allow all types.
123
131
  #
124
132
  # <tt>:typecast_xml_value</tt> :: If true, won't typecast values for parsed document
125
- def parse(xml, options={})
133
+ def parse(xml, options = {}) # rubocop:disable AbcSize, CyclomaticComplexity, MethodLength, PerceivedComplexity
126
134
  xml ||= ''
127
135
 
128
136
  options = DEFAULT_OPTIONS.merge(options)
129
137
 
130
- xml.strip! if xml.respond_to?(:strip!)
138
+ xml = xml.strip if xml.respond_to?(:strip)
131
139
  begin
132
140
  xml = StringIO.new(xml) unless xml.respond_to?(:read)
133
141
 
@@ -140,7 +148,7 @@ module MultiXml
140
148
  rescue DisallowedTypeError
141
149
  raise
142
150
  rescue parser.parse_error => error
143
- raise ParseError, error.message, error.backtrace
151
+ raise(ParseError, error.message, error.backtrace) # rubocop:disable RaiseArgs
144
152
  end
145
153
  hash = symbolize_keys(hash) if options[:symbolize_keys]
146
154
  hash
@@ -160,7 +168,7 @@ module MultiXml
160
168
  end
161
169
  end
162
170
 
163
- private
171
+ private
164
172
 
165
173
  # TODO: Add support for other encodings
166
174
  def parse_binary(binary, entity) #:nodoc:
@@ -187,7 +195,7 @@ module MultiXml
187
195
  result.merge(key.to_sym => symbolize_keys(value))
188
196
  end
189
197
  when Array
190
- params.map{|value| symbolize_keys(value)}
198
+ params.collect { |value| symbolize_keys(value) }
191
199
  else
192
200
  params
193
201
  end
@@ -197,23 +205,23 @@ module MultiXml
197
205
  case params
198
206
  when Hash
199
207
  params.inject({}) do |hash, (key, value)|
200
- hash[key.to_s.tr('-', '_')] = undasherize_keys(value)
208
+ hash[key.to_s.tr('-'.freeze, '_'.freeze)] = undasherize_keys(value)
201
209
  hash
202
210
  end
203
211
  when Array
204
- params.map{|value| undasherize_keys(value)}
212
+ params.collect { |value| undasherize_keys(value) }
205
213
  else
206
214
  params
207
215
  end
208
216
  end
209
217
 
210
- def typecast_xml_value(value, disallowed_types=nil)
218
+ def typecast_xml_value(value, disallowed_types = nil) # rubocop:disable AbcSize, CyclomaticComplexity, MethodLength, PerceivedComplexity
211
219
  disallowed_types ||= DISALLOWED_XML_TYPES
212
220
 
213
221
  case value
214
222
  when Hash
215
223
  if value.include?('type') && !value['type'].is_a?(Hash) && disallowed_types.include?(value['type'])
216
- raise DisallowedTypeError, value['type']
224
+ raise(DisallowedTypeError.new(value['type']))
217
225
  end
218
226
 
219
227
  if value['type'] == 'array'
@@ -227,27 +235,29 @@ module MultiXml
227
235
 
228
236
  # This attempt fails to consider the order that the detect method
229
237
  # retrieves the entries.
230
- #_, entries = value.detect {|key, _| key != 'type'}
238
+ # _, entries = value.detect {|key, _| key != 'type'}
231
239
 
232
240
  # This approach ignores attribute entries that are not convertable
233
241
  # to an Array which allows attributes to be ignored.
234
- _, entries = value.detect {|k, v| k != 'type' && (v.is_a?(Array) || v.is_a?(Hash)) }
242
+ _, entries = value.detect { |k, v| k != 'type' && (v.is_a?(Array) || v.is_a?(Hash)) }
235
243
 
236
- if entries.nil? || (entries.is_a?(String) && entries.strip.empty?)
244
+ case entries
245
+ when NilClass
237
246
  []
247
+ when String
248
+ [] if entries.strip.empty?
249
+ when Array
250
+ entries.collect { |entry| typecast_xml_value(entry, disallowed_types) }
251
+ when Hash
252
+ [typecast_xml_value(entries, disallowed_types)]
238
253
  else
239
- case entries
240
- when Array
241
- entries.map {|entry| typecast_xml_value(entry, disallowed_types)}
242
- when Hash
243
- [typecast_xml_value(entries, disallowed_types)]
244
- else
245
- raise "can't typecast #{entries.class.name}: #{entries.inspect}"
246
- end
254
+ raise("can't typecast #{entries.class.name}: #{entries.inspect}")
247
255
  end
248
- elsif value.has_key?(CONTENT_ROOT)
256
+
257
+ elsif value.key?(CONTENT_ROOT)
249
258
  content = value[CONTENT_ROOT]
250
- if block = PARSING[value['type']]
259
+ block = PARSING[value['type']]
260
+ if block
251
261
  if block.arity == 1
252
262
  value.delete('type') if PARSING[value['type']]
253
263
  if value.keys.size > 1
@@ -283,14 +293,13 @@ module MultiXml
283
293
  xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value
284
294
  end
285
295
  when Array
286
- value.map!{|i| typecast_xml_value(i, disallowed_types)}
296
+ value.map! { |i| typecast_xml_value(i, disallowed_types) }
287
297
  value.length > 1 ? value : value.first
288
298
  when String
289
299
  value
290
300
  else
291
- raise "can't typecast #{value.class.name}: #{value.inspect}"
301
+ raise("can't typecast #{value.class.name}: #{value.inspect}")
292
302
  end
293
303
  end
294
304
  end
295
-
296
305
  end
@@ -5,15 +5,18 @@ module MultiXml
5
5
  module Parsers
6
6
  module Libxml #:nodoc:
7
7
  include Libxml2Parser
8
-
9
8
  extend self
10
9
 
11
- def parse_error() ::LibXML::XML::Error end
10
+ def parse_error
11
+ ::LibXML::XML::Error
12
+ end
12
13
 
13
14
  def parse(xml)
14
15
  node_to_hash(LibXML::XML::Parser.io(xml).parse.root)
15
16
  end
16
17
 
18
+ private
19
+
17
20
  def each_child(node, &block)
18
21
  node.each_child(&block)
19
22
  end
@@ -8,16 +8,19 @@ module MultiXml
8
8
  #
9
9
  # hash::
10
10
  # Hash to merge the converted element into.
11
- def node_to_hash(node, hash={})
11
+ def node_to_hash(node, hash = {}) # rubocop:disable AbcSize, CyclomaticComplexity, MethodLength, PerceivedComplexity
12
12
  node_hash = {MultiXml::CONTENT_ROOT => ''}
13
13
 
14
14
  name = node_name(node)
15
15
 
16
16
  # Insert node hash into parent hash correctly.
17
17
  case hash[name]
18
- when Array then hash[name] << node_hash
19
- when Hash then hash[name] = [hash[name], node_hash]
20
- when nil then hash[name] = node_hash
18
+ when Array
19
+ hash[name] << node_hash
20
+ when Hash
21
+ hash[name] = [hash[name], node_hash]
22
+ when NilClass
23
+ hash[name] = node_hash
21
24
  end
22
25
 
23
26
  # Handle child elements
@@ -37,12 +40,8 @@ module MultiXml
37
40
  # Handle attributes
38
41
  each_attr(node) do |a|
39
42
  key = node_name(a)
40
-
41
- node_hash[key] = if v = node_hash[key]
42
- [a.value, v]
43
- else
44
- a.value
45
- end
43
+ v = node_hash[key]
44
+ node_hash[key] = (v ? [a.value, v] : a.value)
46
45
  end
47
46
 
48
47
  hash
@@ -51,23 +50,22 @@ module MultiXml
51
50
  # Parse an XML Document IO into a simple hash.
52
51
  # xml::
53
52
  # XML Document IO to parse
54
- def parse(xml)
55
- raise NotImplementedError, "inheritor should define #{__method__}"
53
+ def parse(_)
54
+ raise(NotImplementedError.new("inheritor should define #{__method__}"))
56
55
  end
57
56
 
58
- # :stopdoc:
59
- private
57
+ private
60
58
 
61
- def each_child(*args)
62
- raise NotImplementedError, "inheritor should define #{__method__}"
59
+ def each_child(*)
60
+ raise(NotImplementedError.new("inheritor should define #{__method__}"))
63
61
  end
64
62
 
65
- def each_attr(*args)
66
- raise NotImplementedError, "inheritor should define #{__method__}"
63
+ def each_attr(*)
64
+ raise(NotImplementedError.new("inheritor should define #{__method__}"))
67
65
  end
68
66
 
69
- def node_name(*args)
70
- raise NotImplementedError, "inheritor should define #{__method__}"
67
+ def node_name(*)
68
+ raise(NotImplementedError.new("inheritor should define #{__method__}"))
71
69
  end
72
70
  end
73
71
  end