murdoc 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6ef249b35659b0df1ac35d233d7ded20dc29e45b
4
- data.tar.gz: 7017b589cae5baf9511e1aaf065931b32d30c75a
3
+ metadata.gz: 7770978eea693f9a8464f272ed228ecd76fc3493
4
+ data.tar.gz: 9943ca4db60ec141f2088ff9d652f5f2949fbd7c
5
5
  SHA512:
6
- metadata.gz: 935006a39b60ce7b2d6c2d1c4eb8247758f36a60a2ce2174757d8befea55231dc5916b3c167d8d1c26b1f693c7eff06b0a7c7c4ca0f2713c12791b0b9d102e15
7
- data.tar.gz: 87622f60399b0217f751cfa09b60eeea353d2af8a00727293057feaffac8de8ebc25ad3a7a5f5a16c186e57466214cb725911abde2fddaf922697ae7682a6227
6
+ metadata.gz: 858b23df3485164ec8630973857152ee8f90901bf6a1ae903cbadb3ac64548e239fb3d8b8eb6d1a06891d14541a108829c09f853f04932c19178f7f069ee208e
7
+ data.tar.gz: cdc220eb7da112690d7605b0ee4c54db009112dfad38ebf4b7674b627128bd92222085a7121b7b846198eb70d378f5809536e5d665eae5140628f91fbff74aa9
data/README.md CHANGED
@@ -1,12 +1,29 @@
1
- Murdoc -- ruby documenter
1
+ Murdoc a ruby documenter
2
2
  ==============================
3
3
 
4
4
  Murdoc is a doccu-style annotated documentation generator.
5
5
 
6
- You may also want to see:
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/)
@@ -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
@@ -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 = Struct.new(:filename, :source, :source_type, :paragraphs, :formatted_paragraphs)
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
- @options ||= {
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"
@@ -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 = Languages.get(source_type)
16
- self.source = source
17
- self.paragraphs = if !language.annotation_only?
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Murdoc
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
@@ -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.0
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