earl 0.3.0 → 2.0.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.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby-tests.yml +32 -0
  3. data/.gitignore +5 -0
  4. data/.rubocop.yml +35 -0
  5. data/.rubocop_todo.yml +22 -0
  6. data/.ruby-gemset +1 -0
  7. data/.ruby-version +1 -0
  8. data/Gemfile +13 -1
  9. data/Guardfile +15 -0
  10. data/LICENSE +2 -2
  11. data/README.md +127 -25
  12. data/Rakefile +10 -2
  13. data/earl.gemspec +19 -14
  14. data/lib/earl/earl.rb +172 -0
  15. data/lib/earl/scraper.rb +92 -0
  16. data/lib/earl/version.rb +4 -2
  17. data/lib/earl.rb +11 -20
  18. data/spec/fixtures/bicycles.html +490 -0
  19. data/spec/fixtures/bicycles_without_description.html +489 -0
  20. data/spec/fixtures/bicycles_without_images.html +457 -0
  21. data/spec/fixtures/cassettes/feed/is_atom_feed.yml +2298 -0
  22. data/spec/fixtures/cassettes/feed/is_rss_feed.yml +48 -0
  23. data/spec/fixtures/cassettes/feed/no_feed.yml +69 -0
  24. data/spec/fixtures/cassettes/feed/with_atom_and_rss_feed.yml +1471 -0
  25. data/spec/fixtures/cassettes/feed/with_rss_feed.yml +47 -0
  26. data/spec/fixtures/cassettes/oembed/no_oembed.yml +101 -0
  27. data/spec/fixtures/cassettes/oembed/youtube_oembed.yml +129 -0
  28. data/spec/fixtures/page_as_atom.html +161 -0
  29. data/spec/fixtures/page_as_rss.html +151 -0
  30. data/spec/fixtures/page_with_atom_feed.html +39 -0
  31. data/spec/fixtures/page_with_rss_and_atom_feeds.html +40 -0
  32. data/spec/fixtures/page_with_rss_feed.html +39 -0
  33. data/spec/fixtures/page_without_feeds.html +36 -0
  34. data/spec/fixtures/youtube.html +1839 -0
  35. data/spec/integration/feed_spec.rb +78 -0
  36. data/spec/integration/oembed_spec.rb +36 -0
  37. data/spec/spec_helper.rb +21 -29
  38. data/spec/support/fixtures.rb +15 -0
  39. data/spec/support/vcr.rb +9 -0
  40. data/spec/unit/earl/earl_spec.rb +15 -0
  41. data/spec/unit/earl/feed_spec.rb +62 -0
  42. data/spec/unit/earl/oembed_spec.rb +50 -0
  43. data/spec/unit/earl/scraper_spec.rb +49 -0
  44. data/spec/unit/earl_spec.rb +74 -0
  45. metadata +90 -62
  46. data/.rvmrc +0 -48
  47. data/lib/earl/email_assembler.rb +0 -11
  48. data/lib/earl/email_entity.rb +0 -27
  49. data/lib/earl/email_parser.tt +0 -58
  50. data/lib/earl/entity_base.rb +0 -37
  51. data/lib/earl/hash_inquirer.rb +0 -16
  52. data/lib/earl/string_inquirer.rb +0 -11
  53. data/lib/earl/url_assembler.rb +0 -15
  54. data/lib/earl/url_entity.rb +0 -23
  55. data/lib/earl/url_parser.tt +0 -163
  56. data/spec/earl/earl_spec.rb +0 -17
  57. data/spec/earl/email_entity_spec.rb +0 -31
  58. data/spec/earl/email_parser_spec.rb +0 -29
  59. data/spec/earl/entity_base_spec.rb +0 -39
  60. data/spec/earl/hash_inquirer_spec.rb +0 -24
  61. data/spec/earl/string_inquirer_spec.rb +0 -9
  62. data/spec/earl/url_entity_spec.rb +0 -45
  63. data/spec/earl/url_parser_spec.rb +0 -189
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Earl do
6
+ subject(:instance) { Earl[url] }
7
+
8
+ vcr_base = 'feed'
9
+
10
+ context 'when page has no feeds associated', vcr: { cassette_name: "#{vcr_base}/no_feed" } do
11
+ let(:url) { 'https://www.google.com/' }
12
+ it { expect(subject.feed?).to be false }
13
+ it { expect(subject.rss_feed).to be_nil }
14
+ it { expect(subject.feed).to be_nil }
15
+ end
16
+
17
+ context 'when page has rss feed associated', vcr: { cassette_name: "#{vcr_base}/with_rss_feed" } do
18
+ let(:url) { 'https://rubyweekly.com/' }
19
+ it { expect(subject.feed?).to be true }
20
+ it { expect(subject.rss_feed).to eql('/rss/') }
21
+ it { expect(subject.feed).to eql('/rss/') }
22
+ end
23
+
24
+ # # context "when page has atom feed associated" do
25
+ # # let(:url) { 'http:// still looking for a page that just has atom' }
26
+ # # { expect(subject.feed?).to be true }
27
+ # # { expect(subject.atom_feed).to eql('http://www.readwriteweb.com/atom.xml') }
28
+ # # { expect(subject.feed).to eql('http://www.readwriteweb.com/atom.xml') }
29
+ # # end
30
+
31
+ context 'when page has rss and atom feed associated', vcr: { cassette_name: "#{vcr_base}/with_atom_and_rss_feed" } do
32
+ let(:url) { 'https://0xfe.blogspot.com/' }
33
+ let(:expected_rss_feed) { 'https://0xfe.blogspot.com/feeds/posts/default?alt=rss' }
34
+ let(:expected_atom_feed) { 'https://0xfe.blogspot.com/feeds/posts/default' }
35
+
36
+ it { expect(subject.feed?).to be true }
37
+ it { expect(subject.rss_feed).to eql(expected_rss_feed) }
38
+ it { expect(subject.atom_feed).to eql(expected_atom_feed) }
39
+ describe '#feed' do
40
+ context 'default (rss)' do
41
+ subject { instance.feed }
42
+ it { expect(subject).to eql(expected_rss_feed) }
43
+ end
44
+ context 'rss prefered' do
45
+ subject { instance.feed(:rss) }
46
+ it { expect(subject).to eql(expected_rss_feed) }
47
+ end
48
+ context 'atom prefered' do
49
+ subject { instance.feed(:atom) }
50
+ it { expect(subject).to eql(expected_atom_feed) }
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'when page IS an rss feed', vcr: { cassette_name: "#{vcr_base}/is_rss_feed" } do
56
+ let(:url) { 'https://cprss.s3.amazonaws.com/rubyweekly.com.xml' }
57
+ it { expect(subject.url).to eql(url) }
58
+ it { expect(subject.base_url).to eql(url) }
59
+ it { expect(subject.content_type).to eql('application/xml') }
60
+ # TODO: fix rss feed detection
61
+ # it { expect(subject.feed?).to be true }
62
+ # it { expect(subject.rss_feed).to eql(url) }
63
+ # it { expect(subject.feed).to eql(url) }
64
+ it { expect(subject.feed?).to be false }
65
+ it { expect(subject.rss_feed).to be_nil }
66
+ it { expect(subject.feed).to be_nil }
67
+ end
68
+
69
+ context 'when page IS an atom feed', vcr: { cassette_name: "#{vcr_base}/is_atom_feed" } do
70
+ let(:url) { 'https://0xfe.blogspot.com/feeds/posts/default' }
71
+ it { expect(subject.url).to eql(url) }
72
+ it { expect(subject.base_url).to eql(url) }
73
+ it { expect(subject.content_type).to eql('application/atom+xml') }
74
+ it { expect(subject.feed?).to be true }
75
+ it { expect(subject.atom_feed).to eql(url) }
76
+ it { expect(subject.feed).to eql(url) }
77
+ end
78
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Earl do
6
+ subject(:instance) { Earl[url] }
7
+
8
+ vcr_base = 'oembed'
9
+
10
+ context 'when page does not support oembed', vcr: { cassette_name: "#{vcr_base}/no_oembed" } do
11
+ let(:url) { 'https://github.com/evendis/earl' }
12
+ it { expect(subject.oembed).to be_nil }
13
+ it { expect(subject.oembed_html).to be_nil }
14
+ describe '#metadata' do
15
+ subject { instance.metadata }
16
+ it { expect(subject[:base_url]).to match(%r{github\.com/evendis/earl}) }
17
+ it { expect(subject[:content_type]).to eql('text/html') }
18
+ it { expect(subject[:html]).to be_nil }
19
+ end
20
+ end
21
+
22
+ context 'when youtube oembed', vcr: { cassette_name: "#{vcr_base}/youtube_oembed" } do
23
+ let(:url) { 'https://www.youtube.com/watch?v=hNSkCqMUMQA' }
24
+ let(:expected_oembed_html) { 'https://www.youtube.com/embed/hNSkCqMUMQA?feature=oembed' }
25
+
26
+ it { expect(subject.oembed).to be_a(Hash) }
27
+ it { expect(subject.oembed_html).to include(expected_oembed_html) }
28
+ describe '#metadata' do
29
+ subject { instance.metadata }
30
+ it { expect(subject[:base_url]).to eql(url) }
31
+ it { expect(subject[:content_type]).to eql('text/html') }
32
+ it { expect(subject[:title]).to eql('[JA][Keynote] Ruby Taught Me About Encoding Under the Hood / Mari Imaizumi @ima1zumi') }
33
+ it { expect(subject[:html]).to include(expected_oembed_html) }
34
+ end
35
+ end
36
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,34 +1,26 @@
1
- require 'earl'
2
-
3
- # Configure RSpec
4
- RSpec.configure do |config|
5
- # Use color
6
- config.color_enabled = true
7
- # Change the formatter
8
- config.formatter = :documentation
9
- end
1
+ # frozen_string_literal: true
10
2
 
