feedjira 3.2.2 → 3.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +17 -0
- data/.github/workflows/ruby.yml +2 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +0 -6
- data/.rubocop_todo.yml +28 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile +13 -3
- data/README.md +3 -3
- data/feedjira.gemspec +3 -12
- data/lib/feedjira/configuration.rb +1 -1
- data/lib/feedjira/core_ext/date.rb +0 -4
- data/lib/feedjira/core_ext/time.rb +3 -3
- data/lib/feedjira/feed_entry_utilities.rb +4 -5
- data/lib/feedjira/feed_utilities.rb +3 -7
- data/lib/feedjira/parser/json_feed.rb +5 -2
- data/lib/feedjira/version.rb +1 -1
- data/lib/feedjira.rb +0 -4
- data/spec/feedjira/core_ext/time_spec.rb +57 -0
- data/spec/feedjira/feed_spec.rb +39 -11
- data/spec/feedjira/feed_utilities_spec.rb +5 -3
- data/spec/feedjira/parser/json_feed_spec.rb +12 -0
- data/spec/feedjira_spec.rb +11 -1
- data/spec/sample_feeds/itunes_feedburner.xml +117 -0
- data/spec/sample_feeds/json_feed.json +2 -0
- data/spec/sample_feeds.rb +1 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/coverage.rb +10 -0
- metadata +19 -120
- data/lib/feedjira/date_time_utilities/date_time_epoch_parser.rb +0 -14
- data/lib/feedjira/date_time_utilities/date_time_language_parser.rb +0 -24
- data/lib/feedjira/date_time_utilities/date_time_pattern_parser.rb +0 -30
- data/lib/feedjira/date_time_utilities.rb +0 -30
- data/spec/feedjira/feed_utilities_date_time_spec.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12ef7af9ab5efeab944facbebb844c347458d7cc422927f0971f74606a0a57a3
|
4
|
+
data.tar.gz: 1d3c99b6799f173aaeea41b8e91f1e28c68cebfe59af92da0c32320c90d8ff20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c8527d5cfdc791d27cc970223575cdd4a75831d1665f63b7f650b733f4c9f7dadbd071ea3403c97a107d8cfbb930abc631a9428acadd3316f22e46802b7f2a2
|
7
|
+
data.tar.gz: b2710b27a649c0544e7f4f71a05117e96bc63c4fff9c3be0a7273ea4a173063b963e59dae9ed1c59aace5ca6319cb56f7012e994c9cecd8b2158f8931299bfbe
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
3
|
+
# Please see the documentation for all configuration options:
|
4
|
+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
5
|
+
|
6
|
+
version: 2
|
7
|
+
updates:
|
8
|
+
- package-ecosystem: "bundler" # See documentation for possible values
|
9
|
+
directory: "/" # Location of package manifests
|
10
|
+
schedule:
|
11
|
+
interval: "weekly"
|
12
|
+
assignees:
|
13
|
+
- "mockdeep"
|
14
|
+
groups:
|
15
|
+
all:
|
16
|
+
patterns:
|
17
|
+
- "*"
|
data/.github/workflows/ruby.yml
CHANGED
@@ -3,7 +3,7 @@ name: Ruby
|
|
3
3
|
on:
|
4
4
|
push:
|
5
5
|
branches:
|
6
|
-
-
|
6
|
+
- main
|
7
7
|
pull_request:
|
8
8
|
|
9
9
|
jobs:
|
@@ -12,7 +12,7 @@ jobs:
|
|
12
12
|
fail-fast: false
|
13
13
|
matrix:
|
14
14
|
os: [ubuntu]
|
15
|
-
ruby: [2.7, 3.0, 3.1]
|
15
|
+
ruby: [2.7, 3.0, 3.1, 3.2, 3.3]
|
16
16
|
handler: [nokogiri, ox, oga]
|
17
17
|
exclude:
|
18
18
|
- { ruby: jruby, handler: ox }
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -29,9 +29,6 @@ Layout/LineLength:
|
|
29
29
|
Exclude:
|
30
30
|
- 'spec/**/*.rb'
|
31
31
|
|
32
|
-
Style/AsciiComments:
|
33
|
-
Enabled: false
|
34
|
-
|
35
32
|
Style/IfUnlessModifier:
|
36
33
|
Enabled: false
|
37
34
|
|
@@ -59,8 +56,5 @@ RSpec/MultipleMemoizedHelpers:
|
|
59
56
|
RSpec/BeforeAfterAll:
|
60
57
|
Enabled: false
|
61
58
|
|
62
|
-
RSpec/VerifiedDoubles:
|
63
|
-
Enabled: false
|
64
|
-
|
65
59
|
RSpec/RepeatedExample:
|
66
60
|
Enabled: false
|
data/.rubocop_todo.yml
CHANGED
@@ -1,11 +1,35 @@
|
|
1
1
|
# This configuration was generated by
|
2
|
-
# `rubocop --auto-gen-config`
|
3
|
-
# on
|
2
|
+
# `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 400`
|
3
|
+
# on 2023-12-16 21:24:13 UTC using RuboCop version 1.59.0.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
8
|
|
9
|
-
# Offense count:
|
9
|
+
# Offense count: 16
|
10
|
+
# Configuration parameters: AllowedConstants.
|
10
11
|
Style/Documentation:
|
11
|
-
|
12
|
+
Exclude:
|
13
|
+
- 'spec/**/*'
|
14
|
+
- 'test/**/*'
|
15
|
+
- 'lib/feedjira/atom_entry_utilities.rb'
|
16
|
+
- 'lib/feedjira/core_ext/string.rb'
|
17
|
+
- 'lib/feedjira/core_ext/time.rb'
|
18
|
+
- 'lib/feedjira/feed.rb'
|
19
|
+
- 'lib/feedjira/feed_entry_utilities.rb'
|
20
|
+
- 'lib/feedjira/feed_utilities.rb'
|
21
|
+
- 'lib/feedjira/parser.rb'
|
22
|
+
- 'lib/feedjira/parser/atom_youtube_entry.rb'
|
23
|
+
- 'lib/feedjira/parser/globally_unique_identifier.rb'
|
24
|
+
- 'lib/feedjira/parser/google_docs_atom.rb'
|
25
|
+
- 'lib/feedjira/parser/google_docs_atom_entry.rb'
|
26
|
+
- 'lib/feedjira/parser/itunes_rss_owner.rb'
|
27
|
+
- 'lib/feedjira/parser/podlove_chapter.rb'
|
28
|
+
- 'lib/feedjira/preprocessor.rb'
|
29
|
+
- 'lib/feedjira/rss_entry_utilities.rb'
|
30
|
+
|
31
|
+
# Offense count: 1
|
32
|
+
# This cop supports safe autocorrection (--autocorrect).
|
33
|
+
Style/SuperWithArgsParentheses:
|
34
|
+
Exclude:
|
35
|
+
- 'lib/feedjira/feed_utilities.rb'
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
@@ -4,8 +4,18 @@ source "https://rubygems.org/"
|
|
4
4
|
|
5
5
|
gemspec
|
6
6
|
|
7
|
+
gem "faraday", "~> 2.8.1"
|
8
|
+
gem "pry", "~> 0.14.2"
|
9
|
+
gem "rspec", "~> 3.13.0"
|
10
|
+
gem "rubocop", "~> 1.60.1"
|
11
|
+
gem "rubocop-performance", "~> 1.20.0"
|
12
|
+
gem "rubocop-rake", "~> 0.6.0"
|
13
|
+
gem "rubocop-rspec", "~> 2.26.1"
|
14
|
+
gem "simplecov", "~> 0.22.0"
|
15
|
+
gem "yard", "~> 0.9.34"
|
16
|
+
|
7
17
|
group :test do
|
8
|
-
gem "oga"
|
9
|
-
gem "ox", platforms: %i[mri rbx]
|
10
|
-
gem "rake"
|
18
|
+
gem "oga", "~> 3.4"
|
19
|
+
gem "ox", "~> 2.14.17", platforms: %i[mri rbx]
|
20
|
+
gem "rake", "~> 13.1.0"
|
11
21
|
end
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# Feedjira
|
2
2
|
|
3
|
-
[![Build Status][
|
3
|
+
[![Build Status][actions-badge]][actions] [![Code Climate][code-climate-badge]][code-climate]
|
4
4
|
|
5
|
-
[
|
6
|
-
[
|
5
|
+
[actions-badge]: https://github.com/feedjira/feedjira/actions/workflows/ruby.yml/badge.svg?branch=main
|
6
|
+
[actions]: https://github.com/feedjira/feedjira/actions?query=branch%3Amain
|
7
7
|
[code-climate-badge]: https://codeclimate.com/github/feedjira/feedjira/badges/gpa.svg
|
8
8
|
[code-climate]: https://codeclimate.com/github/feedjira/feedjira
|
9
9
|
[gitter-badge]: https://badges.gitter.im/feedjira/feedjira.svg
|
data/feedjira.gemspec
CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.metadata = {
|
23
23
|
"homepage_uri" => "https://github.com/feedjira/feedjira",
|
24
24
|
"source_code_uri" => "https://github.com/feedjira/feedjira",
|
25
|
-
"changelog_uri" => "https://github.com/feedjira/feedjira/blob/
|
25
|
+
"changelog_uri" => "https://github.com/feedjira/feedjira/blob/main/CHANGELOG.md",
|
26
26
|
"rubygems_mfa_required" => "true"
|
27
27
|
}
|
28
28
|
|
@@ -31,15 +31,6 @@ Gem::Specification.new do |s|
|
|
31
31
|
|
32
32
|
s.required_ruby_version = ">=2.7"
|
33
33
|
|
34
|
-
s.
|
35
|
-
s.
|
36
|
-
|
37
|
-
s.add_development_dependency "faraday"
|
38
|
-
s.add_development_dependency "pry"
|
39
|
-
s.add_development_dependency "rspec"
|
40
|
-
s.add_development_dependency "rubocop"
|
41
|
-
s.add_development_dependency "rubocop-performance"
|
42
|
-
s.add_development_dependency "rubocop-rake"
|
43
|
-
s.add_development_dependency "rubocop-rspec"
|
44
|
-
s.add_development_dependency "yard"
|
34
|
+
s.add_runtime_dependency "loofah", ">= 2.3.1", "< 3"
|
35
|
+
s.add_runtime_dependency "sax-machine", ">= 1.0", "< 2"
|
45
36
|
end
|
@@ -59,13 +59,13 @@ module Feedjira
|
|
59
59
|
# @private
|
60
60
|
def default_parsers
|
61
61
|
[
|
62
|
+
Feedjira::Parser::ITunesRSS,
|
62
63
|
Feedjira::Parser::RSSFeedBurner,
|
63
64
|
Feedjira::Parser::GoogleDocsAtom,
|
64
65
|
Feedjira::Parser::AtomYoutube,
|
65
66
|
Feedjira::Parser::AtomFeedBurner,
|
66
67
|
Feedjira::Parser::AtomGoogleAlerts,
|
67
68
|
Feedjira::Parser::Atom,
|
68
|
-
Feedjira::Parser::ITunesRSS,
|
69
69
|
Feedjira::Parser::RSS,
|
70
70
|
Feedjira::Parser::JSONFeed
|
71
71
|
]
|
@@ -16,12 +16,12 @@ class Time
|
|
16
16
|
if datetime.is_a?(Time)
|
17
17
|
datetime.utc
|
18
18
|
elsif datetime.respond_to?(:to_datetime)
|
19
|
-
datetime.
|
20
|
-
|
19
|
+
datetime.to_time.utc
|
20
|
+
else
|
21
21
|
parse_string_safely datetime.to_s
|
22
22
|
end
|
23
23
|
rescue StandardError => e
|
24
|
-
Feedjira.logger.debug
|
24
|
+
Feedjira.logger.debug("Failed to parse time #{datetime}")
|
25
25
|
Feedjira.logger.debug(e)
|
26
26
|
nil
|
27
27
|
end
|
@@ -3,7 +3,6 @@
|
|
3
3
|
module Feedjira
|
4
4
|
module FeedEntryUtilities
|
5
5
|
include Enumerable
|
6
|
-
include DateTimeUtilities
|
7
6
|
|
8
7
|
def published
|
9
8
|
@published ||= @updated
|
@@ -12,8 +11,8 @@ module Feedjira
|
|
12
11
|
def parse_datetime(string)
|
13
12
|
DateTime.parse(string).feed_utils_to_gm_time
|
14
13
|
rescue StandardError => e
|
15
|
-
Feedjira.logger.
|
16
|
-
Feedjira.logger.
|
14
|
+
Feedjira.logger.debug("Failed to parse date #{string.inspect}")
|
15
|
+
Feedjira.logger.debug(e)
|
17
16
|
nil
|
18
17
|
end
|
19
18
|
|
@@ -64,11 +63,11 @@ module Feedjira
|
|
64
63
|
end
|
65
64
|
|
66
65
|
def [](field)
|
67
|
-
instance_variable_get("@#{field}")
|
66
|
+
instance_variable_get(:"@#{field}")
|
68
67
|
end
|
69
68
|
|
70
69
|
def []=(field, value)
|
71
|
-
instance_variable_set("@#{field}", value)
|
70
|
+
instance_variable_set(:"@#{field}", value)
|
72
71
|
end
|
73
72
|
end
|
74
73
|
end
|
@@ -41,11 +41,7 @@ module Feedjira
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def last_modified
|
44
|
-
@last_modified ||=
|
45
|
-
published = entries.reject { |e| e.published.nil? }
|
46
|
-
entry = published.max_by(&:published)
|
47
|
-
entry ? entry.published : nil
|
48
|
-
end
|
44
|
+
@last_modified ||= entries.reject { |e| e.published.nil? }.max_by(&:published)&.published
|
49
45
|
end
|
50
46
|
|
51
47
|
def updated?
|
@@ -78,7 +74,7 @@ module Feedjira
|
|
78
74
|
if old_value == new_value
|
79
75
|
false
|
80
76
|
else
|
81
|
-
send("#{name}=", new_value)
|
77
|
+
send(:"#{name}=", new_value)
|
82
78
|
true
|
83
79
|
end
|
84
80
|
end
|
@@ -95,7 +91,7 @@ module Feedjira
|
|
95
91
|
# entries just parsed and insert each one as a new entry until we get to
|
96
92
|
# one that has the same id as the the newest for the feed.
|
97
93
|
def find_new_entries_for(feed)
|
98
|
-
return feed.entries if entries.
|
94
|
+
return feed.entries if entries.empty?
|
99
95
|
|
100
96
|
latest_entry = entries.first
|
101
97
|
found_new_entries = []
|
@@ -15,8 +15,8 @@ module Feedjira
|
|
15
15
|
new(JSON.parse(json))
|
16
16
|
end
|
17
17
|
|
18
|
-
attr_reader :json, :version, :title, :url, :feed_url, :
|
19
|
-
:expired, :entries
|
18
|
+
attr_reader :json, :version, :title, :description, :url, :feed_url, :icon, :favicon,
|
19
|
+
:language, :expired, :entries
|
20
20
|
|
21
21
|
def initialize(json)
|
22
22
|
@json = json
|
@@ -24,7 +24,10 @@ module Feedjira
|
|
24
24
|
@title = json.fetch("title")
|
25
25
|
@url = json.fetch("home_page_url", nil)
|
26
26
|
@feed_url = json.fetch("feed_url", nil)
|
27
|
+
@icon = json.fetch("icon", nil)
|
28
|
+
@favicon = json.fetch("favicon", nil)
|
27
29
|
@description = json.fetch("description", nil)
|
30
|
+
@language = json.fetch("language", nil)
|
28
31
|
@expired = json.fetch("expired", nil)
|
29
32
|
@entries = parse_items(json["items"])
|
30
33
|
end
|
data/lib/feedjira/version.rb
CHANGED
data/lib/feedjira.rb
CHANGED
@@ -8,10 +8,6 @@ require "json"
|
|
8
8
|
|
9
9
|
require "feedjira/core_ext"
|
10
10
|
require "feedjira/configuration"
|
11
|
-
require "feedjira/date_time_utilities/date_time_epoch_parser"
|
12
|
-
require "feedjira/date_time_utilities/date_time_language_parser"
|
13
|
-
require "feedjira/date_time_utilities/date_time_pattern_parser"
|
14
|
-
require "feedjira/date_time_utilities"
|
15
11
|
require "feedjira/feed_entry_utilities"
|
16
12
|
require "feedjira/feed_utilities"
|
17
13
|
require "feedjira/feed"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Time do
|
6
|
+
describe "#parse_safely" do
|
7
|
+
it "returns the datetime in utc when given a Time" do
|
8
|
+
time = described_class.now
|
9
|
+
|
10
|
+
expect(described_class.parse_safely(time)).to eq(time.utc)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns the datetime in utc when given a Date" do
|
14
|
+
date = Date.today
|
15
|
+
|
16
|
+
expect(described_class.parse_safely(date)).to eq(date.to_time.utc)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns the datetime in utc when given a String" do
|
20
|
+
timestamp = "2016-01-01 00:00:00"
|
21
|
+
|
22
|
+
expect(described_class.parse_safely(timestamp)).to eq(described_class.parse(timestamp).utc)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns nil when given an empty String" do
|
26
|
+
timestamp = ""
|
27
|
+
|
28
|
+
expect(described_class.parse_safely(timestamp)).to be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it "returns the the datetime in utc given a 14-digit time" do
|
32
|
+
time = described_class.now.utc
|
33
|
+
timestamp = time.strftime("%Y%m%d%H%M%S")
|
34
|
+
|
35
|
+
expect(described_class.parse_safely(timestamp)).to eq(time.floor)
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when given an invalid time string" do
|
39
|
+
it "returns nil" do
|
40
|
+
timestamp = "2016-51-51 00:00:00"
|
41
|
+
|
42
|
+
expect(described_class.parse_safely(timestamp)).to be_nil
|
43
|
+
end
|
44
|
+
|
45
|
+
it "logs an error" do
|
46
|
+
timestamp = "2016-51-51 00:00:00"
|
47
|
+
|
48
|
+
expect(Feedjira.logger)
|
49
|
+
.to receive(:debug).with("Failed to parse time #{timestamp}")
|
50
|
+
expect(Feedjira.logger)
|
51
|
+
.to receive(:debug).with(an_instance_of(ArgumentError))
|
52
|
+
|
53
|
+
described_class.parse_safely(timestamp)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/spec/feedjira/feed_spec.rb
CHANGED
@@ -2,17 +2,8 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
-
class Hell < StandardError; end
|
6
|
-
|
7
|
-
class FailParser
|
8
|
-
def self.parse(_xml)
|
9
|
-
yield "this parser always fails."
|
10
|
-
# on_failure.call
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
5
|
describe Feedjira::Feed do
|
15
|
-
describe "
|
6
|
+
describe ".add_common_feed_element" do
|
16
7
|
before(:all) do
|
17
8
|
described_class.add_common_feed_element("generator")
|
18
9
|
end
|
@@ -30,7 +21,25 @@ describe Feedjira::Feed do
|
|
30
21
|
end
|
31
22
|
end
|
32
23
|
|
33
|
-
describe "
|
24
|
+
describe ".add_common_feed_elements" do
|
25
|
+
before do
|
26
|
+
described_class.add_common_feed_elements(:foos)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "parses the added element out of Atom feeds" do
|
30
|
+
expect(Feedjira.parse(sample_wfw_feed).foos).to eq []
|
31
|
+
end
|
32
|
+
|
33
|
+
it "parses the added element out of Atom Feedburner feeds" do
|
34
|
+
expect(Feedjira::Parser::Atom.new).to respond_to(:foos)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "parses the added element out of RSS feeds" do
|
38
|
+
expect(Feedjira::Parser::RSS.new).to respond_to(:foos)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe ".add_common_feed_entry_element" do
|
34
43
|
before(:all) do
|
35
44
|
tag = "wfw:commentRss"
|
36
45
|
described_class.add_common_feed_entry_element tag, as: :comment_rss
|
@@ -49,4 +58,23 @@ describe Feedjira::Feed do
|
|
49
58
|
expect(Feedjira::Parser::RSSEntry.new).to respond_to(:comment_rss)
|
50
59
|
end
|
51
60
|
end
|
61
|
+
|
62
|
+
describe ".add_common_feed_entry_elements" do
|
63
|
+
before do
|
64
|
+
described_class.add_common_feed_entry_elements(:things)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "parses the added element out of Atom feeds entries" do
|
68
|
+
entry = Feedjira.parse(sample_wfw_feed).entries.first
|
69
|
+
expect(entry.things).to eq []
|
70
|
+
end
|
71
|
+
|
72
|
+
it "parses the added element out of Atom Feedburner feeds entries" do
|
73
|
+
expect(Feedjira::Parser::AtomEntry.new).to respond_to(:things)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "parses the added element out of RSS feeds entries" do
|
77
|
+
expect(Feedjira::Parser::RSSEntry.new).to respond_to(:things)
|
78
|
+
end
|
79
|
+
end
|
52
80
|
end
|
@@ -116,6 +116,7 @@ describe Feedjira::FeedUtilities do
|
|
116
116
|
it "updates the title if changed" do
|
117
117
|
@updated_feed.title = "new title"
|
118
118
|
@feed.update_from_feed(@updated_feed)
|
119
|
+
|
119
120
|
expect(@feed.title).to eq @updated_feed.title
|
120
121
|
expect(@feed).to be_updated
|
121
122
|
end
|
@@ -252,11 +253,12 @@ describe Feedjira::FeedUtilities do
|
|
252
253
|
let(:url_one) { "http://example.com/post_one.html" }
|
253
254
|
let(:url_two) { "http://example.com/post_two.html" }
|
254
255
|
|
255
|
-
let(:entry_one) {
|
256
|
-
|
256
|
+
let(:entry_one) { object_double(Feedjira::Parser::AtomEntry.new, entry_id: id_one, url: url_one) }
|
257
|
+
|
258
|
+
let(:entry_two) { object_double(Feedjira::Parser::AtomEntry.new, entry_id: id_two, url: url_two) }
|
257
259
|
|
258
260
|
let(:feed_one) { Feedjira::Parser::Atom.new }
|
259
|
-
let(:feed_two) {
|
261
|
+
let(:feed_two) { object_double(Feedjira::Parser::Atom.new, entries: [entry_two]) }
|
260
262
|
|
261
263
|
before do
|
262
264
|
stub_const("Feedjira::FeedUtilities::UPDATABLE_ATTRIBUTES", [])
|
@@ -43,6 +43,18 @@ module Feedjira
|
|
43
43
|
expect(@feed.description).to eq "Brent Simmons’s weblog."
|
44
44
|
end
|
45
45
|
|
46
|
+
it "parses the favicon" do
|
47
|
+
expect(@feed.favicon).to eq "http://inessential.com/favicon.ico"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "parses the icon" do
|
51
|
+
expect(@feed.icon).to eq "http://inessential.com/icon.png"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "parses the language" do
|
55
|
+
expect(@feed.language).to eq "en-US"
|
56
|
+
end
|
57
|
+
|
46
58
|
it "parses expired and return default (nil)" do
|
47
59
|
expect(@feed.expired).to be_nil
|
48
60
|
end
|
data/spec/feedjira_spec.rb
CHANGED
@@ -57,6 +57,16 @@ RSpec.describe Feedjira do
|
|
57
57
|
expect(feed.entries.size).to eq 3
|
58
58
|
end
|
59
59
|
|
60
|
+
it "parses an itunes feedburner feed" do
|
61
|
+
feed = described_class.parse(sample_itunes_feedburner_feed)
|
62
|
+
expect(feed.title).to eq "Welcome to Night Vale"
|
63
|
+
published = Time.parse_safely "2023-09-22 16:30:15 UTC"
|
64
|
+
expect(feed.entries.first.published).to eq published
|
65
|
+
expect(feed.entries.size).to eq 3
|
66
|
+
url = "https://www.podtrac.com/pts/redirect.mp3/dovetail.prxu.org/_/126/e3dafc45-a202-42d0-a55b-216e733a2d7a/2023_09_17_BTS_Episode_EXCERPT_v2.mp3"
|
67
|
+
expect(feed.entries.first.enclosure_url).to eq url
|
68
|
+
end
|
69
|
+
|
60
70
|
it "with nested dc:identifier it does not overwrite entry_id" do
|
61
71
|
feed = described_class.parse(sample_rss_feed_huffpost_ca)
|
62
72
|
expect(feed.title.strip).to eq "HuffPost Canada - Athena2 - All Posts"
|
@@ -66,7 +76,7 @@ RSpec.describe Feedjira do
|
|
66
76
|
end
|
67
77
|
|
68
78
|
it "does not fail if multiple published dates exist and some are unparseable" do
|
69
|
-
expect(described_class.logger).to receive(:
|
79
|
+
expect(described_class.logger).to receive(:debug).twice
|
70
80
|
|
71
81
|
feed = described_class.parse(sample_invalid_date_format_feed)
|
72
82
|
expect(feed.title).to eq "Invalid date format feed"
|
@@ -0,0 +1,117 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:media="http://search.yahoo.com/mrss/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:podcast="https://podcastindex.org/namespace/1.0" version="2.0">
|
3
|
+
<channel>
|
4
|
+
<title>Welcome to Night Vale</title>
|
5
|
+
<link>http://welcometonightvale.com</link>
|
6
|
+
<pubDate>Fri, 22 Sep 2023 16:30:15 -0000</pubDate>
|
7
|
+
<lastBuildDate>Fri, 29 Sep 2023 15:05:26 -0000</lastBuildDate>
|
8
|
+
<ttl>60</ttl>
|
9
|
+
<language>en</language>
|
10
|
+
<copyright>2016, Night Vale Presents</copyright>
|
11
|
+
<webMaster>help@prx.org (PRX)</webMaster>
|
12
|
+
<description>
|
13
|
+
<![CDATA[<p>Twice-monthly community updates for the small desert town of Night Vale...</p>]]>
|
14
|
+
</description>
|
15
|
+
<managingEditor>info@welcometonightvale.com (info@welcometonightvale.com)</managingEditor>
|
16
|
+
<generator>PRX Feeder v1.0.0</generator>
|
17
|
+
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
|
18
|
+
<image>
|
19
|
+
<url>https://f.prxu.org/126/images/bc7d203a-c0dd-46ec-956b-03bad13ba85e/nightvalelogo-web4.jpg</url>
|
20
|
+
<title>Welcome to Night Vale</title>
|
21
|
+
<link>http://welcometonightvale.com</link>
|
22
|
+
<width>1400</width>
|
23
|
+
<height>1400</height>
|
24
|
+
<description>Twice-monthly community updates for the small desert town of Night Vale, where every conspiracy theory is true.</description>
|
25
|
+
</image>
|
26
|
+
<atom:link href="https://feeds.feedburner.com/welcometonightvalepodcast" rel="self" type="application/rss+xml"/>
|
27
|
+
<itunes:author>Night Vale Presents</itunes:author>
|
28
|
+
<itunes:type>episodic</itunes:type>
|
29
|
+
<itunes:category text="Fiction">
|
30
|
+
<itunes:category text="Science Fiction"/>
|
31
|
+
</itunes:category>
|
32
|
+
<itunes:image href="https://f.prxu.org/126/images/1f749c5d-c83a-4db9-8112-a3245da49c54/nightvalelogo-web4.jpg"/>
|
33
|
+
<itunes:explicit>false</itunes:explicit>
|
34
|
+
<itunes:owner>
|
35
|
+
<itunes:email>info@welcometonightvale.com</itunes:email>
|
36
|
+
<itunes:name>Welcome to Night Vale</itunes:name>
|
37
|
+
</itunes:owner>
|
38
|
+
<itunes:subtitle>Twice-monthly community updates for the small desert town of Night Vale, where every conspiracy theory is true.</itunes:subtitle>
|
39
|
+
<itunes:summary>
|
40
|
+
<![CDATA[Twice-monthly community updates for the small desert town of Night Vale...]]>
|
41
|
+
</itunes:summary>
|
42
|
+
<itunes:keywords>cecil,commonplace,cranor,fink,lovecraft,neofuturists,night,nightvale,nightvaleradio,radio,vale,welcome</itunes:keywords>
|
43
|
+
<media:copyright>2016, Night Vale Presents</media:copyright>
|
44
|
+
<media:thumbnail url="https://f.prxu.org/126/images/bc7d203a-c0dd-46ec-956b-03bad13ba85e/nightvalelogo-web4.jpg"/>
|
45
|
+
<media:keywords>cecil,commonplace,cranor,fink,lovecraft,neofuturists,night,nightvale,nightvaleradio,radio,vale,welcome</media:keywords>
|
46
|
+
<media:category scheme="http://www.itunes.com/dtds/podcast-1.0.dtd">Fiction</media:category>
|
47
|
+
<item>
|
48
|
+
<guid isPermaLink="false">prx_126_e3dafc45-a202-42d0-a55b-216e733a2d7a</guid>
|
49
|
+
<title>Patreon Preview: Behind the Scenes (September 2023)</title>
|
50
|
+
<pubDate>Fri, 22 Sep 2023 16:30:15 -0000</pubDate>
|
51
|
+
<link>https://play.prx.org/listen?ge=prx_126_e3dafc45-a202-42d0-a55b-216e733a2d7a&uf=https%3A%2F%2Ffeeds.feedburner.com%2Fwelcometonightvalepodcast</link>
|
52
|
+
<description>
|
53
|
+
<![CDATA[<p>An excerpt from our most recent patreon Behind the Scenes episode...</p>]]>
|
54
|
+
</description>
|
55
|
+
<enclosure url="https://www.podtrac.com/pts/redirect.mp3/dovetail.prxu.org/_/126/e3dafc45-a202-42d0-a55b-216e733a2d7a/2023_09_17_BTS_Episode_EXCERPT_v2.mp3" type="audio/mpeg" length="7133938"/>
|
56
|
+
<itunes:subtitle>An excerpt from our most recent patreon Behind the Scenes episode</itunes:subtitle>
|
57
|
+
<itunes:episodeType>full</itunes:episodeType>
|
58
|
+
<itunes:duration>04:57</itunes:duration>
|
59
|
+
<category>
|
60
|
+
<![CDATA[adfree]]>
|
61
|
+
</category>
|
62
|
+
<itunes:author>Night Vale Presents</itunes:author>
|
63
|
+
<itunes:summary>
|
64
|
+
<![CDATA[An excerpt from our most recent patreon Behind the Scenes episode...]]>
|
65
|
+
</itunes:summary>
|
66
|
+
<itunes:image href="https://f.prxu.org/126/e3dafc45-a202-42d0-a55b-216e733a2d7a/images/6e990c53-0f6d-4806-8716-18cba0fedc8a/nightvalelogo_web4.jpg"/>
|
67
|
+
<media:content fileSize="7133938" type="audio/mpeg" url="https://www.podtrac.com/pts/redirect.mp3/dovetail.prxu.org/_/126/e3dafc45-a202-42d0-a55b-216e733a2d7a/2023_09_17_BTS_Episode_EXCERPT_v2.mp3"/>
|
68
|
+
<content:encoded>
|
69
|
+
<![CDATA[<p>An excerpt from our most recent patreon Behind the Scenes episode...]]>
|
70
|
+
</content:encoded>
|
71
|
+
</item>
|
72
|
+
<item>
|
73
|
+
<guid isPermaLink="false">prx_126_e650b67a-a572-4302-81f4-6223331fa429</guid>
|
74
|
+
<title>234 - The Boy</title>
|
75
|
+
<pubDate>Fri, 15 Sep 2023 04:00:00 -0000</pubDate>
|
76
|
+
<link>https://play.prx.org/listen?ge=prx_126_e650b67a-a572-4302-81f4-6223331fa429&uf=https%3A%2F%2Ffeeds.feedburner.com%2Fwelcometonightvalepodcast</link>
|
77
|
+
<description>
|
78
|
+
<![CDATA[<p>This morning we found a boy. He has no name, and no one knows who he is...</p>]]>
|
79
|
+
</description>
|
80
|
+
<enclosure url="https://www.podtrac.com/pts/redirect.mp3/dovetail.prxu.org/_/126/e650b67a-a572-4302-81f4-6223331fa429/nv234_intro.mp3" type="audio/mpeg" length="33024824"/>
|
81
|
+
<itunes:subtitle>This morning we found a boy. He has no name, and no one knows who he is.</itunes:subtitle>
|
82
|
+
<itunes:episodeType>full</itunes:episodeType>
|
83
|
+
<itunes:duration>22:55</itunes:duration>
|
84
|
+
<itunes:author>Night Vale Presents</itunes:author>
|
85
|
+
<itunes:summary>
|
86
|
+
<![CDATA[This morning we found a boy. He has no name, and no one knows who he is...]]>
|
87
|
+
</itunes:summary>
|
88
|
+
<itunes:image href="https://f.prxu.org/126/e650b67a-a572-4302-81f4-6223331fa429/images/9b91ed0e-9e8c-4e4c-93f1-d4fbe8014ad0/episodes60.jpg"/>
|
89
|
+
<media:content fileSize="33024824" type="audio/mpeg" url="https://www.podtrac.com/pts/redirect.mp3/dovetail.prxu.org/_/126/e650b67a-a572-4302-81f4-6223331fa429/nv234_intro.mp3"/>
|
90
|
+
<content:encoded>
|
91
|
+
<![CDATA[<p>This morning we found a boy. He has no name, and no one knows who he is.</p>]]>
|
92
|
+
</content:encoded>
|
93
|
+
</item>
|
94
|
+
<item>
|
95
|
+
<guid isPermaLink="false">prx_126_ee85d62d-87cb-4abc-8f08-b66ccdd2c103</guid>
|
96
|
+
<title>233 - Citizen Spotlight: The Vampire of Lombardi Street</title>
|
97
|
+
<pubDate>Fri, 01 Sep 2023 04:00:00 -0000</pubDate>
|
98
|
+
<link>https://play.prx.org/listen?ge=prx_126_ee85d62d-87cb-4abc-8f08-b66ccdd2c103&uf=https%3A%2F%2Ffeeds.feedburner.com%2Fwelcometonightvalepodcast</link>
|
99
|
+
<description>
|
100
|
+
<![CDATA[<p>Luca Albescu lives at 831 Lombardi Street, in a dilapidated Victorian mansion at the top of the hill.</p>]]>
|
101
|
+
</description>
|
102
|
+
<enclosure url="https://www.podtrac.com/pts/redirect.mp3/dovetail.prxu.org/_/126/ee85d62d-87cb-4abc-8f08-b66ccdd2c103/nv233_intro.mp3" type="audio/mpeg" length="41761016"/>
|
103
|
+
<itunes:subtitle>Luca Albescu lives at 831 Lombardi Street, in a dilapidated Victorian mansion at the top of the hill.</itunes:subtitle>
|
104
|
+
<itunes:episodeType>full</itunes:episodeType>
|
105
|
+
<itunes:duration>28:59</itunes:duration>
|
106
|
+
<itunes:author>Night Vale Presents</itunes:author>
|
107
|
+
<itunes:summary>
|
108
|
+
<![CDATA[Luca Albescu lives at 831 Lombardi Street, in a dilapidated Victorian mansion at the top of the hill.]]>
|
109
|
+
</itunes:summary>
|
110
|
+
<itunes:image href="https://f.prxu.org/126/ee85d62d-87cb-4abc-8f08-b66ccdd2c103/images/ad5453f1-3ccc-4384-be03-9a4a7558370b/episodes58.jpg"/>
|
111
|
+
<media:content fileSize="41761016" type="audio/mpeg" url="https://www.podtrac.com/pts/redirect.mp3/dovetail.prxu.org/_/126/ee85d62d-87cb-4abc-8f08-b66ccdd2c103/nv233_intro.mp3"/>
|
112
|
+
<content:encoded>
|
113
|
+
<![CDATA[<p>Luca Albescu lives at 831 Lombardi Street, in a dilapidated Victorian mansion at the top of the hill.</p>]]>
|
114
|
+
</content:encoded>
|
115
|
+
</item>
|
116
|
+
</channel>
|
117
|
+
</rss>
|
@@ -6,6 +6,8 @@
|
|
6
6
|
"feed_url": "http://inessential.com/feed.json",
|
7
7
|
"user_comment": "This feed allows you to read the posts from this site in any feed reader that supports the JSON Feed format. To add this feed to your reader, copy the following URL — http://inessential.com/feed.json — and add it your reader.",
|
8
8
|
"favicon": "http://inessential.com/favicon.ico",
|
9
|
+
"icon": "http://inessential.com/icon.png",
|
10
|
+
"language": "en-US",
|
9
11
|
"author": {
|
10
12
|
"name": "Brent Simmons",
|
11
13
|
"url": "http://inessential.com/",
|
data/spec/sample_feeds.rb
CHANGED
@@ -10,6 +10,7 @@ module SampleFeeds
|
|
10
10
|
sample_atom_feed_line_breaks: "AtomFeedWithSpacesAroundEquals.xml",
|
11
11
|
sample_atom_entry_content: "AmazonWebServicesBlogFirstEntryContent.xml",
|
12
12
|
sample_itunes_feed: "itunes.xml",
|
13
|
+
sample_itunes_feedburner_feed: "itunes_feedburner.xml",
|
13
14
|
sample_itunes_feed_with_single_quotes: "ITunesWithSingleQuotedAttributes.xml",
|
14
15
|
sample_itunes_feed_with_spaces: "ITunesWithSpacesInAttributes.xml",
|
15
16
|
sample_podlove_feed: "CRE.xml",
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feedjira
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Hess
|
@@ -14,7 +14,7 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date:
|
17
|
+
date: 2024-02-24 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
20
|
name: loofah
|
@@ -23,6 +23,9 @@ dependencies:
|
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: 2.3.1
|
26
|
+
- - "<"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '3'
|
26
29
|
type: :runtime
|
27
30
|
prerelease: false
|
28
31
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -30,6 +33,9 @@ dependencies:
|
|
30
33
|
- - ">="
|
31
34
|
- !ruby/object:Gem::Version
|
32
35
|
version: 2.3.1
|
36
|
+
- - "<"
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '3'
|
33
39
|
- !ruby/object:Gem::Dependency
|
34
40
|
name: sax-machine
|
35
41
|
requirement: !ruby/object:Gem::Requirement
|
@@ -37,6 +43,9 @@ dependencies:
|
|
37
43
|
- - ">="
|
38
44
|
- !ruby/object:Gem::Version
|
39
45
|
version: '1.0'
|
46
|
+
- - "<"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '2'
|
40
49
|
type: :runtime
|
41
50
|
prerelease: false
|
42
51
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -44,118 +53,9 @@ dependencies:
|
|
44
53
|
- - ">="
|
45
54
|
- !ruby/object:Gem::Version
|
46
55
|
version: '1.0'
|
47
|
-
-
|
48
|
-
name: faraday
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - ">="
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
54
|
-
type: :development
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - ">="
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '0'
|
61
|
-
- !ruby/object:Gem::Dependency
|
62
|
-
name: pry
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - ">="
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '0'
|
68
|
-
type: :development
|
69
|
-
prerelease: false
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - ">="
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '0'
|
75
|
-
- !ruby/object:Gem::Dependency
|
76
|
-
name: rspec
|
77
|
-
requirement: !ruby/object:Gem::Requirement
|
78
|
-
requirements:
|
79
|
-
- - ">="
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
version: '0'
|
82
|
-
type: :development
|
83
|
-
prerelease: false
|
84
|
-
version_requirements: !ruby/object:Gem::Requirement
|
85
|
-
requirements:
|
86
|
-
- - ">="
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version: '0'
|
89
|
-
- !ruby/object:Gem::Dependency
|
90
|
-
name: rubocop
|
91
|
-
requirement: !ruby/object:Gem::Requirement
|
92
|
-
requirements:
|
93
|
-
- - ">="
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
version: '0'
|
96
|
-
type: :development
|
97
|
-
prerelease: false
|
98
|
-
version_requirements: !ruby/object:Gem::Requirement
|
99
|
-
requirements:
|
100
|
-
- - ">="
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
version: '0'
|
103
|
-
- !ruby/object:Gem::Dependency
|
104
|
-
name: rubocop-performance
|
105
|
-
requirement: !ruby/object:Gem::Requirement
|
106
|
-
requirements:
|
107
|
-
- - ">="
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
version: '0'
|
110
|
-
type: :development
|
111
|
-
prerelease: false
|
112
|
-
version_requirements: !ruby/object:Gem::Requirement
|
113
|
-
requirements:
|
114
|
-
- - ">="
|
115
|
-
- !ruby/object:Gem::Version
|
116
|
-
version: '0'
|
117
|
-
- !ruby/object:Gem::Dependency
|
118
|
-
name: rubocop-rake
|
119
|
-
requirement: !ruby/object:Gem::Requirement
|
120
|
-
requirements:
|
121
|
-
- - ">="
|
122
|
-
- !ruby/object:Gem::Version
|
123
|
-
version: '0'
|
124
|
-
type: :development
|
125
|
-
prerelease: false
|
126
|
-
version_requirements: !ruby/object:Gem::Requirement
|
127
|
-
requirements:
|
128
|
-
- - ">="
|
129
|
-
- !ruby/object:Gem::Version
|
130
|
-
version: '0'
|
131
|
-
- !ruby/object:Gem::Dependency
|
132
|
-
name: rubocop-rspec
|
133
|
-
requirement: !ruby/object:Gem::Requirement
|
134
|
-
requirements:
|
135
|
-
- - ">="
|
136
|
-
- !ruby/object:Gem::Version
|
137
|
-
version: '0'
|
138
|
-
type: :development
|
139
|
-
prerelease: false
|
140
|
-
version_requirements: !ruby/object:Gem::Requirement
|
141
|
-
requirements:
|
142
|
-
- - ">="
|
143
|
-
- !ruby/object:Gem::Version
|
144
|
-
version: '0'
|
145
|
-
- !ruby/object:Gem::Dependency
|
146
|
-
name: yard
|
147
|
-
requirement: !ruby/object:Gem::Requirement
|
148
|
-
requirements:
|
149
|
-
- - ">="
|
150
|
-
- !ruby/object:Gem::Version
|
151
|
-
version: '0'
|
152
|
-
type: :development
|
153
|
-
prerelease: false
|
154
|
-
version_requirements: !ruby/object:Gem::Requirement
|
155
|
-
requirements:
|
156
|
-
- - ">="
|
56
|
+
- - "<"
|
157
57
|
- !ruby/object:Gem::Version
|
158
|
-
version: '
|
58
|
+
version: '2'
|
159
59
|
description:
|
160
60
|
email:
|
161
61
|
executables: []
|
@@ -164,6 +64,7 @@ extra_rdoc_files: []
|
|
164
64
|
files:
|
165
65
|
- ".github/ISSUE_TEMPLATE/feed-parsing.md"
|
166
66
|
- ".github/ISSUE_TEMPLATE/general-issue.md"
|
67
|
+
- ".github/dependabot.yml"
|
167
68
|
- ".github/workflows/ruby.yml"
|
168
69
|
- ".gitignore"
|
169
70
|
- ".rspec"
|
@@ -183,10 +84,6 @@ files:
|
|
183
84
|
- lib/feedjira/core_ext/date.rb
|
184
85
|
- lib/feedjira/core_ext/string.rb
|
185
86
|
- lib/feedjira/core_ext/time.rb
|
186
|
-
- lib/feedjira/date_time_utilities.rb
|
187
|
-
- lib/feedjira/date_time_utilities/date_time_epoch_parser.rb
|
188
|
-
- lib/feedjira/date_time_utilities/date_time_language_parser.rb
|
189
|
-
- lib/feedjira/date_time_utilities/date_time_pattern_parser.rb
|
190
87
|
- lib/feedjira/feed.rb
|
191
88
|
- lib/feedjira/feed_entry_utilities.rb
|
192
89
|
- lib/feedjira/feed_utilities.rb
|
@@ -218,8 +115,8 @@ files:
|
|
218
115
|
- lib/feedjira/rss_entry_utilities.rb
|
219
116
|
- lib/feedjira/version.rb
|
220
117
|
- spec/feedjira/configuration_spec.rb
|
118
|
+
- spec/feedjira/core_ext/time_spec.rb
|
221
119
|
- spec/feedjira/feed_spec.rb
|
222
|
-
- spec/feedjira/feed_utilities_date_time_spec.rb
|
223
120
|
- spec/feedjira/feed_utilities_entry_spec.rb
|
224
121
|
- spec/feedjira/feed_utilities_spec.rb
|
225
122
|
- spec/feedjira/parser/atom_entry_spec.rb
|
@@ -282,17 +179,19 @@ files:
|
|
282
179
|
- spec/sample_feeds/atom_with_link_tag_for_url_unmarked.xml
|
283
180
|
- spec/sample_feeds/google_alerts_atom.xml
|
284
181
|
- spec/sample_feeds/itunes.xml
|
182
|
+
- spec/sample_feeds/itunes_feedburner.xml
|
285
183
|
- spec/sample_feeds/json_feed.json
|
286
184
|
- spec/sample_feeds/pet_atom.xml
|
287
185
|
- spec/sample_feeds/youtube_atom.xml
|
288
186
|
- spec/spec_helper.rb
|
187
|
+
- spec/support/coverage.rb
|
289
188
|
homepage: https://github.com/feedjira/feedjira
|
290
189
|
licenses:
|
291
190
|
- MIT
|
292
191
|
metadata:
|
293
192
|
homepage_uri: https://github.com/feedjira/feedjira
|
294
193
|
source_code_uri: https://github.com/feedjira/feedjira
|
295
|
-
changelog_uri: https://github.com/feedjira/feedjira/blob/
|
194
|
+
changelog_uri: https://github.com/feedjira/feedjira/blob/main/CHANGELOG.md
|
296
195
|
rubygems_mfa_required: 'true'
|
297
196
|
post_install_message:
|
298
197
|
rdoc_options: []
|
@@ -309,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
309
208
|
- !ruby/object:Gem::Version
|
310
209
|
version: '0'
|
311
210
|
requirements: []
|
312
|
-
rubygems_version: 3.4.
|
211
|
+
rubygems_version: 3.4.19
|
313
212
|
signing_key:
|
314
213
|
specification_version: 4
|
315
214
|
summary: A feed parsing library
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Feedjira
|
4
|
-
module DateTimeUtilities
|
5
|
-
class DateTimeEpochParser
|
6
|
-
def self.parse(string)
|
7
|
-
epoch_time = string.to_i
|
8
|
-
return Time.at(epoch_time).to_datetime if epoch_time.to_s == string
|
9
|
-
|
10
|
-
raise "#{string} is not a valid epoch time"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Feedjira
|
4
|
-
module DateTimeUtilities
|
5
|
-
class DateTimeLanguageParser
|
6
|
-
MONTHS_ENGLISH =
|
7
|
-
%w[Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec].freeze
|
8
|
-
MONTHS_SPANISH =
|
9
|
-
%w[Ene Feb Mar Abr May Jun Jul Ago Sep Oct Nov Dic].freeze
|
10
|
-
|
11
|
-
def self.parse(string)
|
12
|
-
DateTime.parse(translate(string))
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.translate(string)
|
16
|
-
MONTHS_SPANISH.each_with_index do |m, i|
|
17
|
-
rgx = Regexp.new("\s#{m}\s", Regexp::IGNORECASE)
|
18
|
-
return string.gsub(rgx, MONTHS_ENGLISH[i]) if string&.match?(rgx)
|
19
|
-
end
|
20
|
-
raise "No translation found for #{string}"
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Feedjira
|
4
|
-
module DateTimeUtilities
|
5
|
-
class DateTimePatternParser
|
6
|
-
# Japanese Symbols are required for strange Date Strings like
|
7
|
-
# '水, 31 8 2016 07:37:00 PDT'
|
8
|
-
JAPANESE_SYMBOLS = %w[日 月 火 水 木 金 土].freeze
|
9
|
-
PATTERNS = ["%m/%d/%Y %T %p", "%d %m %Y %T %Z"].freeze
|
10
|
-
|
11
|
-
def self.parse(string)
|
12
|
-
PATTERNS.each do |p|
|
13
|
-
datetime = DateTime.strptime(prepare(string), p)
|
14
|
-
return datetime
|
15
|
-
rescue StandardError => e
|
16
|
-
Feedjira.logger.debug("Failed to parse date #{string}")
|
17
|
-
Feedjira.logger.debug(e)
|
18
|
-
nil
|
19
|
-
end
|
20
|
-
raise "No pattern matched #{string}"
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.prepare(string)
|
24
|
-
rgx = Regexp.new("^(#{JAPANESE_SYMBOLS.join('|')}),\s")
|
25
|
-
string.gsub(rgx, "")
|
26
|
-
end
|
27
|
-
private_class_method :prepare
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Feedjira
|
4
|
-
module DateTimeUtilities
|
5
|
-
# This is our date parsing heuristic.
|
6
|
-
# Date Parsers are attempted in order.
|
7
|
-
DATE_PARSERS = [
|
8
|
-
DateTimePatternParser,
|
9
|
-
DateTimeLanguageParser,
|
10
|
-
DateTimeEpochParser,
|
11
|
-
DateTime
|
12
|
-
].freeze
|
13
|
-
|
14
|
-
# Parse the given string starting with the most common parser (default ruby)
|
15
|
-
# and going over all other available parsers
|
16
|
-
def parse_datetime(string)
|
17
|
-
res = DATE_PARSERS.detect do |parser|
|
18
|
-
return parser.parse(string).feed_utils_to_gm_time
|
19
|
-
rescue StandardError => e
|
20
|
-
Feedjira.logger.debug { "Failed to parse date #{string}" }
|
21
|
-
Feedjira.logger.debug(e)
|
22
|
-
nil
|
23
|
-
end
|
24
|
-
|
25
|
-
Feedjira.logger.warn { "Failed to parse date #{string}" } if res.nil?
|
26
|
-
|
27
|
-
res
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe Feedjira::FeedUtilities do
|
6
|
-
before do
|
7
|
-
@klass = Class.new do
|
8
|
-
include Feedjira::DateTimeUtilities
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
describe "handling dates" do
|
13
|
-
it "parses an ISO 8601 formatted datetime into Time" do
|
14
|
-
time = @klass.new.parse_datetime("2008-02-20T8:05:00-010:00")
|
15
|
-
expect(time.class).to eq Time
|
16
|
-
expect(time).to eq Time.parse_safely("Wed Feb 20 18:05:00 UTC 2008")
|
17
|
-
end
|
18
|
-
|
19
|
-
it "parses a ISO 8601 with milliseconds into Time" do
|
20
|
-
time = @klass.new.parse_datetime("2013-09-17T08:20:13.931-04:00")
|
21
|
-
expect(time.class).to eq Time
|
22
|
-
expect(time).to eq Time.strptime("Tue Sep 17 12:20:13.931 UTC 2013", "%a %b %d %H:%M:%S.%N %Z %Y")
|
23
|
-
end
|
24
|
-
|
25
|
-
it "parses a US Format into Time" do
|
26
|
-
time = @klass.new.parse_datetime("8/23/2016 12:29:58 PM")
|
27
|
-
expect(time.class).to eq Time
|
28
|
-
expect(time).to eq Time.parse_safely("Wed Aug 23 12:29:58 UTC 2016")
|
29
|
-
end
|
30
|
-
|
31
|
-
it "parses a Spanish Format into Time" do
|
32
|
-
time = @klass.new.parse_datetime("Wed, 31 Ago 2016 11:08:22 GMT")
|
33
|
-
expect(time.class).to eq Time
|
34
|
-
expect(time).to eq Time.parse_safely("Wed Aug 31 11:08:22 UTC 2016")
|
35
|
-
end
|
36
|
-
|
37
|
-
it "parses Format with japanese symbols into Time" do
|
38
|
-
time = @klass.new.parse_datetime("水, 31 8 2016 07:37:00 PDT")
|
39
|
-
expect(time.class).to eq Time
|
40
|
-
expect(time).to eq Time.parse_safely("Wed Aug 31 14:37:00 UTC 2016")
|
41
|
-
end
|
42
|
-
|
43
|
-
it "parses epoch into Time" do
|
44
|
-
time = @klass.new.parse_datetime("1472654220")
|
45
|
-
expect(time.class).to eq Time
|
46
|
-
expect(time).to eq Time.parse_safely("Wed Aug 31 14:37:00 UTC 2016")
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|