lookbooklet 0.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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +234 -0
- data/bin/booklet +6 -0
- data/lib/booklet/analyzer.rb +28 -0
- data/lib/booklet/cli/cli.rb +14 -0
- data/lib/booklet/cli/commands/analyze_command.rb +45 -0
- data/lib/booklet/cli/commands/version_command.rb +13 -0
- data/lib/booklet/cli/concerns/colorful.rb +51 -0
- data/lib/booklet/concerns/locatable.rb +22 -0
- data/lib/booklet/file.rb +90 -0
- data/lib/booklet/helpers.rb +19 -0
- data/lib/booklet/node.rb +297 -0
- data/lib/booklet/nodes/anon_node.rb +9 -0
- data/lib/booklet/nodes/asset_node.rb +15 -0
- data/lib/booklet/nodes/directory_node.rb +17 -0
- data/lib/booklet/nodes/document_node.rb +11 -0
- data/lib/booklet/nodes/file_node.rb +15 -0
- data/lib/booklet/nodes/folder_node.rb +13 -0
- data/lib/booklet/nodes/prose_node.rb +7 -0
- data/lib/booklet/nodes/scenario_node.rb +13 -0
- data/lib/booklet/nodes/spec_node.rb +19 -0
- data/lib/booklet/object.rb +23 -0
- data/lib/booklet/options.rb +31 -0
- data/lib/booklet/value.rb +16 -0
- data/lib/booklet/values/code_snippet.rb +25 -0
- data/lib/booklet/values/method_snippet.rb +20 -0
- data/lib/booklet/values/node_type.rb +55 -0
- data/lib/booklet/values/parser_result.rb +11 -0
- data/lib/booklet/values/source_location.rb +17 -0
- data/lib/booklet/values/text_snippet.rb +21 -0
- data/lib/booklet/values.rb +31 -0
- data/lib/booklet/version.rb +5 -0
- data/lib/booklet/visitor.rb +58 -0
- data/lib/booklet/visitors/ascii_tree_renderer.rb +36 -0
- data/lib/booklet/visitors/entity_transformer.rb +18 -0
- data/lib/booklet/visitors/filesystem_loader.rb +18 -0
- data/lib/booklet/visitors/frontmatter_extractor.rb +10 -0
- data/lib/booklet/visitors/preview_class_parser.rb +42 -0
- data/lib/booklet/yard_parser.rb +23 -0
- data/lib/booklet.rb +29 -0
- data/lib/lookbooklet.rb +3 -0
- metadata +182 -0
data/lib/booklet/node.rb
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class Node < Booklet::Object
|
|
5
|
+
include Enumerable
|
|
6
|
+
include Comparable
|
|
7
|
+
include Values
|
|
8
|
+
|
|
9
|
+
prop :ref, String, :positional, reader: :public do |value|
|
|
10
|
+
value.to_s unless value.nil?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_reader :parent
|
|
14
|
+
protected attr_writer :parent
|
|
15
|
+
|
|
16
|
+
after_initialize do
|
|
17
|
+
@parent = nil
|
|
18
|
+
@children = []
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def ref_path
|
|
22
|
+
@ref_path ||= [ancestors&.map(&:ref)&.reverse, ref].flatten.compact.join("/")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @!group Ancestry
|
|
26
|
+
|
|
27
|
+
def root
|
|
28
|
+
root = self
|
|
29
|
+
root = root.parent until root.root?
|
|
30
|
+
root
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def root?
|
|
34
|
+
parent.nil?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def ancestors
|
|
38
|
+
return nil if root?
|
|
39
|
+
|
|
40
|
+
ancestors = []
|
|
41
|
+
prev_parent = parent
|
|
42
|
+
while prev_parent
|
|
43
|
+
ancestors << prev_parent
|
|
44
|
+
prev_parent = prev_parent.parent
|
|
45
|
+
end
|
|
46
|
+
ancestors
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @!endgroup
|
|
50
|
+
|
|
51
|
+
# @!group Descendants
|
|
52
|
+
|
|
53
|
+
def children(&block)
|
|
54
|
+
if block_given?
|
|
55
|
+
@children.each(&block)
|
|
56
|
+
self
|
|
57
|
+
else
|
|
58
|
+
@children.clone
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
delegate :[], to: :children
|
|
63
|
+
|
|
64
|
+
def children?
|
|
65
|
+
children.any?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def depth
|
|
69
|
+
ancestors&.size || 0
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def descendants
|
|
73
|
+
filter { _1 != self }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def first_child
|
|
77
|
+
@children.first
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def last_child
|
|
81
|
+
@children.last
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def first_child?
|
|
85
|
+
self == first_child
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def last_child?
|
|
89
|
+
self == last_child
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def has_child?(node)
|
|
93
|
+
children.find { _1.ref == node.ref && _1.type == node.type }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def leaf?
|
|
97
|
+
!children?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def branch?
|
|
101
|
+
!leaf?
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @!endgroup
|
|
105
|
+
|
|
106
|
+
# @!group Siblings
|
|
107
|
+
|
|
108
|
+
def siblings
|
|
109
|
+
siblings = root? ? [] : parent.children.filter { _1 != self }
|
|
110
|
+
if block_given?
|
|
111
|
+
children.each(&block)
|
|
112
|
+
self
|
|
113
|
+
else
|
|
114
|
+
siblings
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def first_sibling
|
|
119
|
+
root? ? self : parent.children.first
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def first_sibling?
|
|
123
|
+
self == first_sibling
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def last_sibling
|
|
127
|
+
root? ? self : parent.children.last
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def last_sibling?
|
|
131
|
+
self == last_sibling
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def next_sibling
|
|
135
|
+
return nil if root?
|
|
136
|
+
|
|
137
|
+
position = parent.children.index(self)
|
|
138
|
+
parent.children.at(position + 1) if position
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def previous_sibling
|
|
142
|
+
return nil if root?
|
|
143
|
+
|
|
144
|
+
position = parent.children.index(self)
|
|
145
|
+
parent.children.at(position - 1) if position&.positive?
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# @!endgroup
|
|
149
|
+
|
|
150
|
+
# @!group Adding children
|
|
151
|
+
|
|
152
|
+
def add(node)
|
|
153
|
+
validate_child!(node)
|
|
154
|
+
|
|
155
|
+
@children << node
|
|
156
|
+
node.parent = self
|
|
157
|
+
node
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
alias_method :<<, :add
|
|
161
|
+
|
|
162
|
+
def validate_child!(node)
|
|
163
|
+
raise ArgumentError, "Only Node instances can be added as children" unless node.is_a?(Node)
|
|
164
|
+
raise ArgumentError, "`#{node.ref}` is already a child of node `#{ref}`" if has_child?(node)
|
|
165
|
+
raise ArgumentError, "`#{node.ref}` is already attached to another node" unless node.root?
|
|
166
|
+
|
|
167
|
+
raise ArgumentError, "Parent node does not accept children" if valid_child_types.nil?
|
|
168
|
+
|
|
169
|
+
unless valid_child_types.include?(node.type)
|
|
170
|
+
raise TypeError, "Invalid node type '#{node.type}' - must be one of [#{valid_child_types.join(", ")}]"
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def push(*children)
|
|
175
|
+
children.each { add(_1) }
|
|
176
|
+
self
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# @!endgroup
|
|
180
|
+
|
|
181
|
+
# @!group Iteration
|
|
182
|
+
|
|
183
|
+
def each_node
|
|
184
|
+
return to_enum unless block_given?
|
|
185
|
+
|
|
186
|
+
node_stack = [self]
|
|
187
|
+
until node_stack.empty?
|
|
188
|
+
current = node_stack.shift
|
|
189
|
+
next unless current
|
|
190
|
+
yield current
|
|
191
|
+
node_stack = current.children.concat(node_stack)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
self if block_given?
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
protected alias_method :each, :each_node
|
|
198
|
+
|
|
199
|
+
# @!endgroup
|
|
200
|
+
|
|
201
|
+
# @!group Comparison
|
|
202
|
+
|
|
203
|
+
def <=>(other)
|
|
204
|
+
return nil if other.nil? || !other.is_a?(Node)
|
|
205
|
+
|
|
206
|
+
self_index = root.each_node.to_a.index(self)
|
|
207
|
+
other_index = root.each_node.to_a.index(other)
|
|
208
|
+
|
|
209
|
+
return nil if other_index.nil?
|
|
210
|
+
|
|
211
|
+
other_index <=> self_index
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# @!group Visting
|
|
215
|
+
|
|
216
|
+
def accept(visitor)
|
|
217
|
+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
|
218
|
+
def accept(visitor)
|
|
219
|
+
visitor.visit_#{type}(self)
|
|
220
|
+
end
|
|
221
|
+
RUBY
|
|
222
|
+
|
|
223
|
+
accept(visitor)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# @!endgroup
|
|
227
|
+
|
|
228
|
+
# @!group Type & type checking
|
|
229
|
+
|
|
230
|
+
def type
|
|
231
|
+
@type ||= NodeType(self.class)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def method_missing(name, ...)
|
|
235
|
+
if name.end_with?("?")
|
|
236
|
+
type.public_send(name)
|
|
237
|
+
elsif name.start_with?("each_")
|
|
238
|
+
filter_type = name.to_s.delete_prefix("each_")
|
|
239
|
+
filter { _1.type == filter_type }
|
|
240
|
+
else
|
|
241
|
+
super
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def respond_to_missing?(name, ...)
|
|
246
|
+
name.end_with?("?") || name.start_with?("each_") || super
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# @!endgroup
|
|
250
|
+
|
|
251
|
+
# @!group Utilities
|
|
252
|
+
|
|
253
|
+
def inspect
|
|
254
|
+
"#<#{self.class.name} @ref=#{ref}>"
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# @!endgroup
|
|
258
|
+
|
|
259
|
+
# @!group Child type constraints
|
|
260
|
+
|
|
261
|
+
class_attribute :valid_child_types,
|
|
262
|
+
instance_predicate: false,
|
|
263
|
+
default: []
|
|
264
|
+
|
|
265
|
+
class_attribute :file_matcher,
|
|
266
|
+
instance_reader: false,
|
|
267
|
+
instance_writer: false,
|
|
268
|
+
instance_predicate: false,
|
|
269
|
+
default: lambda { false }
|
|
270
|
+
|
|
271
|
+
def permit_child_types(*args)
|
|
272
|
+
args.flatten!
|
|
273
|
+
self.valid_child_types = args.map { NodeType(_1) } unless args.first.nil?
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
class << self
|
|
277
|
+
def permit_child_types(*args)
|
|
278
|
+
args.flatten!
|
|
279
|
+
self.valid_child_types = args.map { NodeType(_1) } unless args.first.nil?
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def type
|
|
283
|
+
NodeType.new(self)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
def match(&block)
|
|
287
|
+
self.file_matcher = block
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def matches?(file)
|
|
291
|
+
file_matcher.call(file)
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
permit_child_types Node
|
|
296
|
+
end
|
|
297
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class AssetNode < Node
|
|
5
|
+
include Locatable
|
|
6
|
+
|
|
7
|
+
MIME_TYPES = %w[text/css text/javascript]
|
|
8
|
+
|
|
9
|
+
match do |file|
|
|
10
|
+
return if file.directory?
|
|
11
|
+
|
|
12
|
+
file.mime_type.in?(MIME_TYPES) || file.mime_type.start_with?("image/")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class DirectoryNode < Node
|
|
5
|
+
include Locatable
|
|
6
|
+
|
|
7
|
+
permit_child_types FileNode, DirectoryNode
|
|
8
|
+
|
|
9
|
+
def name
|
|
10
|
+
file.basename
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
alias_method :label, :name
|
|
14
|
+
|
|
15
|
+
delegate :file?, :directory?, :ext, :ext?, :dirname, :basename, :path_segments, :mime_type, :to_pathname, :contents, to: :file
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class FileNode < Node
|
|
5
|
+
include Locatable
|
|
6
|
+
|
|
7
|
+
def name
|
|
8
|
+
file.basename
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
alias_method :label, :name
|
|
12
|
+
|
|
13
|
+
delegate :file?, :directory?, :ext, :ext?, :dirname, :basename, :path_segments, :mime_type, :to_pathname, :contents, to: :file
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module Booklet
|
|
2
|
+
class ScenarioNode < Node
|
|
3
|
+
prop :notes, _Nilable(TextSnippet), reader: :public, writer: :public
|
|
4
|
+
prop :source, CodeSnippet, reader: :public, writer: :public
|
|
5
|
+
prop :parameters, Array, reader: :public, writer: :public, default: [].freeze
|
|
6
|
+
|
|
7
|
+
alias_method :name, :ref
|
|
8
|
+
|
|
9
|
+
def label
|
|
10
|
+
name.titleize
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class SpecNode < Node
|
|
5
|
+
include Locatable
|
|
6
|
+
|
|
7
|
+
prop :notes, _Nilable(TextSnippet), reader: :public, writer: :public
|
|
8
|
+
|
|
9
|
+
permit_child_types :prose, :scenario
|
|
10
|
+
|
|
11
|
+
match do |file|
|
|
12
|
+
file.ext?(".rb") && file.name.end_with?("_preview")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def scenarios
|
|
16
|
+
filter(&:scenario?)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class Object < Literal::Object
|
|
5
|
+
include ActiveSupport::Callbacks
|
|
6
|
+
include Values
|
|
7
|
+
include Helpers
|
|
8
|
+
|
|
9
|
+
define_callbacks :initialize
|
|
10
|
+
|
|
11
|
+
def after_initialize
|
|
12
|
+
run_callbacks :initialize
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
include Values
|
|
17
|
+
|
|
18
|
+
def after_initialize(&)
|
|
19
|
+
set_callback :initialize, :after, &
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require "active_support/ordered_options"
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class Options < ActiveSupport::InheritableOptions
|
|
5
|
+
def to_h
|
|
6
|
+
transform_values(&self.class.transformer)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def new(options)
|
|
11
|
+
super(options.transform_values(&transformer))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
protected def convert_value(value, wrap = true)
|
|
15
|
+
if !wrap && value.respond_to?(:to_h)
|
|
16
|
+
value.to_h
|
|
17
|
+
elsif wrap && value.respond_to?(:to_h)
|
|
18
|
+
new(value.to_h)
|
|
19
|
+
elsif value.is_a?(Array)
|
|
20
|
+
value.map { convert_value(_1, wrap) }
|
|
21
|
+
else
|
|
22
|
+
value
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected def transformer
|
|
27
|
+
method(:convert_value)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class Value < Literal::Data
|
|
5
|
+
include Comparable
|
|
6
|
+
include Values
|
|
7
|
+
include Helpers
|
|
8
|
+
|
|
9
|
+
def ==(other)
|
|
10
|
+
return nil if !other.is_a?(self.class)
|
|
11
|
+
value == other.value
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
alias_method :eql?, :==
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class CodeSnippet < Value
|
|
5
|
+
prop :raw, String, :positional, reader: :protected
|
|
6
|
+
|
|
7
|
+
prop :lang, Symbol, reader: :public, default: :plain do |value|
|
|
8
|
+
value.to_s.underscore.to_sym unless value.nil?
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
prop :location, _Nilable(SourceLocation), reader: :public do |value|
|
|
12
|
+
if value.is_a?(Array)
|
|
13
|
+
SourceLocation(*value)
|
|
14
|
+
elsif value.is_a?(String) || value.is_a?(Pathname)
|
|
15
|
+
SourceLocation(value)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def value
|
|
20
|
+
strip_indent(raw)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
alias_method :to_s, :value
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class MethodSnippet < CodeSnippet
|
|
5
|
+
prop :name, String, reader: :public
|
|
6
|
+
|
|
7
|
+
def body
|
|
8
|
+
extract_method_body(raw)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
alias_method :value, :body
|
|
12
|
+
alias_method :to_s, :body
|
|
13
|
+
|
|
14
|
+
protected def extract_method_body(source)
|
|
15
|
+
source = strip_indent(source)
|
|
16
|
+
output = source.sub(/^def \w+\s?(\([^)]+\))?/m, "").split("\n")[0..-2].join("\n")
|
|
17
|
+
strip_whitespace(output)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class NodeType < Value
|
|
5
|
+
prop :type, _Class(Booklet::Node), :positional, reader: :public do |value|
|
|
6
|
+
if value.is_a?(String) || value.is_a?(Symbol)
|
|
7
|
+
value = "#{value}_node" unless value.downcase == "node"
|
|
8
|
+
"Booklet::#{value.classify}".constantize
|
|
9
|
+
else
|
|
10
|
+
value
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def name
|
|
15
|
+
@type.name.to_s.demodulize.underscore.delete_suffix("_node")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
alias_method :value, :type
|
|
19
|
+
alias_method :to_s, :name
|
|
20
|
+
|
|
21
|
+
delegate :to_sym, to: :name
|
|
22
|
+
delegate :pluralize, to: :name
|
|
23
|
+
|
|
24
|
+
def enquirer
|
|
25
|
+
ActiveSupport::StringInquirer.new(name)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# def entity?
|
|
29
|
+
# @type < EntityNode
|
|
30
|
+
# end
|
|
31
|
+
|
|
32
|
+
def file?
|
|
33
|
+
@type < FileNode
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def method_missing(name, ...)
|
|
37
|
+
name.end_with?("?") ? enquirer.public_send(name) : super
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def respond_to_missing?(name, ...)
|
|
41
|
+
name.end_with?("?") || super
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def ==(other)
|
|
45
|
+
case other
|
|
46
|
+
when NodeType
|
|
47
|
+
type == other.type
|
|
48
|
+
when Class
|
|
49
|
+
type == other
|
|
50
|
+
else
|
|
51
|
+
name == other.to_s
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class SourceLocation < Value
|
|
5
|
+
prop :path, Pathname, :positional, reader: :public do |value|
|
|
6
|
+
Pathname(value.to_s) unless value.nil?
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
prop :line, _Nilable(Integer), :positional, reader: :public
|
|
10
|
+
|
|
11
|
+
def value
|
|
12
|
+
[path.to_s, line].join(":")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
alias_method :to_s, :value
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
class TextSnippet < Value
|
|
5
|
+
include Values
|
|
6
|
+
|
|
7
|
+
prop :raw, String, :positional, reader: :protected
|
|
8
|
+
|
|
9
|
+
prop :format, Symbol, reader: :public, default: :markdown do |value|
|
|
10
|
+
value.to_s.underscore.to_sym unless value.nil?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
prop :options, Hash, :**, reader: :protected
|
|
14
|
+
|
|
15
|
+
def value
|
|
16
|
+
strip_whitespace(raw)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
alias_method :to_s, :value
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Booklet
|
|
4
|
+
module Values
|
|
5
|
+
def NodeRef(...)
|
|
6
|
+
NodeRef.new(...)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def NodeName(...)
|
|
10
|
+
NodeName.new(...)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def NodeType(...)
|
|
14
|
+
NodeType.new(...)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def Snippet(...)
|
|
18
|
+
Snippet.new(...)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def MethodSnippet(...)
|
|
22
|
+
MethodSnippet.new(...)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def SourceLocation(...)
|
|
26
|
+
SourceLocation.new(...)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
extend self
|
|
30
|
+
end
|
|
31
|
+
end
|