11
- # Custom entity manipulation matcher
12
- RSpec::Matchers.define :produce do |expected|
3
+ require 'earl'
13
4
 
14
- match do |entity_class|
15
- entity = entity_class.new @start
16
- @changes.each do |key, value|
17
- entity.send :"#{key}=", value
18
- end
19
- @actual = entity.to_s
20
- @actual == expected
21
- end
5
+ # Requires supporting files with custom matchers and macros, etc,
6
+ # in ./support/ and its subdirectories.
7
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
22
8
 
23
- failure_message_for_should do |entity|
24
- %Q{expected that "#{@start}" would become "#{expected}" when given #{@changes}, but was "#{@actual}"}
25
- end
9
+ RSpec.configure do |config|
10
+ # == Mock Framework
11
+ #
12
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
13
+ #
14
+ # config.mock_with :mocha
15
+ # config.mock_with :flexmock
16
+ # config.mock_with :rr
17
+ config.mock_with :rspec
26
18
 
27
- chain :from do |start|
28
- @start = start
29
- end
19
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
20
+ # config.fixture_path = "#{::Rails.root}/spec/fixtures"
30
21
 
31
- chain :when_given do |changes|
32
- @changes = changes
33
- end
34
- end
22
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
23
+ # examples within a transaction, remove the following line or assign false
24
+ # instead of true.
25
+ # config.use_transactional_fixtures = true
26
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FixtureHelper
4
+ def fixture_path(name)
5
+ File.dirname(__FILE__) + "/../fixtures/#{name}.html"
6
+ end
7
+
8
+ def fixture(name)
9
+ File.new(fixture_path(name)).read
10
+ end
11
+ end
12
+
13
+ RSpec.configure do |conf|
14
+ conf.include FixtureHelper
15
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vcr'
4
+
5
+ VCR.configure do |config|
6
+ config.cassette_library_dir = 'spec/fixtures/cassettes'
7
+ config.hook_into :webmock
8
+ config.configure_rspec_metadata!
9
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Earl do
6
+ describe '.new' do
7
+ subject { Earl.new('http://test.host/') }
8
+ it { expect(subject.to_s).to eql('http://test.host/') }
9
+ end
10
+
11
+ describe '[]=' do
12
+ subject { Earl['http://test.host/'] }
13
+ it { expect(subject.to_s).to eql('http://test.host/') }
14
+ end
15
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Earl do
6
+ let(:instance) { Earl[url] }
7
+ let(:url) { 'http:://example.com' }
8
+
9
+ before do
10
+ allow_any_instance_of(Earl).to receive(:uri_response).and_return(source)
11
+ end
12
+ subject { instance }
13
+
14
+ context 'when page has no feeds associated' do
15
+ let(:source) { fixture(:page_without_feeds) }
16
+ it { expect(subject.feed?).to be false }
17
+ it { expect(subject.rss_feed).to be_nil }
18
+ it { expect(subject.feed).to be_nil }
19
+ end
20
+
21
+ context 'when page has rss feed associated' do
22
+ let(:source) { fixture(:page_with_rss_feed) }
23
+ it { expect(subject.feed?).to be true }
24
+ it { expect(subject.rss_feed).to eql('http://www.readwriteweb.com/rss.xml') }
25
+ it { expect(subject.feed).to eql('http://www.readwriteweb.com/rss.xml') }
26
+ end
27
+
28
+ context 'when page has atom feed associated' do
29
+ let(:source) { fixture(:page_with_atom_feed) }
30
+ it { expect(subject.feed?).to be true }
31
+ it { expect(subject.atom_feed).to eql('http://www.readwriteweb.com/atom.xml') }
32
+ it { expect(subject.feed).to eql('http://www.readwriteweb.com/atom.xml') }
33
+ end
34
+
35
+ context 'when page has rss and atom feed associated' do
36
+ let(:source) { fixture(:page_with_rss_and_atom_feeds) }
37
+ it { expect(subject.feed?).to be true }
38
+ it { expect(subject.rss_feed).to eql('http://www.readwriteweb.com/rss.xml') }
39
+ it { expect(subject.atom_feed).to eql('http://www.readwriteweb.com/atom.xml') }
40
+ describe '#feed' do
41
+ context 'default (rss)' do
42
+ subject { instance.feed }
43
+ it { expect(subject).to eql('http://www.readwriteweb.com/rss.xml') }
44
+ end
45
+ context 'rss prefered' do
46
+ subject { instance.feed(:rss) }
47
+ it { expect(subject).to eql('http://www.readwriteweb.com/rss.xml') }
48
+ end
49
+ context 'atom prefered' do
50
+ subject { instance.feed(:atom) }
51
+ it { expect(subject).to eql('http://www.readwriteweb.com/atom.xml') }
52
+ end
53
+ end
54
+ end
55
+
56
+ # context "when page IS an rss feed" do
57
+ # let(:source) { fixture(:page_as_rss) }
58
+ # its(:feed?) { should be_true }
59
+ # its(:rss_feed) { should eql(url) }
60
+ # its(:feed) { should eql(url) }
61
+ # end
62
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class MockOembedResponse
6
+ def fields
7
+ { 'html' => '<iframe/>' }
8
+ end
9
+ end
10
+
11
+ describe Earl do
12
+ let(:instance) { Earl.new(url, options) }
13
+ let(:url) { 'http:://example.com' }
14
+ let(:options) { {} }
15
+
16
+ describe '#oembed_options' do
17
+ subject { instance.oembed_options }
18
+ context 'with default options' do
19
+ let(:expected) { { maxwidth: '560', maxheight: '315' } }
20
+ it { expect(subject).to eql(expected) }
21
+ end
22
+ context 'with custom options' do
23
+ let(:options) { { oembed: { maxwidth: '260' } } }
24
+ let(:expected) { { maxwidth: '260', maxheight: '315' } }
25
+ it { expect(subject).to eql(expected) }
26
+ end
27
+ context 'with custom options passed to oembed' do
28
+ let(:expected) { { maxwidth: '360', maxheight: '315' } }
29
+ before do
30
+ allow(instance).to receive(:fetch_oembed).and_return(nil)
31
+ instance.oembed({ maxwidth: '360' })
32
+ end
33
+ it { expect(subject).to eql(expected) }
34
+ end
35
+ end
36
+
37
+ describe '#oembed' do
38
+ let(:dummy_response) { MockOembedResponse.new }
39
+ before do
40
+ expect(instance).to receive(:base_url).and_return('')
41
+ expect(instance).to receive(:fetch_oembed).and_return(dummy_response)
42
+ end
43
+ subject { instance.oembed }
44
+ it { expect(subject).to eql({ html: '<iframe/>' }) }
45
+ describe '#oembed_html' do
46
+ subject { instance.oembed_html }
47
+ it { expect(subject).to eql('<iframe/>') }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Earl::Scraper do
6
+ before do
7
+ allow_any_instance_of(Earl).to receive(:uri_response).and_return(
8
+ <<-DOC
9
+ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
10
+ <html></html>
11
+ DOC
12
+ )
13
+ end
14
+
15
+ describe 'When validating URLs' do
16
+ before do
17
+ class Earl::TestScraper < Earl::Scraper
18
+ match %r{^http://www\.test\.com/$}
19
+ define_attribute(:title) { |_response| :test_title }
20
+ end
21
+ end
22
+
23
+ it 'returns the result if the URL matches the scraper regexp' do
24
+ expect(Earl['http://www.test.com/'].title).to eql :test_title
25
+ end
26
+ end
27
+
28
+ describe 'When retrieving the response' do
29
+ it 'returns a Nokogiri document' do
30
+ expect(Earl['test'].response.css('html').size).to eql 1
31
+ end
32
+ end
33
+
34
+ describe 'Scraper inheritance' do
35
+ class SubScraper < Earl::Scraper
36
+ define_attribute :some_attribute do |doc|
37
+ doc
38
+ end
39
+ end
40
+
41
+ it 'inherits all attributes from its superclass' do
42
+ scraper = SubScraper.new('foo.bar')
43
+ expect(scraper.attributes).to include(:title)
44
+ expect(scraper.attributes).to include(:description)
45
+ expect(scraper.attributes).to include(:image)
46
+ expect(scraper.attributes).to include(:some_attribute)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Earl do
6
+ before do
7
+ allow_any_instance_of(Earl).to receive(:uri_response).and_return(source)
8
+ end
9
+ let(:url) { 'http://mock.net' }
10
+ subject(:instance) { Earl[url] }
11
+
12
+ describe '#title' do
13
+ subject { instance.title }
14
+ context 'example with title tag' do
15
+ let(:source) { fixture(:bicycles) }
16
+ it { expect(subject).to eql('bicycles (bicycles) on Twitter') }
17
+ end
18
+ context 'youtube example with title tag' do
19
+ let(:source) { fixture(:youtube) }
20
+ it { expect(subject).to eql('YouTube - Symptoms of Swine Flu') }
21
+ end
22
+ end
23
+
24
+ describe '#description' do
25
+ subject { instance.description }
26
+ context 'example with description tag' do
27
+ let(:source) { fixture(:bicycles) }
28
+ it { expect(subject).to eql('I write business plans for a living and fiction to stay sane. I also try my hand at all sorts of creative side projects: painting, game dev, whiskey drinking..') }
29
+ end
30
+ context 'example without description tag' do
31
+ let(:source) { fixture(:bicycles_without_description) }
32
+ it { expect(subject).to be_nil }
33
+ end
34
+ end
35
+
36
+ describe '#image' do
37
+ subject { instance.image }
38
+ context 'example with image tag' do
39
+ let(:source) { fixture(:bicycles) }
40
+ it { expect(subject).to eql('http://assets0.twitter.com/images/loader.gif') }
41
+ end
42
+ context 'example without image tag' do
43
+ let(:source) { fixture(:bicycles_without_images) }
44
+ it { expect(subject).to be_nil }
45
+ end
46
+ end
47
+
48
+ describe '#attributes' do
49
+ subject { instance.attributes }
50
+ let(:source) { fixture(:bicycles) }
51
+ it 'is an array of expected elements' do
52
+ expect(subject).to be_an(Array)
53
+ %i[description title image].each do |attribute|
54
+ expect(subject).to include(attribute)
55
+ end
56
+ end
57
+ end
58
+
59
+ describe '#metadata' do
60
+ subject { instance.metadata }
61
+ let(:source) { fixture(:bicycles) }
62
+ it { expect(subject).to be_a(Hash) }
63
+ it 'has the expected elements' do
64
+ expect(subject).to eql({
65
+ title: 'bicycles (bicycles) on Twitter',
66
+ description: 'I write business plans for a living and fiction to stay sane. I also try my hand at all sorts of creative side projects: painting, game dev, whiskey drinking..',
67
+ image: 'http://assets0.twitter.com/images/loader.gif',
68
+ rss_feed: '/statuses/user_timeline/user_id.rss',
69
+ base_url: 'http://mock.net',
70
+ feed: '/statuses/user_timeline/user_id.rss'
71
+ })
72
+ end
73
+ end
74
+ end
metadata CHANGED
@@ -1,113 +1,141 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: earl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
5
- prerelease:
4
+ version: 2.0.0
6
5
  platform: ruby
7
6
  authors:
8
- - Jeremy Ruppel
9
- autorequire:
7
+ - teejayvanslyke
8
+ - Paul Gallagher
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-04-25 00:00:00.000000000 Z
11
+ date: 2025-07-29 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: treetop
14
+ name: nokogiri
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
- version: 1.4.10
19
+ version: '1.18'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: 1.4.10
26
+ version: '1.18'
30
27
  - !ruby/object:Gem::Dependency
31
- name: rspec
28
+ name: ruby-oembed
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
- version: 2.9.0
38
- type: :development
33
+ version: 0.18.1
34
+ type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
- version: 2.9.0
46
- description: What URI wishes it could look like
40
+ version: 0.18.1
41
+ description: URL metadata API
47
42
  email:
48
- - jeremy.ruppel@gmail.com
43
+ - tj@elctech.com
44
+ - gallagher.paul@gmail.com
49
45
  executables: []
50
46
  extensions: []
51
47
  extra_rdoc_files: []
52
48
  files:
53
- - .gitignore
54
- - .rvmrc
49
+ - ".github/workflows/ruby-tests.yml"
50
+ - ".gitignore"
51
+ - ".rubocop.yml"
52
+ - ".rubocop_todo.yml"
53
+ - ".ruby-gemset"
54
+ - ".ruby-version"
55
55
  - Gemfile
56
+ - Guardfile
56
57
  - LICENSE
57
58
  - README.md
58
59
  - Rakefile
59
60
  - earl.gemspec
60
61
  - lib/earl.rb
61
- - lib/earl/email_assembler.rb
62
- - lib/earl/email_entity.rb
63
- - lib/earl/email_parser.tt
64
- - lib/earl/entity_base.rb
65
- - lib/earl/hash_inquirer.rb
66
- - lib/earl/string_inquirer.rb
67
- - lib/earl/url_assembler.rb
68
- - lib/earl/url_entity.rb
69
- - lib/earl/url_parser.tt
62
+ - lib/earl/earl.rb
63
+ - lib/earl/scraper.rb
70
64
  - lib/earl/version.rb
71
- - spec/earl/earl_spec.rb
72
- - spec/earl/email_entity_spec.rb
73
- - spec/earl/email_parser_spec.rb
74
- - spec/earl/entity_base_spec.rb
75
- - spec/earl/hash_inquirer_spec.rb
76
- - spec/earl/string_inquirer_spec.rb
77
- - spec/earl/url_entity_spec.rb
78
- - spec/earl/url_parser_spec.rb
65
+ - spec/fixtures/bicycles.html
66
+ - spec/fixtures/bicycles_without_description.html
67
+ - spec/fixtures/bicycles_without_images.html
68
+ - spec/fixtures/cassettes/feed/is_atom_feed.yml
69
+ - spec/fixtures/cassettes/feed/is_rss_feed.yml
70
+ - spec/fixtures/cassettes/feed/no_feed.yml
71
+ - spec/fixtures/cassettes/feed/with_atom_and_rss_feed.yml
72
+ - spec/fixtures/cassettes/feed/with_rss_feed.yml
73
+ - spec/fixtures/cassettes/oembed/no_oembed.yml
74
+ - spec/fixtures/cassettes/oembed/youtube_oembed.yml
75
+ - spec/fixtures/page_as_atom.html
76
+ - spec/fixtures/page_as_rss.html
77
+ - spec/fixtures/page_with_atom_feed.html
78
+ - spec/fixtures/page_with_rss_and_atom_feeds.html
79
+ - spec/fixtures/page_with_rss_feed.html
80
+ - spec/fixtures/page_without_feeds.html
81
+ - spec/fixtures/youtube.html
82
+ - spec/integration/feed_spec.rb
83
+ - spec/integration/oembed_spec.rb
79
84
  - spec/spec_helper.rb
80
- homepage: https://github.com/remind101/earl
81
- licenses: []
82
- post_install_message:
85
+ - spec/support/fixtures.rb
86
+ - spec/support/vcr.rb
87
+ - spec/unit/earl/earl_spec.rb
88
+ - spec/unit/earl/feed_spec.rb
89
+ - spec/unit/earl/oembed_spec.rb
90
+ - spec/unit/earl/scraper_spec.rb
91
+ - spec/unit/earl_spec.rb
92
+ homepage: https://github.com/evendis/earl
93
+ licenses:
94
+ - MIT
95
+ metadata: {}
83
96
  rdoc_options: []
84
97
  require_paths:
85
98
  - lib
86
99
  required_ruby_version: !ruby/object:Gem::Requirement
87
- none: false
88
100
  requirements:
89
- - - ! '>='
101
+ - - ">="
90
102
  - !ruby/object:Gem::Version
91
- version: '0'
103
+ version: '3.0'
92
104
  required_rubygems_version: !ruby/object:Gem::Requirement
93
- none: false
94
105
  requirements:
95
- - - ! '>='
106
+ - - ">="
96
107
  - !ruby/object:Gem::Version
97
108
  version: '0'
98
109
  requirements: []
99
- rubyforge_project:
100
- rubygems_version: 1.8.19
101
- signing_key:
102
- specification_version: 3
103
- summary: What URI wishes it could look like
110
+ rubygems_version: 3.6.2
111
+ specification_version: 4
112
+ summary: URL metadata API for scraping titles, descriptions, images, and videos from
113
+ URLs
104
114
  test_files:
105
- - spec/earl/earl_spec.rb
106
- - spec/earl/email_entity_spec.rb
107
- - spec/earl/email_parser_spec.rb
108
- - spec/earl/entity_base_spec.rb
109
- - spec/earl/hash_inquirer_spec.rb
110
- - spec/earl/string_inquirer_spec.rb
111
- - spec/earl/url_entity_spec.rb
112
- - spec/earl/url_parser_spec.rb
115
+ - spec/fixtures/bicycles.html
116
+ - spec/fixtures/bicycles_without_description.html
117
+ - spec/fixtures/bicycles_without_images.html
118
+ - spec/fixtures/cassettes/feed/is_atom_feed.yml
119
+ - spec/fixtures/cassettes/feed/is_rss_feed.yml
120
+ - spec/fixtures/cassettes/feed/no_feed.yml
121
+ - spec/fixtures/cassettes/feed/with_atom_and_rss_feed.yml
122
+ - spec/fixtures/cassettes/feed/with_rss_feed.yml
123
+ - spec/fixtures/cassettes/oembed/no_oembed.yml
124
+ - spec/fixtures/cassettes/oembed/youtube_oembed.yml
125
+ - spec/fixtures/page_as_atom.html
126
+ - spec/fixtures/page_as_rss.html
127
+ - spec/fixtures/page_with_atom_feed.html
128
+ - spec/fixtures/page_with_rss_and_atom_feeds.html
129
+ - spec/fixtures/page_with_rss_feed.html
130
+ - spec/fixtures/page_without_feeds.html
131
+ - spec/fixtures/youtube.html
132
+ - spec/integration/feed_spec.rb
133
+ - spec/integration/oembed_spec.rb
113
134
  - spec/spec_helper.rb
135
+ - spec/support/fixtures.rb
136
+ - spec/support/vcr.rb
137
+ - spec/unit/earl/earl_spec.rb
138
+ - spec/unit/earl/feed_spec.rb
139
+ - spec/unit/earl/oembed_spec.rb
140
+ - spec/unit/earl/scraper_spec.rb
141
+ - spec/unit/earl_spec.rb