markdown_exec 0.0.1 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 631d15d315eeb3a40ef3458f9b0577d4b2f5f9eeddbcdd3ad26c9d2cb1e28c3a
4
- data.tar.gz: f1fdebc4461fb7b5f3b37ebd2f8d369cbe804621cc42ca8c672baec5ea0c4f74
3
+ metadata.gz: 8c89f954d1fc114cb22e9222ebc2c7d0575848d597899e1385edbf7b5963f08b
4
+ data.tar.gz: f14d0e24a3c348c303e96014b68a477d560ed1c3c707ac486173ffe19513df1d
5
5
  SHA512:
6
- metadata.gz: f597613ff0bd0c556e0c205168d32653b4a4cd71cd93c24549b0b9f3f18dd8551ca301ac618f191fa005dfdbfaceef6263e4fe18cb229244c20c989b8fb99ac4
7
- data.tar.gz: c890e7187a1394e37f56a81e7f3a2a64dbd3ec0fe8f6d9b904089b9d7b3d10a89c7df476aac2ff3bc437c50137d89f28bea8f4711995f2b1ed8f660785dd76ae
6
+ metadata.gz: b78cd2cfbef3c47acd318c173fa953891f83c29ea2ac59b062dafc2e2ce8573c4f862f2e681cacb6ebd827dc77b10b984dd8a33a1349849357e9c64ab564932d
7
+ data.tar.gz: 8f8282f7a5a171dee4c83f9fce9974f48b7ee55b43d25651bfebaec0f46b97028c1ed58bd23ea85a796f949cd1eeae923d6899a5efb448879de96aa37287915d
data/.rubocop.yml CHANGED
@@ -1,6 +1,36 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 2.6
3
3
 
4
+ Metrics/AbcSize:
5
+ Enabled: false
6
+
7
+ Metrics/BlockLength:
8
+ Enabled: false
9
+
10
+ Metrics/BlockNesting:
11
+ Enabled: false
12
+
13
+ Metrics/ClassLength:
14
+ Enabled: false
15
+
16
+ Metrics/CyclomaticComplexity:
17
+ Enabled: false
18
+
19
+ # Metrics/LayoutLength:
20
+ # Enabled: false
21
+
22
+ Metrics/MethodLength:
23
+ Enabled: false
24
+
25
+ Metrics/PerceivedComplexity:
26
+ Enabled: false
27
+
28
+ Style/GlobalVars:
29
+ Enabled: false
30
+
31
+ Style/MultilineBlockChain:
32
+ Enabled: false
33
+
4
34
  Style/StringLiterals:
5
35
  Enabled: true
6
36
  EnforcedStyle: single_quotes
data/Gemfile CHANGED
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "https://rubygems.org"
3
+ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in markdown_exec.gemspec
6
6
  gemspec
7
7
 
8
- gem "rake", "~> 13.0"
8
+ gem 'rake', '~> 13.0'
9
9
 
10
- gem "minitest", "~> 5.0"
10
+ gem 'minitest', '~> 5.0'
11
11
 
