Skip to content

Instantly share code, notes, and snippets.

@jeroenvandijk
Created May 3, 2010 20:16
Show Gist options
  • Save jeroenvandijk/388532 to your computer and use it in GitHub Desktop.
Save jeroenvandijk/388532 to your computer and use it in GitHub Desktop.
module Commander
class << self
attr_writer :commands
def commands
@commands ||= []
end
def add_command(constant_name, name, stack)
self.commands += [ Command.new(constant_name, name, stack) ]
end
def find(command_name)
@commands.detect { |command| command.name == command_name }
end
def run
if ARGV.empty?
puts "Usage: commandline command1 arg1 arg2"
else
command_name, *command_args = *ARGV
command = find(command_name)
raise "No such command found: #{command_name}" unless command
command.call(*command_args)
end
end
end
class Command
attr_accessor :name,
:arguments, :options, :arity, :comment,
:filename, :line, :constant_name
def initialize(constant_name, method_name, stack)
@constant_name, @name = constant_name, method_name
@filename, @line = extract_file_and_lineno(stack)
end
# Command.instance_eval { @file_cache = { "file" => %w( - #a #b #c ) }}
# c = Command.new("Dummy", "dummy", []).tap { |c| c.filename = "file"; c.line = 10 }
# c.comment.should == "a\n\b\nc"
def comment
last_line = @line - 1
first_line = last_line
first_line -= 1 while first_line >= 1 && file_line(first_line - 1) =~ /\#/
file_line(first_line..last_line).map do |line|
line.sub(/\s*\#/, '')
end.join
end
def call(*args)
mod = Module.const_get(constant_name)
Object.new.send(:extend, mod).send(name, *args)
end
def arguments
@arguments ||= extract_arguments
end
def extract_arguments
def_line = file_line @line
arguments_regex = /\w+,\s*(?:\w+)/
def_line.scan /def(?:\(#{arguments_regex}\)| #{arguments_regex})/
end
private
def extract_file_and_lineno(stack)
parse_stack_line(stack.first)
end
def parse_stack_line(where)
if where =~ /^(.*):(\d+)/
[ $1, Integer($2) ]
end
end
def file_cache
self.class.file_cache(@filename)
end
def file_line(num_or_range)
if num_or_range.is_a?(Range)
file_cache[(num_or_range.first - 1)..(num_or_range.last - 1)]
else
file_cache[num_or_range - 1]
end
end
def self.file_cache(filename)
@file_cache ||= {}
@file_cache[filename] ||= File.readlines(filename)
end
end
end
require "rubygems"
require "bundler"
Bundler.setup
require 'test/unit'
class InlineTest < Test::Unit::TestCase
end
require 'commander'
class Module
def method_added(method_name)
unless method_name.to_s =~ /method_added$/
constant_name = self.name
Commander.add_command(constant_name, method_name.to_s, caller)
end
end
end
Feature: Inline tests
In order to stimulate testing
As a programmer
I want to write tests where it happens
@announce
Scenario: testing simple method with TestUnit
Given this gem is installed
Given a file named "util.rb" with:
"""
module Util
# def test_hello
# assert(Object.new.extend(Util).hello("jeroen"), "hello jeroen")
# end
def hello(name)
"hello #{name}"
end
end
"""
When I run "inliner util.rb"
Then I should see:
"""
Loaded suite inliner
Started
.
Finished in 0.00037 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
"""
#!/usr/bin/env ruby
$:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
require 'inline_tests'
require File.expand_path(ARGV[0])
Commander.commands.each do |command|
InlineTest.class_eval(command.comment, command.filename, command.line )
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment