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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f86f6e49cb1954ed51dc8aa0c2b6cfdaf3f1fcc3c78141b36c837f0eef26a9c8
4
- data.tar.gz: efaff555c00579430812ca06e3ee6a87376db403321ab302762b393356d7607a
3
+ metadata.gz: fbf1b0d5483938df7b88423f3ecd72bffaf938eadcc49a3001a34fcb0156dfb9
4
+ data.tar.gz: cd8871c7ef91a102a45bcebbcdc8bbf385db3a83ffb34948cd0d3e49c14d8237
5
5
  SHA512:
6
- metadata.gz: c7e7c64d77fac8aadb06e3fc3541db5f8593a571938c12020dcbcb03e3f968dd326eede32b06342843df4b0e84e8722b4beb95b5d202283539b763ba3db01ada
7
- data.tar.gz: 1a3f470b3412fa9187bca282ee1ac051cd1674c34a19a761b6cdedf901f0e5e2e6bb2c1a025ffadf1e2f478fcf13b9f8a90ab29579d46ae0cf3594099b13fb5d
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.15.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
- minitest (5.25.5)
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.4)
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
- # config.output = "output"
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
- # In `integrated` mode, the root is skipped by default. Set to `true` to enable
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 create_pages_root
66
+ def add_content_route
64
67
  return if @content_mode
65
- return unless pages_controller?
66
68
 
67
- template "root.erb.tt", File.join(content_directory, "root.erb")
69
+ route "resources :#{plural_file_name}, module: :content, only: %w[#{actions.join(" ")}]"
68
70
  end
69
71
 
70
- def add_content_route
72
+ def create_data_sources
71
73
  return if @content_mode
74
+ return if options[:data].empty?
72
75
 
73
- route "resources :#{plural_file_name}, module: :content, only: %w[#{actions.join(" ")}]"
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 pages_controller?
108
+ return unless should_include_root?
79
109
  return if root_route_exists?
80
110
 
81
- inject_into_file "config/routes.rb", " root to: \"content/pages#root\"\n", before: /^\s*end\s*$/
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
@@ -1,2 +1,13 @@
1
1
  class Content::<%= class_name %> < Perron::Resource
2
+ <% if data_sources? -%>
3
+
4
+ sources <%= data_sources.map { ":#{it}" }.join(", ") %>
5
+
6
+ def self.source_template(sources)
7
+ <<~TEMPLATE
8
+ ---
9
+ ---
10
+ TEMPLATE
11
+ end
12
+ <% end -%>
2
13
  end
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  ---
3
3
 
4
- Find me in `app/content/pages/root.erb`
4
+ Find me in `app/content/<%= plural_file_name %>/root.erb`
@@ -3,5 +3,5 @@
3
3
  <%%= @resource.filename %>
4
4
  </h1>
5
5
 
6
- <%%= markdownify @resource.content %>
6
+ <%%= @resource.content %>
7
7
  </article>
@@ -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 exclude_root? = !@config.include_root
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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perron
4
+ def self.deprecator
5
+ @deprecator ||= ActiveSupport::Deprecation.new("1.0", "Perron")
6
+ end
7
+ end
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/validate.rake", __FILE__)
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
- foreign_key = foreign_key_for(inverse_association_name, **options)
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
- associated_class.all.select { |record| record.metadata[foreign_key] == lookup_value }
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
- class_name = options[:class_name] || begin
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
- class_name.constantize
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 foreign_key_for(base_name, **options)
63
- (options[:foreign_key] || "#{base_name}_id").to_s
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 = all[0]
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.slug == "/"
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(
@@ -9,6 +9,7 @@ module Perron
9
9
  def previewable?
10
10
  frontmatter.preview.present? && (draft? || scheduled?)
11
11
  end
12
+ alias_method :preview?, :previewable?
12
13
 
13
14
  def preview_token
14
15
  return nil unless previewable?
@@ -40,7 +40,7 @@ module Perron
40
40
  end
41
41
 
42
42
  def combinations
43
- datasets = source_names.map { Perron::Site.data.public_send(it) }
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
- hash[name] = Perron::Site.data.public_send(name).find { it.public_send(primary_key).to_s == identifier.to_s }
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)
@@ -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
- root = resource.slug == "/"
16
+ next if resource.root?
17
17
 
18
- next if skip? root
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Perron
2
- VERSION = "0.15.0"
2
+ VERSION = "0.17.0"
3
3
  end
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.15.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.1
173
+ rubygems_version: 4.0.4
169
174
  specification_version: 4
170
175
  summary: Rails-based static site generator
171
176
  test_files: []
data/lib/perron/root.rb DELETED
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Perron
4
- module Root
5
- include ActiveSupport::Concern
6
-
7
- def root
8
- @resource = Content::Page.root
9
-
10
- render :show
11
- end
12
- end
13
- end