perron 0.15.0 → 0.17.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.lock +7 -3
- data/lib/generators/perron/templates/initializer.rb.tt +7 -11
- data/lib/generators/rails/content/USAGE +23 -0
- data/lib/generators/rails/content/content_generator.rb +54 -15
- data/lib/generators/rails/content/templates/model.rb.tt +11 -0
- data/lib/generators/rails/content/templates/root.erb.tt +1 -1
- data/lib/generators/rails/content/templates/show.html.erb.tt +1 -1
- data/lib/perron/configuration.rb +5 -4
- data/lib/perron/content/data.rb +13 -0
- data/lib/perron/data.rb +48 -0
- data/lib/perron/deprecator.rb +7 -0
- data/lib/perron/engine.rb +8 -1
- data/lib/perron/output_server.rb +49 -0
- data/lib/perron/resource/associations.rb +23 -9
- data/lib/perron/resource/class_methods.rb +4 -4
- data/lib/perron/resource/metadata.rb +1 -1
- data/lib/perron/resource/previewable.rb +1 -0
- data/lib/perron/resource/sourceable.rb +3 -2
- data/lib/perron/resource.rb +6 -4
- data/lib/perron/site/builder/additional_routes.rb +23 -0
- data/lib/perron/site/builder/feeds/author.rb +42 -0
- data/lib/perron/site/builder/feeds/json.rb +12 -0
- data/lib/perron/site/builder/feeds/rss.rb +6 -0
- data/lib/perron/site/builder/paths.rb +2 -9
- data/lib/perron/site/builder/sitemap.rb +20 -2
- data/lib/perron/site/builder.rb +2 -0
- data/lib/perron/site.rb +2 -0
- data/lib/perron/tasks/clobber.rake +12 -0
- data/lib/perron/version.rb +1 -1
- data/lib/perron.rb +2 -1
- metadata +8 -3
- data/lib/perron/root.rb +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fbf1b0d5483938df7b88423f3ecd72bffaf938eadcc49a3001a34fcb0156dfb9
|
|
4
|
+
data.tar.gz: cd8871c7ef91a102a45bcebbcdc8bbf385db3a83ffb34948cd0d3e49c14d8237
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4d21cfbf61b54fb704990a23cbbf73285364e37ab722246c0202ecea37616398edcfe3fc9f841bc3cae9100108cb61e37200780c0e0ef667515f6e27319498e4
|
|
7
|
+
data.tar.gz: bed9e2b68bf2a5697a72a6b3bcb2dfcdb6898b93e31b6bc68b169583462d9e4a4f3e345dec8470077b2566dd31860e8ca97ce83cd82b8a01aff889ad0d5a7d14
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
perron (0.
|
|
4
|
+
perron (0.17.0)
|
|
5
5
|
csv
|
|
6
6
|
json
|
|
7
7
|
psych
|
|
@@ -120,7 +120,8 @@ GEM
|
|
|
120
120
|
net-smtp
|
|
121
121
|
marcel (1.0.4)
|
|
122
122
|
mini_mime (1.1.5)
|
|
123
|
-
|
|
123
|
+
mini_portile2 (2.8.9)
|
|
124
|
+
minitest (5.27.0)
|
|
124
125
|
net-imap (0.5.9)
|
|
125
126
|
date
|
|
126
127
|
net-protocol
|
|
@@ -131,6 +132,9 @@ GEM
|
|
|
131
132
|
net-smtp (0.5.1)
|
|
132
133
|
net-protocol
|
|
133
134
|
nio4r (2.7.4)
|
|
135
|
+
nokogiri (1.18.8)
|
|
136
|
+
mini_portile2 (~> 2.8.2)
|
|
137
|
+
racc (~> 1.4)
|
|
134
138
|
nokogiri (1.18.8-aarch64-linux-gnu)
|
|
135
139
|
racc (~> 1.4)
|
|
136
140
|
nokogiri (1.18.8-aarch64-linux-musl)
|
|
@@ -244,7 +248,7 @@ GEM
|
|
|
244
248
|
concurrent-ruby (~> 1.0)
|
|
245
249
|
unicode-display_width (3.1.4)
|
|
246
250
|
unicode-emoji (~> 4.0, >= 4.0.4)
|
|
247
|
-
unicode-emoji (4.0
|
|
251
|
+
unicode-emoji (4.2.0)
|
|
248
252
|
useragent (0.16.11)
|
|
249
253
|
websocket-driver (0.8.0)
|
|
250
254
|
base64
|
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
Perron.configure do |config|
|
|
2
|
-
#
|
|
2
|
+
# View all options: https://perron.railsdesigner.com/docs/configuration/
|
|
3
3
|
|
|
4
4
|
# config.site_name = "Chirp Form"
|
|
5
5
|
|
|
6
|
-
# The build mode for Perron. Can be :standalone or :integrated
|
|
6
|
+
# The build mode for Perron. Can be :standalone (SSG) or :integrated (alongside your Rails app)
|
|
7
7
|
# config.mode = :standalone
|
|
8
8
|
|
|
9
|
-
#
|
|
10
|
-
# config.include_root = false
|
|
11
|
-
|
|
12
|
-
# config.default_url_options = {host: "helptail.com", protocol: "https", trailing_slash: true}
|
|
9
|
+
# config.default_url_options = {host: "chirpform.com", protocol: "https", trailing_slash: true}
|
|
13
10
|
|
|
14
11
|
# The options hash is passed directly to the chosen library
|
|
15
12
|
# config.markdown_options = {}
|
|
16
13
|
|
|
17
|
-
# Set default meta values
|
|
18
|
-
# Examples:
|
|
19
|
-
# - `config.metadata.description = "Add forms to any static site. Display responses anywhere."`
|
|
20
|
-
# - `config.metadata.author = "Chirp Form Team"`
|
|
21
|
-
|
|
22
14
|
# Set meta title suffix
|
|
23
15
|
# config.metadata.title_suffix = nil
|
|
24
16
|
# config.metadata.title_separator = " — "
|
|
17
|
+
|
|
18
|
+
# Set default meta values
|
|
19
|
+
# config.metadata.description = "Add forms to any static site. Display responses anywhere."
|
|
20
|
+
# config.metadata.author = "Chirp Form Team"
|
|
25
21
|
end
|
|
@@ -17,6 +17,27 @@ Examples:
|
|
|
17
17
|
|
|
18
18
|
And adds: resources :posts, module: :content, only: %w[index show]
|
|
19
19
|
|
|
20
|
+
Generate pages scaffold with root:
|
|
21
|
+
rails generate content Page
|
|
22
|
+
|
|
23
|
+
This will additionally create:
|
|
24
|
+
app/content/pages/root.erb
|
|
25
|
+
def root action in Content::PagesController
|
|
26
|
+
root route in config/routes.rb (if not already defined)
|
|
27
|
+
|
|
28
|
+
Skip root generation for pages:
|
|
29
|
+
rails generate content Page --no-include-root
|
|
30
|
+
|
|
31
|
+
Include root for non-pages content:
|
|
32
|
+
rails generate content Article --include-root
|
|
33
|
+
|
|
34
|
+
Generate content scaffold with data sources:
|
|
35
|
+
rails generate content Product --data countries products
|
|
36
|
+
rails generate content Product --data countries.json products.yml
|
|
37
|
+
|
|
38
|
+
This will additionally create data source files in app/content/products/
|
|
39
|
+
and add sources/template_source class methods to the model.
|
|
40
|
+
|
|
20
41
|
Create new content file from template:
|
|
21
42
|
rails generate content Post --new
|
|
22
43
|
rails generate content Post --new "My First Post"
|
|
@@ -38,4 +59,6 @@ Arguments:
|
|
|
38
59
|
|
|
39
60
|
Options:
|
|
40
61
|
--new [TITLE]: Create new content file instead of scaffold
|
|
62
|
+
--data [source1(.ext) source2(.ext)]: Create data source files (default extension: .yml)
|
|
41
63
|
--force-plural: Use plural form for model name and class
|
|
64
|
+
--[no-]include-root: Include root action and route (default: true for pages, false otherwise)
|
|
@@ -8,8 +8,11 @@ module Rails
|
|
|
8
8
|
source_root File.expand_path("templates", __dir__)
|
|
9
9
|
|
|
10
10
|
class_option :force_plural, type: :boolean, default: false, desc: "Forces the use of a plural model name and class"
|
|
11
|
+
class_option :include_root, type: :boolean, default: nil, desc: "Include root action and route (defaults to true for pages)"
|
|
11
12
|
class_option :new, type: :string, default: nil, banner: "TITLE",
|
|
12
13
|
desc: "Create a new content file from template instead of generating scaffold"
|
|
14
|
+
class_option :data, type: :array, default: [], banner: "source1(.ext) source2(.ext)",
|
|
15
|
+
desc: "Specify data sources with optional extensions (defaults to .yml)"
|
|
13
16
|
|
|
14
17
|
argument :actions, type: :array, default: %w[index show], banner: "actions", desc: "Specify which actions to generate (index/show)"
|
|
15
18
|
|
|
@@ -60,25 +63,52 @@ module Rails
|
|
|
60
63
|
FileUtils.mkdir_p(content_directory)
|
|
61
64
|
end
|
|
62
65
|
|
|
63
|
-
def
|
|
66
|
+
def add_content_route
|
|
64
67
|
return if @content_mode
|
|
65
|
-
return unless pages_controller?
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
route "resources :#{plural_file_name}, module: :content, only: %w[#{actions.join(" ")}]"
|
|
68
70
|
end
|
|
69
71
|
|
|
70
|
-
def
|
|
72
|
+
def create_data_sources
|
|
71
73
|
return if @content_mode
|
|
74
|
+
return if options[:data].empty?
|
|
72
75
|
|
|
73
|
-
|
|
76
|
+
options[:data].each do |source|
|
|
77
|
+
name, extension = source.split(".", 2)
|
|
78
|
+
|
|
79
|
+
create_file File.join(content_directory, "#{name}.#{extension || "yml"}"), ""
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def add_root_action
|
|
84
|
+
return if @content_mode
|
|
85
|
+
return unless should_include_root?
|
|
86
|
+
|
|
87
|
+
inject_into_class "app/controllers/content/#{plural_file_name}_controller.rb", "Content::#{plural_class_name}Controller" do
|
|
88
|
+
<<-RUBY
|
|
89
|
+
|
|
90
|
+
def root
|
|
91
|
+
@resource = Content::#{class_name}.root
|
|
92
|
+
|
|
93
|
+
render :show
|
|
94
|
+
end
|
|
95
|
+
RUBY
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def create_root_content_file
|
|
100
|
+
return if @content_mode
|
|
101
|
+
return unless should_include_root?
|
|
102
|
+
|
|
103
|
+
template "root.erb.tt", File.join(content_directory, "root.erb")
|
|
74
104
|
end
|
|
75
105
|
|
|
76
106
|
def add_root_route
|
|
77
107
|
return if @content_mode
|
|
78
|
-
return unless
|
|
108
|
+
return unless should_include_root?
|
|
79
109
|
return if root_route_exists?
|
|
80
110
|
|
|
81
|
-
|
|
111
|
+
route "root to: \"content/#{plural_file_name}#root\""
|
|
82
112
|
end
|
|
83
113
|
|
|
84
114
|
private
|
|
@@ -99,14 +129,6 @@ module Rails
|
|
|
99
129
|
|
|
100
130
|
def pages_controller? = plural_file_name == "pages"
|
|
101
131
|
|
|
102
|
-
def root_route_exists?
|
|
103
|
-
routes = File.join(destination_root, "config", "routes.rb")
|
|
104
|
-
|
|
105
|
-
return false unless File.exist?(routes)
|
|
106
|
-
|
|
107
|
-
File.read(routes).match?(/\broot\s+to:/)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
132
|
def template_file
|
|
111
133
|
@template_file ||= Dir.glob(File.join(content_directory, "{YYYY-MM-DD-,}template.*.tt")).first
|
|
112
134
|
end
|
|
@@ -121,6 +143,23 @@ module Rails
|
|
|
121
143
|
end
|
|
122
144
|
end
|
|
123
145
|
end
|
|
146
|
+
|
|
147
|
+
def should_include_root?
|
|
148
|
+
options[:include_root].nil? ? pages_controller? : options[:include_root]
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def root_route_exists?
|
|
152
|
+
routes = File.join(destination_root, "config", "routes.rb")
|
|
153
|
+
return false unless File.exist?(routes)
|
|
154
|
+
|
|
155
|
+
File.read(routes).match?(/\broot\s+to:/)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def data_sources
|
|
159
|
+
options[:data].map { it.split(".").first }
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def data_sources? = !options[:data].empty?
|
|
124
163
|
end
|
|
125
164
|
end
|
|
126
165
|
end
|
data/lib/perron/configuration.rb
CHANGED
|
@@ -16,12 +16,9 @@ module Perron
|
|
|
16
16
|
@config.site_name = nil
|
|
17
17
|
@config.site_description = nil
|
|
18
18
|
|
|
19
|
-
@config.site_email = nil
|
|
20
|
-
|
|
21
19
|
@config.output = "output"
|
|
22
20
|
|
|
23
21
|
@config.mode = :standalone
|
|
24
|
-
@config.include_root = false
|
|
25
22
|
|
|
26
23
|
@config.allowed_extensions = %w[erb md]
|
|
27
24
|
|
|
@@ -55,7 +52,11 @@ module Perron
|
|
|
55
52
|
|
|
56
53
|
def mode = @config.mode.to_s.inquiry
|
|
57
54
|
|
|
58
|
-
def
|
|
55
|
+
def additional_routes
|
|
56
|
+
@additional_routes || (mode.integrated? ? [] : %w[root_path])
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
attr_writer :additional_routes
|
|
59
60
|
|
|
60
61
|
def url
|
|
61
62
|
options = Perron.configuration.default_url_options
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Content
|
|
4
|
+
module Data
|
|
5
|
+
def self.const_missing(name)
|
|
6
|
+
klass = Class.new(Perron::Data) do
|
|
7
|
+
def self.const_missing(nested_name) = const_set(nested_name, Class.new(Perron::Data))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
const_set(name, klass)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
data/lib/perron/data.rb
CHANGED
|
@@ -4,6 +4,8 @@ require "csv"
|
|
|
4
4
|
|
|
5
5
|
module Perron
|
|
6
6
|
class Data < SimpleDelegator
|
|
7
|
+
include Enumerable
|
|
8
|
+
|
|
7
9
|
def initialize(identifier)
|
|
8
10
|
@identifier = identifier
|
|
9
11
|
@file_path = self.class.path_for!(identifier)
|
|
@@ -12,7 +14,51 @@ module Perron
|
|
|
12
14
|
super(records)
|
|
13
15
|
end
|
|
14
16
|
|
|
17
|
+
def each(&block) = @records.each(&block)
|
|
18
|
+
|
|
19
|
+
def count = @records.count
|
|
20
|
+
|
|
21
|
+
def first(n = nil)
|
|
22
|
+
n ? @records.first(n) : @records.first
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def last = @records.last
|
|
26
|
+
|
|
27
|
+
def [](index) = @records[index]
|
|
28
|
+
|
|
29
|
+
def size = @records.size
|
|
30
|
+
alias_method :length, :size
|
|
31
|
+
|
|
15
32
|
class << self
|
|
33
|
+
def all
|
|
34
|
+
parts = name.to_s.split("::").drop(2)
|
|
35
|
+
identifier = parts.empty? ? name.demodulize.underscore : parts.map(&:underscore).join("/")
|
|
36
|
+
|
|
37
|
+
new(identifier)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def find(id)
|
|
41
|
+
all.find { it[:id] == id || it["id"] == id }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def count = all.size
|
|
45
|
+
|
|
46
|
+
def first = all.first
|
|
47
|
+
|
|
48
|
+
def second = all[1]
|
|
49
|
+
|
|
50
|
+
def third = all[2]
|
|
51
|
+
|
|
52
|
+
def fourth = all[3]
|
|
53
|
+
|
|
54
|
+
def fifth = all[4]
|
|
55
|
+
|
|
56
|
+
def forty_two = all[41]
|
|
57
|
+
|
|
58
|
+
def last = all.last
|
|
59
|
+
|
|
60
|
+
def take(n) = all.first(n)
|
|
61
|
+
|
|
16
62
|
def path_for(identifier)
|
|
17
63
|
path = Pathname.new(identifier)
|
|
18
64
|
|
|
@@ -107,6 +153,8 @@ module Perron
|
|
|
107
153
|
|
|
108
154
|
def [](key) = @attributes[key.to_sym]
|
|
109
155
|
|
|
156
|
+
def association_value(key) = self[key]
|
|
157
|
+
|
|
110
158
|
def to_partial_path
|
|
111
159
|
@to_partial_path ||= begin
|
|
112
160
|
identifier = @identifier.to_s
|
data/lib/perron/engine.rb
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "perron/output_server"
|
|
4
|
+
|
|
3
5
|
module Perron
|
|
4
6
|
class Engine < Rails::Engine
|
|
5
7
|
initializer "perron.default_url_options" do |app|
|
|
6
8
|
app.config.action_controller.default_url_options = Perron.configuration.default_url_options
|
|
7
9
|
end
|
|
8
10
|
|
|
11
|
+
initializer "perron.output_server" do |app|
|
|
12
|
+
app.middleware.use Perron::OutputServer
|
|
13
|
+
end
|
|
14
|
+
|
|
9
15
|
rake_tasks do
|
|
10
16
|
load File.expand_path("../tasks/build.rake", __FILE__)
|
|
11
|
-
load File.expand_path("../tasks/
|
|
17
|
+
load File.expand_path("../tasks/clobber.rake", __FILE__)
|
|
12
18
|
load File.expand_path("../tasks/sync_sources.rake", __FILE__)
|
|
19
|
+
load File.expand_path("../tasks/validate.rake", __FILE__)
|
|
13
20
|
end
|
|
14
21
|
end
|
|
15
22
|
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Perron
|
|
4
|
+
class OutputServer
|
|
5
|
+
def initialize(app)
|
|
6
|
+
@app = app
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def call(environment)
|
|
10
|
+
return @app.call(environment) if disabled?
|
|
11
|
+
|
|
12
|
+
static_file(environment).then do |file|
|
|
13
|
+
file ? serve(file) : @app.call(environment)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def disabled? = !enabled?
|
|
20
|
+
|
|
21
|
+
def static_file(environment)
|
|
22
|
+
request_path = Rack::Request.new(environment).path_info
|
|
23
|
+
file_path = File.join(output_path, request_path, "index.html")
|
|
24
|
+
|
|
25
|
+
File.file?(file_path) ? file_path : nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def serve(file_path)
|
|
29
|
+
content = File.read(file_path)
|
|
30
|
+
|
|
31
|
+
[
|
|
32
|
+
200,
|
|
33
|
+
|
|
34
|
+
{
|
|
35
|
+
"Content-Type" => "text/html; charset=utf-8",
|
|
36
|
+
"Content-Length" => content.bytesize.to_s
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
[content]
|
|
40
|
+
]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def enabled? = Dir.exist?(output_path)
|
|
44
|
+
|
|
45
|
+
def output_path
|
|
46
|
+
@output_path ||= Rails.root.join(Perron.configuration.output)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -22,11 +22,11 @@ module Perron
|
|
|
22
22
|
define_method(association_name) do
|
|
23
23
|
cache_has_many_association(association_name) do
|
|
24
24
|
associated_class = association_class_for(association_name, singularize: true, **options)
|
|
25
|
-
|
|
26
|
-
primary_key_method = options.fetch(:primary_key, :slug)
|
|
27
|
-
lookup_value = public_send(primary_key_method)
|
|
25
|
+
ids_key = "#{association_name}_ids"
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
metadata[ids_key] ?
|
|
28
|
+
records_for_ids(associated_class, metadata[ids_key]) :
|
|
29
|
+
records_for_foreign_key(associated_class, association_name, **options)
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -41,6 +41,10 @@ module Perron
|
|
|
41
41
|
@belongs_to_cache[name] = yield
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
def foreign_key_for(base_name, **options)
|
|
45
|
+
(options[:foreign_key] || "#{base_name}_id").to_s
|
|
46
|
+
end
|
|
47
|
+
|
|
44
48
|
def cache_has_many_association(name)
|
|
45
49
|
@has_many_cache ||= {}
|
|
46
50
|
return @has_many_cache[name] if @has_many_cache.key?(name)
|
|
@@ -49,18 +53,28 @@ module Perron
|
|
|
49
53
|
end
|
|
50
54
|
|
|
51
55
|
def association_class_for(association_name, singularize: false, **options)
|
|
52
|
-
|
|
56
|
+
if options[:class_name]
|
|
57
|
+
options[:class_name].to_s.constantize
|
|
58
|
+
else
|
|
53
59
|
name = association_name.to_s
|
|
54
60
|
name = name.singularize if singularize
|
|
55
61
|
|
|
56
|
-
"Content::#{name.classify}"
|
|
62
|
+
"Content::#{name.classify}".constantize
|
|
57
63
|
end
|
|
64
|
+
end
|
|
58
65
|
|
|
59
|
-
|
|
66
|
+
def records_for_ids(associated_class, ids)
|
|
67
|
+
ids = Array(ids)
|
|
68
|
+
|
|
69
|
+
associated_class.all.select { ids.include?(it[:id]) || ids.include?(it["id"]) }
|
|
60
70
|
end
|
|
61
71
|
|
|
62
|
-
def
|
|
63
|
-
|
|
72
|
+
def records_for_foreign_key(associated_class, association_name, **options)
|
|
73
|
+
foreign_key = foreign_key_for(inverse_association_name, **options)
|
|
74
|
+
primary_key_method = options.fetch(:primary_key, :slug)
|
|
75
|
+
lookup_value = public_send(primary_key_method)
|
|
76
|
+
|
|
77
|
+
associated_class.all.select { it.association_value(foreign_key) == lookup_value }
|
|
64
78
|
end
|
|
65
79
|
|
|
66
80
|
def inverse_association_name = self.class.name.demodulize.underscore
|
|
@@ -12,7 +12,9 @@ module Perron
|
|
|
12
12
|
|
|
13
13
|
def count = all.size
|
|
14
14
|
|
|
15
|
-
def first =
|
|
15
|
+
def first(n = nil)
|
|
16
|
+
n ? all.first(n) : all[0]
|
|
17
|
+
end
|
|
16
18
|
|
|
17
19
|
def second = all[1]
|
|
18
20
|
|
|
@@ -30,9 +32,7 @@ module Perron
|
|
|
30
32
|
|
|
31
33
|
def collection = Collection.new(collection_name)
|
|
32
34
|
|
|
33
|
-
def root
|
|
34
|
-
collection_name.pages? && collection.find_by_file_name("root", name.constantize)
|
|
35
|
-
end
|
|
35
|
+
def root = all.find(&:root?)
|
|
36
36
|
|
|
37
37
|
def model_name
|
|
38
38
|
@model_name ||= ActiveModel::Name.new(self, nil, name.demodulize.to_s)
|
|
@@ -47,7 +47,7 @@ module Perron
|
|
|
47
47
|
|
|
48
48
|
def canonical_url
|
|
49
49
|
return @frontmatter[:canonical_url] if @frontmatter[:canonical_url]
|
|
50
|
-
return Rails.application.routes.url_helpers.root_url(**Perron.configuration.default_url_options) if @resource.
|
|
50
|
+
return Rails.application.routes.url_helpers.root_url(**Perron.configuration.default_url_options) if @resource.root?
|
|
51
51
|
|
|
52
52
|
begin
|
|
53
53
|
Rails.application.routes.url_helpers.polymorphic_url(
|
|
@@ -40,7 +40,7 @@ module Perron
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def combinations
|
|
43
|
-
datasets = source_names.map { Perron::
|
|
43
|
+
datasets = source_names.map { Perron::Data.new(it.to_s) }
|
|
44
44
|
|
|
45
45
|
datasets.first.product(*datasets[1..])
|
|
46
46
|
end
|
|
@@ -71,7 +71,8 @@ module Perron
|
|
|
71
71
|
primary_key = options[:primary_key]
|
|
72
72
|
singular_name = name.to_s.singularize
|
|
73
73
|
identifier = frontmatter["#{singular_name}_#{primary_key}"]
|
|
74
|
-
|
|
74
|
+
|
|
75
|
+
hash[name] = Perron::Data.new(name.to_s).find { it.public_send(primary_key).to_s == identifier.to_s }
|
|
75
76
|
end
|
|
76
77
|
|
|
77
78
|
Source.new(data)
|
data/lib/perron/resource.rb
CHANGED
|
@@ -66,6 +66,8 @@ module Perron
|
|
|
66
66
|
render_inline_erb using: page_content
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
def association_value(key) = metadata[key]
|
|
70
|
+
|
|
69
71
|
def to_partial_path
|
|
70
72
|
@to_partial_path ||= begin
|
|
71
73
|
element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self.class.model_name))
|
|
@@ -80,6 +82,10 @@ module Perron
|
|
|
80
82
|
def related_resources(limit: 5) = Perron::Site::Resource::Related.new(self).find(limit:)
|
|
81
83
|
alias_method :related, :related_resources
|
|
82
84
|
|
|
85
|
+
def root?
|
|
86
|
+
slug == "/"
|
|
87
|
+
end
|
|
88
|
+
|
|
83
89
|
private
|
|
84
90
|
|
|
85
91
|
def frontmatter
|
|
@@ -101,9 +107,5 @@ module Perron
|
|
|
101
107
|
def erb_processing?
|
|
102
108
|
@file_path.ends_with?(".erb") || metadata.erb == true
|
|
103
109
|
end
|
|
104
|
-
|
|
105
|
-
def root?
|
|
106
|
-
collection.name.inquiry.pages? && File.basename(filename) == "root"
|
|
107
|
-
end
|
|
108
110
|
end
|
|
109
111
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Perron
|
|
4
|
+
module Site
|
|
5
|
+
class Builder
|
|
6
|
+
class AdditionalRoutes
|
|
7
|
+
def initialize(paths)
|
|
8
|
+
@paths = paths
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def get
|
|
12
|
+
Perron.configuration.additional_routes.each do |route_name|
|
|
13
|
+
@paths << routes.public_send(route_name) if routes.respond_to?(route_name)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def routes = Rails.application.routes.url_helpers
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Perron
|
|
4
|
+
module Site
|
|
5
|
+
class Builder
|
|
6
|
+
class Feeds
|
|
7
|
+
module Author
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def author(resource)
|
|
11
|
+
author = (resource&.respond_to?(:author) && resource.author) ||
|
|
12
|
+
feed_configuration.author
|
|
13
|
+
|
|
14
|
+
Author.new(author) if author
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class Author
|
|
18
|
+
def initialize(author)
|
|
19
|
+
@author = author
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def name
|
|
23
|
+
@author.respond_to?(:metadata) ? @author.metadata.name : @author[:name]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def email
|
|
27
|
+
@author.respond_to?(:metadata) ? @author.metadata.email : @author[:email]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def url
|
|
31
|
+
@author.respond_to?(:metadata) ? @author.metadata.url : @author[:url]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def avatar
|
|
35
|
+
@author.respond_to?(:metadata) ? @author.metadata.avatar : @author[:avatar]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require "perron/site/builder/feeds/author"
|
|
4
5
|
|
|
5
6
|
module Perron
|
|
6
7
|
module Site
|
|
7
8
|
class Builder
|
|
8
9
|
class Feeds
|
|
9
10
|
class Json
|
|
11
|
+
include Feeds::Author
|
|
12
|
+
|
|
10
13
|
def initialize(collection:)
|
|
11
14
|
@collection = collection
|
|
12
15
|
@configuration = Perron.configuration
|
|
@@ -27,6 +30,7 @@ module Perron
|
|
|
27
30
|
id: resource.id,
|
|
28
31
|
url: url.polymorphic_url(resource, ref: feed_configuration.ref).delete_suffix("?ref="),
|
|
29
32
|
date_published: resource.published_at&.iso8601,
|
|
33
|
+
authors: authors(resource),
|
|
30
34
|
title: resource.metadata.title,
|
|
31
35
|
content_html: Perron::Markdown.render(resource.content)
|
|
32
36
|
}
|
|
@@ -48,6 +52,14 @@ module Perron
|
|
|
48
52
|
end
|
|
49
53
|
|
|
50
54
|
def feed_configuration = @collection.configuration.feeds.json
|
|
55
|
+
|
|
56
|
+
def authors(resource)
|
|
57
|
+
author = author(resource)
|
|
58
|
+
|
|
59
|
+
return nil unless author&.name
|
|
60
|
+
|
|
61
|
+
[{name: author.name, email: author.email, url: author.url, avatar: author.avatar}.compact].presence
|
|
62
|
+
end
|
|
51
63
|
end
|
|
52
64
|
end
|
|
53
65
|
end
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "nokogiri"
|
|
4
|
+
require "perron/site/builder/feeds/author"
|
|
4
5
|
|
|
5
6
|
module Perron
|
|
6
7
|
module Site
|
|
7
8
|
class Builder
|
|
8
9
|
class Feeds
|
|
9
10
|
class Rss
|
|
11
|
+
include Feeds::Author
|
|
12
|
+
|
|
10
13
|
def initialize(collection:)
|
|
11
14
|
@collection = collection
|
|
12
15
|
@configuration = Perron.configuration
|
|
@@ -29,6 +32,9 @@ module Perron
|
|
|
29
32
|
xml.guid resource.id
|
|
30
33
|
xml.link url.polymorphic_url(resource, ref: feed_configuration.ref).delete_suffix("?ref="), isPermaLink: true
|
|
31
34
|
xml.pubDate(resource.published_at&.rfc822)
|
|
35
|
+
if (author = author(resource)) && author.email
|
|
36
|
+
xml.author author.name ? "#{author.email} (#{author.name})" : author.email
|
|
37
|
+
end
|
|
32
38
|
xml.title resource.metadata.title
|
|
33
39
|
xml.description { xml.cdata(Perron::Markdown.render(resource.content)) }
|
|
34
40
|
end
|
|
@@ -13,11 +13,9 @@ module Perron
|
|
|
13
13
|
|
|
14
14
|
if routes.respond_to?(show_path)
|
|
15
15
|
@collection.send(:load_resources).select(&:buildable?).each do |resource|
|
|
16
|
-
|
|
16
|
+
next if resource.root?
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@paths << (root ? routes.root_path : routes.public_send(show_path, resource))
|
|
18
|
+
@paths << routes.public_send(show_path, resource)
|
|
21
19
|
|
|
22
20
|
(resource.class.try(:nested_routes) || []).each do |nested|
|
|
23
21
|
@paths << routes.polymorphic_path([resource, nested])
|
|
@@ -28,11 +26,6 @@ module Perron
|
|
|
28
26
|
|
|
29
27
|
private
|
|
30
28
|
|
|
31
|
-
def skip?(root)
|
|
32
|
-
root &&
|
|
33
|
-
Perron.configuration.mode.integrated? && Perron.configuration.exclude_root?
|
|
34
|
-
end
|
|
35
|
-
|
|
36
29
|
def routes = Rails.application.routes.url_helpers
|
|
37
30
|
|
|
38
31
|
def index_path = "#{@collection.name}_path"
|
|
@@ -13,6 +13,8 @@ module Perron
|
|
|
13
13
|
|
|
14
14
|
xml = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |builder|
|
|
15
15
|
builder.urlset(xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9") do
|
|
16
|
+
add_additional_routes(with: builder)
|
|
17
|
+
|
|
16
18
|
Perron::Site.collections.each do |collection|
|
|
17
19
|
add_urls_for(collection, with: builder)
|
|
18
20
|
end
|
|
@@ -24,6 +26,21 @@ module Perron
|
|
|
24
26
|
|
|
25
27
|
private
|
|
26
28
|
|
|
29
|
+
def add_additional_routes(with:)
|
|
30
|
+
(Perron.configuration.additional_routes || []).each do |route_name|
|
|
31
|
+
next unless routes.respond_to?(route_name)
|
|
32
|
+
|
|
33
|
+
routes.with_options(Perron.configuration.default_url_options) do |url|
|
|
34
|
+
with.url do
|
|
35
|
+
with.loc url.public_send(route_name.to_s.gsub("_path", "_url"))
|
|
36
|
+
with.priority Perron.configuration.sitemap.priority
|
|
37
|
+
with.changefreq Perron.configuration.sitemap.change_frequency
|
|
38
|
+
with.lastmod Time.current.iso8601
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
27
44
|
def add_urls_for(collection, with:)
|
|
28
45
|
return if collection.configuration.blank?
|
|
29
46
|
return if collection.configuration.sitemap.exclude == true
|
|
@@ -31,13 +48,12 @@ module Perron
|
|
|
31
48
|
collection.resources.each do |resource|
|
|
32
49
|
next if resource.metadata.sitemap == false
|
|
33
50
|
|
|
34
|
-
root = resource.slug == "/"
|
|
35
51
|
priority = resource.metadata.sitemap_priority || collection.configuration.sitemap.priority || Perron.configuration.sitemap.priority
|
|
36
52
|
change_frequency = resource.metadata.sitemap_change_frequency || collection.configuration.sitemap.change_frequency || Perron.configuration.sitemap.change_frequency
|
|
37
53
|
|
|
38
54
|
Rails.application.routes.url_helpers.with_options(Perron.configuration.default_url_options) do |url|
|
|
39
55
|
with.url do
|
|
40
|
-
with.loc root ? url.root_url : url.polymorphic_url(resource)
|
|
56
|
+
with.loc resource.root? ? url.root_url : url.polymorphic_url(resource)
|
|
41
57
|
with.priority priority
|
|
42
58
|
with.changefreq change_frequency
|
|
43
59
|
begin
|
|
@@ -49,6 +65,8 @@ module Perron
|
|
|
49
65
|
end
|
|
50
66
|
end
|
|
51
67
|
end
|
|
68
|
+
|
|
69
|
+
def routes = Rails.application.routes.url_helpers
|
|
52
70
|
end
|
|
53
71
|
end
|
|
54
72
|
end
|
data/lib/perron/site/builder.rb
CHANGED
|
@@ -5,6 +5,7 @@ require "perron/site/builder/sitemap"
|
|
|
5
5
|
require "perron/site/builder/feeds"
|
|
6
6
|
require "perron/site/builder/public_files"
|
|
7
7
|
require "perron/site/builder/paths"
|
|
8
|
+
require "perron/site/builder/additional_routes"
|
|
8
9
|
require "perron/site/builder/page"
|
|
9
10
|
|
|
10
11
|
module Perron
|
|
@@ -40,6 +41,7 @@ module Perron
|
|
|
40
41
|
|
|
41
42
|
def paths
|
|
42
43
|
Set.new.tap do |paths|
|
|
44
|
+
Perron::Site::Builder::AdditionalRoutes.new(paths).get
|
|
43
45
|
Perron::Site.collections.each { Perron::Site::Builder::Paths.new(it, paths).get }
|
|
44
46
|
end
|
|
45
47
|
end
|
data/lib/perron/site.rb
CHANGED
|
@@ -24,6 +24,8 @@ module Perron
|
|
|
24
24
|
def collection(name) = Collection.new(name)
|
|
25
25
|
|
|
26
26
|
def data(name = nil)
|
|
27
|
+
Perron.deprecator.deprecation_warning(:data, "Use Content::Data::ClassName instead, e.g. `Content::Data::Users.all`")
|
|
28
|
+
|
|
27
29
|
(name && Perron::Data.new(name)) || Perron::Data::Proxy.new
|
|
28
30
|
end
|
|
29
31
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
namespace :perron do
|
|
2
|
+
desc "Remove compiled static output"
|
|
3
|
+
task clobber: :environment do
|
|
4
|
+
output_path = Rails.root.join(Perron.configuration.output)
|
|
5
|
+
|
|
6
|
+
if Dir.exist?(output_path)
|
|
7
|
+
FileUtils.rm_rf(output_path)
|
|
8
|
+
|
|
9
|
+
puts "Removed #{output_path}"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/perron/version.rb
CHANGED
data/lib/perron.rb
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
require "perron/version"
|
|
4
4
|
require "perron/configuration"
|
|
5
|
+
require "perron/deprecator"
|
|
5
6
|
require "perron/errors"
|
|
6
|
-
require "perron/root"
|
|
7
7
|
require "perron/site"
|
|
8
|
+
require "perron/content/data"
|
|
8
9
|
require "perron/resource"
|
|
9
10
|
require "perron/markdown"
|
|
10
11
|
require "perron/feeds"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: perron
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.17.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rails Designer Developers
|
|
@@ -99,8 +99,10 @@ files:
|
|
|
99
99
|
- lib/perron.rb
|
|
100
100
|
- lib/perron/collection.rb
|
|
101
101
|
- lib/perron/configuration.rb
|
|
102
|
+
- lib/perron/content/data.rb
|
|
102
103
|
- lib/perron/data.rb
|
|
103
104
|
- lib/perron/data/proxy.rb
|
|
105
|
+
- lib/perron/deprecator.rb
|
|
104
106
|
- lib/perron/engine.rb
|
|
105
107
|
- lib/perron/errors.rb
|
|
106
108
|
- lib/perron/feeds.rb
|
|
@@ -111,6 +113,7 @@ files:
|
|
|
111
113
|
- lib/perron/html_processor/target_blank.rb
|
|
112
114
|
- lib/perron/markdown.rb
|
|
113
115
|
- lib/perron/metatags.rb
|
|
116
|
+
- lib/perron/output_server.rb
|
|
114
117
|
- lib/perron/refinements/delete_suffixes.rb
|
|
115
118
|
- lib/perron/resource.rb
|
|
116
119
|
- lib/perron/resource/associations.rb
|
|
@@ -128,11 +131,12 @@ files:
|
|
|
128
131
|
- lib/perron/resource/slug.rb
|
|
129
132
|
- lib/perron/resource/sourceable.rb
|
|
130
133
|
- lib/perron/resource/table_of_content.rb
|
|
131
|
-
- lib/perron/root.rb
|
|
132
134
|
- lib/perron/site.rb
|
|
133
135
|
- lib/perron/site/builder.rb
|
|
136
|
+
- lib/perron/site/builder/additional_routes.rb
|
|
134
137
|
- lib/perron/site/builder/assets.rb
|
|
135
138
|
- lib/perron/site/builder/feeds.rb
|
|
139
|
+
- lib/perron/site/builder/feeds/author.rb
|
|
136
140
|
- lib/perron/site/builder/feeds/json.rb
|
|
137
141
|
- lib/perron/site/builder/feeds/rss.rb
|
|
138
142
|
- lib/perron/site/builder/page.rb
|
|
@@ -141,6 +145,7 @@ files:
|
|
|
141
145
|
- lib/perron/site/builder/sitemap.rb
|
|
142
146
|
- lib/perron/site/validate.rb
|
|
143
147
|
- lib/perron/tasks/build.rake
|
|
148
|
+
- lib/perron/tasks/clobber.rake
|
|
144
149
|
- lib/perron/tasks/sync_sources.rake
|
|
145
150
|
- lib/perron/tasks/validate.rake
|
|
146
151
|
- lib/perron/version.rb
|
|
@@ -165,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
165
170
|
- !ruby/object:Gem::Version
|
|
166
171
|
version: '0'
|
|
167
172
|
requirements: []
|
|
168
|
-
rubygems_version: 4.0.
|
|
173
|
+
rubygems_version: 4.0.4
|
|
169
174
|
specification_version: 4
|
|
170
175
|
summary: Rails-based static site generator
|
|
171
176
|
test_files: []
|