perron 0.14.0 → 0.15.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: '080352c09efb475419f74de6ee7cf01a491d4cc349f6cf0d6e23d35132c83953'
4
- data.tar.gz: 156c0419afc4c3aa77411ac7f7508cbea56de584d164624be86b4d2615baf7f5
3
+ metadata.gz: f86f6e49cb1954ed51dc8aa0c2b6cfdaf3f1fcc3c78141b36c837f0eef26a9c8
4
+ data.tar.gz: efaff555c00579430812ca06e3ee6a87376db403321ab302762b393356d7607a
5
5
  SHA512:
6
- metadata.gz: c75e1453c34bf8a8b8a4345d9167110745c1c47d8094aea3345e85fb46de51b0d326c904a7132c20e058ae89156c48dac5b9311121fc0359ad1d348ccde7d27f
7
- data.tar.gz: a3acd15ee6f0224c032b31dac7272539e6ed6e6c9451a4b22d47c83c108f8fa374f5b6b7ceab97ae7bf4d6cc1296bbac8cd9c8788b28c7187f50c29c4621ee01
6
+ metadata.gz: c7e7c64d77fac8aadb06e3fc3541db5f8593a571938c12020dcbcb03e3f968dd326eede32b06342843df4b0e84e8722b4beb95b5d202283539b763ba3db01ada
7
+ data.tar.gz: 1a3f470b3412fa9187bca282ee1ac051cd1674c34a19a761b6cdedf901f0e5e2e6bb2c1a025ffadf1e2f478fcf13b9f8a90ab29579d46ae0cf3594099b13fb5d
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- perron (0.14.0)
4
+ perron (0.15.0)
5
5
  csv
6
6
  json
7
7
  psych
@@ -11,10 +11,7 @@ module Perron
11
11
  end
12
12
 
13
13
  def create_data_directory
14
- data_directory = Rails.root.join("app", "content", "data")
15
- empty_directory data_directory
16
-
17
- template "README.md.tt", File.join(data_directory, "README.md")
14
+ template "README.md.tt", "app/content/data/README.md"
18
15
  end
19
16
 
20
17
  def add_markdown_gems
