bcat 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ Report bcat bugs and patches to the issue tracker:
2
+
3
+ <http://github.com/rtomayko/bcat/issues>
4
+
5
+ Unified diff patches and links to forks are appreciated.
data/COPYING CHANGED
@@ -0,0 +1,19 @@
1
+ bcat
2
+ Copyright (c) 2010 Ryan Tomayko <http://tomayko.com/about>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to
6
+ deal in the Software without restriction, including without limitation the
7
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8
+ sell copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all 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,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
+ THE AUTHORS 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.
@@ -0,0 +1,5 @@
1
+ bcat is usually installed with rubygems:
2
+
3
+ $ gem install bcat
4
+
5
+ bcat depends on the rack package.
data/README CHANGED
@@ -1,7 +1,17 @@
1
- bcat reads from standard input and displays output in a web browser:
1
+ bcat
2
+ http://github.com/rtomayko/bcat
3
+ git clone git://github.com/rtomayko/bcat.git
4
+ gem install bcat
5
+
6
+ bcat is a pipe to browser utility. It reads from standard input and displays
7
+ what it reads in a web browser:
2
8
 
3
9
  $ echo "hi mom" |bcat
4
- $ echo "hi mom" |bcat -t 'Page Title'
10
+ $ echo "hi mom" |bcat -t 'Important Message'
11
+
12
+ bcat assumes its input is plain text, but you can also pipe in HTML:
13
+
14
+ $ echo "<h1>hi mom</h1>" |bcat -h
5
15
  $ echo "*hi mom*" |markdown |bcat -h
6
16
 
7
17
  Browser output is displayed progressively as it's read from standard input,
@@ -11,3 +21,19 @@ generate output over longer periods of time:
11
21
  $ make all |bcat
12
22
  $ rake test |bcat
13
23
  $ tail -f /var/log/syslog |bcat
24
+ $ (while printf .; do sleep 1; done) |bcat
25
+
26
+ See the bcat(1) manual for detailed command usage.
27
+
28
+ bcat is known to work under MacOS X, Linux, and FreeBSD (other UNIX-like
29
+ environments with freedesktop.org integration should work fine too). Progressive
30
+ output has been tested under Safari, Firefox, Chrome, and GNOME Epiphany.
31
+
32
+ See the INSTALLING, COPYING, and CONTRIBUTING files for information on those
33
+ things.
34
+
35
+ bcat was inspired by the HTML output capabilities included in TextMate
36
+ and a desire to have those capabilities from the shell and within editors
37
+ like Vim.
38
+ <http://manual.macromates.com/en/commands#html_output>
39
+ <http://blog.macromates.com/2005/html-output-for-commands/>
data/Rakefile CHANGED
@@ -1,4 +1,26 @@
1
1
  require 'date'
