markdown_exec 0.0.1 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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: