brandish 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,163 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "forwardable"
|
5
|
+
|
6
|
+
module Brandish
|
7
|
+
# A set of paths that can be searched for a certain file. This is used for
|
8
|
+
# looking for certain files, like sources or templates. This can allow
|
9
|
+
# Brandish to provide "default" files.
|
10
|
+
#
|
11
|
+
# Despite its name, the order in which the paths are added to the pathset
|
12
|
+
# are important.
|
13
|
+
class PathSet
|
14
|
+
extend Forwardable
|
15
|
+
include Enumerable
|
16
|
+
|
17
|
+
# @!method clear
|
18
|
+
# Removes all of the paths from this pathset.
|
19
|
+
#
|
20
|
+
# @return [void]
|
21
|
+
def_delegator :@paths, :clear
|
22
|
+
|
23
|
+
# @!method each(&block)
|
24
|
+
# @overload each
|
25
|
+
# Returns an enumerable over all of the paths in the pathset.
|
26
|
+
#
|
27
|
+
# @return [::Enumerable<::Pathname>]
|
28
|
+
# @overload each(&block)
|
29
|
+
# Iterates over all of the paths in this pathset.
|
30
|
+
#
|
31
|
+
# @yield path For each path in the pathset.
|
32
|
+
# @yieldparam path [::Pathname] The path.
|
33
|
+
# @return [void]
|
34
|
+
def_delegator :@paths, :each
|
35
|
+
|
36
|
+
# Initialize the pathset.
|
37
|
+
def initialize
|
38
|
+
@paths = []
|
39
|
+
end
|
40
|
+
|
41
|
+
# Adds a path to this pathset.
|
42
|
+
#
|
43
|
+
# @param path [::String, ::Pathname]
|
44
|
+
# @return [self]
|
45
|
+
def <<(path)
|
46
|
+
@paths << ::Pathname.new(path)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Calls {#clear}, and then uses {#<<} to append the given path to the
|
50
|
+
# pathset, effectively replacing all of the paths in the pathset with the
|
51
|
+
# one given.
|
52
|
+
#
|
53
|
+
# @param path [::String, ::Pathname]
|
54
|
+
# @return [self]
|
55
|
+
def replace(path)
|
56
|
+
clear
|
57
|
+
self << path
|
58
|
+
end
|
59
|
+
|
60
|
+
# The default options for {#find} and {#find_all}.
|
61
|
+
#
|
62
|
+
# @return [{::Symbol => ::Object}]
|
63
|
+
DEFAULT_FIND_OPTIONS = { file: true, allow_absolute: false }.freeze
|
64
|
+
|
65
|
+
# "Resolves" a path. This is resolved the exact same way that {#find}
|
66
|
+
# and {#find_all} are (with some slight variations), and so can be used
|
67
|
+
# as a sort of "name" for a certain path.
|
68
|
+
#
|
69
|
+
# @param path [::String, ::Pathname] The path to the file.
|
70
|
+
# @param options [{::Symbol => ::Object}] The options for resolution.
|
71
|
+
# @return [::Pathname] The resolved path.
|
72
|
+
def resolve(path, options = {})
|
73
|
+
options = DEFAULT_FIND_OPTIONS.merge(options)
|
74
|
+
path = ::Pathname.new(path)
|
75
|
+
if options[:allow_absolute]
|
76
|
+
path.cleanpath
|
77
|
+
else
|
78
|
+
::Pathname.new(path.expand_path("/").to_s.gsub(%r{\A(/|\\)}, ""))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Finds a file in the pathset. If the file is returned, it is guarenteed
|
83
|
+
# to exist. Relative paths, that do not expand out of the relative path,
|
84
|
+
# are handled like you would expect - the path is appended to one of the
|
85
|
+
# paths in the set, and checked for existance. However, for a file that
|
86
|
+
# expands out of the relative path (e.g. `../a` or `a/../../b`), the
|
87
|
+
# behavior for expansion depends on the `allow_absolute` option. If
|
88
|
+
# `allow_absolute` is false (default), the path is expanded against `/`
|
89
|
+
# before it is joind with the paths in the set (e.g. `../a`, against
|
90
|
+
# `/path/to`, with `allow_absolute=false`, expands to `/path/to/a`).
|
91
|
+
# If `allow_absolute` is true, it directly expanding against the path
|
92
|
+
# (e.g. `../a`, against `/path/to`, with `allow_absolute=true`, expands
|
93
|
+
# to `/path/a`). `allow_absolute` should only be used if the given path
|
94
|
+
# is trusted. Absolute paths are handled in a similar manner; if
|
95
|
+
# `allow_absolute=false`, for `/a` against `/path/to`, it expands to
|
96
|
+
# `/path/to/a`; with `allow_absolute=true`, for `/a` against `/path/to`,
|
97
|
+
# it expands to `/a`.
|
98
|
+
#
|
99
|
+
# @example
|
100
|
+
# pathset
|
101
|
+
# # => #<PathSet ...>
|
102
|
+
# pathset.find("some/file")
|
103
|
+
# # => #<Pathname /path/to/some/file>
|
104
|
+
# pathset.find("not/real")
|
105
|
+
# # !> NoFileError
|
106
|
+
# pathset.find("/path/to/some/file")
|
107
|
+
# # !> NoFileError
|
108
|
+
# pathset.find("/path/to/some/file", allow_absolute: true)
|
109
|
+
# # => #<Pathname /path/to/some/file>
|
110
|
+
# pathset.find("../to/some/file")
|
111
|
+
# # !> NoFileError
|
112
|
+
# pathset.find("../to/some/file", allow_absolute: true)
|
113
|
+
# # => #<Pathname /path/to/some/file>
|
114
|
+
# @raise [NoFileError] If no file could be found.
|
115
|
+
# @param short [::String, ::Pathname] The "short" path to resolve.
|
116
|
+
# @param options [{::Symbol => ::Object}] The options for finding.
|
117
|
+
# @option (see #find_all)
|
118
|
+
# @return [::Pathname] The full absolute path to the file.
|
119
|
+
def find(short, options = {})
|
120
|
+
find_all(short, options).next
|
121
|
+
rescue ::StopIteration
|
122
|
+
fail NoFileError, "Could not find `#{short}' in any of the given paths (paths: #{@paths})"
|
123
|
+
end
|
124
|
+
|
125
|
+
# Finds all versions of the short path name in the paths in the path
|
126
|
+
# sets. If no block is given, it returns an enumerable; otherwise, if
|
127
|
+
# a block is given, it yields the joined path if it exists.
|
128
|
+
#
|
129
|
+
# @raise NoFileError If no file could be found.
|
130
|
+
# @param short [::String, ::Pathname] The "short" path to resolve.
|
131
|
+
# @param options [{::Symbol => ::Object}] The options for finding.
|
132
|
+
# @option options [Boolean] :allow_absolute (false)
|
133
|
+
# @option options [Boolean] :file (true) Whether or not the full path
|
134
|
+
# must be a file for it to be considered existant. This should be set
|
135
|
+
# to true, because in most cases, it's the desired behavior.
|
136
|
+
# @yield [path] For every file that exists.
|
137
|
+
# @yieldparam path [::Pathname] The path to the file. This is guarenteed
|
138
|
+
# to exist.
|
139
|
+
# @return [void]
|
140
|
+
def find_all(short, options = {})
|
141
|
+
return to_enum(:find_all, short, options) unless block_given?
|
142
|
+
short = ::Pathname.new(short)
|
143
|
+
options = DEFAULT_FIND_OPTIONS.merge(options)
|
144
|
+
|
145
|
+
@paths.reverse.each do |path|
|
146
|
+
joined = path_join(path, short, options)
|
147
|
+
yield joined if (options[:file] && joined.file?) || joined.exist?
|
148
|
+
end
|
149
|
+
|
150
|
+
nil
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def path_join(path, short, options)
|
156
|
+
if options[:allow_absolute]
|
157
|
+
short.expand_path(path)
|
158
|
+
else
|
159
|
+
::Pathname.new(::File.join(path, short.expand_path("/")))
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "brandish/processor/base"
|
5
|
+
require "brandish/processor/context"
|
6
|
+
require "brandish/processor/name_filter"
|
7
|
+
require "brandish/processor/block"
|
8
|
+
require "brandish/processor/command"
|
9
|
+
require "brandish/processor/descend"
|
10
|
+
|
11
|
+
module Brandish
|
12
|
+
# Processors for Brandish. These just handle reshaping nodes so that they
|
13
|
+
# output nicely. This can be used for things like including, bold tags,
|
14
|
+
# etc.
|
15
|
+
module Processor
|
16
|
+
# A structure containing all of the processors available. This is a key
|
17
|
+
# value store, with the key being the format and the name, and the value
|
18
|
+
# being the actual processor.
|
19
|
+
#
|
20
|
+
# @return [{(::Symbol, ::Symbol) => Processor::Base}]
|
21
|
+
def self.all
|
22
|
+
@_processors ||= ::Hash.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# Registers processors with the global registry. This interns the format
|
26
|
+
# and name of the processor. If the format and name pair already exists,
|
27
|
+
# it raises a {ProcessorError}.
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# Processor.register [:html, :stripper] => self
|
31
|
+
# @example
|
32
|
+
# Processor.register [:all, :descend] => self
|
33
|
+
# @raise [ProcessorError] If one of the format and name pairs already
|
34
|
+
# exists.
|
35
|
+
# @param map [{(::Symbol, ::Symbol) => Processor::Base}] The processors to
|
36
|
+
# register.
|
37
|
+
# @return [void]
|
38
|
+
def self.register(map)
|
39
|
+
map.each do |(format, name), processor|
|
40
|
+
format, name = format.intern, name.intern
|
41
|
+
fail ProcessorError, "#{format}:#{name} already exists" \
|
42
|
+
if all.key?([format, name])
|
43
|
+
all[[format, name]] = processor
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Brandish
|
5
|
+
module Processor
|
6
|
+
# A processor. This responds to a set of methods that return updated
|
7
|
+
# versions of the nodes that are passed to them. Processors are all
|
8
|
+
# initialized at the same time, with a context. The processor is expected
|
9
|
+
# to add an object that responds to #call with arity matching `1` to the
|
10
|
+
# context using {Context#<<}. The processor is allowed to add any number
|
11
|
+
# of objects to the context using this, if need be; by default, the
|
12
|
+
# processor just adds itself.
|
13
|
+
#
|
14
|
+
# @abstract
|
15
|
+
# This class is not designed to be used and instantiated directly; this
|
16
|
+
# just provides common behavior for a processor. This class should be
|
17
|
+
# subclassed and proper behavior defined on a subclass.
|
18
|
+
class Base
|
19
|
+
# (see Processor.register)
|
20
|
+
def self.register(map)
|
21
|
+
Processor.register(map)
|
22
|
+
end
|
23
|
+
|
24
|
+
# The context associated with this processor.
|
25
|
+
#
|
26
|
+
# @return [Context]
|
27
|
+
attr_reader :context
|
28
|
+
|
29
|
+
# Initializes the processor with the given context. This adds the
|
30
|
+
# processor to the context, and sets the context for use on the
|
31
|
+
# processor.
|
32
|
+
#
|
33
|
+
# @param context [Context]
|
34
|
+
# @param options [::Object] The options for this processor.
|
35
|
+
def initialize(context, options = {})
|
36
|
+
@context = context
|
37
|
+
@context << self
|
38
|
+
@options = options
|
39
|
+
setup
|
40
|
+
end
|
41
|
+
|
42
|
+
# This is called by {#initialize}. This allows subclasses to perform
|
43
|
+
# any nessicary setups without having to override {#initialize}. This
|
44
|
+
# does nothing by default.
|
45
|
+
#
|
46
|
+
# @return [void]
|
47
|
+
def setup; end
|
48
|
+
|
49
|
+
# Processes the given node. By default, it checks the classes of the
|
50
|
+
# inbound node, and maps them to `process_*` blocks. If it doesn't
|
51
|
+
# match, an `ArgumentError` is thrown.
|
52
|
+
#
|
53
|
+
# If this function returns a `nil` value, the node should be ignored.
|
54
|
+
# {Context#accept} acknowledges this, and skips over the remaining
|
55
|
+
# processors once a processor returns a `nil` value for a node.
|
56
|
+
#
|
57
|
+
# @raise [::ArgumentError] if the node given isn't one of
|
58
|
+
# {Parser::Node::Block}, {Parser::Node::Command}, {Parser::Node::Root},
|
59
|
+
# or {Parser::Node::Text}.
|
60
|
+
# @param node [Parser::Node] A parser node to handle.
|
61
|
+
# @return [Parser::Node, nil] The result of processing.
|
62
|
+
def call(node)
|
63
|
+
_fix_result(_switch_node(node), node)
|
64
|
+
rescue LocationError then fail
|
65
|
+
rescue => e
|
66
|
+
fail BuildError.new("#{e.class}: #{e.message}", node.location,
|
67
|
+
e.backtrace)
|
68
|
+
end
|
69
|
+
|
70
|
+
# (see Context#accept)
|
71
|
+
def accept(node)
|
72
|
+
context.accept(node)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Processes a block. By default, this performs no modifications on the
|
76
|
+
# node, and returns the node itself.
|
77
|
+
#
|
78
|
+
# @param node [Parser::Node::Block]
|
79
|
+
# @return [::Object]
|
80
|
+
def process_block(node)
|
81
|
+
node
|
82
|
+
end
|
83
|
+
|
84
|
+
# Processes a command. By default, this performs no modifications on the
|
85
|
+
# node, and returns the node itself.
|
86
|
+
#
|
87
|
+
# @param node [Parser::Node::Command]
|
88
|
+
# @return [::Object]
|
89
|
+
def process_command(node)
|
90
|
+
node
|
91
|
+
end
|
92
|
+
|
93
|
+
# Processes a root node. By default, this performs no modifications on
|
94
|
+
# the node, and returns the node itself.
|
95
|
+
#
|
96
|
+
# @param node [Parser::Node::Root]
|
97
|
+
# @return [::Object]
|
98
|
+
def process_root(node)
|
99
|
+
node
|
100
|
+
end
|
101
|
+
|
102
|
+
# Processes a text node. By default, this performs no modifications on
|
103
|
+
# the node, and returns the node itself.
|
104
|
+
#
|
105
|
+
# @param node [Parser::Node::Text]
|
106
|
+
# @return [::Object]
|
107
|
+
def process_text(node)
|
108
|
+
node
|
109
|
+
end
|
110
|
+
|
111
|
+
# An optional post-process.
|
112
|
+
#
|
113
|
+
# @param root [Parser::Node::Root]
|
114
|
+
# @return [void]
|
115
|
+
def postprocess(root); end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def _switch_node(node)
|
120
|
+
case node
|
121
|
+
when Parser::Node::Block then process_block(node)
|
122
|
+
when Parser::Node::Command then process_command(node)
|
123
|
+
when Parser::Node::Root then process_root(node)
|
124
|
+
when Parser::Node::Text then process_text(node)
|
125
|
+
else
|
126
|
+
fail ArgumentError, "Expected node, got `#{node.class}'"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def _fix_result(result, node)
|
131
|
+
case result
|
132
|
+
when Parser::Node, nil
|
133
|
+
result
|
134
|
+
when ::String
|
135
|
+
Parser::Node::Text.new(value: result, location: node.location)
|
136
|
+
.prevent_update
|
137
|
+
else
|
138
|
+
fail ArgumentError, "Unknown result type `#{result.class}' " \
|
139
|
+
"(given from #{self.class})"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Brandish
|
5
|
+
module Processor
|
6
|
+
# A block processor. This is designed to act over a base to modify
|
7
|
+
# one specific block. The block name itself is specified on the
|
8
|
+
# class, and the class provides logic to only modify block nodes with
|
9
|
+
# the same name.
|
10
|
+
module Block
|
11
|
+
# Ruby hook.
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
# @return [void]
|
15
|
+
def self.included(base)
|
16
|
+
base.include Processor::NameFilter
|
17
|
+
base.include Processor::Pairfilter
|
18
|
+
end
|
19
|
+
|
20
|
+
# Processes the block. If the node's name doesn't match the name for
|
21
|
+
# this class, it passes it on up to {Base#process_block}; otherwise,
|
22
|
+
# it passes it over to {#perform}.
|
23
|
+
#
|
24
|
+
# @param node [Parser::Node::Block]
|
25
|
+
# @return [::Object]
|
26
|
+
def process_block(node)
|
27
|
+
return super unless allowed_names.include?(node.name)
|
28
|
+
@node = node
|
29
|
+
@name = node.name
|
30
|
+
@pairs = node.pairs
|
31
|
+
@body = node.body
|
32
|
+
|
33
|
+
assert_valid_pairs
|
34
|
+
perform
|
35
|
+
end
|
36
|
+
|
37
|
+
# Performs the command adjustment. This must be subclassed and
|
38
|
+
# overwritten.
|
39
|
+
#
|
40
|
+
# @abstract
|
41
|
+
# @return [::Object]
|
42
|
+
def perform
|
43
|
+
fail NotImplementedError, "Please implement #{self.class}#perform"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Brandish
|
5
|
+
module Processor
|
6
|
+
# A command processor. This is designed to act over a base to modify
|
7
|
+
# one specific command. The command name itself is specified on the
|
8
|
+
# class, and the class provides logic to only modify command nodes with
|
9
|
+
# the same name.
|
10
|
+
module Command
|
11
|
+
# Ruby hook.
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
# @return [void]
|
15
|
+
def self.included(base)
|
16
|
+
base.include Processor::NameFilter
|
17
|
+
base.include Processor::PairFilter
|
18
|
+
end
|
19
|
+
|
20
|
+
# Processes the command. If the node's name doesn't match the name for
|
21
|
+
# this class, it passes it on up to {Base#process_command}; otherwise,
|
22
|
+
# it passes it over to {#perform}.
|
23
|
+
#
|
24
|
+
# @param node [Parser::Node::Command]
|
25
|
+
# @return [::Object]
|
26
|
+
def process_command(node)
|
27
|
+
return super unless allowed_names.include?(node.name)
|
28
|
+
@node = node
|
29
|
+
@name = node.name
|
30
|
+
@pairs = node.pairs
|
31
|
+
@body = nil
|
32
|
+
|
33
|
+
assert_valid_pairs
|
34
|
+
perform
|
35
|
+
end
|
36
|
+
|
37
|
+
# Performs the command adjustment. This must be subclassed and
|
38
|
+
# overwritten.
|
39
|
+
#
|
40
|
+
# @abstract
|
41
|
+
# @return [::Object]
|
42
|
+
def perform
|
43
|
+
fail NotImplementedError, "Please implement #{self.class}#perform"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|