murdoc 0.1.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.
@@ -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