lifer 0.5.1 → 0.6.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
2
  SHA256:
3
- metadata.gz: a9ccb1942c2bb2b9cc5dafc28700275358f43579761c8039a621b082445da70d
4
- data.tar.gz: 48e0f8e204cc65fae8f1ddec4d10da85b9b7bb0d2f87a875d57896b54e4c02a6
3
+ metadata.gz: a9302b5310be7c9e07cf71edea4b464c6be7251ccf8753f508b308b51879bb8f
4
+ data.tar.gz: 82a9a1cf45a1a4e33c7a070527b3641d003af94c5b59089ec92194f288fb59fc
5
5
  SHA512:
6
- metadata.gz: 21497c604f22994484a1dfe7fe082052aa2cc07b9fe0bd27161046a346eb465caa6afdd2f1620fc1052b6cce19654523bcdf6371f97ca7d0643122f102079b26
7
- data.tar.gz: 58f941ae10d2a95157c20c88b4a7c657f3810f783441b09e4093f49008ee267182458387ed6b4e383e383889473d5a6a1fdf5e12d1725dfbb32f1de2e21d2dca
6
+ metadata.gz: 29c29c7d458205032517bd098e9e89a98ea0a7e3b5585eb14e2b46aa881779bcbac218ab2671054db5f7c408682e466cbeadc794a658b93f7d5f8fe91c42fb89
7
+ data.tar.gz: 4915942529c379b870f265699efce4493a0d532a0b686bc822850aa822450d811b964e2b9e20551931b92e118d2448308bd0ff1a586866901b585d8ae4fadbb0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ## Next
2
2
 
3
+ ## v0.6.0
4
+
5
+ This release contains improvements to RSS feed generation:
6
+
7
+ - Additonal settings per RSS feed (maximum feed item count and configurable
8
+ managing editor metadata).
9
+ - No more invalid `<managingEditor>` values. A default managing editor email is
10
+ now prefixed to the default collection author name for [W3C validated
11
+ feeds][w3c-feed-checker].
12
+
13
+ [w3c-feed-checker]: https://validator.w3.org/feed/check.cgi
14
+
3
15
  ## v0.5.1
4
16
 
5
17
  Resolved warnings output by `gem build`.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lifer (0.5.1)
4
+ lifer (0.6.0)
5
5
  i18n (< 2)
6
6
  kramdown (~> 2.4)
7
7
  liquid (~> 5.6, < 6)
@@ -1,14 +1,60 @@
1
1
  require "fileutils"
2
2
  require "rss"
3
3
 
4
- # Builds a simple RSS 2.0[1] feed using the Ruby standard library's RSS
4
+ # Builds a simple, UTF-8, RSS 2.0[1] feed using the Ruby standard library's RSS
5
5
  # features.
6
6
  #
7
+ # The features of the generated feed attempt to follow the recommendations for
8
+ # RSS feeds specified by RSS Board[2].
9
+ #
10
+ # The RSS builder can be configured in a number of ways:
11
+ #
12
+ # 1. Boolean
13
+ #
14
+ # Simply set `rss: true` or `rss: false` to enable or disable a feed for a
15
+ # collection. If `true`, an RSS feed will be built to `name-of-collection.xml`
16
+ #
17
+ # 2. Simple
18
+ #
19
+ # Simply set `rss: name-of-output-file.xml` to specify the name of the
20
+ # output XML file.
21
+ #
22
+ # 3. Fine-grained
23
+ #
24
+ # Provide an object under `rss:` for more fine-grained control over
25
+ # configuration. The following sub-settings are supported:
26
+ #
27
+ # - `count:` - The limit of RSS feed items that should be included in the
28
+ # output document. Leave unset or set to `0` to include all entries.
29
+ # - `managing_editor:` - the contents of the `<managingEditor>` node of the
30
+ # RSS document. When unset, Lifer builds a valid `<managingEditor>` value
31
+ # using the collection or root `author` value and a null email address to
32
+ # ensure that RSS feed validators are satisfied.
33
+ # - `url:` - the path to the filename of the output XML file.
34
+ #
7
35
  # [1]: https://www.rssboard.org/rss-specification
36
+ # [2]: https://www.rssboard.org/rss-profile
8
37
  #
9
38
  class Lifer::Builder::RSS < Lifer::Builder
39
+ # Because Lifer has no reason to have record of anyone's email address, we
40
+ # provide a non-email address so a <managingEditor> can be set and validated by
41
+ # RSS validators.
42
+ #
43
+ # Note that `.invalid` is a special-use TLD[1] that helps us indicate that the
44
+ # email address is definitely not real.
45
+ #
46
+ # [1]: https://datatracker.ietf.org/doc/html/rfc6761
47
+ #
48
+ DEFAULT_MANAGING_EDITOR_EMAIL = "editor@null.invalid"
49
+
10
50
  self.name = :rss
