hanna 0.1.12

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,102 @@
1
+ # Hanna — a better RDoc template
2
+
3
+ Hanna is an RDoc template that scales. It's implemented in Haml, making the sources clean
4
+ and readable. It's built with simplicity, beauty and ease of browsing in mind. (See more
5
+ in [the wiki][wiki].)
6
+
7
+ Hanna gem is available from [Gemcutter][]:
8
+
9
+ gem install hanna
10
+
11
+ The template was created by [Mislav][] and since then has seen contributions from:
12
+
13
+ 1. [Tony Strauss](http://github.com/DesigningPatterns), who participated from the early
14
+ start and made tons of fixes and enhancements to the template;
15
+ 2. [Hongli Lai](http://blog.phusion.nl/) with the search filter for methods.
16
+
17
+
18
+ ## Usage
19
+
20
+ There is a command-line tool installed with the Hanna gem:
21
+
22
+ hanna -h
23
+
24
+ This is a wrapper over `rdoc` and it forwards all the parameters to it. Manual usage
25
+ would require specifying Hanna as a template when invoking RDoc on the command-line:
26
+
27
+ rdoc -o doc --inline-source --format=html -T hanna lib/*.rb
28
+
29
+ Hanna requires the `--inline-source` (or `-S`) flag.
30
+
31
+ An alternative is to set the `RDOCOPT` environment variable:
32
+
33
+ RDOCOPT="-S -f html -T hanna"
34
+
35
+ This will make RDoc always use Hanna unless it is explicitly overridden.
36
+
37
+ Another neat trick is to put the following line in your .gemrc:
38
+
39
+ rdoc: --inline-source --line-numbers --format=html --template=hanna
40
+
41
+ This will make RubyGems use Hanna when generating documentation for installed gems.
42
+
43
+ ### Rake task
44
+
45
+ For repeated generation of API docs, it's better to set up a Rake task. If you already
46
+ have an `RDocTask` set up in your Rakefile, the only thing you need to change is this:
47
+
48
+ # replace this:
49
+ require 'rake/rdoctask'
50
+ # with this:
51
+ require 'hanna/rdoctask'
52
+
53
+ Tip: you can do this in the Rakefile of your Rails project before running `rake doc:rails`.
54
+
55
+ Here is an example of a task for the [will_paginate library][wp]:
56
+
57
+ # instead of 'rake/rdoctask':
58
+ require 'hanna/rdoctask'
59
+
60
+ desc 'Generate RDoc documentation for the will_paginate plugin.'
61
+ Rake::RDocTask.new(:rdoc) do |rdoc|
62
+ rdoc.rdoc_files.include('README.rdoc', 'LICENSE', 'CHANGELOG').
63
+ include('lib/**/*.rb').
64
+ exclude('lib/will_paginate/named_scope*').
65
+ exclude('lib/will_paginate/array.rb').
66
+ exclude('lib/will_paginate/version.rb')
67
+
68
+ rdoc.main = "README.rdoc" # page to start on
69
+ rdoc.title = "will_paginate documentation"
70
+
71
+ rdoc.rdoc_dir = 'doc' # rdoc output folder
72
+ rdoc.options << '--webcvs=http://github.com/mislav/will_paginate/tree/master/'
73
+ end
74
+
75
+ ### Generating documentation for installed gems
76
+
77
+ You can generate documentation for installed gems, which might be more convenient than the
78
+ `gem rdoc` command with the +RDOCOPT+ environment variable set as described. For instance,
79
+ to generate docs for "actionpack" and "activerecord" type:
80
+
81
+ [sudo] hanna --gems actionpack activerecord
82
+
83
+
84
+ ## You can help
85
+
86
+ Don't like something? Think you can design better? (You probably can.)
87
+
88
+ I think of Hanna as the first RDoc template that's actually _maintainable_. First thing I
89
+ have done is converted the original HTML template to Haml and Sass, cleaning up and
90
+ removing the (ridiculous amount of) duplication. Also, the template fragments are now in
91
+ _separate files_.
92
+
93
+ Ultimately, I'd like to lose the frameset. Currently that is far from possible because the
94
+ whole RDoc HTML Generator is built for frames. Still, that is my goal.
95
+
96
+ This is git. Fork it, hack away, tell me about it!
97
+
98
+
99
+ [wiki]: http://github.com/mislav/hanna/wikis/home "Hanna wiki"
100
+ [gemcutter]: http://gemcutter.org/ "Gemcutter gem server"
101
+ [wp]: http://github.com/mislav/will_paginate/tree/master/Rakefile
102
+ [Mislav]: http://mislav.caboo.se/ "Mislav Marohnić"
@@ -0,0 +1,4 @@
1
+ desc "builds the gem"
2
+ task :gem do
3
+ system %(gem build hanna.gemspec)
4
+ end
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/ruby
2
+ if ARGV.size == 1 and ARGV.first == '-h'
3
+ puts <<-HELP
4
+ Hanna -- a better RDoc template
5
+ Synopsis:
6
+ hanna [options] [file names...]
7
+ [sudo] hanna --gems [gem names...]
8
+
9
+ Example usage:
10
+
11
+ hanna lib/**/*.rb
12
+
13
+ Hanna passes all arguments to RDoc. To find more about RDoc options, see
14
+ "rdoc -h". Default options are:
15
+
16
+ -o doc --inline-source --charset=UTF-8
17
+
18
+ The second form, with the "--gems" argument, serves the same purpose as
19
+ the "gem rdoc" command: it generates documentation for installed gems.
20
+ When no gem names are given, "hanna --gems" will install docs for EACH of
21
+ the gems, which can, uh, take a little while.
22
+
23
+ HELP
24
+ exit 0
25
+ end
26
+
27
+ unless RUBY_PLATFORM =~ /(:?mswin|mingw)/
28
+ require 'pathname'
29
+ hanna_dir = Pathname.new(__FILE__).realpath.dirname + '../lib'
30
+ else
31
+ # windows
32
+ hanna_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
33
+ end
34
+
35
+ $:.unshift(hanna_dir) unless $:.include?(hanna_dir)
36
+
37
+ require 'rubygems'
38
+ require 'hanna/version'
39
+ Hanna::require_rdoc
40
+ require 'rdoc/rdoc'
41
+
42
+ options = []
43
+
44
+ options << '-f' << 'html' << '-T' << 'hanna'
45
+ options << '--inline-source' << '--charset=UTF-8'
46
+
47
+ if ARGV.first == '--gems'
48
+ require 'rubygems/doc_manager'
49
+ Gem::DocManager.configured_args = options
50
+
51
+ gem_names = ARGV.dup
52
+ gem_names.shift
53
+
54
+ unless gem_names.empty?
55
+ specs = gem_names.inject([]) do |arr, name|
56
+ found = Gem::SourceIndex.from_installed_gems.find_name(name)
57
+ spec = found.sort_by {|s| s.version }.last
58
+ arr << spec if spec
59
+ arr
60
+ end
61
+ else
62
+ specs = Gem::SourceIndex.from_installed_gems.inject({}) do |all, pair|
63
+ full_name, spec = pair
64
+ if spec.has_rdoc? and (!all[spec.name] or spec.version > all[spec.name].version)
65
+ all[spec.name] = spec
66
+ end
67
+ all
68
+ end
69
+ specs = specs.values
70
+ puts "Hanna is installing documentation for #{specs.size} gem#{specs.size > 1 ? 's' : ''} ..."
71
+ end
72
+
73
+ specs.each do |spec|
74
+ Gem::DocManager.new(spec).generate_rdoc
75
+ end
76
+ else
77
+ options << '-o' << 'doc' unless ARGV.include?('-o') or ARGV.include?('--op')
78
+ options.concat ARGV
79
+
80
+ RDoc::RDoc.new.document(options)
81
+ end
@@ -0,0 +1 @@
1
+ require 'hanna/hanna'
@@ -0,0 +1,48 @@
1
+ # = A better RDoc HTML template
2
+ #
3
+ # Authors: Mislav Marohnić <mislav.marohnic@gmail.com>
4
+ # Tony Strauss (http://github.com/DesigningPatterns)
5
+ # Michael Granger <ged@FaerieMUD.org>, who had maintained the original RDoc template
6
+
7
+ require 'haml'
8
+ require 'sass'
9
+ require 'rdoc/generator/html'
10
+ require 'hanna/template_page_patch'
11
+
12
+ module RDoc::Generator::HTML::HANNA
13
+ class << self
14
+ def dir
15
+ @dir ||= File.join File.dirname(__FILE__), 'template_files'
16
+ end
17
+
18
+ def read(*names)
19
+ content = names.inject('') { |all, name| all << File.read(File.join(dir, name)) }
20
+ extension = names.first =~ /\.(\w+)$/ && $1
21
+
22
+ Hanna::TemplateHelpers.silence_warnings do
23
+ case extension
24
+ when 'sass'
25
+ Sass::Engine.new(content)
26
+ when 'haml'
27
+ Haml::Engine.new(content, :format => :html4, :filename => names.join(','))
28
+ else
29
+ content
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ STYLE = read('styles.sass')
36
+
37
+ CLASS_PAGE = read('page.haml')
38
+ FILE_PAGE = CLASS_PAGE
39
+ METHOD_LIST = read('method_list.haml', 'sections.haml')
40
+
41
+ FR_INDEX_BODY = BODY = read('layout.haml')
42
+
43
+ FILE_INDEX = read('file_index.haml')
44
+ CLASS_INDEX = read('class_index.haml')
45
+ METHOD_INDEX = read('method_index.haml')
46
+
47
+ INDEX = read('index.haml')
48
+ end
@@ -0,0 +1,42 @@
1
+ require 'hanna/version'
2
+ require 'rake'
3
+ require 'rake/rdoctask'
4
+
5
+ Rake::RDocTask.class_eval do
6
+ # don't allow it
7
+ undef :external=, :template=
8
+
9
+ # Create the tasks defined by this task lib.
10
+ def define
11
+ @template = 'hanna'
12
+ options << '--format=html'
13
+
14
+ # inline source and UTF-8 are defaults:
15
+ options << '--inline-source' unless options.include? '--inline-source' or options.include? '-S'
16
+ options << '--charset=UTF-8' if options.grep(/^(--charset\b|-c\b)/).empty?
17
+
18
+ desc "Build the HTML documentation"
19
+ task name
20
+
21
+ desc "Force a rebuild of the RDOC files"
22
+ task paste("re", name) => [paste("clobber_", name), name]
23
+
24
+ desc "Remove rdoc products"
25
+ task paste("clobber_", name) do
26
+ rm_r rdoc_dir rescue nil
27
+ end
28
+
29
+ task :clobber => [paste("clobber_", name)]
30
+
31
+ directory @rdoc_dir
32
+ task name => [rdoc_target]
33
+ file rdoc_target => @rdoc_files + [Rake.application.rakefile] do
34
+ rm_r @rdoc_dir rescue nil
35
+ Hanna::require_rdoc
36
+ require 'rdoc/rdoc'
37
+
38
+ RDoc::RDoc.new.document(option_list + @rdoc_files)
39
+ end
40
+ return self
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ %h1= values[:list_title]
2
+ %ol#index-entries.classes
3
+ = render_class_tree make_class_tree(values[:entries])
@@ -0,0 +1,12 @@
1
+ %h1= values[:list_title]
2
+ - any_hidden = false
3
+
4
+ %ol#index-entries{ :class => 'files' }
5
+ - for entry in values[:entries]
6
+ - hide = entry[:name] =~ /\.rb$/
7
+ - any_hidden = true if hide
8
+ %li{ :class => hide ? 'other' : nil }= link_to entry[:name], entry[:href]
9
+
10
+ - if any_hidden
11
+ %li
12
+ %a.show{ :href => '#', :onclick => 'this.parentNode.parentNode.className += " expanded"; this.parentNode.removeChild(this); return false' } show all
@@ -0,0 +1,11 @@
1
+ !!! Frameset
2
+ %html{ "xml:lang" => "en", :lang => "en", :xmlns => "http://www.w3.org/1999/xhtml" }
3
+ %head
4
+ %title= values[:title]
5
+ %meta{ :content => "text/html; charset=#{values[:charset]}", "http-equiv" => "Content-Type" }
6
+ %frameset{ :cols => "20%, *", :border => "1", :frameborder => "1", :bordercolor => "gray" }
7
+ %frameset{ :rows => "15%, 35%, 50%" }
8
+ %frame{ :name => "Files", :title => "Files", :src => "fr_file_index.html" }
9
+ %frame{ :name => "Classes", :src => "fr_class_index.html" }
10
+ %frame{ :name => "Methods", :src => "fr_method_index.html" }
11
+ %frame{ :name => "docwin", :src => values[:initial_page] }=""
@@ -0,0 +1,34 @@
1
+ !!! strict
2
+ - index = values[:list_title]
3
+ %html{ :lang => "en" }
4
+ %head
5
+ %title= values[:title]
6
+ %meta{ 'http-equiv' => "Content-Type", :content => "text/html; charset=#{values[:charset]}" }
7
+ %link{ :rel => "stylesheet", :href => values[:style_url], :type => "text/css", :media => "screen" }
8
+ - unless index
9
+ :javascript
10
+ function popupCode(url) {
11
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
12
+ }
13
+
14
+ function toggleCode(id) {
15
+ var code = document.getElementById(id)
16
+
17
+ code.style.display = code.style.display != 'block' ? 'block' : 'none'
18
+ return true
19
+ }
20
+
21
+ // Make codeblocks hidden by default
22
+ document.writeln('<' + 'style type="text/css">.method .source pre { display: none }<\/style>')
23
+ - else
24
+ %base{ :target => 'docwin' }/
25
+
26
+ %body{ :class => index ? 'list' : 'page' }
27
+ - if index
28
+ #index= yield
29
+ - else
30
+ #wrapper{ :class => values[:classmod] ? 'class' : 'file' }
31
+ = yield
32
+ #footer-push
33
+ #footer
34
+ = link_to '<strong>Hanna</strong> RDoc template', 'http://github.com/mislav/hanna/tree/master'
@@ -0,0 +1,13 @@
1
+ %h1= values[:list_title]
2
+
3
+ %script{:type => 'text/javascript'}
4
+ = read("prototype-1.6.0.3.js")
5
+ = build_javascript_search_index(values[:entries])
6
+ = read("method_search.js")
7
+ %form{:onsubmit => 'return performSearch()'}
8
+ %input{:type => 'text', :id => 'search', :class => 'untouched', :value => 'Enter search terms...'}
9
+ %ol#search-results{ :class => 'methods', :style => 'display: none' }
10
+
11
+ %ol#index-entries{ :class => 'methods' }
12
+ - for entry in values[:entries]
13
+ %li= link_to_method entry[:name], entry[:href]
@@ -0,0 +1,37 @@
1
+ - methods = methods_from_sections values[:sections]
2
+ - unless methods.empty?
3
+ #method-list
4
+ %h2 Methods
5
+ - for type in ['public class', 'protected class', 'public instance', 'protected instance']
6
+ - unless (list = methods[type]).empty?
7
+ %h3= type
8
+ %ol
9
+ - for method in list
10
+ - if method[:name].to_s.empty? && method[:callseq]
11
+ %li= link_to method[:callseq].gsub(/<br\s*\/?>/, "").split(/[\r\n]+/).map{ |s| s.split(/([({]+|\[\{|\s+(#?=>|&rarr;)\s+)/).first.sub(/^[A-Za-z0-9_:]+\./, "").sub(/\s+=\s+.*/, "=").strip }.uniq.join("<br />\n"), '#' + method[:aref]
12
+ - else
13
+ %li= link_to method[:name], '#' + method[:aref]
14
+
15
+ - if values[:requires] or values[:toc] or values[:includes]
16
+ #context
17
+ - if values[:requires]
18
+ #requires
19
+ %h2 Required files
20
+ %ol
21
+ - for req in values[:requires]
22
+ %li= link_to req[:name], req[:aref]
23
+
24
+ - if values[:toc]
25
+ #contents
26
+ %h2 Contents
27
+ %ol
28
+ - for item in values[:toc]
29
+ %li= link_to values[:secname], values[:href]
30
+
31
+ - if values[:includes]
32
+ #includes
33
+ %h2 Included modules
34
+ %ol
35
+ - for inc in values[:includes]
36
+ %li= link_to inc[:name], inc[:aref]
37
+
@@ -0,0 +1,63 @@
1
+ $(document).observe('dom:loaded', function() {
2
+ // Setup search-during-typing.
3
+ new Form.Element.Observer('search', 0.3, function(element, value) {
4
+ performSearch();
5
+ });
6
+
7
+ // Remove the default search box value when the user puts the focus on
8
+ // the search box for the first time.
9
+ var search_box = $('search');
10
+ if ($F('search') == 'Enter search terms...') {
11
+ search_box.observe('focus', function() {
12
+ if (search_box.hasClassName('untouched')) {
13
+ search_box.removeClassName('untouched');
14
+ search_box.value = '';
15
+ }
16
+ });
17
+ } else {
18
+ search_box.removeClassName('untouched');
19
+ }
20
+
21
+ search_box.insert({
22
+ after: new Element('span', { 'class': 'clear_button' }).update('x').observe('click', function(e) {
23
+ e.stopPropagation()
24
+ search_box.setValue('')
25
+ search_box.focus()
26
+ })
27
+ })
28
+ });
29
+
30
+ function searchInIndex(query) {
31
+ var i;
32
+ var results = [];
33
+ query = query.toLowerCase();
34
+ for (i = 0; i < search_index.length; i++) {
35
+ if (search_index[i].method.indexOf(query) != -1) {
36
+ results.push(search_index[i]);
37
+ }
38
+ }
39
+ return results;
40
+ }
41
+
42
+ function buildHtmlForResults(results) {
43
+ var html = "";
44
+ var i;
45
+ for (i = 0; i < results.length; i++) {
46
+ html += '<li>' + results[i].html + '</li>';
47
+ }
48
+ return html;
49
+ }
50
+
51
+ function performSearch() {
52
+ var query = $F('search');
53
+ if (query == '') {
54
+ $('index-entries').show();
55
+ $('search-results').hide();
56
+ } else {
57
+ var results = searchInIndex(query);
58
+ $('search-results').update(buildHtmlForResults(results));
59
+ $('index-entries').hide();
60
+ $('search-results').show();
61
+ }
62
+ return false;
63
+ }