Thursday, March 24, 2011

Ruby autoload like in PHP

(Disclaimer: this is a translation from Autoload do Ruby como no PHP, in Portuguese.)

Who has worked with OOP in PHP and starts to learn Ruby soon will miss the PHP __autoload.

In fact, Ruby has autoload, but it seems useless for a PHP programmer.

In Ruby, the autoload is for using less memory, leaving files to be loaded only when necessary. But then you need to type more than a simple require; besides specifying the filename, you need also type the constants (classnames) which are in the file. For example:

autoload :MyClass, "myclass.rb"

I guess the computers was made to help the people, and that includes the programmer. From the programmer point of view (and not from the machine's one), would be far easier to type:

require "myclass"

Unless resources are critical, the development/maintenance time is more important in this case.

In PHP, you define only once a function which will guess the filename from the classname, and then you don't worry ever more. You don't need to specify nothing!!! When a reference to "MyClass" appears, the function __autoload will convert it to a filename (e.g., "myclass.inc"; you can code __autoload with your needs) and will try to include that file. That's awesome useful!

Fortunately, Ruby is a very powerful language, and, following a tip, I made my version:

# autoload like in PHP
# (c) Sony Santos 2011
# License: Public Domain
# http://rubychallenger.blogspot.com/2011/03/ruby-autoload-like-in-php.html

# alters Object#const_missing
#
class Object

  # it's a class method, not an instance one
  class << self

    # preserves the original method
    alias_method :old_const_missing, :const_missing
    private :old_const_missing

    # redefine the method which is called on a missing const
    def const_missing(const)

      # guess a filename (use your favorite algorithm)
      filename = const.to_s.downcase

      begin
        # try to require it
        require filename

        # if it did, returns that missing const
        const_get(const)

      rescue LoadError => e
        if e.message.include? filename

          # that constant doesn't really exist; use the old method
          old_const_missing(const)

        else

          # other reason
          raise

        end
      end
    end
  end
end

1 comment:

  1. ~const~ parameter is only 'MainMod' in this example; MainMod::SubMod::FooClass, so I cannot take the SubMod nor the FooClass and cannot use in the const_missing function.

    ReplyDelete