jekyll-notion 2.4.4 → 3.0.0.beta1

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: e44e3ab5a282cedcb01589e19fa93a7431123eda2ced53c3a0dd557f46cae968
4
- data.tar.gz: cc3f9c5a136cf4e763680ae96cbd916c654c95f71137c96ffb3fccadf8f93f80
3
+ metadata.gz: ed820907d9684cde0edb6ec147eec63f01c5d0c84ece59e2eae336ffeae89576
4
+ data.tar.gz: d1007a311273a529246618a538a658ac88e0ac688160294cd730053f721ddb46
5
5
  SHA512:
6
- metadata.gz: ebc8f23fff22e506f48b1cc91c54d50377bf7305697f3e97870183c1b718545d5bae2125ab9a4f6148895104494a5349931615596d5d7649b0b60bac5288c64c
7
- data.tar.gz: bb097aa7684dc69f6208d0d6bc373fc4b83d634aff15bfbdcf6595408c5ccd5a548611dcc470cbf024d2efc6a415c297dde94accc1b9653ab1a79beba3ec377a
6
+ metadata.gz: 7492e73cf69027072ce70e458446c27834344e33bccaab9d4e77b5f8f4d6703993b39bde77c96c29658ddfed93e69f49c23882bb4fe803148faa35ca78bca4a4
7
+ data.tar.gz: 3a0c7bf81c0c2ac03a1b46912dfbb1c499caf5db9621716bfb1a292c697a31dde4b50706b6b6558a9920da69c30ee95a5edf070d7803cd7befac8a20fd376508
data/README.md CHANGED
@@ -1,61 +1,94 @@
1
+ <img src="https://ik.imagekit.io/gxidvqvc9/jekyll_notion_logo_Thmlxy7GZ.png?updatedAt=1756230501479" width="200">
2
+
1
3
  # jekyll-notion
2
4
 
