proscribe 0.0.1 → 0.0.3

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 CHANGED
@@ -1,3 +1,16 @@
1
+ v0.0.2 - Jul 29, 2011
2
+ ---------------------
3
+
4
+ ### Added:
5
+ * Github link
6
+ * Literate programming style stuff
7
+
8
+ ### Removed:
9
+ * ghpages support
10
+
11
+ ### Misc:
12
+ * Cleaned up extension
13
+
1
14
  v0.0.1 - Jul 24, 2011
2
15
  ---------------------
3
16
 
@@ -7,8 +7,3 @@ tilt_options:
7
7
  haml:
8
8
  ugly: true
9
9
 
10
- # Custom stuff
11
- extractor:
12
- files:
13
- - source: ../lib/**/*.rb
14
- target: api/
@@ -1,4 +1,4 @@
1
- module Hyde::Helpers
1
+ module Proton::Helpers
2
2
  def page_children(page)
3
3
  children = page.children
4
4
  of_type = lambda { |str| children.select { |p| p.html? && p.meta.page_type == str } }
@@ -10,6 +10,15 @@ module Hyde::Helpers
10
10
  type.nil? ? nil : Inflector[type].pluralize.to_sym
11
11
  }
12
12
  end
13
+
14
+ # A link to the source file on GitHub
15
+ def github_source_link
16
+ if project.config.github && project.config.git
17
+ if page.meta.source_file
18
+ "https://github.com/#{project.config.github}/blob/#{project.config.git[0..6]}/#{page.source_file}#L#{page.source_line}".squeeze('/')
19
+ end
20
+ end
21
+ end
13
22
  end
14
23
 
15
24
  # Inflector['hello'].pluralize
@@ -18,6 +18,9 @@
18
18
 
19
19
  %link{:rel => 'stylesheet', :href => rel('/style.css')+"?#{File.mtime(Proton::Page['/style.css'].file).to_i}"}
20
20
 
21
+ %script{src: 'http://cachedcommons.org/cache/prettify/1.0.0/javascripts/prettify-min.js', type: 'text/javascript'}
22
+ %script{src: 'http://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.2/jquery.min.js', type: 'text/javascript'}
23
+ %script{src: rel('/proscribe.js')+"?#{File.mtime(Proton::Page['/proscribe.js'].file).to_i}", type: 'text/javascript'}
21
24
  %body
22
25
  #top
23
26
  %a#logo{href: rel('/')}
@@ -54,6 +57,28 @@
54
57
  - unless method.meta.brief.to_s.empty?
55
58
  %span.brief= method.meta.brief
56
59
 
60
+ -# Source
61
+ %section.footer
62
+ .left
63
+ %strong
64
+ - page.breadcrumbs[1...-1].each do |pp|
65
+ %a{href: rel(page.path)}
66
+ = pp.title
67
+ -# if pp.meta.page_type
68
+ -# %span.type= pp.meta.page_type
69
+
70
+ %span.arrow!= "›"
71
+
72
+ = page.title
73
+ - if page.meta.page_type
74
+ %span.type= page.meta.page_type
75
+
76
+ - if github_source_link
77
+ Defined in
78
+ %a{href: github_source_link}
79
+ %span= page.source_file
80
+ %span.view-source!= "View source ›"
81
+
57
82
  %nav#nav
58
83
  - parent = (page.children.any? ? page : (page.parent || page))
59
84
  - children = parent.children.select { |p| p.html? }
@@ -87,37 +112,3 @@
87
112
  %a{href: rel(pp.path), class: classes.join(' ')}
88
113
  = pp
89
114
 
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
-
@@ -0,0 +1,52 @@
1
+ $(function () {
2
+ $("h4").each(function() {
3
+ var $this = $(this);
4
+
5
+ // Find the next p
6
+ var $p = $this.find('+ p');
7
+ if (!$p.length) { $p = $this; }
8
+
9
+ var $pre = $p.find('+ pre');
10
+ if (!$pre.length) { return; }
11
+
12
+ // Build it
13
+ var $el = $("<section class='literate'>");
14
+ $this.before($el);
15
+
16
+ // Move them
17
+ $el.append($pre);
18
+ $el.append($this);
19
+ $el.append($p);
20
+ });
21
+
22
+ $("pre").each(function() {
23
+ var $this = $(this);
24
+ $this.addClass('prettyprint');
25
+
26
+ // Filename
27
+ var r = /\[(.*?)\s*\((.*?)\)\]\n*/;
28
+ var m = $this.text().match(r);
29
+ if (m) {
30
+ var file = m[1];
31
+ var type = m[2];
32
+ $this.addClass('lang-'+type);
33
+
34
+ if (file.length) {
35
+ $this.addClass('has-caption');
36
+ $this.prepend($("<h5 class='caption'>").text(file));
37
+ }
38
+
39
+ $this.html($this.html().replace(r, ''));
40
+ }
41
+
42
+ // Terminal
43
+ if ($this.text().match(/^\s*([a-zA-Z_~\/]*)\$ /)) {
44
+ $this.addClass('terminal');
45
+ $this.removeClass('prettyprint');
46
+ $this.html($this.html().replace(/([a-zA-Z_~\/]*\$ )(.*?)[\r\n$]/g, "<strong><em>$1</em>$2</strong>\n"));
47
+ }
48
+ });
49
+
50
+ prettyPrint();
51
+ });
52
+
@@ -135,6 +135,7 @@ $pad: 40px;
135
135
  #content {
136
136
  @include border-top-radius(2px);
137
137
  background: white; padding: 40px;
138
+ padding-bottom: 140px;
138
139
  position: relative;
139
140
  @include box-sizing(border-box);
140
141
  @include clearfix;
@@ -195,7 +196,7 @@ $pad: 40px;
195
196
  }
196
197
 
