Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

delay requires to speed up startup time

  • Loading branch information...
commit 5e00981957c4b6f64b43f3d0aed357741971f680 1 parent 94d958d
@qrush authored
View
5 Rakefile
@@ -10,6 +10,11 @@ Rake::TestTask.new do |t|
t.pattern = 'test/*_test.rb'
end
+desc 'Run simple benchmarks'
+task :bench do
+ exec "ruby test/bench.rb"
+end
+
# ROCCO ===============================================================
require 'rdiscount'
View
129 lib/m.rb
@@ -77,30 +77,121 @@
#
#This gem is MIT licensed, please see `LICENSE` for more information.
-### M, setup and other top level fun
-#### Stdlib requires
-# Using delegators and open structs since I'm too lazy to make objects
-require "forwardable"
-require "ostruct"
-
-#### External requires
-# Instead of using rake/rake_test_loader and reduplicating logic there, just use `TestTask`.
-require "rake/testtask"
-# After trying several source parsing libraries, this is the only one that seems to work consistently.
-require "method_source"
-
-#### Internal requires
-require "m/runner"
-require "m/test_collection"
-require "m/test_method"
-
-#### Public interface
+### M, your metal test runner
# Maybe this gem should have a longer name? Metal?
module M
- VERSION = "0.0.1"
+ VERSION = "1.0.0"
# Accept arguments coming from bin/m and run tests.
def self.run(argv)
Runner.new(argv).run
end
+
+ ### Runner is in charge of running your tests.
+ # Instead of slamming all of this junk in an `M` class, it's here instead.
+ class Runner
+ def initialize(argv)
+ @argv = argv
+ end
+
+ # There's two steps to running our tests:
+ # 1. Parsing the given input for the tests we need to find (or groups of tests)
+ # 2. Run those tests we found that match what you wanted
+ def run
+ parse
+ execute
+ end
+
+ private
+
+ def parse
+ # With no arguments,
+ if @argv.empty?
+ # Just shell out to `rake test`.
+ exec "rake test"
+ else
+ # Parse out ARGV, it should be coming in in a format like `test/test_file.rb:9`
+ @file, line = @argv.first.split(':')
+ @line = line.to_i
+
+ # If this file is a directory, not a file, run the tests inside of this directory
+ if Dir.exist?(@file)
+ # Make a new rake test task with a hopefully unique name, and run every test looking file in it
+ require "rake/testtask"
+ Rake::TestTask.new(:m_custom) do |t|
+ t.libs << 'test'
+ t.pattern = "#{@file}/*test*.rb"
+ end
+ # Invoke the rake task and exit, hopefully it'll work!
+ Rake::Task['m_custom'].invoke
+ exit
+ end
+ end
+ end
+
+ def execute
+ # Locate tests to run that may be inside of this line. There could be more than one!
+ tests_to_run = tests.within(@line)
+
+ # If we found any tests,
+ if tests_to_run.size > 0
+ # assemble the regexp to run these tests,
+ test_names = tests_to_run.map(&:name).join('|')
+
+ # directly run the tests from here and exit with the status of the tests passing or failing
+ exit Test::Unit::AutoRunner.run(false, nil, ["-n", "/(#{test_names})/"])
+ else
+ # Otherwise we found no tests on this line, so you need to pick one.
+ message = "No tests found on line #{@line}. Valid tests to run:\n\n"
+
+ # For every test ordered by line number,
+ # spit out the test name and line number where it starts,
+ tests.by_line_number do |test|
+ message << "#{sprintf("%0#{tests.column_size}s", test.name)}: m #{@file}:#{test.start_line}\n"
+ end
+
+ # fail like a good unix process should.
+ abort message
+ end
+ end
+
+ # Finds all test suites in this test file, with test methods included.
+ def suites
+ # Since we're not using `ruby -Itest` to run the tests, we need to add this directory to the `LOAD_PATH`
+ $:.unshift "./test"
+
+ begin
+ # Fire up this Ruby file. Let's hope it actually has tests.
+ load @file
+ rescue LoadError => e
+ # Fail with a happier error message instead of spitting out a backtrace from this gem
+ abort "Failed loading test file:\n#{e.message}"
+ end
+
+ # Use some janky internal test/unit API to group test methods by test suite.
+ Test::Unit::TestCase.test_suites.inject({}) do |suites, suite_class|
+ # End up with a hash of suite class name to an array of test methods, so we can later find them and ignore empty test suites
+ suites[suite_class] = suite_class.test_methods if suite_class.test_methods.size > 0
+ suites
+ end
+ end
+
+ # Shoves tests together in our custom container and collection classes.
+ # Memoize it since it's unnecessary to do this more than one for a given file.
+ def tests
+ @tests ||= begin
+ require "m/test_collection"
+ require "m/test_method"
+ # With each suite and array of tests,
+ # and with each test method present in this test file,
+ # shove a new test method into this collection.
+ suites.inject(TestCollection.new) do |collection, (suite_class, test_methods)|
+ test_methods.each do |test_method|
+ collection << TestMethod.create(suite_class, test_method)
+ end
+ collection
+ end
+ end
+ end
+ end
end
View
103 lib/m/runner.rb
@@ -1,103 +0,0 @@
-module M
- ### Runner is in charge of running your tests.
- # Instead of slamming all of this junk in an `M` class, it's here instead.
- class Runner
- def initialize(argv)
- @argv = argv
- end
-
- def run
- parse
- execute
- end
-
- private
-
- def parse
- # With no arguments,
- if @argv.empty?
- # Just shell out to `rake test`.
- exec "rake test"
- else
- # Parse out ARGV, it should be coming in in a format like `test/test_file.rb:9`
- @file, line = @argv.first.split(':')
- @line = line.to_i
-
- # If this file is a directory, not a file, run the tests inside of this directory
- if Dir.exist?(@file)
- # Make a new rake task with a hopefully unique name, and run every test looking file in it
- Rake::TestTask.new(:m_custom) do |t|
- t.libs << 'test'
- t.pattern = "#{@file}/*test*.rb"
- end
- # Invoke the rake task and exit, hopefully it'll work!
- Rake::Task['m_custom'].invoke
- exit
- end
- end
- end
-
- def execute
- # Locate tests to run that may be inside of this line. There could be more than one!
- tests_to_run = tests.within(@line)
-
- # If we found any tests,
- if tests_to_run.size > 0
- # assemble the regexp to run these tests,
- test_names = tests_to_run.map(&:name).join('|')
-
- # directly run the tests from here and exit with the status of the tests passing or failing
- exit Test::Unit::AutoRunner.run(false, nil, ["-n", "/(#{test_names})/"])
- else
- # Otherwise we found no tests on this line, so you need to pick one.
- message = "No tests found on line #{@line}. Valid tests to run:\n\n"
-
- # For every test ordered by line number,
- # spit out the test name and line number where it starts,
- tests.by_line_number do |test|
- message << "#{sprintf("%0#{tests.column_size}s", test.name)}: m #{@file}:#{test.start_line}\n"
- end
-
- # fail like a good unix process should.
- abort message
- end
- end
-
- # Finds all test suites in this test file, with test methods included.
- def suites
- # Since we're not using `ruby -Itest` to run the tests, we need to add this directory to the `LOAD_PATH`
- $:.unshift "./test"
-
- begin
- # Fire up this Ruby file. Let's hope it actually has tests.
- load @file
- rescue LoadError => e
- # Fail with a happier error message instead of spitting out a backtrace from this gem
- abort "Failed loading test file:\n#{e.message}"
- end
-
- # Use some janky internal test/unit API to group test methods by test suite.
- Test::Unit::TestCase.test_suites.inject({}) do |suites, suite_class|
- # End up with a hash of suite class name to an array of test methods, so we can later find them and ignore empty test suites
- suites[suite_class] = suite_class.test_methods if suite_class.test_methods.size > 0
- suites
- end
- end
-
- # Shoves tests together in our custom container and collection classes.
- # Memoize it since it's unnecessary to do this more than one for a given file.
- def tests
- @tests ||= begin
- # With each suite and array of tests,
- # and with each test method present in this test file,
- # shove a new test method into this collection.
- suites.inject(TestCollection.new) do |collection, (suite_class, test_methods)|
- test_methods.each do |test_method|
- collection << TestMethod.create(suite_class, test_method)
- end
- collection
- end
- end
- end
- end
-end
View
2  lib/m/test_collection.rb
@@ -1,3 +1,5 @@
+require "forwardable"
+
module M
### Custom wrapper around an array of test methods
# In charge of some smart querying, filtering, sorting, etc on the the
View
3  lib/m/test_method.rb
@@ -1,3 +1,5 @@
+require "ostruct"
+
module M
### Simple data structure for what a test method contains.
#
@@ -22,6 +24,7 @@ def self.create(suite_class, test_method)
#
# The end line should be the number of line breaks in the method source,
# added to the starting line and subtracted by one.
+ require "method_source"
end_line = method.source.split("\n").size + start_line - 1
# Shove the given attributes into a new databag
View
10 test/bench.rb
@@ -0,0 +1,10 @@
+require 'benchmark'
+
+Benchmark.bmbm do |bench|
+ TIMES = 100
+ bench.report("running m on a file that doesn't exist, #{TIMES} times") do
+ TIMES.times do
+ `ruby -Ilib ./bin/m failwhale 2>/dev/null`
+ end
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.