saxophone 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 57c5242aea2b5daec2f7129d6b12fe56e28e07a8
4
- data.tar.gz: c5f4823813e45c56693feeafbb808253367cf533
2
+ SHA256:
3
+ metadata.gz: 99eb0392977bf92c77b61dd1d79feddde93e8d91b5eea7a76fb03892354ee3b6
4
+ data.tar.gz: 0c2c3c808f9b5c70258238835ee9240b4745876a5948c9fce7879372d4a4077a
5
5
  SHA512:
6
- metadata.gz: 18a39e8330f39c5da059bfcb39f147084d8d707fd6375a9561d4711ce3269dc16a98f860a717d45b181cbd79c555edfc329e7ff80818c0f7e41a65f29a0ce9e6
7
- data.tar.gz: 6d4b5006f62bacf0d51e6300ba146083301fcb3922dd960282216272622a130ce7cd6fac88481ad5149ceedf4f0e69c5538decde24cae5fa16ae7944594a3c7c
6
+ metadata.gz: c40ff56245b84fc4592a949726455feb15c25fe914e93234203976409e8a6b9d47dc6d7b636f29644992e553bb4f88847594890abee24ce88bdeb7de9bf0ca7a
7
+ data.tar.gz: f2d65e68ba0dbf5bb91f97a644d1a4a4a74860186f365dc5f1aa3deb443d8260ec42c7a1fb2f5207f3f24d0ac12a53877f9e76f44d177ca3c3b6f3cfbece8bf4
@@ -0,0 +1,25 @@
1
+ name: build
2
+ on:
3
+ push:
4
+ branches:
5
+ - master
6
+ pull_request:
7
+ branches:
8
+ - master
9
+ jobs:
10
+ build:
11
+ if: "!contains(github.event.head_commit.message, '[skip ci]')"
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ ruby: ['2.5', '2.6', '2.7', '3.0']
16
+ handler: ['nokogiri', 'ox', 'oga']
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ bundler-cache: true
23
+ - run: bundle exec rake
24
+ env:
25
+ HANDLER: ${{ matrix.handler }}
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.5.1
1
+ 3.0.1
data/Gemfile CHANGED
@@ -8,12 +8,12 @@ group :development, :test do
8
8
  gem 'simplecov', require: false, platforms: [:mri]
9
9
  gem 'coveralls', require: false, platforms: [:mri]
10
10
 
11
- gem 'activerecord', '~> 5.0.0'
11
+ gem 'activerecord', '~> 6.0'
12
12
  gem 'nokogiri', '>= 1.8.2'
13
- gem 'ox', '>= 2.1.2', platforms: [:mri, :rbx]
14
- gem 'oga', '>= 0.3.4'
13
+ gem 'ox', '>= 2.10.0'
14
+ gem 'oga', '>= 2.15'
15
15
  end
16
16
 
17
17
  group :test do
18
- gem 'sqlite3'
18
+ gem 'sqlite3', '~> 1.4.2'
19
19
  end
data/README.md CHANGED
@@ -1,6 +1,14 @@
1
- # Saxophone
2
-
3
- A declarative SAX parsing library backed by Nokogiri, Ox or Oga.
1
+ <div align="center">
2
+ <img alt="Saxophone" src="logo.svg" width="400px">
3
+ <br>
4
+ <br>
5
+ <strong>A declarative SAX parsing library backed by Nokogiri, Ox or Oga.</strong>
6
+ <br>
7
+ <br>
8
+ <a href="https://github.com/Absolventa/saxophone/actions/workflows/build.yml">
9
+ <img src="https://github.com/Absolventa/saxophone/actions/workflows/build.yml/badge.svg" alt="Build Status" style="max-width: 100%;">
10
+ </a>
11
+ </div>
4
12
 
5
13
  ## Origins
6
14
 
