On Nov 6, 2008, at 8:01 AM, David Chelimsky wrote:
I've really moved away from shared example groups and started writing
more targeted macros. So I might do something like this:
def for_roles *roles
roles.each do |role|
before(:each) { login_as role }
yield
end
end
describe OrdersController do
describe "GET index" do
for_roles :admin, :sysadmin do |role|
it "..." do ... end
end
for_roles :sysadmin do |role|
it "..." do ... end
end
end
I was attempting to follow this example and discovered that
before(scope, &block) is an alias for append_before which, as the
method name indicates, appends the before block to the existing
collection of before blocks.
So, in your example code above it seems that login_as would get called
for each role passed to for_roles before each example is executed.
Since the before blocks are stored internally as an array, the last
element of the array would win.
Another example:
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
def for_roles *roles
roles.each do |role|
before(:each) do
puts role.to_s
end
yield
end
end
describe "DRY roles test" do
describe "GET index" do
for_roles :admin, :sysadmin do |role|
it "..." do
puts 'in example'
end
end
end
end
Running this sample spec from the command line generates this output:
admin
sysadmin
in example
.admin
sysadmin
in example
.
I noticed that there is a method called 'remove_after' in
before_and_after_hooks.rb but no corresponding remove_before. Looking
at the code:
def remove_after(scope, &block)
after_each_parts.delete(block)
end
I noticed that this method doesn't use the scope parameter at all and
just attempts to delete the block from after_each_parts. So, I
modified the method to honor the scope parameter and wrote a
corresponding remove_before method:
def remove_after(scope, &block)
parts = after_parts_from_scope(scope)
parts.delete(block)
end
def remove_before(scope, &block)
parts = before_parts_from_scope(scope)
parts.delete(block)
end
However, this doesn't work as expected because if you do something like:
before(:each) { login_as role }
remove_before(:each) { login_as role }
two different Proc objects are created by each method call so
parts.delete(block) will always fail. The only way I could see around
this was if there were versions of append_before and remove_before
which took a Proc object as a parameter instead of converting the
block so you could maintain a reference to it in the calling code, i.e.
def append_before_proc(*args, block)
scope, options = scope_and_options(*args)
parts = before_parts_from_scope(scope)
parts << block
end
def remove_before_proc(scope, block)
parts = before_parts_from_scope(scope)
parts.delete(block)
end
my_block = Proc.new { login_as role }
append_before_proc(:each, my_block)
remove_before_proc(:each, my_block)
Which seems like a lot of monkey patching to get this working. So now
(finally) my questions:
1) Is there a better way to do this?
2) The current version of remove_after seems broken. Should I report
this as a bug?
Thanks,
-Jesse
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users