12
- gem "rubocop", "~> 1.21"
12
+ gem 'rubocop', '~> 1.21'
data/Gemfile.lock ADDED
@@ -0,0 +1,56 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ markdown_exec (0.0.3)
5
+ tty-prompt (~> 0.23.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ ast (2.4.2)
11
+ minitest (5.15.0)
12
+ parallel (1.21.0)
13
+ parser (3.1.1.0)
14
+ ast (~> 2.4.1)
15
+ pastel (0.8.0)
16
+ tty-color (~> 0.5)
17
+ rainbow (3.1.1)
18
+ rake (13.0.6)
19
+ regexp_parser (2.2.1)
20
+ rexml (3.2.5)
21
+ rubocop (1.26.0)
22
+ parallel (~> 1.10)
23
+ parser (>= 3.1.0.0)
24
+ rainbow (>= 2.2.2, < 4.0)
25
+ regexp_parser (>= 1.8, < 3.0)
26
+ rexml
27
+ rubocop-ast (>= 1.16.0, < 2.0)
28
+ ruby-progressbar (~> 1.7)
29
+ unicode-display_width (>= 1.4.0, < 3.0)
30
+ rubocop-ast (1.16.0)
31
+ parser (>= 3.1.1.0)
32
+ ruby-progressbar (1.11.0)
33
+ tty-color (0.6.0)
34
+ tty-cursor (0.7.1)
35
+ tty-prompt (0.23.1)
36
+ pastel (~> 0.8)
37
+ tty-reader (~> 0.8)
38
+ tty-reader (0.9.0)
39
+ tty-cursor (~> 0.7)
40
+ tty-screen (~> 0.8)
41
+ wisper (~> 2.0)
42
+ tty-screen (0.8.1)
43
+ unicode-display_width (2.1.0)
44
+ wisper (2.0.1)
45
+
46
+ PLATFORMS
47
+ arm64-darwin-21
48
+
49
+ DEPENDENCIES
50
+ markdown_exec!
51
+ minitest (~> 5.0)
52
+ rake (~> 13.0)
53
+ rubocop (~> 1.21)
54
+
55
+ BUNDLED WITH
56
+ 2.2.32
data/Rakefile CHANGED
@@ -1,37 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rake/testtask"
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
5
 
6
6
  Rake::TestTask.new(:test) do |t|
7
- t.libs << "test"
8
- t.libs << "lib"
9
- t.test_files = FileList["test/**/*_test.rb"]
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
10
  end
11
11
 
12
- require "rubocop/rake_task"
12
+ require 'rubocop/rake_task'
13
13
 
14
14
  RuboCop::RakeTask.new
15
15
 
16
16
  task default: %i[test rubocop]
17
17
 
18
- GEM_NAME = "pagekey"
19
- GEM_VERSION = "0.0.0"
18
+ GEM_NAME = 'markdown_exec'
19
+ GEM_VERSION = '0.0.6'
20
20
 
21
21
  # task :default => :build
22
22
 
23
23
  task :build do
24
- system "gem build " + GEM_NAME + ".gemspec"
24
+ system "gem build #{GEM_NAME}.gemspec"
25
25
  end
26
26
 
27
- task :install => :build do
28
- system "gem install " + GEM_NAME + "-" + GEM_VERSION + ".gem"
27
+ task install: :build do
28
+ system "gem install #{GEM_NAME}-#{GEM_VERSION}.gem"
29
29
  end
30
30
 
31
- task :publish => :build do
32
- system 'gem push ' + GEM_NAME + "-" + GEM_VERSION + ".gem"
31
+ task publish: :build do
32
+ system "gem push #{GEM_NAME}-#{GEM_VERSION}.gem"
33
+ end
34
+
35
+ task uninstall: :build do
36
+ system "gem uninstall #{GEM_NAME}"
33
37
  end
34
38
 
35
39
  task :clean do
36
- system "rm *.gem"
40
+ system 'rm *.gem'
37
41
  end
data/bin/console CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "bundler/setup"
5
- require "markdown_exec"
4
+ require 'bundler/setup'
5
+ require 'markdown_exec'
6
6
 
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
@@ -11,5 +11,5 @@ require "markdown_exec"
11
11
  # require "pry"
12
12
  # Pry.start
13
13
 
14
- require "irb"
14
+ require 'irb'
15
15
  IRB.start(__FILE__)
data/bin/mde CHANGED
@@ -3,519 +3,8 @@
3
3
 
4
4
  # encoding=utf-8
5
5
 
6
- env_debug = ENV["MARKDOWN_EXEC_DEBUG"]
7
- $pdebug = !(env_debug || "").empty?
6
+ require 'markdown_exec'
8
7
 
9
- APP_NAME = "MDExec"
10
- APP_DESC = "Markdown block executor"
11
- VERSION = "0.0.2"
12
-
13
- require "markdown_exec"
14
- # puts MarkdownExec::MDExec.echo(ARGV[0])
15
-
16
- require "optparse"
17
- require "pathname"
18
- require "tty-prompt"
19
- require "yaml"
20
-
21
- # require_relative 'mdlib'
22
- # #!/usr/bin/env ruby
23
- # # frozen_string_literal: true
24
- # # encoding=utf-8
25
-
26
- # env_debug = ENV['MARKDOWN_EXEC_DEBUG']
27
- # $pdebug = !(env_debug || '').empty?
28
-
29
- require "open3"
30
- require "tty-prompt"
31
- # require 'yaml'
32
- # require_relative 'deep_merge'
33
- # require_relative 'object_odig'
34
- # require_relative 'present'
35
-
36
- BLOCK_SIZE = 1024
37
- SELECT_PAGE_HEIGHT = 12
38
-
39
- ##
40
- #
41
- class MarkParse
42
- attr_accessor :options
43
-
44
- def initialize(options)
45
- @options = options
46
- end
47
-
48
- def count_blocks
49
- cnt = 0
50
- File.readlines(options[:mdfilename]).each do |line|
51
- cnt += 1 if line.match(/^```/)
52
- end
53
- cnt / 2
54
- end
55
-
56
- def find_files
57
- puts "pwd: #{`pwd`}" if $pdebug
58
- # `ls -1 *.md`.split("\n").tap { |ret| puts "find_files() ret: #{ret.inspect}" if $pdebug }
59
- `ls -1 #{File.join options[:mdfolder], "*.md"}`.split("\n").tap do |ret|
60
- puts "find_files() ret: #{ret.inspect}" if $pdebug
61
- end
62
- end
63
-
64
- def fout(str)
65
- puts str # to stdout
66
- end
67
-
68
- def copts(call_options = {}, options_block = nil)
69
- class_call_options = options.merge(call_options || {})
70
- if options_block
71
- options_block.call class_call_options
72
- else
73
- class_call_options
74
- end.tap { |ret| puts "copts() ret: #{ret.inspect}" if $pdebug }
75
- end
76
-
77
- def bsr(headings, title)
78
- # puts "bsr() headings: #{headings.inspect}"
79
- { headings: headings, name: title, title: title }
80
- end
81
-
82
- def block_summary(opts, headings, block_title, current)
83
- puts "block_summary() block_title: #{block_title.inspect}" if $pdebug
84
- return [current] unless opts[:struct]
85
-
86
- # return [{ body: current, name: block_title, title: block_title }] unless opts[:bash]
87
- return [bsr(headings, block_title).merge({ body: current })] unless opts[:bash]
88
-
89
- bm = block_title.match(/:(\S+)( |$)/)
90
- reqs = block_title.scan(/\+\S+/).map { |s| s[1..] }
91
-
92
- if $pdebug
93
- puts ["block_summary() bm: #{bm.inspect}",
94
- "block_summary() reqs: #{reqs.inspect}"]
95
- end
96
-
97
- if bm && bm[1]
98
- # [{ body: current, name: bm[1], reqs: reqs, title: bm[1] }]
99
- [bsr(headings, bm[1]).merge({ body: current, reqs: reqs })]
100
- else
101
- # [{ body: current, name: block_title, reqs: reqs, title: block_title }]
102
- [bsr(headings, block_title).merge({ body: current, reqs: reqs })]
103
- end
104
- end
105
-
106
- def get_blocks(call_options = {}, &options_block)
107
- opts = copts call_options, options_block
108
-
109
- blocks = []
110
- current = nil
111
- in_block = false
112
- block_title = ""
113
-
114
- headings = []
115
- File.readlines(opts[:mdfilename]).each do |line|
116
- puts "get_blocks() line: #{line.inspect}" if $pdebug
117
- continue unless line
118
-
119
- if opts[:mdheadings]
120
- if lm = line.match(/^### *(.+?) *$/)
121
- headings = [headings[0], headings[1], lm[1]]
122
- elsif lm = line.match(/^## *([^#]*?) *$/)
123
- headings = [headings[0], lm[1]]
124
- elsif lm = line.match(/^# *([^#]*?) *$/)
125
- headings = [lm[1]]
126
- end
127
- puts "get_blocks() headings: #{headings.inspect}" if $pdebug
128
- end
129
-
130
- if line.match(/^`{3,}/)
131
- if in_block
132
- puts "get_blocks() in_block" if $pdebug
133
- if current
134
-
135
- # block_title ||= current.join(' ').gsub(/ +/, ' ')[0..64]
136
- block_title = current.join(" ").gsub(/ +/, " ")[0..64] if block_title.nil? || block_title.empty?
137
-
138
- blocks += block_summary opts, headings, block_title, current
139
- current = nil
140
- end
141
- in_block = false
142
- block_title = ""
143
- else
144
- ## new block
145
- #
146
-
147
- # lm = line.match(/^`{3,}([^`\s]+)( .+)?$/)
148
- lm = line.match(/^`{3,}([^`\s]*) *(.*)$/)
149
-
150
- do1 = false
151
- if opts[:bash_only]
152
- do1 = true if lm && (lm[1] == "bash")
153
- elsif opts[:exclude_expect_blocks]
154
- do1 = true unless lm && (lm[1] == "expect")
155
- else
156
- do1 = true
157
- end
158
- if $pdebug
159
- puts ["get_blocks() lm: #{lm.inspect}",
160
- "get_blocks() opts: #{opts.inspect}",
161
- "get_blocks() do1: #{do1}"]
162
- end
163
-
164
- if do1 && (!opts[:title_match] || (lm && lm[2] && lm[2].match(opts[:title_match])))
165
- current = []
166
- in_block = true
167
- block_title = (lm && lm[2])
168
- end
169
-
170
- end
171
- elsif current
172
- current += [line.chomp]
173
- end
174
- end
175
- blocks.tap { |ret| puts "get_blocks() ret: #{ret.inspect}" if $pdebug }
176
- end
177
-
178
- def make_block_label(block, call_options = {})
179
- opts = options.merge(call_options)
180
- puts "make_block_label() opts: #{opts.inspect}" if $pdebug
181
- puts "make_block_label() block: #{block.inspect}" if $pdebug
182
- if opts[:mdheadings]
183
- heads = block.fetch(:headings, []).compact.join(" # ")
184
- "#{block[:title]} [#{heads}] (#{opts[:mdfilename]})"
185
- else
186
- "#{block[:title]} (#{opts[:mdfilename]})"
187
- end
188
- end
189
-
190
- def make_block_labels(call_options = {})
191
- opts = options.merge(call_options)
192
- get_blocks(opts).map do |block|
193
- make_block_label block, opts
194
- end
195
- end
196
-
197
- def select_block(call_options = {}, &options_block)
198
- opts = copts call_options, options_block
199
-
200
- blocks = get_blocks(opts.merge(struct: true))
201
- puts "select_block() blocks: #{blocks.to_yaml}" if $pdebug
202
-
203
- prompt = TTY::Prompt.new(interrupt: :exit)
204
- pt = "#{opts.fetch(:prompt, nil) || "Pick one"}:"
205
- puts "select_block() pt: #{pt.inspect}" if $pdebug
206
-
207
- blocks.each { |block| block.merge! label: make_block_label(block, opts) }
208
- block_labels = blocks.map { |block| block[:label] }
209
- puts "select_block() block_labels: #{block_labels.inspect}" if $pdebug
210
-
211
- if opts[:preview_options]
212
- select_per_page = 3
213
- block_labels.each do |bn|
214
- fout " - #{bn}"
215
- end
216
- else
217
- select_per_page = SELECT_PAGE_HEIGHT
218
- end
219
-
220
- return nil if block_labels.count.zero?
221
-
222
- sel = prompt.select(pt, block_labels, per_page: select_per_page)
223
- puts "select_block() sel: #{sel.inspect}" if $pdebug
224
- # catch
225
- # # catch TTY::Reader::InputInterrupt
226
- # puts "InputInterrupt"
227
- # end
228
-
229
- block = blocks.select { |block| block[:label] == sel }.fetch(0, nil)
230
- puts "select_block() block: #{block.inspect}" if $pdebug
231
- sel = block[:name]
232
- puts "select_block() sel: #{sel.inspect}" if $pdebug
233
-
234
- cbs = code_blocks(blocks, sel)
235
- puts "select_block() cbs: #{cbs.inspect}" if $pdebug
236
-
237
- ## display code blocks for approval
238
- #
239
- cbs.each { |cb| fout cb } if opts[:display] || opts[:approve]
240
-
241
- allow = true
242
- allow = prompt.yes? "Process?" if opts[:approve]
243
-
244
- selected = table_block blocks, sel
245
- puts "select_block() selected: #{selected.inspect}" if $pdebug
246
- if allow && opts[:execute]
247
-
248
- ## process in script, to handle line continuations
249
- #
250
- cmd2 = cbs.flatten.join("\n")
251
- fout "$ #{cmd2.to_yaml}"
252
- cnt = 0
253
-
254
- # Open3.popen3(cmd2) do |stdin, stdout, stderr, wait_thr|
255
- # cnt += 1
256
- # # stdin.puts "This is sent to the command"
257
- # # stdin.close # we're done
258
- # stdout_str = stdout.read # read stdout to string. note that this will block until the command is done!
259
- # stderr_str = stderr.read # read stderr to string
260
- # status = wait_thr.value # will block until the command finishes; returns status that responds to .success? etc
261
- # fout "#{stdout_str}"
262
- # fout "#{cnt}: err: #{stderr_str}" if stderr_str != ''
263
- # # fout "#{cnt}: stt: #{status}"
264
- # end
265
-
266
- Open3.popen3(cmd2) do |stdin, stdout, stderr|
267
- stdin.close_write
268
- begin
269
- files = [stdout, stderr]
270
-
271
- until all_eof(files)
272
- ready = IO.select(files)
273
-
274
- next unless ready
275
-
276
- readable = ready[0]
277
- # writable = ready[1]
278
- # exceptions = ready[2]
279
-
280
- readable.each do |f|
281
- fileno = f.fileno
282
-
283
- begin
284
- data = f.read_nonblock(BLOCK_SIZE)
285
- # fout "- fileno: #{fileno}\n#{data}"
286
- fout data
287
- rescue EOFError => e
288
- # fout "fileno: #{fileno} EOF"
289
- end
290
- end
291
- end
292
- rescue IOError => e
293
- fout "IOError: #{e}"
294
- end
295
- end
296
- end
297
-
298
- selected[:name]
299
- end
300
-
301
- def select_md_file
302
- opts = options
303
- files = find_files
304
- if files.count == 1
305
- sel = files[0]
306
- elsif files.count >= 2
307
-
308
- if opts[:preview_options]
309
- select_per_page = 3
310
- files.each do |file|
311
- fout " - #{file}"
312
- end
313
- else
314
- select_per_page = SELECT_PAGE_HEIGHT
315
- end
316
-
317
- prompt = TTY::Prompt.new
318
- sel = prompt.select("#{opts.fetch(:prompt, "Pick one")}:", files, per_page: select_per_page)
319
- end
320
-
321
- sel
322
- end
323
-
324
- # Returns true if all files are EOF
325
- #
326
- def all_eof(files)
327
- files.find { |f| !f.eof }.nil?
328
- end
329
-
330
- def code(table, block)
331
- puts "code() table: #{table.inspect}" if $pdebug
332
- puts "code() block: #{block.inspect}" if $pdebug
333
- all = [block[:name]] + unroll(table, block[:reqs])
334
- puts "code() all: #{all.inspect}" if $pdebug
335
- all.reverse.map do |req|
336
- puts "code() req: #{req.inspect}" if $pdebug
337
- table_block(table, req).fetch(:body, "")
338
- end.flatten(1).tap { |ret| puts "code() ret: #{ret.inspect}" if $pdebug }
339
- end
340
-
341
- def table_block(table, name, default = {})
342
- table.select { |block| block[:name] == name }.fetch(0, default)
343
- end
344
-
345
- def code_blocks(table, name)
346
- puts "code_blocks() table: #{table.inspect}" if $pdebug
347
- puts "code_blocks() name: #{name.inspect}" if $pdebug
348
- block = table_block(table, name)
349
- puts "code_blocks() block: #{block.inspect}" if $pdebug
350
- all = [block[:name]] + unroll(table, block[:reqs])
351
- puts "code_blocks() all: #{all.inspect}" if $pdebug
352
- all.reverse.map do |req|
353
- puts "code_blocks() req: #{req.inspect}" if $pdebug
354
- table_block(table, req).fetch(:body, "")
355
- end.flatten(1).tap { |ret| puts "code_blocks() ret: #{ret.inspect}" if $pdebug }
356
- end
357
-
358
- def unroll(table, reqs)
359
- puts "unroll() table: #{table.inspect}" if $pdebug
360
- puts "unroll() reqs: #{reqs.inspect}" if $pdebug
361
- all = []
362
- rem = reqs
363
- while rem.count.positive?
364
- puts "unrol() rem: #{rem.inspect}" if $pdebug
365
- rem = rem.map do |req|
366
- puts "unrol() req: #{req.inspect}" if $pdebug
367
- next if all.include? req
368
-
369
- all += [req]
370
- puts "unrol() all: #{all.inspect}" if $pdebug
371
- table_block(table, req).fetch(:reqs, [])
372
- end.compact.flatten(1).tap { |_ret| puts "unroll() rem: #{rem.inspect}" if $pdebug }
373
- end
374
- all.tap { |ret| puts "unroll() ret: #{ret.inspect}" if $pdebug }
375
- end
376
- end
377
-
378
- $stderr.sync = true
379
- $stdout.sync = true
380
-
381
- def fout(str)
382
- puts str # to stdout
383
- end
384
-
385
- ## configuration file
386
- #
387
- def read_configuration!(options, configuration_path)
388
- if Pathname.new(configuration_path).exist?
389
- # rubocop:disable Security/YAMLLoad
390
- options.merge!((YAML::load(open(configuration_path)) || {})
391
- .transform_keys(&:to_sym))
392
- # rubocop:enable Security/YAMLLoad
393
- end
394
- options
395
- end
396
-
397
- ## default configuration
398
- #
399
- options = {
400
- mdheadings: true,
401
- list_blocks: false,
402
- list_docs: false,
403
- mdfilename: "README.md",
404
- mdfolder: "."
405
- }
406
-
407
- def options_finalize!(options); end
408
-
409
- # read local configuration file
410
- #
411
- read_configuration! options, ".#{APP_NAME.downcase}.yml"
412
-
413
- ## read current details for aws resources from app_data_file
414
- #
415
- # load_resources! options
416
- # puts "q31 options: #{options.to_yaml}" if $pdebug
417
-
418
- option_parser = OptionParser.new do |opts|
419
- executable_name = File.basename($PROGRAM_NAME)
420
- opts.banner = [
421
- APP_VDESC = "#{APP_NAME} - #{APP_DESC} (#{VERSION})",
422
- "Usage: #{executable_name} [options]"
423
- ].join("\n")
424
-
425
- ## menu top: on_head appear in reverse order added
426
- #
427
- opts.on("--config PATH", "Read configuration file") do |value|
428
- read_configuration! options, value
429
- end
430
-
431
- ## menu body: items appear in order added
432
- #
433
- opts.on("-f RELATIVE", "--mdfilename", "Name of document") do |value|
434
- options[:mdfilename] = value
435
- end
436
-
437
- opts.on("-p PATH", "--mdfolder", "Path to documents") do |value|
438
- options[:mdfolder] = value
439
- end
440
-
441
- opts.on("--list-blocks", "List blocks") do |_value|
442
- options[:list_blocks] = true
443
- end
444
-
445
- opts.on("--list-docs", "List docs in current folder") do |_value|
446
- options[:list_docs] = true
447
- end
448
-
449
- ## menu bottom: items appear in order added
450
- #
451
- opts.on_tail("-h", "--help", "App help") do |_value|
452
- puts option_parser.help
453
- exit
454
- end
455
-
456
- opts.on_tail("-v", "--version", "App version") do |_value|
457
- puts VERSION
458
- exit
459
- end
460
-
461
- opts.on_tail("-x", "--exit", "Exit app") do |_value|
462
- exit
463
- end
464
-
465
- opts.on_tail("-0", "Show configuration") do |_v|
466
- options_finalize! options
467
- puts options.to_yaml
468
- end
469
- end
470
-
471
- option_parser.load # filename defaults to basename of the program without suffix in a directory ~/.options
472
- option_parser.environment # env defaults to the basename of the program.
473
- option_parser.parse! # (into: options)
474
- options_finalize! options
475
-
476
- ## process
477
- #
478
- loop do # once
479
- mp = MarkParse.new options
480
- options.merge!(
481
- {
482
- approve: true,
483
- bash: true,
484
- display: true,
485
- execute: true,
486
- prompt: "Execute",
487
- struct: true
488
- }
489
- )
490
-
491
- ## show
492
- #
493
- if options[:list_docs]
494
- fout mp.find_files
495
- break
496
- end
497
-
498
- if options[:list_blocks]
499
- fout (mp.find_files.map do |file|
500
- mp.make_block_labels(mdfilename: file, struct: true)
501
- end).flatten(1).to_yaml
502
- break
503
- end
504
-
505
- ## process
506
- #
507
- mp.select_block(bash: true, struct: true) if options[:mdfilename]
508
-
509
- =begin
510
- # rescue ArgumentError => e
511
- # puts "User abort: #{e}"
512
-
513
- # rescue StandardError => e
514
- # puts "ERROR: #{e}"
515
- # raise StandardError, e
516
-
517
- # ensure
518
- # exit
519
- =end
520
- break unless false
521
- end
8
+ mp = MarkdownExec::MarkParse.new
9
+ mp.fout Time.now
10
+ # mp.run
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MarkdownExec
4
- VERSION = "0.0.1"
4
+ VERSION = '0.0.6'
5
5
  end
data/lib/markdown_exec.rb CHANGED
@@ -1,14 +1,536 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "markdown_exec/version"
3
+ require_relative 'markdown_exec/version'
4
+
5
+ #!/usr/bin/env ruby
6
+ # frozen_string_literal: true
7
+
8
+ # encoding=utf-8
9
+ # rubocop:disable Style/GlobalVars
10
+
11
+ env_debug = ENV['MARKDOWN_EXEC_DEBUG']
12
+ $pdebug = !(env_debug || '').empty?
13
+
14
+ # APP_NAME = 'MDExec'
15
+ # APP_DESC = 'Markdown block executor'
16
+ # VERSION = '0.0.6'
17
+
18
+ # require 'markdown_exec'
19
+ # # puts MarkdownExec::MarkParse.echo(ARGV[0])
20
+
21
+ require 'optparse'
22
+ require 'pathname'
23
+ require 'tty-prompt'
24
+ require 'yaml'
25
+
26
+ # require_relative 'mdlib'
27
+ # #!/usr/bin/env ruby
28
+ # # frozen_string_literal: true
29
+ # # encoding=utf-8
30
+
31
+ # env_debug = ENV['MARKDOWN_EXEC_DEBUG']
32
+ # $pdebug = !(env_debug || '').empty?
33
+
34
+ require 'open3'
35
+ # require 'tty-prompt'
36
+
37
+ BLOCK_SIZE = 1024
38
+ SELECT_PAGE_HEIGHT = 12
4
39
 
5
40
  module MarkdownExec
6
41
  class Error < StandardError; end
7
- # Your code goes here...
8
42
 
9
- class MDExec
10
- def self.echo(str = "")
11
- "#{str}#{str}"
43
+ # Markdown Exec
44
+ # class MarkParse
45
+ # def self.echo(str = '')
46
+ # "#{str}#{str}"
47
+ # end
48
+ # end
49
+ ##
50
+ #
51
+ class MarkParse
52
+ attr_accessor :options
53
+
54
+ def initialize(options = {})
55
+ @options = options
56
+ end
57
+
58
+ def count_blocks
59
+ cnt = 0
60
+ File.readlines(options[:mdfilename]).each do |line|
61
+ cnt += 1 if line.match(/^```/)
62
+ end
63
+ cnt / 2
64
+ end
65
+
66
+ def find_files
67
+ puts "pwd: #{`pwd`}" if $pdebug
68
+ # `ls -1 *.md`.split("\n").tap { |ret| puts "find_files() ret: #{ret.inspect}" if $pdebug }
69
+ `ls -1 #{File.join options[:mdfolder], '*.md'}`.split("\n").tap do |ret|
70
+ puts "find_files() ret: #{ret.inspect}" if $pdebug
71
+ end
72
+ end
73
+
74
+ def fout(str)
75
+ puts str # to stdout
76
+ end
77
+
78
+ def copts(call_options = {}, options_block = nil)
79
+ class_call_options = options.merge(call_options || {})
80
+ if options_block
81
+ options_block.call class_call_options
82
+ else
83
+ class_call_options
84
+ end.tap { |ret| puts "copts() ret: #{ret.inspect}" if $pdebug }
85
+ end
86
+
87
+ def bsr(headings, title)
88
+ # puts "bsr() headings: #{headings.inspect}"
89
+ { headings: headings, name: title, title: title }
90
+ end
91
+
92
+ def block_summary(opts, headings, block_title, current)
93
+ puts "block_summary() block_title: #{block_title.inspect}" if $pdebug
94
+ return [current] unless opts[:struct]
95
+
96
+ # return [{ body: current, name: block_title, title: block_title }] unless opts[:bash]
97
+ return [bsr(headings, block_title).merge({ body: current })] unless opts[:bash]
98
+
99
+ bm = block_title.match(/:(\S+)( |$)/)
100
+ reqs = block_title.scan(/\+\S+/).map { |s| s[1..] }
101
+
102
+ if $pdebug
103
+ puts ["block_summary() bm: #{bm.inspect}",
104
+ "block_summary() reqs: #{reqs.inspect}"]
105
+ end
106
+
107
+ if bm && bm[1]
108
+ # [{ body: current, name: bm[1], reqs: reqs, title: bm[1] }]
109
+ [bsr(headings, bm[1]).merge({ body: current, reqs: reqs })]
110
+ else
111
+ # [{ body: current, name: block_title, reqs: reqs, title: block_title }]
112
+ [bsr(headings, block_title).merge({ body: current, reqs: reqs })]
113
+ end
114
+ end
115
+
116
+ def get_blocks(call_options = {}, &options_block)
117
+ opts = copts call_options, options_block
118
+
119
+ blocks = []
120
+ current = nil
121
+ in_block = false
122
+ block_title = ''
123
+
124
+ headings = []
125
+ File.readlines(opts[:mdfilename]).each do |line|
126
+ puts "get_blocks() line: #{line.inspect}" if $pdebug
127
+ continue unless line
128
+
129
+ if opts[:mdheadings]
130
+ if (lm = line.match(/^### *(.+?) *$/))
131
+ headings = [headings[0], headings[1], lm[1]]
132
+ elsif (lm = line.match(/^## *([^#]*?) *$/))
133
+ headings = [headings[0], lm[1]]
134
+ elsif (lm = line.match(/^# *([^#]*?) *$/))
135
+ headings = [lm[1]]
136
+ end
137
+ puts "get_blocks() headings: #{headings.inspect}" if $pdebug
138
+ end
139
+
140
+ if line.match(/^`{3,}/)
141
+ if in_block
142
+ puts 'get_blocks() in_block' if $pdebug
143
+ if current
144
+
145
+ # block_title ||= current.join(' ').gsub(/ +/, ' ')[0..64]
146
+ block_title = current.join(' ').gsub(/ +/, ' ')[0..64] if block_title.nil? || block_title.empty?
147
+
148
+ blocks += block_summary opts, headings, block_title, current
149
+ current = nil
150
+ end
151
+ in_block = false
152
+ block_title = ''
153
+ else
154
+ ## new block
155
+ #
156
+
157
+ # lm = line.match(/^`{3,}([^`\s]+)( .+)?$/)
158
+ lm = line.match(/^`{3,}([^`\s]*) *(.*)$/)
159
+
160
+ do1 = false
161
+ if opts[:bash_only]
162
+ do1 = true if lm && (lm[1] == 'bash')
163
+ elsif opts[:exclude_expect_blocks]
164
+ do1 = true unless lm && (lm[1] == 'expect')
165
+ else
166
+ do1 = true
167
+ end
168
+ if $pdebug
169
+ puts ["get_blocks() lm: #{lm.inspect}",
170
+ "get_blocks() opts: #{opts.inspect}",
171
+ "get_blocks() do1: #{do1}"]
172
+ end
173
+
174
+ if do1 && (!opts[:title_match] || (lm && lm[2] && lm[2].match(opts[:title_match])))
175
+ current = []
176
+ in_block = true
177
+ block_title = (lm && lm[2])
178
+ end
179
+
180
+ end
181
+ elsif current
182
+ current += [line.chomp]
183
+ end
184
+ end
185
+ blocks.tap { |ret| puts "get_blocks() ret: #{ret.inspect}" if $pdebug }
186
+ end
187
+
188
+ def make_block_label(block, call_options = {})
189
+ opts = options.merge(call_options)
190
+ puts "make_block_label() opts: #{opts.inspect}" if $pdebug
191
+ puts "make_block_label() block: #{block.inspect}" if $pdebug
192
+ if opts[:mdheadings]
193
+ heads = block.fetch(:headings, []).compact.join(' # ')
194
+ "#{block[:title]} [#{heads}] (#{opts[:mdfilename]})"
195
+ else
196
+ "#{block[:title]} (#{opts[:mdfilename]})"
197
+ end
198
+ end
199
+
200
+ def make_block_labels(call_options = {})
201
+ opts = options.merge(call_options)
202
+ get_blocks(opts).map do |block|
203
+ make_block_label block, opts
204
+ end
205
+ end
206
+
207
+ def select_block(call_options = {}, &options_block)
208
+ opts = copts call_options, options_block
209
+
210
+ blocks = get_blocks(opts.merge(struct: true))
211
+ puts "select_block() blocks: #{blocks.to_yaml}" if $pdebug
212
+
213
+ prompt = TTY::Prompt.new(interrupt: :exit)
214
+ pt = "#{opts.fetch(:prompt, nil) || 'Pick one'}:"
215
+ puts "select_block() pt: #{pt.inspect}" if $pdebug
216
+
217
+ blocks.each { |block| block.merge! label: make_block_label(block, opts) }
218
+ block_labels = blocks.map { |block| block[:label] }
219
+ puts "select_block() block_labels: #{block_labels.inspect}" if $pdebug
220
+
221
+ if opts[:preview_options]
222
+ select_per_page = 3
223
+ block_labels.each do |bn|
224
+ fout " - #{bn}"
225
+ end
226
+ else
227
+ select_per_page = SELECT_PAGE_HEIGHT
228
+ end
229
+
230
+ return nil if block_labels.count.zero?
231
+
232
+ sel = prompt.select(pt, block_labels, per_page: select_per_page)
233
+ puts "select_block() sel: #{sel.inspect}" if $pdebug
234
+ # catch
235
+ # # catch TTY::Reader::InputInterrupt
236
+ # puts "InputInterrupt"
237
+ # end
238
+
239
+ label_block = blocks.select { |block| block[:label] == sel }.fetch(0, nil)
240
+ puts "select_block() label_block: #{label_block.inspect}" if $pdebug
241
+ sel = label_block[:name]
242
+ puts "select_block() sel: #{sel.inspect}" if $pdebug
243
+
244
+ cbs = code_blocks(blocks, sel)
245
+ puts "select_block() cbs: #{cbs.inspect}" if $pdebug
246
+
247
+ ## display code blocks for approval
248
+ #
249
+ cbs.each { |cb| fout cb } if opts[:display] || opts[:approve]
250
+
251
+ allow = true
252
+ allow = prompt.yes? 'Process?' if opts[:approve]
253
+
254
+ selected = block_by_name blocks, sel
255
+ puts "select_block() selected: #{selected.inspect}" if $pdebug
256
+ if allow && opts[:execute]
257
+
258
+ ## process in script, to handle line continuations
259
+ #
260
+ cmd2 = cbs.flatten.join("\n")
261
+ fout "$ #{cmd2.to_yaml}"
262
+
263
+ # Open3.popen3(cmd2) do |stdin, stdout, stderr, wait_thr|
264
+ # cnt += 1
265
+ # # stdin.puts "This is sent to the command"
266
+ # # stdin.close # we're done
267
+ # stdout_str = stdout.read # read stdout to string. note that this will block until the command is done!
268
+ # stderr_str = stderr.read # read stderr to string
269
+ # status = wait_thr.value # will block until the command finishes; returns status that responds to .success?
270
+ # fout "#{stdout_str}"
271
+ # fout "#{cnt}: err: #{stderr_str}" if stderr_str != ''
272
+ # # fout "#{cnt}: stt: #{status}"
273
+ # end
274
+
275
+ Open3.popen3(cmd2) do |stdin, stdout, stderr|
276
+ stdin.close_write
277
+ begin
278
+ files = [stdout, stderr]
279
+
280
+ until all_eof(files)
281
+ ready = IO.select(files)
282
+
283
+ next unless ready
284
+
285
+ readable = ready[0]
286
+ # writable = ready[1]
287
+ # exceptions = ready[2]
288
+
289
+ readable.each do |f|
290
+ # fileno = f.fileno
291
+
292
+ data = f.read_nonblock(BLOCK_SIZE)
293
+ # fout "- fileno: #{fileno}\n#{data}"
294
+ fout data
295
+ rescue EOFError #=> e
296
+ # fout "fileno: #{fileno} EOF"
297
+ end
298
+ end
299
+ rescue IOError => e
300
+ fout "IOError: #{e}"
301
+ end
302
+ end
303
+ end
304
+
305
+ selected[:name]
306
+ end
307
+
308
+ def select_md_file
309
+ opts = options
310
+ files = find_files
311
+ if files.count == 1
312
+ sel = files[0]
313
+ elsif files.count >= 2
314
+
315
+ if opts[:preview_options]
316
+ select_per_page = 3
317
+ files.each do |file|
318
+ fout " - #{file}"
319
+ end
320
+ else
321
+ select_per_page = SELECT_PAGE_HEIGHT
322
+ end
323
+
324
+ prompt = TTY::Prompt.new
325
+ sel = prompt.select("#{opts.fetch(:prompt, 'Pick one')}:", files, per_page: select_per_page)
326
+ end
327
+
328
+ sel
329
+ end
330
+
331
+ # Returns true if all files are EOF
332
+ #
333
+ def all_eof(files)
334
+ files.find { |f| !f.eof }.nil?
335
+ end
336
+
337
+ def code(table, block)
338
+ puts "code() table: #{table.inspect}" if $pdebug
339
+ puts "code() block: #{block.inspect}" if $pdebug
340
+ all = [block[:name]] + unroll(table, block[:reqs])
341
+ puts "code() all: #{all.inspect}" if $pdebug
342
+ all.reverse.map do |req|
343
+ puts "code() req: #{req.inspect}" if $pdebug
344
+ block_by_name(table, req).fetch(:body, '')
345
+ end
346
+ .flatten(1)
347
+ .tap { |ret| puts "code() ret: #{ret.inspect}" if $pdebug }
348
+ end
349
+
350
+ def block_by_name(table, name, default = {})
351
+ table.select { |block| block[:name] == name }.fetch(0, default)
352
+ end
353
+
354
+ def code_blocks(table, name)
355
+ puts "code_blocks() table: #{table.inspect}" if $pdebug
356
+ puts "code_blocks() name: #{name.inspect}" if $pdebug
357
+ name_block = block_by_name(table, name)
358
+ puts "code_blocks() name_block: #{name_block.inspect}" if $pdebug
359
+ all = [name_block[:name]] + unroll(table, name_block[:reqs])
360
+ puts "code_blocks() all: #{all.inspect}" if $pdebug
361
+
362
+ # in order of appearance in document
363
+ table.select { |block| all.include? block[:name] }
364
+ .map { |block| block.fetch(:body, '') }
365
+ .flatten(1)
366
+ .tap { |ret| puts "code_blocks() ret: #{ret.inspect}" if $pdebug }
367
+ end
368
+
369
+ def unroll(table, reqs)
370
+ puts "unroll() table: #{table.inspect}" if $pdebug
371
+ puts "unroll() reqs: #{reqs.inspect}" if $pdebug
372
+ all = []
373
+ rem = reqs
374
+ while rem.count.positive?
375
+ puts "unrol() rem: #{rem.inspect}" if $pdebug
376
+ rem = rem.map do |req|
377
+ puts "unrol() req: #{req.inspect}" if $pdebug
378
+ next if all.include? req
379
+
380
+ all += [req]
381
+ puts "unrol() all: #{all.inspect}" if $pdebug
382
+ block_by_name(table, req).fetch(:reqs, [])
383
+ end
384
+ .compact
385
+ .flatten(1)
386
+ .tap { |_ret| puts "unroll() rem: #{rem.inspect}" if $pdebug }
387
+ end
388
+ all.tap { |ret| puts "unroll() ret: #{ret.inspect}" if $pdebug }
389
+ end
390
+ end
391
+
392
+ # $stderr.sync = true
393
+ # $stdout.sync = true
394
+
395
+ def fout(str)
396
+ puts str # to stdout
397
+ end
398
+
399
+ ## configuration file
400
+ #
401
+ def read_configuration!(options, configuration_path)
402
+ if Pathname.new(configuration_path).exist?
403
+ # rubocop:disable Security/YAMLLoad
404
+ options.merge!((YAML.load(File.open(configuration_path)) || {})
405
+ .transform_keys(&:to_sym))
406
+ # rubocop:enable Security/YAMLLoad
407
+ end
408
+ options
409
+ end
410
+
411
+ def run
412
+ ## default configuration
413
+ #
414
+ options = {
415
+ mdheadings: true,
416
+ list_blocks: false,
417
+ list_docs: false,
418
+ mdfilename: 'README.md',
419
+ mdfolder: '.'
420
+ }
421
+
422
+ def options_finalize!(options); end
423
+
424
+ # read local configuration file
425
+ #
426
+ read_configuration! options, ".#{APP_NAME.downcase}.yml"
427
+
428
+ ## read current details for aws resources from app_data_file
429
+ #
430
+ # load_resources! options
431
+ # puts "q31 options: #{options.to_yaml}" if $pdebug
432
+
433
+ # rubocop:disable Metrics/BlockLength
434
+ option_parser = OptionParser.new do |opts|
435
+ executable_name = File.basename($PROGRAM_NAME)
436
+ opts.banner = [
437
+ "#{APP_NAME} - #{APP_DESC} (#{VERSION})".freeze,
438
+ "Usage: #{executable_name} [options]"
439
+ ].join("\n")
440
+
441
+ ## menu top: on_head appear in reverse order added
442
+ #
443
+ opts.on('--config PATH', 'Read configuration file') do |value|
444
+ read_configuration! options, value
445
+ end
446
+
447
+ ## menu body: items appear in order added
448
+ #
449
+ opts.on('-f RELATIVE', '--mdfilename', 'Name of document') do |value|
450
+ options[:mdfilename] = value
451
+ end
452
+
453
+ opts.on('-p PATH', '--mdfolder', 'Path to documents') do |value|
454
+ options[:mdfolder] = value
455
+ end
456
+
457
+ opts.on('--list-blocks', 'List blocks') do |_value|
458
+ options[:list_blocks] = true
459
+ end
460
+
461
+ opts.on('--list-docs', 'List docs in current folder') do |_value|
462
+ options[:list_docs] = true
463
+ end
464
+
465
+ ## menu bottom: items appear in order added
466
+ #
467
+ opts.on_tail('-h', '--help', 'App help') do |_value|
468
+ puts option_parser.help
469
+ exit
470
+ end
471
+
472
+ opts.on_tail('-v', '--version', 'App version') do |_value|
473
+ puts VERSION
474
+ exit
475
+ end
476
+
477
+ opts.on_tail('-x', '--exit', 'Exit app') do |_value|
478
+ exit
479
+ end
480
+
481
+ opts.on_tail('-0', 'Show configuration') do |_v|
482
+ options_finalize! options
483
+ puts options.to_yaml
484
+ end
485
+ end
486
+ # rubocop:enable Metrics/BlockLength
487
+
488
+ option_parser.load # filename defaults to basename of the program without suffix in a directory ~/.options
489
+ option_parser.environment # env defaults to the basename of the program.
490
+ option_parser.parse! # (into: options)
491
+ options_finalize! options
492
+
493
+ ## process
494
+ #
495
+ # rubocop:disable Metrics/BlockLength
496
+ loop do # once
497
+ mp = MarkParse.new options
498
+ options.merge!(
499
+ {
500
+ approve: true,
501
+ bash: true,
502
+ display: true,
503
+ exclude_expect_blocks: true,
504
+ execute: true,
505
+ prompt: 'Execute',
506
+ struct: true
507
+ }
508
+ )
509
+
510
+ ## show
511
+ #
512
+ if options[:list_docs]
513
+ fout mp.find_files
514
+ break
515
+ end
516
+
517
+ if options[:list_blocks]
518
+ fout (mp.find_files.map do |file|
519
+ mp.make_block_labels(mdfilename: file, struct: true)
520
+ end).flatten(1).to_yaml
521
+ break
522
+ end
523
+
524
+ ## process
525
+ #
526
+ mp.select_block(bash: true, struct: true) if options[:mdfilename]
527
+
528
+ # rubocop:disable Style/BlockComments
529
+ # rubocop:enable Style/BlockComments
530
+
531
+ break unless false # rubocop:disable Lint/LiteralAsCondition
12
532
  end
13
533
  end
534
+ # rubocop:enable Metrics/BlockLength
535
+ # rubocop:enable Style/GlobalVars
14
536
  end
metadata CHANGED
@@ -1,20 +1,91 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markdown_exec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fareed Stevenson
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-07 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-03-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: open3
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: optparse
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.1.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: pathname
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.1.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.1.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: tty-prompt
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.23.1
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.23.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: yaml
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.2.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.2.0
13
83
  description: Execute shell blocks in markdown files. Name blocks and require named
14
84
  blocks.
15
85
  email:
16
86
  - fareed@phomento.com
17
- executables: []
87
+ executables:
88
+ - mde
18
89
  extensions: []
19
90
  extra_rdoc_files: []
20
91
  files:
@@ -22,6 +93,7 @@ files:
22
93
  - CHANGELOG.md
23
94
  - CODE_OF_CONDUCT.md
24
95
  - Gemfile
96
+ - Gemfile.lock
25
97
  - LICENSE.txt
26
98
  - README.md
27
99
  - Rakefile
@@ -30,11 +102,11 @@ files:
30
102
  - bin/setup
31
103
  - lib/markdown_exec.rb
32
104
  - lib/markdown_exec/version.rb
33
- homepage: https://rubygems.org/gems/markdown_executor
105
+ homepage: https://rubygems.org/gems/markdown_exec
34
106
  licenses:
35
107
  - MIT
36
108
  metadata:
37
- homepage_uri: https://rubygems.org/gems/markdown_executor
109
+ homepage_uri: https://rubygems.org/gems/markdown_exec
38
110
  post_install_message:
39
111
  rdoc_options: []
40
112
  require_paths: