feedjira-podcast 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e920f641d84394882a25efd751ff461cd16bbf89
4
- data.tar.gz: 5b93125bc0612379a7f1860522285ca6901d2f98
3
+ metadata.gz: 2ec26cc9fb4659fdd60822fe789156df198d5ad3
4
+ data.tar.gz: d85cf9221e5dfb231ca61cfc58474a3765a288ae
5
5
  SHA512:
6
- metadata.gz: 0b76182e96816ea1ed6b189471610a8e34c26217f4c4150ebfb27614784c0dc0a89ec978a38f0493d55766740f6a038739321d23463ff567c85e01be8440c0f5
7
- data.tar.gz: 2d41af05dcface90980736ba4deee0a7c7de7f1ce2eab0d1c4404a19a7ec3dca32a0234e967ce7b42dc0155c2a782e71149601dc414261fe4d971fc2ef29f382
6
+ metadata.gz: c7935ac9352a2716082dca3a0db6498a372ec2eb99dcf80682da312b640d1e5e87f727147ebdf40e6f27de9ddbbb58b11f511e0d3c37e515a286d152154482d8
7
+ data.tar.gz: 8b998f9898ef191a8ddc6e46699eb7dffb93eccd4d0825bd26934e3aabec487527b2ffed078e2f71f273a09c302a5c32583bf8964f4504c94979819d897bfcf8
data/.gitignore CHANGED
@@ -8,3 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  /vendor/bundle/
11
+ /*.gem
data/README.md CHANGED
@@ -4,4 +4,64 @@
4
4
  [![Dependency Status](https://gemnasium.com/scour/feedjira-podcast.svg)](https://gemnasium.com/scour/feedjira-podcast)
5
5
  [![Build Status](https://travis-ci.org/scour/feedjira-podcast.svg)](https://travis-ci.org/scour/feedjira-podcast)
6
6
  [![Code Climate](https://codeclimate.com/github/scour/feedjira-podcast/badges/gpa.svg)](https://codeclimate.com/github/scour/feedjira-podcast)
7
- [![Coverage Status](https://coveralls.io/repos/scour/feedjira-podcast/badge.svg)](https://coveralls.io/r/scour/feedjira-podcast)
7
+ [![Coverage Status](https://coveralls.io/repos/scour/feedjira-podcast/badge.svg?branch=master)](https://coveralls.io/r/scour/feedjira-podcast?branch=master)
8
+
9
+ This is a highly opinionated RSS parser designed for working with podcast feeds. It is built on top of [Feedjira](http://feedjira.com/), but is not compatible with the parsers that ship with Feedjira and are normalized across a variety of feed formats. Feedjira::Podcast provides a number of features beyond basic feed parsing, including analysis of podcast feed best practices.
10
+
11
+ ## Usage
12
+
13
+ The Feedjira::Podcast gem tries to strike a balance between standard Ruby idioms, the RSS and podcast specs, and needing to deal with real-world feeds that may not behave as expected. For the most part, interacting with a parsed podcast feed should be straight forward.
14
+
15
+ This gem registers the podcast parser class with Feedjira, so `Feedjira::Feed.parse` and the other standard fetch/parse methods are generally the easiest ways to ingest feeds. For more information, see Feedjira's documentation.
16
+
17
+ ### Common Behaviors
18
+
19
+ #### Grouping
20
+
21
+ In nearly all cases, items, properties, etc can be accessed in a predictable way, according to familiar Ruby patterns. Any logical groupings (namespaces, multiple attributes on a single element, etc) that exist within the feeds are abstracted by the parser.
22
+
23
+ The parser creates nested `Struct` objects whenever necessary, allowing application code to read attributes at any depth without having to check for the existence of objects at each level.
24
+
25
+ **Examples**
26
+
27
+ ```ruby
28
+ @feed.itunes.image.href
29
+ @feed.feedburner.info.uri
30
+ @item.enclosure.type
31
+ ```
32
+
33
+ *(One exception to this is the `<atom:link rel="self">` element. Standard access would be `atom.link.self.href`, for example. In order to avoid using `self`, this can be accessed through `atom.link[:self].href`. This may be unnecessary, but it's an option if you would like to use it.)*
34
+
35
+ Regardless of the inclusion of those specific attributes, or even their parent elements, you can safely access those properties without needing `&&` or `.try`. This is true for all values that are exposed by the parser.
36
+
37
+ #### Naming
38
+
39
+ Most names either match their counterpart in the feed exactly (e.g. `description`, `author`), convert camel case to snake case (e.g. `pubDate` becomes `pub_date`), or transpose boolean attributes to question-mark-notation (e.g. `isPermaLink` becomes `perma_link?`, and `itunes:block` becomes `itunes.block?`).
40
+
41
+ In cases where an element can repeat in a given context, the accessor will be pluralized (e.g. `<category>` becomes `categories`) and the value is an array, even if only a single element exists in a given feed.
42
+
43
+ #### Typecasting
44
+
45
+ In nearly all cases the value types of podcast feed data is predictable. As such, the parser will cast values appropriately. In cases where a feed is malformed, the result of the type cast may be somewhat unpredictable, but no more so than the original data was. A bad value should never prevent parsing of the rest of the document, but it bust a specific value (e.g. a date that is human-readable but not parseable will end up as `nil` rather than fallback to an ambiguous `String` value).
46
+
47
+ Date values are parsed as `Time` objects, number values become `Float` objects, hrefs, URIs and URLs are parsed using [Addressable](https://github.com/sporkmonger/addressable), and boolean values will return `true` or `false.`
48
+
49
+ In the case of the `<itunes:explicit>` tag, there are three mutually exclusive options, `"yes"`, `"clean"`, and any other value (representing `"no"`). This element gets expanded to two properties through parsing, `explicit?` and `clean?`, allowing both to be simple boolean values.
50
+
51
+ The spec for the item `<guid>` indicates that the default value if no value is given for the `isPermaLink` attribute is `true`. It also states that when `isPermaLink` is true, the value of `<guid>` represents a URI (and that the client can choose to treat it that way or not). As such, whenever a `<guid>` is acting as a `permaLink`, whether implicitly or explicitly, the `guid` value will return an `Addressable::URI`. Only if `isPermaLink` has a value of `"false"` with `guid` return a string.
52
+
53
+ #### Validation
54
+
55
+ The parser will try its best to parse whatever data it has available, with a strong preference for data that meets the specs commonly used for podcast feeds. The library will provide additional information that you can use to decide how to handle the data produced by the parser, but the parser itself will never refuse a document based on deficiencies or invalid data.
56
+
57
+ Besides standard typecasting, the parser won't try to clean up any data. For example, many elements (such as `<description>`) explicitly allow only plaintext, but it is common for them to include markup in the wild. The parser will assume that markup to be plaintext, according to the spec. If you want to sanitize those parts of feeds, you should handle that on your end.
58
+
59
+ ### More Information
60
+
61
+ For more detailed information about specific aspects of feeds, how they are spec'd, and how they are handled by the parser, see the [wiki](https://github.com/scour/feedjira-podcast/wiki).
62
+
63
+ ## In Progress
64
+
65
+ Coverage of RSS, iTunes, and the other common constituents of podcast feeds is very high, but there are some bits that need to be addressed. Several rarely-used RSS elements (`<cloud>`, `<rating>`, etc) are not supported. Due to how they can be nested `<itunes:category>` is also a work in progress. Currently only top-level categories are available. More esoteric elements, such a host-specific tags, or various parts of Dublin Core, are added based on their prevalence in real world feeds.
66
+
67
+ Experimental feed elements may be added over time, but they should be used with caution until they reach a critical mass or become standardized.
@@ -13,7 +13,8 @@ module Feedjira
13
13
  elements :item, as: :items, class: PodcastItem
14
14
 
15
15
  def self.able_to_parse?(xml)
16
- # TODO Look for something podcast-specific
16
+ # TODO Look several something podcast-specific matches, especially
17
+ # to cover feeds that may not have any items yet
17
18
  (/\<rss|\<rdf/ =~ xml) && (/enclosure/ =~ xml)
18
19
  end
19
20
  end
@@ -10,7 +10,7 @@ module Feedjira
10
10
  block == 'yes'
11
11
  end
12
12
 
13
- # base.element :"itunes:category", as: :itunes_author
13
+ base.elements :"itunes:category", as: :itunes_categories, class: AppleCategory
14
14
 
15
15
  base.element :"itunes:image", as: :itunes_image_href, value: :href do |href|
16
16
  Addressable::URI.parse(href)
@@ -34,7 +34,7 @@ module Feedjira
34
34
  @itunes ||= Struct.new(
35
35
  :author,
36
36
  :block?,
37
- # :category,
37
+ :categories,
38
38
  :image,
39
39
  :explicit?,
40
40
  :clean?,
@@ -46,7 +46,7 @@ module Feedjira
46
46
  ).new(
47
47
  itunes_author,
48
48
  itunes_block,
49
- # itunes_category,
49
+ itunes_categories,
50
50
  itunes_image,
51
51
  itunes_explicit,
52
52
  itunes_clean,
@@ -0,0 +1,15 @@
1
+ module Feedjira
2
+ module Podcast
3
+ module Channel
4
+ class AppleCategory
5
+ include SAXMachine
6
+ include FeedUtilities
7
+
8
+ attribute :text
9
+
10
+ element :"itunes:category", as: :subcategory, class: AppleSubcategory
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module Feedjira
2
+ module Podcast
3
+ module Channel
4
+ class AppleSubcategory
5
+ include SAXMachine
6
+ include FeedUtilities
7
+
8
+ attribute :text
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -38,6 +38,12 @@ module Feedjira
38
38
  end
39
39
 
40
40
  # base.element :cloud
41
+ # A has five required attributes: domain is the domain name or IP
42
+ # address of the cloud, port is the TCP port that the cloud is running
43
+ # on, path is the location of its responder, registerProcedure is the
44
+ # name of the procedure to call to request notification, and protocol
45
+ # is xml-rpc, soap or http-post (case-sensitive), indicating which
46
+ # protocol is to be used.
41
47
 
42
48
  base.element :ttl do |ttl|
43
49
  ttl.to_f
@@ -57,8 +63,16 @@ module Feedjira
57
63
  end
58
64
 
59
65
  # base.element :rating
60
- # base.element :skipHours
61
- # base.element :skipDays
66
+ base.element :textInput, as: :text_input, class: TextInput, default: Struct.new(:title, :description, :name, :link).new
67
+ base.element :skipHours, as: :skip_hours, class: SkipHours
68
+ base.element :skipDays, as: :skip_days, class: SkipDays
69
+
70
+ def skip
71
+ @skip ||= Struct.new(:hours, :days).new(
72
+ skip_hours.hours,
73
+ skip_days.days
74
+ )
75
+ end
62
76
 
63
77
  end
64
78
  end
@@ -0,0 +1,18 @@
1
+ module Feedjira
2
+ module Podcast
3
+ module Channel
4
+ class SkipDays
5
+ include SAXMachine
6
+ include FeedUtilities
7
+
8
+ elements :day, as: :day do |day|
9
+ day.to_sym
10
+ end
11
+
12
+ def days
13
+ @days ||= day ? day : []
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module Feedjira
2
+ module Podcast
3
+ module Channel
4
+ class SkipHours
5
+ include SAXMachine
6
+ include FeedUtilities
7
+
8
+ elements :hour, as: :hour do |hour|
9
+ hour.to_f
10
+ end
11
+
12
+ def hours
13
+ @hours ||= hour ? hour : []
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module Feedjira
2
+ module Podcast
3
+ module Channel
4
+ class TextInput
5
+ include SAXMachine
6
+ include FeedUtilities
7
+
8
+ element :title
9
+ element :description
10
+ element :name
11
+
12
+ element :link do |link|
13
+ Addressable::URI.parse(link)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  module Feedjira
2
2
  module Podcast
3
- VERSION = "0.9.0"
3
+ VERSION = "0.9.1"
4
4
  end
5
5
  end
@@ -4,7 +4,12 @@ require 'addressable/uri'
4
4
  require 'feedjira/podcast/version'
5
5
 
6
6
  require 'feedjira/podcast/channel/image'
7
+ require 'feedjira/podcast/channel/skip_hours'
8
+ require 'feedjira/podcast/channel/skip_days'
9
+ require 'feedjira/podcast/channel/text_input'
7
10
  require 'feedjira/podcast/channel/apple_owner'
11
+ require 'feedjira/podcast/channel/apple_subcategory'
12
+ require 'feedjira/podcast/channel/apple_category'
8
13
 
9
14
  require 'feedjira/podcast/channel/required'
10
15
  require 'feedjira/podcast/channel/optional'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feedjira-podcast
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Kalafarski
@@ -114,12 +114,17 @@ files:
114
114
  - lib/feedjira/parser/podcast_item.rb
115
115
  - lib/feedjira/podcast.rb
116
116
  - lib/feedjira/podcast/channel/apple.rb
117
+ - lib/feedjira/podcast/channel/apple_category.rb
117
118
  - lib/feedjira/podcast/channel/apple_owner.rb
119
+ - lib/feedjira/podcast/channel/apple_subcategory.rb
118
120
  - lib/feedjira/podcast/channel/atom.rb
119
121
  - lib/feedjira/podcast/channel/feedburner.rb
120
122
  - lib/feedjira/podcast/channel/image.rb
121
123
  - lib/feedjira/podcast/channel/optional.rb
122
124
  - lib/feedjira/podcast/channel/required.rb
125
+ - lib/feedjira/podcast/channel/skip_days.rb
126
+ - lib/feedjira/podcast/channel/skip_hours.rb
127
+ - lib/feedjira/podcast/channel/text_input.rb
123
128
  - lib/feedjira/podcast/error.rb
124
129
  - lib/feedjira/podcast/item/apple.rb
125
130
  - lib/feedjira/podcast/item/content.rb