ASPN ActiveState Programmer Network
ActiveState
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups


Recent Messages
List Archives
About the List
List Leaders
Subscription Options

View Subscriptions
Help

View by Topic
ActiveState
.NET Framework
Open Source
Perl
PHP
Python
Tcl
Web Services
XML & XSLT

View by Category
Database
General
SOAP
System Administration
Tools
User Interfaces
Web Programming
XML Programming


MyASPN >> Mail Archive >> ruby-talk
ruby-talk
Re: redefining a method using Module#include
by Trans other posts by this author
Nov 12 2006 10:15AM messages near this date
Re: redefining a method using Module#include | RubyGems Issue
me@[...].net wrote:
>  Hi,
> 
>  How can I redefine Array#[] using an included Module?  Here is my
>  attempt:
> 
>  module AbsenceHandling
>      def if_absent_call(p)
>          @if_absent = p
>          self
>      end
> 
>      def [](index)
>          result = old_accessor(index)
>          if(result.nil? && !@if_absent.nil?)
>              result = @if_absent.call(index)
>              self[index]=result
>          end
>          result
>      end
>  end
> 
>  class Array
>      alias :old_accessor :[]
>      include AbsenceHandling
>  end
> 
> 
>  x = [1,2,3].if_absent_call(proc{|index|
>      "#{index}"
>  })
>  puts x[5]

There are a number of ways. To be clear you are asking for code inject
rather then inheritance. traditionally subclasses are used add
functionality, But with Ruby we have the power to directly effect core
classes. In doing so first ask yourself if you really need a module. If
not the simple do:

  class Array
    def if_absent_call(p)
      ...
    alias :old_accessor :[]
    def [](index)
       ...

The next levelup gets more complicated one way is to use the #included
callback to inject the code directly, but this is a misrepresentation
of what include should do (i.e. inheritance) and I strong discourage
it. Another related approach is alias_method_chain supported by both
ActiveSupport and Facets. Here is an example:

    module X
      def self.included(base)
        base.module_eval {
          alias_method_chain :foo, :feature
        }
      end
      def foo_with_feature
        foo_without_feature + '!'
      end
    end

    class Y
      def foo ; "FOO" ; end
      include X
    end

    y = Y.new
    assert_equal( "FOO!", y.foo )

But this would be a little tricker with an operator and it also has
it's own downsides. Other solution you can look into are Facets'
Module#prepend and Facets' Cut implementation.

Having said all that, you know what you are attempting to do is
dangerous stuff. Muckng with Array#[] may have sever side effects. In
this case, I highly recommend using singleton instead:

  a = []
  a.extend AbsenceHandling

Just replace #old_accessor with #super. It's a  case be case basis, but
it's much safer and hek, it's easy :-)

T.
Thread:
Jan Svitok
Trans

Privacy Policy | Email Opt-out | Feedback | Syndication
© ActiveState Software Inc. All rights reserved