perron 0.10.0 → 0.12.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 +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +3 -1
- data/README.md +108 -46
- data/app/helpers/meta_tags_helper.rb +1 -1
- data/lib/generators/content/content_generator.rb +25 -0
- data/lib/generators/content/templates/root.erb.tt +0 -1
- data/lib/generators/perron/install_generator.rb +6 -1
- data/lib/generators/perron/templates/README.md.tt +18 -1
- data/lib/generators/perron/templates/initializer.rb.tt +5 -2
- data/lib/perron/{site/collection.rb → collection.rb} +8 -2
- data/lib/perron/configuration.rb +4 -0
- data/lib/perron/{site/data.rb → data.rb} +16 -2
- data/lib/perron/feeds.rb +1 -0
- data/lib/perron/html_processor/syntax_highlight.rb +30 -0
- data/lib/perron/html_processor.rb +12 -8
- data/lib/perron/markdown.rb +6 -5
- data/lib/perron/metatags.rb +33 -59
- data/lib/perron/refinements/delete_suffixes.rb +11 -7
- data/lib/perron/{site/resource → resource}/class_methods.rb +5 -1
- data/lib/perron/resource/metadata.rb +67 -0
- data/lib/perron/{site/resource → resource}/publishable.rb +5 -5
- data/lib/perron/{site/resource → resource}/related.rb +2 -1
- data/lib/perron/{site/resource → resource}/separator.rb +5 -5
- data/lib/perron/resource/slug.rb +27 -0
- data/lib/perron/{site/resource.rb → resource.rb} +38 -14
- data/lib/perron/root.rb +1 -1
- data/lib/perron/site/builder/assets.rb +2 -1
- data/lib/perron/site/builder/feeds/json.rb +6 -4
- data/lib/perron/site/builder/feeds/rss.rb +6 -4
- data/lib/perron/site/builder/feeds.rb +2 -0
- data/lib/perron/site/builder/page.rb +5 -3
- data/lib/perron/site/builder/sitemap.rb +1 -0
- data/lib/perron/site/builder.rb +1 -1
- data/lib/perron/site.rb +3 -4
- data/lib/perron/version.rb +1 -1
- data/lib/perron.rb +1 -0
- data/perron.gemspec +1 -1
- metadata +18 -16
- data/lib/perron/site/resource/slug.rb +0 -24
- /data/lib/perron/{site/data → data}/proxy.rb +0 -0
- /data/lib/perron/{site/resource → resource}/configuration.rb +0 -0
- /data/lib/perron/{site/resource → resource}/core.rb +0 -0
- /data/lib/perron/{site/resource → resource}/related/stop_words.rb +0 -0
- /data/lib/perron/{site/resource → resource}/renderer.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70a9d142afefaac54496efbd93312cae38e14525b7f6310be576f74e7f9dfb4d
|
4
|
+
data.tar.gz: fd010ef141b72700120c926a104b8f33f72971d94e58ae01c8c793424d4c5319
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ab5c1d522c8645f3470451e74c7a5a3475f1a683d6dc953e88fd8fb123e4477558ae99839f2db4742741663c2957eec9d94696d05d7936aa1df14880a5d59a4
|
7
|
+
data.tar.gz: fb40411ad56556967b82396d1bb540766550e73131b9358f870f441c75bd1538c9ef071b3fcb4a6c371f389ee7a1a031c101c4e24cb76b9875b4841756a68dc7
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
perron (0.
|
4
|
+
perron (0.12.0)
|
5
5
|
csv
|
6
6
|
json
|
7
7
|
psych
|
@@ -204,6 +204,7 @@ GEM
|
|
204
204
|
regexp_parser (2.10.0)
|
205
205
|
reline (0.6.1)
|
206
206
|
io-console (~> 0.5)
|
207
|
+
rouge (4.6.0)
|
207
208
|
rubocop (1.75.8)
|
208
209
|
json (~> 2.3)
|
209
210
|
language_server-protocol (~> 3.17.0.2)
|
@@ -267,6 +268,7 @@ DEPENDENCIES
|
|
267
268
|
perron!
|
268
269
|
rails (~> 7.2.0)
|
269
270
|
rake (~> 13.3.0)
|
271
|
+
rouge (~> 4.6.0)
|
270
272
|
standard (~> 1.50.0)
|
271
273
|
|
272
274
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -13,7 +13,7 @@ A Rails-based static site generator.
|
|
13
13
|
</a>
|
14
14
|
|
15
15
|
|
16
|
-
## Getting
|
16
|
+
## Getting started
|
17
17
|
|
18
18
|
### Installation
|
19
19
|
|
@@ -38,7 +38,7 @@ end
|
|
38
38
|
|
39
39
|
## Mode
|
40
40
|
|
41
|
-
Perron can operate in two modes, configured via `config.mode`. This allows
|
41
|
+
Perron can operate in two modes, configured via `config.mode`. This allows a build to be either a full static site or be integrated pages in a dynamic Rails application.
|
42
42
|
|
43
43
|
| **Mode** | `:standalone` (default) | `:integrated` |
|
44
44
|
| :--- | :--- | :--- |
|
@@ -47,14 +47,14 @@ Perron can operate in two modes, configured via `config.mode`. This allows you t
|
|
47
47
|
| **Asset Handling** | Via Perron | Via Asset Pipeline |
|
48
48
|
|
49
49
|
|
50
|
-
##
|
50
|
+
## Collections
|
51
51
|
|
52
|
-
Perron is, just like Rails, designed with convention over configuration in mind. Content is stored in `app/content/*/*.{erb,md}
|
52
|
+
Perron is, just like Rails, designed with convention over configuration in mind. Content is stored in `app/content/*/*.{erb,md,*}` and backed by a class, located in `app/models/content/` that inherits from `Perron::Resource`.
|
53
53
|
|
54
54
|
The controllers are located in `app/controllers/content/`. To make them available, create a route: `resources :posts, module: :content, only: %w[index show]`.
|
55
55
|
|
56
56
|
|
57
|
-
###
|
57
|
+
### Create a new collection
|
58
58
|
|
59
59
|
```bash
|
60
60
|
bin/rails generate content Post
|
@@ -66,32 +66,82 @@ This will create the following files:
|
|
66
66
|
* `app/controllers/content/posts_controller.rb`
|
67
67
|
* `app/views/content/posts/index.html.erb`
|
68
68
|
* `app/views/content/posts/show.html.erb`
|
69
|
-
* Adds route: `resources :posts, module: :content, only: %w[index show]`
|
70
69
|
|
70
|
+
And adds a route: `resources :posts, module: :content, only: %w[index show]`
|
71
71
|
|
72
|
-
### Setting a Root Page
|
73
72
|
|
74
|
-
|
73
|
+
### Routes
|
74
|
+
|
75
|
+
Perron uses standard Rails routing, allowing the use of familiar route helpers. For a typical “clean slug”, the filename without extensions serves as the `id` parameter (slug).
|
76
|
+
```ruby
|
77
|
+
<%# For app/content/pages/about.md %>
|
78
|
+
<%= link_to "About Us", page_path("about") # => <a href="/about/">About Us</a> %>
|
79
|
+
```
|
80
|
+
|
81
|
+
To create files with specific extensions directly (e.g., `pricing.html`), the route must first be configured to treat the entire filename as the ID. In `config/routes.rb`, modify the generated `resources` line by adding a `constraints` option:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
# Change from…
|
85
|
+
resources :pages, path: "/", module: :content, only: %w[show]
|
86
|
+
|
87
|
+
# …to…
|
88
|
+
resources :pages, path: "/", module: :content, only: %w[show], constraints: { id: /[^\/]+/ }
|
89
|
+
```
|
90
|
+
|
91
|
+
With this change, a content file named `app/content/pages/pricing.html.erb` can be linked using the full filename. The builder will then create `pricing.html` in the output directory.
|
92
|
+
```ruby
|
93
|
+
<%= link_to "View Pricing", page_path("pricing", format: :html) # => <a href="/pricing.html">View Pricing</a> %>
|
94
|
+
```
|
75
95
|
|
76
|
-
This is automatically added when you create a `Page` collection.
|
77
96
|
|
97
|
+
### Setting a root page
|
78
98
|
|
79
|
-
|
99
|
+
To set a root page, include `Perron::Root` in your `Content::PagesController` and add a `app/content/pages/root.{md,erb,*}` file. Then add `root to: "content/pages#root"` add the bottom of your `config/routes.erb`.
|
100
|
+
|
101
|
+
This is automatically added for you when you create a `Page` collection.
|
102
|
+
|
103
|
+
|
104
|
+
## Markdown support
|
80
105
|
|
81
106
|
Perron supports markdown with the `markdownify` helper.
|
82
107
|
|
83
|
-
There are no markdown gems bundled by default, so you'll need to add one of these
|
108
|
+
There are no markdown gems bundled by default, so you'll need to add one of these to your `Gemfile`:
|
84
109
|
|
85
|
-
-
|
86
|
-
-
|
87
|
-
-
|
110
|
+
- `commonmarker`
|
111
|
+
- `kramdown`
|
112
|
+
- `redcarpet`
|
88
113
|
|
89
114
|
```bash
|
90
115
|
bundle add {commonmarker,kramdown,redcarpet}
|
91
116
|
```
|
92
117
|
|
118
|
+
### Configuration
|
93
119
|
|
94
|
-
|
120
|
+
To pass options to the parser, set `markdown_options` in `config/initializers/perron.rb`. The options hash is passed directly to the chosen library.
|
121
|
+
|
122
|
+
**Commonmarker**
|
123
|
+
```ruby
|
124
|
+
# Options are passed as keyword arguments.
|
125
|
+
Perron.configuration.markdown_options = { options: [:HARDBREAKS], extensions: [:table] }
|
126
|
+
```
|
127
|
+
|
128
|
+
**Kramdown**
|
129
|
+
```ruby
|
130
|
+
# Options are passed as a standard hash.
|
131
|
+
Perron.configuration.markdown_options = { input: "GFM", smart_quotes: "apos,quot" }
|
132
|
+
```
|
133
|
+
|
134
|
+
**Redcarpet**
|
135
|
+
```ruby
|
136
|
+
# Options are nested under :renderer_options and :markdown_options.
|
137
|
+
Perron.configuration.markdown_options = {
|
138
|
+
renderer_options: { hard_wrap: true },
|
139
|
+
markdown_options: { tables: true, autolink: true }
|
140
|
+
}
|
141
|
+
```
|
142
|
+
|
143
|
+
|
144
|
+
## HTML transformations
|
95
145
|
|
96
146
|
Perron can post-process the HTML generated from your Markdown content.
|
97
147
|
|
@@ -100,19 +150,20 @@ Perron can post-process the HTML generated from your Markdown content.
|
|
100
150
|
|
101
151
|
Apply transformations by passing an array of processor names or classes to the `markdownify` helper via the `process` option.
|
102
152
|
```erb
|
103
|
-
<%= markdownify @resource.content, process: %w[target_blank
|
153
|
+
<%= markdownify @resource.content, process: %w[lazy_load_images syntax_highlight target_blank] %>
|
104
154
|
```
|
105
155
|
|
106
156
|
|
107
|
-
### Available
|
157
|
+
### Available processors
|
108
158
|
|
109
159
|
The following processors are built-in and can be activated by passing their string name:
|
110
160
|
|
111
161
|
- `target_blank`: Adds `target="_blank"` to all external links;
|
112
162
|
- `lazy_load_images`: Adds `loading="lazy"` to all `<img>` tags.
|
163
|
+
- `syntax_highlight`: Applies syntax highlighting to fenced code blocks (e.g., \`\`\`ruby). This requires adding the `rouge` gem to your Gemfile (`bundle add rouge`). You will also need to include a Rouge CSS theme for colors to appear.
|
113
164
|
|
114
165
|
|
115
|
-
### Creating
|
166
|
+
### Creating your own processors
|
116
167
|
|
117
168
|
You can create your own processor by defining a class that inherits from `Perron::HtmlProcessor::Base` and implements a `process` method.
|
118
169
|
Then, pass the class constant directly in the `process` array.
|
@@ -184,19 +235,8 @@ Check out our amazing features:
|
|
184
235
|
<% end %>
|
185
236
|
```
|
186
237
|
|
187
|
-
**Result:**
|
188
|
-
```html
|
189
|
-
<p>Check out our amazing features:</p>
|
190
|
-
<ul>
|
191
|
-
<li>Rails based</li>
|
192
|
-
<li>SEO friendly</li>
|
193
|
-
<li>Markdown first</li>
|
194
|
-
<li>ERB support</li>
|
195
|
-
</ul>
|
196
|
-
```
|
197
|
-
|
198
238
|
|
199
|
-
## Data
|
239
|
+
## Data files
|
200
240
|
|
201
241
|
Perron can consume structured data from YML, JSON, or CSV files, making them available within your templates.
|
202
242
|
This is useful for populating features, team members, or any other repeated data structure.
|
@@ -211,12 +251,12 @@ To use a data file, instantiate `Perron::Site.data` with the basename of the fil
|
|
211
251
|
<% end %>
|
212
252
|
```
|
213
253
|
|
214
|
-
### File
|
254
|
+
### File location and formats
|
215
255
|
|
216
256
|
By default, Perron looks up `app/content/data/` for files with a `.yml`, `.json`, or `.csv` extension.
|
217
257
|
For a `features` call, it would find `features.yml`, `features.json`, or `features.csv`. You can also provide a path to any data file, via `Perron::Data.new("path/to/data.json")`.
|
218
258
|
|
219
|
-
### Accessing
|
259
|
+
### Accessing data
|
220
260
|
|
221
261
|
The wrapper object provides flexible, read-only access to each record's attributes. Both dot notation and hash-like key access are supported.
|
222
262
|
```ruby
|
@@ -224,6 +264,22 @@ feature.name
|
|
224
264
|
feature[:name]
|
225
265
|
```
|
226
266
|
|
267
|
+
### Rendering
|
268
|
+
|
269
|
+
You can render data collections directly using Rails-like partial rendering. When you call `render` on a data collection, Perron will automatically render a partial for each item.
|
270
|
+
```erb
|
271
|
+
<%= render Perron::Site.data.features %>
|
272
|
+
```
|
273
|
+
|
274
|
+
This expects a partial at `app/views/content/features/_feature.html.erb` that will be rendered once for each feature in your data file. The individual record is made available as a local variable matching the singular form of the collection name.
|
275
|
+
```erb
|
276
|
+
<!-- app/views/content/features/_feature.html.erb -->
|
277
|
+
<div class="feature">
|
278
|
+
<h4><%= feature.name %></h4>
|
279
|
+
<p><%= feature.description %></p>
|
280
|
+
</div>
|
281
|
+
```
|
282
|
+
|
227
283
|
|
228
284
|
## Feeds
|
229
285
|
|
@@ -260,9 +316,14 @@ Feeds are configured within the `Resource` class corresponding to a collection:
|
|
260
316
|
class Content::Post < Perron::Resource
|
261
317
|
configure do |config|
|
262
318
|
config.feeds.rss.enabled = true
|
319
|
+
# config.feeds.rss.title = "My RSS feed" # defaults to configured site_name
|
320
|
+
# config.feeds.rss.description = "My RSS feed description" # defaults to configured site_description
|
263
321
|
# config.feeds.rss.path = "path-to-feed.xml"
|
264
322
|
# config.feeds.rss.max_items = 25
|
323
|
+
#
|
265
324
|
config.feeds.json.enabled = true
|
325
|
+
# config.feeds.json.title = "My JSON feed" # defaults to configured site_name
|
326
|
+
# config.feeds.json.description = "My JSON feed description" # defaults to configured site_description
|
266
327
|
# config.feeds.json.max_items = 15
|
267
328
|
# config.feeds.json.path = "path-to-feed.json"
|
268
329
|
end
|
@@ -299,7 +360,7 @@ Or exclude certain tags:
|
|
299
360
|
|
300
361
|
Values are determined with the following precedence, from highest to lowest:
|
301
362
|
|
302
|
-
#### 1. Controller
|
363
|
+
#### 1. Controller action
|
303
364
|
|
304
365
|
Define a `@metadata` instance variable in your controller:
|
305
366
|
```ruby
|
@@ -314,10 +375,9 @@ class Content::PostsController < ApplicationController
|
|
314
375
|
end
|
315
376
|
```
|
316
377
|
|
317
|
-
#### 2. Page
|
378
|
+
#### 2. Page frontmatter
|
318
379
|
|
319
380
|
Add values to the YAML frontmatter in content files:
|
320
|
-
|
321
381
|
```yaml
|
322
382
|
---
|
323
383
|
title: My Awesome Post
|
@@ -331,17 +391,19 @@ Your content here…
|
|
331
391
|
|
332
392
|
#### 3. Collection configuration
|
333
393
|
|
334
|
-
Set
|
394
|
+
Set collection defaults in the resource model:
|
335
395
|
```ruby
|
336
396
|
class Content::Post < Perron::Resource
|
337
|
-
|
397
|
+
Perron.configure do |config|
|
398
|
+
# …
|
338
399
|
|
339
|
-
|
340
|
-
|
400
|
+
config.metadata.description = "Put your routine tasks on autopilot"
|
401
|
+
config.metadata.author = "Helptail team"
|
402
|
+
end
|
341
403
|
end
|
342
404
|
```
|
343
405
|
|
344
|
-
#### 4. Default
|
406
|
+
#### 4. Default values
|
345
407
|
|
346
408
|
Set site-wide defaults in the initializer:
|
347
409
|
```ruby
|
@@ -354,13 +416,13 @@ end
|
|
354
416
|
```
|
355
417
|
|
356
418
|
|
357
|
-
## Related
|
419
|
+
## Related resources
|
358
420
|
|
359
421
|
The `related_resources` method allows to find and display a list of similar resources
|
360
|
-
from the
|
422
|
+
from the sme collection. Similarity is calculated using the **[TF-IDF](https://en.wikipedia.org/wiki/Tf%E2%80%93idf)** algorithm on the content of each resource.
|
361
423
|
|
362
424
|
|
363
|
-
### Basic
|
425
|
+
### Basic usage
|
364
426
|
|
365
427
|
To get a list of the 5 most similar resources, call the method on any resource instance.
|
366
428
|
```ruby
|
@@ -372,9 +434,9 @@ To get a list of the 5 most similar resources, call the method on any resource i
|
|
372
434
|
```
|
373
435
|
|
374
436
|
|
375
|
-
## XML
|
437
|
+
## XML sitemap
|
376
438
|
|
377
|
-
A sitemap is
|
439
|
+
A sitemap is a XML file that lists all the pages of a website to help search engines discover and index content more efficiently, typically containing URLs, last modification dates, change frequency, and priority values.
|
378
440
|
|
379
441
|
Enable it with the following line in the Perron configuration:
|
380
442
|
```ruby
|
@@ -409,7 +471,7 @@ sitemap_change_frequency: :daily
|
|
409
471
|
```
|
410
472
|
|
411
473
|
|
412
|
-
## Building
|
474
|
+
## Building your static site
|
413
475
|
|
414
476
|
When in `standalone` mode and you're ready to generate your static site, run:
|
415
477
|
```bash
|
@@ -5,6 +5,8 @@ require "rails/generators/base"
|
|
5
5
|
class ContentGenerator < Rails::Generators::NamedBase
|
6
6
|
source_root File.expand_path("templates", __dir__)
|
7
7
|
|
8
|
+
class_option :force_plural, type: :boolean, default: false, desc: "Forces the use of a plural model name and class"
|
9
|
+
|
8
10
|
argument :actions, type: :array, default: %w[index show], desc: "Specify which actions to generate (index/show)"
|
9
11
|
|
10
12
|
def create_model
|
@@ -35,8 +37,23 @@ class ContentGenerator < Rails::Generators::NamedBase
|
|
35
37
|
route "resources :#{plural_file_name}, module: :content, only: %w[#{actions.join(" ")}]"
|
36
38
|
end
|
37
39
|
|
40
|
+
def add_root_route
|
41
|
+
return unless pages_controller?
|
42
|
+
return if root_route_exists?
|
43
|
+
|
44
|
+
inject_into_file "config/routes.rb", " root to: \"content/pages#show\"\n", before: /^\s*end\s*$/
|
45
|
+
end
|
46
|
+
|
38
47
|
private
|
39
48
|
|
49
|
+
def file_name
|
50
|
+
options[:force_plural] ? super.pluralize : super.singularize
|
51
|
+
end
|
52
|
+
|
53
|
+
def class_name
|
54
|
+
options[:force_plural] ? super.pluralize : super.singularize
|
55
|
+
end
|
56
|
+
|
40
57
|
def view_directory = Rails.root.join("app", "views", "content", plural_file_name)
|
41
58
|
|
42
59
|
def content_directory = Rails.root.join("app", "content", plural_file_name)
|
@@ -44,4 +61,12 @@ class ContentGenerator < Rails::Generators::NamedBase
|
|
44
61
|
def plural_class_name = plural_name.camelize
|
45
62
|
|
46
63
|
def pages_controller? = plural_file_name == "pages"
|
64
|
+
|
65
|
+
def root_route_exists?
|
66
|
+
routes = Rails.root.join("config", "routes.rb")
|
67
|
+
|
68
|
+
return false unless File.exist?(routes)
|
69
|
+
|
70
|
+
File.read(routes).match?(/\broot\s+to:/)
|
71
|
+
end
|
47
72
|
end
|
@@ -18,11 +18,16 @@ module Perron
|
|
18
18
|
def add_markdown_gems
|
19
19
|
append_to_file "Gemfile", <<~RUBY
|
20
20
|
|
21
|
-
# Perron
|
21
|
+
# Perron supports Markdown rendering using one of the following gems.
|
22
|
+
# Uncomment your preferred choice and run `bundle install`
|
22
23
|
# gem "commonmarker"
|
23
24
|
# gem "kramdown"
|
24
25
|
# gem "redcarpet"
|
25
26
|
RUBY
|
26
27
|
end
|
28
|
+
|
29
|
+
def gitignore_output_folder
|
30
|
+
append_to_file ".gitignore", "/#{Perron.configuration.output}/\n"
|
31
|
+
end
|
27
32
|
end
|
28
33
|
end
|
@@ -17,7 +17,7 @@ To use a data file, you can access it through the `Perron::Site.data` object fol
|
|
17
17
|
|
18
18
|
This is a convenient shorthand for `Perron::Data.new("features")`, which can also be used directly:
|
19
19
|
```ruby
|
20
|
-
|
20
|
+
|
21
21
|
<h4><%%= feature.name %></h4>
|
22
22
|
|
23
23
|
<p><%%= feature.description %></p>
|
@@ -38,3 +38,20 @@ The wrapper object provides flexible, read-only access to each record's attribut
|
|
38
38
|
feature.name
|
39
39
|
feature[:name]
|
40
40
|
```
|
41
|
+
|
42
|
+
|
43
|
+
## Rendering
|
44
|
+
|
45
|
+
You can render data collections directly using Rails-like partial rendering. When you call `render` on a data collection, Perron will automatically render a partial for each item.
|
46
|
+
```erb
|
47
|
+
<%= render Perron::Site.data.features %>
|
48
|
+
```
|
49
|
+
|
50
|
+
This expects a partial at `app/views/content/features/_feature.html.erb` that will be rendered once for each feature in your data file. The individual record is made available as a local variable matching the singular form of the collection name.
|
51
|
+
```erb
|
52
|
+
<!-- app/views/content/features/_feature.html.erb -->
|
53
|
+
<div class="feature">
|
54
|
+
<h4><%= feature.name %></h4>
|
55
|
+
<p><%= feature.description %></p>
|
56
|
+
</div>
|
57
|
+
```
|
@@ -3,14 +3,17 @@ Perron.configure do |config|
|
|
3
3
|
|
4
4
|
# config.site_name = "Helptail"
|
5
5
|
|
6
|
-
# The build mode for Perron. Can be :standalone or :integrated
|
6
|
+
# The build mode for Perron. Can be :standalone or :integrated
|
7
7
|
# config.mode = :standalone
|
8
8
|
|
9
|
-
# In `integrated` mode, the root is skipped by default. Set to `true` to enable
|
9
|
+
# In `integrated` mode, the root is skipped by default. Set to `true` to enable
|
10
10
|
# config.include_root = false
|
11
11
|
|
12
12
|
# config.default_url_options = {host: "helptail.com", protocol: "https", trailing_slash: true}
|
13
13
|
|
14
|
+
# The options hash is passed directly to the chosen library
|
15
|
+
# config.markdown_options = {}
|
16
|
+
|
14
17
|
# Set default meta values
|
15
18
|
# Examples:
|
16
19
|
# - `config.metadata.description = "Put your routine tasks on autopilot"`
|
@@ -5,14 +5,14 @@ module Perron
|
|
5
5
|
attr_reader :name
|
6
6
|
|
7
7
|
def initialize(name)
|
8
|
-
@name = name
|
8
|
+
@name = name.inquiry
|
9
9
|
@collection_path = File.join(Perron.configuration.input, name)
|
10
10
|
|
11
11
|
raise Errors::CollectionNotFoundError, "No such collection: #{name}" unless File.exist?(@collection_path) && File.directory?(@collection_path)
|
12
12
|
end
|
13
13
|
|
14
14
|
def configuration(resource_class = "Content::#{name.classify}".safe_constantize)
|
15
|
-
resource_class
|
15
|
+
resource_class&.configuration
|
16
16
|
end
|
17
17
|
|
18
18
|
def all(resource_class = "Content::#{name.classify}".safe_constantize)
|
@@ -29,5 +29,11 @@ module Perron
|
|
29
29
|
|
30
30
|
raise Errors::ResourceNotFoundError, "Resource not found with slug: #{slug}"
|
31
31
|
end
|
32
|
+
|
33
|
+
def find_by_file_name(file_name, resource_class = Resource)
|
34
|
+
resource_class.new(
|
35
|
+
Perron.configuration.allowed_extensions.lazy.map { File.join(@collection_path, [file_name, it].join(".")) }.find { File.exist?(it) }
|
36
|
+
)
|
37
|
+
end
|
32
38
|
end
|
33
39
|
end
|
data/lib/perron/configuration.rb
CHANGED
@@ -28,12 +28,16 @@ module Perron
|
|
28
28
|
@config.exclude_from_public = %w[assets storage]
|
29
29
|
@config.excluded_assets = %w[action_cable actioncable actiontext activestorage rails-ujs trix turbo]
|
30
30
|
|
31
|
+
@config.view_unpublished = Rails.env.development?
|
32
|
+
|
31
33
|
@config.default_url_options = {
|
32
34
|
host: ENV.fetch("PERRON_HOST", "localhost:3000"),
|
33
35
|
protocol: ENV.fetch("PERRON_PROTOCOL", "http"),
|
34
36
|
trailing_slash: ENV.fetch("PERRON_TRAILING_SLASH", "true") == "true"
|
35
37
|
}
|
36
38
|
|
39
|
+
@config.markdown_options = {}
|
40
|
+
|
37
41
|
@config.sitemap = ActiveSupport::OrderedOptions.new
|
38
42
|
@config.sitemap.enabled = false
|
39
43
|
@config.sitemap.priority = 0.5
|
@@ -5,6 +5,7 @@ require "csv"
|
|
5
5
|
module Perron
|
6
6
|
class Data < SimpleDelegator
|
7
7
|
def initialize(identifier)
|
8
|
+
@identifier = identifier
|
8
9
|
@file_path = self.class.path_for!(identifier)
|
9
10
|
@records = records
|
10
11
|
|
@@ -47,7 +48,7 @@ module Perron
|
|
47
48
|
raise Errors::DataParseError, "Data in `#{@file_path}` must be an array of objects."
|
48
49
|
end
|
49
50
|
|
50
|
-
data.map { Item.new(it) }
|
51
|
+
data.map { Item.new(it, identifier: @identifier) }
|
51
52
|
end
|
52
53
|
|
53
54
|
def rendered_from(path)
|
@@ -93,16 +94,29 @@ module Perron
|
|
93
94
|
end
|
94
95
|
|
95
96
|
def get_binding = binding
|
97
|
+
|
98
|
+
def default_url_options = Perron.configuration.default_url_options || {}
|
96
99
|
end
|
97
100
|
private_constant :HelperContext
|
98
101
|
|
99
102
|
class Item
|
100
|
-
def initialize(attributes)
|
103
|
+
def initialize(attributes, identifier:)
|
101
104
|
@attributes = attributes.transform_keys(&:to_sym)
|
105
|
+
@identifier = identifier
|
102
106
|
end
|
103
107
|
|
104
108
|
def [](key) = @attributes[key.to_sym]
|
105
109
|
|
110
|
+
def to_partial_path
|
111
|
+
@to_partial_path ||= begin
|
112
|
+
identifier = @identifier.to_s
|
113
|
+
collection = File.extname(identifier).present? ? File.basename(identifier, ".*") : identifier
|
114
|
+
element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.singularize(File.basename(collection)))
|
115
|
+
|
116
|
+
File.join("content", collection, element)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
106
120
|
def method_missing(method_name, *arguments, &block)
|
107
121
|
return super if !@attributes.key?(method_name) || arguments.any? || block
|
108
122
|
|
data/lib/perron/feeds.rb
CHANGED
@@ -13,6 +13,7 @@ module Perron
|
|
13
13
|
|
14
14
|
next if options[:only]&.map(&:to_s)&.exclude?(collection_name)
|
15
15
|
next if options[:except]&.map(&:to_s)&.include?(collection_name)
|
16
|
+
next if collection.configuration.blank?
|
16
17
|
|
17
18
|
collection.configuration.feeds.each do |type, feed|
|
18
19
|
next unless feed.enabled && feed.path && MIME_TYPES.key?(type)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rouge"
|
4
|
+
require "perron/html_processor/base"
|
5
|
+
|
6
|
+
module Perron
|
7
|
+
class HtmlProcessor
|
8
|
+
class SyntaxHighlight < HtmlProcessor::Base
|
9
|
+
def process
|
10
|
+
@html.css('pre > code[class*="language-"]').each do |code_block|
|
11
|
+
language = code_block[:class][/(?<=language-)\S+/]
|
12
|
+
|
13
|
+
next if language.blank?
|
14
|
+
|
15
|
+
code_block.parent.replace(
|
16
|
+
highlight(code_block.text, with: language)
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def highlight(code_block, with:)
|
24
|
+
lexer = Rouge::Lexer.find(with) || Rouge::Lexers::PlainText.new
|
25
|
+
|
26
|
+
Rouge::Formatters::HTMLPygments.new(::Rouge::Formatters::HTML.new).format(lexer.lex(code_block))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -11,11 +11,9 @@ module Perron
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def process
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
document.to_html
|
14
|
+
Nokogiri::HTML::DocumentFragment.parse(@html).tap do |document|
|
15
|
+
@processors.each { it.new(document).process }
|
16
|
+
end.to_html
|
19
17
|
end
|
20
18
|
|
21
19
|
private
|
@@ -23,7 +21,13 @@ module Perron
|
|
23
21
|
BUILT_IN = {
|
24
22
|
"target_blank" => Perron::HtmlProcessor::TargetBlank,
|
25
23
|
"lazy_load_images" => Perron::HtmlProcessor::LazyLoadImages
|
26
|
-
}
|
24
|
+
}.tap do |processors|
|
25
|
+
require "rouge"
|
26
|
+
require "perron/html_processor/syntax_highlight"
|
27
|
+
|
28
|
+
processors["syntax_highlight"] = Perron::HtmlProcessor::SyntaxHighlight
|
29
|
+
rescue LoadError
|
30
|
+
end
|
27
31
|
|
28
32
|
def find_by(identifier)
|
29
33
|
case identifier
|
@@ -43,8 +47,8 @@ module Perron
|
|
43
47
|
|
44
48
|
return processor if processor
|
45
49
|
|
46
|
-
raise Perron::Errors::ProcessorNotFoundError,
|
47
|
-
|
50
|
+
raise Perron::Errors::ProcessorNotFoundError, "The `syntax_highlight` processor requires `rouge`. Run `bundle add rouge` to add it to your Gemfile." if name.inquiry.syntax_highlight?
|
51
|
+
raise Perron::Errors::ProcessorNotFoundError, "Could not find processor `#{name}`. It is not a Perron-included processor and the constant `#{name.camelize}` could not be found."
|
48
52
|
end
|
49
53
|
end
|
50
54
|
end
|