This is a markdown document example.md I have:
## New language
Raku is a new language different from Perl.
## what does it offer
+ Object-oriented programming including generics, roles and multiple dispatch
+ Functional programming primitives, lazy and eager list evaluation, junctions, autothreading and hyperoperators (vector operators)
+ Parallelism, concurrency, and asynchrony including multi-core support
+ Definable grammars for pattern matching and generalized string processing
+ Optional and gradual typing
This code will be evaluated.
```{raku evaluate=TRUE}
4/5
```
Rakudo is a compiler for raku programming language. Install it and you're all set to run raku programs!
This code will be evaluated.
```{raku evaluate=TRUE}
say "this is promising";
say $*CWD;
```
This code will **not** be evaluated.
```{raku evaluate=FALSE}
say "Hello world";
```
which I want to convert into example.md as shown below with the code and output within it.
## New language
Raku is a new language different from Perl.
## what does it offer
+ Object-oriented programming including generics, roles and multiple dispatch
+ Functional programming primitives, lazy and eager list evaluation, junctions, autothreading and hyperoperators (vector operators)
+ Parallelism, concurrency, and asynchrony including multi-core support
+ Definable grammars for pattern matching and generalized string processing
+ Optional and gradual typing
This code will be evaluated.
Code:
```{raku evaluate=TRUE}
4/5
```
Output:
```
0.8
```
Rakudo is a compiler for raku programming language. Install it and you're all set to run raku programs!
This code will be evaluated.
Code:
```{raku evaluate=TRUE}
say "this is promising";
say $*CWD;
```
Output:
```
this is promising
"C:\Users\suman".IO
```
This code will **not** be evaluated.
Code:
```{raku evaluate=FALSE}
say "Hello world";
```
What I want to accomplish is:
backticks{raku evaluate}
and backticks
What I tried to do:
my $array= 'example.md'.IO.slurp;
#multiline capture code chunk and evaluate separately
if $array~~/\`\`\`\{raku (.*)\}(.*)\`\`\`/ {
#the first capture $0 will be evaluate
if $0~~"TRUE"{
#execute second capture which is code chunk which is captured in $1
}else {
# don't execute code
};
};
my $fh="temp.p6".IO.spurt: $1;
my $output= q:x/raku temp.p6/ if $0==TRUE
my $fh-out = open "example_new.md", :w; # Create a new file
# Print out next file, line by line
for "$file.tex".IO.lines -> $line {
# write output of code to example_new.md
}
$fh-out.close;
# copy
my $io = IO::Path.new("example_new.md");
$io.copy("example.md");
# clean up
unlink("example.md");
# move
$io.rename("example.md");
I am stuck in the first step. Any help?
You can run this code against your data with glot.io.
use v6;
constant $ticks = '```';
my regex Search {
$ticks '{raku evaluate=' $<evaluate>=(TRUE|FALSE) '}'
$<code>=[<!before $ticks> .]*
$ticks
}
sub Replace ($/) {
"Code:\n" ~ $ticks ~ $<code> ~ $ticks ~
($<evaluate> eq 'TRUE'
?? "\n\n" ~ 'Output:' ~ "\n" ~ $ticks ~ "\n" ~ Evaluate($<code>) ~ $ticks
!! '');
}
sub Evaluate ($code) {
my $out; my $*OUT = $*OUT but role { method print (*@args) { $out ~= @args } }
use MONKEY; my $eval-result = EVAL $code;
$out // $eval-result ~ "\n"
}
spurt
'example_new.md',
slurp('example.md')
.subst: &Search, &Replace, :g;
Starting at the bottom and then working upwards:
The .subst
method substitutes parts of its invocant string that need to be replaced and returns the revised string. .subst
's first argument is a matcher; it can be a string, or, as here, a regex -- &Search
1. .subst
's second argument is a replacement; this can also be a string, or, as here, a Callable
-- &Replace
. If it's a Callable
then .subst
passes the match from the matcher as a match object2 as the first argument to the Callable
. The :g
adverb directs .subst
to do the search/replace repeatedly for as many matches as there are in the invocant string.
slurp
generates a string in one go from a file. No need for open
, using handles, close
, etc. Its result in this case becomes the invocant of the .subst
explained above.
spurt
does the opposite, generating a file in one go from a string, in this case the results of the slurp(...).subst...
operation.
The Evaluate
routine generates a string that's the output from evaluating the string of code passed to it. To capture the result of evaluation it temporarily modifies Raku's STDOUT variable $*OUT
, redirecting print
s (and thus also say
s etc.) to the internal variable $out
before EVAL
ing the code. If the EVAL
results in anything being print
d to $out
then that is returned; if not, then the result of the EVAL
is returned (coerced to a string by the ~
). (A newline is appended in this second scenario but not the first because that is what's needed to get the correctly displayed result given how you've "specified" things by your example.)
The Replace
routine is passed a match object from a call of the Code
regex. It reconstructs the code section (without the evaluate bit) using the $<code>
capture. If the $<evaluate>
capture is 'TRUE'
then it also appends a fresh Output:
section using the Evaluate
routine explained above to produce the code's output.
The Code
regex matches a code section. It captures the TRUE
or FALSE
setting from the evaluate directive into a capture named $<evaluate>
and the code into a capture named $<code>
.
1 To pass a routine (a regex is a routine) rather than call it, it must be written with a sigil (&foo
), not without (foo
).
2 It does this even if the matcher was merely a string!