3
- Import notion pages to jekyll.
5
+ > [!WARNING]
6
+ > The **main branch** is under active development for version 3.
7
+ > For the current **stable release**, please check out the [v2.x.x branch](https://github.com/emoriarty/jekyll-notion/tree/v2.x.x).
4
8
 
5
- You can learn more about how to use jekyll-notion with the following links:
9
+ Import [Notion](https://www.notion.so) pages into
10
+ [Jekyll](https://jekyllrb.com/).
6
11
 
7
- * [Load notion pages in jekyll](https://enrq.me/dev/2022/03/20/load-notion-pages-in-jekyll/)
8
- * [Managing Jekyll posts in Notion](https://enrq.me/dev/2022/03/24/managing-jekyll-posts-in-notion/)
9
- * [Embedding videos with jekyll-notion](https://enrq.me/dev/2023/03/31/embedding-videos-with-jekyll-notion/)
12
+ 📚 Learn more with these guides:
13
+ - [Load Notion pages in
14
+ Jekyll](https://enrq.me/dev/2022/03/20/load-notion-pages-in-jekyll/)
15
+ - [Managing Jekyll posts in
16
+ Notion](https://enrq.me/dev/2022/03/24/managing-jekyll-posts-in-notion/)
17
+ - [Embedding videos with
18
+ jekyll-notion](https://enrq.me/dev/2023/03/31/embedding-videos-with-jekyll-notion/)
10
19
 
11
20
  ## Installation
12
21
 
13
- Use gem to install.
14
- ```bash
15
- $ gem install 'jekyll-notion'
22
+ Install via RubyGems:
23
+
24
+ ``` bash
25
+ gem install jekyll-notion
16
26
  ```
17
27
 
18
- Or add it to the `Gemfile`.
19
- ```ruby
28
+ Or add it to your `Gemfile`:
29
+
30
+ ``` ruby
20
31
  # Gemfile
21
32
  gem 'jekyll-notion'
22
33
  ```
23
34
 
24
- > [!IMPORTANT]
25
- > When using jekyll-archives, make sure that jekyll-notion is placed before jekyll-archives in the gemfile. Otherwise pages imported by jekyll-notion won't be collected by jekyll-archives. More info [here](https://github.com/emoriarty/jekyll-notion/issues/95#issuecomment-2732112458).
35
+ > \[!IMPORTANT\]\
36
+ > If you are using **jekyll-archives**, list `jekyll-notion` *before*
37
+ > `jekyll-archives` in the Gemfile. Otherwise, imported pages will not
38
+ > be picked up.\
39
+ > See the discussion
40
+ > [here](https://github.com/emoriarty/jekyll-notion/issues/95#issuecomment-2732112458).
26
41
 
27
- And update your jekyll plugins property in `_config.yml`.
42
+ Then enable the plugin in `_config.yml`:
28
43
 
29
- ```yml
44
+ ``` yaml
30
45
  plugins:
31
46
  - jekyll-notion
32
47
  ```
33
-
34
48
  ## Usage
35
49
 
36
- Before using the gem, create an integration and generate a secret token. For more in-depth instructions, refer to the Notion "Getting Started" [guide](https://developers.notion.com/docs/getting-started).
50
+ Before using the gem, [create a Notion
51
+ integration](https://developers.notion.com/docs/getting-started) and
52
+ generate a secret token.
37
53
 
38
- Once you have your secret token, make sure to export it into an environment variable named `NOTION_TOKEN`.
54
+ Export the token as an environment variable:
39
55
 
40
- ```bash
41
- $ export NOTION_TOKEN=<secret_...>
56
+ ``` bash
57
+ export NOTION_TOKEN=<secret_...>
58
+ ```
59
+
60
+ ### Environment Variables
61
+
62
+ The plugin supports the following environment variables for configuration:
63
+
64
+ - **`NOTION_TOKEN`** (required): Your Notion integration secret token
65
+ - **`JEKYLL_NOTION_CACHE`**: Fallback cache setting when not specified in `_config.yml` (`1`, `true`, `yes` to enable; `0`, `false`, `no` to disable)
66
+ - **`JEKYLL_NOTION_CACHE_DIR`**: Fallback cache directory when not specified in `_config.yml` (defaults to `.cache/jekyll-notion/vcr_cassettes`)
67
+
68
+ Example usage:
69
+ ``` bash
70
+ export NOTION_TOKEN=secret_abc123...
71
+ export JEKYLL_NOTION_CACHE=false
72
+ export JEKYLL_NOTION_CACHE_DIR=/tmp/my-custom-cache
42
73
  ```
43
74
 
44
75
  ### Databases
45
76
 
46
- Once the [notion database](https://developers.notion.com/docs/working-with-databases) has been shared, specify the database `id` in the `_config.yml` file as follows.
77
+ Share a [Notion
78
+ database](https://developers.notion.com/docs/working-with-databases),
79
+ then specify its `id` in `_config.yml`:
47
80
 
48
- ```yml
81
+ ``` yaml
49
82
  notion:
50
83
  databases:
51
84
  - id: 5cfed4de3bdc4f43ae8ba653a7a2219b
52
85
  ```
53
86
 
54
- By default, the notion pages in the database will be loaded into the `posts` collection.
87
+ By default, entries will be added to the `posts` collection.
55
88
 
56
- We can also define __multiple databases__ as follows.
89
+ You can also define **multiple databases**:
57
90
 
58
- ```yml
91
+ ``` yaml
59
92
  collections:
60
93
  - recipes
61
94
  - films
@@ -65,22 +98,26 @@ notion:
65
98
  - id: b0e688e199af4295ae80b67eb52f2e2f
66
99
  - id: 2190450d4cb34739a5c8340c4110fe21
67
100
  collection: recipes
68
- - id: e42383cd49754897b967ce453760499f
101
+ - id: e42383cd49754897b967ce453760499f
69
102
  collection: films
70
103
  ```
71
104
 
72
- After running `jekyll build` (or `serve`) command, the `posts`, `recipes` and `films` collections will be loaded with pages from the notion databases.
105
+ After running `jekyll build` or `jekyll serve`, the `posts`, `recipes`,
106
+ and `films` collections will contain pages from the specified databases.
73
107
 
74
108
  #### Database options
75
109
 
76
- Each dabatase support the following options.
110
+ Each database supports the following options:
77
111
 
78
- * `id`: the notion database unique identifier,
79
- * `collection`: the collection each page belongs to (posts by default),
80
- * `filter`: the database [filter property](https://developers.notion.com/reference/post-database-query-filter),
81
- * `sorts`: the database [sorts criteria](https://developers.notion.com/reference/post-database-query-sort),
112
+ - `id`: the unique Notion database ID
113
+ - `collection`: which collection to assign pages to (`posts` by
114
+ default)
115
+ - `filter`: a database
116
+ [filter](https://developers.notion.com/reference/post-database-query-filter)
117
+ - `sorts`: database [sorting
118
+ criteria](https://developers.notion.com/reference/post-database-query-sort)
82
119
 
83
- ```yml
120
+ ``` yaml
84
121
  notion:
85
122
  databases:
86
123
  - id: e42383cd49754897b967ce453760499f
@@ -89,25 +126,29 @@ notion:
89
126
  sorts: [{ "timestamp": "created_time", "direction": "ascending" }]
90
127
  ```
91
128
 
92
- #### Posts date
129
+ #### Post dates
93
130
 
94
- The `created_time` property of a notion page is used to set the date in the post filename. This is the date used for the `date` variable of the [predefined variables for posts](https://jekyllrb.com/docs/front-matter/#predefined-variables-for-posts).
131
+ By default, the Notion page `created_time` property sets the post
132
+ filename date. This value is used for Jekyll's [`date`
133
+ variable\`](https://jekyllrb.com/docs/front-matter/#predefined-variables-for-posts).
95
134
 
96
- It's important to note that the `created_time` cannot be modifed. However, if you wish to change the date of a post, you can create a new page property named "date" (or "Date"). This way, the posts collection will use the `date` property for the post date variable instead of the `created_time`.
135
+ Since `created_time` cannot be modified, you can override it by adding a
136
+ custom Notion property named `date` (or `Date`). That property will be
137
+ used instead.
97
138
 
98
139
  ### Pages
99
140
 
100
- Individual Notion pages can also be loaded into Jekyll. Just define the `page` property as follows.
141
+ You can also load individual Notion pages:
101
142
 
102
- ```yml
143
+ ``` yaml
103
144
  notion:
104
145
  pages:
105
146
  - id: 5cfed4de3bdc4f43ae8ba653a7a2219b
106
147
  ```
107
148
 
108
- As databases, we can set up multiple pages.
149
+ Multiple pages are supported:
109
150
 
110
- ```yaml
151
+ ``` yaml
111
152
  notion:
112
153
  pages:
113
154
  - id: e42383cd49754897b967ce453760499f
@@ -115,15 +156,19 @@ notion:
115
156
  - id: 2190450d4cb34739a5c8340c4110fe21
116
157
  ```
117
158
 
118
- The filename of the generated page is the notion page title. Check [below](#page-filename) for more info.
159
+ The generated filename is based on the Notion page title (see [Page
160
+ filename](#page-filename)).
119
161
 
120
- All properties assigned to a notion page will be interpreted by jekyll as front matter. For example, if the [permalink](https://jekyllrb.com/docs/permalinks/#front-matter) property is set to `/about/` in the notion page, jekyll will use it to create the corresponding path at the output directory at `/about/index.html`.
162
+ All page properties are exposed as Jekyll front matter. For example, if
163
+ a page has a `permalink` property set to `/about/`, Jekyll will generate
164
+ `/about/index.html`.
121
165
 
122
166
  ### Data
123
167
 
124
- Instead of storing the notion pages in a collection or in the pages list, you can assign them to the data object.Just declare the `data` property next to the page or database id.
168
+ Instead of adding Notion pages to collections or `pages`, you can store
169
+ them under the Jekyll **data object** using the `data` option:
125
170
 
126
- ```yml
171
+ ``` yaml
127
172
  notion:
128
173
  databases:
129
174
  - id: b0e688e199af4295ae80b67eb52f2e2f
@@ -135,93 +180,138 @@ notion:
135
180
  data: about
136
181
  ```
137
182
 
138
- Page properties and body of the notion page are stored as a hash object.
183
+ Each page is stored as a hash. The page body is available under the
184
+ `content` key.
139
185
 
140
- Data objects can be accessed as follows.
186
+ Example:
141
187
 
142
- ```html
188
+ ``` html
143
189
  <ul>
144
- {% for film in site.data.films %}
145
- <li>{{ film.title }}</li>
146
- {% endfor %}
190
+ {% for film in site.data.films %}
191
+ <li>{{ film.title }}</li>
192
+ {% endfor %}
147
193
  </ul>
148
- ```
149
-
150
- Notice, the page body is stored in the key `content`.
151
194
 
152
- ```html
153
195
  {{ site.data.about.content }}
154
196
  ```
155
197
 
156
- The rest of properties are mapped as expected. For more info go to [notion properties](#notion-properties).
198
+ Other properties are mapped normally (see [Notion
199
+ properties](#notion-properties)).
157
200
 
158
- ### Watch (Deprecated)
201
+ ### Cache
159
202
 
160
- _Use the cache mechanism instead._
203
+ All Notion requests are cached locally with the [VCR](https://github.com/vcr/vcr) gem to speed up rebuilds.
204
+ The first build fetches from the Notion API; subsequent builds reuse the cache.
161
205
 
162
- By default, databases are only requested during the first build. Subsequent builds use the results from the cache.
206
+ The cache mechanism provides:
163
207
 
164
- Set `fetch_on_watch` to true to allow request on each rebuild.
208
+ - Per-page cache files that include the Notion page title + ID, making them easy to identify.
209
+ - Page-level deletion: remove a single cached page without affecting others.
210
+ - Databases fetched on every rebuild: new content in Notion is always discovered, while cached pages prevent unnecessary re-fetches.
165
211
 
166
- ```yml
167
- notion:
168
- fetch_on_watch: true
169
- databases:
170
- - id: e42383cd49754897b967ce453760499f
212
+ **Example cached file (title + ID):**
213
+ ```bash
214
+ .cache/jekyll-notion/vcr_cassettes/my-page-title-e42383cd49754897b967ce453760499f.yml
171
215
  ```
172
216
 
173
- And that's all. Each page in the notion database will be included in the selected collection.
217
+ #### Cache folder
174
218
 
175
- ### Cache
219
+ Default: `.cache/jekyll-notion/vcr_cassettes`
176
220
 
177
- Starting from version 2.4.0, every request to Notion is cached locally. The cache enables the retrieval of Notion resources only during the first request. Subsequent requests are fetched from the cache, which can significantly reduce build times.
221
+ You can override the cache directory in two ways:
178
222
 
179
- The cache mechanism is based on the [vcr](https://github.com/vcr/vcr) gem, which records HTTP requests. Every Notion resource, whether it is a database or page, is stored in an independent file using the document ID as the filename. For example, a database ID e42383cd49754897b967ce453760499f will be stored in the following path:
223
+ **Option 1: Configuration file** (in `_config.yml`):
224
+ ``` yaml
225
+ notion:
226
+ cache_dir: another/folder
227
+ ```
180
228
 
181
- ```bash
182
- .cache/jekyll-notion/vcr_cassetes/e42383cd49754897b967ce453760499f.yml
229
+ **Option 2: Environment variable**:
230
+ ``` bash
231
+ export JEKYLL_NOTION_CACHE_DIR=/path/to/custom/cache
183
232
  ```
184
233
 
185
- **Note: The `cache` option invalidates the fetch_on_watch feature.**
234
+ The `_config.yml` setting takes precedence over the environment variable.
235
+ Both relative and absolute paths are supported - relative paths are resolved
236
+ from the project root.
186
237
 
187
- #### Cache folder
238
+ #### Cleaning the cache
239
+
240
+ - Delete the entire cache folder to reset everything.
241
+ - Or delete a single cached page file to refresh only that page.
242
+
243
+ #### Disabling the cache
188
244
 
189
- By default, the cache folder is `.cache/jekyll-notion/vcr_cassetes`, but you can change this folder by setting the `cache_dir` property in the `_config.yml` file as follows.
245
+ To disable caching entirely:
190
246
 
191
- ```yaml
247
+ ``` yaml
192
248
  notion:
193
- cache_dir: another/folder
249
+ cache: false
194
250
  ```
195
251
 
196
- The path must be relative to the working folder.
252
+ Or use the `JEKYLL_NOTION_CACHE` environment variable:
197
253
 
198
- #### Cleaning cache
254
+ ```bash
255
+ export JEKYLL_NOTION_CACHE=false # or 0, no
256
+ ```
199
257
 
200
- To clear the cache, delete the cache folder. If you want to remove a specific cache file, locate the file that matches the Notion resource ID and delete it.
258
+ ## Sensitive data
201
259
 
202
- #### Disabling cache
260
+ The cache stores full request and response payloads from the Notion API.
261
+ This may include sensitive information such as authentication tokens, URLs, or private content.
203
262
 
204
- If you're not interested in the cache or you just want to disable it, set the ˋcache` option to false.
263
+ If you intend to store cached files in version control or share them with others, be mindful of what they contain.
264
+ By default, jekyll-notion automatically redacts the `NOTION_TOKEN` from all cache files.
265
+ If you need to mask additional values, you can configure [VCR filters](https://benoittgt.github.io/vcr/#/configuration/filter_sensitive_data?id=filter-sensitive-data).
205
266
 
206
- ```yaml
207
- notion:
208
- cache: false
267
+ For example, add a file `_plugins/vcr_config.rb`:
268
+
269
+ ```ruby
270
+ VCR.configure do |config|
271
+ # Already handled by jekyll-notion: NOTION_TOKEN
272
+ # Example of masking a custom header or property:
273
+ config.filter_sensitive_data("[MASKED]") do |interaction|
274
+ interaction.request.headers["User-Agent"]&.first
275
+ end
276
+ end
209
277
  ```
210
278
 
279
+ This file will be automatically picked up by Jekyll and merged into the VCR configuration provided by jekyll-notion.
280
+
281
+ You can add filters for headers, query parameters, or any other values you don’t want exposed in the cache.
282
+
211
283
  ## Notion properties
212
284
 
213
- Notion page properties are set for each document in the front matter.
285
+ Notion page properties are mapped into each Jekyll document's front
286
+ matter.
214
287
 
215
- Please, refer to the [notion_to_md](https://github.com/emoriarty/notion_to_md/) gem to learn more.
288
+ See the companion gem
289
+ [notion_to_md](https://github.com/emoriarty/notion_to_md/) for details.
216
290
 
217
291
  ## Page filename
218
292
 
219
- There are two kinds of documents in Jekyll: posts and others.
293
+ Jekyll distinguishes between **posts** and **other documents**:
294
+
295
+ - **Posts**: filenames follow the format
296
+ `YEAR-MONTH-DAY-title.MARKUP`, where the date comes from the Notion
297
+ `created_time` (or the `date` property if present).\
298
+ - **Other documents**: filenames are derived from the Notion page
299
+ title.
300
+
301
+ ## Testing
220
302
 
221
- When the document is a post, the filename format contains the `created_time` property plus the page title as specified in [jekyll docs](https://jekyllrb.com/docs/posts/#creating-posts).
303
+ Run the test suite:
222
304
 
305
+ ```bash
306
+ bundle exec rspec # Run all tests
307
+ bundle exec rspec spec/path/to/test # Run specific test file
223
308
  ```
224
- YEAR-MONTH-DAY-title.MARKUP
309
+
310
+ ### Golden Files
311
+
312
+ Tests use golden files to validate generated output against known-good snapshots. Update snapshots when expected output changes:
313
+
314
+ ```bash
315
+ UPDATE_GOLDEN=1 bundle exec rspec
225
316
  ```
226
317
 
227
- The filename for any other document is the page title.
@@ -1,33 +1,64 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- #
3
+ require_relative "cassette_manager"
4
4
 
5
5
  module JekyllNotion
6
6
  module Cacheable
7
- def self.setup(cache_dir)
8
- # Using VCR to record and playback Notion API responses for caching
9
- VCR.configure do |config|
10
- config.cassette_library_dir = cache_path(cache_dir)
11
- config.hook_into :faraday # Faraday is used by notion-ruby-client gem
12
- config.filter_sensitive_data("<NOTION_TOKEN>") { ENV.fetch("NOTION_TOKEN", nil) }
13
- config.allow_http_connections_when_no_cassette = true
14
- config.default_cassette_options = {
15
- :allow_playback_repeats => true,
16
- :record => :new_episodes,
17
- }
7
+ class << self
8
+ def configure(cache_dir:, cache_enabled:)
9
+ @cache_dir = cache_dir
10
+ @cache_enabled = cache_enabled
11
+
12
+ configure_vcr
13
+ end
14
+
15
+ def cache_dir
16
+ # Always return VCR's configured directory to ensure consistency
17
+ # between CassetteManager operations and VCR cassette storage
18
+ VCR.configuration.cassette_library_dir
19
+ end
20
+
21
+ def enabled?
22
+ @cache_enabled
18
23
  end
19
- end
20
24
 
21
- def self.cache_path(path = nil)
22
- if path.nil?
23
- File.join(Dir.getwd, ".cache", "jekyll-notion", "vcr_cassettes")
24
- else
25
- File.join(Dir.getwd, path)
25
+ private
26
+
27
+ def configure_vcr
28
+ # Determine the directory to use based on configuration and environment
29
+ target_dir = @cache_dir || ENV["JEKYLL_NOTION_CACHE_DIR"] || File.join(Dir.pwd, ".cache",
30
+ "jekyll-notion", "vcr_cassettes")
31
+
32
+ VCR.configure do |config|
33
+ config.cassette_library_dir = target_dir
34
+ config.hook_into :faraday # Faraday is used by notion-ruby-client gem
35
+ config.filter_sensitive_data("<REDACTED>") { ENV.fetch("NOTION_TOKEN", nil) }
36
+ config.allow_http_connections_when_no_cassette = true
37
+ config.default_cassette_options = {
38
+ :allow_playback_repeats => true,
39
+ :record => :new_episodes,
40
+ }
41
+ end
26
42
  end
27
43
  end
28
44
 
29
- def generate(*args)
30
- VCR.use_cassette(resource_id) { super(*args) }
45
+ def call
46
+ return super unless JekyllNotion::Cacheable.enabled?
47
+
48
+ cassette_manager = CassetteManager.new(JekyllNotion::Cacheable.cache_dir)
49
+ cassette_name = cassette_manager.cassette_name_for(id)
50
+ result = nil
51
+
52
+ VCR.use_cassette(
53
+ cassette_name,
54
+ :record => :new_episodes,
55
+ :allow_playback_repeats => true
56
+ ) do
57
+ result = super
58
+ end
59
+
60
+ cassette_manager.update_after_call(id, result)
61
+ result
31
62
  end
32
63
  end
33
64
  end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "fileutils"
5
+
6
+ module JekyllNotion
7
+ class CassetteManager
8
+ INDEX_BASENAME = ".pages_index.yml"
9
+ PAGES_DIR = "pages"
10
+
11
+ def initialize(cache_dir)
12
+ @cache_dir = cache_dir
13
+ end
14
+
15
+ def cassette_name_for(id)
16
+ sanitized_id = sanitize_id(id)
17
+
18
+ # a) index mapping wins
19
+ if (pretty = load_index_yaml[sanitized_id]) && File.exist?(cassette_path(pretty))
20
+ return pretty
21
+ end
22
+
23
+ # b) any existing "*-id.yml" (handles prior runs / title changes)
24
+ if (found = find_existing_by_id(sanitized_id))
25
+ return found
26
+ end
27
+
28
+ # c) fallback to plain id (first run)
29
+ "#{PAGES_DIR}/#{sanitized_id}"
30
+ end
31
+
32
+ def update_after_call(id, result)
33
+ return unless (title = extract_title(result)).to_s != ""
34
+
35
+ sanitized_id = sanitize_id(id)
36
+ current_cassette = cassette_name_for(sanitized_id)
37
+ pretty_name = "#{PAGES_DIR}/#{sanitize_title(title)}-#{sanitized_id}"
38
+
39
+ rename_cassette_if_needed(:from => current_cassette, :to => pretty_name)
40
+ update_index_yaml(:id => sanitized_id, :pretty => pretty_name)
41
+ end
42
+
43
+ private
44
+
45
+ attr_reader :cache_dir
46
+
47
+ def cassette_path(name)
48
+ File.join(cache_dir, "#{name}.yml")
49
+ end
50
+
51
+ def find_existing_by_id(id)
52
+ matches = Dir[File.join(cache_dir, "pages", "*-#{id}.yml")]
53
+ return nil if matches.empty?
54
+
55
+ File.join(PAGES_DIR, File.basename(matches.first, ".yml"))
56
+ end
57
+
58
+ def rename_cassette_if_needed(from:, to:)
59
+ return if from == to
60
+
61
+ src = cassette_path(from)
62
+ dst = cassette_path(to)
63
+ return unless File.exist?(src)
64
+ return if File.exist?(dst)
65
+
66
+ FileUtils.mkdir_p(File.dirname(dst))
67
+ FileUtils.mv(src, dst)
68
+ rescue SystemCallError
69
+ nil
70
+ end
71
+
72
+ def index_path
73
+ File.join(cache_dir, INDEX_BASENAME)
74
+ end
75
+
76
+ def load_index_yaml
77
+ return {} unless File.exist?(index_path)
78
+
79
+ YAML.safe_load(File.read(index_path), :permitted_classes => [], :aliases => false) || {}
80
+ rescue Psych::SyntaxError
81
+ {}
82
+ end
83
+
84
+ def update_index_yaml(id:, pretty:)
85
+ idx = load_index_yaml
86
+ return if idx[id] == pretty
87
+
88
+ FileUtils.mkdir_p(File.dirname(index_path))
89
+ tmp = "#{index_path}.tmp"
90
+ idx[id] = pretty
91
+ File.write(tmp, idx.to_yaml)
92
+ FileUtils.mv(tmp, index_path)
93
+ end
94
+
95
+ def sanitize_title(str)
96
+ Jekyll::Utils.slugify(str)
97
+ end
98
+
99
+ def sanitize_id(id)
100
+ id.delete("-")
101
+ end
102
+
103
+ def extract_title(metadata)
104
+ metadata.title
105
+ end
106
+ end
107
+ end