Permalink
Browse files

second stab, abstracted a bit further, so more flexibility and consis…

…tency now
  • Loading branch information...
1 parent 79db5a2 commit 62664247a570b86c21abe1c98aca01b5913a9e75 Sven Fuchs committed Dec 3, 2008
View
@@ -1,3 +1,4 @@
+require 'with/sharing'
require 'with/context'
require 'with/group'
require 'with/named_block'
@@ -6,17 +7,17 @@ module With
def self.included(base)
base.send :extend, ClassMethods
end
-
+
module ClassMethods
- include Dsl::Sharing
-
+ include Sharing
+
def inherited(base)
base.instance_variable_set(:@shared, @shared)
end
-
+
def describe(name, &block)
group = Group.new name, &block
- shared.each {|name, blocks| group.share(name, *blocks) }
+ shared.each {|name, contexts| group.share(name, *contexts) }
group.compile(self)
group
end
View
@@ -1,10 +1,7 @@
-require 'with/dsl'
-
module With
class Context
- include Dsl
-
- attr_reader :name
+ attr_accessor :parent
+ attr_reader :name, :children
def initialize(name, action, preconditions, assertions, &block)
@name, @action, @preconditions, @assertions = name, action, [], []
@@ -16,38 +13,64 @@ def initialize(name, action, preconditions, assertions, &block)
@assertions += assertions
end
- def leafs
- return self if children.empty?
- children.map { |child| child.leafs }.flatten
- end
-
def calls
[find_action, collect_preconditions, collect_assertions]
end
+ def parents
+ parent ? parent.parents + [parent] : []
+ end
+
+ def leafs
+ return [self] if children.empty?
+ children.map { |child| child.leafs }.flatten
+ end
+
def add_children(*children)
children.each do |child|
child.parent = self
@children << child
end
end
-
- def self_and_parents
- (parent ? parent.self_and_parents : []) + [self]
+
+ def append_children(children)
+ leafs.each { |leaf| leaf.add_children *children }
end
+ def compile(target)
+ leafs.each { |leaf| define_test_method(target, leaf) }
+ end
+
protected
def find_action
- @action || parent && parent.find_action || raise("could not find action")
+ @action || parent && parent.find_action
end
def collect_preconditions
- (parent ? parent.collect_preconditions : []) + preconditions
+ (parent ? parent.collect_preconditions : []) + @preconditions
end
def collect_assertions
- (parent ? parent.collect_assertions : []) + assertions
+ (parent ? parent.collect_assertions : []) + @assertions
+ end
+
+ def define_test_method(target, context)
+ action, preconditions, assertions = *context.calls
+ method_name = generate_test_method_name(context)
+
+ target.send :define_method, method_name, &lambda {
+ preconditions.map { |precondition| instance_eval &precondition }
+ instance_eval &action if action
+ assertions.map { |assertion| instance_eval &assertion }
+ }
+ end
+
+ def generate_test_method_name(context)
+ contexts = context.parents << context
+ name = "test_<#{context.object_id}>_#{contexts.shift.name}_"
+ name += contexts.map { |c| "with_#{c.name}" }.join('_and_')
+ name.gsub(/[\W ]/, '_').gsub('__', '_')
end
end
end
View
@@ -1,55 +0,0 @@
-module With
- module Dsl
- def self.included(base)
- base.send :include, Sharing
- end
-
- attr_accessor :parent
-
- def with(*names, &block)
- names << { :parent => self }
- Group.new(*names, &block)
- end
-
- def before(name = nil, &block)
- name ||= "before #{block.inspect}"
- preconditions << NamedBlock.new(name, &block)
- end
-
- def action(name = nil, &block)
- name ||= "action #{block.inspect}"
- @action = NamedBlock.new(name, &block)
- end
-
- def assertion(name = nil, options = {}, &block)
- group = options[:with] ? with(*options[:with]) : self
- group.assertions << NamedBlock.new(name, &block)
- end
- alias :it :assertion
-
- def children
- @children ||= []
- end
-
- def preconditions
- @preconditions ||= []
- end
-
- def assertions
- @assertions ||= []
- end
-
- module Sharing
- def share(*blocks, &block)
- name = blocks.shift
- blocks << block if block
- shared[name] ||= []
- shared[name] += blocks
- end
-
- def shared
- @shared ||= {}
- end
- end
- end
-end
View
@@ -1,57 +1,85 @@
-require 'with/dsl'
-
module With
class Group
- include Dsl
-
+ include Sharing
+
+ attr_accessor :parent
attr_reader :names
- def initialize(*args, &block)
- options = args.last.is_a?(Hash) ? args.pop : {}
- @parent = options[:parent]
- @parent.children << self if @parent
- @names = args
-
+ def initialize(*names, &block)
+ @names = names
instance_eval &block if block
end
- def compile(target)
- expand.first.leafs.each { |leaf| define_test_method(target, leaf) }
+ def with(*names, &block)
+ options = names.last.is_a?(Hash) ? names.pop : {}
+ group = options[:with] ? with(*options[:with]) : self
+ group.add_child(*names, &block)
+ end
+ alias :it :with
+
+ def assertion(name = nil, options = {}, &block)
+ assertions << NamedBlock.new(name, &block)
+ end
+
+ def before(name = nil, &block)
+ name ||= "before #{block.inspect}"
+ preconditions << NamedBlock.new(name, &block)
+ end
+
+ def action(name = nil, &block)
+ name ||= "action #{block.inspect}"
+ @action = NamedBlock.new(name, &block)
+ end
+
+ def children
+ @children ||= []
end
+ def preconditions
+ @preconditions ||= []
+ end
+
+ def assertions
+ @assertions ||= []
+ end
+
+ def compile(target)
+ expand.first.compile(target)
+ end
+
protected
def expand
names.map do |name|
- shared_blocks = find_shared(name) || [nil]
- shared_blocks.map do |shared|
- context = Context.new(name, @action, preconditions.dup, assertions.dup, &shared)
- children.each { |child| context.add_children *child.expand }
- context
+ contexts_for(name).each do |context|
+ context.append_children children.map{|c| c.expand }.flatten
end
end.flatten
end
+
+ def contexts_for(name)
+ if shared_contexts = find_shared(name)
+ shared_contexts.map{|c| c.expand }.flatten
+ else
+ [Context.new(name, @action, preconditions.dup, assertions.dup)]
+ end
+ end
def find_shared(name)
shared[name] || parent && parent.find_shared(name)
end
-
- def define_test_method(target, context)
- action, preconditions, assertions = *context.calls
- method_name = generate_test_method_name(context)
-
- target.send :define_method, method_name, &lambda {
- preconditions.map { |precondition| instance_eval &precondition }
- instance_eval &action
- assertions.map { |assertion| instance_eval &assertion }
- }
+
+ def add_child(*names, &block)
+ child = Group.new(*names, &block)
+ child.parent = self
+ children << child
+ child
end
-
- def generate_test_method_name(context)
- contexts = context.self_and_parents
- name = "test_<#{context.object_id}>_#{contexts.shift.name}_"
- name += contexts.map { |c| "with_#{c.name}" }.join('_and_')
- name.gsub(/[\W ]/, '_').gsub('__', '_')
+
+ def method_missing(name, *args, &block)
+ assertion name do
+ send name, *args, &block
+ end
end
end
end
View
@@ -10,5 +10,9 @@ def initialize(name, &block)
def to_proc
@block
end
+
+ def call
+ to_proc.call
+ end
end
end
View
@@ -0,0 +1,17 @@
+module With
+ module Sharing
+ def share(name, *shareds, &block)
+ shareds << block if block
+ shareds.each do |shared|
+ group = shared.is_a?(Group) ? shared : Group.new(name, &shared)
+
+ self.shared[name] ||= []
+ self.shared[name] << group
+ end
+ end
+
+ def shared
+ @shared ||= {}
+ end
+ end
+end
@@ -2,12 +2,12 @@
class TestUnitWithTest < Test::Unit::TestCase
include With
-
+
describe 'foo' do
action { :'called action!' }
with :'context 1', :'context 2' do
- it :'assertion 1', :with => :'context 3' do
+ it :'does something', :with => :'context 3' do
:'called assertion 1'
end
end
@@ -28,8 +28,8 @@ class TestUnitWithTest < Test::Unit::TestCase
@@tests_defined = instance_methods.grep(/^test_/).map{|name| name.gsub(/test_[\d]*/, 'test')}.sort
def test_with_defined_two_tests
- names = [ "test_foo_with_context_1_and_with_context_3",
- "test_foo_with_context_2_and_with_context_3" ]
+ names = [ "test_foo_with_context_1_and_with_context_3_and_with_does_something",
+ "test_foo_with_context_2_and_with_context_3_and_with_does_something" ]
assert_equal names, @@tests_defined
end
end
View
@@ -80,7 +80,8 @@ class ActionController::TestCase
before { @params = valid_article_params.except(:body) }
end
- def it_redirects_to(path)
+ def it_redirects_to(path = nil, &block)
+ path = instance_eval(&block) if block
assert_redirected_to path
end
@@ -94,9 +95,11 @@ def valid_article_params
end
# TODO figure out how to reduce this
-module With::Dsl
- def it_redirects_to(path)
- assertion { assert_redirected_to path }
+class With::Group
+ def it_redirects_to(path = nil, &block)
+ assertion do
+ it_redirects_to(path, &block)
+ end
end
end
@@ -108,7 +111,7 @@ class ArticlesControllerTest < ActionController::TestCase
with :login_as_admin do
it "succeeds", :with => :valid_article_params do
- it_redirects_to 'articles/1'
+ it_redirects_to { 'articles/1' }
end
it "fails", :with => :invalid_article_params do
@@ -117,7 +120,7 @@ class ArticlesControllerTest < ActionController::TestCase
end
with :login_as_user, :no_login do
- it_redirects_to '/login'
+ it_redirects_to { '/login' }
end
end
Oops, something went wrong.

0 comments on commit 6266424

Please sign in to comment.