diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aa17a67..326fb81 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - ruby: ['2.5', '2.6', '2.7'] + ruby: ['2.5', '2.6', '2.7', '3.0'] handler: ['nokogiri', 'ox', 'oga'] steps: - uses: actions/checkout@v2 diff --git a/.ruby-version b/.ruby-version index 73462a5..cb2b00e 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.5.1 +3.0.1 diff --git a/Gemfile b/Gemfile index 99c3e27..4c51661 100644 --- a/Gemfile +++ b/Gemfile @@ -8,12 +8,12 @@ group :development, :test do gem 'simplecov', require: false, platforms: [:mri] gem 'coveralls', require: false, platforms: [:mri] - gem 'activerecord', '~> 5.0.0' + gem 'activerecord', '~> 6.0' gem 'nokogiri', '>= 1.8.2' gem 'ox', '>= 2.10.0' gem 'oga', '>= 2.15' end group :test do - gem 'sqlite3', '~> 1.3.13' + gem 'sqlite3', '~> 1.4.2' end diff --git a/README.md b/README.md index 5e217fd..1ba23b4 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,25 @@ document determines the value assigned to the alias. If an element is defined in the source but is blank (e.g., ``), it is ignored, and non-empty one is picked. +## Parsing Errors +By default, there are no notification or exceptions on parsing errors and warnings. For Nokogiri and Ox, you can +specify a custom behavior by passing procs that receive a string: + +```ruby +on_error = ->(error_string) { raise error_string } +on_warning = ->(warning_string) { raise warning_string } + +feed = Atom.parse(xml, on_error, on_warning) +``` + +You can also use a global setting (e.g. in `config/initializers/saxophone.rb` when using Saxophone together +with Ruby on Rails): + +```ruby +Saxophone.on_error = ->(error_string) { raise error_string } +Saxophone.on_warning = ->(warning_string) { raise warning_string } +``` + ## Contributing 1. Fork it diff --git a/lib/saxophone.rb b/lib/saxophone.rb index 682de3c..25bbbad 100644 --- a/lib/saxophone.rb +++ b/lib/saxophone.rb @@ -14,6 +14,22 @@ def self.handler=(handler) @@handler = handler end end + + def self.on_error + @@on_error ||= ->(_) {} + end + + def self.on_error=(on_error_proc) + @@on_error = on_error_proc + end + + def self.on_warning + @@on_warning ||= ->(_) {} + end + + def self.on_warning=(on_warning_proc) + @@on_warning = on_warning_proc + end end # Try handlers diff --git a/lib/saxophone/sax_document.rb b/lib/saxophone/sax_document.rb index 8e27510..1445b8a 100644 --- a/lib/saxophone/sax_document.rb +++ b/lib/saxophone/sax_document.rb @@ -4,7 +4,7 @@ def self.included(base) base.extend(ClassMethods) end - def parse(xml_input, on_error = ->(_){}, on_warning = ->(_){}) + def parse(xml_input, on_error = Saxophone.on_error, on_warning = Saxophone.on_warning) handler_klass = Saxophone.const_get("SAX#{Saxophone.handler.capitalize}Handler") handler = handler_klass.new(self, on_error, on_warning) @@ -15,7 +15,7 @@ def parse(xml_input, on_error = ->(_){}, on_warning = ->(_){}) module InstanceMethods def initialize(attributes = {}) - attributes.each do |name, value| + attributes&.each do |name, value| send("#{name}=", value) end diff --git a/lib/saxophone/version.rb b/lib/saxophone/version.rb index 4b8492c..5cb53c2 100644 --- a/lib/saxophone/version.rb +++ b/lib/saxophone/version.rb @@ -1,3 +1,3 @@ module Saxophone - VERSION = "1.0.0" + VERSION = "1.1.0" end diff --git a/spec/saxophone/global_config_spec.rb b/spec/saxophone/global_config_spec.rb new file mode 100644 index 0000000..6045798 --- /dev/null +++ b/spec/saxophone/global_config_spec.rb @@ -0,0 +1,88 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe "Saxophone global configurations" do + before(:all) do + class A + include Saxophone + end + end + + after(:all) do + Object.send(:remove_const, :A) + end + + describe "handler config" do + after(:all) do + Saxophone.handler = :ox # restore default settings + end + + context "with handler set to ox" do + before do + Saxophone.handler = :ox + end + + it "uses ox as handler" do + expect(Saxophone.handler).to eq :ox + end + end + + context "with handler set to oga" do + before do + Saxophone.handler = :oga + end + + it "uses oga as handler" do + expect(Saxophone.handler).to eq :oga + end + end + + context "with handler set to nokogiri" do + before do + Saxophone.handler = :nokogiri + end + + it "uses nokogiri as handler" do + expect(Saxophone.handler).to eq :nokogiri + end + end + + context "with handler set to some other value" do + it "raises error" do + expect { Saxophone.handler = :not_a_valid_handler }.to raise_error(LoadError) + end + end + end + + describe "global on_error config" do + broken_xml = "Te & stMatched!And Again" + xml = "TestMatched!And Again" + + context "not configured" do + it "does not raise exception on valid xml" do + expect { A.parse xml }.not_to raise_error + end + + it "does not raise exception on broken xml" do + expect { A.parse broken_xml }.not_to raise_error + end + end + + context "configured to raise exception" do + before(:all) do + Saxophone.on_error = ->(error_string) { raise error_string } + end + + after(:all) do + Saxophone.on_error = ->(_) {} # restore default settings + end + + it "does not raise exception on valid xml" do + expect { A.parse xml }.not_to raise_error + end + + it "raises exception on broken xml" do + expect { A.parse broken_xml }.to raise_error(RuntimeError) + end + end + end +end