11
- self.settings = [:rss]
51
+ self.settings = [
52
+ rss: [
53
+ :count,
54
+ :managing_editor,
55
+ :url
56
+ ]
57
+ ]
12
58
 
13
59
  class << self
14
60
  # Traverses and renders an RSS feed for each feedable collection in the
@@ -35,8 +81,10 @@ class Lifer::Builder::RSS < Lifer::Builder
35
81
  File.open filename, "w" do |file|
36
82
  file.puts(
37
83
  rss_feed_for(collection) do |current_feed|
84
+ max_index = max_feed_items(collection) - 1
85
+
38
86
  collection.entries
39
- .select { |entry| entry.feedable? }
87
+ .select { |entry| entry.feedable? }[0..max_index]
40
88
  .each { |entry| rss_entry current_feed, entry }
41
89
  end.to_feed
42
90
  )
@@ -54,17 +102,75 @@ class Lifer::Builder::RSS < Lifer::Builder
54
102
  @root = root
55
103
  end
56
104
 
105
+ # According to the RSS Board, the recommended format for the
106
+ # `<managingEditor>` feed data is
107
+ #
108
+ # editor@example.com (Editor Name)
109
+ #
110
+ # Unfortunately, Lifer has no reason to have record of the editor's email
111
+ # address except for in RSS feeds, so if an `rss.managing_editor` is not
112
+ # configured we'll do our best to at provide information managing editor's
113
+ # that RSS feed validators are satisified with using other site configuration
114
+ # containing an author's name. Example output:
115
+ #
116
+ # editor@null.invalid (Configured Author Name)
117
+ #
118
+ # @param collection [Lifer::Collection]
119
+ # @return [String] The managing editor string for a `<managingEditor>` RSS
120
+ # feed field.
121
+ def managing_editor(collection)
122
+ editor = collection.setting(:rss, :managing_editor)
123
+
124
+ return editor if editor
125
+
126
+ "%s (%s)" % [
127
+ DEFAULT_MANAGING_EDITOR_EMAIL,
128
+ Lifer.setting(:author, collection: collection)
129
+ ]
130
+ end
131
+
132
+ # The amount of feed items to output to the RSS file. If set to 0, there is no
133
+ # max limit of feed items.
134
+ #
135
+ # @param collection [Lifer::Collection]
136
+ # @return [Integer]
137
+ def max_feed_items(collection) = Lifer.setting(:rss, :count, collection:) || 0
138
+
57
139
  def output_filename(collection)
58
- strict_mode = !collection.root?
140
+ strict = !collection.root?
59
141
 
60
- case collection.setting(:rss, strict: strict_mode)
142
+ case collection.setting(:rss, strict:)
61
143
  when FalseClass, NilClass then nil
62
- when TrueClass then File.join(Dir.pwd, "#{collection.name}.xml")
63
- else
64
- File.join Dir.pwd, collection.setting(:rss, strict: strict_mode)
144
+ when TrueClass
145
+ File.join Dir.pwd, "#{collection.name}.xml"
146
+ when Hash
147
+ File.join Dir.pwd, collection.setting(:rss, :url, strict:)
148
+ when String
149
+ File.join Dir.pwd, collection.setting(:rss, strict:)
65
150
  end
66
151
  end
67
152
 
153
+ # FIXME: Using the W3C feed validation checker[1], I found that RSS feed items
154
+ # generated by Lifer are missing some recommended functionality. Reports
155
+ #
156
+ # > This feed is valid, but interoperability with the widest range of feed
157
+ # > readers could be improved by implementing the following recommendations.
158
+ # >
159
+ # > An item should not include both pubDate and dc:date
160
+ # > (https://validator.w3.org/feed/docs/warning/DuplicateItemSemantics.html)
161
+ # >
162
+ # > item should contain a guid element
163
+ # > (https://validator.w3.org/feed/docs/warning/MissingGuid.html)
164
+ # >
165
+ # > content:encoded should not contain relative URL references
166
+ # > (https://validator.w3.org/feed/docs/warning/ContainsRelRef.html)
167
+ #
168
+ # Regarding the `<content:encoded>` field... this seems to be more closely
169
+ # related to our Markdown parser implementation than the RSS feed generation
170
+ # itself.
171
+ #
172
+ # [1]: https://validator.w3.org/feed/check.cgi
173
+ #
68
174
  def rss_entry(rss_feed, lifer_entry)