@@ -0,0 +1,41 @@
1
+ Description:
2
+ Generates content model scaffold (controller, views, routes) or creates
3
+ new content files from templates.
4
+
5
+ Examples:
6
+ Generate content scaffold:
7
+ rails generate content Post
8
+ rails generate content Post index
9
+ rails generate content Post index show
10
+
11
+ This will create:
12
+ app/content/posts/
13
+ app/models/content/post.rb
14
+ app/controllers/content/posts_controller.rb
15
+ app/views/content/posts/index.html.erb
16
+ app/views/content/posts/show.html.erb
17
+
18
+ And adds: resources :posts, module: :content, only: %w[index show]
19
+
20
+ Create new content file from template:
21
+ rails generate content Post --new
22
+ rails generate content Post --new "My First Post"
23
+
24
+ This will create a new content file in app/content/posts/ using:
25
+ - YYYY-MM-DD-template.*.tt (if exists, with date prefix)
26
+ - template.*.tt (if exists, without date prefix)
27
+ - Empty file with frontmatter dashes (if no template)
28
+
29
+ Template files support ERB:
30
+ ---
31
+ title: <%= @title %>
32
+ published_at: <%= Time.current %>
33
+ ---
34
+
35
+ Arguments:
36
+ NAME: Name of the content model (singular or plural)
37
+ actions: Actions to generate (default: index show)
38
+
39
+ Options:
40
+ --new [TITLE]: Create new content file instead of scaffold
41
+ --force-plural: Use plural form for model name and class
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/base"
4
+
5
+ module Rails
6
+ module Generators
7
+ class ContentGenerator < Rails::Generators::NamedBase
8
+ source_root File.expand_path("templates", __dir__)
9
+
10
+ class_option :force_plural, type: :boolean, default: false, desc: "Forces the use of a plural model name and class"
11
+ class_option :new, type: :string, default: nil, banner: "TITLE",
12
+ desc: "Create a new content file from template instead of generating scaffold"
13
+
14
+ argument :actions, type: :array, default: %w[index show], banner: "actions", desc: "Specify which actions to generate (index/show)"
15
+
16
+ def initialize(*args)
17
+ super
18
+
19
+ @content_mode = !options[:new].nil?
20
+ @content_title = options[:new].presence
21
+ end
22
+
23
+ def create_content_file
24
+ return unless @content_mode
25
+
26
+ @title = @content_title
27
+
28
+ if template_file
29
+ create_file File.join(content_directory, filename_from_template), ERB.new(File.read(template_file)).result(binding)
30
+ else
31
+ create_file File.join(content_directory, filename_from_template), "---\n---\n"
32
+ end
33
+ end
34
+
35
+ def create_model
36
+ return if @content_mode
37
+
38
+ template "model.rb.tt", File.join("app/models/content", "#{file_name}.rb")
39
+ end
40
+
41
+ def create_controller
42
+ return if @content_mode
43
+
44
+ template "controller.rb.tt", File.join("app/controllers/content", "#{plural_file_name}_controller.rb")
45
+ end
46
+
47
+ def create_views
48
+ return if @content_mode
49
+
50
+ empty_directory view_directory
51
+
52
+ actions.each do |action|
53
+ template "#{action}.html.erb.tt", File.join(view_directory, "#{action}.html.erb")
54
+ end
55
+ end
56
+
57
+ def create_content_directory
58
+ return if @content_mode
59
+
60
+ FileUtils.mkdir_p(content_directory)
61
+ end
62
+
63
+ def create_pages_root
64
+ return if @content_mode
65
+ return unless pages_controller?
66
+
67
+ template "root.erb.tt", File.join(content_directory, "root.erb")
68
+ end
69
+
70
+ def add_content_route
71
+ return if @content_mode
72
+
73
+ route "resources :#{plural_file_name}, module: :content, only: %w[#{actions.join(" ")}]"
74
+ end
75
+
76
+ def add_root_route
77
+ return if @content_mode
78
+ return unless pages_controller?
79
+ return if root_route_exists?
80
+
81
+ inject_into_file "config/routes.rb", " root to: \"content/pages#root\"\n", before: /^\s*end\s*$/
82
+ end
83
+
84
+ private
85
+
86
+ def file_name
87
+ options[:force_plural] ? super.pluralize : super.singularize
88
+ end
89
+
90
+ def class_name
91
+ options[:force_plural] ? super.pluralize : super.singularize
92
+ end
93
+
94
+ def view_directory = File.join(destination_root, "app", "views", "content", plural_file_name)
95
+
96
+ def content_directory = File.join(destination_root, "app", "content", plural_file_name)
97
+
98
+ def plural_class_name = plural_name.camelize
99
+
100
+ def pages_controller? = plural_file_name == "pages"
101
+
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
+ def template_file
111
+ @template_file ||= Dir.glob(File.join(content_directory, "{YYYY-MM-DD-,}template.*.tt")).first
112
+ end
113
+
114
+ def filename_from_template
115
+ @filename_from_template ||= begin
116
+ return "untitled.md" unless template_file
117
+
118
+ File.basename(template_file, ".tt").tap do |name|
119
+ name.gsub!("YYYY-MM-DD", Time.current.strftime("%Y-%m-%d"))
120
+ name.sub!("template", @content_title ? @content_title.parameterize : "untitled")
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -16,17 +16,12 @@ module Perron
16
16
  end
17
17
 
18
18
  def all(resource_class = "Content::#{name.classify}".safe_constantize)
19
- allowed_extensions = Perron.configuration.allowed_extensions.map { ".#{it}" }.to_set
20
-
21
- Dir.glob("#{@collection_path}/**/*.*")
22
- .select { allowed_extensions.include?(File.extname(it)) }
23
- .map { resource_class.new(it) }
24
- .select(&:published?)
19
+ load_resources(resource_class).select(&:published?)
25
20
  end
26
21
  alias_method :resources, :all
27
22
 
28
23
  def find(slug, resource_class = Resource)
29
- resource = all(resource_class).find { it.slug == slug }
24
+ resource = load_resources(resource_class).find { it.slug == slug }
30
25
 
31
26
  return resource if resource
32
27
 
@@ -40,5 +35,15 @@ module Perron
40
35
  end
41
36
 
42
37
  def validate = Perron::Site::Validate.new(collections: [self]).validate
38
+
39
+ private
40
+
41
+ def load_resources(resource_class = "Content::#{name.classify}".safe_constantize)
42
+ allowed_extensions = Perron.configuration.allowed_extensions.map { ".#{it}" }.to_set
43
+
44
+ Dir.glob("#{@collection_path}/**/*.*")
45
+ .select { allowed_extensions.include?(File.extname(it)) }
46
+ .map { resource_class.new(it) }
47
+ end
43
48
  end
