foxpage 0.1.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +9 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +76 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/exe/foxpage +6 -0
- data/foxpage.gemspec +59 -0
- data/lib/fox_page/app_parts/base.rb +15 -0
- data/lib/fox_page/app_parts/builder.rb +13 -0
- data/lib/fox_page/app_parts/configuration.rb +46 -0
- data/lib/fox_page/app_parts/routes.rb +25 -0
- data/lib/fox_page/app_parts/server.rb +13 -0
- data/lib/fox_page/app_parts/sprockets.rb +28 -0
- data/lib/fox_page/app_parts.rb +24 -0
- data/lib/fox_page/app_template/__dot__gitignore.tt +2 -0
- data/lib/fox_page/app_template/__dot__rubocop.yml.tt +9 -0
- data/lib/fox_page/app_template/app/assets/images/__dot__keep.tt +0 -0
- data/lib/fox_page/app_template/app/assets/stylesheets/application.scss.tt +8 -0
- data/lib/fox_page/app_template/app/controllers/application_controller.rb.tt +4 -0
- data/lib/fox_page/app_template/app/controllers/home_controller.rb.tt +13 -0
- data/lib/fox_page/app_template/app/helpers/application_helper.rb.tt +5 -0
- data/lib/fox_page/app_template/app/views/home/index.haml.tt +4 -0
- data/lib/fox_page/app_template/app/views/layouts/_footer.haml.tt +5 -0
- data/lib/fox_page/app_template/app/views/layouts/default.haml.tt +15 -0
- data/lib/fox_page/app_template/config/application.rb.tt +6 -0
- data/lib/fox_page/app_template/config/boot.rb.tt +6 -0
- data/lib/fox_page/app_template/config/environment.rb.tt +5 -0
- data/lib/fox_page/app_template/config/routes.rb.tt +12 -0
- data/lib/fox_page/app_template/config/site.yml.tt +41 -0
- data/lib/fox_page/app_template/gems.rb.tt +9 -0
- data/lib/fox_page/app_template/public/__dot__keep.tt +0 -0
- data/lib/fox_page/application.rb +31 -0
- data/lib/fox_page/builders/assets.rb +28 -0
- data/lib/fox_page/builders/file_copy.rb +22 -0
- data/lib/fox_page/builders/pages.rb +124 -0
- data/lib/fox_page/cli.rb +35 -0
- data/lib/fox_page/controller.rb +17 -0
- data/lib/fox_page/generator.rb +40 -0
- data/lib/fox_page/helpers/app_helper.rb +20 -0
- data/lib/fox_page/helpers/assets_helper.rb +17 -0
- data/lib/fox_page/helpers/render_helper.rb +17 -0
- data/lib/fox_page/refinements/camelize.rb +13 -0
- data/lib/fox_page/refinements/to_deep_open_struct.rb +33 -0
- data/lib/fox_page/router.rb +56 -0
- data/lib/fox_page/server.rb +47 -0
- data/lib/fox_page/site_builder.rb +32 -0
- data/lib/fox_page/version.rb +5 -0
- data/lib/fox_page.rb +20 -0
- data/lib/foxpage.rb +3 -0
- data/misc/foxpage.png +0 -0
- data/misc/foxpage.svg +28 -0
- metadata +272 -0
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
App.draw_routes do
|
4
|
+
# This defines the landing page of your website.
|
5
|
+
root "home#index"
|
6
|
+
|
7
|
+
# Additional routes can be created by using `map`.
|
8
|
+
# For example to map `/projects` to the index method of ProjectsController,
|
9
|
+
# you can do this:
|
10
|
+
#
|
11
|
+
# map "/projects" => "projects#index"
|
12
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
---
|
2
|
+
# This file defines everything that's available via `App.config` in your
|
3
|
+
# website.
|
4
|
+
#
|
5
|
+
# Here are some site defaults:
|
6
|
+
site:
|
7
|
+
title: <%= name.inspect %>
|
8
|
+
description: |-
|
9
|
+
Another site created with FoxPage.
|
10
|
+
url: "https://example.com" # the base hostname & protocol for your site
|
11
|
+
|
12
|
+
# You can also add your own items here. For example, here is what a list of
|
13
|
+
# social media sites could look like:
|
14
|
+
#
|
15
|
+
# social_media:
|
16
|
+
# - name: GitHub
|
17
|
+
# css_class: github
|
18
|
+
# url: "https://github.com/<yourusername>"
|
19
|
+
# - name: Mastodon
|
20
|
+
# css_class: mastodon
|
21
|
+
# url: "https://ruby.social/@<yourusername>"
|
22
|
+
#
|
23
|
+
# In a view, you can then iterate over it like this:
|
24
|
+
#
|
25
|
+
# - App.config.site.social_media.each do |site|
|
26
|
+
# %a{class: site.css_class, href: site.url}= site.name
|
27
|
+
|
28
|
+
# This list defines all the assets that should be built. By default it only
|
29
|
+
# includes the main application style sheet.
|
30
|
+
#
|
31
|
+
# All image assets will be added to the assets pipeline automatically.
|
32
|
+
#
|
33
|
+
# To use an asset in a view, you can use the `assets_path` helper, e.g:
|
34
|
+
#
|
35
|
+
# %img{src: asset_path("lisp-alien.png")}
|
36
|
+
#
|
37
|
+
# For style sheets, you can use the `stylesheet_link_tag` helper:
|
38
|
+
#
|
39
|
+
# = stylesheet_link_tag("application.css")
|
40
|
+
assets:
|
41
|
+
- application.css
|
File without changes
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
require "forwardable"
|
5
|
+
require "yaml"
|
6
|
+
|
7
|
+
module FoxPage
|
8
|
+
class Application
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
prepend AppParts::Builder
|
12
|
+
prepend AppParts::Configuration
|
13
|
+
prepend AppParts::Routes
|
14
|
+
prepend AppParts::Server
|
15
|
+
prepend AppParts::Sprockets
|
16
|
+
|
17
|
+
def initialize!
|
18
|
+
AppParts.initializers_for(self.class).each do |proc|
|
19
|
+
instance_eval(&proc)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# delegate _ALL_ the things!
|
24
|
+
self.class.extend Forwardable
|
25
|
+
(instance.public_methods - Object.methods)
|
26
|
+
.reject { |x| x.to_s.start_with?("_") }
|
27
|
+
.each do |meth|
|
28
|
+
self.class.def_delegator :instance, meth
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sprockets"
|
4
|
+
|
5
|
+
module FoxPage
|
6
|
+
module Builders
|
7
|
+
module Assets
|
8
|
+
def build_assets
|
9
|
+
all_assets.each do |asset|
|
10
|
+
puts "ASSET\t#{asset}"
|
11
|
+
app.sprockets.manifest.compile(asset)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def all_assets
|
18
|
+
app.config.assets + image_assets
|
19
|
+
end
|
20
|
+
|
21
|
+
def image_assets
|
22
|
+
image_assets_path = app.root.join("app/assets/images")
|
23
|
+
Dir.glob("#{image_assets_path}/**/*.{png,jpg,gif,jpeg}")
|
24
|
+
.map { |full_path| full_path.sub(%r{\A#{image_assets_path}/}, "") }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FoxPage
|
4
|
+
module Builders
|
5
|
+
module FileCopy
|
6
|
+
def copy_public_files
|
7
|
+
puts "COPY\tpublic/* => #{OUTPUT_DIRECTORY}/"
|
8
|
+
FileUtils.cp_r public_path, output_path
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def public_path
|
14
|
+
app.root.join("public", ".")
|
15
|
+
end
|
16
|
+
|
17
|
+
def output_path
|
18
|
+
app.root.join(OUTPUT_DIRECTORY)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tilt"
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
module FoxPage
|
7
|
+
module Builders
|
8
|
+
module Pages
|
9
|
+
using Refinements::Camelize
|
10
|
+
|
11
|
+
def build_pages
|
12
|
+
app.routes.each do |path, route|
|
13
|
+
puts "PAGE\t#{path} => #{route.base_name}"
|
14
|
+
|
15
|
+
target_directory = File.join(output_directory, path)
|
16
|
+
FileUtils.mkdir_p(target_directory)
|
17
|
+
|
18
|
+
File.open(File.join(target_directory, "index.html"), "w") do |f|
|
19
|
+
f.puts render_route(route)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def render_route(route)
|
25
|
+
controller = spiced_controller(route).new
|
26
|
+
controller.method(route.method_name).call
|
27
|
+
|
28
|
+
layout = Tilt.new(layout_path(controller))
|
29
|
+
page = Tilt.new(page_path(route))
|
30
|
+
|
31
|
+
controller.instance_eval do
|
32
|
+
layout.render(self) { page.render(self) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# for the sake of keeping the original classes sane while building, we
|
37
|
+
# create a subclass of the original dynamically and inject common helpers
|
38
|
+
# to it and also run before_actions
|
39
|
+
def spiced_controller(route) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/LineLength
|
40
|
+
Class.new(route.controller).tap do |klass| # rubocop:disable Metrics/BlockLength, Metrics/LineLength
|
41
|
+
klass.include(Helpers::AppHelper.new(app))
|
42
|
+
klass.include(Helpers::AssetsHelper)
|
43
|
+
klass.include(Helpers::RenderHelper)
|
44
|
+
|
45
|
+
# include global ApplicationHelper if possible
|
46
|
+
begin
|
47
|
+
klass.include(ApplicationHelper)
|
48
|
+
rescue NameError # rubocop:disable Lint/HandleExceptions
|
49
|
+
# we don't have a global ApplicationHelper... which is fine
|
50
|
+
end
|
51
|
+
|
52
|
+
# find a controller-specific helper class and include it if we can
|
53
|
+
begin
|
54
|
+
helper = Kernel.const_get("#{route.base_name}_helper".camelize)
|
55
|
+
klass.include(helper)
|
56
|
+
rescue NameError # rubocop:disable Lint/HandleExceptions
|
57
|
+
# same difference
|
58
|
+
end
|
59
|
+
|
60
|
+
klass.define_method(:inspect) do |*args|
|
61
|
+
# report that we are actually the controller, not some random
|
62
|
+
# anonymous class
|
63
|
+
# append a + to it to indicate that it's different than an ordinary
|
64
|
+
# class instance
|
65
|
+
super(*args).sub(/#<Class:[^>]+>/, "#{route.controller}+")
|
66
|
+
end
|
67
|
+
|
68
|
+
klass.define_singleton_method(:inspect) do
|
69
|
+
# for .ancestors to show up correctly
|
70
|
+
"#{route.controller}+"
|
71
|
+
end
|
72
|
+
|
73
|
+
klass.define_method(:to_s) do |*args|
|
74
|
+
# irb uses this method for displaying in the prompt
|
75
|
+
super(*args).sub(/#<Class:[^>]+>/, "#{route.controller}+")
|
76
|
+
end
|
77
|
+
|
78
|
+
# inject filters
|
79
|
+
route.controller.public_instance_methods(false).each do |method|
|
80
|
+
klass.define_method(method) do |*args|
|
81
|
+
# @__before_actions is set on the original class -- use it from
|
82
|
+
# that one
|
83
|
+
route.controller.instance_variable_get(:@__before_actions)&.each do |action| # rubocop:disable Metrics/LineLength
|
84
|
+
send(action)
|
85
|
+
end
|
86
|
+
super(*args)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def layout_path(controller)
|
93
|
+
File
|
94
|
+
.join(views_path, controller.class.layout)
|
95
|
+
.tap(&method(:validate_file_exists))
|
96
|
+
end
|
97
|
+
|
98
|
+
def page_path(route)
|
99
|
+
Dir
|
100
|
+
.glob(
|
101
|
+
File.join(views_path, route.base_name, "#{route.method_name}.*")
|
102
|
+
)
|
103
|
+
.first
|
104
|
+
.tap { |file| validate_file_exists(file, route) }
|
105
|
+
end
|
106
|
+
|
107
|
+
def views_path
|
108
|
+
@views_path ||= app.root.join("app", "views")
|
109
|
+
end
|
110
|
+
|
111
|
+
def validate_file_exists(file, route = nil)
|
112
|
+
return if file && File.exist?(file)
|
113
|
+
|
114
|
+
error_message = if route
|
115
|
+
"template for #{route.base_name}##{route.method_name}"
|
116
|
+
else
|
117
|
+
"layout template"
|
118
|
+
end
|
119
|
+
|
120
|
+
raise ArgumentError, "Could not find #{error_message}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/fox_page/cli.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
|
5
|
+
module FoxPage
|
6
|
+
class Cli < Thor
|
7
|
+
desc "build", "Builds your website"
|
8
|
+
def build
|
9
|
+
app = require_application
|
10
|
+
|
11
|
+
app.build
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "server", "Runs a server for quick development"
|
15
|
+
def server
|
16
|
+
app = require_application
|
17
|
+
|
18
|
+
app.server.start
|
19
|
+
end
|
20
|
+
|
21
|
+
register FoxPage::Generator,
|
22
|
+
"new", "new NAME",
|
23
|
+
"Create a new FoxPage website"
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def require_application
|
28
|
+
require File.join(Bundler.root, "config", "environment")
|
29
|
+
|
30
|
+
ObjectSpace.each_object(Class).find do |klass|
|
31
|
+
klass.superclass == FoxPage::Application
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FoxPage
|
4
|
+
class Controller
|
5
|
+
DEFAULT_LAYOUT = "layouts/default.haml"
|
6
|
+
private_constant :DEFAULT_LAYOUT
|
7
|
+
|
8
|
+
def self.layout
|
9
|
+
DEFAULT_LAYOUT
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.before_action(method_name)
|
13
|
+
@__before_actions ||= []
|
14
|
+
@__before_actions << method_name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "thor"
|
4
|
+
|
5
|
+
module FoxPage
|
6
|
+
class Generator < Thor::Group
|
7
|
+
include Thor::Actions
|
8
|
+
|
9
|
+
argument :name, type: :string, desc: "The name of your website"
|
10
|
+
|
11
|
+
def self.source_root
|
12
|
+
File.join(__dir__, "app_template")
|
13
|
+
end
|
14
|
+
|
15
|
+
def create_application
|
16
|
+
Dir[File.join(self.class.source_root, "**/*.tt")]
|
17
|
+
.map { |path| path.sub(self.class.source_root + "/", "") }
|
18
|
+
.each do |path|
|
19
|
+
template(path,
|
20
|
+
File.join(name,
|
21
|
+
path.sub(/\.tt$/, "")
|
22
|
+
.gsub(/__dot__/, ".")))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def run_bundle
|
27
|
+
Dir.chdir(name) do
|
28
|
+
system("bundle install")
|
29
|
+
system("bundle binstubs foxpage")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def init_git_repo
|
34
|
+
Dir.chdir(name) do
|
35
|
+
system("git init")
|
36
|
+
system("git add .")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FoxPage
|
4
|
+
module Helpers
|
5
|
+
# the AppHelper module builder injects the core FoxPage::Application
|
6
|
+
# instance to the method `app`
|
7
|
+
class AppHelper < Module
|
8
|
+
def initialize(app)
|
9
|
+
@__app = app
|
10
|
+
define_method(:app) do
|
11
|
+
app
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def inspect
|
16
|
+
"#{self.class.name}(#{@__app.class})"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sprockets"
|
4
|
+
|
5
|
+
module FoxPage
|
6
|
+
module Helpers
|
7
|
+
module AssetsHelper
|
8
|
+
def asset_path(source)
|
9
|
+
File.join("/assets", app.sprockets.manifest.assets[source])
|
10
|
+
end
|
11
|
+
|
12
|
+
def stylesheet_link_tag(source)
|
13
|
+
%(<link rel="stylesheet" href=#{asset_path(source).inspect} />)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FoxPage
|
4
|
+
module Helpers
|
5
|
+
module RenderHelper
|
6
|
+
def render(view)
|
7
|
+
full_path = Dir.glob(app.root.join("app/views/#{view}.*")).first
|
8
|
+
|
9
|
+
unless full_path
|
10
|
+
raise ArgumentError, "Could not find template for #{view}"
|
11
|
+
end
|
12
|
+
|
13
|
+
Tilt.new(full_path).render(self)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ostruct"
|
4
|
+
|
5
|
+
module FoxPage
|
6
|
+
module Refinements
|
7
|
+
module ToDeepOpenStruct
|
8
|
+
refine Array do
|
9
|
+
def to_deep_ostruct
|
10
|
+
map do |value|
|
11
|
+
next value unless value.is_a?(Hash) || value.is_a?(Array)
|
12
|
+
|
13
|
+
value.to_deep_ostruct
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
refine Hash do
|
19
|
+
def to_deep_ostruct
|
20
|
+
OpenStruct.new(
|
21
|
+
dup.tap do |hash|
|
22
|
+
hash.each do |key, value|
|
23
|
+
next unless value.is_a?(Hash) || value.is_a?(Array)
|
24
|
+
|
25
|
+
hash[key] = value.to_deep_ostruct
|
26
|
+
end
|
27
|
+
end
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ostruct"
|
4
|
+
|
5
|
+
module FoxPage
|
6
|
+
class Router
|
7
|
+
using Refinements::Camelize
|
8
|
+
|
9
|
+
def self.draw_routes(&block)
|
10
|
+
new.draw_routes(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :routes
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@routes = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def draw_routes(&block)
|
20
|
+
instance_eval(&block)
|
21
|
+
routes
|
22
|
+
end
|
23
|
+
|
24
|
+
def root(target)
|
25
|
+
routes["/"] = parse_target(target)
|
26
|
+
end
|
27
|
+
|
28
|
+
def map(mapping)
|
29
|
+
mapping.each do |path, target|
|
30
|
+
routes[path] = parse_target(target)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def parse_target(target)
|
37
|
+
base_name, method_name = target.split("#")
|
38
|
+
controller = Kernel.const_get("#{base_name}_controller".camelize)
|
39
|
+
method_name = method_name.to_sym
|
40
|
+
|
41
|
+
validate_controller_method(controller, method_name)
|
42
|
+
|
43
|
+
OpenStruct.new(
|
44
|
+
base_name: base_name,
|
45
|
+
controller: controller,
|
46
|
+
method_name: method_name
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def validate_controller_method(controller, method_name)
|
51
|
+
return if controller.instance_methods.include?(method_name)
|
52
|
+
|
53
|
+
raise ArgumentError, "#{controller} does not define ##{method_name}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "listen"
|
4
|
+
require "webrick"
|
5
|
+
|
6
|
+
module FoxPage
|
7
|
+
class Server
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
@listener = Listen.to(app.root.join("app"),
|
11
|
+
app.root.join("public"),
|
12
|
+
&method(:handle_modified_app))
|
13
|
+
@server = WEBrick::HTTPServer.new(
|
14
|
+
BindAddress: ENV.fetch("APP_BIND", "127.0.0.1"),
|
15
|
+
Port: ENV.fetch("APP_PORT", 3000).to_i,
|
16
|
+
DocumentRoot: app.root.join(OUTPUT_DIRECTORY)
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def start
|
21
|
+
puts "==> Starting up development server at " \
|
22
|
+
"http://#{@server.config[:BindAddress]}:#{@server.config[:Port]}"
|
23
|
+
|
24
|
+
trap "INT" do
|
25
|
+
@server.shutdown
|
26
|
+
end
|
27
|
+
|
28
|
+
@app.build
|
29
|
+
@listener.start
|
30
|
+
@server.start
|
31
|
+
end
|
32
|
+
|
33
|
+
def handle_modified_app(_modified, _added, _removed)
|
34
|
+
reload_code
|
35
|
+
@app.build
|
36
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
37
|
+
# need to rescue Exception as syntax errors may cause the builds to break
|
38
|
+
puts "!!! An error occurred while building the app"
|
39
|
+
puts e.full_message
|
40
|
+
end
|
41
|
+
|
42
|
+
def reload_code
|
43
|
+
@app.code_loader.reload
|
44
|
+
@app.reload_routes!
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module FoxPage
|
6
|
+
class SiteBuilder
|
7
|
+
include Builders::Assets
|
8
|
+
include Builders::FileCopy
|
9
|
+
include Builders::Pages
|
10
|
+
|
11
|
+
def self.build(app)
|
12
|
+
new(app).build
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :app, :output_directory
|
16
|
+
|
17
|
+
def initialize(app)
|
18
|
+
@app = app
|
19
|
+
@output_directory = app.root.join(OUTPUT_DIRECTORY)
|
20
|
+
end
|
21
|
+
|
22
|
+
def build
|
23
|
+
puts "==> Building site #{App.config.site&.title}"
|
24
|
+
|
25
|
+
FileUtils.mkdir_p output_directory
|
26
|
+
|
27
|
+
build_assets
|
28
|
+
build_pages
|
29
|
+
copy_public_files
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/fox_page.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler"
|
4
|
+
|
5
|
+
require "zeitwerk"
|
6
|
+
loader = Zeitwerk::Loader.for_gem
|
7
|
+
begin
|
8
|
+
loader.ignore Bundler.root
|
9
|
+
rescue Bundler::GemfileNotFound # rubocop:disable Lint/HandleExceptions
|
10
|
+
# don't care ...
|
11
|
+
end
|
12
|
+
loader.setup
|
13
|
+
|
14
|
+
require_relative "./fox_page/version"
|
15
|
+
|
16
|
+
module FoxPage
|
17
|
+
class Error < StandardError; end
|
18
|
+
|
19
|
+
OUTPUT_DIRECTORY = "_site"
|
20
|
+
end
|
data/lib/foxpage.rb
ADDED
data/misc/foxpage.png
ADDED
Binary file
|