Search code examples
emacsorg-modeliterate-programmingnoweb

Emacs org mode: how to create literate programs with noweb syntax


I am trying to create this Perl program:

#!/usr/bin/perl

use strict;
use warnings;

open(my $fh, "<", "test.txt")
    or die "cannot open < file name: $!";

while (my $line = <$fh>) {
    print $line;
}

close($fh);

I created this org file:

#+BABEL: :cache yes :tangle yes :noweb yes

#+NAME: top_block
#+begin_src perl :tangle test.pl
  #!/usr/bin/perl

  use strict;
  use warnings;

  open(my $fh, "<", "test.txt")
      or die "cannot open < file name: $!";
  <<output all the lines from file>>
  close($fh);
#+end_src

#+NAME: output all the lines from file
#+begin_src perl :tangle test.pl
  while (my $line = <$fh>) {
      print $line;
  }
#+end_src

But it created this:

empty line here
#!/usr/bin/perl

use strict;
use warnings;

open(my $fh, "<", "test.txt")
    or die "cannot open < file name: $!";
<<output all the lines from file>>
close($fh);

while (my $line = <$fh>) {
    print $line;
}

Problems:

  1. There is an empty line at the top of the file.
  2. Noweb block wasn't expanded, but put to the bottom of the file.
  3. I don't understand, how to write the output file name once at the top? Currently, I have to rewrite it for every block: :tangle test.pl.

Solution

  • Here is the solution:

    #+BABEL: :cache yes :tangle yes :noweb yes
    
    #+NAME: top_block
    #+begin_src perl :tangle "test.pl" :noweb tangle :shebang #!/usr/bin/perl
      use strict;
      use warnings;
    
      open(my $fh, "<", "test.txt")
          or die "cannot open < file name: $!";
      <<output-all>>
      close($fh);
    #+end_src
    
    #+NAME: output-all
    #+begin_src perl
      while (my $line = <$fh>) {
          print $line;
      }
    #+end_src
    
    1. To put #!/usr/bin/perl to the top line use :shebang #!/usr/bin/perl
    2. Noweb blocks names shouldn't contain spaces. Replace them with "-".
    3. Write the file name for the root noweb block.