69
175
  rss_feed.maker.items.new_item do |rss_feed_item|
70
176
  if (authors = lifer_entry.authors).any?
@@ -79,6 +185,14 @@ class Lifer::Builder::RSS < Lifer::Builder
79
185
  end
80
186
  end
81
187
 
188
+ # FIXME: Using the W3C feed validation checker[1], I found that RSS feeds
189
+ # generated by Lifer are missing some recommended functionality. Reports:
190
+ #
191
+ # > Missing atom:link with rel="self"
192
+ # > (https://validator.w3.org/feed/docs/warning/MissingAtomSelfLink.html)
193
+ #
194
+ # [1]: https://validator.w3.org/feed/check.cgi
195
+ #
82
196
  def rss_feed_for(collection, &block)
83
197
  feed_object = nil
84
198
 
@@ -96,11 +210,8 @@ class Lifer::Builder::RSS < Lifer::Builder
96
210
  Lifer.setting(:rss, collection: collection)
97
211
  ]
98
212
 
99
- feed.channel.managingEditor =
100
- Lifer.setting(:site_default_author, collection: collection)
101
-
213
+ feed.channel.managingEditor = managing_editor(collection)
102
214
  feed.channel.title = Lifer.setting(:title, collection: collection)
103
-
104
215
  feed.channel.webMaster =
105
216
  Lifer.setting(:site_default_author, collection: collection)
106
217
 
data/lib/lifer/config.rb CHANGED
@@ -118,14 +118,14 @@ class Lifer::Config
118
118
  name_in_collection = name.dup.unshift(collection_name) if collection_name
119
119
 
120
120
  return if strict && collection_name.nil?
121
- return settings.dig(*name_in_collection) if (strict && collection_name)
121
+ return dig_from(settings, *name_in_collection) if (strict && collection_name)
122
122
 
123
123
  candidates = [
124
- settings.dig(*name),
125
- default_settings.dig(*name),
126
- DEFAULT_IMPLICIT_SETTINGS.dig(*name)
124
+ dig_from(settings, *name),
125
+ dig_from(default_settings, *name),
126
+ dig_from(DEFAULT_IMPLICIT_SETTINGS, *name)
127
127
  ]
128
- candidates.unshift settings.dig(*name_in_collection) if name_in_collection
128
+ candidates.unshift dig_from(settings, *name_in_collection) if name_in_collection
129
129
 
130
130
  candidates.detect &:itself
131
131
  end
@@ -173,6 +173,12 @@ class Lifer::Config
173
173
  Lifer::Utilities.symbolize_keys(YAML.load_file DEFAULT_CONFIG_FILE).to_h
174
174
  end
175
175
 
176
+ def dig_from(hash, *keys)
177
+ keys.reduce(hash) { |result, key|
178
+ result.is_a?(Hash) || result.is_a?(Array) ? result[key] : nil
179
+ }
180
+ end
181
+
176
182
  def has_collection_settings?(settings_key)
177
183
  confirmed_collections = collection_candidates & unregistered_settings.keys
178
184
 
@@ -119,6 +119,11 @@ class Lifer::Entry::Markdown < Lifer::Entry
119
119
 
120
120
  # The HTML representation of the Markdown entry as parsed by Kramdown.
121
121
  #
122
+ # FIXME: Before converting a Kramdown document to Markdown, we chould
123
+ # convert any relative URLs to absolute ones. This makes it more flexible to
124
+ # use HTML output where ever we want, especially in RSS feeds where feed
125
+ # readers may "wtf" a relative URL.
126
+ #
122
127
  # @return [String] The HTML for the body of the entry.
123
128
  def to_html
124
129
  Kramdown::Document.new(body).to_html
data/lib/lifer/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Lifer
2
- VERSION = "0.5.1"
2
+ VERSION = "0.6.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lifer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - benjamin wil
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-02-16 00:00:00.000000000 Z
11
+ date: 2025-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -207,8 +207,8 @@ licenses:
207
207
  - MIT
208
208
  metadata:
209
209
  allowed_push_host: https://rubygems.org
210
- homepage_uri: https://github.com/benjaminwil/lifer/blob/0.5.1/README.md
211
- source_code_uri: https://github.com/benjaminwil/lifer/tree/0.5.1
210
+ homepage_uri: https://github.com/benjaminwil/lifer/blob/0.6.0/README.md
211
+ source_code_uri: https://github.com/benjaminwil/lifer/tree/0.6.0
212
212
  changelog_uri: https://github.com/benjaminwil/lifer/blob/main/CHANGELOG.md
213
213
  post_install_message:
214
214
  rdoc_options: []