brandish 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +3 -0
- data/.rubocop.yml +41 -0
- data/.travis.yml +5 -0
- data/.yardopts +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +9 -0
- data/bin/brandish +16 -0
- data/brandish.gemspec +39 -0
- data/defaults/templates/html.liquid +39 -0
- data/lib/brandish.rb +51 -0
- data/lib/brandish/application.rb +163 -0
- data/lib/brandish/application/bench_command.rb +96 -0
- data/lib/brandish/application/build_command.rb +73 -0
- data/lib/brandish/application/initialize_command.rb +83 -0
- data/lib/brandish/application/serve_command.rb +150 -0
- data/lib/brandish/configure.rb +196 -0
- data/lib/brandish/configure/dsl.rb +135 -0
- data/lib/brandish/configure/dsl/form.rb +136 -0
- data/lib/brandish/configure/form.rb +32 -0
- data/lib/brandish/errors.rb +65 -0
- data/lib/brandish/execute.rb +26 -0
- data/lib/brandish/markup.rb +10 -0
- data/lib/brandish/markup/redcarpet.rb +14 -0
- data/lib/brandish/markup/redcarpet/format.rb +127 -0
- data/lib/brandish/markup/redcarpet/html.rb +95 -0
- data/lib/brandish/parser.rb +26 -0
- data/lib/brandish/parser/main.rb +237 -0
- data/lib/brandish/parser/node.rb +89 -0
- data/lib/brandish/parser/node/block.rb +98 -0
- data/lib/brandish/parser/node/command.rb +102 -0
- data/lib/brandish/parser/node/pair.rb +42 -0
- data/lib/brandish/parser/node/root.rb +83 -0
- data/lib/brandish/parser/node/string.rb +18 -0
- data/lib/brandish/parser/node/text.rb +114 -0
- data/lib/brandish/path_set.rb +163 -0
- data/lib/brandish/processor.rb +47 -0
- data/lib/brandish/processor/base.rb +144 -0
- data/lib/brandish/processor/block.rb +47 -0
- data/lib/brandish/processor/command.rb +47 -0
- data/lib/brandish/processor/context.rb +169 -0
- data/lib/brandish/processor/descend.rb +32 -0
- data/lib/brandish/processor/inline.rb +49 -0
- data/lib/brandish/processor/name_filter.rb +67 -0
- data/lib/brandish/processor/pair_filter.rb +96 -0
- data/lib/brandish/processors.rb +26 -0
- data/lib/brandish/processors/all.rb +19 -0
- data/lib/brandish/processors/all/comment.rb +29 -0
- data/lib/brandish/processors/all/embed.rb +56 -0
- data/lib/brandish/processors/all/if.rb +109 -0
- data/lib/brandish/processors/all/import.rb +95 -0
- data/lib/brandish/processors/all/literal.rb +42 -0
- data/lib/brandish/processors/all/verify.rb +47 -0
- data/lib/brandish/processors/common.rb +20 -0
- data/lib/brandish/processors/common/asset.rb +118 -0
- data/lib/brandish/processors/common/asset/paths.rb +93 -0
- data/lib/brandish/processors/common/group.rb +67 -0
- data/lib/brandish/processors/common/header.rb +86 -0
- data/lib/brandish/processors/common/markup.rb +127 -0
- data/lib/brandish/processors/common/output.rb +73 -0
- data/lib/brandish/processors/html.rb +18 -0
- data/lib/brandish/processors/html/group.rb +33 -0
- data/lib/brandish/processors/html/header.rb +46 -0
- data/lib/brandish/processors/html/markup.rb +131 -0
- data/lib/brandish/processors/html/output.rb +62 -0
- data/lib/brandish/processors/html/output/document.rb +127 -0
- data/lib/brandish/processors/html/script.rb +64 -0
- data/lib/brandish/processors/html/script/babel.rb +48 -0
- data/lib/brandish/processors/html/script/coffee.rb +47 -0
- data/lib/brandish/processors/html/script/vanilla.rb +45 -0
- data/lib/brandish/processors/html/style.rb +82 -0
- data/lib/brandish/processors/html/style/highlight.rb +89 -0
- data/lib/brandish/processors/html/style/sass.rb +64 -0
- data/lib/brandish/processors/html/style/vanilla.rb +71 -0
- data/lib/brandish/processors/latex.rb +15 -0
- data/lib/brandish/processors/latex/markup.rb +47 -0
- data/lib/brandish/scanner.rb +64 -0
- data/lib/brandish/version.rb +9 -0
- data/templates/initialize/Gemfile.tt +14 -0
- data/templates/initialize/brandish.config.rb.tt +49 -0
- metadata +296 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Brandish
|
|
5
|
+
class Application
|
|
6
|
+
# The bench command. This builds the project in the set directory,
|
|
7
|
+
# and benchmarks. This is for debugging.
|
|
8
|
+
class BenchCommand
|
|
9
|
+
include Commander::Methods
|
|
10
|
+
|
|
11
|
+
# Defines the command on the given application. This sets the important
|
|
12
|
+
# data information for the command, for use for the help output.
|
|
13
|
+
#
|
|
14
|
+
# @param application [Application]
|
|
15
|
+
# @param command [Commander::Command]
|
|
16
|
+
# @return [void]
|
|
17
|
+
def self.define(application, command)
|
|
18
|
+
command.syntax = "brandish build"
|
|
19
|
+
command.option "-o", "--only NAMES", [::String]
|
|
20
|
+
command.option "-p", "--path PATH", ::String
|
|
21
|
+
command.option "-n", "--name NAME", ::String
|
|
22
|
+
|
|
23
|
+
command.action { |_, o| call(application, o.__hash__) }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# The default options for the build command.
|
|
27
|
+
#
|
|
28
|
+
# @return [{::Symbol => ::Object}]
|
|
29
|
+
DEFAULTS = { only: :all, path: "profile", name: "default" }.freeze
|
|
30
|
+
|
|
31
|
+
# Performs the build command. This initializes the command, and
|
|
32
|
+
# calls {#call}.
|
|
33
|
+
#
|
|
34
|
+
# @param application [Application] The application.
|
|
35
|
+
# @param options [{::Symbol => ::Object}] The options for the command.
|
|
36
|
+
#
|
|
37
|
+
# @return [void]
|
|
38
|
+
def self.call(application, options)
|
|
39
|
+
new(application, options).call
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Initialize the build command.
|
|
43
|
+
#
|
|
44
|
+
# @params (see {.call})
|
|
45
|
+
def initialize(application, options)
|
|
46
|
+
@application = application
|
|
47
|
+
@options = DEFAULTS.merge(options)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Performs the build. First, it loads the configuration file for the
|
|
51
|
+
# build. Then, it performs the build, calling {Configure#build} with
|
|
52
|
+
# the `:only` filter provided by the options. This uses a Commander
|
|
53
|
+
# native called `progress` to make it look nice on the output.
|
|
54
|
+
#
|
|
55
|
+
# @return [void]
|
|
56
|
+
def call
|
|
57
|
+
require "ruby-prof"
|
|
58
|
+
require "benchmark"
|
|
59
|
+
|
|
60
|
+
@configure = @application.load_configuration_file
|
|
61
|
+
@path = ::Pathname.new(@options[:path]).expand_path(Dir.pwd)
|
|
62
|
+
@path.mkpath
|
|
63
|
+
say "=> Beginning build..."
|
|
64
|
+
|
|
65
|
+
result = nil
|
|
66
|
+
time = Benchmark.measure { result = RubyProf.profile { perform_build } }
|
|
67
|
+
say "-> Build ended, time: #{time}"
|
|
68
|
+
say "=> Outputting profile..."
|
|
69
|
+
|
|
70
|
+
result.eliminate_methods!(method_eleminations)
|
|
71
|
+
output_profile(result)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def output_profile(result)
|
|
77
|
+
printer = RubyProf::MultiPrinter.new(result)
|
|
78
|
+
printer.print(path: @path, profile: @options[:name])
|
|
79
|
+
say "-> Profile output to `#{@options[:path]}'!"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def perform_build
|
|
83
|
+
@configure.build(@options[:only]).each(&:call)
|
|
84
|
+
rescue => e
|
|
85
|
+
say_error "!> Error while building!"
|
|
86
|
+
say_error "-> Received exception: #{e.class}: #{e.message}"
|
|
87
|
+
e.backtrace.each { |l| say_warning "\t-> in #{l}" } if @options[:trace]
|
|
88
|
+
exit!
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def method_eleminations
|
|
92
|
+
[/\A(Set|Class|Array|Enumerable)#/]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Brandish
|
|
5
|
+
class Application
|
|
6
|
+
# The build command. This just builds the project in the set directory.
|
|
7
|
+
class BuildCommand
|
|
8
|
+
include Commander::Methods
|
|
9
|
+
|
|
10
|
+
# The description for the build command.
|
|
11
|
+
#
|
|
12
|
+
# @return [::String]
|
|
13
|
+
COMMAND_DESCRIPTION =
|
|
14
|
+
"Builds an existing Brandish project. If no directory is specified " \
|
|
15
|
+
" using --directory or -d, it defaults to the current directory."
|
|
16
|
+
|
|
17
|
+
# Defines the command on the given application. This sets the important
|
|
18
|
+
# data information for the command, for use for the help output.
|
|
19
|
+
#
|
|
20
|
+
# @param application [Application]
|
|
21
|
+
# @param command [Commander::Command]
|
|
22
|
+
# @return [void]
|
|
23
|
+
def self.define(application, command)
|
|
24
|
+
command.syntax = "brandish build"
|
|
25
|
+
command.description = COMMAND_DESCRIPTION
|
|
26
|
+
command.option "-o", "--only NAMES", [::String],
|
|
27
|
+
"Which forms to build. If this is omitted, it defaults to all."
|
|
28
|
+
|
|
29
|
+
command.action { |_, o| call(application, o.__hash__) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# The default options for the build command.
|
|
33
|
+
#
|
|
34
|
+
# @return [{::Symbol => ::Object}]
|
|
35
|
+
DEFAULTS = { only: :all }.freeze
|
|
36
|
+
|
|
37
|
+
# Performs the build command. This initializes the command, and
|
|
38
|
+
# calls {#call}.
|
|
39
|
+
#
|
|
40
|
+
# @param application [Application] The application.
|
|
41
|
+
# @param options [{::Symbol => ::Object}] The options for the command.
|
|
42
|
+
#
|
|
43
|
+
# @return [void]
|
|
44
|
+
def self.call(application, options)
|
|
45
|
+
new(application, options).call
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Initialize the build command.
|
|
49
|
+
#
|
|
50
|
+
# @params (see {.call})
|
|
51
|
+
def initialize(application, options)
|
|
52
|
+
@application = application
|
|
53
|
+
@options = DEFAULTS.merge(options)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Performs the build. First, it loads the configuration file for the
|
|
57
|
+
# build. Then, it performs the build, calling {Configure#build} with
|
|
58
|
+
# the `:only` filter provided by the options. This uses a Commander
|
|
59
|
+
# native called `progress` to make it look nice on the output.
|
|
60
|
+
#
|
|
61
|
+
# @return [void]
|
|
62
|
+
def call
|
|
63
|
+
configure = @application.load_configuration_file
|
|
64
|
+
@application.progress(configure.build(@options[:only]).to_a, &:call)
|
|
65
|
+
rescue => e
|
|
66
|
+
say_error "\n!> Error while building!"
|
|
67
|
+
say_error "!> #{e.location}" if e.respond_to?(:location)
|
|
68
|
+
say_error "!> Received exception: #{e.class}: #{e.message}"
|
|
69
|
+
e.backtrace.each { |l| say_warning "\t~> in #{l}" } if @options[:trace]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "thor"
|
|
5
|
+
require "rubygems"
|
|
6
|
+
|
|
7
|
+
module Brandish
|
|
8
|
+
class Application
|
|
9
|
+
# The initialize command for the application. This creates a new project
|
|
10
|
+
# at a given directory. The Brandish project is placed at
|
|
11
|
+
# `directory`/`name`.
|
|
12
|
+
class InitializeCommand
|
|
13
|
+
include Thor::Base
|
|
14
|
+
include Thor::Actions
|
|
15
|
+
|
|
16
|
+
# The description for the initialize command.
|
|
17
|
+
#
|
|
18
|
+
# @return [::String]
|
|
19
|
+
COMMAND_DESCRIPTION =
|
|
20
|
+
"Creates a new Brandish project. The name given should not contain " \
|
|
21
|
+
"any path seperators - if a brandish project needs to be placed in " \
|
|
22
|
+
"a seperate directory, use the --directory (or -d) option."
|
|
23
|
+
|
|
24
|
+
# The source root for the templates used by Thor for initialization.
|
|
25
|
+
#
|
|
26
|
+
# @return [::String]
|
|
27
|
+
def self.source_root
|
|
28
|
+
File.expand_path("../../../../templates/initialize", __FILE__)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Defines the command on the given application. This sets the important
|
|
32
|
+
# data information for the command, for use for the help output.
|
|
33
|
+
#
|
|
34
|
+
# @param application [Application]
|
|
35
|
+
# @param command [Commander::Command]
|
|
36
|
+
# @return [void]
|
|
37
|
+
def self.define(application, command)
|
|
38
|
+
command.syntax = "brandish initialize NAME"
|
|
39
|
+
command.description = COMMAND_DESCRIPTION
|
|
40
|
+
|
|
41
|
+
command.action { |a, o| call(application, a, o.__hash__) }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Performs the initialize command. Since this class uses Thor, this
|
|
45
|
+
# performs some setup to interface with the Thor class.
|
|
46
|
+
#
|
|
47
|
+
# @param application [Application]
|
|
48
|
+
# @param arguments [<::String>] The arguments passed to the initialize
|
|
49
|
+
# command. This should contain one value - the name.
|
|
50
|
+
# @param _options [Hash] The options for the command. Since this command
|
|
51
|
+
# takes no specific options, this is ignored.
|
|
52
|
+
# @return [void]
|
|
53
|
+
def self.call(application, arguments, _options)
|
|
54
|
+
name = arguments[0]
|
|
55
|
+
directory = application.directory / name
|
|
56
|
+
new([], { name: name }, destination_root: directory).call
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Performs the initialize command, setting up the project.
|
|
60
|
+
#
|
|
61
|
+
# @return [void]
|
|
62
|
+
def call
|
|
63
|
+
template "brandish.config.rb"
|
|
64
|
+
%w(source source/assets source/assets/styles source/assets/scripts
|
|
65
|
+
templates output).each { |d| empty_directory(d) }
|
|
66
|
+
template "Gemfile"
|
|
67
|
+
inside(".") { run "bundle install" }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
protected
|
|
71
|
+
|
|
72
|
+
# The approximate recommendation for the current running version of
|
|
73
|
+
# Brandish. This is used to set up a requirement for Brandish in both
|
|
74
|
+
# the Gemfile and the `brandish.config.rb` file.
|
|
75
|
+
#
|
|
76
|
+
# @return [::String]
|
|
77
|
+
def approx
|
|
78
|
+
@approx ||=
|
|
79
|
+
Gem::Version.new(Brandish::VERSION).approximate_recommendation
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Brandish
|
|
5
|
+
class Application
|
|
6
|
+
# The serve command. This builds, and then serves, an existing Brandish
|
|
7
|
+
# project. This watches the source. If it detects a change, it rebuilds.
|
|
8
|
+
class ServeCommand
|
|
9
|
+
include Commander::Methods
|
|
10
|
+
|
|
11
|
+
# The description for the serve command.
|
|
12
|
+
#
|
|
13
|
+
# @return [::String]
|
|
14
|
+
COMMAND_DESCRIPTION = "Builds, and serves, an existing Brandish project."
|
|
15
|
+
|
|
16
|
+
# Defines the command on the given application. This sets the important
|
|
17
|
+
# data information for the command, for use for the help output.
|
|
18
|
+
#
|
|
19
|
+
# @param application [Application]
|
|
20
|
+
# @param command [Commander::Command]
|
|
21
|
+
# @return [void]
|
|
22
|
+
def self.define(application, command)
|
|
23
|
+
command.syntax = "branish serve"
|
|
24
|
+
command.description = COMMAND_DESCRIPTION
|
|
25
|
+
command.option "-p", "--port PORT", ::Integer, "The port to listen on"
|
|
26
|
+
command.option "-o", "--only NAMES", [::String], "The forms to build"
|
|
27
|
+
command.option "--verbose", "Whether or not to be verbose in the output"
|
|
28
|
+
|
|
29
|
+
command.action { |_, o| call(application, o.__hash__) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Performs the serve command. This initializes the command, and
|
|
33
|
+
# calls {#call}.
|
|
34
|
+
#
|
|
35
|
+
# @param application [Application] The application.
|
|
36
|
+
# @param options [{::Symbol => ::Object}] The options for the command.
|
|
37
|
+
#
|
|
38
|
+
# @return [void]
|
|
39
|
+
def self.call(application, options)
|
|
40
|
+
puts "Running with options #{options.inspect}..."
|
|
41
|
+
new(application, options).call
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# The default options for the serve command.
|
|
45
|
+
#
|
|
46
|
+
# @return [{::Symbol => ::Object}]
|
|
47
|
+
DEFAULTS = { only: :all, show_build: false }.freeze
|
|
48
|
+
|
|
49
|
+
# Initialize the serve command.
|
|
50
|
+
#
|
|
51
|
+
# @params (see {.call})
|
|
52
|
+
def initialize(application, options)
|
|
53
|
+
@application = application
|
|
54
|
+
@options = DEFAULTS.merge(options)
|
|
55
|
+
@port = @options.fetch(:port, (ENV["PORT"] || "3000").to_i)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Performs the serve command. It first loads the configuration file,
|
|
59
|
+
# then calls {#start_webserver}, followed by {#start_buildserver}. Once
|
|
60
|
+
# both servers are setup, it calls {#wait_on_servers}.
|
|
61
|
+
#
|
|
62
|
+
# @return [void]
|
|
63
|
+
def call
|
|
64
|
+
@configuration = @application.load_configuration_file
|
|
65
|
+
say "=> Beginning serve..."
|
|
66
|
+
start_webserver
|
|
67
|
+
start_buildserver
|
|
68
|
+
color "\r=> Ready and waiting! ", :erase_line, :green
|
|
69
|
+
wait_on_servers
|
|
70
|
+
rescue StandardError, ScriptError => e
|
|
71
|
+
# Whenever we receive a general error, which only occurs while setup,
|
|
72
|
+
# we complain, and pass up the exception.
|
|
73
|
+
say_error "\n!> Received exception: #{e.class}: #{e.message}"
|
|
74
|
+
e.backtrace.each { |l| say_warning "\t-> in #{l}" } if @options[:trace]
|
|
75
|
+
fail
|
|
76
|
+
rescue SignalException, NoMemoryError, SystemExit, SystemStackError => e
|
|
77
|
+
# Whenever we receive a signal, or an unrecoverable error, we kill
|
|
78
|
+
# the servers and complain. These exceptions occur on the main thread,
|
|
79
|
+
# and so we handle them here.
|
|
80
|
+
say_warning "\n!> Received exception: #{e.class}: #{e.message}"
|
|
81
|
+
say_ok "\n-> Received termination, shutting down..."
|
|
82
|
+
kill_webserver
|
|
83
|
+
kill_buildserver
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def start_webserver
|
|
89
|
+
say "-> Setting up web server on port #{@port}..."
|
|
90
|
+
log_file = @options[:verbose] ? $stdout : StringIO.new
|
|
91
|
+
log = WEBrick::Log.new(log_file)
|
|
92
|
+
access_log = [[log_file, WEBrick::AccessLog::COMBINED_LOG_FORMAT]]
|
|
93
|
+
data = { Port: @port, DocumentRoot: @configuration.output.to_s,
|
|
94
|
+
Logger: log, AccessLog: access_log }
|
|
95
|
+
|
|
96
|
+
@webserver = Thread.start { WEBrick::HTTPServer.new(data).start }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def print(a, *)
|
|
100
|
+
fail if a.is_a?(::IO)
|
|
101
|
+
super
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def start_buildserver
|
|
105
|
+
perform_build
|
|
106
|
+
say "\n"
|
|
107
|
+
say "-> Setting up listen server..."
|
|
108
|
+
source_build_server = Listen.to(*listen_paths) { perform_build }
|
|
109
|
+
config_build_server = Listen.to(@application.directory.to_s) do
|
|
110
|
+
say "-> Configuration file changed, updating..."
|
|
111
|
+
@configuration = @application.load_configuration_file!
|
|
112
|
+
perform_build
|
|
113
|
+
end
|
|
114
|
+
config_build_server.only(/#{Regexp.escape(@application.config_file.to_s)}\z/)
|
|
115
|
+
|
|
116
|
+
@buildservers = [source_build_server, config_build_server].each(&:start)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def perform_build
|
|
120
|
+
builds = @configuration.build!(@options[:only])
|
|
121
|
+
color "\r~> Building... ", :erase_line, :clear
|
|
122
|
+
builds.each(&:call)
|
|
123
|
+
color "\r=> Build completed at #{Time.now.strftime('%T.%L')}! ", :erase_line, :green
|
|
124
|
+
|
|
125
|
+
rescue => e
|
|
126
|
+
say_error "\n!> Error while building!"
|
|
127
|
+
say_error "!> #{e.location}" if e.respond_to?(:location)
|
|
128
|
+
say_error "-> Received exception: #{e.class}: #{e.message}"
|
|
129
|
+
e.backtrace.each { |l| say_warning "\t-> in #{l}" } if @options[:trace]
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def kill_webserver
|
|
133
|
+
@webserver&.kill
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def kill_buildserver
|
|
137
|
+
@buildservers&.each { |b| b&.stop }
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def wait_on_servers
|
|
141
|
+
@webserver.join
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def listen_paths
|
|
145
|
+
(@configuration.sources.to_a + @configuration.templates.to_a)
|
|
146
|
+
.select(&:directory?).map(&:to_s)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "rubygems" # for Gem::Requirement
|
|
5
|
+
require "securerandom"
|
|
6
|
+
require "forwardable"
|
|
7
|
+
|
|
8
|
+
require "brandish/configure/dsl"
|
|
9
|
+
require "brandish/configure/form"
|
|
10
|
+
|
|
11
|
+
module Brandish
|
|
12
|
+
# This provides a central location for all configuration options. For the
|
|
13
|
+
# DSL, see {DSL}.
|
|
14
|
+
class Configure
|
|
15
|
+
extend Forwardable
|
|
16
|
+
|
|
17
|
+
# The options. These can be anything; predefined options are `:root`,
|
|
18
|
+
# `:source`, `:output`, and `:templates`; for more information on those,
|
|
19
|
+
# see {#root}, {#sources}, {#output}, and {#templates} for more information.
|
|
20
|
+
# These options should not be accessed directly, but rather through their
|
|
21
|
+
# accessors. Other options must be accessed through this.
|
|
22
|
+
#
|
|
23
|
+
# @return [{::Symbol => ::Object}]
|
|
24
|
+
attr_reader :options
|
|
25
|
+
|
|
26
|
+
# The forms that are defined on this configuration instance.
|
|
27
|
+
#
|
|
28
|
+
# @return [Set<Configure::Form>]
|
|
29
|
+
attr_reader :forms
|
|
30
|
+
|
|
31
|
+
# @!method [](key)
|
|
32
|
+
# Sets a key on the options. This gets an option that is used for all
|
|
33
|
+
# processors on the options.
|
|
34
|
+
#
|
|
35
|
+
# @param key [::Symbol, ::String] The key.
|
|
36
|
+
# @return [::Object]
|
|
37
|
+
# @!method []=(key, value)
|
|
38
|
+
# Sets a key on the options. This sets an option that is used for all
|
|
39
|
+
# processors on the options.
|
|
40
|
+
#
|
|
41
|
+
# @param key [::Symbol, ::String] The key.
|
|
42
|
+
# @param value [::Object] The value.
|
|
43
|
+
# @return [::Object]
|
|
44
|
+
# @!method fetch(key, default = CANARY, &block)
|
|
45
|
+
# Fetches a value at the given key, or provides a default if the key
|
|
46
|
+
# doesn't exist. If both a block and a default argument are given,
|
|
47
|
+
# the block form takes precedence.
|
|
48
|
+
#
|
|
49
|
+
# @overload fetch(key)
|
|
50
|
+
# Attempts to retrieve a value at the given key. If there is no
|
|
51
|
+
# key-value pair at the given key, it raises an error.
|
|
52
|
+
#
|
|
53
|
+
# @raise [KeyError] if the key isn't on the options.
|
|
54
|
+
# @param key [::Symbol, ::String] The key.
|
|
55
|
+
# @return [::Object] The value.
|
|
56
|
+
#
|
|
57
|
+
# @overload fetch(key, default)
|
|
58
|
+
# Attempts to retrieve a value at the given key. If there is no
|
|
59
|
+
# key-value pair at the given key, it returns the value given by
|
|
60
|
+
# `default`.
|
|
61
|
+
#
|
|
62
|
+
# @param key [::Symbol, ::String] The key.
|
|
63
|
+
# @param default [::Object] The default value.
|
|
64
|
+
# @return [::Object] The value, or the default value if there isn't
|
|
65
|
+
# one.
|
|
66
|
+
#
|
|
67
|
+
# @overload fetch(key, &block)
|
|
68
|
+
# attempts to retrieve a value at the given key. If there is no
|
|
69
|
+
# key-value pair at the given key, it yields.
|
|
70
|
+
#
|
|
71
|
+
# @yield if there is no corresponding key-value pair.
|
|
72
|
+
# @param key [::Symbol, ::String] The key.
|
|
73
|
+
# @return [::Object] The value, or the result of the block if there
|
|
74
|
+
# isn't one.
|
|
75
|
+
delegate [:[], :fetch] => :options
|
|
76
|
+
|
|
77
|
+
# Initializes the configure instance.
|
|
78
|
+
#
|
|
79
|
+
# @param root [::String, ::Pathname] The root for the project. This is
|
|
80
|
+
# used to determine the correct paths for the output directory, the
|
|
81
|
+
# sources directory, and the templates directory.
|
|
82
|
+
def initialize(root = Dir.pwd)
|
|
83
|
+
root = ::Pathname.new(root)
|
|
84
|
+
@options = { root: root, sources: PathSet.new, templates: PathSet.new }
|
|
85
|
+
@forms = ::Set.new
|
|
86
|
+
default_paths
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Retrieves the root path. This is where all of the other directories
|
|
90
|
+
# should be located, and where the configuration file should be
|
|
91
|
+
# located.
|
|
92
|
+
#
|
|
93
|
+
# @return [::Pathname]
|
|
94
|
+
def root
|
|
95
|
+
fetch(:root)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Retrieves the output path. This is where the outputs for all of the forms
|
|
99
|
+
# should be located.
|
|
100
|
+
#
|
|
101
|
+
# @return [::Pathname]
|
|
102
|
+
def output
|
|
103
|
+
fetch(:output) { root / "output" }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Retrieves the source path. This is where the sources for all of the
|
|
107
|
+
# documents in the Brandish project are located.
|
|
108
|
+
#
|
|
109
|
+
# @return [PathSet]
|
|
110
|
+
def sources
|
|
111
|
+
fetch(:sources)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Retrieves the templates path. This is where all of the templates for
|
|
115
|
+
# all of the forms should be located.
|
|
116
|
+
#
|
|
117
|
+
# @return [PathSet]
|
|
118
|
+
def templates
|
|
119
|
+
fetch(:templates)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Given a set of forms to build, it yields blocks that can be called to
|
|
123
|
+
# build a form.
|
|
124
|
+
#
|
|
125
|
+
# @param which [::Symbol, <::Symbol>] If this is `:all`, all of the forms
|
|
126
|
+
# available are built; otherwise, it only builds the forms whose names
|
|
127
|
+
# are listed.
|
|
128
|
+
# @yield [build] Yields for each form that can be built.
|
|
129
|
+
# @yieldparam build [::Proc<void>] A block that can be called to build
|
|
130
|
+
# a form.
|
|
131
|
+
# @return [void]
|
|
132
|
+
def build(which = :all)
|
|
133
|
+
return to_enum(:build, which) unless block_given?
|
|
134
|
+
select_forms(which).each { |f| yield proc { f.build(self) } }
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Given a set of forms to build, it yields blocks that can be called to
|
|
138
|
+
# build a form.
|
|
139
|
+
#
|
|
140
|
+
# This first clears the cache for file nodes.
|
|
141
|
+
#
|
|
142
|
+
# @param which [::Symbol, <::Symbol>] If this is `:all`, all of the forms
|
|
143
|
+
# available are built; otherwise, it only builds the forms whose names
|
|
144
|
+
# are listed.
|
|
145
|
+
# @yield [build] Yields for each form that can be built.
|
|
146
|
+
# @yieldparam build [::Proc<void>] A block that can be called to build
|
|
147
|
+
# a form.
|
|
148
|
+
# @return [void]
|
|
149
|
+
def build!(which = :all)
|
|
150
|
+
return to_enum(:build!, which) unless block_given?
|
|
151
|
+
@_roots = nil
|
|
152
|
+
select_forms(which).each { |f| yield proc { f.build(self) } }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# A cache for all of the root nodes. This is a regular hash; however, upon
|
|
156
|
+
# attempt to access an item that isn't already in the hash, it first
|
|
157
|
+
# parses the file at that item, and stores the result in the hash, returning
|
|
158
|
+
# the root node in the file. This is to cache files so that they do not
|
|
159
|
+
# get reparsed multiple times.
|
|
160
|
+
#
|
|
161
|
+
# @return [{::Pathname => Parser::Root}]
|
|
162
|
+
def roots
|
|
163
|
+
@_roots ||= ::Hash.new { |h, k| h[k] = parse_from(k) }
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Parses a file. This bypasses the cache.
|
|
167
|
+
#
|
|
168
|
+
# @param path [::Pathname] The path to the actual file. This should
|
|
169
|
+
# respond to `#read`. If this isn't a pathname, the short should be
|
|
170
|
+
# provided.
|
|
171
|
+
# @param short [::String] The short name of the file. This is used for
|
|
172
|
+
# location information.
|
|
173
|
+
# @return [Parser::Root]
|
|
174
|
+
def parse_from(path, short = path.relative_path_from(root))
|
|
175
|
+
Parser.new(Scanner.new(path.read, short, options).call).call
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
private
|
|
179
|
+
|
|
180
|
+
def default_paths
|
|
181
|
+
sources <<
|
|
182
|
+
File.expand_path("../../../defaults/source", __FILE__) <<
|
|
183
|
+
(root / "source")
|
|
184
|
+
templates <<
|
|
185
|
+
File.expand_path("../../../defaults/templates", __FILE__) <<
|
|
186
|
+
(root / "templates")
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def select_forms(which)
|
|
190
|
+
which = @forms.map(&:name) if which == :all || !which.is_a?(::Array) ||
|
|
191
|
+
which.empty?
|
|
192
|
+
which = which.to_set
|
|
193
|
+
@forms.select { |f| which.include?(f.name) }
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|