markdown-run 0.1.6 → 0.1.7

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: ac1a715b89896b392f75d2222bda1a4f5899dda9da7a12871548faee8d3c86bb
4
- data.tar.gz: 5fd7954991346dd940594b264d5b162a91451ed7c89e7510eb6b0315d2c39195
3
+ metadata.gz: c11a9addb3e251e9830fe2126d2d752dc8c04c879b607d1ee0ad80998d51b294
4
+ data.tar.gz: '014954e8178d28729dfa86350a9e92aa91010892e6d177a5f7616dfd0e9ad72b'
5
5
  SHA512:
6
- metadata.gz: 1ee917248f47a0ccc7770fdd419fe3d65dfe2ca99c79d44efe0b46a9fd599761e0c218e622c39989c806de07f92480c0de1e4c7c869d7d9f7db2439a9fb70fd0
7
- data.tar.gz: 2c3eeb35fee738e405c30bdbb5fee6e8cad6bb0acc599c1115ad77315179e28dd37c6aace1b125c5306d9702b2cbc4c2dec1394695c9908a73853917f73a1fa3
6
+ metadata.gz: 5a26f680f607d52d7ceb0b0f31cca84af2a811ed2a70f6f73f9ab6ae3f9032f9135943c9e765df4d9714cbbd766179de14bab8006148e1d65d27a26388dd935c
7
+ data.tar.gz: 3ed109437211b62afd2dcdf1469e3103db9bd36a13be207f0ea636d67163c269e4a199e9a4b901ed4f7756319b5aa9c20f00e7613106be463c5139965f209fbf
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.7] - 2025-06-01
4
+
5
+ - Added rerun functionality
6
+
3
7
  ## [0.1.6] - 2025-06-01
4
8
 
5
9
  - Refactor code to state pattern
data/README.md CHANGED
@@ -8,6 +8,15 @@ Do not rerun code blocks if result block is present.
8
8
 
9
9
  Meant to be used from the terminal or from an editor with a keybinding.
10
10
 
11
+ Supported languages:
12
+
13
+ - Javascript
14
+ - Ruby
15
+ - sqlite3
16
+ - postgresql
17
+ - bash
18
+ - zsh
19
+
11
20
  ## Installation
12
21
 
13
22
  `gem install markdown-run`
@@ -43,9 +52,20 @@ example vscode keybinding
43
52
  },
44
53
  ```
45
54
 
55
+ ### Code block options
56
+
57
+ - `rerun=true` or `rerun=false` for a code block to rerun or skip execution. `rerun=true` is the default if not specified
58
+
59
+ example:
60
+
61
+ ```js rerun=false
62
+ console.log("hello world");
63
+ ```
64
+
46
65
  ## Frontmatter
47
66
 
48
67
  You can add a yaml frontmatter to redefine code block behavior.
68
+
49
69
  For example sql blocks run by default against sqlite
50
70
  To have them run with postgres you can add at the top of your markdown file:
51
71
 
data/exe/markdown-run CHANGED
@@ -88,6 +88,7 @@ class MarkdownProcessor
88
88
  @state = :outside_code_block
89
89
  @current_block_lang = ""
90
90
  @current_code_content = ""
91
+ @current_block_rerun = false
91
92
  @aliases = {}
92
93
  end
93
94
 
@@ -193,6 +194,16 @@ class MarkdownProcessor
193
194
  line && line.strip == ""
194
195
  end
195
196
 
197
+ def parse_rerun_option(options_string)
198
+ return false unless options_string
199
+
200
+ # Match rerun=true or rerun=false
201
+ match = options_string.match(/rerun\s*=\s*(true|false)/i)
202
+ return false unless match
203
+
204
+ match[1].downcase == "true"
205
+ end
206
+
196
207
  def safe_enum_operation(file_enum, operation)
197
208
  file_enum.send(operation)
198
209
  rescue StopIteration
@@ -221,11 +232,12 @@ class MarkdownProcessor
221
232
  def handle_outside_code_block(current_line, file_enum)
222
233
  if current_line.match?(/^```ruby\s+RESULT$/i)
223
234
  handle_existing_ruby_result_block(current_line, file_enum)
