bcat 0.0.0

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/COPYING ADDED
File without changes
@@ -0,0 +1,42 @@
1
+ require 'date'
2
+
3
+ require 'rubygems'
4
+ $spec = eval(File.read('bcat.gemspec'))
5
+
6
+ desc "Build gem package"
7
+ task :package => 'bcat.gemspec' do
8
+ sh "gem build bcat.gemspec"
9
+ end
10
+
11
+ desc 'Build the manual'
12
+ task :man do
13
+ ENV['RONN_MANUAL'] = "Bcat #{source_version}"
14
+ ENV['RONN_ORGANIZATION'] = "Ryan Tomayko"
15
+ sh "ronn -w -r5 man/*.ronn"
16
+ end
17
+
18
+ def source_version
19
+ @source_version ||= `ruby -Ilib -rbcat -e 'puts Bcat::VERSION'`.chomp
20
+ end
21
+
22
+ file 'bcat.gemspec' => FileList['{lib,test,bin}/**','Rakefile'] do |f|
23
+ # read spec file and split out manifest section
24
+ spec = File.read(f.name)
25
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
26
+ # replace version and date
27
+ head.sub!(/\.version = '.*'/, ".version = '#{source_version}'")
28
+ head.sub!(/\.date = '.*'/, ".date = '#{Date.today.to_s}'")
29
+ # determine file list from git ls-files
30
+ files = `git ls-files`.
31
+ split("\n").
32
+ sort.
33
+ reject{ |file| file =~ /^\./ }.
34
+ reject { |file| file =~ /^doc/ }.
35
+ map{ |file| " #{file}" }.
36
+ join("\n")
37
+ # piece file back together and write...
38
+ manifest = " s.files = %w[\n#{files}\n ]\n"
39
+ spec = [head,manifest,tail].join(" # = MANIFEST =\n")
40
+ File.open(f.name, 'w') { |io| io.write(spec) }
41
+ puts "updated #{f.name}"
42
+ end
@@ -0,0 +1,37 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'bcat'
3
+ s.version = '0.0.0'
4
+ s.date = '2010-06-19'
5
+
6
+ s.summary = "browser cat"
7
+ s.description =
8
+ "Concatenate input from standard input, or one or more files, " +
9
+ "and write progressive output to a browser."
10
+
11
+ s.authors = ["Ryan Tomayko"]
12
+ s.email = "rtomayko@gmail.com"
13
+
14
+ # = MANIFEST =
15
+ s.files = %w[
16
+ Rakefile
17
+ bcat.gemspec
18
+ bin/bcat
19
+ lib/bcat.rb
20
+ lib/bcat/kidgloves.rb
21
+ man/bcat.1.ronn
22
+ ]
23
+ # = MANIFEST =
24
+
25
+ s.default_executable = 'bcat'
26
+ s.executables = ['bcat']
27
+
28
+ s.test_files = s.files.select {|path| path =~ /^test\/.*_test.rb/}
29
+ s.add_dependency 'rack'
30
+
31
+ s.extra_rdoc_files = %w[COPYING]
32
+
33
+ s.has_rdoc = true
34
+ s.homepage = "http://github.com/rtomayko/bcat/"
35
+ s.rdoc_options = ["--line-numbers", "--inline-source"]
36
+ s.require_paths = %w[lib]
37
+ end
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+ # Usage: bcat [<file>]...
3
+ # Read standard input, or one or more <file>s, and write to browser.
4
+ require 'bcat'
5
+
6
+ fds =
7
+ ARGV.map do |file|
8
+ if file == '-'
9
+ $stdin
10
+ else
11
+ File.open(file, 'rb')
12
+ end
13
+ end
14
+ fds = [$stdin] if fds.empty?
15
+
16
+ command = ENV['BCAT_COMMAND'] || 'open $BCAT_ARGS "$BCAT_URL"'
17
+
18
+ pid = nil
19
+ begin
20
+ bcat = Bcat.new(fds)
21
+ bcat.serve! do |sock|
22
+ pid =
23
+ fork do
24
+ (fds + [sock, $stdin, $stdout]).uniq.each { |fd| fd.close }
25
+ ENV['BCAT_URL'] = "http://#{bcat[:Host]}:#{bcat[:Port]}/#{File.basename(Dir.pwd)}"
26
+ ENV['BCAT_ARGS'] = "-a '#{ENV['BCAT_APPLICATION']}'" if !ENV['BCAT_APPLICATION'].to_s.empty?
27
+ exec "/bin/sh -c \"#{command}\""
28
+ end
29
+ end
30
+ rescue Interrupt
31
+ end
32
+
33
+ Process.wait(pid) if pid
34
+ exit $?
@@ -0,0 +1,69 @@
1
+ require 'rack'
2
+ require 'bcat/kidgloves'
3
+
4
+ class Bcat
5
+ VERSION = '0.0.0'
6
+ include Rack::Utils
7
+
8
+ def initialize(fds=[$stdin], config={})
9
+ @fds = fds
10
+ @config = {:Host => '127.0.0.1', :Port => 8091}.merge(config)
11
+ end
12
+
13
+ def [](key)
14
+ @config[key]
15
+ end
16
+
17
+ def call(env)
18
+ [200, {"Content-Type" => "text/html;charset=utf-8"}, self]
19
+ end
20
+
21
+ def head
22
+ ["<html>",
23
+ "<head><title>bcat</title></head>",
24
+ "<body><pre>"].join
25
+ end
26
+
27
+ def foot
28
+ "</pre></body></html>"
29
+ end
30
+
31
+ def each
32
+ yield "\n" * 1000
33
+ yield "<!DOCTYPE html>\n"
34
+ yield head
35
+
36
+ begin
37
+ @fds.each do |fd|
38
+ begin
39
+ while buf = fd.readpartial(4096)
40
+ output = escape_html(buf)
41
+ output = output.gsub(/\n/, "<br>")
42
+ yield "<script>document.write('#{output}');</script>"
43
+ end
44
+ rescue EOFError
45
+ ensure
46
+ fd.close rescue nil
47
+ end
48
+ end
49
+ end
50
+
51
+ yield foot
52
+ end
53
+
54
+ def close
55
+ raise Interrupt
56
+ end
57
+
58
+ def to_app
59
+ app = self
60
+ Rack::Builder.new do
61
+ use Rack::Chunked
62
+ run app
63
+ end
64
+ end
65
+
66
+ def serve!(&bk)
67
+ Rack::Handler::KidGloves.run to_app, @config, &bk
68
+ end
69
+ end
@@ -0,0 +1,149 @@
1
+ require 'socket'
2
+ require 'stringio'
3
+
4
+ module Rack
5
+ module Handler
6
+ class KidGloves
7
+ attr_accessor :app
8
+
9
+ StatusMessage = {
10
+ 100 => 'Continue',
11
+ 101 => 'Switching Protocols',
12
+ 200 => 'OK',
13
+ 201 => 'Created',
14
+ 202 => 'Accepted',
15
+ 203 => 'Non-Authoritative Information',
16
+ 204 => 'No Content',
17
+ 205 => 'Reset Content',
18
+ 206 => 'Partial Content',
19
+ 300 => 'Multiple Choices',
20
+ 301 => 'Moved Permanently',
21
+ 302 => 'Found',
22
+ 303 => 'See Other',
23
+ 304 => 'Not Modified',
24
+ 305 => 'Use Proxy',
25
+ 307 => 'Temporary Redirect',
26
+ 400 => 'Bad Request',
27
+ 401 => 'Unauthorized',
28
+ 402 => 'Payment Required',
29
+ 403 => 'Forbidden',
30
+ 404 => 'Not Found',
31
+ 405 => 'Method Not Allowed',
32
+ 406 => 'Not Acceptable',
33
+ 407 => 'Proxy Authentication Required',
34
+ 408 => 'Request Timeout',
35
+ 409 => 'Conflict',
36
+ 410 => 'Gone',
37
+ 411 => 'Length Required',
38
+ 412 => 'Precondition Failed',
39
+ 413 => 'Request Entity Too Large',
40
+ 414 => 'Request-URI Too Large',
41
+ 415 => 'Unsupported Media Type',
42
+ 416 => 'Request Range Not Satisfiable',
43
+ 417 => 'Expectation Failed',
44
+ 500 => 'Internal Server Error',
45
+ 501 => 'Not Implemented',
46
+ 502 => 'Bad Gateway',
47
+ 503 => 'Service Unavailable',
48
+ 504 => 'Gateway Timeout',
49
+ 505 => 'HTTP Version Not Supported'
50
+ }
51
+
52
+ def self.run(app, options={}, &block)
53
+ new(app, options).listen(&block)
54
+ end
55
+
56
+ def initialize(app, options={})
57
+ @app = app
58
+ @host = options[:Host] || '0.0.0.0'
59
+ @port = options[:Port] || 8089
60
+ end
61
+
62
+ def listen
63
+ log "Starting server on #{@host}:#{@port}"
64
+ server = TCPServer.new(@host, @port)
65
+
66
+ yield server if block_given?
67
+
68
+ loop do
69
+ socket = server.accept
70
+ socket.sync = true
71
+ log "#{socket.peeraddr[2]} (#{socket.peeraddr[3]})"
72
+ begin
73
+
74
+ req = {}
75
+
76
+ # parse the request line
77
+ request = socket.gets
78
+ method, path, version = request.split(" ")
79
+ req["REQUEST_METHOD"] = method
80
+ info, query = path.split("?")
81
+ req["PATH_INFO"] = info
82
+ req["QUERY_STRING"] = query
83
+
84
+ # parse the headers
85
+ while (line = socket.gets)
86
+ line.strip!
87
+ break if line.size == 0
88
+ key, val = line.split(": ")
89
+ key = key.upcase.gsub('-', '_')
90
+ key = "HTTP_#{key}" if !%w[CONTENT_TYPE CONTENT_LENGTH].include?(key)
91
+ req[key] = val
92
+ end
93
+
94
+ # parse the body
95
+ body = ''
96
+ if (len = req['CONTENT_LENGTH']) && ["POST", "PUT"].member?(method)
97
+ body = socket.read(len.to_i)
98
+ end
99
+
100
+ # process the request
101
+ process_request(req, body, socket)
102
+
103
+ ensure
104
+ socket.close if not socket.closed?
105
+ end
106
+ end
107
+ end
108
+
109
+ def log(message)
110
+ # $stderr.puts message
111
+ end
112
+
113
+ def status_message(code)
114
+ StatusMessage[code]
115
+ end
116
+
117
+ def process_request(request, input_body, socket)
118
+ env = {}.replace(request)
119
+ env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
120
+ env["QUERY_STRING"] ||= ""
121
+ env["SCRIPT_NAME"] = ""
122
+
123
+ rack_input = StringIO.new(input_body)
124
+ rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
125
+
126
+ env.update({"rack.version" => [1,0],
127
+ "rack.input" => rack_input,
128
+ "rack.errors" => $stderr,
129
+ "rack.multithread" => true,
130
+ "rack.multiprocess" => true,
131
+ "rack.run_once" => false,
132
+
133
+ "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
134
+ })
135
+ status, headers, body = app.call(env)
136
+ begin
137
+ socket.write("HTTP/1.1 #{status} #{status_message(status)}\r\n")
138
+ headers.each do |k, vs|
139
+ vs.split("\n").each { |v| socket.write("#{k}: #{v}\r\n")}
140
+ end
141
+ socket.write("\r\n")
142
+ body.each { |s| socket.write(s) }
143
+ ensure
144
+ body.close if body.respond_to? :close
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,27 @@
1
+ bcat(1) -- browser cat
2
+ ======================
3
+
4
+ ## SYNOPSIS
5
+
6
+ `bcat`<br>
7
+ `bcat` <file>... [-]<br>
8
+
9
+ ## DESCRIPTION
10
+
11
+ The `bcat` utility reads from standard input, or one or more <file>s, and writes
12
+ output to a web browser progressively. When <file> is '-'
13
+
14
+ ## ENVIRONMENT
15
+
16
+ * `BCAT_COMMAND`=`open -a $BCAT_APPLICATION $url`:
17
+ * `BCAT_COMMAND`=`xdg-open "$url"`:
18
+ The command used to launch to the browser application.
19
+
20
+ * `BCAT_APPLICATION`=[`Safari | Google Chrome | Firefox`]:
21
+ MacOS X only. The name of the Application . This is given as the value of
22
+ the `-a` argument to open(1). When `BCAT_APPLICATION` is undefined, the
23
+ system default browser is used.
24
+
25
+ ## SEE ALSO
26
+
27
+ cat(1), open(1)
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bcat
3
+ version: !ruby/object:Gem::Version
4
+ hash: 31
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 0
10
+ version: 0.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Ryan Tomayko
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-06-19 00:00:00 -07:00
19
+ default_executable: bcat
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rack
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: Concatenate input from standard input, or one or more files, and write progressive output to a browser.
36
+ email: rtomayko@gmail.com
37
+ executables:
38
+ - bcat
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - COPYING
43
+ files:
44
+ - Rakefile
45
+ - bcat.gemspec
46
+ - bin/bcat
47
+ - lib/bcat.rb
48
+ - lib/bcat/kidgloves.rb
49
+ - man/bcat.1.ronn
50
+ - COPYING
51
+ has_rdoc: true
52
+ homepage: http://github.com/rtomayko/bcat/
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --line-numbers
58
+ - --inline-source
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.3.7
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: browser cat
86
+ test_files: []
87
+