exemplar 0.1.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/.gitignore +6 -0
- data/Gemfile +6 -0
- data/README.rdoc +7 -0
- data/Rakefile +27 -0
- data/VERSION.yml +5 -0
- data/examples/algebra.rb +28 -0
- data/exemplar.gemspec +55 -0
- data/lib/exemplar.rb +3 -0
- data/lib/exemplar/example.rb +58 -0
- data/lib/exemplar/loggable.rb +17 -0
- data/lib/exemplar/runner.rb +45 -0
- data/test/example_test.rb +54 -0
- data/test/runner_test.rb +31 -0
- data/test/test_helper.rb +43 -0
- metadata +80 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'jeweler'
|
5
|
+
Jeweler::Tasks.new do |gem|
|
6
|
+
gem.name = "exemplar"
|
7
|
+
|
8
|
+
gem.summary = "Makes writing examples easy and fun"
|
9
|
+
|
10
|
+
gem.email = "ratnikov@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/ratnikov/exemplar"
|
12
|
+
gem.authors = [ "Dmitry Ratnikov" ]
|
13
|
+
end
|
14
|
+
|
15
|
+
Jeweler::GemcutterTasks.new
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
Rake::TestTask.new(:test) do |test|
|
21
|
+
test.test_files = FileList["test/**/*_test.rb"]
|
22
|
+
test.libs << 'test'
|
23
|
+
test.verbose = false
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Run the test suite"
|
27
|
+
task :default => :test
|
data/VERSION.yml
ADDED
data/examples/algebra.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'exemplar'
|
2
|
+
|
3
|
+
class Exemplar::Example
|
4
|
+
# <tt>Exemplar::Example</tt> invoked <tt>rescue_error</tt> when it encounters an error during
|
5
|
+
# execution of an example. While the default implementation is logging a simple error message,
|
6
|
+
# it's possible to change that behavior by providing a handler of our own:
|
7
|
+
def rescue_error(error)
|
8
|
+
case error
|
9
|
+
when ZeroDivisionError then log("Tried to divide by a zero. Bah!")
|
10
|
+
when ArgumentError then log("Whoops, bad argument!")
|
11
|
+
else
|
12
|
+
log("Unknown error: %s" % error.inspect)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
example "adding two numbers together" do
|
18
|
+
puts "1 + 5 = %s" % (1 + 5)
|
19
|
+
end
|
20
|
+
|
21
|
+
example "subtracting a number" do
|
22
|
+
puts "5 - 1 = %s" % (5 - 1 )
|
23
|
+
end
|
24
|
+
|
25
|
+
example "error catching" do
|
26
|
+
# this should be caught by our custom error rescuer
|
27
|
+
puts "5 / 0 = %s" % (5 / 0)
|
28
|
+
end
|
data/exemplar.gemspec
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{exemplar}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Dmitry Ratnikov"]
|
12
|
+
s.date = %q{2010-08-16}
|
13
|
+
s.email = %q{ratnikov@gmail.com}
|
14
|
+
s.extra_rdoc_files = [
|
15
|
+
"README.rdoc"
|
16
|
+
]
|
17
|
+
s.files = [
|
18
|
+
".gitignore",
|
19
|
+
"Gemfile",
|
20
|
+
"README.rdoc",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION.yml",
|
23
|
+
"examples/algebra.rb",
|
24
|
+
"exemplar.gemspec",
|
25
|
+
"lib/exemplar.rb",
|
26
|
+
"lib/exemplar/example.rb",
|
27
|
+
"lib/exemplar/loggable.rb",
|
28
|
+
"lib/exemplar/runner.rb",
|
29
|
+
"test/example_test.rb",
|
30
|
+
"test/runner_test.rb",
|
31
|
+
"test/test_helper.rb"
|
32
|
+
]
|
33
|
+
s.homepage = %q{http://github.com/ratnikov/exemplar}
|
34
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
35
|
+
s.require_paths = ["lib"]
|
36
|
+
s.rubygems_version = %q{1.3.7}
|
37
|
+
s.summary = %q{Makes writing examples easy and fun}
|
38
|
+
s.test_files = [
|
39
|
+
"test/example_test.rb",
|
40
|
+
"test/runner_test.rb",
|
41
|
+
"test/test_helper.rb",
|
42
|
+
"examples/algebra.rb"
|
43
|
+
]
|
44
|
+
|
45
|
+
if s.respond_to? :specification_version then
|
46
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
47
|
+
s.specification_version = 3
|
48
|
+
|
49
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
|
+
else
|
51
|
+
end
|
52
|
+
else
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
data/lib/exemplar.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module Exemplar
|
2
|
+
class Example
|
3
|
+
include Loggable
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def before_callbacks
|
7
|
+
@before_callbacks ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def before(*before_methods)
|
11
|
+
before_callbacks.push *before_methods
|
12
|
+
end
|
13
|
+
|
14
|
+
def examples
|
15
|
+
@examples ||= []
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :name, :options, :block
|
20
|
+
|
21
|
+
def initialize(name, options, block)
|
22
|
+
@name, @options, @block = name, options, block
|
23
|
+
|
24
|
+
self.class.examples << self
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
log "Running example #{name}..."
|
29
|
+
|
30
|
+
block_return = run_before_callbacks && block.call(self)
|
31
|
+
|
32
|
+
log "Done running example #{name}"
|
33
|
+
|
34
|
+
block_return
|
35
|
+
rescue Exception => error
|
36
|
+
rescue_error(error)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def rescue_error(error)
|
42
|
+
log "Whoops, seems like something went wrong. Here's the error message: %s." % error.message
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def run_before_callbacks
|
47
|
+
self.class.before_callbacks.all? { |callback| send(callback) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def runner
|
51
|
+
Exemplar::Runner
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def example(name, options = nil, &block)
|
57
|
+
Exemplar::Example.new(name, options, block)
|
58
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Exemplar
|
4
|
+
class Runner
|
5
|
+
attr_reader :examples
|
6
|
+
|
7
|
+
def initialize(examples, options = nil)
|
8
|
+
@examples = examples
|
9
|
+
@match_regex = options && options[:match]
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
examples.select { |example| run?(example) }.each { |example| example.run }
|
14
|
+
end
|
15
|
+
|
16
|
+
def run?(example)
|
17
|
+
@match_regex.nil? || example.name =~ @match_regex
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.parse_options!(argv)
|
21
|
+
options = {}
|
22
|
+
|
23
|
+
OptionParser.new do |opt|
|
24
|
+
opt.banner = "Exemplar automatic example runner.\n"
|
25
|
+
opt.banner << "Usage: #{$0} [options]"
|
26
|
+
|
27
|
+
opt.on
|
28
|
+
opt.on("-e", "--example [REGEX]", "Run examples matching the regex.") do |regex|
|
29
|
+
options[:match] = Regexp.new(regex)
|
30
|
+
end
|
31
|
+
|
32
|
+
opt.on_tail
|
33
|
+
end.parse!(argv)
|
34
|
+
|
35
|
+
options
|
36
|
+
rescue OptionParser::ParseError => e
|
37
|
+
puts "%s. Run `#{$0} --help` for help." % e
|
38
|
+
exit false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Kernel.at_exit do
|
44
|
+
Exemplar::Runner.new(Exemplar::Example.examples, Exemplar::Runner.parse_options!(ARGV)).run
|
45
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Exemplar
|
4
|
+
class ExampleTest < Test::Unit::TestCase
|
5
|
+
def test_declaring_example
|
6
|
+
test_example = example("test example", :foo => 'bar') { }
|
7
|
+
|
8
|
+
assert_equal 'test example', test_example.name
|
9
|
+
assert_equal({ :foo => 'bar' }, test_example.options)
|
10
|
+
|
11
|
+
assert_equal [ test_example ], Example.examples, "Should register the example with the runner"
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_running_example
|
15
|
+
test_example = example("test example") { |example| self.invoke_something(example); :block_return }
|
16
|
+
|
17
|
+
mock( self ).invoke_something(test_example)
|
18
|
+
|
19
|
+
assert_equal :block_return, test_example.run, "Should run the example block and return whatever it returns"
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_before_callback
|
23
|
+
Example.before :do_foo
|
24
|
+
|
25
|
+
assert_equal [ :do_foo ], Example.before_callbacks, "Should register a callback"
|
26
|
+
|
27
|
+
example = example("test example") { :block_return }
|
28
|
+
|
29
|
+
mock( example ).do_foo.returns true
|
30
|
+
|
31
|
+
assert_equal :block_return, example.run
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_before_callback_cancellation
|
35
|
+
Example.before :false_callback
|
36
|
+
|
37
|
+
example = example("test example") { flunk("Wasn't supposed to be run") }
|
38
|
+
|
39
|
+
mock( example ).false_callback.returns false
|
40
|
+
|
41
|
+
assert_equal false, example.run, "Should return that example failed to run"
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_exception_handling
|
45
|
+
error = Exception.new "bad error"
|
46
|
+
|
47
|
+
example = example("erroring example") { raise error }
|
48
|
+
|
49
|
+
mock( example ).rescue_error(error).returns :rescue_return
|
50
|
+
|
51
|
+
assert_equal :rescue_return, example.run, "should return whatever rescue returned"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/test/runner_test.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Exemplar
|
4
|
+
class RunnerTest < Test::Unit::TestCase
|
5
|
+
def test_examples_running
|
6
|
+
run_examples = []
|
7
|
+
|
8
|
+
example1 = example("first test example") { |e| run_examples << e }
|
9
|
+
example2 = example("second test example") { |e| run_examples << e }
|
10
|
+
|
11
|
+
Runner.new([ example1, example2 ]).run
|
12
|
+
|
13
|
+
assert_equal [ example1, example2 ], run_examples, "Should run the examples in order declared"
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_example_regex
|
17
|
+
foo = example("a foo example") { }
|
18
|
+
bar = example("a bar example") { }
|
19
|
+
|
20
|
+
# should run foo, but not run bar
|
21
|
+
mock( foo ).run.once
|
22
|
+
mock( bar ).run.never
|
23
|
+
|
24
|
+
Runner.new([ foo, bar], { :match => /foo/ }).run
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_parse_options!
|
28
|
+
assert_equal({ :match => /foo bar/ }, Runner.parse_options!([ '-e', 'foo bar' ]))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
begin
|
3
|
+
require 'bundler'
|
4
|
+
|
5
|
+
Bundler.setup
|
6
|
+
rescue LoadError => error
|
7
|
+
warn "Bundler doesn't seem to be installed. Please install bundler and run: bundle install"
|
8
|
+
exit
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'test/unit'
|
12
|
+
require 'rr'
|
13
|
+
|
14
|
+
require 'exemplar'
|
15
|
+
|
16
|
+
# disable the logging for the tests
|
17
|
+
Exemplar::Loggable.log = false
|
18
|
+
|
19
|
+
class << Exemplar::Runner
|
20
|
+
|
21
|
+
# stub out the option parsing to make sure it doesn't conflict with test/unit options
|
22
|
+
# Yea, it's ugly... :(
|
23
|
+
alias_method :default_parse_options!, :parse_options!
|
24
|
+
def parse_options!(args)
|
25
|
+
args == ARGV ? { } : default_parse_options!(args)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Test::Unit::TestCase
|
30
|
+
include RR::Adapters::TestUnit
|
31
|
+
|
32
|
+
setup
|
33
|
+
def setup_examples
|
34
|
+
# make sure there aren't any lingering examples declared
|
35
|
+
Exemplar::Example.examples.clear
|
36
|
+
end
|
37
|
+
|
38
|
+
teardown
|
39
|
+
def teardown_callbacks
|
40
|
+
# clear the callbacks to avoid future test breakage
|
41
|
+
Exemplar::Example.before_callbacks.clear
|
42
|
+
end
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: exemplar
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Dmitry Ratnikov
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-08-16 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description:
|
22
|
+
email: ratnikov@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README.rdoc
|
29
|
+
files:
|
30
|
+
- .gitignore
|
31
|
+
- Gemfile
|
32
|
+
- README.rdoc
|
33
|
+
- Rakefile
|
34
|
+
- VERSION.yml
|
35
|
+
- examples/algebra.rb
|
36
|
+
- exemplar.gemspec
|
37
|
+
- lib/exemplar.rb
|
38
|
+
- lib/exemplar/example.rb
|
39
|
+
- lib/exemplar/loggable.rb
|
40
|
+
- lib/exemplar/runner.rb
|
41
|
+
- test/example_test.rb
|
42
|
+
- test/runner_test.rb
|
43
|
+
- test/test_helper.rb
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://github.com/ratnikov/exemplar
|
46
|
+
licenses: []
|
47
|
+
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options:
|
50
|
+
- --charset=UTF-8
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 1.3.7
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: Makes writing examples easy and fun
|
76
|
+
test_files:
|
77
|
+
- test/example_test.rb
|
78
|
+
- test/runner_test.rb
|
79
|
+
- test/test_helper.rb
|
80
|
+
- examples/algebra.rb
|