murdoc 0.2.0 → 0.2.1
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/README.md +27 -12
- data/bin/murdoc-tree +48 -0
- data/lib/murdoc.rb +100 -2
- data/lib/murdoc/annotator.rb +18 -6
- data/lib/murdoc/formatted_paragraph.rb +1 -1
- data/lib/murdoc/paragraph.rb +12 -0
- data/lib/murdoc/version.rb +1 -1
- data/markup/template.haml +7 -1
- data/markup/template_index.haml +20 -0
- data/markup/template_multifile.haml +6 -0
- data/spec/murdoc/annotator_spec.rb +19 -0
- data/spec/murdoc/paragraph_spec.rb +12 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7770978eea693f9a8464f272ed228ecd76fc3493
|
4
|
+
data.tar.gz: 9943ca4db60ec141f2088ff9d652f5f2949fbd7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 858b23df3485164ec8630973857152ee8f90901bf6a1ae903cbadb3ac64548e239fb3d8b8eb6d1a06891d14541a108829c09f853f04932c19178f7f069ee208e
|
7
|
+
data.tar.gz: cdc220eb7da112690d7605b0ee4c54db009112dfad38ebf4b7674b627128bd92222085a7121b7b846198eb70d378f5809536e5d665eae5140628f91fbff74aa9
|
data/README.md
CHANGED
@@ -1,12 +1,29 @@
|
|
1
|
-
Murdoc
|
1
|
+
Murdoc — a ruby documenter
|
2
2
|
==============================
|
3
3
|
|
4
4
|
Murdoc is a doccu-style annotated documentation generator.
|
5
5
|
|
6
|
-
|
6
|
+
Rationale
|
7
|
+
---------
|
8
|
+
|
9
|
+
Sometimes it makes sense to create a guide, a story told by code and comments side by side. Murdoc generates a pretty html for such a story.
|
10
|
+
|
11
|
+
Example
|
12
|
+
-------
|
13
|
+
|
14
|
+
Demo at [GH.pages](http://jsus.github.io/murdoc).
|
15
|
+
|
16
|
+
See also:
|
17
|
+
|
18
|
+
* [example](http://jsus.github.io/murdoc/docs) of integration with [jsus](http://github.com/jsus/jsus)
|
19
|
+
|
20
|
+
Usage
|
21
|
+
-----
|
22
|
+
|
23
|
+
* `gem install murdoc`
|
24
|
+
* `murdoc <input file> <output html file>` **or**
|
25
|
+
* `murdoc <input file 1> <input file 2> ... <output html file>`
|
7
26
|
|
8
|
-
* [docco.coffee](http://jashkenas.github.com/docco/)
|
9
|
-
* [Rocco](http://rtomayko.github.com/rocco/)
|
10
27
|
|
11
28
|
Dependencies
|
12
29
|
------------
|
@@ -14,16 +31,14 @@ Dependencies
|
|
14
31
|
* Haml
|
15
32
|
* Either RDiscount (for MRI rubies) or Kramdown (for non-mri rubies)
|
16
33
|
|
17
|
-
Example
|
18
|
-
-------
|
19
|
-
|
20
|
-
See example at [GH.pages](http://jsus.github.com/murdoc).
|
21
|
-
|
22
|
-
See also:
|
23
|
-
* [example](http://jsus.github.com/murdoc/docs) of integration with [jsus](http://github.com/jsus/jsus)
|
24
|
-
* [LSD documentation guides](https://github.com/lovelyscalabledrawings/lsd-guides/tree/gh-pages/grid)
|
25
34
|
|
26
35
|
License
|
27
36
|
-------
|
28
37
|
|
29
38
|
Public domain, see UNLICENSE file.
|
39
|
+
|
40
|
+
See also
|
41
|
+
--------
|
42
|
+
|
43
|
+
* [docco.coffee](http://jashkenas.github.io/docco/)
|
44
|
+
* [Rocco](http://rtomayko.github.io/rocco/)
|
data/bin/murdoc-tree
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "optparse"
|
3
|
+
$: << File.expand_path("../../lib/", __FILE__)
|
4
|
+
require "murdoc"
|
5
|
+
|
6
|
+
options = {}
|
7
|
+
|
8
|
+
option_parser = OptionParser.new do |opts|
|
9
|
+
opts.banner = "#{$0} <input dir> <output dir>"
|
10
|
+
|
11
|
+
opts.on('--index-template [FILENAME]', 'template to use for index files') do |template|
|
12
|
+
options[:index_template] = template
|
13
|
+
end
|
14
|
+
|
15
|
+
opts.on('--index-stylesheet [FILENAME]', 'stylesheet to use for index files') do |stylesheet|
|
16
|
+
options[:index_stylesheet] = stylesheet
|
17
|
+
end
|
18
|
+
|
19
|
+
opts.on('--template [FILENAME]', 'template to use for other files') do |template|
|
20
|
+
options[:template] = template
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on('--stylesheet [FILENAME]', 'stylesheet to use for other files') do |stylesheet|
|
24
|
+
options[:stylesheet] = stylesheet
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("--[no-]syntax-highlight", "Highlight syntax using pygments") do |h|
|
28
|
+
options[:highlight] = h
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("--do-not-count-comment-lines") do |dncl|
|
32
|
+
options[:do_not_count_comment_lines] = dncl
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
36
|
+
puts opts
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
option_parser.parse!
|
42
|
+
|
43
|
+
if ARGV.size != 2
|
44
|
+
puts option_parser
|
45
|
+
exit(1)
|
46
|
+
else
|
47
|
+
Murdoc.generate_tree(ARGV[0], ARGV[1], false, nil, options)
|
48
|
+
end
|
data/lib/murdoc.rb
CHANGED
@@ -8,20 +8,29 @@
|
|
8
8
|
# [ro]: "http://rtomayko.github.com/rocco"
|
9
9
|
#
|
10
10
|
|
11
|
+
require 'fileutils'
|
12
|
+
require 'pathname'
|
11
13
|
|
12
14
|
module Murdoc
|
13
|
-
AnnotatedFile
|
15
|
+
# `AnnotatedFile` is a struct we pass into our templates
|
16
|
+
AnnotatedFile = Struct.new(:filename, :metadata, :source, :source_type, :paragraphs, :formatted_paragraphs)
|
14
17
|
|
18
|
+
# `Murdoc.annotate` arguments are gathered from CLI utility
|
19
|
+
#
|
20
|
+
# `highlight` regulates syntax highlighting and `do_not_count_comment_lines` flag
|
21
|
+
# toggles counting comment lines towards line numbering in the output.
|
15
22
|
def self.annotate(filename, highlight = true, do_not_count_comment_lines = false)
|
16
23
|
filename = File.expand_path(filename)
|
17
24
|
annotator = Annotator.from_file(filename, nil, do_not_count_comment_lines)
|
18
25
|
AnnotatedFile.new(filename,
|
26
|
+
annotator.metadata,
|
19
27
|
annotator.source,
|
20
28
|
annotator.source_type,
|
21
29
|
annotator.paragraphs,
|
22
30
|
annotator.paragraphs.map {|p| FormattedParagraph.new(p, highlight) })
|
23
31
|
end
|
24
32
|
|
33
|
+
# Generate a single file story
|
25
34
|
def self.generate_from_file(input, output, options = {})
|
26
35
|
options = default_options.merge(options)
|
27
36
|
annotator = Annotator.from_file(input, nil)
|
@@ -32,6 +41,7 @@ module Murdoc
|
|
32
41
|
end
|
33
42
|
end
|
34
43
|
|
44
|
+
# ... or use multiple files
|
35
45
|
def self.generate_from_multiple_files(input_files, output, options = {})
|
36
46
|
options = default_options_for_multiple_files.merge(options)
|
37
47
|
annotated_files = input_files.map {|fn| annotate(fn, options[:highlight], options[:do_not_count_comment_lines]) }
|
@@ -41,6 +51,69 @@ module Murdoc
|
|
41
51
|
end
|
42
52
|
end
|
43
53
|
|
54
|
+
# Generate a documentation tree
|
55
|
+
def self.generate_tree(input_dir, output_dir, has_parent = false, base_dir = nil, options = {})
|
56
|
+
options = default_options_for_tree.merge(options)
|
57
|
+
input_dir = Pathname(input_dir).expand_path
|
58
|
+
output_dir = Pathname(output_dir).expand_path
|
59
|
+
base_dir ||= input_dir
|
60
|
+
|
61
|
+
FileUtils.mkdir_p(output_dir)
|
62
|
+
|
63
|
+
entries = input_dir.children
|
64
|
+
|
65
|
+
directories = entries.select(&:directory?).
|
66
|
+
reject {|dir| dir == output_dir }.
|
67
|
+
reject {|dir| dir.basename.to_s.start_with?('.')}
|
68
|
+
directories.each do |dir|
|
69
|
+
next if dir == output_dir
|
70
|
+
generate_tree(dir,
|
71
|
+
output_dir + dir.relative_path_from(input_dir),
|
72
|
+
true,
|
73
|
+
base_dir,
|
74
|
+
options)
|
75
|
+
end
|
76
|
+
|
77
|
+
files = entries.select(&:file?).select {|file| Languages.detect(file.to_s) }
|
78
|
+
files.each do |file|
|
79
|
+
relpath = file.relative_path_from(input_dir)
|
80
|
+
generate_from_file(file, "#{output_dir}/#{relpath}.html", {
|
81
|
+
highlight: options[:highlight],
|
82
|
+
template: options[:template],
|
83
|
+
stylesheet: options[:stylesheet],
|
84
|
+
do_not_count_comment_lines: options[:do_not_count_comment_lines]
|
85
|
+
})
|
86
|
+
end
|
87
|
+
|
88
|
+
unless files.empty? && directories.empty?
|
89
|
+
generate_index("#{output_dir}/index.html", {
|
90
|
+
current_directory: input_dir,
|
91
|
+
files: files,
|
92
|
+
directories: directories,
|
93
|
+
has_parent: has_parent,
|
94
|
+
base_dir: base_dir,
|
95
|
+
template: options[:index_template],
|
96
|
+
stylesheet: options[:index_stylesheet]
|
97
|
+
})
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.generate_index(fn, options)
|
102
|
+
options = default_options_for_index.merge(options)
|
103
|
+
File.open(fn, 'w+') do |f|
|
104
|
+
f.puts Renderer.new(options[:template]).render({
|
105
|
+
stylesheet: File.read(options[:stylesheet]),
|
106
|
+
base_dir: options[:base_dir],
|
107
|
+
has_parent: options[:has_parent],
|
108
|
+
current_directory: options[:current_directory],
|
109
|
+
files: options[:files],
|
110
|
+
directories: options[:directories]
|
111
|
+
})
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
# Rest is self-explanatory
|
44
117
|
def self.default_options
|
45
118
|
@options ||= {
|
46
119
|
template: "#{markup_dir}/template.haml",
|
@@ -50,16 +123,41 @@ module Murdoc
|
|
50
123
|
end
|
51
124
|
|
52
125
|
def self.default_options_for_multiple_files
|
53
|
-
@
|
126
|
+
@options_multi ||= {
|
54
127
|
template: "#{markup_dir}/template_multifile.haml",
|
55
128
|
stylesheet: "#{markup_dir}/stylesheet.css",
|
56
129
|
highlight: true
|
57
130
|
}
|
58
131
|
end
|
59
132
|
|
133
|
+
def self.default_options_for_tree
|
134
|
+
@options_tree ||= {
|
135
|
+
index_template: default_options_for_index[:template],
|
136
|
+
index_stylesheet: default_options_for_index[:stylesheet],
|
137
|
+
template: default_options[:template],
|
138
|
+
stylesheet: default_options[:stylesheet],
|
139
|
+
highlight: default_options[:highlight],
|
140
|
+
do_not_count_comment_lines: false
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.default_options_for_index
|
145
|
+
@options_index ||= {
|
146
|
+
template: "#{markup_dir}/template_index.haml",
|
147
|
+
stylesheet: "#{markup_dir}/stylesheet.css"
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
60
151
|
def self.markup_dir
|
61
152
|
File.expand_path("../..", __FILE__)+ "/markup"
|
62
153
|
end
|
154
|
+
|
155
|
+
|
156
|
+
def self.try_load_yaml(yaml)
|
157
|
+
YAML.load(yaml)
|
158
|
+
rescue => e
|
159
|
+
nil
|
160
|
+
end
|
63
161
|
end
|
64
162
|
|
65
163
|
require "murdoc/annotator"
|
data/lib/murdoc/annotator.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
1
3
|
module Murdoc
|
2
4
|
class Annotator
|
3
5
|
attr_accessor :source
|
4
|
-
|
6
|
+
attr_accessor :metadata
|
5
7
|
# Attribute accessor containing the resulting paragraphs
|
6
8
|
attr_accessor :paragraphs
|
7
9
|
|
@@ -11,14 +13,15 @@ module Murdoc
|
|
11
13
|
# `source` string contains annotated source code
|
12
14
|
# `source_type` is one of supported source types (currently `[:ruby, :javascript]`)
|
13
15
|
def initialize(source, source_type, do_not_count_comment_lines = false)
|
16
|
+
self.source = source
|
14
17
|
self.source_type = source_type
|
15
|
-
self.language
|
16
|
-
self.
|
17
|
-
|
18
|
-
Scanner.new(language).call(source, do_not_count_comment_lines)
|
18
|
+
self.language = Languages.get(source_type)
|
19
|
+
self.paragraphs = if !language.annotation_only?
|
20
|
+
Scanner.new(language).call(self.source, do_not_count_comment_lines)
|
19
21
|
else
|
20
|
-
[Paragraph.new('', source, 0, nil)]
|
22
|
+
[Paragraph.new('', self.source, 0, nil)]
|
21
23
|
end
|
24
|
+
extract_metadata!
|
22
25
|
end
|
23
26
|
|
24
27
|
|
@@ -30,6 +33,15 @@ module Murdoc
|
|
30
33
|
do_not_count_comment_lines)
|
31
34
|
end
|
32
35
|
|
36
|
+
def extract_metadata!
|
37
|
+
if paragraphs.count > 0 && paragraphs[0].annotation =~ /\A\s*---\n(.*?)\n\s*---\n?(.*)\z/m
|
38
|
+
paragraphs[0].annotation = $2
|
39
|
+
self.metadata = Murdoc.try_load_yaml($1)
|
40
|
+
else
|
41
|
+
self.metadata = {}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
33
45
|
def source_type
|
34
46
|
@source_type
|
35
47
|
end
|
@@ -3,7 +3,7 @@ module Murdoc
|
|
3
3
|
class FormattedParagraph
|
4
4
|
extend Forwardable
|
5
5
|
|
6
|
-
def_delegators :paragraph, :annotation, :source, :starting_line, :source_type
|
6
|
+
def_delegators :paragraph, :annotation, :source, :starting_line, :source_type, :metadata
|
7
7
|
|
8
8
|
attr_reader :paragraph
|
9
9
|
attr_reader :highlight
|
data/lib/murdoc/paragraph.rb
CHANGED
@@ -6,6 +6,7 @@ rescue LoadError
|
|
6
6
|
end
|
7
7
|
require "cgi"
|
8
8
|
require "tempfile"
|
9
|
+
require "yaml"
|
9
10
|
|
10
11
|
module Murdoc
|
11
12
|
class Paragraph
|
@@ -13,12 +14,23 @@ module Murdoc
|
|
13
14
|
attr_accessor :annotation
|
14
15
|
attr_accessor :source_type
|
15
16
|
attr_accessor :starting_line
|
17
|
+
attr_accessor :metadata
|
16
18
|
|
17
19
|
def initialize(source, annotation, starting_line = 0, source_type = nil)
|
18
20
|
self.source = source
|
19
21
|
self.annotation = annotation
|
20
22
|
self.starting_line = starting_line
|
21
23
|
self.source_type = source_type
|
24
|
+
extract_metadata!
|
25
|
+
end
|
26
|
+
|
27
|
+
def extract_metadata!
|
28
|
+
if annotation =~ /(.*\n)?^---!([^\n]*)\n?(.*)\z/m
|
29
|
+
self.metadata = Murdoc.try_load_yaml($2)
|
30
|
+
self.annotation = $1.to_s + $3.to_s
|
31
|
+
else
|
32
|
+
self.metadata = {}
|
33
|
+
end
|
22
34
|
end
|
23
35
|
end
|
24
36
|
end
|
data/lib/murdoc/version.rb
CHANGED
data/markup/template.haml
CHANGED
@@ -2,10 +2,16 @@
|
|
2
2
|
%html
|
3
3
|
%head
|
4
4
|
%title Murdoc
|
5
|
-
%style=stylesheet
|
5
|
+
%style= stylesheet
|
6
6
|
%body
|
7
7
|
.document{:class => annotated_file.source_type}
|
8
|
+
/
|
9
|
+
metadata:
|
10
|
+
= annotated_file.metadata.inspect
|
8
11
|
- annotated_file.formatted_paragraphs.each do |p|
|
12
|
+
/
|
13
|
+
paragraph metadata:
|
14
|
+
= p.metadata.inspect
|
9
15
|
- unless p.annotation.empty?
|
10
16
|
%section= p.formatted_annotation
|
11
17
|
- unless p.source.empty?
|
@@ -0,0 +1,20 @@
|
|
1
|
+
!!!
|
2
|
+
- reldir = current_directory == base_dir ? base_dir.basename : current_directory.relative_path_from(base_dir)
|
3
|
+
%html
|
4
|
+
%head
|
5
|
+
%title Murdoc / #{reldir}
|
6
|
+
%style= stylesheet
|
7
|
+
%body
|
8
|
+
.document.index
|
9
|
+
%section
|
10
|
+
%h2 #{reldir}
|
11
|
+
%ul
|
12
|
+
- if has_parent
|
13
|
+
%li
|
14
|
+
%a{:href => "../index.html"} ..
|
15
|
+
- directories.each do |dir|
|
16
|
+
%li
|
17
|
+
%a{:href => "#{dir.basename}/index.html"}= dir.basename
|
18
|
+
- files.each do |file|
|
19
|
+
%li
|
20
|
+
%a{:href => "#{file.basename}.html"}= file.basename
|
@@ -6,7 +6,13 @@
|
|
6
6
|
%body
|
7
7
|
- annotated_files.each do |af|
|
8
8
|
.document{:class => af.source_type}
|
9
|
+
/
|
10
|
+
metadata:
|
11
|
+
= af.metadata.inspect
|
9
12
|
- af.formatted_paragraphs.each_with_index do |p, j|
|
13
|
+
/
|
14
|
+
paragraph metadata:
|
15
|
+
= p.metadata.inspect
|
10
16
|
%section
|
11
17
|
- if j == 0
|
12
18
|
%label= File.basename(af.filename)
|
@@ -124,4 +124,23 @@ describe Murdoc::Annotator do
|
|
124
124
|
subject.paragraphs[0].source.should == "def hi\n\nend"
|
125
125
|
end
|
126
126
|
end
|
127
|
+
|
128
|
+
describe "metadata extraction" do
|
129
|
+
subject { described_class.new("# ---\n# foo: 'bar'\n# baz: 'foobar'\n# ---\nhello, world!", :ruby) }
|
130
|
+
it "extracts and parses yaml blocks in the beginning of the file" do
|
131
|
+
subject.metadata.should == {
|
132
|
+
'foo' => 'bar',
|
133
|
+
'baz' => 'foobar'
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
it "cuts metadata from the paragraph annotation text" do
|
138
|
+
subject.paragraphs[0].annotation.should_not include('---')
|
139
|
+
end
|
140
|
+
|
141
|
+
it "doesn't raise on invalid yaml" do
|
142
|
+
subject = described_class.new("---\n{\n---\nfoo bar", :ruby)
|
143
|
+
subject.metadata.should == {}
|
144
|
+
end
|
145
|
+
end
|
127
146
|
end
|
@@ -17,5 +17,17 @@ describe Murdoc::Paragraph do
|
|
17
17
|
it "should optionally set starting line" do
|
18
18
|
described_class.new("", "", 666, :ruby).starting_line.should == 666
|
19
19
|
end
|
20
|
+
|
21
|
+
it "extracts metadata" do
|
22
|
+
subject = described_class.new("", "---! {'foo': 'bar'}\nbaz")
|
23
|
+
subject.metadata.should == {'foo' => 'bar'}
|
24
|
+
subject.annotation.should == 'baz'
|
25
|
+
end
|
26
|
+
|
27
|
+
it "extracts metadata from the middle of annotation too" do
|
28
|
+
subject = described_class.new("", "foo\n---! {bar: 'baz'}\nfoo2")
|
29
|
+
subject.metadata.should == {'bar' => 'baz'}
|
30
|
+
subject.annotation.should == "foo\nfoo2"
|
31
|
+
end
|
20
32
|
end
|
21
33
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: murdoc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Abramov
|
@@ -99,6 +99,7 @@ email: markizko@gmail.com
|
|
99
99
|
executables:
|
100
100
|
- murdoc
|
101
101
|
- murdoc-strip-comments
|
102
|
+
- murdoc-tree
|
102
103
|
extensions: []
|
103
104
|
extra_rdoc_files: []
|
104
105
|
files:
|
@@ -112,6 +113,7 @@ files:
|
|
112
113
|
- UNLICENSE
|
113
114
|
- bin/murdoc
|
114
115
|
- bin/murdoc-strip-comments
|
116
|
+
- bin/murdoc-tree
|
115
117
|
- lib/murdoc.rb
|
116
118
|
- lib/murdoc/annotator.rb
|
117
119
|
- lib/murdoc/formatted_paragraph.rb
|
@@ -127,6 +129,7 @@ files:
|
|
127
129
|
- lib/murdoc/version.rb
|
128
130
|
- markup/stylesheet.css
|
129
131
|
- markup/template.haml
|
132
|
+
- markup/template_index.haml
|
130
133
|
- markup/template_multifile.haml
|
131
134
|
- murdoc.gemspec
|
132
135
|
- spec/murdoc/annotator_spec.rb
|