2
+ task :default => :test
3
+
4
+ ROOTDIR = File.expand_path('..', __FILE__).sub(/#{Dir.pwd}(?=\/)/, '.')
5
+ LIBDIR = "#{ROOTDIR}/lib"
6
+ BINDIR = "#{ROOTDIR}/bin"
7
+
8
+ task :environment do
9
+ $:.unshift ROOTDIR if !$:.include?(ROOTDIR)
10
+ $:.unshift LIBDIR if !$:.include?(LIBDIR)
11
+ ENV['RUBYLIB'] = $LOAD_PATH.join(':')
12
+ ENV['PATH'] = "#{BINDIR}:#{ENV['PATH']}"
13
+ end
14
+
15
+ desc 'Run tests'
16
+ task :test => :environment do
17
+ $LOAD_PATH.unshift "#{ROOTDIR}/test"
18
+ Dir['test/test_*.rb'].each { |f| require(f) }
19
+ end
20
+
21
+ def source_version
22
+ @source_version ||= `ruby -Ilib -rbcat -e 'puts Bcat::VERSION'`.chomp
23
+ end
2
24
 
3
25
  require 'rubygems'
4
26
  $spec = eval(File.read('bcat.gemspec'))
@@ -15,10 +37,6 @@ task :man do
15
37
  sh "ronn -w -r5 man/*.ronn"
16
38
  end
17
39
 
18
- def source_version
19
- @source_version ||= `ruby -Ilib -rbcat -e 'puts Bcat::VERSION'`.chomp
20
- end
21
-
22
40
  file 'bcat.gemspec' => FileList['{lib,test,bin}/**','Rakefile'] do |f|
23
41
  # read spec file and split out manifest section
24
42
  spec = File.read(f.name)
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'bcat'
3
- s.version = '0.2.0'
4
- s.date = '2010-06-20'
3
+ s.version = '0.3.0'
4
+ s.date = '2010-06-21'
5
5
 
6
6
  s.summary = "browser cat"
7
7
  s.description =
@@ -13,6 +13,9 @@ Gem::Specification.new do |s|
13
13
 
14
14
  # = MANIFEST =
15
15
  s.files = %w[
16
+ CONTRIBUTING
17
+ COPYING
18
+ INSTALLING
16
19
  README
17
20
  Rakefile
18
21
  bcat.gemspec
@@ -21,10 +24,12 @@ Gem::Specification.new do |s|
21
24
  bin/btee
22
25
  lib/bcat.rb
23
26
  lib/bcat/browser.rb
27
+ lib/bcat/html.rb
24
28
  lib/bcat/kidgloves.rb
25
29
  lib/bcat/reader.rb
26
30
  man/bcat.1.ronn
27
31
  man/btee.1.ronn
32
+ test/test_bcat_head_parser.rb
28
33
  ]
29
34
  # = MANIFEST =
30
35
 
data/bin/bcat CHANGED
@@ -1,32 +1,41 @@
1
1
  #!/usr/bin/env ruby
2
- #/ Usage: bcat [-h] [-t <title>] [<file>]...
2
+ #/ Usage: bcat [-ht] [-m <module>] [-T <title>] [<file>]...
3
3
  #/ btee <options> [<file>]...
4
- #/ Read standard input, or one or more <file>s, and write to browser. When
5
- #/ invoked as btee, also write input to standard output.
4
+ #/ Pipe to browser utility. Read standard input, possibly one or more <file>s,
5
+ #/ and write concatenated / formatted output to browser. When invoked as btee,
6
+ #/ also write all input back to standard output.
6
7
  #/
7
- #/ Options
8
- #/ -h, --html input is html encoded
9
- #/ -t, --title=<text> use <text> as the page title
10
- #/ -d, --debug enable verbose debug logging on stderr
8
+ #/ Input format (auto detected by default):
9
+ #/ -h, --html input is already HTML encoded, perhaps a whole document
10
+ #/ -t, --text input is unencoded text
11
+ #/
12
+ #/ Tweak output with these options:
13
+ #/ -T, --title=<text> use <text> as the page title
14
+ #/ -m, --module=<m1>[,<m2>]...
15
+ #/ inject formatting module(s)
16
+ #/
17
+ #/ -d, --debug enable verbose debug logging on stderr
11
18
  require 'optparse'
12
19
 
13
20
  options = {
14
- :html => false,
15
- :title => Dir.pwd,
16
- :Host => '127.0.0.1',
17
- :Port => 8091,
18
- :debug => false
21
+ :format => nil,
22
+ :title => Dir.pwd,
23
+ :Host => '127.0.0.1',
24
+ :Port => 8091,
25
+ :debug => false,
26
+ :tee => !!($0 =~ /tee$/)
19
27
  }
20
28
 
21
29
  (class <<self;self;end).send(:define_method, :notice) { |message|
22
30
  warn "#{File.basename($0)}: #{message}" if options[:debug] }
23
31
 
24
32
  ARGV.options do |argv|
25
- argv.on('-h', '--html') { options[:html] = true }
33
+ argv.on('-h', '--html') { options[:format] = 'html' }
34
+ argv.on('-t', '--text') { options[:format] = 'text' }
26
35
  argv.on('-a', '--app=v') { |app| ENV['BCAT_APPLICATION'] = app }
27
- argv.on('-t', '--title=v') { |text| options[:title] = text }
36
+ argv.on('-T', '--title=v') { |text| options[:title] = text }
28
37
  argv.on('-d', '--debug') { options[:debug] = true }
29
- argv.on_tail('--help') { exec "grep ^#/ <#{__FILE__} | cut -c4-" }
38
+ argv.on_tail('--help') { exec "grep ^#/ <#{__FILE__} | cut -c4-" }
30
39
  argv.parse!
31
40
  end
32
41
  ARGV.push '-' if ARGV.empty?
@@ -38,17 +47,10 @@ include Bcat::Browser
38
47
  notice "env BCAT_APPLICATION=#{ENV['BCAT_APPLICATION'].inspect}"
39
48
  notice "env BCAT_COMMAND=#{browser_command.inspect}"
40
49
 
41
- reader =
42
- if File.basename($0) =~ /tee$/
43
- Bcat::TeeReader.new(ARGV, $stdout)
44
- else
45
- Bcat::Reader.new(ARGV)
46
- end
47
-
48
50
  notice "starting server"
49
51
  pid = nil
50
52
  begin
51
- bcat = Bcat.new(reader, options)
53
+ bcat = Bcat.new(ARGV, options)
52
54
  bcat.serve! do |sock|
53
55
  url = "http://#{bcat[:Host]}:#{bcat[:Port]}/#{File.basename(Dir.pwd)}"
54
56
  pid = browser(url)
@@ -59,5 +61,5 @@ end
59
61
 
60
62
  Process.wait(pid) if pid
61
63
  status = $?
62
- notice "open exited with #{status}"
64
+ notice "browser exited with #{status}"
63
65
  exit status
@@ -1,49 +1,84 @@
1
1
  require 'rack'
2
2
  require 'bcat/reader'
3
+ require 'bcat/html'
3
4
  require 'bcat/kidgloves'
4
5
  require 'bcat/browser'
5
6
 
6
7
  class Bcat
7
- VERSION = '0.2.0'
8
+ VERSION = '0.3.0'
8
9
  include Rack::Utils
9
10
 
10
- def initialize(reader, config={})
11
- @reader = reader
11
+ attr_reader :format
12
+
13
+ def initialize(files=[], config={})
12
14
  @config = {:Host => '127.0.0.1', :Port => 8091}.merge(config)
15
+ @reader = Bcat::Reader.new(files)
16
+ @format = @config[:format] || @reader.sniff
17
+
18
+ @filter = @reader
19
+ @filter = TeeFilter.new(@filter) if @config[:tee]
20
+ @filter = TextFilter.new(@filter) if @format == 'text'
13
21
  end
14
22
 
15
23
  def [](key)
16
24
  @config[key]
17
25
  end
18
26
 
27
+ def to_app
28
+ app = self
29
+ Rack::Builder.new do
30
+ use Rack::Chunked
31
+ run app
32
+ end
33
+ end
34
+
35
+ def serve!(&bk)
36
+ Rack::Handler::KidGloves.run to_app, @config, &bk
37
+ end
38
+
19
39
  def call(env)
20
40
  notice "#{env['REQUEST_METHOD']} #{env['PATH_INFO'].inspect}"
21
41
  [200, {"Content-Type" => "text/html;charset=utf-8"}, self]
22
42
  end
23
43
 
24
44
  def each
25
- yield "\n" * 1000
26
- yield "<!DOCTYPE html>\n"
27
- yield head
28
- yield "<pre>" if !self[:html]
29
-
30
- @reader.each do |buf|
31
- if !self[:html]
32
- buf = escape_html(buf)
33
- buf.gsub!(/\n/, "<br>")
34
- end
35
- buf = escape_js(buf)
36
- yield "<script>document.write('#{buf}');</script>"
45
+ head_parser = Bcat::HeadParser.new
46
+
47
+ @filter.each do |buf|
48
+ if head_parser.nil?
49
+ yield buf
50
+ elsif head_parser.feed(buf)
51
+ yield content_for_head(inject=head_parser.head)
52
+ yield head_parser.body
53
+ head_parser = nil
54
+ end
55
+ end
56
+
57
+ if head_parser
58
+ yield content_for_head(inject=head_parser.head) +
59
+ head_parser.body
37
60
  end
38
61
 
39
- yield "</pre>" if !self[:html]
40
62
  yield foot
63
+ rescue Errno::EINVAL
64
+ # socket was closed
65
+ notice "browser client went away"
66
+ rescue => boom
67
+ notice "boom: #{boom.class}: #{boom.to_s}"
68
+ raise
41
69
  end
42
70
 
43
- def head
44
- ["<html>",
45
- "<head><title>#{self[:title] || 'bcat'}</title></head>",
46
- "<body>"].join
71
+ def content_for_head(inject='')
72
+ [
73
+ "\n" * 1000,
74
+ "<!DOCTYPE html>",
75
+ "<html>",
76
+ "<head>",
77
+ "<!-- bcat was here -->",
78
+ "<title>#{self[:title] || 'bcat'}</title>",
79
+ inject.to_s,
80
+ "</head>"
81
+ ].join("\n")
47
82
  end
48
83
 
49
84
  def foot
@@ -61,18 +96,6 @@ class Bcat
61
96
  raise Interrupt
62
97
  end
63
98
 
64
- def to_app
65
- app = self
66
- Rack::Builder.new do
67
- use Rack::Chunked
68
- run app
69
- end
70
- end
71
-
72
- def serve!(&bk)
73
- Rack::Handler::KidGloves.run to_app, @config, &bk
74
- end
75
-
76
99
  def notice(message)
77
100
  return if !@config[:debug]
78
101
  warn "#{File.basename($0)}: #{message}"
@@ -0,0 +1,106 @@
1
+ class Bcat
2
+
3
+ # Parses HTML until the first displayable body character and provides methods
4
+ # for accessing head and body contents.
5
+ class HeadParser
6
+ attr_accessor :buf
7
+
8
+ def initialize
9
+ @buf = ''
10
+ @head = []
11
+ @body = nil
12
+ @html = nil
13
+ end
14
+
15
+ # Called to parse new data as it arrives.
16
+ def feed(data)
17
+ if complete?
18
+ @body << data
19
+ else
20
+ @buf << data
21
+ parse(@buf)
22
+ end
23
+ complete?
24
+ end
25
+
26
+ # Truthy once the first displayed character of the body has arrived.
27
+ def complete?
28
+ !@body.nil?
29
+ end
30
+
31
+ # Determine if the input is HTML. This nil before the first non-whitespace
32
+ # character is received, true if the first non-whitespace character is a
33
+ # '<', and false if the first non-whitespace character is something other
34
+ # than '<'.
35
+ def html?
36
+ @html
37
+ end
38
+
39
+ # The head contents without any DOCTYPE, <html>, or <head> tags. This should
40
+ # consist of only <style>, <script>, <link>, <meta>, and <title> tags.
41
+ def head
42
+ @head.join.gsub(/<\/?(?:html|head|!DOCTYPE).*?>/mi, '')
43
+ end
44
+
45
+ # The current body contents. The <body> tag is guaranteed to be present. If
46
+ # a <body> was included in the input, it's preserved with original
47
+ # attributes; otherwise, a <body> tag is inserted. The inject argument can
48
+ # be used to insert a string as the immediate descendant of the <body> tag.
49
+ def body(inject=nil)
50
+ if @body =~ /\A\s*(<body.*?>)(.*)/mi
51
+ [$1, inject, $2].compact.join("\n")
52
+ else
53
+ ["<body>", inject, @body].compact.join("\n")
54
+ end
55
+ end
56
+
57
+ HEAD_TOKS = [
58
+ /\A(<!DOCTYPE.*?>)/m,
59
+ /\A(<title.*?>.*?<\/title>)/mi,
60
+ /\A(<script.*?>.*?<\/script>)/mi,
61
+ /\A(<style.*?>.*?<\/style>)/mi,
62
+ /\A(<(?:html|head|meta|link).*?>)/mi,
63
+ /\A(<\/(?:html|head|meta|link|script|style|title)>)/mi,
64
+ /\A(<!--(.*?)-->)/m
65
+ ]
66
+
67
+ BODY_TOKS = [
68
+ /\A[^<]/,
69
+ /\A<(?!html|head|meta|link|script|style|title).*?>/
70
+ ]
71
+
72
+ # Parses buf into head and body parts. Basic approach is to eat anything
73
+ # possibly body related until we hit text or a body element.
74
+ def parse(buf=@buf)
75
+ if @html.nil?
76
+ if buf =~ /\A\s*[<]/m
77
+ @html = true
78
+ elsif buf =~ /\A\s*[^<]/m
79
+ @html = false
80
+ end
81
+ end
82
+
83
+ while !buf.empty?
84
+ buf.sub!(/\A(\s+)/m) { @head << $1 ; '' }
85
+ matched =
86
+ HEAD_TOKS.any? do |tok|
87
+ buf.sub!(tok) do
88
+ @head << $1
89
+ ''
90
+ end
91
+ end
92
+ break unless matched
93
+ end
94
+
95
+
96
+ if buf.empty?
97
+ buf
98
+ elsif BODY_TOKS.any? { |tok| buf =~ tok }
99
+ @body = buf
100
+ nil
101
+ else
102
+ buf
103
+ end
104
+ end
105
+ end
106
+ end
@@ -1,3 +1,5 @@
1
+ require 'rack/utils'
2
+
1
3
  class Bcat
2
4
  # ARGF style multi-file streaming interface. Input is read with IO#readpartial
3
5
  # to avoid buffering.
@@ -15,36 +17,73 @@ class Bcat
15
17
  File.open(f, 'rb')
16
18
  end
17
19
  end
20
+ @buf = []
18
21
  end
19
22
 
20
23
  def each
21
- fds.each do |fd|
24
+ yield @buf.shift while @buf.any?
25
+ while fd = fds.first
22
26
  fd.sync = true
23
27
  begin
24
28
  while buf = fd.readpartial(4096)
25
29
  yield buf
26
30
  end
27
31
  rescue EOFError
28
- ensure
29
32
  fd.close
30
33
  end
34
+ fds.shift
31
35
  end
32
36
  end
37
+
38
+ def sniff
39
+ @format ||=
40
+ catch :detect do
41
+ each do |chunk|
42
+ @buf << chunk
43
+ case chunk
44
+ when /\A\s*</m
45
+ throw :detect, 'html'
46
+ when /\A\s*[^<]/m
47
+ throw :detect, 'text'
48
+ end
49
+ end
50
+ throw :detect, 'text'
51
+ end
52
+ end
33
53
  end
34
54
 
35
55
  # Like Reader but writes all input to an output IO object in addition to
36
56
  # yielding to the block.
37
- class TeeReader < Reader
38
- def initialize(files=[], out=$stdout)
57
+ class TeeFilter
58
+ def initialize(source, out=$stdout)
59
+ @source = source
39
60
  @out = out
40
- super(files)
41
61
  end
42
62
 
43
63
  def each
44
- super() do |chunk|
64
+ @source.each do |chunk|
65
+ yield chunk
45
66
  @out.write chunk
67
+ end
68
+ end
69
+ end
70
+
71
+ class TextFilter
72
+ include Rack::Utils
73
+
74
+ def initialize(source, force=false)
75
+ @source = source
76
+ @force = force
77
+ end
78
+
79
+ def each
80
+ yield "<pre>"
81
+ @source.each do |chunk|
82
+ chunk = escape_html(chunk)
83
+ chunk = "<span>#{chunk}</span>" if !chunk.gsub!(/\n/, "<br>")
46
84
  yield chunk
47
85
  end
86
+ yield "</pre>"
48
87
  end
49
88
  end
50
89
  end
@@ -17,16 +17,26 @@ addition to being piped into the browser.
17
17
 
18
18
  ## OPTIONS
19
19
 
20
- * `-t`, `--title`=<text>:
21
- Use <text> as the page `<title>`. By default, the path to the current working
22
- directory is used as the title.
20
+ By default, `bcat` attempts to detect whether input is HTML or plain text using
21
+ a simple heuristic, but you can force input to be treated as one or the other
22
+ with these options:
23
+
24
+ * `-t`, `--text`:
25
+ The input is non-HTML encoded text. All bare `<` and `&` characters are
26
+ entity encoded, end-of-line characters are converted to `<br>`, and the
27
+ entire output is wrapped in a `<pre>`.
23
28
 
24
29
  * `-h`, `--html`:
25
- Do not HTML encode input. By default, `bcat` assumes input is plain text
26
- and entity encodes any `<` or `&` characters, converts raw end-of-line
27
- characters (`\n`) to `<br>` tags, and wraps output in a `<pre>` block. The
28
- `--html` option disables all of these conversions, causing the input text
29
- to be written directly as HTML.
30
+ The input is already HTML encoded. Under this mode, bcat passes input
31
+ through to the browser mostly unmodified. The input may be a full HTML
32
+ document, or it may be an HTML fragment. `bcat` outputs `<html>`, `<head>`,
33
+ and `<body>` elements even if they are not included in the input.
34
+
35
+ Customization
36
+
37
+ * `-T`, `--title`=<text>:
38
+ Use <text> as the page `<title>`. By default, the path to the current working
39
+ directory is used as the title.
30
40
 
31
41
  * `-a`, `--app`=`Safari`|`Google Chrome`|`Firefox`:
32
42
  MacOS only. The name of the browser application. This can also be set using
@@ -17,16 +17,26 @@ addition to being piped into the browser.
17
17
 
18
18
  ## OPTIONS
19
19
 
20
- * `-t`, `--title`=<text>:
21
- Use <text> as the page `<title>`. By default, the path to the current working
22
- directory is used as the title.
20
+ By default, `bcat` attempts to detect whether input is HTML or plain text using
21
+ a simple heuristic, but you can force input to be treated as one or the other
22
+ with these options:
23
+
24
+ * `-t`, `--text`:
25
+ The input is non-HTML encoded text. All bare `<` and `&` characters are
26
+ entity encoded, end-of-line characters are converted to `<br>`, and the
27
+ entire output is wrapped in a `<pre>`.
23
28
 
24
29
  * `-h`, `--html`:
25
- Do not HTML encode input. By default, `bcat` assumes input is plain text
26
- and entity encodes any `<` or `&` characters, converts raw end-of-line
27
- characters (`\n`) to `<br>` tags, and wraps output in a `<pre>` block. The
28
- `--html` option disables all of these conversions, causing the input text
29
- to be written directly as HTML.
30
+ The input is already HTML encoded. Under this mode, bcat passes input
31
+ through to the browser mostly unmodified. The input may be a full HTML
32
+ document, or it may be an HTML fragment. `bcat` outputs `<html>`, `<head>`,
33
+ and `<body>` elements even if they are not included in the input.
34
+
35
+ Customization
36
+
37
+ * `-T`, `--title`=<text>:
38
+ Use <text> as the page `<title>`. By default, the path to the current working
39
+ directory is used as the title.
30
40
 
31
41
  * `-a`, `--app`=`Safari`|`Google Chrome`|`Firefox`:
32
42
  MacOS only. The name of the browser application. This can also be set using
@@ -0,0 +1,56 @@
1
+ require 'contest'
2
+ require 'bcat/html'
3
+
4
+ class HeadParserTest < Test::Unit::TestCase
5
+
6
+ setup { @parser = Bcat::HeadParser.new }
7
+
8
+ test 'starts in an unknown state' do
9
+ assert @parser.html?.nil?
10
+ assert @parser.buf.empty?
11
+ end
12
+
13
+ test 'detects non-HTML input' do
14
+ @parser.feed("HOWDY <h1>")
15
+ assert_equal false, @parser.html?
16
+ assert_equal '', @parser.head
17
+ end
18
+
19
+ test 'separates head elements from body' do
20
+ @parser.feed("<style>h1{ font-size:500% }</style>")
21
+ @parser.feed("<h1>HOLLA</h1>")
22
+ assert_equal "<style>h1{ font-size:500% }</style>", @parser.head.strip
23
+ assert_equal "<body>\n<h1>HOLLA</h1>", @parser.body
24
+ end
25
+
26
+ test 'handles multiple head elements' do
27
+ stuff = [
28
+ "<style>h1{ font-size:500% }</style>",
29
+ "<link rel=alternate>",
30
+ "<script type='text/javascript'>{};</script>"
31
+ ]
32
+ stuff.each { |html| @parser.feed(html) }
33
+ @parser.feed("\n \n\n\n<h1>HOLLA</h1>")
34
+
35
+ assert_equal stuff.join, @parser.head.strip
36
+ end
37
+
38
+ test 'handles full documents' do
39
+ @parser.feed("<!DOCTYPE html>\n")
40
+ @parser.feed("<html><head><title>YO</title></head>")
41
+ @parser.feed("<body id=oyy><h1>OY</h1></body></html>")
42
+ assert_equal "<title>YO</title>", @parser.head.strip
43
+ assert_equal "<body id=oyy>\n<h1>OY</h1></body></html>", @parser.body
44
+ end
45
+
46
+ test 'knows when the head is fully parsed' do
47
+ @parser.feed("<!DOCTYPE html>\n")
48
+ assert !@parser.complete?
49
+
50
+ @parser.feed("<html><head><title>YO</title></head>")
51
+ assert !@parser.complete?
52
+
53
+ @parser.feed("<body id=oyy><h1>OY</h1></body></html>")
54
+ assert @parser.complete?
55
+ end
56
+ end
metadata CHANGED
@@ -1,13 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bcat
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 2
9
- - 0
10
- version: 0.2.0
4
+ version: 0.3.0
11
5
  platform: ruby
12
6
  authors:
13
7
  - Ryan Tomayko
@@ -15,23 +9,19 @@ autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
11
 
18
- date: 2010-06-20 00:00:00 -07:00
12
+ date: 2010-06-21 00:00:00 -07:00
19
13
  default_executable: bcat
20
14
  dependencies:
21
15
  - !ruby/object:Gem::Dependency
22
16
  name: rack
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
26
20
  requirements:
27
21
  - - ">="
28
22
  - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
23
  version: "0"
33
- type: :runtime
34
- version_requirements: *id001
24
+ version:
35
25
  description: Concatenate input from standard input, or one or more files, and write progressive output to a browser.
36
26
  email: rtomayko@gmail.com
37
27
  executables:
@@ -41,6 +31,9 @@ extensions: []
41
31
  extra_rdoc_files:
42
32
  - COPYING
43
33
  files:
34
+ - CONTRIBUTING
35
+ - COPYING
36
+ - INSTALLING
44
37
  - README
45
38
  - Rakefile
46
39
  - bcat.gemspec
@@ -49,11 +42,12 @@ files:
49
42
  - bin/btee
50
43
  - lib/bcat.rb
51
44
  - lib/bcat/browser.rb
45
+ - lib/bcat/html.rb
52
46
  - lib/bcat/kidgloves.rb
53
47
  - lib/bcat/reader.rb
54
48
  - man/bcat.1.ronn
55
49
  - man/btee.1.ronn
56
- - COPYING
50
+ - test/test_bcat_head_parser.rb
57
51
  has_rdoc: true
58
52
  homepage: http://github.com/rtomayko/bcat/
59
53
  licenses: []
@@ -65,27 +59,21 @@ rdoc_options:
65
59
  require_paths:
66
60
  - lib
67
61
  required_ruby_version: !ruby/object:Gem::Requirement
68
- none: false
69
62
  requirements:
70
63
  - - ">="
71
64
  - !ruby/object:Gem::Version
72
- hash: 3
73
- segments:
74
- - 0
75
65
  version: "0"
66
+ version:
76
67
  required_rubygems_version: !ruby/object:Gem::Requirement
77
- none: false
78
68
  requirements:
79
69
  - - ">="
80
70
  - !ruby/object:Gem::Version
81
- hash: 3
82
- segments:
83
- - 0
84
71
  version: "0"
72
+ version:
85
73
  requirements: []
86
74
 
87
75
  rubyforge_project:
88
- rubygems_version: 1.3.7
76
+ rubygems_version: 1.3.5
89
77
  signing_key:
90
78
  specification_version: 3
91
79
  summary: browser cat