Passing a method as a paramter

I’m probably missing some basic Ruby syntax, but I’m relatively new to
Ruby and can’t figure this out from the various references I’ve looked
at

I’d like to use this nifty test helper:

Calls creation_method with nil values for field_names and asserts

that

the resulting object was not saved and that errors were added for

that field.

assert_required_fields :create_article, :subject, :body, :author

def assert_required_fields(creation_method, *field_names)
field_names.each do |field|
record = send(creation_method, field => nil)
assert_equal false, record.valid?
assert_not_nil record.errors.on(field)
end
end

However, I don’t know how to pass the creation method. My basic test
would be:

def test_should_create_user
user = User.create(:email => “[email protected]”, :lastname => “jones”,
:password => “secret”);
assert user.valid?, “User was invalid:\n#{user.to_yaml}”
end

I tried this for the failure case…
def test_should_not_create_user_unless_default_fields
assert_required_fields User::create, :email, :lastname, :password
end

But that reports an error:

  1. Error:
    test_should_not_create_user_unless_default_fields(UserTest):
    TypeError: #<User uuid: nil, firstname: nil, lastname: nil, login: nil,
    email: nil, …> is not a symbol

Can someone advise me of the correct syntax?

Thanks,
Sarah

assert_required_fields User::create, :email, :lastname, :password

Instead of User::create, which doesn’t return the method as it would
in some other languages but calls it right away, you could use either
one of:

User.method(:create)
lambda {|*args| User.create(*args)}

HTH

Hi Leo,

This gave me the same error:
assert_required_fields User.method(:create), :email, :lastname,
:password

I got a different error with this:
assert_required_fields {|*args| User.create(*args)}, :email, :lastname,
:password

test/unit/user_test.rb:15: syntax error, unexpected ‘,’, expecting kEND
assert_required_fields {|*args| User.create(*args)}, :email,
:lastname, :password

Am I missing something?

Thanks,
Sarah

Wow. Awesome run through of various Ruby syntax options – I think I’ll
print that out and hang it on my wall. Oddly none of those match the
original definition which uses send but has just a single
“creation_method” parameter…

 #  assert_required_fields :create_article, :subject, :body, :author
 def assert_required_fields(creation_method, *field_names)
  field_names.each do |field|
   record = send(creation_method, field => nil)
   assert_equal false, record.valid?
   assert_not_nil record.errors.on(field)
  end
 end

Any thoughts on how that could be called?

Thanks,
Sarah

On Mon, Mar 2, 2009 at 7:44 PM, Sarah A. [email protected]
wrote:

   assert_not_nil record.errors.on(field)
  end
 end

Any thoughts on how that could be called?

It’s the second example, you cannot obtain an instance of Method like
you would do in Python or JavaScript by simply omitting the
parenthesis, you have to use the Object#method method.

All of these are equivalent:

User.create
User.create()
User.method(:create).call
User.send(:create)

^ manveru

On Mon, Mar 2, 2009 at 6:49 PM, Sarah A. [email protected]
wrote:

 #
 #  assert_required_fields :create_article, :subject, :body, :author
 def assert_required_fields(creation_method, *field_names)
  field_names.each do |field|
   record = send(creation_method, field => nil)
   assert_equal false, record.valid?
   assert_not_nil record.errors.on(field)
  end
 end

Using blocks:

