bri 0.4.4 → 1.0.0.pre.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/TODO +2 -3
  3. data/bin/bri +21 -7
  4. data/lib/bri.rb +18 -15
  5. data/lib/bri/mall.rb +12 -14
  6. data/lib/bri/match/base.rb +1 -1
  7. data/lib/bri/match/class.rb +5 -1
  8. data/lib/bri/match/method.rb +2 -1
  9. data/lib/bri/renderer.rb +28 -188
  10. data/lib/bri/renderer/blank_line.rb +9 -0
  11. data/lib/bri/renderer/default.rb +27 -0
  12. data/lib/bri/renderer/document.rb +11 -0
  13. data/lib/bri/renderer/heading.rb +9 -0
  14. data/lib/bri/renderer/list.rb +24 -0
  15. data/lib/bri/renderer/list/base.rb +18 -0
  16. data/lib/bri/renderer/list/bullet.rb +15 -0
  17. data/lib/bri/renderer/list/labeled.rb +15 -0
  18. data/lib/bri/renderer/list/lower_lettered.rb +18 -0
  19. data/lib/bri/renderer/list/note.rb +15 -0
  20. data/lib/bri/renderer/list/numbered.rb +18 -0
  21. data/lib/bri/renderer/list/upper_lettered.rb +18 -0
  22. data/lib/bri/renderer/list_item.rb +24 -0
  23. data/lib/bri/renderer/paragraph.rb +11 -0
  24. data/lib/bri/renderer/result.rb +73 -0
  25. data/lib/bri/renderer/rule.rb +9 -0
  26. data/lib/bri/renderer/verbatim.rb +14 -0
  27. data/lib/bri/search/class.rb +3 -1
  28. data/lib/bri/search/method.rb +3 -3
  29. data/lib/bri/templates.rb +7 -38
  30. data/lib/bri/text_formatting_utils.rb +92 -0
  31. metadata +19 -12
  32. data/spec/bri_dummy_spec_class.rb +0 -132
  33. data/spec/lib/bri/mall_spec.rb +0 -38
  34. data/spec/lib/bri/match/class_spec.rb +0 -125
  35. data/spec/lib/bri/match/method_spec.rb +0 -112
  36. data/spec/lib/bri/matcher_spec.rb +0 -70
  37. data/spec/lib/bri/renderer_spec.rb +0 -338
  38. data/spec/lib/bri/search/class_method_spec.rb +0 -172
  39. data/spec/lib/bri/search/class_spec.rb +0 -66
  40. data/spec/lib/bri/search/instance_method_spec.rb +0 -173
  41. data/spec/lib/bri/search/method_spec.rb +0 -41
  42. data/spec/spec_helper.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 74b87ae62d01b5be9164734271754be0cc3a1ef68ad3b35bd78b633d829a529a
4
- data.tar.gz: 27fdfe717c1cea3b49525ff5e9c59b462757d1d86db440bd4dc1fd9719f47c70
3
+ metadata.gz: 2a26dfbcd940347c2bf68246c1223702a30ae82cc6ff032fd9160f4f6cd2587f
4
+ data.tar.gz: ad88f5eb0b894300eb1f8073da1baf4444ebebd07aa992d772465044f1a6d444
5
5
  SHA512:
6
- metadata.gz: e0d96c3ae752ec0b5b3fb59ad58da596869fd91665282eeb588ba8c03041b3f26040f331189b9db84a6d55aaf5e5540430dddbd07c925a7dde198ed6939bc7f0
7
- data.tar.gz: 4f3cc64561cb91cc53caf689611c32f6daf8d0482eb2bee3407358fad32fd808e0b70ce613c979b57917c0c2afe4b135f48f46e19de8888a167591d205aadecc
6
+ metadata.gz: c258a7980e40af727d7d543f70d14398df03019be7496116180d6c6812e5becbad29bde410d26983b49ec6617cbb477c73ed357ef18cf60e72ab362fce914ec1
7
+ data.tar.gz: 9cbe6dc1a11b9cc745ce75b8f602416dbba701bcb0a22f0c973d15375875cf23d67faa1b03836d63595752a189cbccacb4c6d943a0464a2ef616cf4254b2b6a0
data/TODO CHANGED
@@ -1,7 +1,4 @@
1
1
  - Extend unqualified search to include class methods and case insensitive searches
