perron 0.17.0 → 1.0.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 -1
- data/Gemfile.lock +25 -2
- data/app/controllers/perron/concierge_controller.rb +13 -0
- data/app/controllers/perron/searches_controller.rb +48 -0
- data/app/helpers/perron/feeds_helper.rb +7 -0
- data/app/helpers/perron/markdown_helper.rb +3 -3
- data/app/helpers/perron/meta_tags_helper.rb +17 -0
- data/app/views/perron/concierge/show.html.erb +271 -0
- data/bin/release +19 -4
- data/lib/generators/rails/content/USAGE +45 -26
- data/lib/generators/rails/content/content_generator.rb +16 -13
- data/lib/generators/rails/content/templates/controller.rb.tt +7 -5
- data/lib/generators/rails/content/templates/model.rb.tt +4 -4
- data/lib/perron/assets/icon.png +0 -0
- data/lib/perron/assets/icon.svg +1 -0
- data/lib/perron/collection.rb +10 -1
- data/lib/perron/configuration.rb +13 -4
- data/lib/perron/content/data.rb +6 -2
- data/lib/perron/data_source/class_methods.rb +66 -0
- data/lib/perron/data_source/helper_context.rb +20 -0
- data/lib/perron/data_source/item.rb +37 -0
- data/lib/perron/{data → data_source}/proxy.rb +1 -1
- data/lib/perron/data_source.rb +140 -0
- data/lib/perron/development_feed_server.rb +69 -0
- data/lib/perron/engine.rb +41 -1
- data/lib/perron/errors.rb +2 -0
- data/lib/perron/feeds.rb +4 -3
- data/lib/perron/html_processor/absolute_urls.rb +27 -0
- data/lib/perron/html_processor/base.rb +2 -2
- data/lib/perron/html_processor.rb +7 -11
- data/lib/perron/install/README.md.tt +67 -0
- data/lib/{generators/perron/templates → perron/install}/initializer.rb.tt +8 -4
- data/lib/perron/install.rb +23 -0
- data/lib/perron/markdown.rb +2 -2
- data/lib/perron/output_server.rb +16 -2
- data/lib/perron/relation.rb +51 -0
- data/lib/perron/resource/adjacency.rb +70 -0
- data/lib/perron/resource/associations.rb +3 -3
- data/lib/perron/resource/class_methods.rb +10 -0
- data/lib/perron/resource/configuration.rb +16 -14
- data/lib/perron/resource/core.rb +11 -0
- data/lib/perron/resource/metadata.rb +10 -1
- data/lib/perron/resource/publishable.rb +2 -0
- data/lib/perron/resource/related/stop_words.rb +20 -20
- data/lib/perron/resource/related.rb +76 -54
- data/lib/perron/resource/scopes.rb +29 -0
- data/lib/perron/resource/searchable.rb +19 -0
- data/lib/perron/resource/sourceable.rb +39 -9
- data/lib/perron/resource/sweeper.rb +45 -0
- data/lib/perron/resource/table_of_content.rb +0 -18
- data/lib/perron/resource.rb +32 -20
- data/lib/perron/site/builder/assets.rb +1 -1
- data/lib/perron/site/builder/feeds/atom.erb +44 -0
- data/lib/perron/site/builder/feeds/atom.rb +41 -0
- data/lib/perron/site/builder/feeds/json.erb +19 -0
- data/lib/perron/site/builder/feeds/json.rb +7 -33
- data/lib/perron/site/builder/feeds/rss.erb +28 -0
- data/lib/perron/site/builder/feeds/rss.rb +6 -28
- data/lib/perron/site/builder/feeds/template.rb +63 -0
- data/lib/perron/site/builder/feeds.rb +8 -3
- data/lib/perron/site/builder/paths.rb +58 -14
- data/lib/perron/site/builder/route_resources.rb +79 -0
- data/lib/perron/site/builder/sitemap.rb +71 -20
- data/lib/perron/site/builder.rb +1 -1
- data/lib/perron/site/validate.rb +1 -2
- data/lib/perron/site.rb +10 -3
- data/lib/perron/tasks/build.rake +6 -0
- data/lib/perron/tasks/install.rake +12 -0
- data/lib/perron/version.rb +1 -1
- data/lib/perron.rb +1 -0
- data/perron.gemspec +1 -0
- metadata +45 -10
- data/app/helpers/feeds_helper.rb +0 -5
- data/app/helpers/meta_tags_helper.rb +0 -15
- data/lib/generators/perron/install_generator.rb +0 -32
- data/lib/generators/perron/templates/README.md.tt +0 -45
- data/lib/perron/data.rb +0 -180
- data/lib/perron/html_processor/syntax_highlight.rb +0 -30
|
@@ -2,17 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
require "perron/html_processor/target_blank"
|
|
4
4
|
require "perron/html_processor/lazy_load_images"
|
|
5
|
+
require "perron/html_processor/absolute_urls"
|
|
5
6
|
|
|
6
7
|
module Perron
|
|
7
8
|
class HtmlProcessor
|
|
8
|
-
def initialize(html, processors: [])
|
|
9
|
+
def initialize(html, processors: [], resource: nil)
|
|
9
10
|
@html = html
|
|
11
|
+
@resource = resource
|
|
10
12
|
@processors = processors.map { find_by(it) }
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def process
|
|
14
16
|
Nokogiri::HTML::DocumentFragment.parse(@html).tap do |document|
|
|
15
|
-
@processors.each { it.new(document).process }
|
|
17
|
+
@processors.each { it.new(document, resource: @resource).process }
|
|
16
18
|
end.to_html
|
|
17
19
|
end
|
|
18
20
|
|
|
@@ -20,14 +22,9 @@ module Perron
|
|
|
20
22
|
|
|
21
23
|
BUILT_IN = {
|
|
22
24
|
"target_blank" => Perron::HtmlProcessor::TargetBlank,
|
|
23
|
-
"lazy_load_images" => Perron::HtmlProcessor::LazyLoadImages
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
require "perron/html_processor/syntax_highlight"
|
|
27
|
-
|
|
28
|
-
processors["syntax_highlight"] = Perron::HtmlProcessor::SyntaxHighlight
|
|
29
|
-
rescue LoadError
|
|
30
|
-
end
|
|
25
|
+
"lazy_load_images" => Perron::HtmlProcessor::LazyLoadImages,
|
|
26
|
+
"absolute_urls" => Perron::HtmlProcessor::AbsoluteUrls
|
|
27
|
+
}
|
|
31
28
|
|
|
32
29
|
def find_by(identifier)
|
|
33
30
|
case identifier
|
|
@@ -47,7 +44,6 @@ module Perron
|
|
|
47
44
|
|
|
48
45
|
return processor if processor
|
|
49
46
|
|
|
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
47
|
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."
|
|
52
48
|
end
|
|
53
49
|
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Data
|
|
2
|
+
|
|
3
|
+
Perron can consume structured data from YML, JSON or CSV files, making them available within views. This is useful for populating features, team members or any other repeated data structure.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
|
|
8
|
+
Access data sources using the `Content::Data` namespace with the class name matching the file's basename:
|
|
9
|
+
```erb
|
|
10
|
+
<% Content::Data::Features.all.each do |feature| %>
|
|
11
|
+
<h4><%= feature.name %></h4>
|
|
12
|
+
<p><%= feature.description %></p>
|
|
13
|
+
<% end %>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Look up a single entry with `Content::Data::Features.find("advanced-search")`, where `"advanced-search"` matches the value of the entry's `id` field.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## File location and formats
|
|
20
|
+
|
|
21
|
+
By default, Perron looks up `app/content/data/` for files with a `.yml`, `.json` or `.csv` extension. For a `features` call, it would find `features.yml`, `features.json` or `features.csv`. Provide a path to any data resource in `/app/content/data/`, via `Content::Data.new("path/to/data-resource")`.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## Accessing data
|
|
25
|
+
|
|
26
|
+
The wrapper object provides flexible, read-only access to each record's attributes. Both dot notation and hash-like key access are supported.
|
|
27
|
+
```ruby
|
|
28
|
+
feature.name
|
|
29
|
+
feature[:name]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Rendering
|
|
34
|
+
|
|
35
|
+
Render data collections directly using Rails-like partial rendering:
|
|
36
|
+
```erb
|
|
37
|
+
<%= render Content::Data::Features.all %>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This expects a partial at `app/views/content/features/_feature.html.erb` that will be rendered once for each item in `Content::Data::Features.all`. The individual record is made available as a local variable matching the singular form of the collection name.
|
|
41
|
+
```erb
|
|
42
|
+
<!-- app/views/content/features/_feature.html.erb -->
|
|
43
|
+
<div class="feature">
|
|
44
|
+
<h4><%= feature.name %></h4>
|
|
45
|
+
<p><%= feature.description %></p>
|
|
46
|
+
</div>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
## Data structure
|
|
51
|
+
|
|
52
|
+
Data resources must contain an array of objects. Each record should include an `id` field if used with [associations](/docs/resources/#associations) or with the `find` method:
|
|
53
|
+
```yaml
|
|
54
|
+
# app/content/data/authors.yml
|
|
55
|
+
- id: rails-designer
|
|
56
|
+
name: Rails Designer
|
|
57
|
+
bio: Creator of Perron
|
|
58
|
+
|
|
59
|
+
- id: cam
|
|
60
|
+
name: Cam
|
|
61
|
+
bio: Contributing author
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## Enumerable methods
|
|
66
|
+
|
|
67
|
+
All data objects support enumerable methods like `select`, `sort_by`, `first` and `count`. See [Enumerable methods](/docs/rendering/#enumerable-methods) for the full list of available methods.
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
Perron.configure do |config|
|
|
2
|
-
#
|
|
2
|
+
# For all options check out:
|
|
3
|
+
# https://perron.railsdesigner.com/docs/configuration/
|
|
3
4
|
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
# The build mode for Perron. Can be :standalone (SSG) or :integrated (alongside your Rails app)
|
|
5
|
+
# The build mode for Perron. Can be :standalone (SSG, default) or :integrated (alongside your Rails app)
|
|
7
6
|
# config.mode = :standalone
|
|
8
7
|
|
|
8
|
+
# Enable Live Reload with DOM Morphing in development
|
|
9
|
+
# config.live_reload = true
|
|
10
|
+
|
|
9
11
|
# config.default_url_options = {host: "chirpform.com", protocol: "https", trailing_slash: true}
|
|
10
12
|
|
|
11
13
|
# The options hash is passed directly to the chosen library
|
|
12
14
|
# config.markdown_options = {}
|
|
13
15
|
|
|
16
|
+
# config.site_name = "Chirp Form"
|
|
17
|
+
|
|
14
18
|
# Set meta title suffix
|
|
15
19
|
# config.metadata.title_suffix = nil
|
|
16
20
|
# config.metadata.title_separator = " — "
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
say "Install Perron in your Rails app"
|
|
2
|
+
|
|
3
|
+
say "Create Perron initializer"
|
|
4
|
+
copy_file "#{__dir__}/install/initializer.rb", "config/initializers/perron.rb"
|
|
5
|
+
|
|
6
|
+
say "Create content data directory"
|
|
7
|
+
copy_file "#{__dir__}/install/README.md", "app/content/data/README.md"
|
|
8
|
+
|
|
9
|
+
say "Add Markdown gem options to Gemfile"
|
|
10
|
+
append_to_file "Gemfile", <<~RUBY
|
|
11
|
+
|
|
12
|
+
# Perron supports Markdown rendering using one of the following gems.
|
|
13
|
+
# Uncomment your preferred choice and run `bundle install`
|
|
14
|
+
# gem "commonmarker"
|
|
15
|
+
# gem "kramdown"
|
|
16
|
+
# gem "redcarpet"
|
|
17
|
+
RUBY
|
|
18
|
+
|
|
19
|
+
copy_file "#{__dir__}/assets/icon.png", "public/icon.png", force: true
|
|
20
|
+
copy_file "#{__dir__}/assets/icon.svg", "public/icon.svg", force: true
|
|
21
|
+
|
|
22
|
+
say "Add output folder to .gitignore"
|
|
23
|
+
append_to_file ".gitignore", "/#{Perron.configuration.output}/\n"
|
data/lib/perron/markdown.rb
CHANGED
|
@@ -5,9 +5,9 @@ require "perron/html_processor"
|
|
|
5
5
|
module Perron
|
|
6
6
|
class Markdown
|
|
7
7
|
class << self
|
|
8
|
-
def render(text, processors: [])
|
|
8
|
+
def render(text, processors: [], resource: nil)
|
|
9
9
|
parser.parse(text)
|
|
10
|
-
.then { Perron::HtmlProcessor.new(it, processors: processors).process }
|
|
10
|
+
.then { Perron::HtmlProcessor.new(it, processors: processors, resource: resource).process }
|
|
11
11
|
.html_safe
|
|
12
12
|
end
|
|
13
13
|
|
data/lib/perron/output_server.rb
CHANGED
|
@@ -8,6 +8,7 @@ module Perron
|
|
|
8
8
|
|
|
9
9
|
def call(environment)
|
|
10
10
|
return @app.call(environment) if disabled?
|
|
11
|
+
return not_found if !static_file(environment) && Perron.configuration.output_server_strict
|
|
11
12
|
|
|
12
13
|
static_file(environment).then do |file|
|
|
13
14
|
file ? serve(file) : @app.call(environment)
|
|
@@ -27,21 +28,34 @@ module Perron
|
|
|
27
28
|
|
|
28
29
|
def serve(file_path)
|
|
29
30
|
content = File.read(file_path)
|
|
31
|
+
injected_content = inject_preview_indicator(content)
|
|
30
32
|
|
|
31
33
|
[
|
|
32
34
|
200,
|
|
33
35
|
|
|
34
36
|
{
|
|
35
37
|
"Content-Type" => "text/html; charset=utf-8",
|
|
36
|
-
"Content-Length" =>
|
|
38
|
+
"Content-Length" => injected_content.bytesize.to_s
|
|
37
39
|
},
|
|
38
40
|
|
|
39
|
-
[
|
|
41
|
+
[injected_content]
|
|
42
|
+
]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def not_found
|
|
46
|
+
[
|
|
47
|
+
404,
|
|
48
|
+
{"Content-Type" => "text/plain"},
|
|
49
|
+
["Not Found"]
|
|
40
50
|
]
|
|
41
51
|
end
|
|
42
52
|
|
|
43
53
|
def enabled? = Dir.exist?(output_path)
|
|
44
54
|
|
|
55
|
+
def inject_preview_indicator(content)
|
|
56
|
+
content.gsub(/<title>(.*?)<\/title>/i, "<title>[PREVIEW] \\1</title>")
|
|
57
|
+
end
|
|
58
|
+
|
|
45
59
|
def output_path
|
|
46
60
|
@output_path ||= Rails.root.join(Perron.configuration.output)
|
|
47
61
|
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Perron
|
|
4
|
+
class Relation < Array
|
|
5
|
+
def initialize(resources = [])
|
|
6
|
+
super
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def where(**conditions)
|
|
10
|
+
filtered = select do |resource|
|
|
11
|
+
conditions.all? do |key, value|
|
|
12
|
+
key_value = resource.public_send(key)
|
|
13
|
+
|
|
14
|
+
if value.is_a?(Array)
|
|
15
|
+
value.map(&:to_s).include?(key_value.to_s)
|
|
16
|
+
else
|
|
17
|
+
key_value.to_s == value.to_s
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Relation.new(filtered)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def limit(count) = Relation.new(first(count))
|
|
26
|
+
|
|
27
|
+
def offset(count) = Relation.new(drop(count))
|
|
28
|
+
|
|
29
|
+
def order(attribute, direction = :asc)
|
|
30
|
+
if attribute.is_a?(Hash)
|
|
31
|
+
attribute, direction = attribute.first
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
sorted = sort_by { it.public_send(attribute) }
|
|
35
|
+
|
|
36
|
+
Relation.new((direction == :desc) ? sorted.reverse : sorted)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def pluck(*attributes)
|
|
40
|
+
raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" if attributes.empty?
|
|
41
|
+
|
|
42
|
+
map do |resource|
|
|
43
|
+
if attributes.size == 1
|
|
44
|
+
resource.public_send(attributes.first)
|
|
45
|
+
else
|
|
46
|
+
attributes.map { resource.public_send(it) }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Perron
|
|
4
|
+
class Resource
|
|
5
|
+
module Adjacency
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
class_methods do
|
|
9
|
+
def adjacent_by(position_method, within: {})
|
|
10
|
+
return unless within.present?
|
|
11
|
+
|
|
12
|
+
grouping_method = within.is_a?(Hash) ? within.keys.first : within
|
|
13
|
+
grouping_order = within.is_a?(Hash) ? within.values.first : nil
|
|
14
|
+
|
|
15
|
+
define_method(:next) do
|
|
16
|
+
resources = self.class.all.sort_by do |resource|
|
|
17
|
+
group_value = resource.public_send(grouping_method)
|
|
18
|
+
|
|
19
|
+
group_order = if grouping_order
|
|
20
|
+
grouping_order.index(group_value.to_s) || grouping_order.index(group_value.to_sym) || Float::INFINITY
|
|
21
|
+
else
|
|
22
|
+
group_value.to_s
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
[group_order, resource.public_send(position_method)]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
return if (position = resources.index { it.id == id }).nil? || position >= resources.size - 1
|
|
29
|
+
|
|
30
|
+
resources[position + 1]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
define_method(:previous) do
|
|
34
|
+
resources = self.class.all.sort_by do |resource|
|
|
35
|
+
group_value = resource.public_send(grouping_method)
|
|
36
|
+
|
|
37
|
+
group_order = if grouping_order
|
|
38
|
+
grouping_order.index(group_value.to_s) || grouping_order.index(group_value.to_sym) || Float::INFINITY
|
|
39
|
+
else
|
|
40
|
+
group_value.to_s
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
[group_order, resource.public_send(position_method)]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
return if (position = resources.index { it.id == id }).nil? || position <= 0
|
|
47
|
+
|
|
48
|
+
resources[position - 1]
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
included do
|
|
54
|
+
define_method(:next) do
|
|
55
|
+
resources = self.class.all
|
|
56
|
+
return if (position = resources.index { it.id == id }).nil? || position >= resources.size - 1
|
|
57
|
+
|
|
58
|
+
resources[position + 1]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
define_method(:previous) do
|
|
62
|
+
resources = self.class.all
|
|
63
|
+
return if (position = resources.index { it.id == id }).nil? || position <= 0
|
|
64
|
+
|
|
65
|
+
resources[position - 1]
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -13,7 +13,7 @@ module Perron
|
|
|
13
13
|
foreign_key = foreign_key_for(association_name, **options)
|
|
14
14
|
identifier = metadata[foreign_key]
|
|
15
15
|
|
|
16
|
-
identifier ? associated_class.find(identifier) : nil
|
|
16
|
+
identifier ? associated_class.find!(identifier) : nil
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
end
|
|
@@ -66,7 +66,7 @@ module Perron
|
|
|
66
66
|
def records_for_ids(associated_class, ids)
|
|
67
67
|
ids = Array(ids)
|
|
68
68
|
|
|
69
|
-
associated_class.all.select { ids.include?(it[:id]) || ids.include?(it["id"]) }
|
|
69
|
+
Perron::Relation.new(associated_class.all.select { ids.include?(it[:id]) || ids.include?(it["id"]) })
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def records_for_foreign_key(associated_class, association_name, **options)
|
|
@@ -74,7 +74,7 @@ module Perron
|
|
|
74
74
|
primary_key_method = options.fetch(:primary_key, :slug)
|
|
75
75
|
lookup_value = public_send(primary_key_method)
|
|
76
76
|
|
|
77
|
-
associated_class.all.select { it.association_value(foreign_key) == lookup_value }
|
|
77
|
+
Perron::Relation.new(associated_class.all.select { it.association_value(foreign_key) == lookup_value })
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def inverse_association_name = self.class.name.demodulize.underscore
|
|
@@ -8,10 +8,20 @@ module Perron
|
|
|
8
8
|
class_methods do
|
|
9
9
|
def find(slug) = collection.find(slug, name.constantize)
|
|
10
10
|
|
|
11
|
+
def find!(slug) = collection.find!(slug, name.constantize)
|
|
12
|
+
|
|
11
13
|
def all = collection.all(self)
|
|
12
14
|
|
|
15
|
+
def where(**conditions) = all.where(**conditions)
|
|
16
|
+
|
|
17
|
+
def limit(count) = all.limit(count)
|
|
18
|
+
|
|
19
|
+
def offset(count) = all.offset(count)
|
|
20
|
+
|
|
13
21
|
def count = all.size
|
|
14
22
|
|
|
23
|
+
def order(attribute, direction = :asc) = all.order(attribute, direction)
|
|
24
|
+
|
|
15
25
|
def first(n = nil)
|
|
16
26
|
n ? all.first(n) : all[0]
|
|
17
27
|
end
|
|
@@ -12,17 +12,20 @@ module Perron
|
|
|
12
12
|
|
|
13
13
|
config.feeds = Options.new
|
|
14
14
|
|
|
15
|
-
config.feeds.
|
|
16
|
-
config.feeds.
|
|
17
|
-
config.feeds.
|
|
18
|
-
config.feeds.
|
|
15
|
+
config.feeds.atom = ActiveSupport::OrderedOptions.new
|
|
16
|
+
config.feeds.atom.enabled = false
|
|
17
|
+
config.feeds.atom.path = "feeds/#{collection.name.demodulize.parameterize}.atom"
|
|
18
|
+
config.feeds.atom.max_items = 20
|
|
19
19
|
|
|
20
20
|
config.feeds.json = ActiveSupport::OrderedOptions.new
|
|
21
21
|
config.feeds.json.enabled = false
|
|
22
22
|
config.feeds.json.path = "feeds/#{collection.name.demodulize.parameterize}.json"
|
|
23
23
|
config.feeds.json.max_items = 20
|
|
24
24
|
|
|
25
|
-
config.
|
|
25
|
+
config.feeds.rss = ActiveSupport::OrderedOptions.new
|
|
26
|
+
config.feeds.rss.enabled = false
|
|
27
|
+
config.feeds.rss.path = "feeds/#{collection.name.demodulize.parameterize}.xml"
|
|
28
|
+
config.feeds.rss.max_items = 20
|
|
26
29
|
|
|
27
30
|
config.related_posts = ActiveSupport::OrderedOptions.new
|
|
28
31
|
config.related_posts.enabled = false
|
|
@@ -39,18 +42,17 @@ module Perron
|
|
|
39
42
|
end
|
|
40
43
|
|
|
41
44
|
class Options < ActiveSupport::OrderedOptions
|
|
42
|
-
def
|
|
43
|
-
if
|
|
44
|
-
key
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return self[key].merge!(value) if self[key].is_a?(ActiveSupport::OrderedOptions) && value.is_a?(Hash)
|
|
45
|
+
def []=(key, value)
|
|
46
|
+
if self[key].is_a?(ActiveSupport::OrderedOptions) && value.is_a?(Hash)
|
|
47
|
+
self[key].merge!(value)
|
|
48
|
+
else
|
|
49
|
+
super
|
|
48
50
|
end
|
|
49
|
-
|
|
50
|
-
super
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
def respond_to_missing?(name, include_private = false)
|
|
53
|
+
def respond_to_missing?(name, include_private = false)
|
|
54
|
+
name.to_s.end_with?("=") || super
|
|
55
|
+
end
|
|
54
56
|
end
|
|
55
57
|
private_constant :Options
|
|
56
58
|
end
|
data/lib/perron/resource/core.rb
CHANGED
|
@@ -10,6 +10,17 @@ module Perron
|
|
|
10
10
|
def to_model = self
|
|
11
11
|
|
|
12
12
|
def model_name = self.class.model_name
|
|
13
|
+
|
|
14
|
+
def association_value(key) = metadata[key]
|
|
15
|
+
|
|
16
|
+
def to_partial_path
|
|
17
|
+
@to_partial_path ||= begin
|
|
18
|
+
element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self.class.model_name))
|
|
19
|
+
collection = ActiveSupport::Inflector.tableize(self.class.model_name)
|
|
20
|
+
|
|
21
|
+
File.join("content", collection, element)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
13
24
|
end
|
|
14
25
|
end
|
|
15
26
|
end
|
|
@@ -25,6 +25,8 @@ module Perron
|
|
|
25
25
|
|
|
26
26
|
to[:canonical_url] ||= canonical_url
|
|
27
27
|
|
|
28
|
+
to[:image] = absolute_url(to[:image]) if to[:image]
|
|
29
|
+
|
|
28
30
|
to[:og_image] ||= to[:image]
|
|
29
31
|
to[:twitter_image] ||= to[:og_image]
|
|
30
32
|
|
|
@@ -52,13 +54,20 @@ module Perron
|
|
|
52
54
|
begin
|
|
53
55
|
Rails.application.routes.url_helpers.polymorphic_url(
|
|
54
56
|
@resource,
|
|
55
|
-
|
|
57
|
+
**Perron.configuration.default_url_options
|
|
56
58
|
)
|
|
57
59
|
rescue
|
|
58
60
|
false
|
|
59
61
|
end
|
|
60
62
|
end
|
|
61
63
|
|
|
64
|
+
def absolute_url(path)
|
|
65
|
+
return path if path.blank?
|
|
66
|
+
return path if path.start_with?("http://", "https://", "//")
|
|
67
|
+
|
|
68
|
+
Perron.configuration.url.delete_suffix("/") + path
|
|
69
|
+
end
|
|
70
|
+
|
|
62
71
|
def site_data
|
|
63
72
|
@config.metadata.except(:title_separator, :title_suffix).deep_symbolize_keys || {}
|
|
64
73
|
end
|
|
@@ -5,28 +5,28 @@ module Perron
|
|
|
5
5
|
class Resource
|
|
6
6
|
class Related
|
|
7
7
|
module StopWords
|
|
8
|
+
ALL = Set[
|
|
9
|
+
"a", "about", "above", "after", "again", "against", "all", "am",
|
|
10
|
+
"an", "and", "any", "are", "as", "at", "be", "because", "been",
|
|
11
|
+
"before", "being", "below", "between", "both", "but", "by", "can",
|
|
12
|
+
"did", "do", "does", "doing", "down", "during", "each", "few",
|
|
13
|
+
"for", "from", "further", "had", "has", "have", "having", "he",
|
|
14
|
+
"her", "here", "hers", "herself", "him", "himself", "his", "how",
|
|
15
|
+
"i", "if", "in", "into", "is", "it", "its", "itself", "just",
|
|
16
|
+
"me", "more", "most", "my", "myself", "no", "nor", "not", "now",
|
|
17
|
+
"of", "off", "on", "once", "only", "or", "other", "our", "ours",
|
|
18
|
+
"ourselves", "out", "over", "own", "s", "same", "she", "should",
|
|
19
|
+
"so", "some", "such", "t", "than", "that", "the", "their",
|
|
20
|
+
"theirs", "them", "themselves", "then", "there", "these", "they",
|
|
21
|
+
"this", "those", "through", "to", "too", "under", "until", "up",
|
|
22
|
+
"very", "was", "we", "were", "what", "when", "where", "which",
|
|
23
|
+
"while", "who", "whom", "why", "will", "with", "you", "your",
|
|
24
|
+
"yours", "yourself", "yourselves"
|
|
25
|
+
].freeze
|
|
26
|
+
|
|
8
27
|
module_function
|
|
9
28
|
|
|
10
|
-
def all
|
|
11
|
-
Set[
|
|
12
|
-
"a", "about", "above", "after", "again", "against", "all", "am",
|
|
13
|
-
"an", "and", "any", "are", "as", "at", "be", "because", "been",
|
|
14
|
-
"before", "being", "below", "between", "both", "but", "by", "can",
|
|
15
|
-
"did", "do", "does", "doing", "down", "during", "each", "few",
|
|
16
|
-
"for", "from", "further", "had", "has", "have", "having", "he",
|
|
17
|
-
"her", "here", "hers", "herself", "him", "himself", "his", "how",
|
|
18
|
-
"i", "if", "in", "into", "is", "it", "its", "itself", "just",
|
|
19
|
-
"me", "more", "most", "my", "myself", "no", "nor", "not", "now",
|
|
20
|
-
"of", "off", "on", "once", "only", "or", "other", "our", "ours",
|
|
21
|
-
"ourselves", "out", "over", "own", "s", "same", "she", "should",
|
|
22
|
-
"so", "some", "such", "t", "than", "that", "the", "their",
|
|
23
|
-
"theirs", "them", "themselves", "then", "there", "these", "they",
|
|
24
|
-
"this", "those", "through", "to", "too", "under", "until", "up",
|
|
25
|
-
"very", "was", "we", "were", "what", "when", "where", "which",
|
|
26
|
-
"while", "who", "whom", "why", "will", "with", "you", "your",
|
|
27
|
-
"yours", "yourself", "yourselves"
|
|
28
|
-
]
|
|
29
|
-
end
|
|
29
|
+
def all = ALL
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|