Skip to content

Instantly share code, notes, and snippets.

@lucaspiller
Created April 29, 2010 15:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lucaspiller/383802 to your computer and use it in GitHub Desktop.
Save lucaspiller/383802 to your computer and use it in GitHub Desktop.
Play Spec - Making your specs fun!
#!/usr/bin/env ruby
#
# Play Spec v0.2.0
# Making your specs fun!
#
# 1) Download
# 2) Save as play_spec, somewhere in your path
# 3) chmod +x play_spec
# 4) Run it!
# play_spec spec/controllers/application_spec.rb
#
# History
#
# 0.2.0
# Tidyer points display after specs
# Lots of pretty colours
#
# 0.1.1
# Fix silly bugs
#
# 0.1.0
# Initial version
#
require 'yaml'
require 'open3'
require 'rubygems'
# load options
begin
$options = YAML::load_file(File.expand_path('~/.play_spec'))
rescue Errno::ENOENT
$options = nil
end
# doesn't exist yet
if $options.nil?
$options = {
:points => 0,
:name => ENV['USER']
}
end
def terminal_width
$term_width ||= %x{stty size}.split[1].to_i
end
$small_width = 40
def level
Math.sqrt($options[:points] < 1 ? 1 : ($options[:points] / 2)).to_i
end
def render_status_line
if defined? Term::ANSIColor
part_width = (terminal_width - 4) / 3
name_part = $options[:name].ljust(part_width)
points_part = ($options[:points].to_s + " point(s)").ljust(part_width)
level_part = ("level " + level.to_s).ljust(part_width)
print Term::ANSIColor.negative, Term::ANSIColor.bold, "\n"
print (" " + name_part + points_part + level_part + " ").ljust(terminal_width)
print "\n", Term::ANSIColor.reset
else
print "\n"
print $options[:name].ljust(20)
print ($options[:points].to_s + " point(s)").ljust(20)
print ("level " + level.to_s).ljust(20)
print "\n"
end
end
def alter_points(points, reason)
$options[:points] += points
if defined? Term::ANSIColor
part_width = terminal_width / 3
if points < 0
print Term::ANSIColor.bold, Term::ANSIColor.red, points.to_s.rjust(10), Term::ANSIColor.reset
else
print Term::ANSIColor.bold, Term::ANSIColor.green, (("+" + points.to_s).rjust(10)), Term::ANSIColor.reset
end
print Term::ANSIColor.bold, ' ' + reason, "\n", Term::ANSIColor.reset
else
if points < 0
print points.to_s.rjust(10)
else
print(("+" + points.to_s).rjust(10))
end
print ' ' + reason
print "\n"
end
end
# save options at exit
at_exit do
render_status_line
File.open(File.expand_path('~/.play_spec'), 'w') { |f| f.write(YAML::dump($options)) }
end
# catch ctrl c
Signal.trap('INT') { exit }
# check gems
begin
gem 'rspec'; require 'spec'
rescue Gem::LoadError
alter_points -10, "You need the `rspec' gem installed. n00b."
exit
end
begin
gem 'term-ansicolor'; require 'term/ansicolor'
rescue Gem::LoadError
alter_points -1, "You need the `term-ansicolor' gem installed."
exit
end
unless ARGV.size == 1
print "Err... Nothing to play with?\n\n"
print "usage: play_spec [options] file\n"
exit
end
file = ARGV[0]
unless File.exists?(file)
print "Err... Can't find `#{ARGV[0]}'?\n\n"
print "usage: play_spec [options] file\n"
exit
end
# sexy, its like being back in 1986!
print Term::ANSIColor.on_red, " "
print Term::ANSIColor.on_yellow, " "
print Term::ANSIColor.on_green, " "
print Term::ANSIColor.on_blue, " "
print "\n"
print Term::ANSIColor.on_red, " "
print Term::ANSIColor.on_yellow, " "
print Term::ANSIColor.on_green, " "
print Term::ANSIColor.on_blue, " "
print "\n"
print Term::ANSIColor.on_red, " "
print Term::ANSIColor.on_yellow, " "
print Term::ANSIColor.on_green, " "
print Term::ANSIColor.on_blue, " "
print Term::ANSIColor.reset, Term::ANSIColor.bold, " OK... Lets play spec!", Term::ANSIColor.reset
print "\n"
print Term::ANSIColor.on_red, " "
print Term::ANSIColor.on_yellow, " "
print Term::ANSIColor.on_green, " "
print Term::ANSIColor.on_blue, " "
print Term::ANSIColor.reset, " Copyright (C) 1986", Term::ANSIColor.reset
print "\n"
print Term::ANSIColor.on_red, " "
print Term::ANSIColor.on_yellow, " "
print Term::ANSIColor.on_green, " "
print Term::ANSIColor.on_blue, " "
print Term::ANSIColor.reset
print "\n"
round = 0
last_changed = 0
examples = nil
failures = nil
pending = nil
loop do
# check it exists
unless File.exists?(file)
print "Looks like that's it folks!"
exit
end
# any change?
if last_changed == 0 or File.mtime(file) > last_changed
old_examples = examples
old_failures = failures
old_pending = pending
last_changed = File.mtime(file)
print "\n", Term::ANSIColor.on_cyan, Term::ANSIColor.black, " Get ready for round #{round += 1}! ", Term::ANSIColor.reset, "\n"
# run the command
stdin, stdout, stderr = Open3.popen3("spec -fs --color #{file}")
loop do
out = stdout.gets
break if out.nil?
print out
if out =~ /([0-9]+) examples?, ([0-9]+) failures?(, ([0-9]+) pending)?/
examples = $1.to_i
failures = $2.to_i
pending = ($4 || 0).to_i
end
end
# points baby
if not old_failures.nil?
print "\n"
points = old_failures - failures
if old_failures > failures
alter_points points, "You fixed #{points} example(s), great job!"
elsif failures > old_failures
alter_points (points * 2), "You do know you are supposed to fix the specs?"
end
end
if failures == 0
print "\n", Term::ANSIColor.on_green, Term::ANSIColor.bold, Term::ANSIColor.blink
print " Looks like your work here is done! \n"
print Term::ANSIColor.reset
exit
end
render_status_line
else
sleep 1
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment