murdoc 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ UNLICENSE.txt
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --autotest
2
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "jeweler"
4
+ gem "rspec", "~> 2.1.0"
5
+ gem "rdiscount", "~> 1.6.5"
6
+ gem "haml", "~> 3.0.0"
7
+ gem "sass", "~> 3.1.0"
@@ -0,0 +1,31 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ git (1.2.5)
6
+ haml (3.0.24)
7
+ jeweler (1.5.1)
8
+ bundler (~> 1.0.0)
9
+ git (>= 1.2.5)
10
+ rake
11
+ rake (0.8.7)
12
+ rdiscount (1.6.5)
13
+ rspec (2.1.0)
14
+ rspec-core (~> 2.1.0)
15
+ rspec-expectations (~> 2.1.0)
16
+ rspec-mocks (~> 2.1.0)
17
+ rspec-core (2.1.0)
18
+ rspec-expectations (2.1.0)
19
+ diff-lcs (~> 1.1.2)
20
+ rspec-mocks (2.1.0)
21
+ sass (3.1.0.alpha.39)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ haml (~> 3.0.0)
28
+ jeweler
29
+ rdiscount (~> 1.6.5)
30
+ rspec (~> 2.1.0)
31
+ sass (~> 3.1.0)
@@ -0,0 +1,19 @@
1
+ Murdoc -- evil ruby documenter
2
+ ==============================
3
+
4
+ Murdoc is a doccu-style annotated documentation generator.
5
+
6
+ You may also want to see:
7
+
8
+ * [docco.coffee](http://jashkenas.github.com/docco/)
9
+ * [Rocco](http://rtomayko.github.com/rocco/)
10
+
11
+ Example
12
+ =======
13
+
14
+ See example at [GH.pages](http://markiz.github.com/murdoc).
15
+
16
+ License and authorship
17
+ ======================
18
+
19
+ Murdoc is originally authored by Mark Abramov and belongs to public domain (see UNLICENSE for details).
@@ -0,0 +1,48 @@
1
+ require 'rubygems'
2
+ require 'bundler'
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.add_runtime_dependency "haml", "~> 3.0.0"
23
+ gem.add_runtime_dependency "rdiscount", "~> 1.6.5"
24
+ end
25
+ Jeweler::RubygemsDotOrgTasks.new
26
+
27
+ require 'rspec/core'
28
+ require 'rspec/core/rake_task'
29
+ RSpec::Core::RakeTask.new(:spec) do |spec|
30
+ spec.pattern = FileList['spec/**/*_spec.rb']
31
+ end
32
+
33
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
34
+ spec.pattern = 'spec/**/*_spec.rb'
35
+ spec.rcov = true
36
+ end
37
+
38
+ task :default => :spec
39
+
40
+ require 'rake/rdoctask'
41
+ Rake::RDocTask.new do |rdoc|
42
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
43
+
44
+ rdoc.rdoc_dir = 'rdoc'
45
+ rdoc.title = "murdoc #{version}"
46
+ rdoc.rdoc_files.include('README*')
47
+ rdoc.rdoc_files.include('lib/**/*.rb')
48
+ end
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ require "optparse"
3
+ $: << "./lib/"
4
+ require "murdoc"
5
+
6
+
7
+
8
+ option_parser = OptionParser.new do |opts|
9
+ opts.banner = "murdoc <input file> <output html>"
10
+
11
+ opts.on_tail("-h", "--help", "Show this message") do
12
+ puts opts
13
+ exit
14
+ end
15
+
16
+ end
17
+
18
+ option_parser.parse!
19
+
20
+ if ARGV.size < 2
21
+ puts option_parser
22
+ else
23
+ Murdoc.generate_from_file(ARGV[0], ARGV[1])
24
+ end
@@ -0,0 +1,25 @@
1
+ #
2
+ # Murdoc is *yet another* Doccu-like documentation generator.
3
+ # Murdoc reads ruby source files and produces annotated html documentation.
4
+ #
5
+ # See also: [Docco][do], [Rocco][ro]
6
+ #
7
+ # [do]: "http://jashkenas.github.com/docco/"
8
+ # [ro]: "http://rtomayko.github.com/rocco"
9
+ #
10
+
11
+
12
+ module Murdoc
13
+ def self.generate_from_file(input, output)
14
+ annotator = Annotator.from_file(input)
15
+ File.open(output, "w+") do |f|
16
+ f.puts Formatter.new("markup/template.haml").render(:paragraphs => annotator.paragraphs, :stylesheet => File.read("markup/stylesheet.css"))
17
+ end
18
+ end
19
+ end
20
+
21
+ require "murdoc/annotator"
22
+ require "murdoc/paragraph"
23
+ require "murdoc/formatter"
24
+
25
+ Dir["#{File.dirname(File.expand_path(__FILE__))}/murdoc/languages/*.rb"].each {|lang| require lang }
@@ -0,0 +1,112 @@
1
+ # Annotator class does all the main job: parses out comments
2
+ # and returns annotated code
3
+
4
+
5
+ # Main module
6
+ module Murdoc
7
+ class Annotator
8
+ # Attribute accessor containing the resulting paragraphs
9
+ attr_accessor :paragraphs
10
+
11
+
12
+ # `source` string contains annotated source code
13
+ # `source_type` is one of supported source types (currently `[:ruby, :javascript]`)
14
+ def initialize(source, source_type)
15
+ self.source_type = source_type
16
+ self.source = source
17
+ end
18
+
19
+ # You may also initialize annotator from file, it will even try to detect the
20
+ # source type from extension.
21
+ def self.from_file(filename, source_type = nil)
22
+ self.new(File.read(filename), source_type || detect_source_type_from_filename(filename))
23
+ end
24
+
25
+ def source_type
26
+ @source_type
27
+ end
28
+
29
+ def source_type=(source_type)
30
+ @source_type = source_type.to_s
31
+ end
32
+
33
+ # Big and hairy code parser
34
+ def source=(src)
35
+ @source = src
36
+ @paragraphs = []
37
+
38
+ # Lambda for checking source for comments. Used for getting consequent non-comments
39
+ # into resulting stream
40
+ is_comment = lambda do |line|
41
+ result = false
42
+ # If source supports single line comments
43
+ if comment_symbols[:single_line]
44
+ result ||= line =~ /^\s*#{Regexp.escape(comment_symbols[:single_line])}/
45
+ end
46
+
47
+ # If source supports multi-line comments
48
+ if comment_symbols[:multiline]
49
+ result ||= line =~ /^\s*#{Regexp.escape(comment_symbols[:multiline][:begin])}/
50
+ end
51
+ result
52
+ end
53
+
54
+ # splitting stuff into lines and setting cursor into initial position
55
+ lines = src.split("\n")
56
+ i = 0
57
+ while i < lines.size
58
+ comment_lines = []
59
+ # get single line comments (removing optional first space after comment symbol)
60
+ if comment_symbols[:single_line]
61
+ while i < lines.size && lines[i] =~ /^\s*#{Regexp.escape(comment_symbols[:single_line])}\s?(.*)/
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
+ starting_line = i
82
+ source_lines = []
83
+ while i < lines.size && !is_comment.call(lines[i])
84
+ source_lines << lines[i]
85
+ i += 1
86
+ end
87
+ # post-processing: stripping comments and removing empty strings from beginnings and ends
88
+ while source_lines.size > 0 && source_lines[0] =~ /^\s*$/
89
+ starting_line += 1
90
+ source_lines.delete_at(0)
91
+ end
92
+ source_lines.delete_at(-1) while source_lines.size > 0 && source_lines[-1] =~ /^\s*$/
93
+ comment_lines.map! {|l| l.strip }
94
+ comment_lines.delete_at(0) while comment_lines.size > 0 && comment_lines[0].empty?
95
+ comment_lines.delete_at(-1) while comment_lines.size > 0 && comment_lines[-1].empty?
96
+
97
+ # writing a new paragraph
98
+ @paragraphs << Paragraph.new(source_lines.join("\n"), comment_lines.join("\n"), starting_line, source_type)
99
+ end
100
+ end
101
+
102
+ # Rest of the file quite less self-explanatory
103
+ def source
104
+ @source
105
+ end
106
+
107
+ protected
108
+ def comment_symbols
109
+ super || {}
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,19 @@
1
+ require "haml"
2
+
3
+ module Murdoc
4
+ class Formatter
5
+ attr_accessor :template
6
+
7
+ def initialize(template_or_filename)
8
+ if File.exists?(template_or_filename)
9
+ @template = File.read(template_or_filename)
10
+ else
11
+ @template = template_or_filename
12
+ end
13
+ end
14
+
15
+ def render(locals = {})
16
+ ::Haml::Engine.new(template).render(self, locals)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,43 @@
1
+ # Javascript language module
2
+ module Murdoc
3
+ module Languages
4
+ module Javascript
5
+ module Annotator
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ protected
12
+ def detect_source_type_from_filename(filename)
13
+ if File.extname(filename) == ".js"
14
+ :javascript
15
+ else
16
+ super if defined?(super)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ module CommentSymbols
23
+ protected
24
+ def comment_symbols
25
+ if source_type == "javascript"
26
+ {:single_line => "//", :multiline => {:begin => "/*", :end => "*/"}}
27
+ else
28
+ super if defined?(super)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ class Annotator
36
+ include Languages::Javascript::Annotator
37
+ include Languages::Javascript::CommentSymbols
38
+ end
39
+
40
+ class Paragraph
41
+ include Languages::Javascript::CommentSymbols
42
+ end
43
+ end
@@ -0,0 +1,43 @@
1
+ # Ruby language module
2
+ module Murdoc
3
+ module Languages
4
+ module Ruby
5
+ module Annotator
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ protected
12
+ def detect_source_type_from_filename(filename)
13
+ if File.extname(filename) == ".rb"
14
+ :ruby
15
+ else
16
+ super if defined?(super)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ module CommentSymbols
23
+ protected
24
+ def comment_symbols
25
+ if source_type == "ruby"
26
+ {:single_line => "#", :multiline => {:begin => "=begin", :end => "=end"}}
27
+ else
28
+ super if defined?(super)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ class Annotator
36
+ include Languages::Ruby::Annotator
37
+ include Languages::Ruby::CommentSymbols
38
+ end
39
+
40
+ class Paragraph
41
+ include Languages::Ruby::CommentSymbols
42
+ end
43
+ end
@@ -0,0 +1,50 @@
1
+ require "rubygems"
2
+ require "rdiscount"
3
+ require "cgi"
4
+ require "tempfile"
5
+
6
+ module Murdoc
7
+ class Paragraph
8
+ attr_accessor :source
9
+ attr_accessor :annotation
10
+ attr_accessor :source_type
11
+ attr_accessor :starting_line
12
+
13
+ def initialize(source, annotation, starting_line = 0, source_type = nil)
14
+ self.source = source
15
+ self.annotation = annotation
16
+ self.starting_line = starting_line
17
+ self.source_type = source_type
18
+ end
19
+
20
+ def source_type
21
+ @source_type
22
+ end
23
+
24
+ def source_type=(source_type)
25
+ @source_type = source_type.to_s
26
+ end
27
+
28
+
29
+ def formatted_annotation
30
+ Markdown.new(annotation, :smart).to_html
31
+ end
32
+
33
+ def formatted_source
34
+ @formatted_source ||= if pygments_installed?
35
+ IO.popen("pygmentize -l #{source_type} -f html", "w+") do |pipe|
36
+ pipe.puts source
37
+ pipe.close_write
38
+ pipe.read
39
+ end
40
+ else
41
+ "<pre>" + CGI.escapeHTML(source) + "</pre>"
42
+ end
43
+ end
44
+
45
+ protected
46
+ def pygments_installed?
47
+ @@pygments_installed ||= ENV['PATH'].split(':').any? { |dir| File.exist?("#{dir}/pygmentize") }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,241 @@
1
+ html, body {
2
+ min-height: 100%; }
3
+
4
+ p, h1, h2, h3, ol, li, ol, ul, dt, dd, dl, body, html {
5
+ padding: 0;
6
+ margin: 0; }
7
+
8
+ body {
9
+ width: 45%;
10
+ padding-left: 2.5%;
11
+ padding-right: 2.5%;
12
+ background: #7ba32d;
13
+ font-family: Helvetica; }
14
+ body:after {
15
+ content: ".";
16
+ font-size: 0.01em;
17
+ line-height: 0.01em;
18
+ display: block;
19
+ clear: both; }
20
+
21
+ body > * {
22
+ padding-left: 6%;
23
+ padding-right: 6%; }
24
+
25
+ html {
26
+ background: #094201; }
27
+
28
+ header {
29
+ background: rgba(255, 255, 255, 0.1);
30
+ padding-top: 1em;
31
+ display: block; }
32
+ header dl {
33
+ margin-top: 1.125em;
34
+ font-size: 0.75em; }
35
+ header dl dt {
36
+ width: 5em;
37
+ font-weight: bold; }
38
+
39
+ p, dl, li {
40
+ color: #c4eeff;
41
+ font-weight: normal; }
42
+
43
+ a {
44
+ color: #a41717; }
45
+
46
+ p {
47
+ margin-top: 1.5em; }
48
+
49
+ h1 {
50
+ font-size: 2em; }
51
+
52
+ h2 {
53
+ font-size: 1em;
54
+ line-height: 2em; }
55
+
56
+ h1, h2, h3 {
57
+ color: #a41717; }
58
+
59
+ ol, li {
60
+ margin-left: 1em; }
61
+
62
+ body > div.paragraph, body > h1, body > h2 {
63
+ clear: both; }
64
+
65
+ header {
66
+ padding-bottom: 1em;
67
+ overflow: hidden; }
68
+
69
+ pre {
70
+ margin-top: 0;
71
+ }
72
+
73
+ dl {
74
+ clear: left; }
75
+ dl dt, dl dd {
76
+ float: left; }
77
+ dl dt {
78
+ clear: left; }
79
+ dl dd {
80
+ margin-left: 1em; }
81
+
82
+ section {
83
+ clear: both;
84
+ }
85
+
86
+ figure {
87
+ display: block;
88
+ float: right;
89
+ margin-right: -112.5%;
90
+ width: 95%;
91
+ clear: right;
92
+ padding: 2.5em 5% 3em; }
93
+ figure > ol {
94
+ width: 7.5%;
95
+ text-align: right;
96
+ float: left;
97
+ font-size: 0.8em;
98
+ color: #7ba32d;
99
+ -webkit-border-radius: 0.2em;
100
+ background: rgba(255, 255, 255, 0.1);
101
+ border: 1px solid rgba(0, 0, 0, 0.3);
102
+ list-style: none;
103
+ margin-left: -11.25%; }
104
+ figure > ol li {
105
+ margin: 0; }
106
+ figure pre {
107
+ background: rgba(255, 255, 255, 0.5);
108
+ border: 1px solid rgba(0, 0, 0, 0.3);
109
+ border-left: none;
110
+ margin-bottom: 0;
111
+ padding-bottom: 0;
112
+ }
113
+ figure > code, figure > ol {
114
+ font-size: 1em;
115
+ font-family: monospace; }
116
+ figure ~ figure {
117
+ padding-top: 1.5em; }
118
+
119
+ body .hll {
120
+ background-color: #ffffcc; }
121
+ body .c {
122
+ color: #408080;
123
+ font-style: italic; }
124
+ body .err {
125
+ border: 1px solid red; }
126
+ body .k {
127
+ color: #954121; }
128
+ body .o {
129
+ color: #666666; }
130
+ body .cm {
131
+ color: #408080;
132
+ font-style: italic; }
133
+ body .cp {
134
+ color: #bc7a00; }
135
+ body .c1, body .cs {
136
+ color: #408080;
137
+ font-style: italic; }
138
+ body .gd {
139
+ color: #a00000; }
140
+ body .ge {
141
+ font-style: italic; }
142
+ body .gr {
143
+ color: red; }
144
+ body .gh {
145
+ color: navy;
146
+ font-weight: bold; }
147
+ body .gi {
148
+ color: #00a000; }
149
+ body .go {
150
+ color: gray; }
151
+ body .gp {
152
+ color: navy;
153
+ font-weight: bold; }
154
+ body .gs {
155
+ font-weight: bold; }
156
+ body .gu {
157
+ color: purple;
158
+ font-weight: bold; }
159
+ body .gt {
160
+ color: #0040d0; }
161
+ body .kc {
162
+ color: #954121; }
163
+ body .kd, body .kn {
164
+ color: #954121;
165
+ font-weight: bold; }
166
+ body .kp {
167
+ color: #954121; }
168
+ body .kr {
169
+ color: #954121;
170
+ font-weight: bold; }
171
+ body .kt {
172
+ color: #b00040; }
173
+ body .m {
174
+ color: #666666; }
175
+ body .s {
176
+ color: #219161; }
177
+ body .na {
178
+ color: #7d9029; }
179
+ body .nb {
180
+ color: #954121; }
181
+ body .nc {
182
+ color: blue;
183
+ font-weight: bold; }
184
+ body .no {
185
+ color: #880000; }
186
+ body .nd {
187
+ color: #aa22ff; }
188
+ body .ni {
189
+ color: #999999;
190
+ font-weight: bold; }
191
+ body .ne {
192
+ color: #d2413a;
193
+ font-weight: bold; }
194
+ body .nf {
195
+ color: blue; }
196
+ body .nl {
197
+ color: #a0a000; }
198
+ body .nn {
199
+ color: blue;
200
+ font-weight: bold; }
201
+ body .nt {
202
+ color: #954121;
203
+ font-weight: bold; }
204
+ body .nv {
205
+ color: #19469d; }
206
+ body .ow {
207
+ color: #aa22ff;
208
+ font-weight: bold; }
209
+ body .w {
210
+ color: #bbbbbb; }
211
+ body .mf, body .mh, body .mi, body .mo {
212
+ color: #666666; }
213
+ body .sb, body .sc {
214
+ color: #219161; }
215
+ body .sd {
216
+ color: #219161;
217
+ font-style: italic; }
218
+ body .s2 {
219
+ color: #219161; }
220
+ body .se {
221
+ color: #bb6622;
222
+ font-weight: bold; }
223
+ body .sh {
224
+ color: #219161; }
225
+ body .si {
226
+ color: #bb6688;
227
+ font-weight: bold; }
228
+ body .sx {
229
+ color: #954121; }
230
+ body .sr {
231
+ color: #bb6688; }
232
+ body .s1 {
233
+ color: #219161; }
234
+ body .ss {
235
+ color: #19469d; }
236
+ body .bp {
237
+ color: #954121; }
238
+ body .vc, body .vg, body .vi {
239
+ color: #19469d; }
240
+ body .il {
241
+ color: #666666; }
@@ -0,0 +1,15 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title Murdoc
5
+ %style=stylesheet
6
+ %body
7
+ - paragraphs.each do |p|
8
+ - unless p.annotation.empty?
9
+ %section= p.formatted_annotation
10
+ - unless p.source.empty?
11
+ %figure
12
+ %ol
13
+ - 1.upto(p.source.split("\n").size) do |i|
14
+ %li= i + p.starting_line
15
+ %code<= p.formatted_source
@@ -0,0 +1,88 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{murdoc}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Mark Abramov"]
12
+ s.date = %q{2010-11-23}
13
+ s.default_executable = %q{murdoc}
14
+ s.description = %q{Annotated documentation generator, see README.md for details}
15
+ s.email = %q{markizko@gmail.com}
16
+ s.executables = ["murdoc"]
17
+ s.extra_rdoc_files = [
18
+ "README.md"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ ".rspec",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "README.md",
26
+ "Rakefile",
27
+ "UNLICENSE",
28
+ "VERSION",
29
+ "autotest/discover.rb",
30
+ "bin/murdoc",
31
+ "lib/murdoc.rb",
32
+ "lib/murdoc/annotator.rb",
33
+ "lib/murdoc/formatter.rb",
34
+ "lib/murdoc/languages/javascript.rb",
35
+ "lib/murdoc/languages/ruby.rb",
36
+ "lib/murdoc/paragraph.rb",
37
+ "markup/stylesheet.css",
38
+ "markup/template.haml",
39
+ "murdoc.gemspec",
40
+ "spec/murdoc/annotator_spec.rb",
41
+ "spec/murdoc/formatter_spec.rb",
42
+ "spec/murdoc/paragraph_spec.rb",
43
+ "spec/spec_helper.rb"
44
+ ]
45
+ s.homepage = %q{http://github.com/markiz/murdoc}
46
+ s.licenses = ["Public Domain"]
47
+ s.require_paths = ["lib"]
48
+ s.rubygems_version = %q{1.3.7}
49
+ s.summary = %q{Annotated documentation generator}
50
+ s.test_files = [
51
+ "spec/murdoc/annotator_spec.rb",
52
+ "spec/murdoc/formatter_spec.rb",
53
+ "spec/murdoc/paragraph_spec.rb",
54
+ "spec/spec_helper.rb"
55
+ ]
56
+
57
+ if s.respond_to? :specification_version then
58
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
59
+ s.specification_version = 3
60
+
61
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
62
+ s.add_runtime_dependency(%q<jeweler>, [">= 0"])
63
+ s.add_runtime_dependency(%q<rspec>, ["~> 2.1.0"])
64
+ s.add_runtime_dependency(%q<rdiscount>, ["~> 1.6.5"])
65
+ s.add_runtime_dependency(%q<haml>, ["~> 3.0.0"])
66
+ s.add_runtime_dependency(%q<sass>, ["~> 3.1.0"])
67
+ s.add_runtime_dependency(%q<haml>, ["~> 3.0.0"])
68
+ s.add_runtime_dependency(%q<rdiscount>, ["~> 1.6.5"])
69
+ else
70
+ s.add_dependency(%q<jeweler>, [">= 0"])
71
+ s.add_dependency(%q<rspec>, ["~> 2.1.0"])
72
+ s.add_dependency(%q<rdiscount>, ["~> 1.6.5"])
73
+ s.add_dependency(%q<haml>, ["~> 3.0.0"])
74
+ s.add_dependency(%q<sass>, ["~> 3.1.0"])
75
+ s.add_dependency(%q<haml>, ["~> 3.0.0"])
76
+ s.add_dependency(%q<rdiscount>, ["~> 1.6.5"])
77
+ end
78
+ else
79
+ s.add_dependency(%q<jeweler>, [">= 0"])
80
+ s.add_dependency(%q<rspec>, ["~> 2.1.0"])
81
+ s.add_dependency(%q<rdiscount>, ["~> 1.6.5"])
82
+ s.add_dependency(%q<haml>, ["~> 3.0.0"])
83
+ s.add_dependency(%q<sass>, ["~> 3.1.0"])
84
+ s.add_dependency(%q<haml>, ["~> 3.0.0"])
85
+ s.add_dependency(%q<rdiscount>, ["~> 1.6.5"])
86
+ end
87
+ end
88
+
@@ -0,0 +1,111 @@
1
+ require "spec_helper"
2
+ require "fileutils"
3
+
4
+ describe Murdoc::Annotator do
5
+ describe "#initialize" do
6
+ it "should set #source from source text" do
7
+ Murdoc::Annotator.new("Procrastination", "plaintext").source.should == "Procrastination"
8
+ end
9
+
10
+ it "should set source type from second argument" do
11
+ Murdoc::Annotator.new("# Hello", "ruby").source_type.should == "ruby"
12
+ Murdoc::Annotator.new("# Hello", :ruby).source_type.should == "ruby"
13
+ end
14
+ end
15
+
16
+ describe ".from_file" do
17
+ after(:each) { FileUtils.rm "annotator_test.rb", :force => true }
18
+ it "should set #source from file contents" do
19
+ File.open("annotator_test.rb", "w+") do |f|
20
+ f.puts "# Comment"
21
+ f.puts "puts 'Hello, world!'"
22
+ end
23
+
24
+ described_class.from_file("annotator_test.rb").source.should =~ /# Comment\s+puts 'Hello, world!'/
25
+ end
26
+
27
+ it "should detect source type from extension" do
28
+ File.open("annotator_test.rb", "w+")
29
+ described_class.stub!(:detect_source_type_from_filename).and_return("test")
30
+ described_class.from_file("annotator_test.rb").source_type.should == "test"
31
+ end
32
+
33
+ it "should still let me force source type" do
34
+ File.open("annotator_test.rb", "w+")
35
+ described_class.from_file("annotator_test.rb", "code").source_type.should == "code"
36
+ end
37
+ end
38
+
39
+
40
+ describe "#source=" do
41
+ let(:source) { "" }
42
+ subject { described_class.new(source, :ruby) }
43
+ context "for source with single-line comments" do
44
+ let(:source) { "# Block one\n# Block one!!!!\n def hi\nputs 'hello'\nend\n\n# Block two\ndef yo\nputs 'rap'\nend\n" }
45
+
46
+ it "should split source into paragraphs" do
47
+ subject.should have_exactly(2).paragraphs
48
+ subject.paragraphs[0].source.should =~ /\A\s*def hi\s*puts 'hello'\s*end\s*\Z/m
49
+ subject.paragraphs[0].annotation.should =~ /\ABlock one\s*Block one!!!!\Z/m
50
+ subject.paragraphs[1].source.should =~ /\A\s*def yo\s*puts 'rap'\s*end\s*\Z/m
51
+ subject.paragraphs[1].annotation.should =~ /\ABlock two\Z/m
52
+ end
53
+
54
+ it "should remove trailing comment blank line" do
55
+ subject.source = "# Hello\n# \n \n\n"
56
+ subject.should have_exactly(1).paragraphs
57
+ subject.paragraphs[0].annotation.should == "Hello"
58
+ end
59
+ end
60
+
61
+ context "for source with multi-line comments" do
62
+ let(:source) { "=begin\n Block one\n Block one!!!!\n=end\n def hi\nputs 'hello'\nend\n=begin\nBlock two\n=end\ndef yo\nputs 'rap'\nend\n" }
63
+
64
+ it "should split source into paragraphs" do
65
+ subject.should have_exactly(2).paragraphs
66
+ subject.paragraphs[0].source.should =~ /\A\s*def hi\s*puts 'hello'\s*end\s*\Z/m
67
+ subject.paragraphs[0].annotation.should =~ /\ABlock one\s*Block one!!!!\Z/m
68
+ subject.paragraphs[1].source.should =~ /\A\s*def yo\s*puts 'rap'\s*end\s*\Z/m
69
+ subject.paragraphs[1].annotation.should =~ /\ABlock two\Z/m
70
+ end
71
+ end
72
+
73
+ context "for comment without code" do
74
+ let(:source) { "# Header\n\n\n# Comment\ndef body\nend" }
75
+ it "should create a separate paragraph" do
76
+ subject.should have_exactly(2).paragraphs
77
+ subject.paragraphs[0].source.should == ""
78
+ subject.paragraphs[0].annotation.should == "Header"
79
+ end
80
+ end
81
+
82
+ it "should not choke on edge cases" do
83
+ subject.source = ""
84
+ subject.source = "#"
85
+ subject.source = "# A\n#"
86
+ subject.source = " # A\n # "
87
+ subject.source = "# A\n=begin\n"
88
+ subject.source = "# A\n=begin\n\n =end yo"
89
+ subject.source = "# A\n=begin\n\n asdasd =end yo"
90
+ subject.source = "# A\n=begin\n\n !!$$ =end yo"
91
+ subject.source = "\n =begin\n\n =end yo"
92
+ subject.source = "=begin YO =end\n\n\n\n asdasd asd"
93
+ end
94
+
95
+ it "should remove totally empty source" do
96
+ subject.source = "# Comment\n\n\n\n"
97
+ subject.paragraphs[0].source.should be_empty
98
+ end
99
+
100
+ it "should remove semi-empty lines" do
101
+ subject.source = "def hi\n\nend"
102
+ subject.paragraphs[0].source.should == "def hi\n\nend"
103
+ end
104
+ end
105
+
106
+
107
+ describe "#annotated" do
108
+ let(:source) { "# this" }
109
+ subject { described_class.new(source, :ruby) }
110
+ end
111
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+ require "tempfile"
3
+ describe Murdoc::Formatter do
4
+ describe "#initialize" do
5
+ it "should set template from given string" do
6
+ described_class.new("%p Hello").template.should == "%p Hello"
7
+ end
8
+
9
+ it "should set template from given filename if that filename exists" do
10
+ Tempfile.open("test") do |f|
11
+ f.puts("%p Hello")
12
+ f.close
13
+ described_class.new(f.path).template.should == "%p Hello\n"
14
+ end
15
+ end
16
+ end
17
+
18
+ describe "#render" do
19
+ it "should render with haml" do
20
+ described_class.new("%p Hello").render.should =~ %r{<p>Hello</p>}
21
+ end
22
+
23
+ it "should send locals to haml" do
24
+ described_class.new("%p= foo").render(:foo => 123).should =~ %r{<p>123</p>}
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+
3
+ describe Murdoc::Paragraph do
4
+ describe "#initialize" do
5
+ it "should set source" do
6
+ described_class.new("A", "").source.should == "A"
7
+ end
8
+
9
+ it "should set annotation" do
10
+ described_class.new("", "B").annotation.should == "B"
11
+ end
12
+
13
+ it "should optionally set source_type" do
14
+ described_class.new("", "", 0, :ruby).source_type.should == "ruby"
15
+ end
16
+
17
+ it "should optionally set starting line" do
18
+ described_class.new("", "", 666, :ruby).starting_line.should == 666
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ require "rspec"
4
+
5
+ require "murdoc"
metadata ADDED
@@ -0,0 +1,192 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: murdoc
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Mark Abramov
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-11-23 00:00:00 +03:00
18
+ default_executable: murdoc
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: jeweler
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ prerelease: false
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: rspec
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 2
42
+ - 1
43
+ - 0
44
+ version: 2.1.0
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: rdiscount
50
+ requirement: &id003 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 1
57
+ - 6
58
+ - 5
59
+ version: 1.6.5
60
+ type: :runtime
61
+ prerelease: false
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: haml
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 3
72
+ - 0
73
+ - 0
74
+ version: 3.0.0
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: *id004
78
+ - !ruby/object:Gem::Dependency
79
+ name: sass
80
+ requirement: &id005 !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ segments:
86
+ - 3
87
+ - 1
88
+ - 0
89
+ version: 3.1.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: *id005
93
+ - !ruby/object:Gem::Dependency
94
+ name: haml
95
+ requirement: &id006 !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ~>
99
+ - !ruby/object:Gem::Version
100
+ segments:
101
+ - 3
102
+ - 0
103
+ - 0
104
+ version: 3.0.0
105
+ type: :runtime
106
+ prerelease: false
107
+ version_requirements: *id006
108
+ - !ruby/object:Gem::Dependency
109
+ name: rdiscount
110
+ requirement: &id007 !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ~>
114
+ - !ruby/object:Gem::Version
115
+ segments:
116
+ - 1
117
+ - 6
118
+ - 5
119
+ version: 1.6.5
120
+ type: :runtime
121
+ prerelease: false
122
+ version_requirements: *id007
123
+ description: Annotated documentation generator, see README.md for details
124
+ email: markizko@gmail.com
125
+ executables:
126
+ - murdoc
127
+ extensions: []
128
+
129
+ extra_rdoc_files:
130
+ - README.md
131
+ files:
132
+ - .document
133
+ - .rspec
134
+ - Gemfile
135
+ - Gemfile.lock
136
+ - README.md
137
+ - Rakefile
138
+ - UNLICENSE
139
+ - VERSION
140
+ - autotest/discover.rb
141
+ - bin/murdoc
142
+ - lib/murdoc.rb
143
+ - lib/murdoc/annotator.rb
144
+ - lib/murdoc/formatter.rb
145
+ - lib/murdoc/languages/javascript.rb
146
+ - lib/murdoc/languages/ruby.rb
147
+ - lib/murdoc/paragraph.rb
148
+ - markup/stylesheet.css
149
+ - markup/template.haml
150
+ - murdoc.gemspec
151
+ - spec/murdoc/annotator_spec.rb
152
+ - spec/murdoc/formatter_spec.rb
153
+ - spec/murdoc/paragraph_spec.rb
154
+ - spec/spec_helper.rb
155
+ has_rdoc: true
156
+ homepage: http://github.com/markiz/murdoc
157
+ licenses:
158
+ - Public Domain
159
+ post_install_message:
160
+ rdoc_options: []
161
+
162
+ require_paths:
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ none: false
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ hash: 303347797677614350
170
+ segments:
171
+ - 0
172
+ version: "0"
173
+ required_rubygems_version: !ruby/object:Gem::Requirement
174
+ none: false
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ segments:
179
+ - 0
180
+ version: "0"
181
+ requirements: []
182
+
183
+ rubyforge_project:
184
+ rubygems_version: 1.3.7
185
+ signing_key:
186
+ specification_version: 3
187
+ summary: Annotated documentation generator
188
+ test_files:
189
+ - spec/murdoc/annotator_spec.rb
190
+ - spec/murdoc/formatter_spec.rb
191
+ - spec/murdoc/paragraph_spec.rb
192
+ - spec/spec_helper.rb