multi_xml 0.5.5 → 0.7.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7bebe7a08139024835279d7ffc78a7d86d0cb9a5ff59787068e044f7c75dc6f9
4
+ data.tar.gz: a2f579d2e18a266fe9573174de87ac960fcf867081705a2a6feb458bfa573225
5
+ SHA512:
6
+ metadata.gz: be4ffea0dd836f1d1d1baf73ffded7de5a79fdc53a5b039b5e7fd0a615a786ca08dc0a7bbf5561266cdade44a9cb3c2382fe6e35a54599876f77ec74ec937d42
7
+ data.tar.gz: d579ab46f0122a1011704e397062b5d9e648eeaae85a8baa30ac8eda7f3d1cdaa9e57fe1922e6e3e7ac608ef9607033c1547773dbb2eb1fe6785176a3471764d
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --order random
data/.rubocop.yml ADDED
@@ -0,0 +1,54 @@
1
+ require:
2
+ - rubocop-performance
3
+ - rubocop-rake
4
+ - rubocop-rspec
5
+ - standard
6
+ - standard-performance
7
+
8
+ AllCops:
9
+ NewCops: enable
10
+ TargetRubyVersion: 3.1
11
+
12
+ Layout/ArgumentAlignment:
13
+ EnforcedStyle: with_fixed_indentation
14
+ IndentationWidth: 2
15
+
16
+ Layout/CaseIndentation:
17
+ EnforcedStyle: end
18
+
19
+ Layout/EndAlignment:
20
+ EnforcedStyleAlignWith: start_of_line
21
+
22
+ Layout/LineLength:
23
+ Max: 140
24
+
25
+ Layout/ParameterAlignment:
26
+ EnforcedStyle: with_fixed_indentation
27
+ IndentationWidth: 2
28
+
29
+ Layout/SpaceInsideHashLiteralBraces:
30
+ EnforcedStyle: no_space
31
+
32
+ Metrics/ParameterLists:
33
+ CountKeywordArgs: false
34
+
35
+ Style/Alias:
36
+ EnforcedStyle: prefer_alias_method
37
+
38
+ Style/Documentation:
39
+ Enabled: false
40
+
41
+ Style/FrozenStringLiteralComment:
42
+ EnforcedStyle: never
43
+
44
+ Style/OpenStructUse:
45
+ Enabled: false
46
+
47
+ Style/StringLiterals:
48
+ EnforcedStyle: double_quotes
49
+
50
+ Style/StringLiteralsInInterpolation:
51
+ EnforcedStyle: double_quotes
52
+
53
+ Style/TernaryParentheses:
54
+ EnforcedStyle: require_parentheses
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ 0.7.0
2
+ -----
3
+ * [Add support for Ruby 3.3](https://github.com/sferik/multi_xml/pull/67)
4
+ * [Drop support for Ruby 3.0](https://github.com/sferik/multi_xml/commit/eec72c56307fede3a93f1a61553587cb278b0c8a) [and](https://github.com/sferik/multi_xml/commit/6a6dec80a36c30774a5525b45f71d346fb561e69) [earlier](https://github.com/sferik/multi_xml/commit/e7dad37a0a0be8383a26ffe515c575b5b4d04588)
5
+ * [Don't mutate strings](https://github.com/sferik/multi_xml/commit/71be3fff4afb0277a7e1c47c5f1f4b6106a8eb45)
6
+
7
+ 0.6.0
8
+ -----
9
+ * [Duplexed Streams](https://github.com/sferik/multi_xml/pull/45)
10
+ * [Support for Oga](https://github.com/sferik/multi_xml/pull/47)
11
+ * [Integer unification for Ruby 2.4](https://github.com/sferik/multi_xml/pull/54)
12
+
1
13
  0.5.5
2
14
  -----
3
15
  * [Fix symbolize_keys function](https://github.com/sferik/multi_xml/commit/a4cae3aeb690999287cd30206399abaa5ce1ae81)
data/CONTRIBUTING.md CHANGED
@@ -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/Gemfile ADDED
@@ -0,0 +1,21 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "libxml-ruby", require: nil, platforms: :ruby
4
+ gem "nokogiri", require: nil
5
+ gem "oga", ">= 2.3", require: nil
6
+ gem "ox", require: nil, platforms: :ruby
7
+ gem "rexml", require: nil
8
+
9
+ gem "rake", ">= 13.2.1"
10
+ gem "rspec", ">= 3.12"
11
+ gem "rubocop", ">= 1.62.1"
12
+ gem "rubocop-performance", ">= 1.20.2"
13
+ gem "rubocop-rake", ">= 0.6"
14
+ gem "rubocop-rspec", ">= 2.24"
15
+ gem "simplecov", ">= 0.22"
16
+ gem "standard", ">= 1.35.1"
17
+ gem "standard-performance", ">= 1.3.1"
18
+ gem "yard", ">= 0.9.36"
19
+ gem "yardstick", ">= 0.9.9"
20
+
21
+ gemspec
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2013 Erik Michaels-Ober
1
+ Copyright (c) 2010-2024 Erik Berlin
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,42 +1,16 @@
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]
8
-
9
- [gem]: https://rubygems.org/gems/multi_xml
10
- [travis]: http://travis-ci.org/sferik/multi_xml
11
- [gemnasium]: https://gemnasium.com/sferik/multi_xml
12
- [codeclimate]: https://codeclimate.com/github/sferik/multi_xml
13
- [coveralls]: https://coveralls.io/r/sferik/multi_xml
14
-
15
3
  A generic swappable back-end for XML parsing
16
4
 
17
5
  ## Installation
18
6
  gem install multi_xml
19
7
 
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
8
  ## Documentation
31
9
  [http://rdoc.info/gems/multi_xml][documentation]
32
10
 
33
11
  [documentation]: http://rdoc.info/gems/multi_xml
34
12
 
35
13
  ## Usage Examples
36
- Lots of Ruby libraries utilize XML parsing in some form, and everyone has their
37
- favorite XML library. In order to best support multiple XML parsers and
38
- libraries, `multi_xml` is a general-purpose swappable XML backend library. You
39
- use it like so:
40
14
  ```ruby
41
15
  require 'multi_xml'
42
16
 
@@ -55,25 +29,28 @@ MultiXml.parse('<tag>This is the contents</tag>') # Parsed using Nokogiri
55
29
  MultiXml.parser = :rexml
56
30
  MultiXml.parser = MultiXml::Parsers::Rexml # Same as above
57
31
  MultiXml.parse('<tag>This is the contents</tag>') # Parsed using REXML
32
+
33
+ MultiXml.parser = :oga
34
+ MultiXml.parser = MultiXml::Parsers::Oga # Same as above
35
+ MultiXml.parse('<tag>This is the contents</tag>') # Parsed using Oga
58
36
  ```
59
37
  The `parser` setter takes either a symbol or a class (to allow for custom XML
60
38
  parsers) that responds to `.parse` at the class level.
61
39
 
62
40
  MultiXML tries to have intelligent defaulting. That is, if you have any of the
63
- supported parsers already loaded, it will utilize them before attempting to
64
- load any. When loading, libraries are ordered by speed: first Ox, then LibXML,
41
+ supported parsers already loaded, it will use them before attempting to load
42
+ a new one. When loading, libraries are ordered by speed: first Ox, then LibXML,
65
43
  then Nokogiri, and finally REXML.
66
44
 
67
45
  ## Supported Ruby Versions
68
- This library aims to support and is [tested against][travis] the following Ruby
46
+ This library aims to support and is tested against the following Ruby
69
47
  implementations:
70
48
 
71
- * Ruby 1.8.7
72
- * Ruby 1.9.2
73
- * Ruby 1.9.3
74
- * Ruby 2.0.0
49
+ * 3.1
50
+ * 3.2
51
+ * 3.3
75
52
 
76
- If something doesn't work on one of these interpreters, it's a bug.
53
+ If something doesn't work on one of these versions, it's a bug.
77
54
 
78
55
  This library may inadvertently work (or seem to work) on other Ruby
79
56
  implementations, however support will only be provided for the versions listed
@@ -92,6 +69,6 @@ MultiXML was inspired by [MultiJSON][].
92
69
  [multijson]: https://github.com/intridea/multi_json/
93
70
 
94
71
  ## Copyright
95
- Copyright (c) 2010-2013 Erik Michaels-Ober. See [LICENSE][] for details.
72
+ Copyright (c) 2010-2024 Erik Berlin. See [LICENSE][] for details.
96
73
 
97
74
  [license]: LICENSE.md
data/Rakefile CHANGED
@@ -1,21 +1,33 @@
1
- require 'bundler'
1
+ require "bundler"
2
2
  Bundler::GemHelper.install_tasks
3
3
 
4
- require 'rspec/core/rake_task'
4
+ require "rspec/core/rake_task"
5
5
  RSpec::Core::RakeTask.new(:spec)
6
6
 
7
- task :test => :spec
8
- task :default => :spec
7
+ task test: :spec
9
8
 
10
- namespace :doc do
11
- require 'yard'
12
- YARD::Rake::YardocTask.new do |task|
13
- task.files = ['lib/**/*.rb', '-', 'LICENSE.md']
14
- task.options = [
15
- '--no-private',
16
- '--protected',
17
- '--output-dir', 'doc/yard',
18
- '--markup', 'markdown',
19
- ]
20
- end
9
+ require "rubocop/rake_task"
10
+ RuboCop::RakeTask.new
11
+
12
+ require "yard"
13
+ YARD::Rake::YardocTask.new do |task|
14
+ task.files = ["lib/**/*.rb", "-", "LICENSE.md"]
15
+ task.options = [
16
+ "--no-private",
17
+ "--protected",
18
+ "--output-dir", "doc/yard",
19
+ "--markup", "markdown"
20
+ ]
21
+ end
22
+
23
+ require "yardstick/rake/measurement"
24
+ Yardstick::Rake::Measurement.new do |measurement|
25
+ measurement.output = "measurement/report.txt"
21
26
  end
27
+
28
+ require "yardstick/rake/verify"
29
+ Yardstick::Rake::Verify.new do |verify|
30
+ verify.threshold = 48.8
31
+ end
32
+
33
+ task default: %i[spec rubocop verify_measurements]
@@ -1,25 +1,28 @@
1
- require 'libxml' unless defined?(LibXML)
2
- require 'multi_xml/parsers/libxml2_parser'
1
+ require "libxml" unless defined?(LibXML)
2
+ require "multi_xml/parsers/libxml2_parser"
3
3
 
4
4
  module MultiXml
5
5
  module Parsers
6
- module Libxml #:nodoc:
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
 
17
- def each_child(node, &block)
18
- node.each_child(&block)
18
+ private
19
+
20
+ def each_child(node, &)
21
+ node.each_child(&)
19
22
  end
20
23
 
21
- def each_attr(node, &block)
22
- node.each_attr(&block)
24
+ def each_attr(node, &)
25
+ node.each_attr(&)
23
26
  end
24
27
 
25
28
  def node_name(node)
@@ -1,6 +1,6 @@
1
1
  module MultiXml
2
2
  module Parsers
3
- module Libxml2Parser #:nodoc:
3
+ module Libxml2Parser # :nodoc:
4
4
  # Convert XML document to hash
5
5
  #
6
6
  # node::
@@ -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={})
12
- node_hash = {MultiXml::CONTENT_ROOT => ''}
11
+ def node_to_hash(node, hash = {}) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
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
@@ -25,24 +28,18 @@ module MultiXml
25
28
  if c.element?
26
29
  node_to_hash(c, node_hash)
27
30
  elsif c.text? || c.cdata?
28
- node_hash[MultiXml::CONTENT_ROOT] << c.content
31
+ node_hash[MultiXml::CONTENT_ROOT] += c.content
29
32
  end
30
33
  end
31
34
 
32
35
  # Remove content node if it is empty
33
- if node_hash[MultiXml::CONTENT_ROOT].strip.empty?
34
- node_hash.delete(MultiXml::CONTENT_ROOT)
35
- end
36
+ node_hash.delete(MultiXml::CONTENT_ROOT) if node_hash[MultiXml::CONTENT_ROOT].strip.empty?
36
37
 
37
38
  # Handle attributes
38
39
  each_attr(node) do |a|
39
40
  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
41
+ v = node_hash[key]
42
+ node_hash[key] = ((v) ? [a.value, v] : a.value)
46
43
  end
47
44
 
48
45
  hash
@@ -51,23 +48,22 @@ module MultiXml
51
48
  # Parse an XML Document IO into a simple hash.
52
49
  # xml::
53
50
  # XML Document IO to parse
54
- def parse(xml)
55
- raise NotImplementedError, "inheritor should define #{__method__}"
51
+ def parse(_)
52
+ raise(NotImplementedError, "inheritor should define #{__method__}")
56
53
  end
57
54
 
58
- # :stopdoc:
59
55
  private
60
56
 
61
- def each_child(*args)
62
- raise NotImplementedError, "inheritor should define #{__method__}"
57
+ def each_child(*)
58
+ raise(NotImplementedError, "inheritor should define #{__method__}")
63
59
  end
64
60
 
65
- def each_attr(*args)
66
- raise NotImplementedError, "inheritor should define #{__method__}"
61
+ def each_attr(*)
62
+ raise(NotImplementedError, "inheritor should define #{__method__}")
67
63
  end
68
64
 
69
- def node_name(*args)
70
- raise NotImplementedError, "inheritor should define #{__method__}"
65
+ def node_name(*)
66
+ raise(NotImplementedError, "inheritor should define #{__method__}")
71
67
  end
72
68
  end
73
69
  end
@@ -1,27 +1,31 @@
1
- require 'nokogiri' unless defined?(Nokogiri)
2
- require 'multi_xml/parsers/libxml2_parser'
1
+ require "nokogiri" unless defined?(Nokogiri)
2
+ require "multi_xml/parsers/libxml2_parser"
3
3
 
4
4
  module MultiXml
5
5
  module Parsers
6
- module Nokogiri #:nodoc:
6
+ module Nokogiri # :nodoc:
7
7
  include Libxml2Parser
8
-
9
8
  extend self
10
9
 
11
- def parse_error() ::Nokogiri::XML::SyntaxError end
10
+ def parse_error
11
+ ::Nokogiri::XML::SyntaxError
12
+ end
12
13
 
13
14
  def parse(xml)
14
15
  doc = ::Nokogiri::XML(xml)
15
- raise doc.errors.first if doc.errors.length > 0
16
+ raise(doc.errors.first) unless doc.errors.empty?
17
+
16
18
  node_to_hash(doc.root)
17
19
  end
18
20
 
19
- def each_child(node, &block)
20
- node.children.each(&block)
21
+ private
22
+
23
+ def each_child(node, &)
24
+ node.children.each(&)
21
25
  end
22
26
 
23
- def each_attr(node, &block)
24
- node.attribute_nodes.each(&block)
27
+ def each_attr(node, &)
28
+ node.attribute_nodes.each(&)
25
29
  end
26
30
 
27
31
  def node_name(node)
@@ -0,0 +1,71 @@
1
+ require "oga" unless defined?(Oga)
2
+ require "multi_xml/parsers/libxml2_parser"
3
+
4
+ module MultiXml
5
+ module Parsers
6
+ module Oga # :nodoc:
7
+ include Libxml2Parser
8
+ extend self
9
+
10
+ def parse_error
11
+ LL::ParserError
12
+ end
13
+
14
+ def parse(io)
15
+ document = ::Oga.parse_xml(io)
16
+ node_to_hash(document.children[0])
17
+ end
18
+
19
+ def node_to_hash(node, hash = {}) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
20
+ node_hash = {MultiXml::CONTENT_ROOT => ""}
21
+
22
+ name = node_name(node)
23
+
24
+ # Insert node hash into parent hash correctly.
25
+ case hash[name]
26
+ when Array
27
+ hash[name] << node_hash
28
+ when Hash
29
+ hash[name] = [hash[name], node_hash]
30
+ when NilClass
31
+ hash[name] = node_hash
32
+ end
33
+
34
+ # Handle child elements
35
+ each_child(node) do |c|
36
+ if c.is_a?(::Oga::XML::Element)
37
+ node_to_hash(c, node_hash)
38
+ elsif c.is_a?(::Oga::XML::Text) || c.is_a?(::Oga::XML::Cdata)
39
+ node_hash[MultiXml::CONTENT_ROOT] += c.text
40
+ end
41
+ end
42
+
43
+ # Remove content node if it is empty
44
+ node_hash.delete(MultiXml::CONTENT_ROOT) if node_hash[MultiXml::CONTENT_ROOT].strip.empty?
45
+
46
+ # Handle attributes
47
+ each_attr(node) do |a|
48
+ key = node_name(a)
49
+ v = node_hash[key]
50
+ node_hash[key] = ((v) ? [a.value, v] : a.value)
51
+ end
52
+
53
+ hash
54
+ end
55
+
56
+ private
57
+
58
+ def each_child(node, &)
59
+ node.children.each(&)
60
+ end
61
+
62
+ def each_attr(node, &)
63
+ node.attributes.each(&)
64
+ end
65
+
66
+ def node_name(node)
67
+ node.name
68
+ end
69
+ end
70
+ end
71
+ end
@@ -1,4 +1,4 @@
1
- require 'ox' unless defined?(Ox)
1
+ require "ox" unless defined?(Ox)
2
2
 
3
3
  # Each MultiXml parser is expected to parse an XML document into a Hash. The
4
4
  # conversion rules are:
@@ -20,9 +20,8 @@ require 'ox' unless defined?(Ox)
20
20
 
21
21
  module MultiXml
22
22
  module Parsers
23
- module Ox #:nodoc:
24
-
25
- extend self
23
+ module Ox # :nodoc:
24
+ module_function
26
25
 
27
26
  def parse_error
28
27
  Exception
@@ -30,14 +29,14 @@ module MultiXml
30
29
 
31
30
  def parse(io)
32
31
  handler = Handler.new
33
- ::Ox.sax_parse(handler, io, :convert_special => true)
32
+ ::Ox.sax_parse(handler, io, convert_special: true, skip: :skip_return)
34
33
  handler.doc
35
34
  end
36
35
 
37
36
  class Handler
38
37
  attr_accessor :stack
39
38
 
40
- def initialize()
39
+ def initialize
41
40
  @stack = []
42
41
  end
43
42
 
@@ -46,9 +45,7 @@ module MultiXml
46
45
  end
47
46
 
48
47
  def attr(name, value)
49
- unless @stack.empty?
50
- append(name, value)
51
- end
48
+ append(name, value) unless @stack.empty?
52
49
  end
53
50
 
54
51
  def text(value)
@@ -60,26 +57,24 @@ module MultiXml
60
57
  end
61
58
 
62
59
  def start_element(name)
63
- if @stack.empty?
64
- @stack.push(Hash.new)
65
- end
66
- h = Hash.new
60
+ @stack.push({}) if @stack.empty?
61
+ h = {}
67
62
  append(name, h)
68
63
  @stack.push(h)
69
64
  end
70
65
 
71
- def end_element(name)
72
- @stack.pop()
66
+ def end_element(_)
67
+ @stack.pop
73
68
  end
74
69
 
75
70
  def error(message, line, column)
76
- raise Exception.new("#{message} at #{line}:#{column}")
71
+ raise(StandardError, "#{message} at #{line}:#{column}")
77
72
  end
78
73
 
79
74
  def append(key, value)
80
75
  key = key.to_s
81
76
  h = @stack.last
82
- if h.has_key?(key)
77
+ if h.key?(key)
83
78
  v = h[key]
84
79
  if v.is_a?(Array)
85
80
  v << value
@@ -90,8 +85,7 @@ module MultiXml
90
85
  h[key] = value
91
86
  end
92
87
  end
93
-
94
- end # Handler
95
- end # Ox
96
- end # Parsers
97
- end # MultiXml
88
+ end
89
+ end
90
+ end
91
+ end