sitepress-rails 2.0.0 → 3.0.1

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -19
  3. data/bin/rails +2 -2
  4. data/lib/sitepress/engine.rb +2 -0
  5. data/lib/sitepress/model.rb +68 -0
  6. data/lib/sitepress/models/collection.rb +34 -0
  7. data/lib/sitepress/rails.rb +14 -1
  8. data/lib/sitepress/rails_configuration.rb +1 -4
  9. data/lib/sitepress/route_constraint.rb +3 -1
  10. data/lib/sitepress/routing_mapper.rb +31 -0
  11. data/rails/app/controllers/concerns/sitepress/site_pages.rb +2 -1
  12. data/rails/lib/generators/sitepress/controller/USAGE +8 -0
  13. data/rails/lib/generators/sitepress/controller/controller_generator.rb +19 -0
  14. data/rails/lib/generators/sitepress/controller/templates/controllers/site_controller.rb +17 -0
  15. data/rails/lib/generators/sitepress/install/USAGE +10 -0
  16. data/rails/lib/generators/sitepress/install/install_generator.rb +14 -0
  17. data/rails/lib/generators/sitepress/install/templates/helpers/page_helper.rb +29 -0
  18. data/rails/lib/generators/sitepress/install/templates/models/page_model.rb +4 -0
  19. data/rails/lib/generators/sitepress/install/templates/pages/index.html.erb +43 -0
  20. data/rails/test/lib/generators/sitepress/controller_generator_test.rb +14 -0
  21. data/rails/test/lib/generators/sitepress/install_generator_test.rb +14 -0
  22. data/sitepress-rails.gemspec +3 -2
  23. data/spec/dummy/app/content/models/page_model.rb +4 -0
  24. data/spec/dummy/config/routes.rb +1 -0
  25. data/spec/dummy/log/test.log +175 -81066
  26. data/spec/sitepress/model_spec.rb +35 -0
  27. data/spec/sitepress/routes_spec.rb +7 -22
  28. data/spec/sitepress-rails_spec.rb +7 -22
  29. data/spec/spec_helper.rb +15 -0
  30. metadata +24 -12
  31. data/rails/config/routes.rb +0 -12
  32. data/spec/dummy/db/test.sqlite3 +0 -0
  33. data/spec/dummy/log/production.log +0 -1976
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e02f24add74ef6493bdea2486f8d9e2eb4b24f6070ba72bfd3c0b15dc5ad09da
4
- data.tar.gz: 149b6a137086b0c65dd5fe3c6d91bb1ff3b5c0acc6fddcf45d9a39c4583cf183
3
+ metadata.gz: f643e0b041182d550499080a8ecc6f3faec68f4c66f325bbcfe1d9e4d1540df4
4
+ data.tar.gz: f4b48adf5b963b72ac89fb285327bbb6bbc9bc99e003f055ae6eb4a3f375d702
5
5
  SHA512:
6
- metadata.gz: e9990fc71151cba0e82e4c9b2745dd57c91dcbd18fb42b5cd815bbd6aa852c60847fedf63bd720199e2e3ddab2f2cc77096a3b96efc4c56b40bfda41ec7193be
7
- data.tar.gz: a8737c1757a5da80edcbdf2dea6cb0c48a204577c083c3bbd219124870ca69eb12d1a6fdfa79d55be12b3f1ff3dd0db18d909e6deb03727e03ae664a49192bf6
6
+ metadata.gz: 2273ca5bc01ebfa3fbc769b9ad5506ffc10801df844aaf442d6e12b910fe26eded7f5e273dc5626d963618a01b2d4d6fee3d29282876b5af2205f8135700e64e
7
+ data.tar.gz: 17b75049b7af578c3ecd96d7befa59b72b017116f94fa7a8710c757936cf9581356ec34c772de3841ad8135764dbc91a8901e1d5c93f7dfde4b0d2152622e42a
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 this line to your application's Gemfile:
7
+ Add `sitepress-rails` to a Rails application by running:
8
8
 
9
9
  ```ruby
10
- gem 'sitepress-rails'
10
+ bundle add sitepress-rails
11
11
  ```
12
12
 
13
- And then execute:
13
+ The install content pages by running:
14
14
 
15
15
  ```bash
16
- $ bundle
16
+ $ ./bin/rails generate sitepress:install
17
17
  ```
18
18
 
19
- Then mount the engine into your `config/routes.rb` file:
19
+ This command creates a few content pages and adds the following to the `config/routes.rb` file:
20
20
 
21
21
  ```ruby
22
- mount Sitepress::Engine => "/"
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
- Create the `app/content/pages` in your rails project:
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('../..', __FILE__)
6
- ENGINE_PATH = File.expand_path('../../lib/sitepress-rails/engine', __FILE__)
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__)
@@ -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
@@ -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
- ResourceNotFound = Class.new(StandardError)
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 :routes, :cache_resources
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
- !!@site.resources.get(request.path)
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 inline: rendition.output, content_type: rendition.mime_type
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,8 @@
1
+ Description:
2
+ Installs a controller that can be used to manipulate Sitepress responses.
3
+
4
+ Example:
5
+ bin/rails generate sitepress:controller SiteController
6
+
7
+ This will create:
8
+ app/controllers/site_controller.rb
@@ -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,10 @@
1
+ Description:
2
+ Installs Sitepress in a Rails appliation
3
+
4
+ Example:
5
+ bin/rails generate sitepress:install
6
+
7
+ This will create:
8
+ app/content/models/page_model.rb
9
+ app/content/helpers/page_helpers.rb
10
+ app/content/pages/index.html.erb
@@ -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,4 @@
1
+ class PageModel < Sitepress::Model
2
+ collection glob: "**/*.html*"
3
+ data :title
4
+ 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
@@ -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", ">= 4.0"
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"
@@ -0,0 +1,4 @@
1
+ class PageModel < Sitepress::Model
2
+ collection glob: "**/*.html*"
3
+ data :title
4
+ end
@@ -1,3 +1,4 @@
1
1
  Rails.application.routes.draw do
2
2
  get "/baseline/render", to: "baseline#show"
3
+ sitepress_pages
3
4
  end