markdown_exec 2.1.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -1
- data/CHANGELOG.md +23 -1
- data/Gemfile +3 -3
- data/Gemfile.lock +134 -92
- data/README.md +13 -13
- data/bin/tab_completion.sh +14 -3
- data/bin/tab_completion.sh.erb +0 -1
- data/examples/bash-blocks.md +58 -0
- data/examples/block-names.md +62 -0
- data/examples/indent.md +43 -2
- data/examples/link-blocks-block.md +5 -0
- data/examples/link-blocks-load-save.md +59 -0
- data/examples/link-blocks-vars.md +56 -0
- data/examples/linked.md +6 -101
- data/examples/opts-blocks-require.md +28 -0
- data/examples/{port.md → port-blocks.md} +18 -9
- data/examples/save.md +76 -4
- data/examples/vars-blocks.md +38 -0
- data/lib/colorize.rb +13 -0
- data/lib/constants.rb +1 -1
- data/lib/fcb.rb +202 -16
- data/lib/filter.rb +12 -12
- data/lib/hash_delegator.rb +695 -326
- data/lib/hierarchy_string.rb +133 -0
- data/lib/input_sequencer.rb +4 -2
- data/lib/link_history.rb +34 -1
- data/lib/markdown_exec/version.rb +1 -1
- data/lib/markdown_exec.rb +67 -79
- data/lib/mdoc.rb +122 -60
- data/lib/menu.src.yml +71 -21
- data/lib/menu.yml +59 -19
- data/lib/namer.rb +50 -0
- data/lib/poly.rb +152 -0
- data/lib/saved_assets.rb +4 -11
- data/lib/string_util.rb +0 -1
- data/lib/text_analyzer.rb +100 -0
- metadata +16 -6
- data/examples/vars.md +0 -20
- /data/examples/{opts.md → opts-blocks.md} +0 -0
- /data/examples/{pass-through.md → pass-through-arguments.md} +0 -0
data/lib/fcb.rb
CHANGED
@@ -2,21 +2,9 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# encoding=utf-8
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def pub_name
|
9
|
-
fetch(:nickname, nil) || fetch(:oname, nil)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
# require 'ostruct'
|
13
|
-
|
14
|
-
# class BlkS < OpenStruct
|
15
|
-
# # Method to fetch the value associated with the attribute :nickname or :oname
|
16
|
-
# def pub_name
|
17
|
-
# self.nickname || self.oname
|
18
|
-
# end
|
19
|
-
# end
|
5
|
+
require 'digest'
|
6
|
+
require_relative 'namer'
|
7
|
+
# require_relative 'poly'
|
20
8
|
|
21
9
|
module MarkdownExec
|
22
10
|
class Error < StandardError; end
|
@@ -106,7 +94,7 @@ module MarkdownExec
|
|
106
94
|
end
|
107
95
|
|
108
96
|
def to_h
|
109
|
-
@attrs
|
97
|
+
@attrs.to_h
|
110
98
|
end
|
111
99
|
|
112
100
|
def to_yaml
|
@@ -171,3 +159,201 @@ if $PROGRAM_NAME == __FILE__
|
|
171
159
|
# end
|
172
160
|
end
|
173
161
|
end
|
162
|
+
|
163
|
+
# #!/usr/bin/env ruby
|
164
|
+
# # frozen_string_literal: true
|
165
|
+
|
166
|
+
# # encoding=utf-8
|
167
|
+
# require 'digest'
|
168
|
+
# require_relative 'poly'
|
169
|
+
|
170
|
+
# # require 'ostruct'
|
171
|
+
|
172
|
+
# module MarkdownExec
|
173
|
+
# class Error < StandardError; end
|
174
|
+
|
175
|
+
# # Fenced Code Block (FCB)
|
176
|
+
# #
|
177
|
+
# # This class represents a fenced code block in a markdown document.
|
178
|
+
# # It allows for setting and getting attributes related to the code block,
|
179
|
+
# # such as body, call, headings, and more.
|
180
|
+
# #
|
181
|
+
# class FCB
|
182
|
+
# def initialize(options = {})
|
183
|
+
# # @attrs = ({
|
184
|
+
# @attrs = Poly.new({
|
185
|
+
# body: nil,
|
186
|
+
# call: nil,
|
187
|
+
# headings: [],
|
188
|
+
# dname: nil,
|
189
|
+
# indent: '',
|
190
|
+
# name: nil,
|
191
|
+
# nickname: nil,
|
192
|
+
# oname: nil,
|
193
|
+
# reqs: [],
|
194
|
+
# shell: '',
|
195
|
+
# title: '',
|
196
|
+
# random: Random.new.rand,
|
197
|
+
# text: nil # displayable in menu
|
198
|
+
# }.merge(options))
|
199
|
+
# end
|
200
|
+
|
201
|
+
# def is?(name)
|
202
|
+
# (save_name == name).tap{|ret|pp [__LINE__,"is?(#{name})",'->',ret]}
|
203
|
+
# end
|
204
|
+
|
205
|
+
# # fenced_name: text from code
|
206
|
+
# # save_name: for file system
|
207
|
+
# # logical_name: used for requires, not displayed
|
208
|
+
# # menu_name: displayed in menu
|
209
|
+
|
210
|
+
# # used for requires, not displayed
|
211
|
+
# def logical_name
|
212
|
+
# (@attrs.fetch(:nickname, nil) || @attrs.fetch(:oname, nil)).tap{|ret|pp [__LINE__,"logical_name()",'->',ret]}
|
213
|
+
# end
|
214
|
+
|
215
|
+
# # displayed in menu
|
216
|
+
# def menu_name # displayed in menu
|
217
|
+
# @attrs.fetch(:nickname, nil).tap{|ret|pp [__LINE__,"menu_name()",'->',ret]}
|
218
|
+
# end
|
219
|
+
|
220
|
+
# # for file system
|
221
|
+
# # block name in commands and documents
|
222
|
+
# def save_name(id_len: 4, max_len: 48)
|
223
|
+
# full = @attrs.fetch(:nickname, nil) || @attrs.fetch(:oname, nil)
|
224
|
+
# trimmed = if full && full[max_len]
|
225
|
+
# r = rand((10**(id_len - 1) + 1)..10**id_len).to_s
|
226
|
+
# dig = Digest::MD5.hexdigest(full)[0, id_len]
|
227
|
+
# full[0..max_len - id_len] + dig
|
228
|
+
# else
|
229
|
+
# full
|
230
|
+
# end
|
231
|
+
|
232
|
+
# trimmed&.to_blockname.tap{|ret|pp [__LINE__,"save_name()",'->',ret]}
|
233
|
+
# end
|
234
|
+
|
235
|
+
# def title=(value)
|
236
|
+
# @attrs[:title] = value
|
237
|
+
# end
|
238
|
+
|
239
|
+
# # Derives a title from the body of an FCB object.
|
240
|
+
# # @param fcb [Object] The FCB object whose title is to be derived.
|
241
|
+
# # @return [String] The derived title.
|
242
|
+
# def derive_title_from_body
|
243
|
+
# unless (body_content = @attrs[:body])
|
244
|
+
# # empty body -> empty title
|
245
|
+
# @attrs[:title] = ''
|
246
|
+
# return
|
247
|
+
# end
|
248
|
+
|
249
|
+
# # body -> title
|
250
|
+
# @attrs[:title] = if body_content.count == 1
|
251
|
+
# body_content.first
|
252
|
+
# else
|
253
|
+
# format_multiline_body_as_title(body_content)
|
254
|
+
# end
|
255
|
+
# end
|
256
|
+
|
257
|
+
# private
|
258
|
+
|
259
|
+
# # Formats multiline body content as a title string.
|
260
|
+
# # indents all but first line with two spaces so it displays correctly in menu
|
261
|
+
# # @param body_lines [Array<String>] The lines of body content.
|
262
|
+
# # @return [String] Formatted title.
|
263
|
+
# def format_multiline_body_as_title(body_lines)
|
264
|
+
# body_lines.map.with_index do |line, index|
|
265
|
+
# index.zero? ? line : " #{line}"
|
266
|
+
# end.join("\n") << "\n"
|
267
|
+
# end
|
268
|
+
|
269
|
+
# # :reek:ManualDispatch
|
270
|
+
# def method_missing(method, *args, &block)
|
271
|
+
# method_name = method.to_s
|
272
|
+
# if @attrs.respond_to?(method_name)
|
273
|
+
# @attrs.send(method_name, *args, &block)
|
274
|
+
# elsif method_name[-1] == '='
|
275
|
+
# @attrs[method_name.chop.to_sym] = args[0]
|
276
|
+
# else
|
277
|
+
# @attrs[method_name.to_sym]
|
278
|
+
# end
|
279
|
+
# rescue StandardError => err
|
280
|
+
# warn("ERROR ** FCB.method_missing(method: #{method_name}," \
|
281
|
+
# " *args: #{args.inspect}, &block)")
|
282
|
+
# warn err.inspect
|
283
|
+
# warn(caller[0..4])
|
284
|
+
# # raise StandardError, error
|
285
|
+
# raise err # Here, we simply propagate the original error instead of wrapping it in a StandardError.
|
286
|
+
# end
|
287
|
+
|
288
|
+
# public
|
289
|
+
|
290
|
+
# def respond_to_missing?(method_name, include_private = false)
|
291
|
+
# @attrs.key?(method_name.to_sym) || super
|
292
|
+
# end
|
293
|
+
|
294
|
+
# def to_h
|
295
|
+
# @attrs.to_h
|
296
|
+
# end
|
297
|
+
|
298
|
+
# def to_yaml
|
299
|
+
# @attrs.to_yaml
|
300
|
+
# end
|
301
|
+
# end
|
302
|
+
# end
|
303
|
+
|
304
|
+
# if $PROGRAM_NAME == __FILE__
|
305
|
+
# require 'bundler/setup'
|
306
|
+
# Bundler.require(:default)
|
307
|
+
|
308
|
+
# require 'minitest/autorun'
|
309
|
+
# require 'yaml'
|
310
|
+
|
311
|
+
# class FCBTest < Minitest::Test
|
312
|
+
# def setup
|
313
|
+
# @fcb_data = {
|
314
|
+
# body: 'Sample body',
|
315
|
+
# call: 'Sample call',
|
316
|
+
# headings: %w[Header1 Header2],
|
317
|
+
# dname: 'Sample name',
|
318
|
+
# indent: '',
|
319
|
+
# nickname: nil,
|
320
|
+
# name: 'Sample name',
|
321
|
+
# oname: 'Sample name',
|
322
|
+
# reqs: %w[req1 req2],
|
323
|
+
# shell: 'bash',
|
324
|
+
# text: 'Sample Text',
|
325
|
+
# title: 'Sample Title'
|
326
|
+
# }
|
327
|
+
# @fcb = MarkdownExec::FCB.new(@fcb_data)
|
328
|
+
# end
|
329
|
+
|
330
|
+
# def test_initialization_with_correct_data
|
331
|
+
# assert_equal 'Sample body', @fcb.body
|
332
|
+
# assert_equal %w[Header1 Header2], @fcb.headings
|
333
|
+
# end
|
334
|
+
|
335
|
+
# def test_to_h_method
|
336
|
+
# assert_equal @fcb_data.merge({ random: @fcb.random }), @fcb.to_h
|
337
|
+
# end
|
338
|
+
|
339
|
+
# def test_to_yaml_method
|
340
|
+
# assert_equal YAML.load(@fcb_data.merge({ random: @fcb.random }).to_yaml),
|
341
|
+
# YAML.load(@fcb.to_yaml)
|
342
|
+
# end
|
343
|
+
|
344
|
+
# def test_method_missing_getter
|
345
|
+
# assert_equal 'Sample Title', @fcb.title
|
346
|
+
# end
|
347
|
+
|
348
|
+
# def test_method_missing_setter
|
349
|
+
# @fcb.title = 'New Title'
|
350
|
+
# assert_equal 'New Title', @fcb.title
|
351
|
+
# end
|
352
|
+
|
353
|
+
# # 2023-10-09 does not trigger error; treats as option name
|
354
|
+
# #
|
355
|
+
# # def test_method_missing_with_unknown_method
|
356
|
+
# # assert_raises(NoMethodError) { @fcb.unknown_method }
|
357
|
+
# # end
|
358
|
+
# end
|
359
|
+
# end
|
data/lib/filter.rb
CHANGED
@@ -36,7 +36,7 @@ module MarkdownExec
|
|
36
36
|
}
|
37
37
|
|
38
38
|
name = fcb.oname
|
39
|
-
shell = fcb.
|
39
|
+
shell = fcb.shell
|
40
40
|
|
41
41
|
apply_name_filters(options, filters, name)
|
42
42
|
apply_shell_filters(options, filters, shell)
|
@@ -109,7 +109,7 @@ module MarkdownExec
|
|
109
109
|
#
|
110
110
|
def self.apply_other_filters(options, filters, fcb)
|
111
111
|
name = fcb.oname
|
112
|
-
shell = fcb.
|
112
|
+
shell = fcb.shell
|
113
113
|
filters[:fcb_chrome] = fcb.fetch(:chrome, false)
|
114
114
|
|
115
115
|
if name.present? && options[:hide_blocks_by_name]
|
@@ -168,10 +168,10 @@ module MarkdownExec
|
|
168
168
|
# @param match_patterns [Array<String>] Array of regular expression patterns for matching
|
169
169
|
# @return [Boolean] True if the block should not be in the menu, false otherwise
|
170
170
|
def self.prepared_not_in_menu?(options, fcb, match_patterns)
|
171
|
-
return false unless fcb
|
171
|
+
return false unless fcb.shell == BlockType::BASH
|
172
172
|
|
173
173
|
match_patterns.any? do |pattern|
|
174
|
-
options[pattern].present? && fcb
|
174
|
+
options[pattern].present? && fcb.oname =~ /#{options[pattern]}/
|
175
175
|
end
|
176
176
|
end
|
177
177
|
|
@@ -217,52 +217,52 @@ if $PROGRAM_NAME == __FILE__
|
|
217
217
|
|
218
218
|
def test_exclude_expect_blocks_condition
|
219
219
|
@options[:exclude_expect_blocks] = true
|
220
|
-
@fcb
|
220
|
+
@fcb.shell = 'expect'
|
221
221
|
refute Filter.fcb_select?(@options, @fcb)
|
222
222
|
end
|
223
223
|
|
224
224
|
def test_hidden_name_condition
|
225
225
|
@options[:hide_blocks_by_name] = true
|
226
226
|
@options[:block_name_hidden_match] = 'hidden'
|
227
|
-
@fcb
|
227
|
+
@fcb.oname = 'hidden_block'
|
228
228
|
refute Filter.fcb_select?(@options, @fcb)
|
229
229
|
end
|
230
230
|
|
231
231
|
def test_include_name_condition
|
232
232
|
@options[:hide_blocks_by_name] = true
|
233
233
|
@options[:block_name_indlude_match] = 'include'
|
234
|
-
@fcb
|
234
|
+
@fcb.oname = 'include_block'
|
235
235
|
assert Filter.fcb_select?(@options, @fcb)
|
236
236
|
end
|
237
237
|
|
238
238
|
def test_wrap_name_condition
|
239
239
|
@options[:hide_blocks_by_name] = true
|
240
240
|
@options[:block_name_wrapper_match] = 'wrap'
|
241
|
-
@fcb
|
241
|
+
@fcb.oname = 'wrap_block'
|
242
242
|
assert Filter.fcb_select?(@options, @fcb)
|
243
243
|
end
|
244
244
|
|
245
245
|
def test_shell_exclude_condition
|
246
246
|
@options[:exclude_by_shell_regex] = 'exclude_this'
|
247
|
-
@fcb
|
247
|
+
@fcb.shell = 'exclude_this_shell'
|
248
248
|
refute Filter.fcb_select?(@options, @fcb)
|
249
249
|
end
|
250
250
|
|
251
251
|
def test_name_select_condition
|
252
252
|
@options[:select_by_name_regex] = 'select'
|
253
|
-
@fcb
|
253
|
+
@fcb.oname = 'select_this'
|
254
254
|
assert Filter.fcb_select?(@options, @fcb)
|
255
255
|
end
|
256
256
|
|
257
257
|
def test_shell_select_condition
|
258
258
|
@options[:select_by_shell_regex] = 'select_this'
|
259
|
-
@fcb
|
259
|
+
@fcb.shell = 'select_this_shell'
|
260
260
|
assert Filter.fcb_select?(@options, @fcb)
|
261
261
|
end
|
262
262
|
|
263
263
|
def test_bash_only_condition_true
|
264
264
|
@options[:bash_only] = true
|
265
|
-
@fcb
|
265
|
+
@fcb.shell = BlockType::BASH
|
266
266
|
assert Filter.fcb_select?(@options, @fcb)
|
267
267
|
end
|
268
268
|
|