reacco 0.0.2
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.
- data/.gitignore +1 -0
- data/Gemfile +2 -0
- data/HISTORY.md +4 -0
- data/README.md +26 -0
- data/Rakefile +31 -0
- data/bin/reacco +95 -0
- data/data/index.erb +17 -0
- data/data/style.css +341 -0
- data/lib/reacco/extractor/block.rb +84 -0
- data/lib/reacco/extractor.rb +96 -0
- data/lib/reacco/filters/brief.rb +12 -0
- data/lib/reacco/filters/headingid.rb +13 -0
- data/lib/reacco/filters/hgroup.rb +26 -0
- data/lib/reacco/filters/literate.rb +36 -0
- data/lib/reacco/filters/prelang.rb +11 -0
- data/lib/reacco/filters/sections.rb +56 -0
- data/lib/reacco/filters/toc.rb +54 -0
- data/lib/reacco/generator.rb +68 -0
- data/lib/reacco/readme.rb +150 -0
- data/lib/reacco/version.rb +5 -0
- data/lib/reacco.rb +44 -0
- data/reacco.gemspec +17 -0
- data/test/blocks_test.rb +18 -0
- data/test/test_helper.rb +9 -0
- metadata +103 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/doc/
|
data/Gemfile
ADDED
data/HISTORY.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Reacco
|
2
|
+
#### Readme documentation prettifier
|
3
|
+
|
4
|
+
In progress. Check out http://ricostacruz.com/sinatra-assetpack for an example.
|
5
|
+
|
6
|
+
# API reference
|
7
|
+
|
8
|
+
(API reference goes here)
|
9
|
+
|
10
|
+
Acknowledgements
|
11
|
+
----------------
|
12
|
+
|
13
|
+
© 2011, Rico Sta. Cruz. Released under the [MIT
|
14
|
+
License](http://www.opensource.org/licenses/mit-license.php).
|
15
|
+
|
16
|
+
Reacco is authored and maintained by [Rico Sta. Cruz][rsc] with help from it's
|
17
|
+
[contributors][c]. It is sponsored by my startup, [Sinefunc, Inc][sf].
|
18
|
+
|
19
|
+
* [My website](http://ricostacruz.com) (ricostacruz.com)
|
20
|
+
* [Sinefunc, Inc.](http://sinefunc.com) (sinefunc.com)
|
21
|
+
* [Github](http://github.com/rstacruz) (@rstacruz)
|
22
|
+
* [Twitter](http://twitter.com/rstacruz) (@rstacruz)
|
23
|
+
|
24
|
+
[rsc]: http://ricostacruz.com
|
25
|
+
[c]: http://github.com/rstacruz/reacco/contributors
|
26
|
+
[sf]: http://sinefunc.com
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
desc "Invokes the test suite in multiple RVM environments"
|
2
|
+
task :'test!' do
|
3
|
+
# Override this by adding RVM_TEST_ENVS=".." in .rvmrc
|
4
|
+
envs = ENV['RVM_TEST_ENVS'] || '1.9.2@reacco,,1.8.7@reacco'
|
5
|
+
puts "* Testing in the following RVM environments: #{envs.gsub(',', ', ')}"
|
6
|
+
system "rvm #{envs} rake test" or abort
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Runs tests"
|
10
|
+
task :test do
|
11
|
+
Dir['test/*_test.rb'].each { |f| load f }
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :test
|
15
|
+
|
16
|
+
gh = "rstacruz/reacco"
|
17
|
+
namespace :doc do
|
18
|
+
# http://github.com/rstacruz/reacco
|
19
|
+
desc "Builds the documentation into doc/"
|
20
|
+
task :build do
|
21
|
+
system "reacco -a --github #{gh} --api lib"
|
22
|
+
end
|
23
|
+
|
24
|
+
# http://github.com/rstacruz/git-update-ghpages
|
25
|
+
desc "Posts documentation to GitHub pages"
|
26
|
+
task :deploy => :build do
|
27
|
+
system "git update-ghpages #{gh} -i doc/"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
task :doc => :'doc:build'
|
data/bin/reacco
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
3
|
+
require 'reacco'
|
4
|
+
|
5
|
+
module Params
|
6
|
+
def extract(what) i = index(what) and slice!(i, 2)[1] end;
|
7
|
+
end
|
8
|
+
ARGV.extend Params
|
9
|
+
|
10
|
+
def tip(str)
|
11
|
+
$stderr.write "#{str}\n"
|
12
|
+
end
|
13
|
+
|
14
|
+
if ARGV == ['-h'] || ARGV == ['--help']
|
15
|
+
tip "Usage: reacco [options]"
|
16
|
+
tip "Generates nice HTML."
|
17
|
+
tip ""
|
18
|
+
tip "Options:"
|
19
|
+
tip " --literate Move <pre> blocks to the right."
|
20
|
+
tip " --toc Show a table of contents."
|
21
|
+
tip ""
|
22
|
+
tip "Theming:"
|
23
|
+
tip " --css FILE Append the CSS from that file to the generated CSS."
|
24
|
+
tip " -t, --template PATH The template to use, if you don't want the default."
|
25
|
+
tip ""
|
26
|
+
tip "API extraction:"
|
27
|
+
tip " --api PATH Where to get stuff."
|
28
|
+
tip ""
|
29
|
+
tip "More:"
|
30
|
+
tip " --github REPO Adds a 'Fork me on GitHub' badge. Repo should be in"
|
31
|
+
tip " 'username/reponame' format."
|
32
|
+
tip " -o, --output PATH Sets the path to put HTML files in. Defaults to 'doc/'."
|
33
|
+
tip ""
|
34
|
+
exit
|
35
|
+
|
36
|
+
else
|
37
|
+
# Build options from arguments.
|
38
|
+
switches = [:literate, :toc]
|
39
|
+
docpath = ARGV.extract('-o') || ARGV.extract('--output') || 'doc'
|
40
|
+
template = ARGV.extract('-t') || ARGV.extract('--template') || nil
|
41
|
+
github = ARGV.extract('--github') || nil
|
42
|
+
css = ARGV.extract('--css') || nil
|
43
|
+
awesome = ARGV.delete('-a') || ARGV.extract('--awesome')
|
44
|
+
options = Hash.new
|
45
|
+
|
46
|
+
extract = Array.new
|
47
|
+
while (x = ARGV.extract('--api'))
|
48
|
+
extract << x
|
49
|
+
end
|
50
|
+
|
51
|
+
switches.each do |opt|
|
52
|
+
options[opt] = true if ARGV.delete("--#{opt}")
|
53
|
+
end
|
54
|
+
|
55
|
+
switches.each { |opt| options[opt] = true } if awesome
|
56
|
+
|
57
|
+
options[:github] = github if github
|
58
|
+
|
59
|
+
if ARGV.any?
|
60
|
+
puts "Invalid usage. See `reacco --help` for help."
|
61
|
+
exit 60
|
62
|
+
end
|
63
|
+
|
64
|
+
# Lets find the readme.
|
65
|
+
readme = Reacco::Readme.new(options)
|
66
|
+
unless readme.exists?
|
67
|
+
tip "Readme file not found."
|
68
|
+
exit 60
|
69
|
+
end
|
70
|
+
|
71
|
+
# If we need to extract API, let's do it.
|
72
|
+
if extract.any?
|
73
|
+
blocks = extract.map { |path|
|
74
|
+
Reacco::Extractor.new(Dir["#{path}/**/*"]).blocks
|
75
|
+
}.flatten
|
76
|
+
|
77
|
+
blocks.each { |blk| readme.inject_api_block blk.to_html }
|
78
|
+
end
|
79
|
+
|
80
|
+
# Now let's generate it.
|
81
|
+
gen = Reacco::Generator.new(readme, docpath, template, css)
|
82
|
+
unless gen.template?
|
83
|
+
tip "Invalid template."
|
84
|
+
tip "A template must at least have an index.xxx page."
|
85
|
+
exit 61
|
86
|
+
end
|
87
|
+
|
88
|
+
gen.write! { |file| tip "* #{file}" }
|
89
|
+
|
90
|
+
# AHHH YYEAAAHHH!
|
91
|
+
tip "Construction complete."
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
#tip Reacco.html(:hgroup => true, :literate => true, :brief => true)
|
data/data/index.erb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8" />
|
5
|
+
<title><%= title %></title>
|
6
|
+
<link href="style.css" rel="stylesheet" />
|
7
|
+
<link href='http://fonts.googleapis.com/css?family=Shanti:400|PT+Sans:700,700italic' rel='stylesheet' type='text/css'>
|
8
|
+
</head>
|
9
|
+
<body class='<%= body_class %>'>
|
10
|
+
<% if github %>
|
11
|
+
<a href="<%= github %>"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://a248.e.akamai.net/assets.github.com/img/e6bef7a091f5f3138b8cd40bc3e114258dd68ddf/687474703a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f7265645f6161303030302e706e67" alt="Fork me on GitHub"></a>
|
12
|
+
<% end %>
|
13
|
+
<div id='all'><%= yield %></div>
|
14
|
+
<script type='text/javascript' src='http://cachedcommons.org/cache/prettify/1.0.0/javascripts/prettify-min.js'></script>
|
15
|
+
<script>prettyPrint();</script>
|
16
|
+
</body>
|
17
|
+
</html>
|
data/data/style.css
ADDED
@@ -0,0 +1,341 @@
|
|
1
|
+
html, body {
|
2
|
+
margin: 0;
|
3
|
+
padding: 0; }
|
4
|
+
|
5
|
+
body {
|
6
|
+
background: #fcfcfa;
|
7
|
+
font-family: 'pt sans', sans-serif;
|
8
|
+
color: #444;
|
9
|
+
font-size: 11pt;
|
10
|
+
line-height: 1.5; }
|
11
|
+
|
12
|
+
::-moz-selection { background: #88a; color: #fff; text-shadow: none; }
|
13
|
+
::selection { background: #88a; color: #fff; text-shadow: none; }
|
14
|
+
|
15
|
+
h1, h2, h3, h4, h5, h6, p, ol, ul, pre, ol>li {
|
16
|
+
max-width: 500px;
|
17
|
+
margin: 20px 0; }
|
18
|
+
|
19
|
+
ol, ul {
|
20
|
+
padding-left: 0;
|
21
|
+
margin-left: 30px; }
|
22
|
+
|
23
|
+
#all {
|
24
|
+
min-width: 960px;
|
25
|
+
box-sizing: border-box;
|
26
|
+
-moz-box-sizing: border-box;
|
27
|
+
-webkit-box-sizing: border-box;
|
28
|
+
width: 100%;
|
29
|
+
overflow-x: hidden;
|
30
|
+
padding: 40px; }
|
31
|
+
|
32
|
+
a, a:visited {
|
33
|
+
text-decoration: none;
|
34
|
+
border-bottom: solid 1px #ccf;
|
35
|
+
color: #46b; }
|
36
|
+
|
37
|
+
a:hover {
|
38
|
+
background: #fafae0; }
|
39
|
+
|
40
|
+
/* List */
|
41
|
+
ul li > p > strong:first-child {
|
42
|
+
display: block;
|
43
|
+
font-size: 1.1em; }
|
44
|
+
|
45
|
+
/* Headings */
|
46
|
+
h1 {
|
47
|
+
font-family: palatino, serif; }
|
48
|
+
|
49
|
+
h1, h2, h3, h4, h5, h6 {
|
50
|
+
text-shadow: 2px 2px 0 rgba(55, 55, 55, 0.1);
|
51
|
+
color: #568;
|
52
|
+
font-weight: normal;
|
53
|
+
font-family: shanti, palatino, serif; }
|
54
|
+
|
55
|
+
h3 {
|
56
|
+
color: #77a; }
|
57
|
+
|
58
|
+
h4, h5, h6 {
|
59
|
+
color: #88a; }
|
60
|
+
|
61
|
+
/* The "(class method)" thing */
|
62
|
+
h1 .type, h2 .type, h3 .type, h4 .type, h5 .type, h6 .type {
|
63
|
+
font-size: 9pt;
|
64
|
+
color: #aaa;
|
65
|
+
text-transform: uppercase;
|
66
|
+
margin-left: 10px; }
|
67
|
+
|
68
|
+
h2 {
|
69
|
+
max-width: none;
|
70
|
+
padding-top: 30px;
|
71
|
+
margin-top: 40px; }
|
72
|
+
|
73
|
+
h3 {
|
74
|
+
max-width: none;
|
75
|
+
padding-top: 10px;
|
76
|
+
margin-top: 40px; }
|
77
|
+
|
78
|
+
h1 { font-size: 30pt; }
|
79
|
+
h2 { font-size: 23pt; }
|
80
|
+
h3 { font-size: 14pt; }
|
81
|
+
h4 { font-size: 14pt; }
|
82
|
+
h5 { font-size: 10pt; }
|
83
|
+
h6 { font-size: 10pt; }
|
84
|
+
|
85
|
+
h2+p { margin-top: 0; }
|
86
|
+
h2+pre.right+p { margin-top: 0; }
|
87
|
+
|
88
|
+
/* Code */
|
89
|
+
pre, code {
|
90
|
+
font-family: Monaco, monospace; }
|
91
|
+
|
92
|
+
code {
|
93
|
+
text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.99);
|
94
|
+
font-family: 'shanti', sans-serif;
|
95
|
+
color: #9090aa; }
|
96
|
+
|
97
|
+
pre > code {
|
98
|
+
color: #60606f;
|
99
|
+
text-shadow: none;
|
100
|
+
font-family: Monaco, monospace;
|
101
|
+
background: 0;
|
102
|
+
padding: 0;
|
103
|
+
border: 0; }
|
104
|
+
|
105
|
+
pre {
|
106
|
+
font-size: 9pt;
|
107
|
+
padding-top: 5px;
|
108
|
+
background: transparent; }
|
109
|
+
|
110
|
+
/* The header */
|
111
|
+
.header h1, .header h2, .header h3,
|
112
|
+
.header h4, .header h5, .header h6 {
|
113
|
+
text-shadow: none;
|
114
|
+
line-height: 1.35;
|
115
|
+
margin: 0;
|
116
|
+
padding: 0; }
|
117
|
+
|
118
|
+
.header h1 a,
|
119
|
+
.header h1 {
|
120
|
+
font-family: 'pt sans', sans-serif;
|
121
|
+
font-weight: bold;
|
122
|
+
color: #779; }
|
123
|
+
|
124
|
+
.header h1 a {
|
125
|
+
border-bottom: 0; }
|
126
|
+
|
127
|
+
.header h2, .header h3,
|
128
|
+
.header h4, .header h5, .header h6 {
|
129
|
+
color: #aab; } /* color: #78b; */
|
130
|
+
|
131
|
+
.header h4 {
|
132
|
+
font-size: 1.4em;
|
133
|
+
font-family: palatino, serif;
|
134
|
+
font-style: italic;
|
135
|
+
font-weight: normal; }
|
136
|
+
|
137
|
+
/* Literate */
|
138
|
+
body.literate h4, body.literate h5, body.literate h6, body.literate p,
|
139
|
+
body.literate ol, body.literate ul, body.literate pre {
|
140
|
+
max-width: 400px; }
|
141
|
+
|
142
|
+
body.literate pre.right {
|
143
|
+
clear: both;
|
144
|
+
max-width: none;
|
145
|
+
width: 490px;
|
146
|
+
margin-left: 50px;
|
147
|
+
float: right; }
|
148
|
+
|
149
|
+
body.literate pre.right code {
|
150
|
+
color: #78a; }
|
151
|
+
|
152
|
+
body.literate h1 + pre.right,
|
153
|
+
body.literate h2 + pre.right,
|
154
|
+
body.literate h3 + pre.right {
|
155
|
+
margin-top: 0; }
|
156
|
+
|
157
|
+
h1, h2, h3 {
|
158
|
+
clear: both; }
|
159
|
+
|
160
|
+
.clear {
|
161
|
+
clear: both; }
|
162
|
+
|
163
|
+
br.post-pre {
|
164
|
+
clear: both; }
|
165
|
+
|
166
|
+
h4 { margin-bottom: 5px; }
|
167
|
+
h4+p,
|
168
|
+
h4+pre.right,
|
169
|
+
h4+pre.right+p { margin-top: 0; }
|
170
|
+
|
171
|
+
/* Section-wrap */
|
172
|
+
section {
|
173
|
+
width: 960px;
|
174
|
+
margin-top: 0;
|
175
|
+
margin-left: 0;
|
176
|
+
padding-left: 40px;
|
177
|
+
margin-left: -40px;
|
178
|
+
padding-right: 9000px; }
|
179
|
+
|
180
|
+
section::after {
|
181
|
+
content: '';
|
182
|
+
display: table;
|
183
|
+
clear: both; }
|
184
|
+
|
185
|
+
section.h2:nth-child(even) {
|
186
|
+
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
|
187
|
+
background: rgba(255, 255, 255, 0.8); }
|
188
|
+
|
189
|
+
section:first-of-type {
|
190
|
+
margin-top: 40px; }
|
191
|
+
|
192
|
+
section.h1, section.h2, section.h3 {
|
193
|
+
padding-top: 30px;
|
194
|
+
padding-bottom: 40px;
|
195
|
+
border-top: solid 1px #eee; }
|
196
|
+
|
197
|
+
section.h1 {
|
198
|
+
border-top: solid 10px #ddd; }
|
199
|
+
|
200
|
+
section.h3 {
|
201
|
+
padding-top: 20px;
|
202
|
+
margin-top: 40px;
|
203
|
+
padding-left: 30px;
|
204
|
+
border-left: solid 10px #e7e7f4;
|
205
|
+
border-top: dotted 1px #ddd; }
|
206
|
+
|
207
|
+
section.h3:nth-child(odd) {
|
208
|
+
border-left-color: #d0d0e8; }
|
209
|
+
|
210
|
+
section.h3 + section.h3 {
|
211
|
+
margin-top: -20px; }
|
212
|
+
|
213
|
+
section.h1>:first-child, section.h2>:first-child, section.h3>:first-child {
|
214
|
+
padding-top: 0;
|
215
|
+
margin-top: 0; }
|
216
|
+
|
217
|
+
/* API */
|
218
|
+
section.api h2,
|
219
|
+
section.api h3 {
|
220
|
+
margin-bottom: 0; }
|
221
|
+
|
222
|
+
section.api h2 + p,
|
223
|
+
section.api h2 + pre + p,
|
224
|
+
section.api h3 + p,
|
225
|
+
section.api h3 + pre + p {
|
226
|
+
margin-top: 0; }
|
227
|
+
|
228
|
+
h2 .args,
|
229
|
+
h3 .args {
|
230
|
+
margin-left: 3px;
|
231
|
+
font-size: 0.9em;
|
232
|
+
margin-right: 15px;
|
233
|
+
color: #aab; }
|
234
|
+
|
235
|
+
/* Pretty printing styles. Used with prettify.js. */
|
236
|
+
.str { color: #080; }
|
237
|
+
.kwd { color: #008; }
|
238
|
+
.com { color: #607077; background: rgba(0, 0, 0, 0.05); padding: 1px 3px; }
|
239
|
+
.typ { color: #606; }
|
240
|
+
.lit { color: #066; }
|
241
|
+
.pun { color: #660; }
|
242
|
+
.pln { color: #000; }
|
243
|
+
.tag { color: #008; }
|
244
|
+
.atn { color: #606; }
|
245
|
+
.atv { color: #080; }
|
246
|
+
.dec { color: #606; }
|
247
|
+
|
248
|
+
/* Specify class=linenums on a pre to get line numbering */
|
249
|
+
ol.linenums { margin-top: 0; margin-bottom: 0 } /* IE indents via margin-left */
|
250
|
+
li.L0, li.L1, li.L2, li.L3, li.L5, li.L6, li.L7, li.L8 { list-style-type: none }
|
251
|
+
/* Alternate shading for lines */
|
252
|
+
li.L1, li.L3, li.L5, li.L7, li.L9 { background: #eee }
|
253
|
+
|
254
|
+
@media print {
|
255
|
+
.str { color: #060; }
|
256
|
+
.kwd { color: #006; font-weight: bold; }
|
257
|
+
.com { color: #600; font-style: italic; }
|
258
|
+
.typ { color: #404; font-weight: bold; }
|
259
|
+
.lit { color: #044; }
|
260
|
+
.pun { color: #440; }
|
261
|
+
.pln { color: #000; }
|
262
|
+
.tag { color: #006; font-weight: bold; }
|
263
|
+
.atn { color: #404; }
|
264
|
+
.atv { color: #060; }
|
265
|
+
}
|
266
|
+
|
267
|
+
/* TOC */
|
268
|
+
body.toc {
|
269
|
+
margin-left: 200px; }
|
270
|
+
|
271
|
+
aside#toc {
|
272
|
+
font-size: 0.9em;
|
273
|
+
line-height: 1.7;
|
274
|
+
position: fixed;
|
275
|
+
top: 0;
|
276
|
+
left: 0;
|
277
|
+
bottom: 0;
|
278
|
+
padding: 20px;
|
279
|
+
width: 180px;
|
280
|
+
overflow-y: auto;
|
281
|
+
box-shadow: inset -2px 0 2px rgba(0, 0, 0, 0.1);
|
282
|
+
border-right: solid 1px #ccc;
|
283
|
+
background: #f4f4fa; }
|
284
|
+
|
285
|
+
aside#toc h1,
|
286
|
+
aside#toc h2,
|
287
|
+
aside#toc h3 {
|
288
|
+
overflow: hidden;
|
289
|
+
margin: 10px 0;
|
290
|
+
padding: 0;
|
291
|
+
font-size: 1.1em; }
|
292
|
+
|
293
|
+
aside#toc h1 {
|
294
|
+
color: #aaa;
|
295
|
+
text-shadow: none;
|
296
|
+
font-size: 1.3em; }
|
297
|
+
|
298
|
+
aside#toc h3 {
|
299
|
+
border-top: solid 1px #ddd;
|
300
|
+
padding-top: 10px; }
|
301
|
+
|
302
|
+
aside#toc h2 .type,
|
303
|
+
aside#toc h3 .type {
|
304
|
+
margin-left: 0; }
|
305
|
+
|
306
|
+
aside#toc ul,
|
307
|
+
aside#toc li {
|
308
|
+
margin: 0;
|
309
|
+
padding: 0;
|
310
|
+
list-style-type: none; }
|
311
|
+
|
312
|
+
aside#toc h1 a,
|
313
|
+
aside#toc h2 a,
|
314
|
+
aside#toc h3 a {
|
315
|
+
color: #333; }
|
316
|
+
|
317
|
+
aside#toc a {
|
318
|
+
overflow: hidden;
|
319
|
+
display: block;
|
320
|
+
border-bottom: 0;
|
321
|
+
color: #555; }
|
322
|
+
|
323
|
+
aside#toc a span.args {
|
324
|
+
display: none; }
|
325
|
+
|
326
|
+
aside#toc a span.type {
|
327
|
+
font-size: 0.8em;
|
328
|
+
text-transform: uppercase;
|
329
|
+
color: #999; }
|
330
|
+
|
331
|
+
aside#toc .type {
|
332
|
+
float: right; }
|
333
|
+
|
334
|
+
aside#toc::-webkit-scrollbar {
|
335
|
+
height: 15px; width: 15px;
|
336
|
+
}
|
337
|
+
|
338
|
+
aside#toc::-webkit-scrollbar-thumb {
|
339
|
+
border-width: 7px 7px 7px 7px;
|
340
|
+
-webkit-border-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDZEMERCMUZGRUI2MTFERkIwQ0RGMkFBNEE3NDlCOUMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDZEMERCMjBGRUI2MTFERkIwQ0RGMkFBNEE3NDlCOUMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0NkQwREIxREZFQjYxMURGQjBDREYyQUE0QTc0OUI5QyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0NkQwREIxRUZFQjYxMURGQjBDREYyQUE0QTc0OUI5QyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PpHo8kwAAACBSURBVHjaYvz//z8DJYCJgUJAsQEsyBxGRkYwBcS6QKwBxLJQqcdAfAOILwPxf2RvM6JwICbYA7EDDgsPAPFBZBPQvaCLRzMDVE4XXxhoEOFtDXwGyBJhgCxNo/ExEXoe4zPgBhEG3MBnwGVoVDHgicbLKGkHLR1QlpCGZmYCCDAAxuMoE4WhhWUAAAAASUVORK5CYII=) 7 7 7 7 round round;
|
341
|
+
}
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Reacco::Extractor::Block [class]
|
2
|
+
# An extractor block.
|
3
|
+
#
|
4
|
+
module Reacco
|
5
|
+
class Extractor
|
6
|
+
class Block
|
7
|
+
# body [method]
|
8
|
+
# Returns the body text as a raw string.
|
9
|
+
attr_reader :body
|
10
|
+
|
11
|
+
# title [method]
|
12
|
+
# Returns the title of the block.
|
13
|
+
attr_reader :title
|
14
|
+
attr_reader :type
|
15
|
+
attr_reader :parent
|
16
|
+
attr_reader :args
|
17
|
+
|
18
|
+
def initialize(options)
|
19
|
+
@body = options[:body]
|
20
|
+
@type = options[:type] && options[:type].downcase
|
21
|
+
@args = options[:args]
|
22
|
+
@title = options[:title]
|
23
|
+
@parent = options[:parent]
|
24
|
+
@tag = options[:tag]
|
25
|
+
@source_line = options[:source_line]
|
26
|
+
@source_path = options[:source_path]
|
27
|
+
end
|
28
|
+
|
29
|
+
# children [method]
|
30
|
+
# Returns an array of child blocks.
|
31
|
+
def children
|
32
|
+
@children ||= Array.new
|
33
|
+
end
|
34
|
+
|
35
|
+
# << [method]
|
36
|
+
# Adds a block to it's children.
|
37
|
+
def <<(blk)
|
38
|
+
children << blk
|
39
|
+
end
|
40
|
+
|
41
|
+
def raw_html
|
42
|
+
Reacco.markdown.render(@body)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Nokogiri node.
|
46
|
+
def doc
|
47
|
+
@doc ||= Nokogiri::HTML(raw_html)
|
48
|
+
end
|
49
|
+
|
50
|
+
def transform!
|
51
|
+
# Create heading.
|
52
|
+
name = @tag
|
53
|
+
node = Nokogiri::XML::Node.new(name, doc)
|
54
|
+
node['class'] = 'api'
|
55
|
+
node.content = title
|
56
|
+
|
57
|
+
# Add '(args)'.
|
58
|
+
if args
|
59
|
+
span = Nokogiri::XML::Node.new("span", doc)
|
60
|
+
span['class'] = 'args'
|
61
|
+
span.content = args
|
62
|
+
node.add_child span
|
63
|
+
end
|
64
|
+
|
65
|
+
# Add '(class method)'.
|
66
|
+
span = Nokogiri::XML::Node.new("span", doc)
|
67
|
+
span['class'] = 'type'
|
68
|
+
span.content = type
|
69
|
+
node.add_child Nokogiri::XML::Text.new(' ', doc)
|
70
|
+
node.add_child span
|
71
|
+
|
72
|
+
# Add heading.
|
73
|
+
doc.at_css('body>*:first-child').add_previous_sibling node
|
74
|
+
doc
|
75
|
+
end
|
76
|
+
|
77
|
+
# to_html [method]
|
78
|
+
# Returns the raw HTML to be included in the documentation.
|
79
|
+
def to_html
|
80
|
+
@to_html ||= transform!.at_css('body').inner_html
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ostruct'
|
4
|
+
require 'fileutils'
|
5
|
+
module Reacco
|
6
|
+
# Reacco::Extractor [class]
|
7
|
+
# Extracts comments from list of files.
|
8
|
+
#
|
9
|
+
# #### Instantiating
|
10
|
+
# Call the constructor with a list of files.
|
11
|
+
#
|
12
|
+
# ex = Extractor.new(Dir['./**/*.rb'])
|
13
|
+
#
|
14
|
+
class Extractor
|
15
|
+
autoload :Block, 'reacco/extractor/block'
|
16
|
+
|
17
|
+
def initialize(files, root=nil, options={})
|
18
|
+
@files = files.sort
|
19
|
+
@root = File.realpath(root || Dir.pwd)
|
20
|
+
end
|
21
|
+
|
22
|
+
# blocks [method]
|
23
|
+
# Returns an array of `Block` instances.
|
24
|
+
#
|
25
|
+
# ex.blocks
|
26
|
+
# ex.blocks.map { |b| puts "file: #{b.file}" }
|
27
|
+
#
|
28
|
+
def blocks
|
29
|
+
@blocks ||= begin
|
30
|
+
@files.map do |file|
|
31
|
+
if File.file?(file)
|
32
|
+
input = File.read(file)
|
33
|
+
get_blocks(input, unroot(file))
|
34
|
+
end
|
35
|
+
end.compact.flatten
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def unroot(fn)
|
41
|
+
(File.realpath(fn))[@root.size..-1]
|
42
|
+
end
|
43
|
+
|
44
|
+
# get_blocks(str, [filename]) [private method]
|
45
|
+
# Returns the documentation blocks in a given `str`ing.
|
46
|
+
# If `filename` is given, it will be set as the *source_file*.
|
47
|
+
#
|
48
|
+
def get_blocks(str, filename=nil)
|
49
|
+
arr = get_comment_blocks(str)
|
50
|
+
|
51
|
+
arr.map do |hash|
|
52
|
+
block = hash[:block]
|
53
|
+
|
54
|
+
# Ensure the first line matches.
|
55
|
+
# This matches:
|
56
|
+
# "### name [type]"
|
57
|
+
# "## name(args) [type]"
|
58
|
+
re = /^(\#{1,6}) (.*?) ?(\(.*?\))? ?(?:\[([a-z ]+)\])?$/
|
59
|
+
block.first =~ re or next
|
60
|
+
|
61
|
+
blk = Extractor::Block.new \
|
62
|
+
:type => $4,
|
63
|
+
:tag => "h#{$1.strip.size}",
|
64
|
+
:title => $2,
|
65
|
+
:args => $3,
|
66
|
+
:source_line => hash[:line] + block.size + 1,
|
67
|
+
:source_file => filename,
|
68
|
+
:body => (block[1..-1].join("\n") + "\n")
|
69
|
+
|
70
|
+
blk
|
71
|
+
end.compact
|
72
|
+
end
|
73
|
+
|
74
|
+
# get_comment_blocks (private method)
|
75
|
+
# Returns contiguous comment blocks.
|
76
|
+
#
|
77
|
+
# Returns an array of hashes that look like
|
78
|
+
# `{ :block => [line1, line2...], :line => (line number) }`
|
79
|
+
#
|
80
|
+
def get_comment_blocks(str)
|
81
|
+
chunks = Array.new
|
82
|
+
i = 0
|
83
|
+
|
84
|
+
str.split("\n").each_with_index { |s, line|
|
85
|
+
if s =~ /^\s*(?:\/\/\/?|##?) ?(.*)$/
|
86
|
+
chunks[i] ||= { :block => Array.new, :line => line }
|
87
|
+
chunks[i][:block] << $1
|
88
|
+
else
|
89
|
+
i += 1 if chunks[i]
|
90
|
+
end
|
91
|
+
}
|
92
|
+
|
93
|
+
chunks.compact
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Reacco
|
2
|
+
module Filters
|
3
|
+
module Hgroup
|
4
|
+
# Wraps the first headings into an <hgroup>.
|
5
|
+
def wrap_hgroup(html)
|
6
|
+
nodes = Array.new
|
7
|
+
html.css('body>*').each { |node|
|
8
|
+
# Consume all headings.
|
9
|
+
if %w(h1 h2 h3 h4 h5 h6).include?(node.name)
|
10
|
+
nodes << node.to_s
|
11
|
+
node.remove
|
12
|
+
|
13
|
+
# Once the headings stop, dump them into an <hgroup>.
|
14
|
+
# Ah, and eat an <hr> if there is one.
|
15
|
+
else
|
16
|
+
node.before("<hgroup class='header'>#{nodes.join('')}</hgroup>") if nodes.any?
|
17
|
+
node.remove if node.name == 'hr'
|
18
|
+
break
|
19
|
+
end
|
20
|
+
}
|
21
|
+
|
22
|
+
html
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Reacco
|
2
|
+
module Filters
|
3
|
+
module Literate
|
4
|
+
# Moves pre's after headers.
|
5
|
+
def move_pre(html)
|
6
|
+
anchor = nil
|
7
|
+
position = nil
|
8
|
+
|
9
|
+
html.css('body>*').each_cons(2) { |(node, nxt)|
|
10
|
+
# Once we find the <pre>, move it.
|
11
|
+
if node.name == 'pre' && anchor && anchor != node && !(node['class'].to_s =~ /full/)
|
12
|
+
node.after "<br class='post-pre'>"
|
13
|
+
|
14
|
+
nxt['class'] = "#{nxt['class']} after-pre" if nxt
|
15
|
+
node['class'] = "#{node['class']} right"
|
16
|
+
|
17
|
+
anchor.send position, node
|
18
|
+
anchor = nil
|
19
|
+
|
20
|
+
# If we find one of these, put the next <pre> after it.
|
21
|
+
elsif %w(h1 h2 h3 h4 pre).include?(node.name)
|
22
|
+
anchor = node
|
23
|
+
position = :add_next_sibling
|
24
|
+
|
25
|
+
# If we find one of these, put the <pre> before it.
|
26
|
+
elsif node['class'].to_s.include?('after-pre')
|
27
|
+
anchor = node
|
28
|
+
position = :add_previous_sibling
|
29
|
+
end
|
30
|
+
}
|
31
|
+
|
32
|
+
html
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Reacco
|
2
|
+
module Filters
|
3
|
+
module Sections
|
4
|
+
# Wraps in sections.
|
5
|
+
def section_wrap(html)
|
6
|
+
%w(h1 h2 h3 h4 h5).each do |h|
|
7
|
+
nodes = html.css(h)
|
8
|
+
nodes.each do |alpha|
|
9
|
+
# For those affected by --hgroup, don't bother.
|
10
|
+
next if alpha.ancestors.any? { |tag| tag.name == 'hgroup' }
|
11
|
+
next unless alpha.parent
|
12
|
+
|
13
|
+
# Find the boundary, and get the nodes until that one.
|
14
|
+
omega = from_x_until(alpha, alpha.name)
|
15
|
+
section_nodes = between(alpha, omega)
|
16
|
+
|
17
|
+
# Create the <section>.
|
18
|
+
section = Nokogiri::XML::Node.new('section', html)
|
19
|
+
section['class'] = "#{alpha['class']} #{h} #{slugify alpha.content}"
|
20
|
+
alpha.add_previous_sibling(section)
|
21
|
+
section_nodes.each { |tag| section.add_child tag }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
html
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def from_x_until(alpha, name)
|
30
|
+
omega = nil
|
31
|
+
n = alpha
|
32
|
+
|
33
|
+
while true
|
34
|
+
n = n.next_sibling
|
35
|
+
break if n.nil? || n.name == name
|
36
|
+
omega = n
|
37
|
+
end
|
38
|
+
|
39
|
+
omega
|
40
|
+
end
|
41
|
+
|
42
|
+
def between(first, last)
|
43
|
+
nodes = Array.new
|
44
|
+
started = false
|
45
|
+
|
46
|
+
first.parent.children.each do |node|
|
47
|
+
started = true if node == first
|
48
|
+
nodes << node if started
|
49
|
+
break if node == last
|
50
|
+
end
|
51
|
+
|
52
|
+
nodes
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Reacco
|
2
|
+
module Filters
|
3
|
+
module TOC
|
4
|
+
def make_toc(contents)
|
5
|
+
aside = Nokogiri::XML::Node.new('aside', contents)
|
6
|
+
aside['id'] = 'toc'
|
7
|
+
|
8
|
+
# Header
|
9
|
+
title = (h1 = contents.at_css('h1')) && h1.text || File.basename(Dir.pwd)
|
10
|
+
aside.inner_html = "#{aside.inner_html}<h1>#{title}</h1>"
|
11
|
+
|
12
|
+
contents.xpath('//body/section').each { |tag|
|
13
|
+
aside.inner_html = "#{aside.inner_html}#{make_section tag}"
|
14
|
+
}
|
15
|
+
|
16
|
+
contents.at_css('body').add_child aside
|
17
|
+
|
18
|
+
contents
|
19
|
+
end
|
20
|
+
|
21
|
+
def linkify(h)
|
22
|
+
href = slugify(h.content)
|
23
|
+
"<a href='##{href}'>#{h.inner_html}</a>"
|
24
|
+
end
|
25
|
+
|
26
|
+
def make_section(section)
|
27
|
+
h = section.at_css('h1, h2, h3')
|
28
|
+
return '' unless h
|
29
|
+
level = h.name[1] # 1 | 2 | 3
|
30
|
+
return '' unless %w(1 2 3).include?(level)
|
31
|
+
name = h.content.strip
|
32
|
+
|
33
|
+
out = case level
|
34
|
+
when "1"
|
35
|
+
[ "<h2>#{linkify h}</h2>",
|
36
|
+
section.css('section.h2').map { |s| make_section s }
|
37
|
+
]
|
38
|
+
when "2"
|
39
|
+
[ "<nav class='level-#{level}'>",
|
40
|
+
"<h3>#{linkify h}</h3>",
|
41
|
+
"<ul>",
|
42
|
+
section.css('section.h3').map { |s| make_section s },
|
43
|
+
"</ul>",
|
44
|
+
"</nav>"
|
45
|
+
]
|
46
|
+
when "3"
|
47
|
+
[ "<li>#{linkify h}</li>" ]
|
48
|
+
end
|
49
|
+
|
50
|
+
out.flatten.join "\n"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Reacco
|
2
|
+
class Generator
|
3
|
+
def initialize(readme, dir, template=nil, css=nil)
|
4
|
+
@readme = readme
|
5
|
+
@dir = dir
|
6
|
+
@css = css
|
7
|
+
@template = template || Reacco.root('data')
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns the HTML contents.
|
11
|
+
def html
|
12
|
+
file = Dir["#{@template}/index.*"].first
|
13
|
+
raise "No index file found in template path." unless file
|
14
|
+
|
15
|
+
tpl = Tilt.new(file)
|
16
|
+
out = tpl.render({}, @readme.locals) { @readme.html }
|
17
|
+
end
|
18
|
+
|
19
|
+
# Writes to the output directory.
|
20
|
+
def write!(&blk)
|
21
|
+
yield "#{@dir}/index.html"
|
22
|
+
write_to "#{@dir}/index.html", html
|
23
|
+
copy_files &blk
|
24
|
+
append_css if @css
|
25
|
+
end
|
26
|
+
|
27
|
+
def template?
|
28
|
+
File.directory?(@template) && Dir["#{@template}/index.*"].first
|
29
|
+
end
|
30
|
+
|
31
|
+
# Adds the CSS file to the style.css file.
|
32
|
+
def append_css
|
33
|
+
contents = File.read(@css)
|
34
|
+
File.open("#{@dir}/style.css", 'a+') { |f| f.write "\n/* Custom */\n#{contents}" }
|
35
|
+
end
|
36
|
+
|
37
|
+
def copy_files(&blk)
|
38
|
+
files = Dir.chdir(@template) { Dir['**/*'] }
|
39
|
+
|
40
|
+
# For each of the template files...
|
41
|
+
files.each do |f|
|
42
|
+
next if File.basename(f)[0] == '_'
|
43
|
+
next if File.fnmatch('index.*', f)
|
44
|
+
ext = File.extname(f)[1..-1]
|
45
|
+
|
46
|
+
fullpath = File.join @template, f
|
47
|
+
|
48
|
+
# Try to render it with Tilt if possible.
|
49
|
+
if Tilt.mappings.keys.include?(ext)
|
50
|
+
contents = Tilt.new(fullpath).render
|
51
|
+
outfile = f.match(/^(.*)(\.[^\.]+)$/) && $1
|
52
|
+
else
|
53
|
+
contents = File.read(fullpath)
|
54
|
+
outfile = f
|
55
|
+
end
|
56
|
+
|
57
|
+
yield "#{@dir}/#{outfile}"
|
58
|
+
write_to "#{@dir}/#{outfile}", contents
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
def write_to(path, data)
|
64
|
+
FileUtils.mkdir_p File.dirname(path)
|
65
|
+
File.open(path, 'w') { |f| f.write data }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# ## Reacco::Readme [class]
|
2
|
+
# A readme file.
|
3
|
+
module Reacco
|
4
|
+
class Readme
|
5
|
+
def initialize(options={})
|
6
|
+
@file = options.delete(:file) if options[:file]
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
# ### file [method]
|
11
|
+
# The path to the README file. Returns nil if not available.
|
12
|
+
def file
|
13
|
+
@file ||= (Dir['README.*'].first || Dir['readme.*'].first || Dir['README'].first)
|
14
|
+
end
|
15
|
+
|
16
|
+
def file=(file)
|
17
|
+
@file = file
|
18
|
+
end
|
19
|
+
|
20
|
+
# ### switches [method]
|
21
|
+
# The switches, like 'literate' and 'hgroup'. Returns an array of strings.
|
22
|
+
def switches
|
23
|
+
@options.keys.map { |k| k.to_s }
|
24
|
+
end
|
25
|
+
|
26
|
+
# ### exists? [method]
|
27
|
+
# Returns true if the file (given in the constructor) exists.
|
28
|
+
def exists?
|
29
|
+
file && File.exists?(file)
|
30
|
+
end
|
31
|
+
|
32
|
+
# ### raw [method]
|
33
|
+
# Returns raw Markdown markup.
|
34
|
+
def raw
|
35
|
+
@raw ||= File.read(file)
|
36
|
+
end
|
37
|
+
|
38
|
+
# ### title [method]
|
39
|
+
# Returns a string of the title of the document (the first h1).
|
40
|
+
def title
|
41
|
+
@title ||= begin
|
42
|
+
h1 = (h1 = doc.at_css('h1')) && h1.text
|
43
|
+
h1 || File.basename(Dir.pwd)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def title?
|
48
|
+
title.to_s.size > 0
|
49
|
+
end
|
50
|
+
|
51
|
+
# ### raw_html [method]
|
52
|
+
# Raw HTML data.
|
53
|
+
def raw_html
|
54
|
+
@raw_html ||= markdown.render(raw)
|
55
|
+
end
|
56
|
+
|
57
|
+
def raw_html=(str)
|
58
|
+
@raw_html = str
|
59
|
+
end
|
60
|
+
|
61
|
+
# ### inject_api_block [method]
|
62
|
+
# Adds an API block. Takes an `html` argument.
|
63
|
+
def inject_api_block(html)
|
64
|
+
@api_blocks = "#{api_blocks}\n#{html}\n"
|
65
|
+
end
|
66
|
+
|
67
|
+
def api_blocks
|
68
|
+
@api_blocks ||= ""
|
69
|
+
end
|
70
|
+
|
71
|
+
# ### doc [method]
|
72
|
+
# Returns HTML as a Nokogiri document.
|
73
|
+
def doc(options={})
|
74
|
+
@doc ||= begin
|
75
|
+
add_api(api_blocks)
|
76
|
+
html = Nokogiri::HTML(raw_html)
|
77
|
+
|
78
|
+
html = pre_lang(html)
|
79
|
+
html = heading_id(html)
|
80
|
+
html = wrap_hgroup(html)
|
81
|
+
html = move_pre(html) if @options[:literate]
|
82
|
+
html = brief_first_p(html)
|
83
|
+
html = section_wrap(html)
|
84
|
+
html = make_toc(html) if @options[:toc]
|
85
|
+
|
86
|
+
html
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# ### html [method]
|
91
|
+
# Returns body's inner HTML.
|
92
|
+
def html
|
93
|
+
doc.at_css('body').inner_html
|
94
|
+
end
|
95
|
+
|
96
|
+
# ### github [method]
|
97
|
+
# Returns the GitHub URL, or nil if not applicable.
|
98
|
+
def github
|
99
|
+
"https://github.com/#{@options[:github]}" if @options[:github]
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns locals for the template.
|
103
|
+
def locals
|
104
|
+
{ :title => title,
|
105
|
+
:body_class => switches.join(' '),
|
106
|
+
:github => github }
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
include Filters::Brief
|
111
|
+
include Filters::Sections
|
112
|
+
include Filters::Hgroup
|
113
|
+
include Filters::Literate
|
114
|
+
include Filters::PreLang
|
115
|
+
include Filters::HeadingID
|
116
|
+
include Filters::TOC
|
117
|
+
|
118
|
+
# Puts `blocks` inside `raw_html`.
|
119
|
+
def add_api(blocks)
|
120
|
+
re1 = %r{^.*api reference goes here.*$}i
|
121
|
+
re2 = %r{^.*#api_reference.*$}i
|
122
|
+
|
123
|
+
if raw_html =~ re1
|
124
|
+
raw_html.gsub! re1, blocks
|
125
|
+
elsif raw_html =~ re2
|
126
|
+
raw_html.gsub! re2, blocks
|
127
|
+
else
|
128
|
+
self.raw_html = "#{raw_html}\n#{blocks}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# ### markdown [private method]
|
133
|
+
# Returns the Markdown processor.
|
134
|
+
#
|
135
|
+
# markdown.render(md)
|
136
|
+
#
|
137
|
+
def markdown
|
138
|
+
Reacco.markdown
|
139
|
+
end
|
140
|
+
|
141
|
+
# ### slugify [private method]
|
142
|
+
# Turns text into a slug.
|
143
|
+
#
|
144
|
+
# "Install instructions" => "install_instructions"
|
145
|
+
#
|
146
|
+
def slugify(str)
|
147
|
+
str.downcase.scan(/[a-z0-9\-]+/).join('_')
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
data/lib/reacco.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'redcarpet'
|
3
|
+
require 'tilt'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
# ## Reacco [module]
|
8
|
+
# This is the main module.
|
9
|
+
#
|
10
|
+
module Reacco
|
11
|
+
extend self
|
12
|
+
|
13
|
+
# ### root [class method]
|
14
|
+
# Returns the root path of the Reacco gem.
|
15
|
+
# You may pass additional parameters.
|
16
|
+
#
|
17
|
+
# Reacco.root #=> '/usr/local/ruby/gems/reacco-0.0.1'
|
18
|
+
#
|
19
|
+
def root(*a)
|
20
|
+
File.join File.expand_path('../../', __FILE__), *a
|
21
|
+
end
|
22
|
+
|
23
|
+
# ### markdown [class method]
|
24
|
+
# Returns the Redcarpet Markdown processor.
|
25
|
+
def markdown
|
26
|
+
Redcarpet::Markdown.new(Redcarpet::Render::HTML,
|
27
|
+
:fenced_code_blocks => true)
|
28
|
+
end
|
29
|
+
|
30
|
+
autoload :Readme, 'reacco/readme'
|
31
|
+
autoload :Generator, 'reacco/generator'
|
32
|
+
autoload :Extractor, 'reacco/extractor'
|
33
|
+
|
34
|
+
module Filters
|
35
|
+
autoload :Brief, 'reacco/filters/brief'
|
36
|
+
autoload :Sections, 'reacco/filters/sections'
|
37
|
+
autoload :Hgroup, 'reacco/filters/hgroup'
|
38
|
+
autoload :Literate, 'reacco/filters/literate'
|
39
|
+
autoload :PreLang, 'reacco/filters/prelang'
|
40
|
+
autoload :HeadingID, 'reacco/filters/headingid'
|
41
|
+
autoload :TOC, 'reacco/filters/toc'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
data/reacco.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require './lib/reacco/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "reacco"
|
5
|
+
s.version = Reacco.version
|
6
|
+
s.summary = %{Readme prettifier.}
|
7
|
+
s.description = %Q{Reacco makes your readme's pretty.}
|
8
|
+
s.authors = ["Rico Sta. Cruz"]
|
9
|
+
s.email = ["rico@sinefunc.com"]
|
10
|
+
s.homepage = "http://github.com/rstacruz/reacco"
|
11
|
+
s.files = `git ls-files`.strip.split("\n")
|
12
|
+
s.executables = Dir["bin/*"].map { |f| File.basename(f) }
|
13
|
+
|
14
|
+
s.add_dependency 'redcarpet', '~> 2.0.0b3'
|
15
|
+
s.add_dependency 'nokogiri', '~> 1.5'
|
16
|
+
s.add_dependency 'tilt'
|
17
|
+
end
|
data/test/blocks_test.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
class BlocksTest < UnitTest
|
4
|
+
setup do
|
5
|
+
@ex = Reacco::Extractor.new(Dir[root 'lib/**/*.rb'])
|
6
|
+
end
|
7
|
+
|
8
|
+
should "extract comments" do
|
9
|
+
# From Reacco.root
|
10
|
+
block = @ex.blocks.detect { |blk| blk.title == "root" && blk.type == "class method" }
|
11
|
+
assert ! block.nil?
|
12
|
+
end
|
13
|
+
|
14
|
+
should "htmlize properly" do
|
15
|
+
block = @ex.blocks.detect { |blk| blk.title == "root" && blk.type == "class method" }
|
16
|
+
p block.to_html
|
17
|
+
end
|
18
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: reacco
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rico Sta. Cruz
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-18 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: redcarpet
|
16
|
+
requirement: &2156349300 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.0.0b3
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2156349300
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: nokogiri
|
27
|
+
requirement: &2156348320 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '1.5'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2156348320
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: tilt
|
38
|
+
requirement: &2156347220 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2156347220
|
47
|
+
description: Reacco makes your readme's pretty.
|
48
|
+
email:
|
49
|
+
- rico@sinefunc.com
|
50
|
+
executables:
|
51
|
+
- reacco
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- .gitignore
|
56
|
+
- Gemfile
|
57
|
+
- HISTORY.md
|
58
|
+
- README.md
|
59
|
+
- Rakefile
|
60
|
+
- bin/reacco
|
61
|
+
- data/index.erb
|
62
|
+
- data/style.css
|
63
|
+
- lib/reacco.rb
|
64
|
+
- lib/reacco/extractor.rb
|
65
|
+
- lib/reacco/extractor/block.rb
|
66
|
+
- lib/reacco/filters/brief.rb
|
67
|
+
- lib/reacco/filters/headingid.rb
|
68
|
+
- lib/reacco/filters/hgroup.rb
|
69
|
+
- lib/reacco/filters/literate.rb
|
70
|
+
- lib/reacco/filters/prelang.rb
|
71
|
+
- lib/reacco/filters/sections.rb
|
72
|
+
- lib/reacco/filters/toc.rb
|
73
|
+
- lib/reacco/generator.rb
|
74
|
+
- lib/reacco/readme.rb
|
75
|
+
- lib/reacco/version.rb
|
76
|
+
- reacco.gemspec
|
77
|
+
- test/blocks_test.rb
|
78
|
+
- test/test_helper.rb
|
79
|
+
homepage: http://github.com/rstacruz/reacco
|
80
|
+
licenses: []
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
requirements: []
|
98
|
+
rubyforge_project:
|
99
|
+
rubygems_version: 1.8.10
|
100
|
+
signing_key:
|
101
|
+
specification_version: 3
|
102
|
+
summary: Readme prettifier.
|
103
|
+
test_files: []
|