224
- elsif (match_data = current_line.match(/^```(\w+)$/i))
235
+ elsif (match_data = current_line.match(/^```(\w+)(?:\s+(.*))?$/i))
225
236
  lang = match_data[1].downcase
237
+ options_string = match_data[2]
226
238
  resolved_lang = resolve_language(lang)
227
239
  if SUPPORTED_LANGUAGES.key?(resolved_lang)
228
- start_code_block(current_line, lang)
240
+ start_code_block(current_line, lang, options_string)
229
241
  else
230
242
  @output_lines << current_line
231
243
  end
@@ -255,9 +267,10 @@ class MarkdownProcessor
255
267
  @state = :inside_result_block
256
268
  end
257
269
 
258
- def start_code_block(current_line, lang)
270
+ def start_code_block(current_line, lang, options_string = nil)
259
271
  @output_lines << current_line
260
272
  @current_block_lang = resolve_language(lang)
273
+ @current_block_rerun = parse_rerun_option(options_string)
261
274
  @state = :inside_code_block
262
275
  @current_code_content = ""
263
276
  end
@@ -273,6 +286,7 @@ class MarkdownProcessor
273
286
  decision = decide_execution(file_enum)
274
287
 
275
288
  if decision[:execute]
289
+ # If we consumed lines for rerun, don't add them to output (they'll be replaced)
276
290
  execute_and_add_result(decision[:blank_line])
277
291
  else
278
292
  skip_and_pass_through_result(decision[:lines_to_pass_through], file_enum)
@@ -286,13 +300,28 @@ class MarkdownProcessor
286
300
  expected_header_regex = result_block_regex(@current_block_lang)
287
301
 
288
302
  if line_matches_pattern?(peek1, expected_header_regex)
289
- return { execute: false, lines_to_pass_through: [file_enum.next] }
303
+ # If rerun=true, execute even if result block exists
304
+ if @current_block_rerun
305
+ # Consume the existing result block and execute
306
+ consumed_lines = [file_enum.next]
307
+ consume_existing_result_block(file_enum, consumed_lines)
308
+ return { execute: true, consumed_lines: consumed_lines }
309
+ else
310
+ return { execute: false, lines_to_pass_through: [file_enum.next] }
311
+ end
290
312
  elsif is_blank_line?(peek1)
291
313
  consumed_blank_line = file_enum.next
292
314
  peek2 = peek_next_line(file_enum)
293
315
 
294
316
  if line_matches_pattern?(peek2, expected_header_regex)
295
- return { execute: false, lines_to_pass_through: [consumed_blank_line, file_enum.next] }
317
+ if @current_block_rerun
318
+ # Consume the blank line and existing result block, then execute
319
+ consumed_lines = [consumed_blank_line, file_enum.next]
320
+ consume_existing_result_block(file_enum, consumed_lines)
321
+ return { execute: true, consumed_lines: consumed_lines, blank_line: consumed_blank_line }
322
+ else
323
+ return { execute: false, lines_to_pass_through: [consumed_blank_line, file_enum.next] }
324
+ end
296
325
  else
297
326
  return { execute: true, blank_line: consumed_blank_line }
298
327
  end
@@ -334,9 +363,22 @@ class MarkdownProcessor
334
363
  end
335
364
  end
336
365
 
366
+ def consume_existing_result_block(file_enum, consumed_lines)
367
+ begin
368
+ loop do
369
+ result_block_line = file_enum.next
370
+ consumed_lines << result_block_line
371
+ break if is_block_end?(result_block_line)
372
+ end
373
+ rescue StopIteration
374
+ warn "Warning: End of file reached while consuming existing result block for rerun."
375
+ end
376
+ end
377
+
337
378
  def reset_code_block_state
338
379
  @state = :outside_code_block
339
380
  @current_code_content = ""
381
+ @current_block_rerun = false
340
382
  end
341
383
  end
342
384
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Markdown
4
4
  module Run
5
- VERSION = "0.1.6"
5
+ VERSION = "0.1.7"
6
6
  end
7
7
  end
