I'm going to argue that your design is off, and then ignore the rest of your post :)
class Person < Struct.new(:name, :age) VOTING_AGE = 18 def voter? age >= VOTING_AGE end end Now your tests become very simple: Person.new('Jenny', 17).should_not be_voter Person.new('Bob', 18).should be_voter Why you want a Person.get_voters method to select voters from a list, I'm not really sure. You can always just do: voters = collection_of_people.select {|p| p.voter?} Also, RSpec has two mechanisms for testing collections the way you want (so I guess I'm not ignoring your post after all). If you only care about inclusion, you can use the include matcher: jenny = Person.new('Jenny', 17) bob = Person.new('Bob', 18) sally = Person.new('Sally', 20) voters = Person.get_voters(jenny, bob, sally) voters.should include(bob, sally) voters.should_not include(jenny) there is also the set equality matcher, which checks that the contents of two collections are equal irrespective of order: voters.should =~ [bob, sally] Pat On Feb 23, 2010, at 10:18 AM, Pete Hodgson wrote: > Hi all, > I've tried to figure out whether rspec has any features to make it > easier to make assertions against the elements of a collection, but I > haven't had any luck finding anything so far. I thought I'd explain > the problem here, and propose a potential feature that might mitigate > it. > > Let's say I have a Person class: > > class Person < Struct.new( :name, :age ) > > VOTING_AGE = 18 > def self.get_voters( people ) > people.reject{ |person| person.age < VOTING_AGE } > end > > end > > As you can see we have a method here which filters a collection of > people, returning only those people old enough to vote. If I were to > test this method in rspec I might write: > > describe 'Person vote filtering' do > it 'filters out people younger than voting age' do > people = [ > Person.new( 'jenny', 18 ), > Person.new( 'dave', 12 ), > Person.new( 'paul', 19 ), > Person.new( 'lisa', 17 ) > ] > > voters = Person.get_voters( people ) > > voter_names = voters.map{ |p| p.name } > voter_names.should == ['jenny','paul'] > end > end > > This works, but having to manually pull out the voter names into a > seperate collection just in order to check who was filtered and who > wasn't has always seemed clunky to me. What I would prefer is to be > able to check whether the collection contains person who matching my > expectations. Say I have a custom matcher: > > Spec::Matchers.define :be_named do |expected| > match do |actual| > actual.name == expected > end > end > > Then I'd like to be able to write something like > > voters.should( have(2).people ) > voters.should( have_one_that( be_named('jenny') ) ) > voters.should( have_one_that( be_named('paul') ) ) > > or even: > > voters.should( have_elements_that( > be_named( 'jenny' ), > be_named( 'paul' ) > ) > > To me this is a lot clearer - although the method names and how > they're composed into the DSL could clearly use some work ;). > > Now, for the trivial case I've been using as an example it would > probably be overkill, but I often find myself writing fairly > convuluted code at the end of a test just to figure out whether a > collection contains an element that matches some complex predicate. It > seems to me that if rspec had the generic ability to apply matchers to > the elements of a collection it would raise the level of > expressiveness for this kind of tests. > > Thoughts? Does Rspec already support something like this that I'm just > not aware of? If I were to write a patch implementing this would it > have any chance of being accepted? > > Cheers, > Pete > _______________________________________________ > rspec-users mailing list > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users