197
198
  >h2, >h3 {
198
- & + pre {
199
+ & + pre, & + section {
199
200
  margin-top: 20px !important; }
200
201
 
201
202
  font-size: 2em;
@@ -360,11 +361,14 @@ pre.has-caption {
360
361
  }
361
362
 
362
363
  pre.terminal {
363
- background: #222;
364
+ background: #444;
365
+ @include box-shadow(inset 2px 2px 8px rgba(black, 0.4));
364
366
 
365
- code {
367
+ &, code {
366
368
  color: #ccc;
367
- text-shadow: 1px 1px 0 rgba(black, 0.3);
369
+ text-shadow: 1px 1px 0 rgba(black, 0.3); }
370
+
371
+ code {
368
372
  background: transparent; }
369
373
 
370
374
  strong {
@@ -376,6 +380,118 @@ pre.terminal {
376
380
  color: #8d8 * 0.5; }
377
381
  }
378
382
 
383
+ section.literate {
384
+ overflow: hidden;
385
+ padding: 20px 40px;
386
+ border-top: solid 1px #eee;
387
+ margin: 0 -40px;
388
+
389
+ font-size: 9pt;
390
+
391
+ pre + * { margin-top: 0; }
392
+ &:first-of-type { margin-top: 30px; }
393
+ &:last-of-type { margin-bottom: 30px; }
394
+
395
+ p { width: 33%; }
396
+ pre { float: right; width: 60%; }
397
+ pre + pre { margin-top: 20px; }
398
+ pre::after { clear: both; }
399
+
400
+ h4 { font-size: 1.2em; margin-bottom: 10px; color: #456 * 1.7; }
401
+ h4 + * { margin-top: 0; }
402
+ }
403
+
404
+ a.github-link, a[title="Source code"] {
405
+ position: absolute;
406
+ top: 0;
407
+ right: 0;
408
+ display: block;
409
+ background: url('https://d3nwyuy0nl342s.cloudfront.net/img/e6bef7a091f5f3138b8cd40bc3e114258dd68ddf/687474703a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f7265645f6161303030302e706e67') top right no-repeat;
410
+ text-indent: -9999px;
411
+ width: 149px; height: 149px;
412
+ z-index: 1;
413
+ }
414
+
415
+ section.aux-links {
416
+ position: absolute;
417
+ top: 40px;
418
+ right: 0px;
419
+
420
+ ul, li { list-style-type: none; margin: 0; padding: 0; }
421
+
422
+ a {
423
+ overflow: hidden;
424
+ display: block;
425
+ margin-bottom: 5px;
426
+ font-size: 8pt;
427
+ padding: 5px 10px;
428
+ width: 140px;
429
+ font-size: 8pt;
430
+ line-height: 12pt;
431
+ font-weight: bold;
432
+ @include border-left-radius(4px);
433
+ background: #eee; }
434
+
435
+ a::after {
436
+ content: '›'; color: #aaa;
437
+ font-size: 1.5em;
438
+ float: right; }
439
+
440
+ a:hover {
441
+ background: #888; color: #ddd;
442
+ text-shadow: 1px 1px 0 rgba(black, 0.1); }
443
+ }
444
+
445
+ section.footer {
446
+ background: #eee;
447
+ border-top: solid 1px #eee;
448
+
449
+ position: absolute;
450
+ @include box-sizing(border-box);
451
+ bottom: 0; left: 0; width: 100%;
452
+ padding: 20px;
453
+
454
+
455
+ font-size: 0.75em;
456
+
457
+ color: #aaa;
458
+ text-shadow: 1px 1px 0 rgba(white, 0.5);
459
+
460
+ @include box-shadow(inset 0 3px 3px rgba(black, 0.1));
461
+ text-align: left;
462
+
463
+ a, strong {
464
+ color: #888; }
465
+
466
+ strong {
467
+ font-size: 1.1em; }
468
+
469
+ span.type {
470
+ opacity: 0.7;
471
+ font-weight: normal; font-size: 0.9em;
472
+ &::before { content: '['; }
473
+ &::after { content: ']'; } }
474
+
475
+ span.arrow {
476
+ margin: 0 5px; }
477
+
478
+ .left {
479
+ strong { display: block; } }
480
+
481
+ .line {
482
+ font-style: normal; }
483
+
484
+ .view-source {
485
+ background: rgba(black, 0.1);
486
+ color: #888;
487
+ padding: 1px 8px;
488
+ font-size: 0.9em;
489
+ font-weight: normal;
490
+ margin-left: 5px;
491
+ @include border-radius(7px);
492
+ font-style: normal; }
493
+ }
494
+
379
495
  //
380
496
  // Prettify
381
497
  //
data/data/rack/config.ru CHANGED
@@ -1,8 +1,4 @@
1
- begin
2
- require 'bundler'
3
- Bundler.setup
4
- rescue LoadError => e
5
- end
6
-
1
+ gem 'proscribe', '~> 0.0.1'
7
2
  require 'proscribe'
3
+
8
4
  run ProScribe.rack_app
data/lib/proscribe/cli.rb CHANGED
@@ -41,5 +41,17 @@ class ProScribe::CLI < Shake
41
41
  copy_files ProScribe.root('data/rack'), dir
42
42
  end
43
43
  task.description = "Makes a project Rack-compatible"
44
+
45
+ invalid do
46
+ if task(command)
47
+ usage = task(command).usage || command
48
+
49
+ err "Invalid usage."
50
+ err "Usage: #{executable} #{usage}"
51
+ err "See `#{executable} help` for more info."
52
+ else
53
+ err "Unknown command: #{command}"
54
+ err "See `#{executable} help` for a list of commands."
55
+ end
56
+ end
44
57
  end
45
-
@@ -17,8 +17,9 @@ module ProScribe
17
17
  # ex.write!('manual/') # Writes to manual/
18
18
  #
19
19
  class Extractor
20
- def initialize(files, options={})
20
+ def initialize(files, root, options={})
21
21
  @files = files
22
+ @root = File.realpath(root)
22
23
  end
23
24
 
24
25
  def write!(output_path = '.', &blk)
@@ -36,17 +37,22 @@ module ProScribe
36
37
  @files.map { |file|
37
38
  if File.file?(file)
38
39
  input = File.read(file)
39
- get_blocks input
40
+ get_blocks(input, unroot(file))
40
41
  end
41
42
  }.compact.flatten
42
43
  end
43
44
  end
44
45
 
45
46
  private
47
+ def unroot(fn)
48
+ (File.realpath(fn))[@root.size..-1]
49
+ end
50
+
46
51
  # Returns blocks that match a blah.
47
- def get_blocks(str)
52
+ def get_blocks(str, filename)
48
53
  arr = get_comment_blocks(str)
49
- arr.map { |block|
54
+ arr.map { |hash|
55
+ block = hash[:block]
50
56
  re = /^([A-Za-z ]*?): (.*?)(?: \((.*?)\))?$/
51
57
 
52
58
  if block.last =~ re
@@ -54,32 +60,37 @@ module ProScribe
54
60
  :type => $1,
55
61
  :title => $2,
56
62
  :parent => $3,
63
+ :line => hash[:line] + block.size + 1,
64
+ :source => filename,
57
65
  :body => (block[0..-2].join("\n") + "\n")
58
66
  elsif block.first =~ re
59
67
  Extractor::Block.new \
60
68
  :type => $1,
61
69
  :title => $2,
62
70
  :parent => $3,
71
+ :line => hash[:line] + block.size + 1,
72
+ :source => filename,
63
73
  :body => (block[1..-1].join("\n") + "\n")
64
74
  end
65
75
  }.compact
66
76
  end
67
77
 
68
78
  # Returns contiguous comment blocks.
79
+ # Returns an array of hashes (:block => [line1,line2...], :line => n)
69
80
  def get_comment_blocks(str)
70
81
  chunks = Array.new
71
82
  i = 0
72
83
 
73
- str.split("\n").each { |s|
84
+ str.split("\n").each_with_index { |s, line|
74
85
  if s =~ /^\s*(?:\/\/\/?|##?) ?(.*)$/
75
- chunks[i] ||= Array.new
76
- chunks[i] << $1
86
+ chunks[i] ||= { :block => Array.new, :line => line }
87
+ chunks[i][:block] << $1
77
88
  else
78
89
  i += 1 if chunks[i]
79
90
  end
80
91
  }
81
92
 
82
- chunks
93
+ chunks.compact
83
94
  end
84
95
  end
85
96
 
@@ -93,11 +104,14 @@ module ProScribe
93
104
  body = options[:body]
94
105
  type = options[:type].downcase
95
106
 
107
+ source = options[:source]
108
+ line = options[:line]
109
+
96
110
  file = to_filename(title, parent)
97
111
  brief, *body = body.split("\n\n")
98
112
  body = "#{body.join("\n\n")}"
99
113
 
100
- heading = "title: #{title}\npage_type: #{type}\nbrief: #{brief}\n"
114
+ heading = "title: #{title}\npage_type: #{type}\nsource_file: #{source}\nsource_line: #{line}\nbrief: #{brief}\n"
101
115
  heading += "--\n"
102
116
 
103
117
  @file = file
@@ -52,19 +52,39 @@ module ProScribe
52
52
  # Copy manual files over
53
53
  copy_files manual_path, dir, :except => ['Gemfile', 'Gemfile.lock', 'config.ru']
54
54
 
55
+ # Merge Scribefile into Protonfile
56
+ File.open(File.join(dir, 'Protonfile'), 'w') { |f| f.write protonfile }
57
+
55
58
  # Extract block comments
56
59
  config.files.each do |group|
57
- ex = ProScribe::Extractor.new Dir[root(group.source)]
58
- ex.write! File.join(dir, group.target)
60
+ ex = ProScribe::Extractor.new(Dir[root(group.source)], root)
61
+ ex.write! File.join(dir, group.prefix || '')
59
62
  end
60
63
  end
61
64
 
65
+ def protonfile
66
+ yaml = YAML::load_file(ProScribe.root('data/default/Protonfile'))
67
+
68
+ # Copy from Scribefile
69
+ c = config.to_hash.dup
70
+ c.delete 'manual'
71
+ c.delete 'output'
72
+ c.delete 'files'
73
+
74
+ # Add some things
75
+ c['git'] = `git rev-parse HEAD`.strip
76
+
77
+ yaml.merge! c
78
+
79
+ YAML::dump yaml
80
+ end
81
+
62
82
  # Attribute: dir (ProScribe::Project)
63
83
  # Returns the path to the temporary Proton project.
64
84
  #
65
85
  def dir(*a)
66
86
  @dir ||= begin
67
- dir = File.join(Dir.tmpdir, File.basename(root))
87
+ dir = File.join(Dir.tmpdir, File.basename(root) + Time.now.to_i.to_s)
68
88
  FileUtils.rm_rf dir
69
89
  FileUtils.mkdir_p dir
70
90
  dir
@@ -2,7 +2,7 @@ require 'proton'
2
2
  require 'proton/server'
3
3
  require 'shake'
4
4
 
5
- # Module: RackApp
5
+ # Module: RackApp (ProScribe)
6
6
  # Provides a Rack app.
7
7
  #
8
8
  # ## Usage
@@ -3,9 +3,9 @@ module ProScribe
3
3
  # Returns the version of the ProScribe gem.
4
4
  #
5
5
  # ## Example
6
- # ProScribe.version #=> "0.0.1"
6
+ # ProScribe.version #=> "0.0.2"
7
7
  #
8
8
  def self.version
9
- "0.0.1"
9
+ "0.0.3"
10
10
  end
11
11
  end
data/lib/proscribe.rb CHANGED
@@ -8,6 +8,17 @@ require 'tilt'
8
8
  # Module: ProScribe
9
9
  # The main module.
10
10
  #
11
+ # #### Hello s1
12
+ #
13
+ # yes s1
14
+ #
15
+ # foo s1
16
+ # foo s1
17
+ #
18
+ # #### Creating something
19
+ #
20
+ # s2
21
+ #
11
22
  module ProScribe
12
23
  def self.root(*a)
13
24
  File.join(File.expand_path('../../', __FILE__), *a)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: proscribe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,12 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-07-24 00:00:00.000000000 +08:00
12
+ date: 2011-07-29 00:00:00.000000000 +08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: hashie
17
- requirement: &2153048280 !ruby/object:Gem::Requirement
17
+ requirement: &2158295020 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: 1.0.0
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2153048280
25
+ version_requirements: *2158295020
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: shake
28
- requirement: &2153047780 !ruby/object:Gem::Requirement
28
+ requirement: &2158294520 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ~>
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: 0.1.2
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *2153047780
36
+ version_requirements: *2158294520
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: tilt
39
- requirement: &2153047320 !ruby/object:Gem::Requirement
39
+ requirement: &2158294060 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ~>
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: 1.2.2
45
45
  type: :runtime
46
46
  prerelease: false
47
- version_requirements: *2153047320
47
+ version_requirements: *2158294060
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: proton
50
- requirement: &2153046860 !ruby/object:Gem::Requirement
50
+ requirement: &2158293600 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ~>
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: 0.3.3
56
56
  type: :runtime
57
57
  prerelease: false
58
- version_requirements: *2153046860
58
+ version_requirements: *2158293600
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: fssm
61
- requirement: &2153046400 !ruby/object:Gem::Requirement
61
+ requirement: &2158293140 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ~>
@@ -66,10 +66,10 @@ dependencies:
66
66
  version: 0.2.7
67
67
  type: :runtime
68
68
  prerelease: false
69
- version_requirements: *2153046400
69
+ version_requirements: *2158293140
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: rdiscount
72
- requirement: &2153045940 !ruby/object:Gem::Requirement
72
+ requirement: &2158292680 !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
75
  - - ~>
@@ -77,7 +77,7 @@ dependencies:
77
77
  version: 1.6.8
78
78
  type: :runtime
79
79
  prerelease: false
80
- version_requirements: *2153045940
80
+ version_requirements: *2158292680
81
81
  description: Build some documentation for your projects of any language.
82
82
  email:
83
83
  - rico@sinefunc.com
@@ -86,18 +86,15 @@ executables:
86
86
  extensions: []
87
87
  extra_rdoc_files: []
88
88
  files:
89
- - data/default/_extensions/manual/lib/cli.rb
90
- - data/default/_extensions/manual/lib/extractor.rb
91
- - data/default/_extensions/manual/lib/helpers.rb
92
- - data/default/_extensions/manual/manual.rb
89
+ - data/default/_extensions/helpers.rb
93
90
  - data/default/_layouts/_nav.haml
94
91
  - data/default/_layouts/default.haml
95
92
  - data/default/Gemfile
96
93
  - data/default/Gemfile.lock
94
+ - data/default/proscribe.js
97
95
  - data/default/Protonfile
98
96
  - data/default/style.scss
99
97
  - data/rack/config.ru
100
- - data/rack/Gemfile
101
98
  - bin/proscribe
102
99
  - lib/proscribe/cli.rb
103
100
  - lib/proscribe/extractor.rb
@@ -1,18 +0,0 @@
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
-
@@ -1,206 +0,0 @@
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__
@@ -1,2 +0,0 @@
1
- require File.expand_path('../lib/cli', __FILE__)
2
- require File.expand_path('../lib/helpers', __FILE__)
data/data/rack/Gemfile DELETED
@@ -1,2 +0,0 @@
1
- source :rubygems
2
- gem 'proscribe', '~> 0.0.1'