lifer 0.8.0 → 0.9.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: ea41a2cd1a058f5a103121b6b7641ce5857ec74300ecad4bb36ec33578170650
4
- data.tar.gz: f752dc7498a0457945d895fc591eefc7a27a296e01a5b547264a13fd8113c3b5
3
+ metadata.gz: 1b6414082e8f6f1d9b18034f2f227890b85ac73b22ab50c25cb2e350812c1a90
4
+ data.tar.gz: 5891afc57d102fd67422bf581edc4de839b05efbe10d104529a817391c0e7cad
5
5
  SHA512:
6
- metadata.gz: 4665579521538df261c0839f6c1a7ee6b24362ca75c03cc6d8fbf42dfffa028ad0bc39c1fe01ef2407459cb1be6bdf9d08e60cd5abacd1e233b0819bbcab6186
7
- data.tar.gz: e1bfbd9fa63bd2de10022f2b5810cfcf518acc5112f51bb843c19c936bc269436807a606c335ab90693bafac53569315b0bfcbe245b9c8570a56ff6ab60af6f0
6
+ metadata.gz: 7adb1041c558a2d60ef525bf1d12af4dd3d587a26f8ae0ef4e2f4c8fb9e04e14c648cf4bd72717aba143e747ccabe970ec1c859cd0c69b5259847887c0f99361
7
+ data.tar.gz: a9ec79fce82554f69ba1634ce414b7b63014c8545f8f8c5a6201c194d375d57d09a36128db4f6b242c279bfe0fe419f3b333034268415379c1b9138d372d352f
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  ## Next
2
2
 
3
+ ## v0.9.0
4
+
5
+ Atom feeds now support entries with both `#published_at` and `#updated_at`
6
+ timestamp. There is no standard equivalent way to provide this functonality for
7
+ RSS-format feeds, unfortunately. As part of this change, we removed all
8
+ `Entry#date` methods in favour of `Entry#published_at` onces. In Atom feeds, if
9
+ an article has no last updated date, the publication date is used instead.
10
+
11
+ Additionally, this release includes a new environment variable:
12
+ `LIFER_UNPARALLELIZED`. You can use this environment variable to run `lifer
13
+ build` or `lifer serve` without any parallelization turned on. This could be
14
+ useful for reproducing bugs and so on. Example usage:
15
+
16
+ LIFER_UNPARALLELIZED=1 lifer build
17
+
3
18
  ## v0.8.0
4
19
 
5
20
  ### Tags
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lifer (0.8.0)
4
+ lifer (0.9.0)
5
5
  i18n (< 2)
6
6
  kramdown (~> 2.4)
7
7
  liquid (~> 5.6, < 6)
@@ -44,7 +44,7 @@ GEM
44
44
  kramdown (2.5.1)
45
45
  rexml (>= 3.3.9)
46
46
  language_server-protocol (3.17.0.3)
47
- liquid (5.8.1)
47
+ liquid (5.8.2)
48
48
  bigdecimal
49
49
  strscan (>= 3.1.1)
50
50
  listen (3.9.0)
@@ -4,7 +4,9 @@ module Lifer::Builder::HTML::FromLiquid::Drops
4
4
  #
5
5
  # @example Usage
6
6
  # <h1>{{ entry.title }}</h1>
7
- # <small>Published on <datetime>{{ entry.date }}</datetime></small>
7
+ # <small>
8
+ # Published on <datetime>{{ entry.published_at }}</datetime>
9
+ # </small>
8
10
  #
9
11
  class EntryDrop < Liquid::Drop
10
12
  attr_accessor :lifer_entry, :collection
@@ -30,11 +32,6 @@ module Lifer::Builder::HTML::FromLiquid::Drops
30
32
  # @return [String]
31
33
  def content = (@content ||= lifer_entry.to_html)
32
34
 
33
- # The entry date (as a string).
34
- #
35
- # @return [String]
36
- def date = (@date ||= lifer_entry.date)
37
-
38
35
  # The entry frontmatter data.
39
36
  #
40
37
  # @return [FrontmatterDrop]
@@ -50,6 +47,11 @@ module Lifer::Builder::HTML::FromLiquid::Drops
50
47
  # @return [String] The entry permalink.
51
48
  def permalink = (@permalink ||= lifer_entry.permalink)
52
49
 
50
+ # The entry publication date (as a string).
51
+ #
52
+ # @return [String]
53
+ def published_at = (@published_at ||= lifer_entry.published_at)
54
+
53
55
  # The summary of the entry.
54
56
  #
55
57
  # @return [String] The summary of the entry.
@@ -59,5 +61,10 @@ module Lifer::Builder::HTML::FromLiquid::Drops
59
61
  #
60
62
  # @return [String] The entry title.
61
63
  def title = (@title ||= lifer_entry.title)
64
+
65
+ # The entry's last updated date (as a string).
66
+ #
67
+ # @return [String]
68
+ def updated_at = (@updated_at ||= lifer_entry.updated_at)
62
69
  end
63
70
  end
@@ -2,7 +2,7 @@
2
2
  # In many cases these utilities exist to be pseudo-compatible with Jekyll.
