hanna-bootstrap 0.0.1

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/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