sitepress-rails 2.0.0.beta3 → 2.0.0.beta8

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: 308a11e4d4472d626fb4f81581085c06e6ae98b2334f0540c314fd000be6a6c4
4
- data.tar.gz: 5fcea186abadb31c9ca5d33b392dc6b5b197c7514421f5a07857d253ef34d051
3
+ metadata.gz: 8847542b4eda39498873172a50e932d9f227bb5449ad36d164a47f563eb0d058
4
+ data.tar.gz: 027d9477d21a64e432fa4a5875570cd64b52eb5fb4124479fd360e5a8d5d31fd
5
5
  SHA512:
6
- metadata.gz: f1fa2ccd305669f776a95e9723fa4aede892ecfce34801481761278da67eeccaf12e056e07b256a81dbf2d253d09a6810f1bb906b09c54a79723a3e24de56967
7
- data.tar.gz: 1744e9291b6a268a196baaf57a2f208ddbb59b5ce62839b41bda20ee87debcacd7fa30d224a434a6c55878c7fa68ad74e1845cd21f3fbeb05bbc71937847e454
6
+ metadata.gz: 2f25562abb42ffa015f2f5736c2fe63e54f773f93f3d25fdcc8704eb23e0636fd9bd1a7e7f6834bf179092c1979620e1f96e7f1e761a1be4f3a8c8d2a2ee7591
7
+ data.tar.gz: 5fc33c2a07f472d74f1bcde41041ee833fd9bab24985282ad0e512004d5d0adc27b84c5da4cf567257699fe3f830613e040b8ebb7478760cbc137e1ef7e6d67f
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ .bundle/
2
+ log/*.log
3
+ pkg/
4
+ test/dummy/db/*.sqlite3
5
+ test/dummy/db/*.sqlite3-journal
6
+ test/dummy/log/*.log
7
+ test/dummy/tmp/
data/bin/rails ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails gems
3
+ # installed from the root of your application.
4
+
5
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
6
+ ENGINE_PATH = File.expand_path('../../lib/sitepress-rails/engine', __FILE__)
7
+
8
+ # Set up gems listed in the Gemfile.
9
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
10
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
11
+
12
+ require 'rails/all'
13
+ require 'rails/engine/commands'
@@ -4,7 +4,7 @@ module Sitepress
4
4
  # hosts like S3. To achieve this effect, we have to compile `pages/blah.html.haml`
5
5
  # to a folder with the filename `index.html`, so the final path would be `/blah/index.html`
6
6
  class DirectoryIndexPath < IndexPath
7
- def path_with_default_format
7
+ def filename_with_default_format
8
8
  File.join(node.name, "#{node.default_name}.#{format}")
9
9
  end
10
10
  end
@@ -4,16 +4,16 @@ module Sitepress
4
4
  # pages too, mainly grabbing the root, which doesn't have a name in the node, to the default_name
5
5
  # of the node, which is usually `index`.
6
6
  class IndexPath < RootPath
7
- def path_without_format
7
+ def filename_without_format
8
8
  node.name
9
9
  end
10
10
 
11
- def path_with_format
11
+ def filename_with_format
12
12
  "#{node.name}.#{format}"
13
13
  end
14
14
 
15
- def path_with_default_format
16
- path_with_format
15
+ def filename_with_default_format
16
+ filename_with_format
17
17
  end
18
18
  end
19
19
  end
@@ -13,27 +13,31 @@ module Sitepress
13
13
  @resource = resource
14
14
  end
15
15
 
16
- def path
16
+ def filename
17
17
  if format.nil?
18
- path_without_format
18
+ filename_without_format
19
19
  elsif format == node.default_format
20
- path_with_default_format
20
+ filename_with_default_format
21
21
  elsif format
22
- path_with_format
22
+ filename_with_format
23
23
  end
24
24
  end
25
25
 
26
+ def path
27
+ File.join(*resource.lineage, filename)
28
+ end
29
+
26
30
  protected
27
- def path_without_format
31
+ def filename_without_format
28
32
  node.default_name
29
33
  end
30
34
 
31
- def path_with_format
35
+ def filename_with_format
32
36
  "#{node.default_name}.#{format}"
33
37
  end
34
38
 
35
- def path_with_default_format
36
- path_with_format
39
+ def filename_with_default_format
40
+ filename_with_format
37
41
  end
38
42
  end
39
43
  end
@@ -6,63 +6,56 @@ module Sitepress
6
6
  class Compiler
7
7
  include FileUtils
8
8
 
9
- class ResourceCompiler
10
- attr_reader :resource
9
+ attr_reader :site, :root_path
11
10
 
12
- def initialize(resource)
13
- @resource = resource
11
+ def initialize(site:, root_path:, stdout: $stdout)
12
+ @site = site
13
+ @stdout = stdout
14
+ @root_path = Pathname.new(root_path)
15
+ end
16
+
17
+ # Iterates through all pages and writes them to disk
18
+ def compile
19
+ status "Building #{site.root_path.expand_path} to #{root_path.expand_path}"
20
+ resources.each do |resource, path|
21
+ if resource.renderable?
22
+ status " Rendering #{path}"
23
+ File.open(path.expand_path, "w"){ |f| f.write render resource }
24
+ else
25
+ status " Copying #{path}"
26
+ cp resource.asset.path, path.expand_path
27
+ end
28
+ rescue
29
+ status "Error building #{resource.inspect}"
30
+ raise
14
31
  end
32
+ status "Successful build to #{root_path.expand_path}"
33
+ end
34
+
35
+ private
36
+ def resources
37
+ Enumerator.new do |y|
38
+ mkdir_p root_path
15
39
 
16
- def compilation_path
17
- File.join(*resource.lineage, compilation_filename)
40
+ site.resources.each do |resource|
41
+ path = build_path resource
42
+ mkdir_p path.dirname
43
+ y << [resource, path]
44
+ end
45
+ end
18
46
  end
19
47
 
20
- # Compiled assets have a slightly different filename for assets, especially the root node.
21
- def compilation_filename(path_builder: BuildPaths::DirectoryIndexPath, root_path_builder: BuildPaths::RootPath)
22
- path_builder = resource.node.root? ? root_path_builder : path_builder
23
- path_builder.new(resource).path
48
+ def build_path(resource)
49
+ path_builder = resource.node.root? ? BuildPaths::RootPath : BuildPaths::DirectoryIndexPath
50
+ root_path.join path_builder.new(resource).path
24
51
  end
25
52
 
26
- def render(page)
53
+ def render(resource)
27
54
  Renderers::Server.new(resource).render
28
55
  end
29
- end
30
56
 
31
- attr_reader :site
32
-
33
- def initialize(site:, stdout: $stdout)
34
- @site = site
35
- @stdout = stdout
36
- end
37
-
38
- # Iterates through all pages and writes them to disk
39
- def compile(target_path:)
40
- target_path = Pathname.new(target_path)
41
- mkdir_p target_path
42
- cache_resources = @site.cache_resources
43
- @stdout.puts "Compiling #{@site.root_path.expand_path}"
44
-
45
- begin
46
- @site.cache_resources = true
47
- @site.resources.each do |resource|
48
- compiler = ResourceCompiler.new(resource)
49
- path = target_path.join(compiler.compilation_path)
50
- mkdir_p path.dirname
51
- if resource.renderable?
52
- @stdout.puts " Rendering #{path}"
53
- File.open(path.expand_path, "w"){ |f| f.write compiler.render(resource) }
54
- else
55
- @stdout.puts " Copying #{path}"
56
- FileUtils.cp resource.asset.path, path.expand_path
57
- end
58
- rescue => e
59
- @stdout.puts "Error compiling #{resource.inspect}"
60
- raise
61
- end
62
- @stdout.puts "Successful compilation to #{target_path.expand_path}"
63
- ensure
64
- @site.cache_resources = cache_resources
57
+ def status(message)
58
+ @stdout.puts message
65
59
  end
66
- end
67
60
  end
68
61
  end
@@ -20,26 +20,20 @@ module Sitepress
20
20
  # Load paths from `Sitepress#site` into rails so it can render views, helpers, etc. properly.
21
21
  initializer :set_sitepress_paths, before: :set_autoload_paths do |app|
22
22
  app.paths["app/helpers"].push site.helpers_path.expand_path
23
+ app.paths["app/assets"].push site.assets_path.expand_path
23
24
  app.paths["app/views"].push site.root_path.expand_path
24
25
  app.paths["app/views"].push site.pages_path.expand_path
25
26
  end
26
27
 
27
28
  # Configure sprockets paths for the site.
28
- initializer :set_asset_paths, before: :append_assets_path do |app|
29
+ initializer :set_manifest_file_path, before: :append_assets_path do |app|
29
30
  manifest_file = sitepress_configuration.manifest_file_path.expand_path
30
-
31
- if manifest_file.exist?
32
- app.paths["app/assets"].push site.assets_path.expand_path
33
- app.config.assets.precompile << manifest_file.to_s
34
- else
35
- Rails.logger.warn "WARNING: Sitepress could not enable Sprockets because it could not find a manifest file at #{manifest_file.to_s.inspect}."
36
- end
31
+ app.config.assets.precompile << manifest_file.to_s if manifest_file.exist?
37
32
  end
38
33
 
39
34
  # Configure Sitepress with Rails settings.
40
35
  initializer :configure_sitepress do |app|
41
36
  sitepress_configuration.parent_engine = app
42
- sitepress_configuration.cache_resources = app.config.cache_classes
43
37
  end
44
38
 
45
39
  private
@@ -3,11 +3,11 @@ require "sitepress-core"
3
3
  module Sitepress
4
4
  autoload :Compiler, "sitepress/compiler"
5
5
  autoload :RailsConfiguration, "sitepress/rails_configuration"
6
- autoload :RouteConstraint, "sitepress/route_constraint"
7
6
  module Renderers
8
7
  autoload :Controller, "sitepress/renderers/controller"
9
8
  autoload :Server, "sitepress/renderers/server"
10
9
  end
10
+ autoload :RouteConstraint, "sitepress/route_constraint"
11
11
  module BuildPaths
12
12
  autoload :RootPath, "sitepress/build_paths/root_path"
13
13
  autoload :IndexPath, "sitepress/build_paths/index_path"
@@ -17,6 +17,9 @@ module Sitepress
17
17
  # Rescued by ActionController to display page not found error.
18
18
  PageNotFoundError = Class.new(StandardError)
19
19
 
20
+ # Raised when any of the Render subclasses can't render a page.
21
+ RenderingError = Class.new(RuntimeError)
22
+
20
23
  # Make site available via Sitepress.site from Rails app.
21
24
  def self.site
22
25
  configuration.site
@@ -1,18 +1,20 @@
1
1
  module Sitepress
2
2
  module Renderers
3
+ # This would be the ideal way to render Sitepress resources, but there's a lot
4
+ # of hackery involved in getting it to work properly.
3
5
  class Controller
4
- attr_reader :controller, :page
6
+ attr_reader :controller, :resource
5
7
 
6
- def initialize(page, controller = SiteController)
8
+ def initialize(resource, controller = SiteController)
7
9
  @controller = controller
8
- @page = page
10
+ @resource = resource
9
11
  end
10
12
 
11
13
  def render
12
- renderer.render inline: page.body,
13
- type: page.asset.template_extensions.last,
14
+ renderer.render inline: resource.body,
15
+ type: resource.asset.template_extensions.last,
14
16
  layout: resolve_layout,
15
- content_type: page.mime_type.to_s
17
+ content_type: resource.mime_type.to_s
16
18
  end
17
19
 
18
20
  private
@@ -29,15 +31,15 @@ module Sitepress
29
31
  end
30
32
 
31
33
  def renderer
32
- controller.renderer.new("PATH_INFO" => page.request_path)
34
+ controller.renderer.new("PATH_INFO" => resource.request_path)
33
35
  end
34
36
 
35
37
  def resolve_layout
36
- return page.data.fetch("layout") if page.data.key? "layout"
38
+ return resource.data.fetch("layout") if resource.data.key? "layout"
37
39
  return layout unless has_layout_conditions?
38
40
 
39
41
  clause, formats = layout_conditions.first
40
- format = page.format.to_s
42
+ format = resource.format.to_s
41
43
 
42
44
  case clause
43
45
  when :only
@@ -1,21 +1,29 @@
1
1
  module Sitepress
2
2
  module Renderers
3
+ # Renders resources by invoking a rack call to the Rails application. From my
4
+ # experiments rendering as of 2021, this is the most reliable way to render
5
+ # resources. Rendering via `Renderers::Controller` has lots of various subtle issues
6
+ # that are surprising. People don't like surprises, so I opted to render through a
7
+ # slightly heavier stack.
3
8
  class Server
4
- attr_reader :rails_app, :page
9
+ attr_reader :rails_app, :resource
5
10
 
6
- def initialize(page, rails_app = Rails.application)
11
+ def initialize(resource, rails_app = Rails.application)
7
12
  @rails_app = rails_app
8
- @page = page
13
+ @resource = resource
9
14
  end
10
15
 
11
16
  def render
12
17
  code, headers, response = rails_app.routes.call env
13
18
  response.body
19
+ rescue => e
20
+ raise RenderingError.new "Error rendering #{resource.request_path.inspect} at #{resource.asset.path.expand_path.to_s.inspect}:\n#{e.message}"
14
21
  end
15
22
 
23
+ private
16
24
  def env
17
25
  {
18
- "PATH_INFO"=> page.request_path,
26
+ "PATH_INFO"=> resource.request_path,
19
27
  "REQUEST_METHOD"=>"GET",
20
28
  "rack.input" => "GET"
21
29
  }
@@ -0,0 +1,132 @@
1
+ module Sitepress
2
+ # Serves up Sitepress site pages in a rails application. This is mixed into the
3
+ # Sitepress::SiteController, but may be included into other controllers for static
4
+ # page behavior.
5
+ module SitePages
6
+ # Rails 5 requires a format to be given to the private layout method
7
+ # to return the path to the layout.
8
+ DEFAULT_PAGE_RAILS_FORMATS = [:html].freeze
9
+
10
+ # Default root path of resources.
11
+ ROOT_RESOURCE_PATH = "".freeze
12
+
13
+ extend ActiveSupport::Concern
14
+
15
+ included do
16
+ rescue_from Sitepress::PageNotFoundError, with: :page_not_found
17
+ helper Sitepress::Engine.helpers
18
+ helper_method :current_page, :site
19
+ before_action :append_relative_partial_path, only: :show
20
+ after_action :reload_site, only: :show
21
+ end
22
+
23
+ def show
24
+ render_page current_page
25
+ end
26
+
27
+ protected
28
+ def render_page(page)
29
+ if page.renderable?
30
+ render_text_resource page
31
+ else
32
+ send_binary_resource page
33
+ end
34
+ end
35
+
36
+ def current_page
37
+ @current_page ||= find_resource
38
+ end
39
+
40
+ def site
41
+ Sitepress.site
42
+ end
43
+
44
+ def page_not_found(e)
45
+ raise ActionController::RoutingError, e.message
46
+ end
47
+
48
+ private
49
+ def append_relative_partial_path
50
+ append_view_path current_page.asset.path.dirname
51
+ end
52
+
53
+ def render_text_resource(resource)
54
+ render inline: resource.body,
55
+ type: resource.asset.template_extensions.last,
56
+ layout: resource.data.fetch("layout", controller_layout),
57
+ content_type: resource.mime_type.to_s
58
+ end
59
+
60
+ def send_binary_resource(resource)
61
+ send_file resource.asset.path,
62
+ disposition: :inline,
63
+ type: resource.mime_type.to_s
64
+ end
65
+
66
+ # Sitepress::PageNotFoundError is handled in the default Sitepress::SiteController
67
+ # with an execption that Rails can use to display a 404 error.
68
+ def get(path)
69
+ resource = site.resources.get(path)
70
+ if resource.nil?
71
+ # TODO: Display error in context of Reources class root.
72
+ raise Sitepress::PageNotFoundError, "No such page: #{path}"
73
+ else
74
+ resource
75
+ end
76
+ end
77
+
78
+ # Default finder of the resource for the current controller context. If the :resource_path
79
+ # isn't present, then its probably the root path so grab that.
80
+ def find_resource
81
+ get params.fetch(:resource_path, ROOT_RESOURCE_PATH)
82
+ end
83
+
84
+ # Returns the current layout for the inline Sitepress renderer. This is
85
+ # exposed via some really convoluted private methods inside of the various
86
+ # versions of Rails, so I try my best to hack out the path to the layout below.
87
+ def controller_layout
88
+ private_layout_method = self.method(:_layout)
89
+ layout =
90
+ if Rails.version >= "6"
91
+ private_layout_method.call lookup_context, current_page_rails_formats
92
+ elsif Rails.version >= "5"
93
+ private_layout_method.call current_page_rails_formats
94
+ else
95
+ private_layout_method.call
96
+ end
97
+
98
+ if layout.instance_of? String # Rails 4 and 5 return a string from above.
99
+ layout
100
+ elsif layout # Rails 3 and older return an object that gives us a file name
101
+ File.basename(layout.identifier).split('.').first
102
+ else
103
+ # If none of the conditions are met, then no layout was
104
+ # specified, so nil is returned.
105
+ nil
106
+ end
107
+ end
108
+
109
+ # Rails 5 requires an extension, like `:html`, to resolve a template. This
110
+ # method returns the intersection of the formats Rails supports from Mime::Types
111
+ # and the current page's node formats. If nothing intersects, HTML is returned
112
+ # as a default.
113
+ def current_page_rails_formats
114
+ extensions = current_page.node.formats.extensions
115
+ supported_extensions = extensions & Mime::EXTENSION_LOOKUP.keys
116
+
117
+ if supported_extensions.empty?
118
+ DEFAULT_PAGE_RAILS_FORMATS
119
+ else
120
+ supported_extensions.map?(&:to_sym)
121
+ end
122
+ end
123
+
124
+ def reload_site
125
+ site.reload! if reload_site?
126
+ end
127
+
128
+ def reload_site?
129
+ !Rails.configuration.cache_classes
130
+ end
131
+ end
132
+ end