sparklemotion / mechanize

Mechanize is a ruby library that makes automated web interaction easy.
https://www.rubydoc.info/gems/mechanize/
MIT License
4.39k stars 473 forks source link

`Mechanize::File` overrides the `File` base class #625

Closed cguess closed 9 months ago

cguess commented 9 months ago

If I'm subclassing Mechanize and want to write anything to a file, without faffing around with something like RealFile = File outside the class, it fails

(ruby) File
Mechanize::File

I'd highly recommend that you not override a base class as it breaks a lot of things.

(Specifically I'm trying to benchmark some scraping I'm doing and write results to a file for analysis. This mucks that all up)

flavorjones commented 9 months ago

Hi @cguess, thanks for opening this issue, I'll try to help.

Mechanize does not override the File base class. The behavior you're seeing just how constant resolution works in Ruby.

#!/usr/bin/env ruby

class Base
  class File
  end
end

class Subclass < Base
  def foo
    File
  end
end

Subclass.new.foo # => Base::File
File # => File

When referencing a constant within a "namespace" (that is, a module or class that nests another module or class), the constant name is looked for in the local module (Module.nesting), then the ancestors, and only if something isn't found does it proceed to the top-level (global) classes. So in the above case it finds Base::File when it proceeds through the class's ancestors.

You can work around this by being explicit that you want the global File class. To do this, use ::File:

#!/usr/bin/env ruby

class Base
  class File
  end
end

class Subclass < Base
  def foo
    ::File
  end
end

Subclass.new.foo # => File
File # => File

Hope this helps!

flavorjones commented 9 months ago

A good longer explanation of how constant resolution works is here: https://cirw.in/blog/constant-lookup.html

flavorjones commented 9 months ago

@cguess Was this answer helpful at all?