Error message, undefined method in Set

Hi,

I run some tests and get this:

1) Error:
test_construction(TestTask):
NoMethodError: undefined method `include?' for #<Set:0x000001009aa2d0>

...

the offending line of code is this:

@@available_classes << file unless @@available_classes.include? file

If I remove the `unless @@available_classes.include? file` then I still get error messages, this time about `<<` being undefined:

1) Error:
test_construction(TestTask):
NoMethodError: undefined method `<<' for #<Set:0x0000010096a6a8>
...

I checked the docs and Set has both of these defined, so I'm stumped as to why this happens. It doesn't happen when the application runs, it runs fine, only when running the tests. I've added `require 'set'` to the top of the test file but that didn't help.

I'm running this through Ruby 1.9.2 on OSX 10.6.4

Any help on this is much appreciated, as I've no idea what to try next.

Regards,
Iain

Iain Barnett wrote:

Any help on this is much appreciated, as I've no idea what to try next.

It is possible that there is another Set class defined somewhere. Try:

  puts Set.to_s # does this show "Set" or "Foo::Set" ?

  assert_equal Set, ::Set, "Using Set not at the top level!"

Otherwise, you could copy your test file to another name, and keep
trimming it until you get the smallest possible file which reproduces
the problem, then post that file here.

I don't recognise "test_construction(TestTask)" so I don't know what
test framework you're using. Good ol' Test::Unit looks fine to me:

require 'test/unit'
require 'set'
class TestSet < Test::Unit::TestCase
  def test_set
    set = Set.new
    assert_nothing_raised do
      set << 1
      set << 2
    end
    assert set.include?(2)
    assert !set.include?(3)
  end
end

Started
.
Finished in 0.000752 seconds.

1 tests, 3 assertions, 0 failures, 0 errors

···

--
Posted via http://www.ruby-forum.com/\.

Iain Barnett wrote:

Any help on this is much appreciated, as I've no idea what to try next.

It is possible that there is another Set class defined somewhere.

Would be my guess as well. I would rather try this to get an idea of
what class @@available_classes is an instance of:

p @@available_classes.class, @@available_classes.class.ancestors

It's likely that we see delegator at work here:

irb(main):010:0> require 'delegate'
=> true

irb(main):016:0> dd = SimpleDelegator.new ::Set.new
=> #<Set: {}>
irb(main):017:0> dd.to_s
=> "#<Set:0x10154174>"
irb(main):018:0> dd.class
=> SimpleDelegator
irb(main):019:0> dd.class.ancestors
=> [SimpleDelegator, Delegator, Object, Kernel, BasicObject]

Note item 17 which looks suspiciously similar to what OP posted.

Still:

irb(main):020:0> dd.include? 123
=> false

Which would not yield the original error.

Try:

puts Set.to_s # does this show "Set" or "Foo::Set" ?

This tells you only about Set but you do not know what class created
@@available_classes.

assert_equal Set, ::Set, "Using Set not at the top level!"

Kind regards

robert

···

On Mon, Sep 27, 2010 at 3:55 PM, Brian Candler <b.candler@pobox.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

It is possible that there is another Set class defined somewhere. Try:

puts Set.to_s # does this show "Set" or "Foo::Set" ?

It shows Set

assert_equal Set, ::Set, "Using Set not at the top level!"

This passed.

... I would rather try this to get an idea of
what class @@available_classes is an instance of:

p @@available_classes.class, @@available_classes.class.ancestors

Set
[Set, Enumerable, Object, Kernel, BasicObject]

I played around with a few things, and it turns out that this works (whether at the top of the test file or another file that does all the requiring) :

require 'set'
require 'choice' #this is the class that utilises Set

but this throws errors:

require 'choice'
require 'set'

I'm very surprised that the order of requires (at the top of a file) can affect anything in this way. Is this the way it's supposed be? If not, what could be the cause?

The Choice class itself doesn't have any requires in it, btw, that's all done in a separate file for all the app.

Regards,
Iain

···

On 27 Sep 2010, at 14:55, Brian Candler wrote:
On 27 Sep 2010, at 15:02, Robert Klemme wrote:

Iain Barnett wrote:

but this throws errors:

require 'choice'
require 'set'

Then at the top of choice.rb I'd put require 'set'.

I'm very surprised that the order of requires (at the top of a file) can
affect anything in this way. Is this the way it's supposed be? If not,
what could be the cause?

It can be. Imagine this:

--- set.rb ---
class Set < Hash
  ...
end

--- choice.rb ---
class Set
  ... add some more methods to the class
end

If you require choice.rb first, you would get an exception when
requiring set.rb

···

--
Posted via http://www.ruby-forum.com/\.

Iain Barnett wrote:

but this throws errors:

require 'choice'
require 'set'

Then at the top of choice.rb I'd put require 'set'.

That's what I was originally doing, but a lot of the advice I've read on structuring projects is to remove the requires from individual classes/files and put them in a central file with the name of the app under lib.

I'm very surprised that the order of requires (at the top of a file) can
affect anything in this way. Is this the way it's supposed be? If not,
what could be the cause?

It can be. Imagine this:

--- set.rb ---
class Set < Hash
...
end

--- choice.rb ---
class Set
... add some more methods to the class
end

If you require choice.rb first, you would get an exception when
requiring set.rb

Ok, thanks. It's good to know gotchas!

Regards,
Iain

···

On 28 Sep 2010, at 07:11, Brian Candler wrote:

Iain Barnett wrote:

Then at the top of choice.rb I'd put require 'set'.

That's what I was originally doing, but a lot of the advice I've read on
structuring projects is to remove the requires from individual
classes/files and put them in a central file with the name of the app
under lib.

Personally I don't support that advice, but it's very much a matter of
personal preference. I like each source file to declare its
dependencies, because it lets them be re-used more easily, although it
is easy to miss some.

I don't know why in your case you have to require set.rb before
choice.rb. If you could boil choice.rb down to a small test case which
demonstrates the problem, it should be fairly easy to identify. But
without seeing the code, I'm only guessing.

···

--
Posted via http://www.ruby-forum.com/\.

Iain Barnett wrote:

Then at the top of choice.rb I'd put require 'set'.

That's what I was originally doing, but a lot of the advice I've read on
structuring projects is to remove the requires from individual
classes/files and put them in a central file with the name of the app
under lib.

Personally I don't support that advice, but it's very much a matter of
personal preference. I like each source file to declare its
dependencies, because it lets them be re-used more easily, although it
is easy to miss some.

+1

I don't know why in your case you have to require set.rb before
choice.rb. If you could boil choice.rb down to a small test case which
demonstrates the problem, it should be fairly easy to identify. But
without seeing the code, I'm only guessing.

Basically order should not matter. It seems choice.rb or some file required from there does something bad to Set like you showed in your example. Although, if I think about it: that should be visible:

$ ruby19 -e 'class Set;end; class Set < Hash; end'
-e:1:in `<main>': superclass mismatch for class Set (TypeError)

Set could be reassigned but even then that would be visible

$ ruby19 -e 'class Set;end; Set = Class.new Hash'
-e:1: warning: already initialized constant Set

Ian, if you really want to know what goes on you could try this at the top of the script, before any requires:

set_trace_func lambda {|*a| p a}

This will create copious output though.

Kind regards

  robert

···

On 28.09.2010 22:13, Brian Candler wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/