brandish 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +41 -0
  5. data/.travis.yml +5 -0
  6. data/.yardopts +1 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +10 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +41 -0
  11. data/Rakefile +9 -0
  12. data/bin/brandish +16 -0
  13. data/brandish.gemspec +39 -0
  14. data/defaults/templates/html.liquid +39 -0
  15. data/lib/brandish.rb +51 -0
  16. data/lib/brandish/application.rb +163 -0
  17. data/lib/brandish/application/bench_command.rb +96 -0
  18. data/lib/brandish/application/build_command.rb +73 -0
  19. data/lib/brandish/application/initialize_command.rb +83 -0
  20. data/lib/brandish/application/serve_command.rb +150 -0
  21. data/lib/brandish/configure.rb +196 -0
  22. data/lib/brandish/configure/dsl.rb +135 -0
  23. data/lib/brandish/configure/dsl/form.rb +136 -0
  24. data/lib/brandish/configure/form.rb +32 -0
  25. data/lib/brandish/errors.rb +65 -0
  26. data/lib/brandish/execute.rb +26 -0
  27. data/lib/brandish/markup.rb +10 -0
  28. data/lib/brandish/markup/redcarpet.rb +14 -0
  29. data/lib/brandish/markup/redcarpet/format.rb +127 -0
  30. data/lib/brandish/markup/redcarpet/html.rb +95 -0
  31. data/lib/brandish/parser.rb +26 -0
  32. data/lib/brandish/parser/main.rb +237 -0
  33. data/lib/brandish/parser/node.rb +89 -0
  34. data/lib/brandish/parser/node/block.rb +98 -0
  35. data/lib/brandish/parser/node/command.rb +102 -0
  36. data/lib/brandish/parser/node/pair.rb +42 -0
  37. data/lib/brandish/parser/node/root.rb +83 -0
  38. data/lib/brandish/parser/node/string.rb +18 -0
  39. data/lib/brandish/parser/node/text.rb +114 -0
  40. data/lib/brandish/path_set.rb +163 -0
  41. data/lib/brandish/processor.rb +47 -0
  42. data/lib/brandish/processor/base.rb +144 -0
  43. data/lib/brandish/processor/block.rb +47 -0
  44. data/lib/brandish/processor/command.rb +47 -0
  45. data/lib/brandish/processor/context.rb +169 -0
  46. data/lib/brandish/processor/descend.rb +32 -0
  47. data/lib/brandish/processor/inline.rb +49 -0
  48. data/lib/brandish/processor/name_filter.rb +67 -0
  49. data/lib/brandish/processor/pair_filter.rb +96 -0
  50. data/lib/brandish/processors.rb +26 -0
  51. data/lib/brandish/processors/all.rb +19 -0
  52. data/lib/brandish/processors/all/comment.rb +29 -0
  53. data/lib/brandish/processors/all/embed.rb +56 -0
  54. data/lib/brandish/processors/all/if.rb +109 -0
  55. data/lib/brandish/processors/all/import.rb +95 -0
  56. data/lib/brandish/processors/all/literal.rb +42 -0
  57. data/lib/brandish/processors/all/verify.rb +47 -0
  58. data/lib/brandish/processors/common.rb +20 -0
  59. data/lib/brandish/processors/common/asset.rb +118 -0
  60. data/lib/brandish/processors/common/asset/paths.rb +93 -0
  61. data/lib/brandish/processors/common/group.rb +67 -0
  62. data/lib/brandish/processors/common/header.rb +86 -0
  63. data/lib/brandish/processors/common/markup.rb +127 -0
  64. data/lib/brandish/processors/common/output.rb +73 -0
  65. data/lib/brandish/processors/html.rb +18 -0
  66. data/lib/brandish/processors/html/group.rb +33 -0
  67. data/lib/brandish/processors/html/header.rb +46 -0
  68. data/lib/brandish/processors/html/markup.rb +131 -0
  69. data/lib/brandish/processors/html/output.rb +62 -0
  70. data/lib/brandish/processors/html/output/document.rb +127 -0
  71. data/lib/brandish/processors/html/script.rb +64 -0
  72. data/lib/brandish/processors/html/script/babel.rb +48 -0
  73. data/lib/brandish/processors/html/script/coffee.rb +47 -0
  74. data/lib/brandish/processors/html/script/vanilla.rb +45 -0
  75. data/lib/brandish/processors/html/style.rb +82 -0
  76. data/lib/brandish/processors/html/style/highlight.rb +89 -0
  77. data/lib/brandish/processors/html/style/sass.rb +64 -0
  78. data/lib/brandish/processors/html/style/vanilla.rb +71 -0
  79. data/lib/brandish/processors/latex.rb +15 -0
  80. data/lib/brandish/processors/latex/markup.rb +47 -0
  81. data/lib/brandish/scanner.rb +64 -0
  82. data/lib/brandish/version.rb +9 -0
  83. data/templates/initialize/Gemfile.tt +14 -0
  84. data/templates/initialize/brandish.config.rb.tt +49 -0
  85. metadata +296 -0