44
49
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perron
4
+ class Resource
5
+ module Previewable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ def previewable?
10
+ frontmatter.preview.present? && (draft? || scheduled?)
11
+ end
12
+
13
+ def preview_token
14
+ return nil unless previewable?
15
+
16
+ @preview_token ||= if frontmatter.preview == true
17
+ Digest::SHA256.hexdigest(file_path)[0..11]
18
+ else
19
+ frontmatter.preview
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -16,8 +16,16 @@ module Perron
16
16
  true
17
17
  end
18
18
 
19
+ def buildable?
20
+ published? || previewable?
21
+ end
22
+
19
23
  def scheduled? = publication_date&.after?(Time.current)
20
24
 
25
+ def draft?
26
+ frontmatter.draft == true || frontmatter.published == false
27
+ end
28
+
21
29
  def publication_date
22
30
  @publication_date ||= begin
23
31
  from_meta = frontmatter.published_at.present? ? begin
@@ -15,8 +15,9 @@ module Perron
15
15
  def create
16
16
  return "/" if Perron.configuration.allowed_extensions.any? { @resource.filename == "root.#{it}" }
17
17
 
18
- @frontmatter.slug.presence ||
19
- @resource.filename.sub(/^[\d-]+-/, "").delete_suffixes(dot_prepended_allowed_extensions)
18
+ base_slug = @frontmatter.slug.presence || @resource.filename.sub(/^[\d-]+-/, "").delete_suffixes(dot_prepended_allowed_extensions)
19
+
20
+ [base_slug, @resource.preview_token].compact.join("-")
20
21
  end
21
22
 
22
23
  private
@@ -5,6 +5,7 @@ require "perron/resource/core"
5
5
  require "perron/resource/class_methods"
6
6
  require "perron/resource/associations"
7
7
  require "perron/resource/metadata"
8
+ require "perron/resource/previewable"
8
9
  require "perron/resource/publishable"
9
10
  require "perron/resource/reading_time"
10
11
  require "perron/resource/related"
@@ -27,6 +28,7 @@ module Perron
27
28
  include Perron::Resource::ReadingTime
28
29
  include Perron::Resource::Sourceable
29
30
  include Perron::Resource::Publishable
31
+ include Perron::Resource::Previewable
30
32
  include Perron::Resource::TableOfContent
31
33
 
32
34
  attr_reader :file_path, :id
@@ -12,7 +12,7 @@ module Perron
12
12
  @paths << routes.public_send(index_path) if routes.respond_to?(index_path)
13
13
 
14
14
  if routes.respond_to?(show_path)
15
- @collection.all.each do |resource|
15
+ @collection.send(:load_resources).select(&:buildable?).each do |resource|
16
16
  root = resource.slug == "/"
17
17
 
18
18
  next if skip? root
@@ -31,6 +31,8 @@ module Perron
31
31
  Perron::Site::Builder::Sitemap.new(@output_path).generate
32
32
  Perron::Site::Builder::Feeds.new(@output_path).generate
33
33
 
34
+ output_preview_urls
35
+
34
36
  puts "\n✅ Build complete"
35
37
  end
36
38
 
@@ -43,6 +45,17 @@ module Perron
43
45
  end
44
46
 
45
47
  def render_page(path) = Perron::Site::Builder::Page.new(path).render
48
+
49
+ def output_preview_urls
50
+ previewable_resources = Perron::Site.collections.flat_map { it.send(:load_resources) }.select(&:previewable?)
51
+
52
+ if previewable_resources.any?
53
+ puts "\n🔒 Preview URLs:"
54
+ previewable_resources.each do |resource|
55
+ puts " #{Rails.application.routes.url_helpers.polymorphic_url(resource, **Perron.configuration.default_url_options)}"
56
+ end
57
+ end
58
+ end
46
59
  end
47
60
  end
48
61
  end
@@ -1,3 +1,3 @@
1
1
  module Perron
2
- VERSION = "0.14.0"
2
+ VERSION = "0.15.0"
3
3
  end
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.14.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rails Designer Developers
@@ -86,16 +86,16 @@ files:
86
86
  - bin/rails
87
87
  - bin/release
88
88
  - bin/setup
89
- - lib/generators/content/USAGE
90
- - lib/generators/content/content_generator.rb
91
- - lib/generators/content/templates/controller.rb.tt
92
- - lib/generators/content/templates/index.html.erb.tt
93
- - lib/generators/content/templates/model.rb.tt
94
- - lib/generators/content/templates/root.erb.tt
95
- - lib/generators/content/templates/show.html.erb.tt
96
89
  - lib/generators/perron/install_generator.rb