3
3
  #
4
4
  # @example A filter in a Liquid template.
5
- # {{ entry.date | date_to_xmlschema }}
5
+ # {{ entry.published_at | date_to_xmlschema }}
6
6
  #
7
7
  module Lifer::Builder::HTML::FromLiquid::Filters
8
8
  # @!visibility private
@@ -65,8 +65,7 @@ class Lifer::Builder::RSS < Lifer::Builder
65
65
  # The name of the format type, as needed by `RSS::Maker`, used by default by
66
66
  # this feed builder.
67
67
  #
68
- DEFAULT_MAkER_FORMAT_NAME = FORMATS[:rss]
69
-
68
+ DEFAULT_MAKER_FORMAT_NAME = FORMATS[:rss]
70
69
 
71
70
  self.name = :rss
72
71
  self.settings = [
@@ -96,7 +95,7 @@ class Lifer::Builder::RSS < Lifer::Builder
96
95
 
97
96
  return FORMATS[format] if FORMATS.keys.include? format
98
97
 
99
- DEFAULT_MAkER_FORMAT_NAME
98
+ DEFAULT_MAKER_FORMAT_NAME
100
99
  end
101
100
 
102
101
  # Traverses and renders an RSS feed for feedable collection.
@@ -220,8 +219,21 @@ class Lifer::Builder::RSS < Lifer::Builder
220
219
  rss_feed_item.link = lifer_entry.permalink
221
220
  rss_feed_item.title = lifer_entry.title
222
221
  rss_feed_item.summary = lifer_entry.summary
223
- rss_feed_item.updated = Time.now.to_s
224
- rss_feed_item.content_encoded = lifer_entry.to_html
222
+
223
+ if feed_format(lifer_entry.collection) == "atom"
224
+ rss_feed_item.content.content = lifer_entry.to_html
225
+ rss_feed_item.published = lifer_entry.published_at
226
+
227
+ # Note: RSS does not provide a standard way to share last updated
228
+ # timestamps at all, while Atom does. This is the reason there is no
229
+ # equivalent call in the condition for RSS feeds.
230
+ #
231
+ rss_feed_item.updated =
232
+ lifer_entry.updated_at(fallback: lifer_entry.published_at)
233
+ else
234
+ rss_feed_item.content_encoded = lifer_entry.to_html
235
+ rss_feed_item.pubDate = lifer_entry.published_at.to_time.rfc2822
236
+ end
225
237
  end
226
238
  end
227
239
 
@@ -57,9 +57,9 @@ class Lifer::Collection
57
57
  cached_entries_variable,
58
58
  case order
59
59
  when :latest
60
- @entries_collection.sort_by { |entry| entry.date }.reverse
60
+ @entries_collection.sort_by { |entry| entry.published_at }.reverse
61
61
  when :oldest
62
- @entries_collection.sort_by { |entry| entry.date }
62
+ @entries_collection.sort_by { |entry| entry.published_at }
63
63
  end
64
64
  )
65
65
  end
data/lib/lifer/entry.rb CHANGED
@@ -150,26 +150,6 @@ module Lifer
150
150
  full_text.gsub(FRONTMATTER_REGEX, "").strip
151
151
  end
152
152
 
153
- # Since text files would only store dates as simple strings, it's nice to
154
- # attempt to convert those into Ruby date or datetime objects.
155
- #
156
- # @return [Time] A Ruby representation of the date and time provided by the
157
- # entry frontmatter or filename.
158
- def date
159
- date_data = frontmatter[:date] || filename_date
160
-
161
- case date_data
162
- when Time then date_data
163
- when String then DateTime.parse(date_data).to_time
164
- else
165
- Lifer::Message.log("entry.no_date_metadata", filename: file)
166
- Lifer::Entry::DEFAULT_DATE
167
- end
168
- rescue ArgumentError => error
169
- Lifer::Message.error("entry.date_error", filename: file, error:)
170
- Lifer::Entry::DEFAULT_DATE
171
- end
172
-
173
153
  def feedable?
174
154
  if (setting = self.class.include_in_feeds).nil?
175
155
  raise NotImplementedError,
@@ -232,6 +212,27 @@ module Lifer
232
212
  # @return [String] The absolute URI path to the entry.
233
213
  def path = permalink(host: "/")
234
214
 
215
+ # The entry's publication date. The published date can be inferred in a few
216
+ # ways. The priority is:
217
+ #
218
+ # 1. the frontmatter's `published_at` field
219
+ # 2. the frontmatter's `published` field
220
+ # 3. the frontamtter's `date` field
221
+ # 4. The date in the filename.
222
+ #
223
+ # Since text files would only store dates as simple strings, it's nice to
224
+ # attempt to convert those into Ruby date or datetime objects.
225
+ #
226
+ # @return [Time] A Ruby representation of the date and time provided by the
227
+ # entry frontmatter or filename.
228
+ def published_at
229
+ date_for frontmatter[:published_at],
230
+ frontmatter[:published],
231
+ frontmatter[:date],
232
+ filename_date,
233
+ missing_metadata_translation_key: "entry.no_published_at_metadata"
234
+ end
235
+
235
236
  # If given a summary in the frontmatter of the entry, we can use this to