def assert_required_fields(*field_names, &block)
field_names.each do |field_name|
record = yield(field_name => nil)
assert_equal(false, record.valid?)
assert_not_nil(record.errors.on(field)
end
end

Usage:

assert_required_fields(:email, :lastname, :password){|field|
User::create(field) }

Using the method itself

def assert_required_fields(method, *field_names)
field_names.each do |field_name|
record = method.call(field_name => nil)
assert_equal(false, record.valid?)
assert_not_nil(record.errors.on(field)
end
end

Usage

assert_required_fields(User.method(:create), :email, :lastname,
:password)

Using send

def assert_required_fields(obj, method, *field_names)
field_names.each do |field_name|
record = obj.send(method, field_name => nil)
assert_equal(false, record.valid?)
assert_not_nil(record.errors.on(field)
end
end

Usage

assert_required_fields(User, :create, :email, :lastname, :password)

^ manveru

On Tue, Mar 3, 2009 at 12:16 AM, Sarah A. [email protected]
wrote:

you would do in Python or JavaScript by simply omitting the

I get the error: (ActiveRecord::Base).create> is not a symbol
calling:
 assert_required_fields User.method(:create), :create, :email,
:lastname, :password

Sorry, with rails all bets on normally behaving ruby code are off.

^ manveru

Michael F. wrote:

On Mon, Mar 2, 2009 at 7:44 PM, Sarah A. [email protected]
wrote:

   assert_not_nil record.errors.on(field)
  end
 end

Any thoughts on how that could be called?

It’s the second example, you cannot obtain an instance of Method like
you would do in Python or JavaScript by simply omitting the
parenthesis, you have to use the Object#method method.

All of these are equivalent:

User.create
User.create()
User.method(:create).call
User.send(:create)

^ manveru

I get the error: (ActiveRecord::Base).create> is not a symbol
calling:
assert_required_fields User.method(:create), :create, :email,
:lastname, :password

the code in my library uses send, not call

Of course, I could just change the definition of assert_required_fields,
but since it is part of a plugin
(http://topfunky.net/svn/plugins/topfunky_power_tools/lib/topfunky/test_helper.rb
), I figure there must be some standard way to call it

Thanks for your help,
Sarah

On Mon, Mar 2, 2009 at 10:16 AM, Sarah A. [email protected]
wrote:

you would do in Python or JavaScript by simply omitting the

http://topfunky.net/svn/plugins/topfunky_power_tools/lib/topfunky/test_helper.rb
), I figure there must be some standard way to call it

Yes, you need to pass a symbol, just as the error is trying to tell you:

def test_should_not_create_user_unless_default_fields
assert_required_fields :create, :email, :lastname, :password
end

I’m assuming that this is in the unit test for the User model.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Rick Denatale wrote:

Yes, you need to pass a symbol, just as the error is trying to tell you:

def test_should_not_create_user_unless_default_fields
assert_required_fields :create, :email, :lastname, :password
end

I’m assuming that this is in the unit test for the User model.

So, how would it magically know to call create on User and not some
other class? as I might expect, I get this error:

  1. Error:
    test_should_not_create_user_unless_default_fields(UserTest):
    NoMethodError: undefined method `create’ for #UserTest:0x1e93a58

Thanks,
Sarah:w

On Mon, Mar 2, 2009 at 1:41 PM, Sarah A. [email protected]
wrote:

other class? as I might expect, I get this error:

  1. Error:
    test_should_not_create_user_unless_default_fields(UserTest):
    NoMethodError: undefined method `create’ for #UserTest:0x1e93a58

Okay, I’m curious where you found the topfunky power tools plugin.
There’s
not much that google reveals about the usage.

However, it appears to come from a very early Peepcode screen cast on
Test
First Design (Peepcode #4 to be exact). I did a quick look at the
screencast and it depends on having helper method called ceate in the
test
case. So you should have something like:

class UserTest < Test::Unit::TestCase
#…
def test_should_not_create_user_unless_default_fields
assert_required_fields :create, :email, :lastname, :password
end

private
def create(options={})
User.create({
:email => “[email protected]”,
:last_name => “jones”,
:password => “secret”
}.merge(options)
)
end
end

The create method creates a valid record, and the assert_required_fields
nils out each field asserted to be required, calls the create method
with
that field set to nil and ensures that the resulting record has an error
on
that field.

And given that helper method, the other test can be re-written as:

def test_should_create_user
user = create
assert user.valid?, “User was invalid:\n#{user.to_yaml}”
end

Now, as I say, this plugin doesn’t seem to be very popular based on a
google
search, and it’s rather old. There are probably more ‘modern’
approaches to
testing required field validations these days using Test::Unit tests in
Rails, I’m not as up on that as I tend to use RSpec rather than
Test::Unit.

And since this really IS a Rails question, it probably would have gotten
a
better response, quicker if it had been submitted ot the ruby on rails
mailing list.

Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Rick Denatale wrote:

Okay, I’m curious where you found the topfunky power tools plugin.
There’s not much that google reveals about the usage.

I’m just getting into TDD. I experimented with cucumber a bit and really
liked it, but I’m diving into an old codebase with lots of pre-existing
unit tests. I wanted to understand the basics, so (as you guessed) I
bought the peepcode tutorial.

Now, as I say, this plugin doesn’t seem to be very popular based on a
google search, and it’s rather old. There are probably more ‘modern’
approaches to
testing required field validations these days using Test::Unit tests in
Rails, I’m not as up on that as I tend to use RSpec rather than
Test::Unit.

If its wisdom is out of date, is there another resource you recommend?
Or is everyone just skipping unit tests these days in favor of the BDD
tools?

And since this really IS a Rails question, it probably would have gotten
a better response, quicker if it had been submitted ot the ruby on rails
mailing list.

Yeah, I see that in retrospect – seemed like a basic language question
at the time. Thanks so much for digging in and letting me know the
scoop, which I clearly didn’t fully understand from the screencast. Of
course, now I know four ways to pass a method as a parameter, which is
fabulous.

Cheers,
Sarah

On Mar 2, 2009, at 3:16 PM, Rick DeNatale wrote:

Okay, I’m curious where you found the topfunky power tools plugin.
There’s
not much that google reveals about the usage.

However, it appears to come from a very early Peepcode screen cast
on Test
First Design (Peepcode #4 to be exact). I did a quick look at the
screencast and it depends on having helper method called ceate in
the test
case. So you should have something like:

Wow. +10 to Rick for his google-ruby-rails-test-unit-mentoring-fu

Gary W.