2
- - {multi word label}[links] won't display correctly if the label is right where
3
- a line wrap occurs
4
- - Refactor the convoluted rendering of lists and list items
5
2
  - Detect ansi capabilities and use what is possible with graceful degradation?
6
3
  - Potentially try to detect method references in documentation prose and
7
4
  highlight these (e.g. Object#send and Object.new)
@@ -9,3 +6,5 @@
9
6
  - Add display of module constant aliases
10
7
  - Rewrite the search code into something understandable and maintainable
11
8
  (sleep deprivation is one hell of a drug)
9
+ - Add UTF8 rendering mode
10
+ - Add --stats switch to see timing data
data/bin/bri CHANGED
@@ -20,12 +20,26 @@ def parse_options
20
20
  opts.separator " * #instance_method_name"
21
21
  opts.separator " * .class_method_name"
22
22
  opts.separator ""
23
- opts.on( nil, "--classes", "List known classes" ) { |v| @options[:list_classes] = true }
24
- opts.on( nil, "--methods", "List known methods" ) { |v| @options[:list_methods] = true }
25
- opts.on( "-l", "--list-names", "List known namespaces/methods" ) { |v| @options[:list_names] = true }
26
- opts.on( "-w", "--width [COLUMNS]", "Set the output width", Integer ) { |v| Bri.width = v.to_i - 8 }
27
- opts.on( "-a", "--all", "Output all documentation for the term. Prefers core documents otherwise") { |v| @options[:show_all] = true }
28
- opts.on_tail( "-h", "--help", "This help text" ) { puts opts; exit }
23
+ opts.on( nil, "--classes", "List known classes" ) do |v|
24
+ @options[:list_classes] = true
25
+ end
26
+ opts.on( nil, "--methods", "List known methods" ) do |v|
27
+ @options[:list_methods] = true
28
+ end
29
+ opts.on( "-l", "--list-names", "List known namespaces/methods" ) do |v|
30
+ @options[:list_names] = true
31
+ end
32
+ opts.on( "-w", "--width [COLUMNS]", "Set the output width", Integer ) do |v|
33
+ Bri.width = v.to_i - 8
34
+ end
35
+ opts.on( "-a", "--all",
36
+ "Output gem documentation in addition to core documents" ) do |v|
37
+ @options[:show_all] = true
38
+ end
39
+ opts.on_tail( "-h", "--help", "This help text" ) do
40
+ puts opts
41
+ exit
42
+ end
29
43
  end
30
44
  parser.parse!( ARGV )
31
45
 
@@ -45,5 +59,5 @@ elsif @options[:list_methods]
45
59
  elsif @options[:list_names]
46
60
  puts Bri.list_names
47
61
  else
48
- puts Bri.ri( ARGV[0], show_all: @options[:show_all] )
62
+ puts Bri.ri( ARGV[0], @options )
49
63
  end
data/lib/bri.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'erb'
2
2
  require 'term/ansicolor'
3
3
 
4
+ require_relative 'bri/text_formatting_utils'
4
5
  require_relative 'bri/renderer'
5
6
  require_relative 'bri/mall'
6
7
  require_relative 'bri/matcher'
@@ -11,22 +12,24 @@ require_relative 'bri/match'
11
12
  module Bri
12
13
  DEFAULT_WIDTH = 72
13
14
 
14
- def self.ri( query, show_all: false )
15
+ def self.ri( query, options )
16
+ if options[:show_all]
17
+ Bri::Mall.ri_paths( system: true, site: true, home: true, gems: true )
18
+ else
19
+ Bri::Mall.ri_paths( system: true, site: true, home: true, gems: false )
20
+ end
21
+
15
22
  results = Bri::Matcher.new( query ).find
16
23
 
17
24
  if results.size == 0
18
25
  "No matching results found"
26
+
19
27
  elsif results.size == 1
20
28
  results.first.to_s
29
+
21
30
  elsif results.all? { |r| r.is_a?(Bri::Match::Class) }
22
- if show_all
23
- results.map(&:to_s)
24
- else
25
- gem_docs, core_docs = results.partition { |r| r.origin =~ %r{gem\b} }
26
-
27
- docs_to_output = core_docs.empty? ? gem_docs : core_docs
28
- docs_to_output.map(&:to_s)
29
- end
31
+ results.map(&:to_s)
32
+
30
33
  else
31
34
  qualified_methods = results.map(&:full_name).sort
32
35
  ERB.new( Bri::Templates::MULTIPLE_CHOICES, nil, '<>' ).result( binding )
@@ -47,18 +50,18 @@ module Bri
47
50
  end
48
51
 
49
52
  def self.list_classes
50
- Bri::Mall.instance.classes.join("\n" )
53
+ Bri::Mall.classes.join("\n" )
51
54
  end
52
55
 
53
56
  def self.list_methods
54
- ( Bri::Mall.instance.instance_methods +
55
- Bri::Mall.instance.class_methods ).sort.join( "\n" )
57
+ ( Bri::Mall.instance_methods +
58
+ Bri::Mall.class_methods ).sort.join( "\n" )
56
59
  end
57
60
 
58
61
  def self.list_names
59
- ( Bri::Mall.instance.classes +
60
- Bri::Mall.instance.instance_methods +
61
- Bri::Mall.instance.class_methods ).sort.join( "\n" )
62
+ ( Bri::Mall.classes +
63
+ Bri::Mall.instance_methods +
64
+ Bri::Mall.class_methods ).sort.join( "\n" )
62
65
  end
63
66
 
64
67
  end
@@ -1,18 +1,24 @@
1
1
  require 'rdoc/ri/paths'
2
2
  require 'rdoc/ri/store'
3
- require 'singleton'
4
3
 
5
4
  module Bri
6
5
  class Mall
7
- include Singleton
8
6
 
9
- attr_reader :stores
7
+ def self.ri_paths( system: true, site: true, home: true, gems: true )
8
+ @ri_paths ||= RDoc::RI::Paths.each( system, site, home, gems )
9
+ end
10
+
11
+ def self.stores
12
+ @stores ||= ri_paths.each_with_object( [] ) do |(path, type), stores|
13
+ stores << RDoc::Store.new( path, type ).tap { |store| store.load_cache }
14
+ end
15
+ end
10
16
 
11
- def classes
17
+ def self.classes
12
18
  stores.flat_map(&:module_names).uniq.sort
13
19
  end
14
20
 
15
- def class_methods
21
+ def self.class_methods
16
22
  stores.each_with_object( [] ) do |store, result|
17
23
  store.class_methods.each do |klass, methods|
18
24
  methods.each { |method| result << "#{klass}.#{method}" }
@@ -20,20 +26,12 @@ module Bri
20
26
  end.uniq
21
27
  end
22
28
 
23
- def instance_methods
29
+ def self.instance_methods
24
30
  stores.each_with_object( [] ) do |store, result|
25
31
  store.instance_methods.each do |klass, methods|
26
32
  methods.each { |method| result << "#{klass}##{method}" }
27
33
  end
28
34
  end.uniq
29
35
  end
30
-
31
- private
32
- def initialize
33
- # We want: system, site, home and gem documentation
34
- @stores = RDoc::RI::Paths.each( true, true, true, true ).each_with_object( [] ) do |(path, type), stores|
35
- stores << RDoc::Store.new( path, type ).tap { |store| store.load_cache }
36
- end
37
- end
38
36
  end
39
37
  end
@@ -8,7 +8,7 @@ module Bri
8
8
 
9
9
  private
10
10
  def build_description( source )
11
- source.map { |element| Bri::Renderer.render( element ) }.compact
11
+ source.map { |element| Bri::Renderer.new( element ).render }.compact.map(&:output)
12
12
  end
13
13
  end
14
14
  end
@@ -4,7 +4,11 @@ require 'rdoc/markup/paragraph'
4
4
  module Bri
5
5
  module Match
6
6
  class Class < Base
7
- include Bri::Templates::Helpers
7
+ # FIXME This should not be part of this class; the template may need
8
+ # a modiified binding.
9
+ #
10
+ include Bri::TextFormattingUtils
11
+
8
12
  TEMPLATE = Bri::Templates::CLASS_DESCRIPTION
9
13
 
10
14
  attr_reader :type, :name, :description_paragraphs,
@@ -1,7 +1,8 @@
1
1
  module Bri
2
2
  module Match
3
3
  class Method < Base
4
- include Bri::Templates::Helpers
4
+ include Bri::TextFormattingUtils
5
+
5
6
  TEMPLATE = Bri::Templates::METHOD_DESCRIPTION
6
7
 
7
8
  attr_accessor :full_name, :call_syntaxes, :description_paragraphs, :origin
@@ -1,195 +1,35 @@
1
1
  require 'strscan'
2
+ require 'rdoc'
3
+ require 'rdoc/markup'
4
+
5
+ require_relative 'renderer/default'
6
+ require_relative 'renderer/blank_line'
7
+ require_relative 'renderer/document'
8
+ require_relative 'renderer/heading'
9
+ require_relative 'renderer/list_item'
10
+ require_relative 'renderer/list'
11
+ require_relative 'renderer/paragraph'
12
+ require_relative 'renderer/rule'
13
+ require_relative 'renderer/verbatim'
14
+ require_relative 'renderer/result'
2
15
 
3
16
  module Bri
4
17
  module Renderer
5
- Color = ::Term::ANSIColor
6
-
7
- INDENT = ' ' * 2
8
- INDENT_WIDTH = 2
9
- LOWER_ALPHABET = ('a'..'z').to_a.map { |char| "#{char}." }.freeze
10
- UPPER_ALPHABET = ('A'..'Z').to_a.map { |char| "#{char}." }.freeze
11
-
12
- def self.render( element, width = Bri.width, alignment_width = 0 )
13
- case element
14
- when RDoc::Markup::Verbatim
15
- text = extract_text( element, width )
16
- styled_text = replace_markup( text )
17
- "#{indent( styled_text )}\n"
18
-
19
- when RDoc::Markup::List
20
- item_width = width - INDENT_WIDTH
21
- case element.type
22
- when :BULLET
23
- rendered_items = element.items.map { |item| render( item, item_width ) }
24
- rendered_items.map! { |item| item.gsub( /\n/, "\n#{INDENT}" ) }
25
- rendered_items.map! { |item| item.prepend( ' *' ) }
26
-
27
- when :NUMBER
28
- rendered_items = element.items.map { |item| render( item, item_width ) }
29
- rendered_items.map! { |item| item.gsub( /\n/, "\n#{INDENT}" ) }
30
- rendered_items.map!.with_index( 1 ) { |item, i| item.prepend( "#{i}." ) }
31
-
32
- when :LALPHA
33
- rendered_items = element.items.map { |item| render( item, item_width ) }
34
- rendered_items.map! { |item| item.gsub( /\n/, "\n#{INDENT}" ) }
35
- rendered_items.map!.with_index { |item, i| item.prepend( LOWER_ALPHABET[i] ) }
36
-
37
- when :UALPHA
38
- rendered_items = element.items.map { |item| render( item, item_width ) }
39
- rendered_items.map! { |item| item.gsub( /\n/, "\n#{INDENT}" ) }
40
- rendered_items.map!.with_index { |item, index| item.prepend( UPPER_ALPHABET[i] ) }
41
-
42
- when :LABEL
43
- # do nothing
44
- rendered_items = element.items.map { |item| render( item, item_width ) }
45
- rendered_items.map! { |item| item.gsub( /\n/, "\n#{INDENT}" ) }
46
-
47
- when :NOTE
48
- alignment_width = element.items.flat_map(&:label).map(&:size).max + 1
49
- rendered_items = element.items.map { |item| render( item, item_width, alignment_width ) }
50
- rendered_items.map! { |item| item.gsub( /\n/, "\n#{INDENT}" ) }
51
- end
52
-
53
- "#{rendered_items.join( "\n" )}\n"
54
-
55
- else
56
- text = extract_text( element, width, alignment_width )
57
-
58
- if text == "\n"
59
- nil
60
- else
61
- styled_text = replace_markup( text )
62
- wrapped_text = wrap_to_width( styled_text, width )
63
- indent( wrapped_text )
64
- end
65
- end
66
- end
67
-
68
- def self.extract_text( element, width, label_alignment_width = 0, conserve_newlines = false )
69
- case element
70
- when RDoc::Markup::Paragraph
71
- join_char = conserve_newlines ? "\n" : " "
72
- element.parts.map(&:strip).join( join_char ) + "\n"
73
-
74
- when RDoc::Markup::BlankLine
75
- "\n"
76
-
77
- when RDoc::Markup::Rule
78
- "-" * width + "\n"
79
-
80
- when RDoc::Markup::Verbatim
81
- element.parts.map { |part| part.prepend( " " ) }.join + "\n"
82
-
83
- when RDoc::Markup::Heading
84
- "<h>#{element.text}</h>\n"
85
-
86
- when RDoc::Markup::ListItem
87
- parts = element.parts.map { |part| extract_text( part, width, 0, true ) }.join
88
-
89
- if element.label
90
- labels = element.label.map { |l| "#{l}:" }.join("\n")
91
- sprintf( "%*s %s", -label_alignment_width, labels, parts )
92
- else
93
- parts
94
- end
95
-
96
- when RDoc::Markup::List
97
- render( element, width - INDENT_WIDTH ) + "\n"
98
-
99
- when RDoc::Markup::Document
100
- element.parts.
101
- map { |part| extract_text( part, width, label_alignment_width, conserve_newlines ) }.
102
- join + "\n"
103
- else
104
- raise "Don't know how to handle type #{element.class}: #{element.inspect}"
105
- end
106
- end
107
-
108
- def self.replace_markup( text )
109
- text.gsub!( /(?<!\\)<(?:tt|code)>/, Color.cyan )
110
- text.gsub!( /(?<!\\)<\/(?:tt|code)>/, Color.reset )
111
-
112
- text.gsub!( /(?<!\\)<b>/, Color.bold )
113
- text.gsub!( /(?<!\\)<\/b>/, Color.reset )
114
-
115
- text.gsub!( /(?<!\\)<(?:em|i)>/, Color.yellow )
116
- text.gsub!( /(?<!\\)<\/(?:em|i)>/, Color.reset )
117
-
118
- text.gsub!( "<h>", Color.green )
119
- text.gsub!( "</h>", Color.reset )
120
-
121
- text.gsub!( "\\<", "<" )
122
-
123
- text.gsub!( /(#\s*=>)(.*)/,
124
- "#{Color.dark}\\1#{Color.reset}#{Color.bold}\\2#{Color.reset}" )
125
-
126
- text.gsub!( /(^|\s)\*(.*?[a-zA-Z0-9]+.*?)\*/,
127
- "\\1#{Color.bold}\\2#{Color.reset}" )
128
- text.gsub!( /(^|\s)\+(.*?[a-zA-Z0-9]+.*?)\+/,
129
- "\\1#{Color.cyan}\\2#{Color.reset}" )
130
- text.gsub!( /(^|\s)_(.*?[a-zA-Z0-9]+.*?)_/,
131
- "\\1#{Color.yellow}\\2#{Color.reset}" )
132
-
133
- text.gsub!( %r{\b((?:https?|ftp)://[-\w.?%&=/]+)\b},
134
- "#{Color.underline}\\1#{Color.reset}" )
135
-
136
- text.gsub!( %r{\b(mailto:[-\w.%]+@[-\w.]+)\b},
137
- "#{Color.underline}\\1#{Color.reset}" )
138
-
139
- text.gsub!( %r{\b((?<!:\/\/)www.[-\w.?%&=]+)\b},
140
- "#{Color.underline}\\1#{Color.reset}" )
141
-
142
- text.gsub!( %r{\blink:(.*?)(\s|$)},
143
- "#{Color.underline}\\1#{Color.reset}\\2" )
144
-
145
- text.gsub!( %r{\{(.*?)\}\[(.*?)\]}, "\\1 (\\2)" )
146
- text.gsub!( %r{\[(#{Regexp.escape( Color.underline )}.*?#{Regexp.escape( Color.reset )})\]},
147
- " (\\1)" )
148
- text
149
- end
150
-
151
- def self.printable_length( text )
152
- Term::ANSIColor.uncolored( text ).length
153
- end
154
-
155
- def self.wrap_list( array, width = Bri.width )
156
- indent( wrap_to_width( array.join(" "), width ) )
157
- end
158
-
159
- def self.wrap_to_width( styled_text, width )
160
- styled_text.split( "\n" ).map { |row| wrap_row( row, width ) }.join
161
- end
162
-
163
- def self.wrap_row( physical_row, width )
164
- output_text = ''
165
- logical_row = ''
166
- printable_row_length = 0
167
-
168
- scanner = StringScanner.new( physical_row )
169
-
170
- while( !scanner.eos? )
171
- token = scanner.scan( /\S+/ ).to_s
172
- printable_token_length = printable_length( token )
173
-
174
- if printable_token_length + printable_row_length > width
175
- output_text << logical_row << "\n"
176
- logical_row = ''
177
- printable_row_length = 0
178
- end
179
-
180
- logical_row << token
181
- printable_row_length += printable_token_length
182
-
183
- token = scanner.scan( /\s*/ ).to_s
184
- logical_row << token
185
- printable_row_length += token.length
186
- end
187
-
188
- output_text << logical_row << "\n"
189
- end
190
-
191
- def self.indent( text )
192
- text.split( "\n" ).map { |row| "#{INDENT}#{row}" }.join("\n" )
18
+ RDOC_TO_BRI_RENDERER_CLASS_MAP = {
19
+ ::RDoc::Markup::Document => ::Bri::Renderer::Document,
20
+ ::RDoc::Markup::Paragraph => ::Bri::Renderer::Paragraph,
21
+ ::RDoc::Markup::BlankLine => ::Bri::Renderer::BlankLine,
22
+ ::RDoc::Markup::Rule => ::Bri::Renderer::Rule,
23
+ ::RDoc::Markup::Verbatim => ::Bri::Renderer::Verbatim,
24
+ ::RDoc::Markup::Heading => ::Bri::Renderer::Heading,
25
+ ::RDoc::Markup::ListItem => ::Bri::Renderer::ListItem,
26
+ ::RDoc::Markup::List => ::Bri::Renderer::List,
27
+ }
28
+ RDOC_TO_BRI_RENDERER_CLASS_MAP.default = ::Bri::Renderer::Default
29
+
30
+ def self.new( element )
31
+ renderer_class = RDOC_TO_BRI_RENDERER_CLASS_MAP[element.class]
32
+ renderer_class.new( element )
193
33
  end
194
34
  end
195
35
  end
@@ -0,0 +1,9 @@
1
+ module Bri
2
+ module Renderer
3
+ class BlankLine < Default
4
+ def extract_text( width, conserve_newlines = false )
5
+ "\n"
6
+ end
7
+ end
8
+ end
9
+ end