236
237
  # provide a summary.
237
238
  #
@@ -263,6 +264,26 @@ module Lifer
263
264
  raise NotImplementedError, I18n.t("shared.not_implemented_method")
264
265
  end
265
266
 
267
+ # The entry's last updated date. In the frontmatter, the last updated date
268
+ # can be specified using one of two fields. In priority order:
269
+ #
270
+ # 1. the `updated_at` field
271
+ # 2. the `updated` field
272
+ #
273
+ # The developer could set a fallback value as a fallback. For example, when
274
+ # building RSS feeds one might want the value of `#published_at` if there is
275
+ # no last updated date.
276
+ #
277
+ # @param fallback [Time, String, NilClass] Provide datetime data, a string
278
+ # that parses to a datetime object, or nil.
279
+ # @return [Time] A Ruby representation of the date and time provided by the
280
+ # entry frontmatter.
281
+ def updated_at(fallback: nil)
282
+ date_for frontmatter[:updated_at],
283
+ frontmatter[:updated],
284
+ default_date: fallback
285
+ end
286
+
266
287
  private
267
288
 
268
289
  # It is conventional for users to use spaces or commas to delimit tags in
@@ -278,6 +299,27 @@ module Lifer
278
299
  end.uniq
279
300
  end
280
301
 
302
+ def date_for(
303
+ *candidate_date_fields,
304
+ default_date: Lifer::Entry::DEFAULT_DATE,
305
+ missing_metadata_translation_key: nil
306
+ )
307
+ date_data = candidate_date_fields.detect(&:itself)
308
+
309
+ case date_data
310
+ when Time then date_data
311
+ when String then DateTime.parse(date_data).to_time
312
+ else
313
+ if (translation_string = missing_metadata_translation_key)
314
+ Lifer::Message.log(translation_string, filename: file)
315
+ end
316
+ default_date
317
+ end
318
+ rescue ArgumentError => error
319
+ Lifer::Message.error("entry.date_error", filename: file, error:)
320
+ default_date
321
+ end
322
+
281
323
  def filename_date
282
324
  return unless file && File.basename(file).match?(FILENAME_DATE_FORMAT)
283
325
 
@@ -76,7 +76,10 @@ module Lifer::Utilities
76
76
  # @raise [Exception] Any exception thrown by a child process.
77
77
  # @return [Array] The mapped results of the operation.
78
78
  def parallelized(collection, &block)
79
- results = Parallel.map(collection) do |collection_item|
79
+ options = {}
80
+ options[:in_threads] = 0 if Lifer.parallelism_disabled?
81
+
82
+ results = Parallel.map(collection, **options) do |collection_item|
80
83
  begin
81
84
  yield collection_item
82
85
  rescue => error
data/lib/lifer/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Lifer
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
data/lib/lifer.rb CHANGED
@@ -96,6 +96,16 @@ module Lifer
96
96
  # project would be built to.
97
97
  def output_directory = brain.output_directory
98
98
 
99
+ # Returns false if the Lifer project will be built with parallelism. This
100
+ # should return false almost always--unless you've explicitly set the
101
+ # `LIFER_UNPARALLELIZED` environment variable before running the program.
102
+ #
103
+ # This method is used internally by Lifer to determine whether features that
104
+ # would normally run in parallel should *not* run in parallel for some reason.
105
+ #
106
+ # @return [boolean] Returns whether parallelism is disabled.
107
+ def parallelism_disabled? = ENV["LIFER_UNPARALLELIZED"].is_a?(String)
108
+
99
109
  # Register new settings so that they are "safe" and can be read from a Lifer
100
110
  # configuration file. Unregistered settings are ignored.
101
111
  #
data/locales/en.yml CHANGED
@@ -33,7 +33,7 @@ en:
33
33
  date_error: "[%{filename}]: %{error}"
34
34
  feedable_error: >
35
35
  please set `%{entry_class}.include_in_feeds` to true or false
36
- no_date_metadata: "[%{filename}]: no date metadata"
36
+ no_published_at_metadata: "[%{filename}]: no `published_at` metadata"
37
37
  not_found: >
38
38
  file "%{file}" does not exist
39
39
  config:
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.8.0
4
+ version: 0.9.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-03-11 00:00:00.000000000 Z
11
+ date: 2025-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -210,8 +210,8 @@ licenses:
210
210
  - MIT
211
211
  metadata:
212
212
  allowed_push_host: https://rubygems.org
213
- homepage_uri: https://github.com/benjaminwil/lifer/blob/v0.8.0/README.md
214
- source_code_uri: https://github.com/benjaminwil/lifer/tree/v0.8.0
213
+ homepage_uri: https://github.com/benjaminwil/lifer/blob/v0.9.0/README.md
214
+ source_code_uri: https://github.com/benjaminwil/lifer/tree/v0.9.0
215
215
  changelog_uri: https://github.com/benjaminwil/lifer/blob/main/CHANGELOG.md
216
216
  post_install_message:
217
217
  rdoc_options: []