@@ -0,0 +1,169 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require "forwardable"
5
+
6
+ module Brandish
7
+ module Processor
8
+ # The state associated with all of the processors. Since all processors
9
+ # are independant class instances, instance variables that are used in
10
+ # one processor does not affect another; however, shared state can be
11
+ # used through the context.
12
+ #
13
+ # The context also keeps track of the processors being used for the
14
+ # processor, and distributes the processing management throughout all of
15
+ # the processors.
16
+ class Context
17
+ # A "skip" construct. This makes the node be skipped through processing
18
+ # for the rest of the processors. This is automatically applied to all
19
+ # nodes that are {Parser::Node#update_prevented?}.
20
+ #
21
+ # Once the skip construct has been passed through the processing, it is
22
+ # automatically unwrapped, returning the original node.
23
+ Skip = Struct.new(:node)
24
+
25
+ extend Forwardable
26
+ # @!method <<(*processors)
27
+ # Adds processors to the processor list. This delegates to
28
+ # {#processors}.
29
+ #
30
+ # @return [<#call>]
31
+ # @!method push(*processors)
32
+ # Adds processors to the processor list. This delegates to
33
+ # {#processors}.
34
+ #
35
+ # @return [<#call>]
36
+ # @!method unshift(*processors)
37
+ # Adds a processor to the start of the processor list. This delegates
38
+ # to {#processors}.
39
+ #
40
+ # @return [<#call>]
41
+ delegate [:<<, :push, :unshift] => :@processors
42
+
43
+ # @!method [](key)
44
+ # Sets a key on the context. This gets an option that is used for all
45
+ # processors on this context.
46
+ #
47
+ # @param key [::Symbol, ::String] The key.
48
+ # @return [::Object]
49
+ # @!method []=(key, value)
50
+ # Sets a key on the context. This sets an option that is used for all
51
+ # processors on this context.
52
+ #
53
+ # @param key [::Symbol, ::String] The key.
54
+ # @param value [::Object] The value.
55
+ # @return [::Object]
56
+ # @!method fetch(key, default = CANARY, &block)
57
+ # Fetches a value at the given key, or provides a default if the key
58
+ # doesn't exist. If both a block and a default argument are given,
59
+ # the block form takes precedence.
60
+ #
61
+ # @overload fetch(key)
62
+ # Attempts to retrieve a value at the given key. If there is no
63
+ # key-value pair at the given key, it raises an error.
64
+ #
65
+ # @raise [KeyError] if the key isn't on the context.
66
+ # @param key [::Symbol, ::String] The key.
67
+ # @return [::Object] The value.
68
+ #
69
+ # @overload fetch(key, default)
70
+ # Attempts to retrieve a value at the given key. If there is no
71
+ # key-value pair at the given key, it returns the value given by
72
+ # `default`.
73
+ #
74
+ # @param key [::Symbol, ::String] The key.
75
+ # @param default [::Object] The default value.
76
+ # @return [::Object] The value, or the default value if there isn't
77
+ # one.
78
+ #
79
+ # @overload fetch(key, &block)
80
+ # attempts to retrieve a value at the given key. If there is no
81
+ # key-value pair at the given key, it yields.
82
+ #
83
+ # @yield if there is no corresponding key-value pair.
84
+ # @param key [::Symbol, ::String] The key.
85
+ # @return [::Object] The value, or the result of the block if there
86
+ # isn't one.
87
+ delegate [:[], :[]=, :fetch] => :@options
88
+
89
+ # @!method merge(options)
90
+ # Merges the given options into this context.
91
+ #
92
+ # @param options [{::Symbol, ::String => ::Object}]
93
+ # @return [void]
94
+ def_delegator :@options, :merge!, :merge
95
+
96
+ # The processors that are going to be run on an accept. This can be
97
+ # a {Processor::Base} subclass, or any object that responds to `#call`.
98
+ #
99
+ # @return [<#call>]
100
+ attr_reader :processors
101
+
102
+ # The configuration for the build. This is used for output directories
103
+ # and the like.
104
+ #
105
+ # @return [Configure]
106
+ attr_reader :configure
107
+
108
+ # The form that is being processed.
109
+ #
110
+ # @return [Configure::Form]
111
+ attr_reader :form
112
+
113
+ # Initialize the context, to set up the internal state.
114
+ def initialize(configure, form)
115
+ @processors = []
116
+ @configure = configure
117
+ @form = form
118
+ @descent = Processor::Descend.new(self)
119
+ @buffer = []
120
+ @options = {}
121
+ end
122
+
123
+ # Performs the processing of the given root node. This should be a
124
+ # {Parser::Node::Root}.
125
+ #
126
+ # @param root [Parser::Node::Root]
127
+ # @return [::Object]
128
+ def process(root)
129
+ root = accept(root)
130
+ effective_processors.each { |p| p.postprocess(root) }
131
+ end
132
+
133
+ # Accepts a node. This passes the node through all of the processors,
134
+ # as well as an instance of the {Processor::Descend} processor.
135
+ #
136
+ # @param node [Parser::Node] The node to process.
137
+ # @return [::Object]
138
+ def accept(node)
139
+ # Injects the node over all effective processors. Every iteration will
140
+ # use the value returned by the last `process` method call, unless it
141
+ # is `nil`.
142
+ result = effective_processors.inject(node) { |n, p| accept_node_with(n, p) }
143
+ result.is_a?(Skip) ? result.node : result
144
+ end
145
+
146
+ private
147
+
148
+ def accept_node_with(node, processor)
149
+ case node
150
+ when Skip, nil
151
+ node
152
+ when Parser::Node
153
+ result = processor.call(node)
154
+ if result.is_a?(Parser::Node) && result.update_prevented?
155
+ Skip.new(result)
156
+ else
157
+ result
158
+ end
159
+ else
160
+ fail ProcessorError, "Unknown node type `#{node.class}'"
161
+ end
162
+ end
163
+
164
+ def effective_processors
165
+ [@descent] + @processors
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Brandish
5
+ module Processor
6
+ # A descent processor. This allows the context to descend into the
7
+ # children of the node as needed. This does *not* descend into block
8
+ # nodes by default, due to a design decision - that has to be handled by
9
+ # another processor.
10
+ #
11
+ # @api private
12
+ class Descend < Base
13
+ # Initializes the processor with the given context. This *does not* adds
14
+ # the processor to the context, and sets the context for use on the
15
+ # processor.
16
+ #
17
+ # @param context [Context]
18
+ def initialize(context)
19
+ @context = context
20
+ end
21
+
22
+ # Processes the root node. This updates the root node with an updated
23
+ # list of children that have been accepted.
24
+ #
25
+ # @param node [Parser::Node::Root]
26
+ # @return [Parser::Node::Root]
27
+ def process_root(node)
28
+ node.update(children: node.children.map { |c| accept(c) }.compact)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Brandish
5
+ module Processor
6
+ # An inline-defined processor. This allows processors to be defined easily
7
+ # within a block. This is mostly used for configuration.
8
+ #
9
+ # @example
10
+ # class RFC < Brandish::Processor::Inline
11
+ # command! :rfc
12
+ # pairs :number
13
+ #
14
+ # perform do
15
+ # number = @pairs.fetch("number")
16
+ # "<a href='https://www.ietf.org/rfc/rfc#{number}.txt'>RFC #{number}</a>"
17
+ # end
18
+ # end
19
+ class Inline < Base
20
+ # Sets this processor as a command processor. This includes
21
+ # {Command}, and passes the given names to
22
+ # {NameFilter::ClassMethods#name}.
23
+ #
24
+ # @return [void]
25
+ def self.command!(*names)
26
+ include Command
27
+ name(*names)
28
+ end
29
+
30
+ # Sets this processor as a block processor. This include {Block}, and
31
+ # passes the given names to {NameFilter::ClassMethods#name}.
32
+ #
33
+ # @return [void]
34
+ def self.block!(*names)
35
+ include Block
36
+ name(*names)
37
+ end
38
+
39
+ # Defines the `#perform` method with the given block. This is only
40
+ # effective if one of {Command} or {Block} is included. This takes the
41
+ # block passed to it and uses that to define the `#perform` method.
42
+ #
43
+ # @return [void]
44
+ def self.perform(&block)
45
+ define_method(:perform, &block)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require "set"
5
+
6
+ module Brandish
7
+ module Processor
8
+ # A "name filter" for command and block nodes. This provides helpers to
9
+ # filter out nodes that don't have the given name. The class will keep
10
+ # an internal list of names that are allowed to be used for the node,
11
+ # and if the node matches, then it processes it.
12
+ #
13
+ # @api private
14
+ module NameFilter
15
+ # The class methods that are implemented on the including module. This
16
+ # is extended onto the class.
17
+ module ClassMethods
18
+ # The name that is assumed from the class name.
19
+ #
20
+ # @return [::String]
21
+ def assumed_class_name
22
+ name
23
+ .gsub(/\A(?:.+::)?(.*?)\z/, "\\1")
24
+ .gsub(/(?<!\A)[A-Z]/) { |m| "-#{m}" }
25
+ .downcase
26
+ end
27
+
28
+ # A list of allowed names for the class.
29
+ #
30
+ # @return [::Set<::String>]
31
+ def allowed_names
32
+ @names ||= name ? Set.new : Set[assumed_class_name]
33
+ end
34
+
35
+ # If no names are given, it retrieves them using {#allowed_names};
36
+ # otherwise, it merges the names into the allowed names set.
37
+ #
38
+ # @param names [#to_s, <#to_s>] The names.
39
+ # @return [::Set<::String>] The allowed names.
40
+ def names(*names)
41
+ return allowed_names if names.none?
42
+ allowed_names.merge(Array(names).flatten.map(&:to_s))
43
+ end
44
+
45
+ alias_method :name, :names
46
+ alias_method :names=, :names
47
+ alias_method :name=, :names
48
+ end
49
+
50
+ # The instance methods on the including class.
51
+ module InstanceMethods
52
+ # (see ClassMethods#allowed_names)
53
+ def allowed_names
54
+ self.class.allowed_names
55
+ end
56
+ end
57
+
58
+ # Used as a hook for Ruby.
59
+ #
60
+ # @api private
61
+ def self.included(receiver)
62
+ receiver.extend ClassMethods
63
+ receiver.send :include, InstanceMethods
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Brandish
5
+ module Processor
6
+ # A filter for defining which pairs are accepted by the given command or
7
+ # block processor. By default, all pairs are restricted; however, certain
8
+ # pairs can be whitelisted, or all pairs can be allowed. The former helps
9
+ # with debugging.
10
+ module PairFilter
11
+ # A placehodler object to denote that all pairs are allowed in the pair
12
+ # set. This is only inserted into the allowed pair set when
13
+ # {ClassMethods#unrestricted_pairs!} is called.
14
+ ALL = Object.new.freeze
15
+
16
+ # The class methods that are implemented on the including module. This
17
+ # is extended onto the class.
18
+ module ClassMethods
19
+ # A set of allowed pairs that can be used with the command or block
20
+ # element.
21
+ #
22
+ # @return [::Set<::String>]
23
+ def allowed_pairs
24
+ @allowed_pairs ||= Set.new
25
+ end
26
+
27
+ # A list of all of the ancestors' pairs. This includes the current
28
+ # classes' pairs. This allows allowed pair inheritance.
29
+ #
30
+ # @return [::Set<::String>]
31
+ def ancestor_allowed_pairs
32
+ ancestors
33
+ .select { |a| a.respond_to?(:allowed_pairs) }
34
+ .map(&:allowed_pairs)
35
+ .inject(Set.new, :merge)
36
+ end
37
+
38
+ # Retrives or sets the pairs for the class.
39
+ #
40
+ # @overload pairs
41
+ # Retrieves the current pairs. This is the same as calling
42
+ # {#allowed_pairs}.
43
+ #
44
+ # @return [::Set<::String>]
45
+ # @overload pairs(*pairs)
46
+ # Adds pairs to the current {#allowed_pairs}.
47
+ #
48
+ # @param pairs [::String, ::Symbol, #to_s]
49
+ # @return [void]
50
+ def pairs(*pairs)
51
+ return allowed_pairs if pairs.none?
52
+ allowed_pairs.merge(Array(pairs).flatten.map(&:to_s))
53
+ end
54
+ alias_method :pair, :pairs
55
+
56
+ # Adds {PairFilter::ALL} to the pair list, allowing all pairs to be
57
+ # used with the command or block.
58
+ #
59
+ # @return [void]
60
+ def unrestricted_pairs!
61
+ pairs PairFilter::ALL
62
+ end
63
+ alias_method :unrestricted_pairs, :unrestricted_pairs!
64
+ end
65
+
66
+ # The instance methods on the including class.
67
+ module InstanceMethods
68
+ # (see ClassMethods#ancestor_allowed_pairs)
69
+ def allowed_pairs
70
+ self.class.ancestor_allowed_pairs
71
+ end
72
+
73
+ # Asserts that the pairs given are all allowed. This uses the
74
+ # `@pairs` and `@node` instance variables.
75
+ #
76
+ # @raise [PairError] If an invalid pair was given.
77
+ # @return [void]
78
+ def assert_valid_pairs
79
+ return if allowed_pairs.include?(PairFilter::ALL)
80
+ excessive = @pairs.keys - allowed_pairs
81
+ return unless excessive.any?
82
+ fail PairError.new("Unexpected pairs found " \
83
+ "(#{excessive.map(&:inspect).join(', ')})", @node.location)
84
+ end
85
+ end
86
+
87
+ # Used as a hook for Ruby.
88
+ #
89
+ # @api private
90
+ def self.included(receiver)
91
+ receiver.extend ClassMethods
92
+ receiver.send :include, InstanceMethods
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require "brandish/processors/common"
5
+ require "brandish/processors/all"
6
+ require "brandish/processors/html"
7
+ require "brandish/processors/latex"
8
+
9
+ module Brandish
10
+ # All of the available processors provided by Brandish by default are defined
11
+ # under this module. Under this module, there are a set of modules, all
12
+ # pertaining to either a format, `All`, or `Common`. `All` processors are
13
+ # provided for all documents, regardless of format; `Common` processors are
14
+ # always abstract, and define a set of processors that are required to be
15
+ # implemented for all formats. If a format does not provide a `Common`
16
+ # processor, it is considered a bug.
17
+ module Processors
18
+ # All of the format modules under the {Processors} module. This is
19
+ # essentially all modules that aren't named `All` or `Common`.
20
+ #
21
+ # @return [<Module>]
22
+ def self.format_modules
23
+ (constants - [:All, :Common]).map { |c| Processors.const_get(c) }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require "brandish/processors/all/embed"
5
+ require "brandish/processors/all/if"
6
+ require "brandish/processors/all/import"
7
+ require "brandish/processors/all/literal"
8
+ require "brandish/processors/all/verify"
9
+
10
+ module Brandish
11
+ module Processors
12
+ # Processors designed for use with all formats. This module does not
13
+ # implement the {Common} processors, since the common processors can be
14
+ # format-dependant. All processors in this module are defined on the
15
+ # `:all` special format.
16
+ module All
17
+ end
18
+ end
19
+ end