@@ -37,13 +45,13 @@ gem 'nokogiri', '~> 1.6'
37
45
  To use **Ox** add this line to your Gemfile:
38
46
 
39
47
  ```ruby
40
- gem 'ox', '>= 2.1.2'
48
+ gem 'ox', '>= 2.10.0'
41
49
  ```
42
50
 
43
51
  To use **Oga** add this line to your Gemfile:
44
52
 
45
53
  ```ruby
46
- gem 'oga', '>= 0.2.0'
54
+ gem 'oga', '>= 2.15'
47
55
  ```
48
56
 
49
57
  You can also specify which handler to use manually, like this:
@@ -66,34 +74,42 @@ end
66
74
  class AtomEntry
67
75
  include Saxophone
68
76
  element :title
77
+
69
78
  # The :as argument makes this available through entry.author instead of .name
70
79
  element :name, as: :author
71
80
  element "feedburner:origLink", as: :url
81
+
72
82
  # The :default argument specifies default value for element when it's missing
73
83
  element :summary, class: String, default: "No summary available"
84
+
74
85
  element :content, class: AtomContent
75
86
  element :published
87
+
76
88
  ancestor :ancestor
77
89
  end
78
90
 
79
91
  class Atom
80
92
  include Saxophone
93
+
81
94
  # Use block to modify the returned value
82
95
  # Blocks are working with pretty much everything,
83
96
  # except for `elements` with `class` attribute
84
97
  element :title do |title|
85
98
  title.strip
86
99
  end
100
+
87
101
  # The :with argument means that you only match a link tag
88
102
  # that has an attribute of type: "text/html"
89
103
  element :link, value: :href, as: :url, with: {
90
104
  type: "text/html"
91
105
  }
106
+
92
107
  # The :value argument means that instead of setting the value
93
108
  # to the text between the tag, it sets it to the attribute value of :href
94
109
  element :link, value: :href, as: :feed_url, with: {
95
110
  type: "application/atom+xml"
96
111
  }
112
+
97
113
  elements :entry, as: :entries, class: AtomEntry
98
114
  end
99
115
  ```
@@ -101,7 +117,7 @@ end
101
117
  Then parse any XML with your class:
102
118
 
103
119
  ```ruby
104
- feed = Atom.parse(xml_text)
120
+ feed = Atom.parse(xml)
105
121
 
106
122
  feed.title # Whatever the title of the blog is
107
123
  feed.url # The main URL of the blog
@@ -151,11 +167,11 @@ Multiple elements can be mapped to the same alias:
151
167
  ```ruby
152
168
  class RSSEntry
153
169
  include Saxophone
154
- # ...
155
- element :pubDate, as: :published
156
- element :pubdate, as: :published
157
- element :"dc:date", as: :published
158
- element :"dc:Date", as: :published
170
+
171
+ element :pubDate, as: :published
172
+ element :pubdate, as: :published
173
+ element :"dc:date", as: :published
174
+ element :"dc:Date", as: :published
159
175
  element :"dcterms:created", as: :published
160
176
  end
161
177
  ```
@@ -166,6 +182,25 @@ document determines the value assigned to the alias.
166
182
 
167
183
  If an element is defined in the source but is blank (e.g., `<pubDate></pubDate>`), it is ignored, and non-empty one is picked.
168
184
 
185
+ ## Parsing Errors
186
+ By default, there are no notification or exceptions on parsing errors and warnings. For Nokogiri and Ox, you can
187
+ specify a custom behavior by passing procs that receive a string:
188
+
189
+ ```ruby
190
+ on_error = ->(error_string) { raise error_string }
191
+ on_warning = ->(warning_string) { raise warning_string }
192
+
193
+ feed = Atom.parse(xml, on_error, on_warning)
194
+ ```
195
+
196
+ You can also use a global setting (e.g. in `config/initializers/saxophone.rb` when using Saxophone together
197
+ with Ruby on Rails):
198
+
199
+ ```ruby
200
+ Saxophone.on_error = ->(error_string) { raise error_string }
201
+ Saxophone.on_warning = ->(warning_string) { raise warning_string }
202
+ ```
203
+
169
204
  ## Contributing
