murdoc 0.1.13 → 0.2.0
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 +4 -4
- data/.gitignore +16 -0
- data/.rspec +1 -0
- data/.travis.yml +1 -3
- data/Gemfile +1 -10
- data/README.md +4 -4
- data/Rakefile +1 -23
- data/bin/murdoc +1 -1
- data/bin/murdoc-strip-comments +16 -3
- data/lib/murdoc.rb +36 -16
- data/lib/murdoc/annotator.rb +15 -137
- data/lib/murdoc/formatted_paragraph.rb +41 -0
- data/lib/murdoc/languages/base.rb +56 -0
- data/lib/murdoc/languages/coffeescript.rb +23 -0
- data/lib/murdoc/languages/html.rb +12 -33
- data/lib/murdoc/languages/javascript.rb +14 -35
- data/lib/murdoc/languages/markdown.rb +24 -0
- data/lib/murdoc/languages/ruby.rb +13 -34
- data/lib/murdoc/paragraph.rb +1 -37
- data/lib/murdoc/{formatter.rb → renderer.rb} +2 -2
- data/lib/murdoc/scanner.rb +138 -0
- data/lib/murdoc/version.rb +3 -0
- data/markup/stylesheet.css +136 -173
- data/markup/template.haml +10 -9
- data/markup/template_multifile.haml +13 -11
- data/murdoc.gemspec +27 -75
- data/spec/murdoc/annotator_spec.rb +42 -60
- data/spec/murdoc/languages/base_spec.rb +23 -0
- data/spec/murdoc/paragraph_spec.rb +2 -6
- data/spec/murdoc/{formatter_spec.rb → renderer_spec.rb} +3 -3
- data/spec/murdoc/scanner_spec.rb +101 -0
- data/spec/spec_helper.rb +10 -1
- metadata +29 -18
- data/Gemfile.lock +0 -71
- data/VERSION +0 -1
- data/autotest/discover.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ef249b35659b0df1ac35d233d7ded20dc29e45b
|
4
|
+
data.tar.gz: 7017b589cae5baf9511e1aaf065931b32d30c75a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 935006a39b60ce7b2d6c2d1c4eb8247758f36a60a2ce2174757d8befea55231dc5916b3c167d8d1c26b1f693c7eff06b0a7c7c4ca0f2713c12791b0b9d102e15
|
7
|
+
data.tar.gz: 87622f60399b0217f751cfa09b60eeea353d2af8a00727293057feaffac8de8ebc25ad3a7a5f5a16c186e57466214cb725911abde2fddaf922697ae7682a6227
|
data/.gitignore
ADDED
data/.rspec
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -9,13 +9,13 @@ You may also want to see:
|
|
9
9
|
* [Rocco](http://rtomayko.github.com/rocco/)
|
10
10
|
|
11
11
|
Dependencies
|
12
|
-
|
12
|
+
------------
|
13
13
|
|
14
14
|
* Haml
|
15
15
|
* Either RDiscount (for MRI rubies) or Kramdown (for non-mri rubies)
|
16
16
|
|
17
17
|
Example
|
18
|
-
|
18
|
+
-------
|
19
19
|
|
20
20
|
See example at [GH.pages](http://jsus.github.com/murdoc).
|
21
21
|
|
@@ -23,7 +23,7 @@ See also:
|
|
23
23
|
* [example](http://jsus.github.com/murdoc/docs) of integration with [jsus](http://github.com/jsus/jsus)
|
24
24
|
* [LSD documentation guides](https://github.com/lovelyscalabledrawings/lsd-guides/tree/gh-pages/grid)
|
25
25
|
|
26
|
-
License
|
27
|
-
|
26
|
+
License
|
27
|
+
-------
|
28
28
|
|
29
29
|
Public domain, see UNLICENSE file.
|
data/Rakefile
CHANGED
@@ -1,27 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require
|
3
|
-
begin
|
4
|
-
Bundler.setup(:default, :development)
|
5
|
-
rescue Bundler::BundlerError => e
|
6
|
-
$stderr.puts e.message
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
-
exit e.status_code
|
9
|
-
end
|
10
|
-
require 'rake'
|
11
|
-
|
12
|
-
require 'jeweler'
|
13
|
-
Jeweler::Tasks.new do |gem|
|
14
|
-
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
-
gem.name = "murdoc"
|
16
|
-
gem.homepage = "http://github.com/markiz/murdoc"
|
17
|
-
gem.license = "Public Domain"
|
18
|
-
gem.summary = "Annotated documentation generator"
|
19
|
-
gem.description = "Annotated documentation generator, see README.md for details"
|
20
|
-
gem.email = "markizko@gmail.com"
|
21
|
-
gem.authors = ["Mark Abramov"]
|
22
|
-
gem.executables = ["murdoc", "murdoc-strip-comments"]
|
23
|
-
end
|
24
|
-
Jeweler::RubygemsDotOrgTasks.new
|
2
|
+
require "bundler/gem_tasks"
|
25
3
|
|
26
4
|
require 'rspec/core'
|
27
5
|
require 'rspec/core/rake_task'
|
data/bin/murdoc
CHANGED
@@ -9,7 +9,7 @@ option_parser = OptionParser.new do |opts|
|
|
9
9
|
opts.banner = "murdoc <input file> <output html>"
|
10
10
|
|
11
11
|
opts.on("--[no-]syntax-highlight", "Highlight syntax using pygments") do |h|
|
12
|
-
options[:
|
12
|
+
options[:highlight] = h
|
13
13
|
end
|
14
14
|
|
15
15
|
opts.on("-t", "--template [FILENAME]", "Use custom haml template for output") do |t|
|
data/bin/murdoc-strip-comments
CHANGED
@@ -2,9 +2,11 @@
|
|
2
2
|
require "optparse"
|
3
3
|
$: << "./lib/"
|
4
4
|
require "murdoc"
|
5
|
+
require 'pp'
|
5
6
|
|
6
7
|
options = {}
|
7
8
|
source_type = nil
|
9
|
+
do_not_count_comment_lines = false
|
8
10
|
|
9
11
|
option_parser = OptionParser.new do |opts|
|
10
12
|
opts.banner = "murdoc-strip-comments [input file]\n\nWhen no input file is provided, murdoc-strip-comments uses standard input stream."
|
@@ -13,16 +15,27 @@ option_parser = OptionParser.new do |opts|
|
|
13
15
|
source_type = st
|
14
16
|
end
|
15
17
|
|
18
|
+
opts.on("--do-not-count-comment-lines") do |dncl|
|
19
|
+
do_not_count_comment_lines = dncl
|
20
|
+
end
|
21
|
+
|
16
22
|
opts.on_tail("-h", "--help", "Show this message") do
|
17
23
|
puts opts
|
18
24
|
exit
|
19
25
|
end
|
20
|
-
|
21
26
|
end
|
22
27
|
|
23
28
|
option_parser.parse!
|
24
29
|
|
25
|
-
annotator = Murdoc::Annotator.from_file(ARGV[0] || "/dev/stdin", source_type,
|
30
|
+
annotator = Murdoc::Annotator.from_file(ARGV[0] || "/dev/stdin", source_type, do_not_count_comment_lines)
|
31
|
+
prev_paragraph = nil
|
26
32
|
annotator.paragraphs.each do |paragraph|
|
27
|
-
|
33
|
+
if prev_paragraph
|
34
|
+
print "\n" * [(paragraph.starting_line - prev_paragraph.starting_line - prev_paragraph.source.lines.count), 0].max
|
35
|
+
end
|
36
|
+
|
37
|
+
if !(paragraph.source =~ /\A\s*\z/m)
|
38
|
+
puts paragraph.source
|
39
|
+
end
|
40
|
+
prev_paragraph = paragraph
|
28
41
|
end
|
data/lib/murdoc.rb
CHANGED
@@ -10,36 +10,50 @@
|
|
10
10
|
|
11
11
|
|
12
12
|
module Murdoc
|
13
|
+
AnnotatedFile = Struct.new(:filename, :source, :source_type, :paragraphs, :formatted_paragraphs)
|
14
|
+
|
15
|
+
def self.annotate(filename, highlight = true, do_not_count_comment_lines = false)
|
16
|
+
filename = File.expand_path(filename)
|
17
|
+
annotator = Annotator.from_file(filename, nil, do_not_count_comment_lines)
|
18
|
+
AnnotatedFile.new(filename,
|
19
|
+
annotator.source,
|
20
|
+
annotator.source_type,
|
21
|
+
annotator.paragraphs,
|
22
|
+
annotator.paragraphs.map {|p| FormattedParagraph.new(p, highlight) })
|
23
|
+
end
|
24
|
+
|
13
25
|
def self.generate_from_file(input, output, options = {})
|
14
26
|
options = default_options.merge(options)
|
15
|
-
annotator = Annotator.from_file(input, nil
|
27
|
+
annotator = Annotator.from_file(input, nil)
|
16
28
|
File.open(output, "w+") do |f|
|
17
|
-
|
18
|
-
|
29
|
+
annotated_file = annotate(input, options[:highlight], options[:do_not_count_comment_lines])
|
30
|
+
f.puts Renderer.new(options[:template]).render(:annotated_file => annotated_file,
|
31
|
+
:stylesheet => File.read(options[:stylesheet]))
|
19
32
|
end
|
20
33
|
end
|
21
34
|
|
22
35
|
def self.generate_from_multiple_files(input_files, output, options = {})
|
23
36
|
options = default_options_for_multiple_files.merge(options)
|
24
|
-
|
37
|
+
annotated_files = input_files.map {|fn| annotate(fn, options[:highlight], options[:do_not_count_comment_lines]) }
|
25
38
|
File.open(output, "w+") do |f|
|
26
|
-
f.puts
|
27
|
-
|
28
|
-
:stylesheet => File.read(options[:stylesheet]))
|
39
|
+
f.puts Renderer.new(options[:template]).render(:annotated_files => annotated_files,
|
40
|
+
:stylesheet => File.read(options[:stylesheet]))
|
29
41
|
end
|
30
42
|
end
|
31
43
|
|
32
44
|
def self.default_options
|
33
|
-
|
34
|
-
|
35
|
-
|
45
|
+
@options ||= {
|
46
|
+
template: "#{markup_dir}/template.haml",
|
47
|
+
stylesheet: "#{markup_dir}/stylesheet.css",
|
48
|
+
highlight: true
|
36
49
|
}
|
37
50
|
end
|
38
51
|
|
39
52
|
def self.default_options_for_multiple_files
|
40
|
-
|
41
|
-
|
42
|
-
|
53
|
+
@options ||= {
|
54
|
+
template: "#{markup_dir}/template_multifile.haml",
|
55
|
+
stylesheet: "#{markup_dir}/stylesheet.css",
|
56
|
+
highlight: true
|
43
57
|
}
|
44
58
|
end
|
45
59
|
|
@@ -49,7 +63,13 @@ module Murdoc
|
|
49
63
|
end
|
50
64
|
|
51
65
|
require "murdoc/annotator"
|
66
|
+
require "murdoc/scanner"
|
52
67
|
require "murdoc/paragraph"
|
53
|
-
require "murdoc/
|
54
|
-
|
55
|
-
|
68
|
+
require "murdoc/formatted_paragraph"
|
69
|
+
require "murdoc/renderer"
|
70
|
+
require "murdoc/languages/base"
|
71
|
+
require "murdoc/languages/html"
|
72
|
+
require "murdoc/languages/coffeescript"
|
73
|
+
require "murdoc/languages/javascript"
|
74
|
+
require "murdoc/languages/ruby"
|
75
|
+
require "murdoc/languages/markdown"
|
data/lib/murdoc/annotator.rb
CHANGED
@@ -1,40 +1,33 @@
|
|
1
|
-
# Annotator class does all the main job: parses out comments
|
2
|
-
# and returns annotated code
|
3
|
-
|
4
|
-
|
5
|
-
# Main module
|
6
1
|
module Murdoc
|
7
2
|
class Annotator
|
3
|
+
attr_accessor :source
|
4
|
+
|
8
5
|
# Attribute accessor containing the resulting paragraphs
|
9
6
|
attr_accessor :paragraphs
|
10
7
|
|
11
|
-
#
|
12
|
-
|
13
|
-
# `:highlight_source` -- highlights source syntax using pygments (default: true)
|
14
|
-
attr_accessor :options
|
15
|
-
|
16
|
-
def self.default_options
|
17
|
-
{
|
18
|
-
:highlight_source => true
|
19
|
-
}
|
20
|
-
end
|
21
|
-
|
8
|
+
# Source language
|
9
|
+
attr_accessor :language
|
22
10
|
|
23
11
|
# `source` string contains annotated source code
|
24
12
|
# `source_type` is one of supported source types (currently `[:ruby, :javascript]`)
|
25
|
-
def initialize(source, source_type,
|
13
|
+
def initialize(source, source_type, do_not_count_comment_lines = false)
|
26
14
|
self.source_type = source_type
|
27
|
-
self.
|
15
|
+
self.language = Languages.get(source_type)
|
28
16
|
self.source = source
|
17
|
+
self.paragraphs = if !language.annotation_only?
|
18
|
+
Scanner.new(language).call(source, do_not_count_comment_lines)
|
19
|
+
else
|
20
|
+
[Paragraph.new('', source, 0, nil)]
|
21
|
+
end
|
29
22
|
end
|
30
23
|
|
31
24
|
|
32
25
|
# You may also initialize annotator from file, it will even try to detect the
|
33
26
|
# source type from extension.
|
34
|
-
def self.from_file(filename, source_type = nil,
|
27
|
+
def self.from_file(filename, source_type = nil, do_not_count_comment_lines = false)
|
35
28
|
self.new(File.read(filename),
|
36
|
-
source_type ||
|
37
|
-
|
29
|
+
source_type || Languages.detect(filename),
|
30
|
+
do_not_count_comment_lines)
|
38
31
|
end
|
39
32
|
|
40
33
|
def source_type
|
@@ -42,122 +35,7 @@ module Murdoc
|
|
42
35
|
end
|
43
36
|
|
44
37
|
def source_type=(source_type)
|
45
|
-
@source_type = source_type.
|
46
|
-
end
|
47
|
-
|
48
|
-
# Big and hairy code parser
|
49
|
-
def source=(src)
|
50
|
-
@source = src
|
51
|
-
@paragraphs = []
|
52
|
-
lines = src.split("\n")
|
53
|
-
|
54
|
-
# splitting stuff into lines and setting cursor into initial position
|
55
|
-
i = 0
|
56
|
-
source_lines_counter = 0
|
57
|
-
while i < lines.size
|
58
|
-
comment_lines = []
|
59
|
-
# get single line comments
|
60
|
-
if comment_symbols[:single_line]
|
61
|
-
while i < lines.size && lines[i] =~ /^\s*#{Regexp.escape(comment_symbols[:single_line])}(.*)/
|
62
|
-
comment_lines << $1
|
63
|
-
i += 1
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
# getting multiline comments
|
68
|
-
if comment_symbols[:multiline]
|
69
|
-
begin_symbol = Regexp.escape(comment_symbols[:multiline][:begin])
|
70
|
-
end_symbol = Regexp.escape(comment_symbols[:multiline][:end])
|
71
|
-
if i < lines.size && lines[i] =~ /\s*#{begin_symbol}/
|
72
|
-
begin
|
73
|
-
match = lines[i].match /\s*(#{begin_symbol})?\s?(.*?)(#{end_symbol}|$)/
|
74
|
-
comment_lines << match[2]
|
75
|
-
i += 1
|
76
|
-
end while i < lines.size && !(lines[i-1] =~ /\s*#{end_symbol}/)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# getting source lines
|
81
|
-
source_lines = []
|
82
|
-
starting_line = if options[:do_not_count_comment_lines]
|
83
|
-
source_lines_counter
|
84
|
-
else
|
85
|
-
i
|
86
|
-
end
|
87
|
-
|
88
|
-
while i < lines.size && !is_comment(lines[i])
|
89
|
-
source_lines << lines[i]
|
90
|
-
source_lines_counter += 1
|
91
|
-
i += 1
|
92
|
-
end
|
93
|
-
|
94
|
-
# post-processing: stripping comments and removing empty strings from beginnings and ends
|
95
|
-
starting_line += postprocess_source(source_lines)
|
96
|
-
postprocess_comments(comment_lines)
|
97
|
-
# clear comment lines if that's commented out code
|
98
|
-
comment_lines.clear if comment_lines[0] =~ /^:code:$/
|
99
|
-
|
100
|
-
# if we have comments or source
|
101
|
-
if comment_lines.size > 0 || source_lines.size > 0
|
102
|
-
@paragraphs << Paragraph.new(source_lines.join("\n"),
|
103
|
-
comment_lines.join("\n"),
|
104
|
-
starting_line,
|
105
|
-
source_type,
|
106
|
-
options)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
# Rest of the file quite less self-explanatory
|
112
|
-
def source
|
113
|
-
@source
|
114
|
-
end
|
115
|
-
|
116
|
-
protected
|
117
|
-
def comment_symbols
|
118
|
-
super || {}
|
119
|
-
end
|
120
|
-
|
121
|
-
# Method for checking source for comments. Used for getting consequent non-comments
|
122
|
-
# into resulting stream
|
123
|
-
def is_comment(line)
|
124
|
-
result = false
|
125
|
-
# If source supports single line comments
|
126
|
-
if comment_symbols[:single_line]
|
127
|
-
result ||= line =~ /^\s*#{Regexp.escape(comment_symbols[:single_line])}/
|
128
|
-
end
|
129
|
-
|
130
|
-
# If source supports multi-line comments
|
131
|
-
if comment_symbols[:multiline]
|
132
|
-
result ||= line =~ /^\s*#{Regexp.escape(comment_symbols[:multiline][:begin])}/
|
133
|
-
end
|
134
|
-
result
|
135
|
-
end
|
136
|
-
|
137
|
-
#
|
138
|
-
# Removes trailing spaces from comments, also removes first space from comments,
|
139
|
-
# but only if there's only one space there (not to mess with markdown)
|
140
|
-
#
|
141
|
-
def postprocess_comments(comment_lines)
|
142
|
-
comment_lines.map! {|l| l.sub(/^\s([^\s])/, '\\1').rstrip }
|
143
|
-
comment_lines.delete_at(0) while comment_lines.size > 0 && comment_lines[0].empty?
|
144
|
-
comment_lines.delete_at(-1) while comment_lines.size > 0 && comment_lines[-1].empty?
|
145
|
-
end
|
146
|
-
|
147
|
-
|
148
|
-
# Removes blank lines from beginning and end of source lines
|
149
|
-
# returns starting offset for source (number of lines deleted from beginning)
|
150
|
-
def postprocess_source(source_lines)
|
151
|
-
starting_offset = 0
|
152
|
-
while source_lines.size > 0 && source_lines[0] =~ /^\s*$/
|
153
|
-
starting_offset += 1
|
154
|
-
source_lines.delete_at(0)
|
155
|
-
end
|
156
|
-
|
157
|
-
while source_lines.size > 0 && source_lines[-1] =~ /^\s*$/
|
158
|
-
source_lines.delete_at(-1)
|
159
|
-
end
|
160
|
-
starting_offset
|
38
|
+
@source_type = (source_type || :base).to_sym
|
161
39
|
end
|
162
40
|
end
|
163
41
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module Murdoc
|
3
|
+
class FormattedParagraph
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
def_delegators :paragraph, :annotation, :source, :starting_line, :source_type
|
7
|
+
|
8
|
+
attr_reader :paragraph
|
9
|
+
attr_reader :highlight
|
10
|
+
|
11
|
+
def initialize(paragraph, highlight = true)
|
12
|
+
@paragraph = paragraph
|
13
|
+
@highlight = highlight
|
14
|
+
end
|
15
|
+
|
16
|
+
def formatted_annotation
|
17
|
+
if defined?(Markdown)
|
18
|
+
Markdown.new(annotation, :smart).to_html
|
19
|
+
else
|
20
|
+
Kramdown::Document.new(annotation, :input => :markdown).to_html
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def formatted_source
|
25
|
+
@formatted_source ||= if pygments_installed? && highlight && source_type != :base
|
26
|
+
IO.popen("pygmentize -l #{source_type} -O encoding=UTF8 -f html -O nowrap", "w+") do |pipe|
|
27
|
+
pipe.puts source
|
28
|
+
pipe.close_write
|
29
|
+
pipe.read
|
30
|
+
end
|
31
|
+
else
|
32
|
+
CGI.escapeHTML(source)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
def pygments_installed?
|
38
|
+
@@pygments_installed ||= ENV['PATH'].split(':').any? { |dir| File.exist?("#{dir}/pygmentize") }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|