hanna-bootstrap 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009 Mislav Marohnić
2
+ Copyright (c) 2010, 2011 Erik Hollensbe
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the "Software"), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ the Software, and to permit persons to whom the Software is furnished to do so,
9
+ subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,81 @@
1
+ = Hanna Bootstrap — a better RDoc template, now for RDoc 2.5 and 3.0.
2
+
3
+ Based on the original Hanna by Mislav, Hanna Nouveau by Erik.
4
+
5
+ Hanna is an RDoc generator that scales. It's implemented in Haml, making the
6
+ sources clean and readable. It's built with simplicity, beauty and ease of
7
+ browsing in mind. (See more in {the
8
+ wiki}[http://github.com/mislav/hanna/wikis/home].)
9
+
10
+ Hanna gem is available from http://rubygems.org:
11
+
12
+ gem install hanna-nouveau
13
+
14
+ The template was created by {Mislav}[http://mislav.caboo.se/] and since then
15
+ has seen contributions from:
16
+
17
+ 1. {Tony Strauss}[http://github.com/DesigningPatterns], who participated from
18
+ the early start and made tons of fixes and enhancements to the template;
19
+ 2. {Hongli Lai}[http://blog.phusion.nl/] with the search filter for methods.
20
+ 3. {Erik Hollensbe}[http://github.com/erikh] a serious refactoring and up to
21
+ date with RDoc 2.5.x and 3.x, now named 'hanna-nouveau'.
22
+ 4. {James Tucker}[http://github.com/raggi] minor cleanups for Erik.
23
+
24
+ == Usage
25
+
26
+ rdoc -o doc -f hanna lib/*.rb
27
+
28
+ An alternative is to set the `RDOCOPT` environment variable:
29
+
30
+ RDOCOPT="-f hanna"
31
+
32
+ This will make RDoc always use Hanna unless it is explicitly overridden.
33
+
34
+ == Integrating with RubyGems
35
+
36
+ Another neat trick is to put the following line in your .gemrc, this will make
37
+ RubyGems use Hanna for all rdoc generation:
38
+
39
+ rdoc: -f hanna
40
+
41
+ This will make RubyGems use Hanna when generating documentation for installed
42
+ gems. Remember, if you wish to have all your gems be formatted in hanna:
43
+
44
+ gem rdoc --all --overwrite
45
+
46
+ The first time. To easily browse your newly created documentation, use:
47
+
48
+ gem server
49
+
50
+ == Rake task
51
+
52
+ For repeated generation of API docs, it's better to set up a Rake task. Simply
53
+ add the hanna format argument to your RDoc::Task options:
54
+
55
+ gem 'rdoc'
56
+ require 'rdoc/task'
57
+ RDoc::Task.new do |rdoc|
58
+ # this only works with RDoc 3.1 or greater
59
+ rdoc.generator = 'hanna'
60
+ # this is what you use pre RDoc 3.1:
61
+ rdoc.options.push '-f', 'hanna'
62
+ end
63
+
64
+ Tip: you can do this in the Rakefile of your Rails project before running
65
+ `rake doc:rails`.
66
+
67
+ Here is an example of a task for the {rdbi
68
+ library}[http://github.com/rdbi/rdbi/tree/master/Rakefile]:
69
+
70
+ gem 'rdoc'
71
+ require 'rdoc/task'
72
+ RDoc::Task.new do |rdoc|
73
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
74
+
75
+ rdoc.generator = 'hanna'
76
+ rdoc.main = 'README.rdoc'
77
+ rdoc.rdoc_dir = 'rdoc'
78
+ rdoc.title = "RDBI #{version} Documentation"
79
+ rdoc.rdoc_files.include('README*')
80
+ rdoc.rdoc_files.include('lib/**/*.rb')
81
+ end
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ require 'rubygems'
4
+ require 'bundler/gem_tasks'
5
+ require 'rdoc/task'
6
+
7
+ task :default => :rdoc
8
+
9
+ RDoc::Task.new do |rdoc|
10
+
11
+ rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb")
12
+ rdoc.generator = 'bootstrap'
13
+ rdoc.main = "README.rdoc"
14
+ rdoc.rdoc_dir = 'doc'
15
+ rdoc.title = 'hanna-bootstrap'
16
+
17
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.4
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ require 'hanna-bootstrap'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{hanna-bootstrap}
8
+ s.version = RDoc::Generator::Bootstrap::VERSION
9
+
10
+ s.authors = ["Atsushi Nagase", "Erik Hollensbe", "James Tucker", "Mislav Marohnic"]
11
+ s.date = Time.now.strftime("%Y-%m-%d")
12
+ s.description = %q{}
13
+ s.email = %q{a@ngs.io}
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = `git ls-files`.split("\n").reject{|f| f =~ /^(\..+|Gemfile.*|Guardfile|)$/}
19
+ s.homepage = %q{http://github.com/ngs/hanna-bootstrap}
20
+ s.licenses = ["MIT"]
21
+ s.require_paths = ["lib"]
22
+ s.summary = %q{Twitter Boostrap theme for RDoc}
23
+
24
+ s.add_development_dependency 'bundler'
25
+ s.add_development_dependency 'coffee-script'
26
+ s.add_development_dependency 'haml'
27
+ s.add_development_dependency 'json'
28
+ s.add_development_dependency 'rake'
29
+ s.add_development_dependency 'sass'
30
+ end
31
+
@@ -0,0 +1,368 @@
1
+ # = Twitter Boostrap theme for RDoc
2
+ #
3
+ # Code rewritten by:
4
+ # Atsushi Nagase <a@ngs.io>
5
+ #
6
+ # Original Authors:
7
+ # James Tucker (aka raggi)
8
+ # Erik Hollensbe <erik@hollensbe.org>
9
+ # Mislav Marohnić <mislav.marohnic@gmail.com>
10
+ # Tony Strauss (http://github.com/DesigningPatterns)
11
+ # Michael Granger <ged@FaerieMUD.org>, who had maintained the original RDoc template
12
+
13
+ require 'pathname'
14
+ require 'haml'
15
+ require 'sass'
16
+ require 'rdoc/rdoc'
17
+ require 'rdoc/generator'
18
+ require 'coffee-script'
19
+ require 'json'
20
+
21
+ class RDoc::Generator::Bootstrap
22
+
23
+ VERSION = '0.0.1'
24
+
25
+ LAYOUT = 'layout.haml'
26
+
27
+ CLASS_PAGE = 'page.haml'
28
+ METHOD_LIST_PAGE = 'method_list.haml'
29
+ FILE_PAGE = CLASS_PAGE
30
+ SECTIONS_PAGE = 'sections.haml'
31
+
32
+ FILE_INDEX = 'file_index.haml'
33
+ CLASS_INDEX = 'class_index.haml'
34
+ METHOD_INDEX = 'method_index.haml'
35
+
36
+ CLASS_DIR = 'classes'
37
+ FILE_DIR = 'files'
38
+
39
+ INDEX_OUT = 'index.html'
40
+ FILE_INDEX_OUT = File.join 'files', 'index.html'
41
+ CLASS_INDEX_OUT = File.join 'classes', 'index.html'
42
+ METHOD_INDEX_OUT = File.join 'method', 'index.html'
43
+
44
+ DESCRIPTION = 'Twitter Bootstrap theme for RDoc'
45
+
46
+ # EPIC CUT AND PASTE TIEM NAO -- GG
47
+ RDoc::RDoc.add_generator( self )
48
+
49
+ def self::for( options )
50
+ new( options )
51
+ end
52
+
53
+ def initialize( options )
54
+ @options = options
55
+
56
+ @templatedir = Pathname.new File.expand_path('../hanna-bootstrap/template_files', __FILE__)
57
+
58
+ @files = nil
59
+ @classes = nil
60
+ @methods = nil
61
+ @attributes = nil
62
+
63
+ @basedir = Pathname.pwd.expand_path
64
+ end
65
+
66
+ def default_values( path )
67
+ {
68
+ stylesheets: [
69
+ outpath(File.join('css', 'bootstrap.min.css' ), path),
70
+ outpath(File.join('css', 'application.css' ), path)
71
+ ],
72
+ javascripts: [
73
+ outpath(File.join('js', 'jquery.js' ), path),
74
+ outpath(File.join('js', 'bootstrap.min.js' ), path),
75
+ outpath(File.join('js', 'index.js' ), path),
76
+ outpath(File.join('js', 'application.js' ), path)
77
+ ],
78
+ mainpage: outpath('', path),
79
+ files: @files,
80
+ classes: @classes,
81
+ methods: @methods,
82
+ attributes: @attributes,
83
+ options: @options,
84
+ path: path
85
+ }
86
+
87
+ end
88
+
89
+ def generate( top_levels )
90
+ @outputdir = Pathname.new( @options.op_dir ).expand_path( @basedir )
91
+
92
+ @files = top_levels.sort
93
+ @classes = RDoc::TopLevel.all_classes_and_modules.sort
94
+ @methods = @classes.map(&:method_list).flatten.sort
95
+ @attributes = @classes.map(&:attributes).flatten.sort
96
+
97
+ # Now actually write the output
98
+ write_static_files
99
+
100
+ generate_class_files
101
+ generate_file_files
102
+ generate_indexes
103
+
104
+ rescue StandardError => err
105
+ p [ err.class.name, err.message, err.backtrace.join("\n ") ]
106
+ raise
107
+ end
108
+
109
+ def write_static_files
110
+ css_dir = outjoin('css')
111
+ js_dir = outjoin('js')
112
+ img_dir = outjoin('img')
113
+
114
+ [css_dir, js_dir, img_dir].each { |dir|
115
+ FileUtils.mkdir dir unless File.directory?(dir)
116
+ }
117
+
118
+ File.open(File.join(css_dir, 'application.css'), 'w') { |f|
119
+ f << Sass::Engine.new(File.read(templjoin('application.sass'))).to_css
120
+ }
121
+
122
+ File.open(File.join(js_dir, 'application.js'), 'w') { |f|
123
+ f << CoffeeScript.compile(File.read(templjoin('application.coffee')))
124
+ }
125
+
126
+ File.open(File.join(js_dir, 'index.js'), 'w') { |f|
127
+ f << build_javascript_search_index(@methods + @attributes)
128
+ }
129
+
130
+ FileUtils.cp %w{
131
+ bootstrap.min.js
132
+ jquery.js
133
+ }.map{|f| templjoin f }, js_dir
134
+
135
+ FileUtils.cp %w{
136
+ glyphicons-halflings-white.png
137
+ glyphicons-halflings.png
138
+ }.map{|f| templjoin f }, img_dir
139
+
140
+ FileUtils.cp %w{
141
+ bootstrap.min.css
142
+ }.map{|f| templjoin f }, css_dir
143
+
144
+ end
145
+
146
+ def generate_indexes
147
+ generate_index(FILE_INDEX_OUT, FILE_INDEX, 'File')
148
+ generate_index(CLASS_INDEX_OUT, CLASS_INDEX, 'Class')
149
+ generate_index(METHOD_INDEX_OUT, METHOD_INDEX, 'Method')
150
+ end
151
+
152
+ def generate_index(outfile, templfile, index_name)
153
+ path = Pathname.new(outfile)
154
+ dir = path.dirname
155
+ unless File.directory? dir
156
+ FileUtils.mkdir_p dir
157
+ end
158
+
159
+ values = default_values(path).merge({
160
+ :list_title => "#{index_name} Index"
161
+ })
162
+
163
+ index = haml_file(templjoin(templfile))
164
+
165
+ File.open(path, 'w') do |f|
166
+ f << with_layout(values) do
167
+ index.to_html(binding, values)
168
+ end
169
+ end
170
+ end
171
+
172
+ def generate_file_files
173
+
174
+ # FIXME non-Ruby files
175
+ @files.each do |file|
176
+ generate_file_file(file)
177
+ generate_file_file(file, 'index.html') if @options.main_page == file.name
178
+ end
179
+ end
180
+
181
+ def generate_file_file(file, path = nil)
182
+ file_page = haml_file(templjoin(FILE_PAGE))
183
+ method_list_page = haml_file(templjoin(METHOD_LIST_PAGE))
184
+
185
+ path = Pathname.new(path || file.path)
186
+ values = default_values(path).merge({
187
+ :file => file,
188
+ :entry => file,
189
+ :classmod => nil,
190
+ :title => file.base_name,
191
+ :list_title => nil,
192
+ :description => file.description
193
+ })
194
+
195
+ result = with_layout(values) do
196
+ file_page.to_html(binding, :values => values) do
197
+ method_list_page.to_html(binding, values)
198
+ end
199
+ end
200
+
201
+ # FIXME XXX sanity check
202
+ dir = path.dirname
203
+ unless File.directory? dir
204
+ FileUtils.mkdir_p dir
205
+ end
206
+
207
+ File.open(outjoin(path.to_path), 'w') { |f| f << result }
208
+
209
+ end
210
+
211
+ def generate_class_files
212
+ class_page = haml_file(templjoin(CLASS_PAGE))
213
+ method_list_page = haml_file(templjoin(METHOD_LIST_PAGE))
214
+ sections_page = haml_file(templjoin(SECTIONS_PAGE))
215
+ # FIXME refactor
216
+
217
+ @classes.each do |klass|
218
+ outfile = classfile(klass)
219
+ sections = {}
220
+ klass.each_section do |section, constants, attributes|
221
+ method_types = []
222
+ alias_types = []
223
+ klass.methods_by_type(section).each do |type, visibilities|
224
+ visibilities.each do |visibility, methods|
225
+ aliases, methods = methods.partition{|x| x.is_alias_for}
226
+ method_types << ["#{visibility.to_s.capitalize} #{type.to_s.capitalize}", methods.sort] unless methods.empty?
227
+ alias_types << ["#{visibility.to_s.capitalize} #{type.to_s.capitalize}", aliases.sort] unless aliases.empty?
228
+ end
229
+ end
230
+ sections[section] = {:constants=>constants, :attributes=>attributes, :method_types=>method_types, :alias_types=>alias_types}
231
+ end
232
+
233
+ path = Pathname.new(klass.path)
234
+
235
+ values = default_values(path).merge({
236
+ :file => klass.path,
237
+ :entry => klass,
238
+ :classmod => klass.type,
239
+ :title => klass.full_name,
240
+ :list_title => nil,
241
+ :description => klass.description,
242
+ :sections => sections
243
+ })
244
+
245
+ result = with_layout(values) do
246
+ h = {:values => values}
247
+ class_page.to_html(binding, h) do
248
+ method_list_page.to_html(binding, h) + sections_page.to_html(binding, h)
249
+ end
250
+ end
251
+
252
+ # FIXME XXX sanity check
253
+ dir = outfile.dirname
254
+ unless File.directory? dir
255
+ FileUtils.mkdir_p dir
256
+ end
257
+
258
+ File.open(outfile, 'w') { |f| f << result }
259
+ end
260
+ end
261
+
262
+ def with_layout(values)
263
+ layout = haml_file(templjoin(LAYOUT))
264
+ layout.to_html(binding, :values => values) { yield }
265
+ end
266
+
267
+ def sanitize_code_blocks(text)
268
+ text.gsub(/<pre>(.+?)<\/pre>/m) do
269
+ code = $1.sub(/^\s*\n/, '')
270
+ indent = code.gsub(/\n[ \t]*\n/, "\n").scan(/^ */).map{ |i| i.size }.min
271
+ code.gsub!(/^#{' ' * indent}/, '') if indent > 0
272
+
273
+ "<pre>#{code}</pre>"
274
+ end
275
+ end
276
+
277
+ def class_dir
278
+ CLASS_DIR
279
+ end
280
+
281
+ def file_dir
282
+ FILE_DIR
283
+ end
284
+
285
+ def h(html)
286
+ CGI::escapeHTML(html)
287
+ end
288
+
289
+ # XXX may my sins be not visited upon my sons.
290
+ def render_class_tree(entries, from_path, parent=nil)
291
+ namespaces = { }
292
+
293
+ entries.sort.inject('') do |out, klass|
294
+ unless namespaces[klass.full_name]
295
+ if parent
296
+ text = '<span class="parent">%s::</span>%s' % [parent.full_name, klass.name]
297
+ else
298
+ text = klass.name
299
+ end
300
+
301
+ if klass.document_self
302
+ link = Pathname.new(classfile(klass)).relative_path_from(from_path.dirname)
303
+ out << "<li>#{ link_to(text, link) }</li>"
304
+ end
305
+
306
+ subentries = @classes.select { |x| x.full_name[/^#{klass.full_name}::/] }
307
+ subentries.each { |x| namespaces[x.full_name] = true }
308
+ out << render_class_tree(subentries, from_path, klass)
309
+
310
+ end
311
+
312
+ out
313
+ end
314
+ end
315
+
316
+ def build_javascript_search_index(entries)
317
+ 'var searchIndex = ' + (entries.map { |entry|
318
+ method_name = entry.name
319
+ module_name = entry.parent_name
320
+ link = [classfile(entry.parent), (entry.aref rescue "method-#{entry.html_name}")].join('#')
321
+ {
322
+ 'method' => method_name,
323
+ 'module' => module_name,
324
+ 'link' => link
325
+ }
326
+ }.to_json)
327
+ end
328
+
329
+ def link_to(text, url = nil, classname = nil, base = nil)
330
+ class_attr = classname ? ' class="%s"' % classname : ''
331
+
332
+ if url
333
+ %[<a href="#{base}#{url}"#{class_attr}>#{text}</a>]
334
+ elsif classname
335
+ %[<span#{class_attr}>#{text}</span>]
336
+ else
337
+ text
338
+ end
339
+ end
340
+
341
+ # +method_text+ is in the form of "ago (ActiveSupport::TimeWithZone)".
342
+ def link_to_method(entry, url = nil, classname = nil)
343
+ method_name = entry.pretty_name rescue entry.name
344
+ module_name = entry.parent_name rescue entry.name
345
+ link_to %Q(<li><strong>#{h method_name}</strong><small>#{h module_name}</small></li>), url, classname
346
+ end
347
+
348
+ def classfile(klass)
349
+ # FIXME sloooooooow
350
+ Pathname.new(File.join(CLASS_DIR, klass.full_name.split('::')) + '.html')
351
+ end
352
+
353
+ def outpath( path, from_path )
354
+ Pathname.new(path).relative_path_from(from_path.dirname)
355
+ end
356
+
357
+ def outjoin(name)
358
+ File.join(@outputdir, name)
359
+ end
360
+
361
+ def templjoin(name)
362
+ File.join(@templatedir, name)
363
+ end
364
+
365
+ def haml_file(file)
366
+ Haml::Engine.new(File.read(file))
367
+ end
368
+ end