Skip to content

Commit

Permalink
Lolcat second edition.
Browse files Browse the repository at this point in the history
* Doesn't add color when stdout is not a tty (Fixes #6)
* Strips color from stdin before adding its own (Fixes #5)
* Now supports animation and fancy config switches
* Error messages imitate what 'cat' would say
  • Loading branch information
m-o-e committed Aug 11, 2011
1 parent 610314e commit 6baa540
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 48 deletions.
130 changes: 100 additions & 30 deletions lib/lolcat/cat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,43 +19,113 @@
require "lolcat/version"
require "lolcat/lol"

require 'optparse'
require 'stringio'
require 'trollop'

module Lol
def self.halp!(text, opts={})
opts = {
:animate => false,
:duration => 12,
:os => 0,
:speed => 20,
:spread => 8.0,
:freq => 0.3
}.merge opts

begin
i = 20
o = rand(256)
text.split("\n").each do |line|
i -= 1
opts[:os] = o+i
Lol.println line, opts
end
puts "\n"
rescue Interrupt
end
exit 1
end

def self.cat!
if ['-h','--help','--halp','--version'].include? ARGV[0]
p = Trollop::Parser.new do
banner <<HEADER
Usage: lolcat [OPTION]... [FILE]...
Concatenate FILE(s), or standard input, to standard output.
With no FILE, or when FILE is -, read standard input.
HEADER
banner ''
opt :spread, "Rainbow spread", :short => 'p', :default => 8.0
opt :seed, "Rainbow seed, 0 = random", :short => 'S', :default => 0
opt :animate, "Enable psychedelics", :short => 'a', :default => false
opt :duration, "Animation duration", :short => 'd', :default => 12
opt :speed, "Animation speed", :short => 's', :default => 20.0
opt :force, "Force color even when stdout is not a tty", :short => 'f', :default => false
opt :version, "Print version and exit", :short => 'v'
opt :help, "Show this message", :short => 'h'
banner <<FOOTER
Examples:
lolcat f - g Output f's contents, then standard input, then g's contents.
lolcat Copy standard input to standard output.
fortune | lolcat Display a rainbow cookie.
Report lolcat bugs to <http://www.github.org/busyloop/lolcat/issues>
lolcat home page: <http://www.github.org/busyloop/lolcat/>
Report lolcat translation bugs to <http://speaklolcat.com/>
For complete documentation, read the source!
FOOTER
end

opts = Trollop::with_standard_exception_handling p do
begin
puts
Lol.whut "Usage: lolcat [[file] [[file] [[file] [[file] [file]]]] [...]]", 20
puts
Lol.whut "Concatenate FILE(s), or standard input, to standard output.", 19
Lol.whut "With no FILE, or when FILE is -, read standard input.", 18
puts
Lol.whut " -h, --help, --halp, --version display this help and exit", 17

puts
Lol.whut "Examples:"
Lol.whut " lolcat f - g Output f's contents, then standard input, then g's contents.", 16
Lol.whut " lolcat Copy standard input to standard output.", 15
Lol.whut " fortune | lolcat Display a rainbow cookie.", 14

puts
Lol.whut "Report lolcat bugs to <http://www.github.org/busyloop/lolcat/issues>", 13
Lol.whut "lolcat home page: <http://www.github.org/busyloop/lolcat/>", 12
Lol.whut "Report lolcat translation bugs to <http://speaklolcat.com/>", 11
Lol.whut "For complete documentation, read the source!", 10
puts
rescue Interrupt
o = p.parse ARGV
rescue Trollop::HelpNeeded
buf = StringIO.new
p.educate buf
buf.rewind
halp! buf.read, {}
buf.close
end
exit 1
o
end


p.die :spread, "must be > 0" if opts[:spread] < 0.1
p.die :duration, "must be > 0" if opts[:duration] < 0.1
p.die :speed, "must be > 0.1" if opts[:duration] < 0.1

opts = { :freq => 0.3 }.merge(opts)
opts[:os] = opts[:seed]
opts[:os] = rand(256) if opts[:os] == 0

begin
fds = ARGV.empty? ? [ARGF] : ARGV[0..-1]
fds.each do |file|
file = ARGF if file == '-'
file = File.open file unless file == ARGF
Lol.cat file,8
files = ARGV.empty? ? [:stdin] : ARGV[0..-1]
files.each do |file|
fd = ARGF if file == '-' or file == :stdin
begin
fd = File.open file unless fd == ARGF

if $stdout.tty? or opts[:force]
Lol.cat fd, opts
else
until fd.eof? do
$stdout.write(fd.read(8192))
end
end
rescue Errno::ENOENT
puts "lolcat: #{file}: No such file or directory"
exit 1
rescue Errno::EACCES
puts "lolcat: #{file}: Permission denied"
exit 1
rescue Errno::EISDIR
puts "lolcat: #{file}: Is a directory"
exit 1
end
end
rescue Interrupt
end
Expand Down
44 changes: 27 additions & 17 deletions lib/lolcat/lol.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,49 @@
# 0. You just DO WHAT THE FUCK YOU WANT TO.

require "lolcat/version"

require 'paint'

module Lol
STRIP_ANSI = Regexp.compile '\e\[(\d+)(;\d+)?(;\d+)?[m|K]', nil

def self.rainbow(freq, i)
red = Math.sin(freq*i + 0) * 127 + 128
green = Math.sin(freq*i + 2*Math::PI/3) * 127 + 128
blue = Math.sin(freq*i + 4*Math::PI/3) * 127 + 128
"#%02X%02X%02X" % [ red, green, blue ]
end

def self.whut(text, duration=12, delay=0.05, spread=8)
(1..duration).each do |i|
print "\e[#{text.length}D"
text.chars.each_with_index do |c,j|
print Paint[c, rainbow(0.3, i+j/spread)]
end
sleep delay
def self.cat(fd, opts={})
fd.each do |line|
opts[:os] += 1
println(line, opts)
end
end

def self.println(str, defaults={}, opts={})
opts.merge!(defaults)
str.chomp!
str.gsub! STRIP_ANSI, '' if !str.nil? and ($stdout.tty? or opts[:force])
opts[:animate] ? println_ani(str, opts) : println_plain(str, opts)
puts
end

def self.lput(str, offset, spread)
print Paint[str, rainbow(0.3, offset/spread)]
private

def self.println_plain(str, defaults={}, opts={})
opts.merge!(defaults)
str.chomp.chars.each_with_index do |c,i|
print Paint[c, rainbow(opts[:freq], opts[:os]+i/opts[:spread])]
end
end

def self.cat(fd, spread)
i=0
fd.each do |line|
line.chars.each_with_index do |c,j|
lput c, i+j, spread
end
i+=1
def self.println_ani(str, opts={})
return if str.empty?
(1..opts[:duration]).each do |i|
print "\e[#{str.length}D"
opts[:os] += opts[:spread]/Math::PI
println_plain(str, opts)
sleep 1.0/opts[:speed]
end
end
end
2 changes: 1 addition & 1 deletion lib/lolcat/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Lolcat
VERSION = "42.0.21"
VERSION = "42.0.42"
end
1 change: 1 addition & 0 deletions lolcat.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Gem::Specification.new do |s|

#s.rubyforge_project = "lolcat"
s.add_dependency "paint", "~> 0.8.3"
s.add_dependency "trollop", "~> 1.16.2"

s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
Expand Down

0 comments on commit 6baa540

Please sign in to comment.