@@ -131,4 +131,74 @@ class TestMarkdownExec < Minitest::Test
131
131
  assert file_content.include?("```RESULT\n"), "RESULT block should be created for aliased language"
132
132
  assert file_content.include?("aliased to psql"), "Output should contain the expected result"
133
133
  end
134
+
135
+ def test_rerun_functionality
136
+ # Test 1: Default behavior (no rerun option) should skip existing result
137
+ md_content_with_result = <<~MARKDOWN
138
+ ```ruby
139
+ puts "Should not change: \#{Time.now.to_i}"
140
+ ```
141
+
142
+ ```ruby RESULT
143
+ Should not change: 999999999
144
+ ```
145
+ MARKDOWN
146
+ create_md_file(md_content_with_result)
147
+ process_markdown_file_main(@test_md_file_path)
148
+
149
+ file_content = read_md_file
150
+ assert file_content.include?("Should not change: 999999999"), "Default behavior should preserve existing result"
151
+ refute file_content.match?(/Should not change: (?!999999999)\d+/), "Default behavior should not generate new timestamp"
152
+
153
+ # Test 2: rerun=false should skip existing result
154
+ md_content_rerun_false = <<~MARKDOWN
155
+ ```ruby rerun=false
156
+ puts "Should not change either: \#{Time.now.to_i}"
157
+ ```
158
+
159
+ ```ruby RESULT
160
+ Should not change either: 888888888
161
+ ```
162
+ MARKDOWN
163
+ create_md_file(md_content_rerun_false)
164
+ process_markdown_file_main(@test_md_file_path)
165
+
166
+ file_content = read_md_file
167
+ assert file_content.include?("Should not change either: 888888888"), "rerun=false should preserve existing result"
168
+ refute file_content.match?(/Should not change either: (?!888888888)\d+/), "rerun=false should not generate new timestamp"
169
+
170
+ # Test 3: rerun=true should replace existing result
171
+ md_content_rerun_true = <<~MARKDOWN
172
+ ```ruby rerun=true
173
+ puts "Should change: \#{Time.now.to_i}"
174
+ ```
175
+
176
+ ```ruby RESULT
177
+ Should change: 777777777
178
+ ```
179
+ MARKDOWN
180
+ create_md_file(md_content_rerun_true)
181
+ process_markdown_file_main(@test_md_file_path)
182
+
183
+ file_content = read_md_file
184
+ refute file_content.include?("Should change: 777777777"), "rerun=true should replace existing result"
185
+ assert file_content.match?(/Should change: \d+/), "rerun=true should generate new result with actual timestamp"
186
+
187
+ # Test 4: rerun=true with blank line before result block
188
+ md_content_rerun_true_blank = <<~MARKDOWN
189
+ ```ruby rerun=true
190
+ puts "Should also change: \#{Time.now.to_i}"
191
+ ```
192
+
193
+ ```ruby RESULT
194
+ Should also change: 666666666
195
+ ```
196
+ MARKDOWN
197
+ create_md_file(md_content_rerun_true_blank)
198
+ process_markdown_file_main(@test_md_file_path)
199
+
200
+ file_content = read_md_file
201
+ refute file_content.include?("Should also change: 666666666"), "rerun=true with blank line should replace existing result"
202
+ assert file_content.match?(/Should also change: \d+/), "rerun=true with blank line should generate new result"
203
+ end
134
204
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markdown-run
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aurélien Bottazini
@@ -57,11 +57,11 @@ files:
57
57
  - lib/markdown/run/version.rb
58
58
  - markdown-run-sample.md
59
59
  - test_markdown_exec.rb
60
- homepage: https://rubygems.org/gems/markdown-run
60
+ homepage: https://github.com/aurelienbottazini/markdown-run
61
61
  licenses:
62
62
  - MIT
63
63
  metadata:
64
- homepage_uri: https://rubygems.org/gems/markdown-run
64
+ homepage_uri: https://github.com/aurelienbottazini/markdown-run
65
65
  source_code_uri: https://github.com/aurelienbottazini/markdown-run
66
66
  changelog_uri: https://github.com/aurelienbottazini/markdown-run/blob/main/CHANGELOG.md
67
67
  post_install_message: