sitepress-rails 2.0.0 → 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -19
- data/bin/rails +2 -2
- data/lib/sitepress/engine.rb +2 -0
- data/lib/sitepress/model.rb +68 -0
- data/lib/sitepress/models/collection.rb +34 -0
- data/lib/sitepress/rails.rb +14 -1
- data/lib/sitepress/rails_configuration.rb +1 -4
- data/lib/sitepress/route_constraint.rb +3 -1
- data/lib/sitepress/routing_mapper.rb +31 -0
- data/rails/app/controllers/concerns/sitepress/site_pages.rb +2 -1
- data/rails/lib/generators/sitepress/controller/USAGE +8 -0
- data/rails/lib/generators/sitepress/controller/controller_generator.rb +19 -0
- data/rails/lib/generators/sitepress/controller/templates/controllers/site_controller.rb +17 -0
- data/rails/lib/generators/sitepress/install/USAGE +10 -0
- data/rails/lib/generators/sitepress/install/install_generator.rb +14 -0
- data/rails/lib/generators/sitepress/install/templates/helpers/page_helper.rb +29 -0
- data/rails/lib/generators/sitepress/install/templates/models/page_model.rb +4 -0
- data/rails/lib/generators/sitepress/install/templates/pages/index.html.erb +43 -0
- data/rails/test/lib/generators/sitepress/controller_generator_test.rb +14 -0
- data/rails/test/lib/generators/sitepress/install_generator_test.rb +14 -0
- data/sitepress-rails.gemspec +3 -2
- data/spec/dummy/app/content/models/page_model.rb +4 -0
- data/spec/dummy/config/routes.rb +1 -0
- data/spec/dummy/log/test.log +175 -81066
- data/spec/sitepress/model_spec.rb +35 -0
- data/spec/sitepress/routes_spec.rb +7 -22
- data/spec/sitepress-rails_spec.rb +7 -22
- data/spec/spec_helper.rb +15 -0
- metadata +24 -12
- data/rails/config/routes.rb +0 -12
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/production.log +0 -1976
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afddca0543c4d48b1396e4ab46caba5cbab0e061a1cf40e8e0a2acc5fb1d2888
|
4
|
+
data.tar.gz: 34ae7a93bd7d5ed9fb0a5de0ab56a7633542a9e5f729f035f1680e86886ce9b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b795c53a066ddf2c05f101ce344f95bd1cc474688c58ee31bd5183e6efed805e77c7fb2f9775d881a08343ee26ef87cd6e6525cab61bec2bbdaaf576d21aa25f
|
7
|
+
data.tar.gz: 35d52136f43f3aa6337eadeaf4d605f256166ccf777ad34b94a75b4fef8694b20d89bc5d968101ce224f08ee859653a0fcb86f55635453971bc66b746c7ab922
|
data/README.md
CHANGED
@@ -4,37 +4,27 @@ Sitepress is a file-backed website content manager that can be embedded in popul
|
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
Add
|
7
|
+
Add `sitepress-rails` to a Rails application by running:
|
8
8
|
|
9
9
|
```ruby
|
10
|
-
|
10
|
+
bundle add sitepress-rails
|
11
11
|
```
|
12
12
|
|
13
|
-
|
13
|
+
The install content pages by running:
|
14
14
|
|
15
15
|
```bash
|
16
|
-
$
|
16
|
+
$ ./bin/rails generate sitepress:install
|
17
17
|
```
|
18
18
|
|
19
|
-
|
19
|
+
This command creates a few content pages and adds the following to the `config/routes.rb` file:
|
20
20
|
|
21
21
|
```ruby
|
22
|
-
|
22
|
+
sitepress_pages
|
23
|
+
sitepress_root # Delete if you don't want your app's root page to be a content page.
|
23
24
|
```
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
```bash
|
28
|
-
$ mkdir -p app/content/pages
|
29
|
-
```
|
30
|
-
|
31
|
-
Then add pages to the `app/content/pages` directory:
|
32
|
-
|
33
|
-
```bash
|
34
|
-
$ echo "<h1>Hello</h1><p>It is <%= Time.now %> o'clock</p>" > app/content/pages/hello.html.erb
|
35
|
-
```
|
36
|
-
|
37
|
-
Point your browser to `http://127.0.0.1:3000/hello` and if all went well you should see the page you just created.
|
26
|
+
Restart the Rails application server and point your browser to `http://127.0.0.1:3000/` and if all went well you should see a sitepress page.
|
38
27
|
|
39
28
|
## License
|
29
|
+
|
40
30
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/bin/rails
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
# This command will automatically be run when you run "rails" with Rails gems
|
3
3
|
# installed from the root of your application.
|
4
4
|
|
5
|
-
ENGINE_ROOT = File.expand_path('
|
6
|
-
ENGINE_PATH = File.expand_path('../../lib/sitepress
|
5
|
+
ENGINE_ROOT = File.expand_path('../../rails', __FILE__)
|
6
|
+
ENGINE_PATH = File.expand_path('../../lib/sitepress/engine', __FILE__)
|
7
7
|
|
8
8
|
# Set up gems listed in the Gemfile.
|
9
9
|
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
data/lib/sitepress/engine.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "rails/engine"
|
2
|
+
require "sitepress/routing_mapper"
|
2
3
|
|
3
4
|
module Sitepress
|
4
5
|
class Engine < ::Rails::Engine
|
@@ -23,6 +24,7 @@ module Sitepress
|
|
23
24
|
app.paths["app/assets"].push site.assets_path.expand_path
|
24
25
|
app.paths["app/views"].push site.root_path.expand_path
|
25
26
|
app.paths["app/views"].push site.pages_path.expand_path
|
27
|
+
app.paths["app/models"].push site.models_path.expand_path
|
26
28
|
end
|
27
29
|
|
28
30
|
# Configure sprockets paths for the site.
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Sitepress
|
2
|
+
# Wraps a page in a class, which makes it much easier to decorate and validate.
|
3
|
+
class Model
|
4
|
+
attr_reader :page
|
5
|
+
|
6
|
+
delegate \
|
7
|
+
:request_path,
|
8
|
+
:data,
|
9
|
+
:body,
|
10
|
+
to: :page
|
11
|
+
|
12
|
+
def initialize(page)
|
13
|
+
@page = page
|
14
|
+
end
|
15
|
+
|
16
|
+
# Treat as equal if the resource and model class are the same.
|
17
|
+
def ==(model)
|
18
|
+
self.page == model.page and self.class == model.class
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
delegate \
|
23
|
+
:first,
|
24
|
+
to: :all
|
25
|
+
|
26
|
+
# Defines a class method that may be called later to return a
|
27
|
+
# collection of objects.
|
28
|
+
def collection(name = Models::Collection::DEFAULT_NAME, glob:, **kwargs)
|
29
|
+
define_singleton_method name do
|
30
|
+
self.glob glob, **kwargs
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Adhoc querying of models via `Model.glob("foo/bar").all`
|
35
|
+
def glob(glob, **kwargs)
|
36
|
+
Models::Collection.new model: self, site: site, glob: glob, **kwargs
|
37
|
+
end
|
38
|
+
|
39
|
+
# Wraps a page in a class if given a string that represents the path or
|
40
|
+
# a page object itself.
|
41
|
+
def get(page)
|
42
|
+
case page
|
43
|
+
when Model
|
44
|
+
page
|
45
|
+
when String
|
46
|
+
new site.get page
|
47
|
+
when Sitepress::Resource
|
48
|
+
new page
|
49
|
+
else
|
50
|
+
raise ModelNotFoundError, "#{self.inspect} could not find #{page.inspect}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
alias :find :get
|
54
|
+
|
55
|
+
def data(*keys, default: nil)
|
56
|
+
keys.each do |key|
|
57
|
+
define_method key do
|
58
|
+
self.data.fetch key.to_s, default
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def site
|
64
|
+
Sitepress.site
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Sitepress
|
2
|
+
module Models
|
3
|
+
# Everything needed to iterate over a set of resources from a glob and wrap
|
4
|
+
# them in a model so they are returned as a sensible enumerable.
|
5
|
+
class Collection
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
# Page models will have `PageModel.all` method defined by default.
|
9
|
+
DEFAULT_NAME = :all
|
10
|
+
|
11
|
+
# Iterate over all resources in the site by default.
|
12
|
+
DEFAULT_GLOB = "**/*.*".freeze
|
13
|
+
|
14
|
+
attr_reader :model, :glob, :site
|
15
|
+
|
16
|
+
def initialize(model:, site:, glob: DEFAULT_GLOB)
|
17
|
+
@model = model
|
18
|
+
@glob = glob
|
19
|
+
@site = site
|
20
|
+
end
|
21
|
+
|
22
|
+
def resources
|
23
|
+
site.glob glob
|
24
|
+
end
|
25
|
+
|
26
|
+
# Wraps each resource in a model object.
|
27
|
+
def each
|
28
|
+
resources.each do |resource|
|
29
|
+
yield model.new resource
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/sitepress/rails.rb
CHANGED
@@ -2,6 +2,10 @@ require "sitepress-core"
|
|
2
2
|
|
3
3
|
module Sitepress
|
4
4
|
autoload :Compiler, "sitepress/compiler"
|
5
|
+
autoload :Model, "sitepress/model"
|
6
|
+
module Models
|
7
|
+
autoload :Collection, "sitepress/models/collection"
|
8
|
+
end
|
5
9
|
autoload :RailsConfiguration, "sitepress/rails_configuration"
|
6
10
|
module Renderers
|
7
11
|
autoload :Controller, "sitepress/renderers/controller"
|
@@ -15,8 +19,17 @@ module Sitepress
|
|
15
19
|
autoload :DirectoryIndexPath, "sitepress/build_paths/directory_index_path"
|
16
20
|
end
|
17
21
|
|
22
|
+
# Base class for errors if Sitepress can't find a resource, model, etc.
|
23
|
+
NotFoundError = Class.new(StandardError)
|
24
|
+
|
18
25
|
# Rescued by ActionController to display page not found error.
|
19
|
-
|
26
|
+
ResourceNotFoundError = Class.new(NotFoundError)
|
27
|
+
# Accidentally left out `Error` in the constant name, so I'm setting
|
28
|
+
# that up here for backwards compatability.
|
29
|
+
ResourceNotFound = ResourceNotFoundError
|
30
|
+
|
31
|
+
# Raised if a model isn't found.
|
32
|
+
ModelNotFoundError = Class.new(NotFoundError)
|
20
33
|
|
21
34
|
# Raised when any of the Render subclasses can't render a page.
|
22
35
|
RenderingError = Class.new(RuntimeError)
|
@@ -6,13 +6,10 @@ module Sitepress
|
|
6
6
|
# Store in ./app/content by default.
|
7
7
|
DEFAULT_SITE_ROOT = "app/content".freeze
|
8
8
|
|
9
|
-
attr_accessor :
|
9
|
+
attr_accessor :cache_resources
|
10
10
|
attr_writer :site, :parent_engine
|
11
11
|
|
12
12
|
def initialize
|
13
|
-
# Injects routes into parent apps routes when set to true. Set to false
|
14
|
-
# to inject routes manually.
|
15
|
-
self.routes = true
|
16
13
|
# Caches sites between requests. Set to `false` for development environments.
|
17
14
|
self.cache_resources = true
|
18
15
|
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
module Sitepress
|
2
2
|
# Route constraint for rails routes.rb file.
|
3
3
|
class RouteConstraint
|
4
|
+
attr_reader :site
|
5
|
+
|
4
6
|
def initialize(site: Sitepress.site)
|
5
7
|
@site = site
|
6
8
|
end
|
7
9
|
|
8
10
|
def matches?(request)
|
9
|
-
|
11
|
+
!!site.resources.get(request.path)
|
10
12
|
end
|
11
13
|
end
|
12
14
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ActionDispatch::Routing
|
2
|
+
# I have no idea how or why this works this way, I lifted the pattern from Devise, which came with even
|
3
|
+
# more weird stuff. Rails could use an API for adding route helpers to decrease the brittleness of this
|
4
|
+
# approach. For now, deal with this helper.
|
5
|
+
class Mapper
|
6
|
+
DEFAULT_CONTROLLER = "sitepress/site".freeze
|
7
|
+
DEFAULT_ACTION = "show".freeze
|
8
|
+
ROUTE_GLOB_KEY = "/*resource_path".freeze
|
9
|
+
|
10
|
+
# Hook up all the Sitepress pages
|
11
|
+
def sitepress_pages(controller: DEFAULT_CONTROLLER, action: DEFAULT_ACTION, root: false, constraints: Sitepress::RouteConstraint.new)
|
12
|
+
get ROUTE_GLOB_KEY,
|
13
|
+
controller: controller,
|
14
|
+
action: action,
|
15
|
+
as: :page,
|
16
|
+
format: false,
|
17
|
+
constraints: constraints
|
18
|
+
|
19
|
+
sitepress_root controller: controller, action: action if root
|
20
|
+
end
|
21
|
+
|
22
|
+
# Hook sitepress root up to the index of rails.
|
23
|
+
def sitepress_root(controller: DEFAULT_CONTROLLER, action: DEFAULT_ACTION)
|
24
|
+
if has_named_route? :root
|
25
|
+
Rails.logger.warn "Sitepress tried to configured the 'root' route, but it was already defined. Check the 'routes.rb' file for a 'root' route or call 'sitepress_pages(root: false)'."
|
26
|
+
else
|
27
|
+
root controller: controller, action: action
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -71,7 +71,7 @@ module Sitepress
|
|
71
71
|
# Send the inline rendered, post-processed string into the Rails rendering method that actually sends
|
72
72
|
# the output to the end-user as a web response.
|
73
73
|
def post_render(rendition)
|
74
|
-
render
|
74
|
+
render body: rendition.output, content_type: rendition.mime_type
|
75
75
|
end
|
76
76
|
|
77
77
|
# A reference to the current resource that's being requested.
|
@@ -116,6 +116,7 @@ module Sitepress
|
|
116
116
|
if resource.nil?
|
117
117
|
raise Sitepress::ResourceNotFound, "No such page: #{path}"
|
118
118
|
else
|
119
|
+
Rails.logger.info "Sitepress resolved asset #{resource.asset.path}"
|
119
120
|
resource
|
120
121
|
end
|
121
122
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Sitepress::ControllerGenerator < Rails::Generators::Base
|
2
|
+
source_root File.expand_path("templates", __dir__)
|
3
|
+
|
4
|
+
def copy_files
|
5
|
+
directory ".", "app"
|
6
|
+
end
|
7
|
+
|
8
|
+
def append_controller_to_sitepress_root_route
|
9
|
+
inject_into_file "config/routes.rb", after: "sitepress_root" do
|
10
|
+
" controller: :site"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def append_controller_to_sitepress_pages_route
|
15
|
+
inject_into_file "config/routes.rb", after: "sitepress_pages" do
|
16
|
+
" controller: :site"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class SiteController < Sitepress::SiteController
|
2
|
+
# Override this method to implement your processing logic for Sitepress pages.
|
3
|
+
def show
|
4
|
+
render_resource current_resource
|
5
|
+
end
|
6
|
+
|
7
|
+
protected
|
8
|
+
|
9
|
+
# This is to be used by end users if they need to do any post-processing on the rendering page.
|
10
|
+
# For example, the user may use Nokogiri to parse static HTML pages and hook it into the asset pipeline.
|
11
|
+
# They may also use tools like `HTMLPipeline` to process links from a markdown renderer.
|
12
|
+
#
|
13
|
+
# For example, the rendition could be modified via `Nokogiri::HTML5::DocumentFragment(rendition)`.
|
14
|
+
def process_rendition(rendition)
|
15
|
+
# Do nothing unless the user extends this method.
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Sitepress
|
2
|
+
class InstallGenerator < Rails::Generators::Base
|
3
|
+
source_root File.expand_path("templates", __dir__)
|
4
|
+
|
5
|
+
def copy_files
|
6
|
+
directory ".", "app/content"
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_sitepress_routes
|
10
|
+
route "sitepress_root"
|
11
|
+
route "sitepress_pages"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module PageHelper
|
2
|
+
# Creates a hyperlink to a page using the `title` key. Change the default in the args
|
3
|
+
# below if you use a different key for page titles.
|
4
|
+
def link_to_page(page, title_key: "title")
|
5
|
+
link_to page.data.fetch(title_key, page.request_path), page.request_path
|
6
|
+
end
|
7
|
+
|
8
|
+
# Quick and easy way to change the class of a page if its current. Useful for
|
9
|
+
# navigation menus.
|
10
|
+
def link_to_if_current(text, page, active_class: "active")
|
11
|
+
if page == current_page
|
12
|
+
link_to text, page.request_path, class: active_class
|
13
|
+
else
|
14
|
+
link_to text, page.request_path
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Conditionally renders the block if an arg is present. If all the args are nil,
|
19
|
+
# the block is not rendered. Handy for laconic templating languages like slim, haml, etc.
|
20
|
+
def with(*args, &block)
|
21
|
+
block.call(*args) unless args.all?(&:nil?)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Render a block within a layout. This is a useful, and prefered way, to handle
|
25
|
+
# nesting layouts, within Sitepress.
|
26
|
+
def render_layout(layout, **kwargs, &block)
|
27
|
+
render html: capture(&block), layout: "layouts/#{layout}", **kwargs
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
---
|
2
|
+
title: Getting started with Sitepress in Rails
|
3
|
+
---
|
4
|
+
|
5
|
+
<style>
|
6
|
+
.sitepress {
|
7
|
+
max-width: 90%;
|
8
|
+
}
|
9
|
+
.sitepress h1 {
|
10
|
+
font-weight: bold;
|
11
|
+
font-size: 3rem;
|
12
|
+
margin-bottom: 4rem;
|
13
|
+
}
|
14
|
+
.sitepress h2 {
|
15
|
+
font-weight: bold;
|
16
|
+
font-size: 1.5rem;
|
17
|
+
}
|
18
|
+
.sitepress * {
|
19
|
+
margin-top: 1rem;
|
20
|
+
}
|
21
|
+
.sitepress code {
|
22
|
+
font-family: monospace;
|
23
|
+
font-size: 1rem;
|
24
|
+
}
|
25
|
+
.sitepress a {
|
26
|
+
text-decoration: underline;
|
27
|
+
}
|
28
|
+
</style>
|
29
|
+
|
30
|
+
<article class="sitepress">
|
31
|
+
<h1><%= current_page.data.fetch("title") %></h1>
|
32
|
+
|
33
|
+
<p>This was generated by the <code>rails generate sitepress:install</code> command.</p>
|
34
|
+
|
35
|
+
<h2>Content</h2>
|
36
|
+
<p>Sitepress content files are in <code><%= site.root_path.expand_path %></code>. There you can edit site content, including this file at <code><%= current_page.asset.path %></code>.
|
37
|
+
|
38
|
+
<h2>Routes</h2>
|
39
|
+
<p>Sitepress defined a root route in <code><%= Rails.root.join("config/routes.rb") %></code>. If that conflicts with your routes configuration, you'll want to open it and edit accordingly.</p>
|
40
|
+
|
41
|
+
<h2>Documentation</h2>
|
42
|
+
<p>Check out the <a href="https://sitepress.cc">Sitepress website</a> for help on getting started and documentation. Since Sitepress is also built on top of Rails, most of the <a href="https://guides.rubyonrails.org/action_view_helpers.html">Rails view helpers</a> work too.</p>
|
43
|
+
</article>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "generators/sitepress/controller/controller_generator"
|
3
|
+
|
4
|
+
class Sitepress::ControllerGeneratorTest < Rails::Generators::TestCase
|
5
|
+
tests Sitepress::ControllerGenerator
|
6
|
+
destination Rails.root.join("tmp/generators")
|
7
|
+
setup :prepare_destination
|
8
|
+
|
9
|
+
# test "generator runs without errors" do
|
10
|
+
# assert_nothing_raised do
|
11
|
+
# run_generator ["arguments"]
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "generators/sitepress/install/install_generator"
|
3
|
+
|
4
|
+
class Sitepress::InstallGeneratorTest < Rails::Generators::TestCase
|
5
|
+
tests Sitepress::InstallGenerator
|
6
|
+
destination Rails.root.join("tmp/generators")
|
7
|
+
setup :prepare_destination
|
8
|
+
|
9
|
+
# test "generator runs without errors" do
|
10
|
+
# assert_nothing_raised do
|
11
|
+
# run_generator ["arguments"]
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
end
|
data/sitepress-rails.gemspec
CHANGED
@@ -19,14 +19,15 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
spec.test_files = Dir["spec/**/*"]
|
21
21
|
|
22
|
+
rails_version = ">= 6.0"
|
23
|
+
|
22
24
|
spec.add_development_dependency "rspec-rails"
|
23
25
|
spec.add_development_dependency "pry"
|
24
|
-
spec.add_development_dependency "rails",
|
26
|
+
spec.add_development_dependency "rails", rails_version
|
25
27
|
|
26
28
|
spec.add_runtime_dependency "sitepress-core", spec.version
|
27
29
|
|
28
30
|
# We don't need every single rals rependency, so grab the subset here.
|
29
|
-
rails_version = ">= 6.0"
|
30
31
|
spec.add_dependency "railties", rails_version
|
31
32
|
spec.add_dependency "actionpack", rails_version
|
32
33
|
spec.add_dependency "sprockets-rails", ">= 2.0.0"
|
data/spec/dummy/config/routes.rb
CHANGED