97
90
  - lib/generators/perron/templates/README.md.tt
98
91
  - lib/generators/perron/templates/initializer.rb.tt
92
+ - lib/generators/rails/content/USAGE
93
+ - lib/generators/rails/content/content_generator.rb
94
+ - lib/generators/rails/content/templates/controller.rb.tt
95
+ - lib/generators/rails/content/templates/index.html.erb.tt
96
+ - lib/generators/rails/content/templates/model.rb.tt
97
+ - lib/generators/rails/content/templates/root.erb.tt
98
+ - lib/generators/rails/content/templates/show.html.erb.tt
99
99
  - lib/perron.rb
100
100
  - lib/perron/collection.rb
101
101
  - lib/perron/configuration.rb
@@ -118,6 +118,7 @@ files:
118
118
  - lib/perron/resource/configuration.rb
119
119
  - lib/perron/resource/core.rb
120
120
  - lib/perron/resource/metadata.rb
121
+ - lib/perron/resource/previewable.rb
121
122
  - lib/perron/resource/publishable.rb
122
123
  - lib/perron/resource/reading_time.rb
123
124
  - lib/perron/resource/related.rb
@@ -164,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
164
165
  - !ruby/object:Gem::Version
165
166
  version: '0'
166
167
  requirements: []
167
- rubygems_version: 3.6.9
168
+ rubygems_version: 4.0.1
168
169
  specification_version: 4
169
170
  summary: Rails-based static site generator
170
171
  test_files: []
@@ -1,16 +0,0 @@
1
- Description:
2
- Creates a new content model with specified actions
3
-
4
- Example:
5
- rails generate content post
6
-
7
- This will create:
8
- - app/models/content/post.rb
9
- - app/controllers/content/posts_controller.rb
10
- - app/views/content/posts/index.html.erb
11
- - app/views/content/posts/show.html.erb
12
- - …and add `resource :posts, module: :content, only: %w[index show]` to `config/routes.rb`
13
-
14
- Arguments:
15
- NAME: Name of the content model
16
- actions: List of actions to generate (index or show)
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "rails/generators/base"
4
-
5
- class ContentGenerator < Rails::Generators::NamedBase
6
- source_root File.expand_path("templates", __dir__)
7
-
8
- class_option :force_plural, type: :boolean, default: false, desc: "Forces the use of a plural model name and class"
9
-
10
- argument :actions, type: :array, default: %w[index show], banner: "actions", desc: "Specify which actions to generate (index/show)"
11
-
12
- def create_model
13
- template "model.rb.tt", File.join("app/models/content", "#{file_name}.rb")
14
- end
15
-
16
- def create_controller
17
- template "controller.rb.tt", File.join("app/controllers/content", "#{plural_file_name}_controller.rb")
18
- end
19
-
20
- def create_views
21
- empty_directory view_directory
22
-
23
- actions.each do |action|
24
- template "#{action}.html.erb.tt", File.join(view_directory, "#{action}.html.erb")
25
- end
26
- end
27
-
28
- def create_content_directory = FileUtils.mkdir_p(content_directory)
29
-
30
- def create_pages_root
31
- return unless pages_controller?
32
-
33
- template "root.erb.tt", File.join(content_directory, "root.erb")
34
- end
35
-
36
- def add_content_route
37
- route "resources :#{plural_file_name}, module: :content, only: %w[#{actions.join(" ")}]"
38
- end
39
-
40
- def add_root_route
41
- return unless pages_controller?
42
- return if root_route_exists?
43
-
44
- inject_into_file "config/routes.rb", " root to: \"content/pages#root\"\n", before: /^\s*end\s*$/
45
- end
46
-
47
- private
48
-
49
- def file_name
50
- options[:force_plural] ? super.pluralize : super.singularize
51
- end
52
-
53
- def class_name
54
- options[:force_plural] ? super.pluralize : super.singularize
55
- end
56
-
57
- def view_directory = Rails.root.join("app", "views", "content", plural_file_name)
58
-
59
- def content_directory = Rails.root.join("app", "content", plural_file_name)
60
-
61
- def plural_class_name = plural_name.camelize
62
-
63
- def pages_controller? = plural_file_name == "pages"
64
-
65
- def root_route_exists?
66
- routes = Rails.root.join("config", "routes.rb")
67
-
68
- return false unless File.exist?(routes)
69
-
70
- File.read(routes).match?(/\broot\s+to:/)
71
- end
72
- end