170
205
 
171
206
  1. Fork it
@@ -178,7 +213,7 @@ If an element is defined in the source but is blank (e.g., `<pubDate></pubDate>`
178
213
 
179
214
  The MIT License
180
215
 
181
- Copyright (c) 2009-2018:
216
+ Copyright (c) 2009-2020:
182
217
 
183
218
  * [Paul Dix](http://www.pauldix.net)
184
219
  * [Julien Kirch](http://www.archiloque.net)
@@ -125,15 +125,11 @@ module Saxophone
125
125
  end
126
126
 
127
127
  def _error(string)
128
- if @on_error
129
- @on_error.call(string)
130
- end
128
+ @on_error.call(string)
131
129
  end
132
130
 
133
131
  def _warning(string)
134
- if @on_warning
135
- @on_warning.call(string)
136
- end
132
+ @on_warning.call(string)
137
133
  end
138
134
 
139
135
  private
@@ -4,7 +4,7 @@ module Saxophone
4
4
  base.extend(ClassMethods)
5
5
  end
6
6
 
7
- def parse(xml_input, on_error = nil, on_warning = nil)
7
+ def parse(xml_input, on_error = Saxophone.on_error, on_warning = Saxophone.on_warning)
8
8
  handler_klass = Saxophone.const_get("SAX#{Saxophone.handler.capitalize}Handler")
9
9
 
10
10
  handler = handler_klass.new(self, on_error, on_warning)
@@ -15,7 +15,7 @@ module Saxophone
15
15
 
16
16
  module InstanceMethods
17
17
  def initialize(attributes = {})
18
- attributes.each do |name, value|
18
+ attributes&.each do |name, value|
19
19
  send("#{name}=", value)
20
20
  end
21
21
 
@@ -1,3 +1,3 @@
1
1
  module Saxophone
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
data/lib/saxophone.rb CHANGED
@@ -14,6 +14,22 @@ module Saxophone
14
14
  @@handler = handler
15
15
  end
16
16
  end
17
+
18
+ def self.on_error
19
+ @@on_error ||= ->(_) {}
20
+ end
21
+
22
+ def self.on_error=(on_error_proc)
23
+ @@on_error = on_error_proc
24
+ end
25
+
26
+ def self.on_warning
27
+ @@on_warning ||= ->(_) {}
28
+ end
29
+
30
+ def self.on_warning=(on_warning_proc)
31
+ @@on_warning = on_warning_proc
32
+ end
17
33
  end
18
34
 
19
35
  # Try handlers
data/logo.svg ADDED
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg viewBox="0 0 764 245" width="764" height="245" xmlns="http://www.w3.org/2000/svg">
3
+ <g fill="none" fill-rule="evenodd">
4
+ <path d="M157.09 209.91c12.955 0 18.683-3.137 23.592-13.092C182.59 205.41 186.409 208 196.5 208v-6.955c-8.182.137-10.636-3.136-10.636-14.454V151c0-21.955-6.955-29.182-28.773-29.182-15.955 0-22.364 4.637-26.591 18.955l7.227 1.772c3.137-10.5 7.637-13.636 19.364-13.636 16.227 0 21.273 5.182 21.273 22.091v8.455H157.09c-21.682 0-28.636 6-28.636 25.772 0 18.682 6.954 24.682 28.636 24.682Zm0-6.955c-16.226 0-21.135-4.228-21.135-17.728 0-14.59 4.909-18.954 21.136-18.954h21.273v12.136c0 18.682-5.046 24.546-21.273 24.546ZM221.183 208l21.273-35.182L263.864 208h8.454l-25.5-42.136 25.5-42.137h-8.454l-21.41 35.182-21.272-35.182h-8.591l25.636 42.137L212.591 208h8.59Zm103.09 1.91c22.5 0 29.728-10.774 29.728-44.046 0-33.273-7.227-44.046-29.727-44.046s-29.591 10.773-29.591 44.046c0 33.272 7.09 44.045 29.59 44.045Zm0-6.955c-16.772 0-22.09-8.728-22.09-37.091 0-28.364 5.318-37.091 22.09-37.091 16.773 0 22.228 8.727 22.228 37.09 0 28.364-5.455 37.092-22.227 37.092Zm60.546 29.863v-34.5c3.682 8.727 11.727 11.591 22.227 11.591 22.5 0 29.728-10.773 29.728-44.182 0-33.272-7.228-43.909-29.728-43.909-10.227 0-18.272 2.046-22.227 8.455v-6.546h-7.5v109.091h7.5Zm22.227-29.863c-13.363 0-22.227-6-22.227-22.773v-39.818c0-8.864 10.227-11.591 22.227-11.591 16.773 0 22.228 8.727 22.228 36.954 0 28.364-5.455 37.228-22.228 37.228ZM468.41 208v-56.182c0-18.545 4.773-23.045 20.864-23.045 15.954 0 21.136 8.318 21.136 35.318V208h7.5v-43.91c0-32.045-6.954-42.272-28.636-42.272-10.228 0-17.864 2.455-20.864 10.227V98.91h-7.5V208h7.5Zm101.318 1.91c22.5 0 29.728-10.774 29.728-44.046 0-33.273-7.228-44.046-29.728-44.046s-29.59 10.773-29.59 44.046c0 33.272 7.09 44.045 29.59 44.045Zm0-6.955c-16.772 0-22.09-8.728-22.09-37.091 0-28.364 5.318-37.091 22.09-37.091 16.773 0 22.228 8.727 22.228 37.09 0 28.364-5.455 37.092-22.228 37.092Zm61.5 5.045v-56.182c0-18.818 5.591-23.045 24.137-23.045 13.772 0 18.136 5.863 18.136 24.545V208h7.5v-54.682c0-24-6.136-31.5-25.636-31.5-13.228 0-19.228 3-24.137 10.091v-8.182h-7.5V208h7.5Zm102.546 1.91c13.909 0 20.727-3.41 28.363-14.046l-6-4.091c-6.681 8.59-11.863 11.182-22.363 11.182-18.137 0-24.137-8.728-24.41-36.682h54.273c0-33.546-7.227-44.455-29.863-44.455-24.273 0-31.91 10.773-31.91 44.046 0 33.272 7.637 44.045 31.91 44.045Zm22.09-50.455H709.5c.682-23.319 6.955-30.682 24.273-30.682 15.545 0 20.863 7.363 22.09 30.682Z" fill="#000" fill-rule="nonzero"/>
5
+ <path d="M139.791 3.5c-7.052 1.164-11.908 2.19-14.566 3.077-7.587 2.53-12.196 5.953-15.414 8.235-4.983 3.534-8.586 8.8-11.227 13.486-3.3 5.853-5.02 11.347-5.137 17.714-.68 52.755-1.203 125.916-1.203 151.243 0 1.848-.113 3.67-.333 5.458-2.69 21.86-21.324 38.787-43.912 38.787-24.435 0-44.244-19.81-44.244-44.245v-61.562l41.965-21.24.585 75.634" stroke="#0A0909" stroke-width="7"/>
6
+ <path d="m76.021 96.23h34.416m-34.416 17.979h34.416m-34.416 18.109h34.416" stroke="#0A0909" stroke-width="5"/>
7
+ </g>
8
+ </svg>
@@ -0,0 +1,88 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Saxophone global configurations" do
4
+ before(:all) do
5
+ class A
6
+ include Saxophone
7
+ end
8
+ end
9
+
10
+ after(:all) do
11
+ Object.send(:remove_const, :A)
12
+ end
13
+
14
+ describe "handler config" do
15
+ after(:all) do
16
+ Saxophone.handler = :ox # restore default settings
17
+ end
18
+
19
+ context "with handler set to ox" do
20
+ before do
21
+ Saxophone.handler = :ox
22
+ end
23
+
24
+ it "uses ox as handler" do
25
+ expect(Saxophone.handler).to eq :ox
26
+ end
27
+ end
28
+
29
+ context "with handler set to oga" do
30
+ before do
31
+ Saxophone.handler = :oga
32
+ end
33
+
34
+ it "uses oga as handler" do
35
+ expect(Saxophone.handler).to eq :oga
36
+ end
37
+ end
38
+
39
+ context "with handler set to nokogiri" do
40
+ before do
41
+ Saxophone.handler = :nokogiri
42
+ end
43
+
44
+ it "uses nokogiri as handler" do
45
+ expect(Saxophone.handler).to eq :nokogiri
46
+ end
47
+ end
48
+
49
+ context "with handler set to some other value" do
50
+ it "raises error" do
51
+ expect { Saxophone.handler = :not_a_valid_handler }.to raise_error(LoadError)
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "global on_error config" do
57
+ broken_xml = "<top><title>Te & st</title><b>Matched!</b><c>And Again</c></top>"
58
+ xml = "<top><title>Test</title><b>Matched!</b><c>And Again</c></top>"
59
+
60
+ context "not configured" do
61
+ it "does not raise exception on valid xml" do
62
+ expect { A.parse xml }.not_to raise_error
63
+ end
64
+
65
+ it "does not raise exception on broken xml" do
66
+ expect { A.parse broken_xml }.not_to raise_error
67
+ end
68
+ end
69
+
70
+ context "configured to raise exception" do
71
+ before(:all) do
72
+ Saxophone.on_error = ->(error_string) { raise error_string }
73
+ end
74
+
75
+ after(:all) do
76
+ Saxophone.on_error = ->(_) {} # restore default settings
77
+ end
78
+
79
+ it "does not raise exception on valid xml" do
80
+ expect { A.parse xml }.not_to raise_error
81
+ end
82
+
83
+ it "raises exception on broken xml" do
84
+ expect { A.parse broken_xml }.to raise_error(RuntimeError)
85
+ end
86
+ end
87
+ end
88
+ end
@@ -1172,8 +1172,9 @@ describe "Saxophone" do
1172
1172
  describe "with error handling" do
1173
1173
  before do
1174
1174
  @xml = %[
1175
- <item id="1">
1175
+ <item:a:b id="1">
1176
1176
  <title>sweet</title>
1177
+ </idem>
1177
1178
  ]
1178
1179
 
1179
1180
  class ItemElement5
@@ -1190,9 +1191,7 @@ describe "Saxophone" do
1190
1191
  )
1191
1192
  end
1192
1193
 
1193
- it "has error" do
1194
- expect(@errors.uniq.size).to eq(1)
1195
- end
1194
+ it { expect(@errors.uniq.size).to be >= 1 }
1196
1195
 
1197
1196
  it "has no warning" do
1198
1197
  expect(@warnings.uniq.size).to eq(0)
data/spec/spec_helper.rb CHANGED
@@ -1,22 +1,2 @@
1
- begin
2
- require 'simplecov'
3
- require 'coveralls'
4
-
5
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
- SimpleCov::Formatter::HTMLFormatter,
7
- Coveralls::SimpleCov::Formatter
8
- ]
9
-
10
- SimpleCov.start do
11
- add_filter '/spec/'
12
- end
13
- rescue LoadError
14
- end
15
-
16
1
  require File.expand_path(File.dirname(__FILE__) + '/../lib/saxophone')
17
2
  Saxophone.handler = ENV['HANDLER'].to_sym if ENV['HANDLER']
18
-
19
- RSpec.configure do |config|
20
- config.run_all_when_everything_filtered = true
21
- config.filter_run :focus
22
- end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saxophone
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Dix
@@ -9,10 +9,10 @@ authors:
9
9
  - Ezekiel Templin
10
10
  - Dmitry Krasnoukhov
11
11
  - Robin Neumann
12
- autorequire:
12
+ autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2018-10-19 00:00:00.000000000 Z
15
+ date: 2021-10-27 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rspec
@@ -28,16 +28,16 @@ dependencies:
28
28
  - - "~>"
29
29
  - !ruby/object:Gem::Version
30
30
  version: '3.6'
31
- description:
32
- email:
31
+ description:
32
+ email:
33
33
  executables: []
34
34
  extensions: []
35
35
  extra_rdoc_files: []
36
36
  files:
37
+ - ".github/workflows/build.yml"
37
38
  - ".gitignore"
38
39
  - ".rspec"
39
40
  - ".ruby-version"
40
- - ".travis.yml"
41
41
  - Gemfile
42
42
  - README.md
43
43
  - Rakefile
@@ -56,9 +56,11 @@ files:
56
56
  - lib/saxophone/sax_configure.rb
57
57
  - lib/saxophone/sax_document.rb
58
58
  - lib/saxophone/version.rb
59
+ - logo.svg
59
60
  - saxophone.gemspec
60
61
  - spec/fixtures/atom-content.html
61
62
  - spec/fixtures/atom.xml
63
+ - spec/saxophone/global_config_spec.rb
62
64
  - spec/saxophone/sax_activerecord_spec.rb
63
65
  - spec/saxophone/sax_configure_spec.rb
64
66
  - spec/saxophone/sax_document_spec.rb
@@ -68,7 +70,7 @@ homepage: http://github.com/Absolventa/saxophone
68
70
  licenses:
69
71
  - MIT
70
72
  metadata: {}
71
- post_install_message:
73
+ post_install_message:
72
74
  rdoc_options: []
73
75
  require_paths:
74
76
  - lib
@@ -83,14 +85,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
85
  - !ruby/object:Gem::Version
84
86
  version: '0'
85
87
  requirements: []
86
- rubyforge_project:
87
- rubygems_version: 2.2.2
88
- signing_key:
88
+ rubygems_version: 3.2.15
89
+ signing_key:
89
90
  specification_version: 4
90
91
  summary: Declarative SAX Parsing with Nokogiri, Ox or Oga
91
92
  test_files:
92
93
  - spec/fixtures/atom-content.html
93
94
  - spec/fixtures/atom.xml
95
+ - spec/saxophone/global_config_spec.rb
94
96
  - spec/saxophone/sax_activerecord_spec.rb
95
97
  - spec/saxophone/sax_configure_spec.rb
96
98
  - spec/saxophone/sax_document_spec.rb
data/.travis.yml DELETED
@@ -1,35 +0,0 @@
1
- language: ruby
2
-
3
- rvm:
4
- - 1.9.3
5
- - 2.0
6
- - 2.1
7
- - 2.2
8
- - 2.3
9
- - 2.4
10
- - 2.5
11
- - jruby-1.7
12
- - rbx-2
13
- - ruby-head
14
- - jruby-head
15
-
16
- sudo: false
17
-
18
- env:
19
- matrix:
20
- - HANDLER="nokogiri"
21
- - HANDLER="ox"
22
- - HANDLER="oga"
23
-
24
- matrix:
25
- exclude:
26
- - env: HANDLER="ox"
27
- rvm: jruby-1.7
28
- - env: HANDLER="ox"
29
- rvm: jruby-head
30
- allow_failures:
31
- - env: HANDLER="oga"
32
- rvm: jruby-1.7
33
- - rvm: rbx-2
34
- - rvm: ruby-head
35
- - rvm: jruby-head