Skip to content

Instantly share code, notes, and snippets.

@avdgaag
Created March 4, 2015 20:00
Show Gist options
  • Save avdgaag/f40be301ef37a52b8c7b to your computer and use it in GitHub Desktop.
Save avdgaag/f40be301ef37a52b8c7b to your computer and use it in GitHub Desktop.
AsciiDoc filter for literate programming-style code blocks.
#!/usr/bin/env ruby
require 'open3'
require 'tmpdir'
module Literate
class Line
INDENT = ''.freeze
def self.indent(str)
return str if str == ""
str.gsub(/^/, INDENT)
end
def initialize(str)
@str = str
end
def to_s
@str
end
def cd?
!path.nil?
end
def path
@str[/^#{INDENT}%-? cd (.+)$/, 1]
end
def silent?
@str =~ /^#{INDENT}%- /
end
def ignore?
@str =~ /^#{INDENT}%% /
end
def command?
@str =~ /^#{INDENT}% /
end
def plain?
!silent? && !ignore? && !command?
end
def formatted_command
"#{INDENT}% #{command}\n"
end
def command
@command ||=
begin
@str[/^#{INDENT}%[-%]? (.+)$/, 1].gsub /\{\{(.+)\}\}/ do |match|
Command.capture($1.strip).chomp
end
end
end
end
def self.in_masked_tmpdir
original_directory = Dir.pwd
new_dir = File.join(Dir.pwd, 'tmp')
Dir.chdir(new_dir)
yield(new_dir).gsub(new_dir, "~/examples")
ensure
Dir.chdir original_directory
end
class LineReader
include Enumerable
def initialize(source)
@source = source
end
def each
@source.each_line do |line|
yield Line.new(line)
end
end
end
class Command
attr_reader :line
def initialize(line)
@line = line
end
def result
if line.silent?
run
''
elsif line.ignore? || line.cd?
line.formatted_command
elsif line.command?
line.formatted_command +
Line.indent(run)
else
line.to_s
end
end
def self.capture(cmd)
input, output, wait_thr = Open3.popen2e(cmd)
output.read
ensure
input.close
output.close
end
private
def run
self.class.capture(line.command)
end
end
def self.literalize(str)
in_masked_tmpdir do |dir|
original_directory = dir
LineReader.new(str).each_with_object('') do |line, output|
if line.cd?
dir = File.join(dir, line.path)
raise "Invalid path: #{dir}" unless dir.start_with?(original_directory)
Dir.chdir(dir)
end
output << Command.new(line).result
end
end
end
end
puts Literate.literalize(STDIN.read)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment