perron 0.15.0 → 0.16.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: 709c1a304332c522dd7e425824f2718b1a84994db9695b842cddab07fa2a6c2d
4
+ data.tar.gz: cd636faddbff65dd1cc27652fb9141a936ce7df7e5f4fca1e156fd7b1ff27522
5
5
  SHA512:
6
- metadata.gz: c7e7c64d77fac8aadb06e3fc3541db5f8593a571938c12020dcbcb03e3f968dd326eede32b06342843df4b0e84e8722b4beb95b5d202283539b763ba3db01ada
7
- data.tar.gz: 1a3f470b3412fa9187bca282ee1ac051cd1674c34a19a761b6cdedf901f0e5e2e6bb2c1a025ffadf1e2f478fcf13b9f8a90ab29579d46ae0cf3594099b13fb5d
6
+ metadata.gz: 40df8027fb5974b0670a80b4c61e918da1f3dd7cec833e5fab48cdb606ddb9d9e56480cb69ad3c3033c2fdf1deb09e0c105cb15730cb92581e1d57c3db57ce3f
7
+ data.tar.gz: af0d331538e600ad27d23f9377d6cdabcc1f3142ad7d07de517b002334c0414896edb45d6d0d5d6ab50a6af81be12f4b2bf667c15e8bc50e211a824b6701d1b2
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.16.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
@@ -16,8 +16,6 @@ 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
@@ -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
@@ -13,6 +13,17 @@ module Perron
13
13
  end
14
14
 
15
15
  class << self
16
+ def all
17
+ parts = name.to_s.split("::").drop(2)
18
+ identifier = parts.empty? ? name.demodulize.underscore : parts.map(&:underscore).join("/")
19
+
20
+ new(identifier)
21
+ end
22
+
23
+ def find(id)
24
+ all.find { it[:id] == id || it["id"] == id }
25
+ end
26
+
16
27
  def path_for(identifier)
17
28
  path = Pathname.new(identifier)
18
29
 
@@ -107,6 +118,8 @@ module Perron
107
118
 
108
119
  def [](key) = @attributes[key.to_sym]
109
120
 
121
+ def association_value(key) = self[key]
122
+
110
123
  def to_partial_path
111
124
  @to_partial_path ||= begin
112
125
  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
@@ -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))
@@ -0,0 +1,41 @@
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.author || feed_configuration.author
12
+
13
+ Author.new(author) if author
14
+ end
15
+
16
+ class Author
17
+ def initialize(author)
18
+ @author = author
19
+ end
20
+
21
+ def name
22
+ @author.respond_to?(:metadata) ? @author.metadata.name : @author[:name]
23
+ end
24
+
25
+ def email
26
+ @author.respond_to?(:metadata) ? @author.metadata.email : @author[:email]
27
+ end
28
+
29
+ def url
30
+ @author.respond_to?(:metadata) ? @author.metadata.url : @author[:url]
31
+ end
32
+
33
+ def avatar
34
+ @author.respond_to?(:metadata) ? @author.metadata.avatar : @author[:avatar]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ 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
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.16.0"
3
3
  end
data/lib/perron.rb CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  require "perron/version"
4
4
  require "perron/configuration"
5
+ require "perron/deprecator"
5
6
  require "perron/errors"
6
7
  require "perron/root"
7
8
  require "perron/site"
9
+ require "perron/content/data"
8
10
  require "perron/resource"
9
11
  require "perron/markdown"
10
12
  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.16.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
@@ -133,6 +136,7 @@ files:
133
136
  - lib/perron/site/builder.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.3
169
174
  specification_version: 4
170
175
  summary: Rails-based static site generator
171
176
  test_files: []