proscribe 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/HISTORY.md ADDED
@@ -0,0 +1,4 @@
1
+ v0.0.1 - Jul 24, 2011
2
+ ---------------------
3
+
4
+ Initial.
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # ProScribe
2
+ #### Source documentation tool
3
+
4
+ $ gem install proscribe
5
+ $ proscribe
6
+
7
+ See the source for info on how to use it.
data/bin/proscribe ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path('../../lib/proscribe', __FILE__)
4
+
5
+ ProScribe::CLI.run!
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+
3
+ gem "proton", "~> 0.3.2"
4
+ gem "rack-cache", "~> 1.0.0"
5
+ gem "rdiscount"
@@ -0,0 +1,43 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ RedCloth (4.2.7)
5
+ chunky_png (1.2.0)
6
+ compass (0.11.5)
7
+ chunky_png (~> 1.2)
8
+ fssm (>= 0.2.7)
9
+ sass (~> 3.1)
10
+ cuba (2.0.0)
11
+ rack (~> 1.2)
12
+ tilt (~> 1.2)
13
+ fssm (0.2.7)
14
+ haml (3.1.2)
15
+ hashie (1.0.0)
16
+ maruku (0.6.0)
17
+ syntax (>= 1.0.0)
18
+ proton (0.3.3)
19
+ RedCloth (~> 4.2.3)
20
+ compass (~> 0.11.1)
21
+ cuba (~> 2.0.0)
22
+ haml (~> 3.1.1)
23
+ hashie (~> 1.0.0)
24
+ maruku (~> 0.6.0)
25
+ sass (~> 3.1.1)
26
+ shake (~> 0.1)
27
+ tilt (~> 1.2.2)
28
+ rack (1.3.0)
29
+ rack-cache (1.0.2)
30
+ rack (>= 0.4)
31
+ rdiscount (1.6.8)
32
+ sass (3.1.4)
33
+ shake (0.1.2)
34
+ syntax (1.0.0)
35
+ tilt (1.2.2)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ proton (~> 0.3.2)
42
+ rack-cache (~> 1.0.0)
43
+ rdiscount
@@ -0,0 +1,14 @@
1
+ hyde_requirement: 0.2
2
+ extensions_path: _extensions
3
+ layouts_path: _layouts
4
+ partials_path: _layouts
5
+
6
+ tilt_options:
7
+ haml:
8
+ ugly: true
9
+
10
+ # Custom stuff
11
+ extractor:
12
+ files:
13
+ - source: ../lib/**/*.rb
14
+ target: api/
@@ -0,0 +1,18 @@
1
+ class Proton::CLI
2
+ task :update do
3
+ require File.expand_path('../extractor', __FILE__)
4
+
5
+ Dir.chdir(Hyde.project.root) {
6
+ Proton.project.config.extractor.files.each { |group|
7
+ FileUtils.rm_rf group.target
8
+
9
+ ex = Extractor.new Dir[group.source]
10
+
11
+ ex.write!(group.target) { |b| puts " update * #{File.join(group.target, b.file)}" }
12
+ }
13
+ }
14
+ end
15
+
16
+ task.description = "Extracts inline documentation."
17
+ end
18
+
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ostruct'
4
+ require 'fileutils'
5
+
6
+ # Extracts comments from list of files.
7
+ # Gets the ones with comment blocks starting with `[...]`
8
+ #
9
+ # == Common usage
10
+ #
11
+ # ex = Extractor.new('.')
12
+ # ex.blocks
13
+ #
14
+ # ex.blocks.map! { |b| b.file = "file: #{b.file}" }
15
+ #
16
+ # ex.write!('manual/') # Writes to manual/
17
+ #
18
+ class Extractor
19
+ def initialize(files, options={})
20
+ @files = files
21
+ end
22
+
23
+ def write!(output_path = '.', &blk)
24
+ blocks.each { |block|
25
+ path = File.join(output_path, block.file)
26
+ FileUtils.mkdir_p File.dirname(path)
27
+ File.open(path, 'w') { |f| f.write block.body }
28
+ yield block if block_given?
29
+ }
30
+ end
31
+
32
+ # Returns an array of Extractor::Blocks.
33
+ def blocks
34
+ @blocks ||= begin
35
+ @files.map { |file|
36
+ if File.file?(file)
37
+ input = File.read(file)
38
+ get_blocks input
39
+ end
40
+ }.compact.flatten
41
+ end
42
+ end
43
+
44
+ private
45
+ # Returns blocks that match a blah.
46
+ def get_blocks(str)
47
+ arr = get_comment_blocks(str)
48
+ arr.map { |block|
49
+ re = /^([A-Za-z ]*?): (.*?)(?: \((.*?)\))?$/
50
+
51
+ if block.last =~ re
52
+ Extractor::Block.new \
53
+ :type => $1,
54
+ :title => $2,
55
+ :parent => $3,
56
+ :body => (block[0..-2].join("\n") + "\n")
57
+ elsif block.first =~ re
58
+ Extractor::Block.new \
59
+ :type => $1,
60
+ :title => $2,
61
+ :parent => $3,
62
+ :body => (block[1..-1].join("\n") + "\n")
63
+ end
64
+ }.compact
65
+ end
66
+
67
+ # Returns contiguous comment blocks.
68
+ def get_comment_blocks(str)
69
+ chunks = Array.new
70
+ i = 0
71
+
72
+ str.split("\n").each { |s|
73
+ if s =~ /^\s*(?:\/\/\/?|##?) ?(.*)$/
74
+ chunks[i] ||= Array.new
75
+ chunks[i] << $1
76
+ else
77
+ i += 1 if chunks[i]
78
+ end
79
+ }
80
+
81
+ chunks
82
+ end
83
+ end
84
+
85
+ class Extractor::Block
86
+ attr_accessor :body
87
+ attr_accessor :file
88
+
89
+ def initialize(options)
90
+ title = options[:title]
91
+ parent = options[:parent]
92
+ body = options[:body]
93
+ type = options[:type].downcase
94
+
95
+ file = to_filename(title, parent)
96
+ brief, *body = body.split("\n\n")
97
+ body = "#{body.join("\n\n")}"
98
+
99
+ heading = "title: #{title}\npage_type: #{type}\nbrief: #{brief}\n"
100
+ heading += "--\n"
101
+
102
+ @file = file
103
+ body = Tilt.new(".md") { body }.render
104
+ body = fix_links(body, from: file)
105
+ @body = heading + body
106
+ end
107
+
108
+ private
109
+ def fix_links(str, options={})
110
+ from = ("/" + options[:from].to_s).squeeze('/')
111
+ depth = from.to_s.count('/')
112
+ indent = (depth > 1 ? '../'*(depth-1) : './')[0..-2]
113
+
114
+ # First pass: {Helpers::content_for} to become links
115
+ str = str.gsub(/{([^}]*?)}/) { |s|
116
+ s = s.gsub(/{|}/, '')
117
+
118
+ m = s.match(/^(.*?)[:\.]+([A-Za-z_\(\)\!\?]+)$/)
119
+ if m
120
+ name, context = $2, $1
121
+ else
122
+ name, context = s, nil
123
+ end
124
+
125
+ s = "<a href='/#{to_filename(s, '', :ext => '.html')}'>#{name}</a>"
126
+ s += " <span class='context'>(#{context})</span>" if context
127
+ s
128
+ }
129
+
130
+ # Second pass: relativize
131
+ re = /href=['"](\/(?:.*?))['"]/
132
+ str.gsub(re) { |s|
133
+ url = s.match(re) && $1
134
+ url = "#{indent}/#{url}".squeeze('/')
135
+ "href=#{url.inspect}"
136
+ }
137
+ end
138
+
139
+ def to_filename(title, parent='', options={})
140
+ extension = options[:ext] || '.erb'
141
+ pathify = lambda { |s|
142
+ s.to_s.scan(/[A-Za-z0-9_\!\?]+/).map { |chunk|
143
+ chunk = chunk.gsub('?', '_question')
144
+ chunk = chunk.gsub('!', '_bang')
145
+
146
+ if chunk[0].upcase == chunk[0]
147
+ chunk
148
+ else
149
+ "#{chunk}_"
150
+ end
151
+ }.join("/")
152
+ }
153
+
154
+ pathify["#{parent}/#{title}"] + extension
155
+ end
156
+ end
157
+
158
+ module Extractor::Command
159
+ module Params
160
+ def extract(what)
161
+ i = index(what) and slice!(i, 2)[1]
162
+ end
163
+
164
+ def extract_all(what)
165
+ re = Array.new
166
+ while true
167
+ x = extract(what) or return re
168
+ re << x
169
+ end
170
+ end
171
+ end
172
+
173
+ def self.show_usage
174
+ puts "Usage: #{$0} <path> [-o <output_path>] [-i <ignore_spec>]"
175
+ puts " Extracts documentation comments from files in <path>, and places"
176
+ puts " them in <output_path>."
177
+ puts ""
178
+ puts "Example:"
179
+ puts " #{$0} **/*.rb -o manual/"
180
+ puts ""
181
+ end
182
+
183
+ def self.run!
184
+ return show_usage if ARGV.empty?
185
+
186
+ ARGV.extend Params
187
+
188
+ glob = lambda { |s| Dir["#{s}/**/*"] + Dir[s] }
189
+
190
+ output = ARGV.extract('--output') || ARGV.extract('-o') || '.'
191
+ ignore = ARGV.extract_all('-i') + ARGV.extract_all('--ignore')
192
+
193
+ files = ARGV.map { |s| glob[s] }.flatten
194
+ files = Dir["**/*"] if ARGV.empty?
195
+
196
+ files -= ignore.map { |s| glob[s] }.flatten
197
+
198
+ ex = Extractor.new(files)
199
+ ex.blocks.map { |b| b.file }
200
+ ex.write!(output) { |blk|
201
+ puts "* #{blk.file}"
202
+ }
203
+ end
204
+ end
205
+
206
+ Extractor::Command.run! if $0 == __FILE__
@@ -0,0 +1,32 @@
1
+ module Hyde::Helpers
2
+ def page_children(page)
3
+ children = page.children
4
+ of_type = lambda { |str| children.select { |p| p.html? && p.meta.page_type == str } }
5
+
6
+ children.
7
+ select { |p| p.html? }.
8
+ group_by { |p|
9
+ type = p.meta.page_type
10
+ type.nil? ? nil : Inflector[type].pluralize.to_sym
11
+ }
12
+ end
13
+ end
14
+
15
+ # Inflector['hello'].pluralize
16
+ class Inflector < String
17
+ def self.[](str)
18
+ new str.to_s
19
+ end
20
+
21
+ def pluralize
22
+ if self[-1] == 's'
23
+ "#{self}es"
24
+ else
25
+ "#{self}s"
26
+ end
27
+ end
28
+
29
+ def sentencize
30
+ self.gsub('_', ' ').capitalize
31
+ end
32
+ end
@@ -0,0 +1,2 @@
1
+ require File.expand_path('../lib/cli', __FILE__)
2
+ require File.expand_path('../lib/helpers', __FILE__)
@@ -0,0 +1,8 @@
1
+ - is_active = from == p
2
+ - if p.html?
3
+ %li
4
+ %a{href: rel(p.path), class: ("active" if is_active)}= p
5
+ %ul{class: "level-#{level}"}
6
+ - p.children.each do |pp|
7
+ != partial :'_nav', from: from, p: pp, level: level+1
8
+
@@ -0,0 +1,123 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title= page.title
5
+
6
+ %meta(charset='UTF-8')
7
+ -# Use the latest IE engine, or Chrome frame.
8
+ %meta(http-equiv='X-UA-Compatible' content='IE=edge,chrome=1')
9
+
10
+ -# Mobile viewport optimization. j.mp/bplateviewport
11
+ %meta(name='viewport' content='width=device-width, initial-scale=1.0')
12
+
13
+ -# Standard SEO meta
14
+ - if page.meta.keywords
15
+ %meta{:name => 'keywords', :content => page.meta.keywords}
16
+ - if page.meta.description
17
+ %meta{:name => 'description', :content => page.meta.description}
18
+
19
+ %link{:rel => 'stylesheet', :href => rel('/style.css')+"?#{File.mtime(Proton::Page['/style.css'].file).to_i}"}
20
+
21
+ %body
22
+ #top
23
+ %a#logo{href: rel('/')}
24
+ = Hyde::Page['/'].title
25
+
26
+ #area
27
+ #content
28
+ %div.c
29
+ #crumbs
30
+ - page.breadcrumbs[0..-2].each do |p|
31
+ %a{href: rel(p.path)}= p
32
+ %span.gt!= "&rarr;"
33
+
34
+ %strong= page
35
+
36
+ %hgroup
37
+ - if page.meta.layout
38
+ %p.type= page.meta.layout.capitalize
39
+ %h1= page.title
40
+ - if page.meta.brief
41
+ %h5= page.meta.brief
42
+
43
+ .content
44
+ != yield
45
+
46
+ - groups = page_children(page)
47
+ - groups.each do |type, children|
48
+ %h3= type.to_s.gsub('_', ' ').capitalize
49
+
50
+ %ul.section
51
+ - children.each do |method|
52
+ %li
53
+ %a{href: rel(method.path)}= method.title
54
+ - unless method.meta.brief.to_s.empty?
55
+ %span.brief= method.meta.brief
56
+
57
+ %nav#nav
58
+ - parent = (page.children.any? ? page : (page.parent || page))
59
+ - children = parent.children.select { |p| p.html? }
60
+ - groups = children.group_by { |p| p.meta.page_type }
61
+
62
+ - if parent && !parent.root?
63
+ %nav.parents
64
+ %ul
65
+ - parent.breadcrumbs.each do |pp|
66
+ %li
67
+ %a{href: rel(pp.path), class: ('active' if pp.path == page.path)}
68
+ - unless pp.path == page.path
69
+ %span.back!= "&lsaquo;"
70
+
71
+ %em= pp.meta.page_type
72
+ = pp
73
+
74
+ - if groups.any?
75
+ - groups.each do |name, pages|
76
+ - name = name ? Inflector[name].pluralize.capitalize : parent.to_s
77
+ %nav
78
+ - if name
79
+ %h4= name
80
+ %ul
81
+ - pages.each do |pp|
82
+ %li
83
+ - classes = []
84
+ - classes << 'active' if pp.path == page.path
85
+ - classes << 'more' if pp.children.any?
86
+
87
+ %a{href: rel(pp.path), class: classes.join(' ')}
88
+ = pp
89
+
90
+
91
+ %script{src: 'http://cachedcommons.org/cache/prettify/1.0.0/javascripts/prettify-min.js', type: 'text/javascript'}
92
+ %script{src: 'http://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.2/jquery.min.js', type: 'text/javascript'}
93
+ :javascript
94
+ $(function () {
95
+ $("pre").each(function() {
96
+ var r = /\[(.*?)\s*\((.*?)\)\]\n*/;
97
+ var m = $(this).text().match(r);
98
+
99
+ $(this).addClass('prettyprint');
100
+
101
+ if (m) {
102
+ var file = m[1];
103
+ var type = m[2];
104
+ $(this).addClass('lang-'+type);
105
+
106
+ if (file.length) {
107
+ $(this).addClass('has-caption');
108
+ $(this).prepend($("<h5 class='caption'>").text(file));
109
+ }
110
+
111
+ $(this).html($(this).html().replace(r, ''));
112
+ }
113
+
114
+ if ($(this).text().match(/^\s*([a-zA-Z_~\/]*)\$ /)) {
115
+ $(this).addClass('terminal');
116
+ $(this).removeClass('prettyprint');
117
+ $(this).html($(this).html().replace(/([a-zA-Z_~\/]*\$ )(.*?)[\r\n$]/g, "<strong><em>$1</em>$2</strong>\n"));
118
+ }
119
+ });
120
+
121
+ prettyPrint();
122
+ });
123
+