literate_md 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/bin/literate_md +107 -0
  2. metadata +106 -0
data/bin/literate_md ADDED
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/ruby -rubygems
2
+
3
+ require 'coderay'
4
+ require 'redcarpet'
5
+ require 'trollop'
6
+ require 'fileutils'
7
+
8
+ opts = Trollop::options do
9
+ opt :weave, "Produce documentation", :short => 'w'
10
+ opt :tangle, "Produce code", :short => 't'
11
+ opt :outputdir, "Directory to write files to", :default => Dir.pwd, :short => 'o'
12
+ opt :lang, "Default language of code", :default => "ruby", :short => 'l'
13
+ opt :files, "Files to process", :type => :string, :short => 'f', :required => true
14
+ end
15
+
16
+ $allowed = '(\w| )*|((.*:)?\*)'
17
+ html_opts = {
18
+ :fenced_code_blocks => true,
19
+ :superscript => true,
20
+ :tables => true,
21
+ :lax_html_blocks => true,
22
+ :strikethrough => true
23
+ }
24
+ $ext_for_lang = {
25
+ :ruby => 'rb',
26
+ :c => 'c',
27
+ }
28
+
29
+ class Weave < Redcarpet::Render::XHTML
30
+ attr_accessor :default_lang, :original_text
31
+ def block_code(code, lang)
32
+ l_ang, r_ang, equiv = "__lang__", "__rang__", "__equiv__"
33
+ line_num = @original_text[0,@original_text.index(code)].count("\n")+1
34
+ code = code.
35
+ gsub(/@(#{$allowed})@\s*\+=/,"#{l_ang}\\1#{r_ang}+#{equiv}").
36
+ gsub(/@(#{$allowed})@/,"#{l_ang}\\1#{r_ang}")
37
+ code = CodeRay.
38
+ scan(code, lang.nil? ? @default_lang : lang.to_sym).
39
+ html(
40
+ :wrap => :div,
41
+ :css => :style,
42
+ :line_numbers => :table,
43
+ :line_number_start => line_num)
44
+ code.
45
+ gsub(/#{l_ang}(#{$allowed})#{r_ang}(\s*)\+#{equiv}/,'&lang;\\1&rang;+&equiv;').
46
+ gsub(/#{l_ang}(#{$allowed})#{r_ang}/,'&lang;\\1&rang;')
47
+ end
48
+ def codespan(code); block_code(code,nil) end
49
+ end
50
+
51
+ def write_to path, data
52
+ FileUtils.mkdir_p(File.dirname(path))
53
+ File.open(path, 'w') {|f| f.write(data)}
54
+ end
55
+
56
+ if opts.weave
57
+ r = Redcarpet::Markdown.new(Weave, html_opts)
58
+ r.renderer.default_lang = opts.lang.to_sym
59
+ opts.files.split(',').each{|file|
60
+ code = File.open(file, 'r'){|f|f.read}
61
+ r.renderer.original_text = code
62
+ html = r.render(code)
63
+ write_to("#{opts.outputdir}/#{file}.html", html)
64
+ }
65
+ end
66
+
67
+ class Tangle < Redcarpet::Render::Base
68
+ attr_accessor :default_lang, :links, :file_no_ext
69
+ def block_code(code, lang)
70
+ chunks =
71
+ [{:start => 0, :anchor => '*', :anchor_len => 0}] +
72
+ code.scan(/(@(#{$allowed})@\s*\+=)/).map{|x|
73
+ {:start => code.index(x[0]), :anchor => x[1], :anchor_len => x[0].length}
74
+ } +
75
+ [{:start => code.length}]
76
+ (1..chunks.length-1).each{|index|
77
+ last, this = chunks[index-1], chunks[index]
78
+ @links[normalise(last[:anchor],lang)] << code[last[:start] + last[:anchor_len], this[:start]]
79
+ }
80
+ nil
81
+ end
82
+ def normalise(link_name, lang)
83
+ if link_name == '*'
84
+ "#{@file_no_ext}.#{$ext_for_lang[lang.nil? ? @default_lang : lang.to_sym]}:*"
85
+ else
86
+ link_name
87
+ end
88
+ end
89
+ def codespan(code); block_code(code,nil) end
90
+ end
91
+
92
+ if opts.tangle
93
+ links = Hash.new{|h,k|h[k]=[]}
94
+ r = Redcarpet::Markdown.new(Tangle, html_opts)
95
+ r.renderer.default_lang, r.renderer.links = opts.lang.to_sym, links
96
+ opts.files.split(',').each{|file|
97
+ r.renderer.file_no_ext = file[0,file.rindex('.')]
98
+ r.render(File.open(file, 'r'){|f|f.read})
99
+ }
100
+ resolve = lambda{|parts| parts.join('').gsub(/@(#{$allowed})@/) {|match|resolve.call(links[match[1..-2]])} }
101
+ links.keys.reject{|k|!k.end_with? ':*'}.each{|root|
102
+ write_to(
103
+ "#{opts.outputdir}/#{root[0..-3]}",
104
+ resolve.call(links[root]))
105
+ }
106
+ end
107
+
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: literate_md
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - remis
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-03-08 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: redcarpet
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: coderay
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: trollop
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :runtime
61
+ version_requirements: *id003
62
+ description: A simple hello world gem
63
+ email:
64
+ executables:
65
+ - literate_md
66
+ extensions: []
67
+
68
+ extra_rdoc_files: []
69
+
70
+ files:
71
+ - bin/literate_md
72
+ homepage: http://remis-thoughts.blogspot.com
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ requirements: []
99
+
100
+ rubyforge_project:
101
+ rubygems_version: 1.8.5
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Convert markdown documents into code or html
105
+ test_files: []
106
+