Help, Ruby 1.8.6-p287 broke my "use" library and I don't know why

Discussion in 'Ruby' started by Daniel Berger, Sep 27, 2008.

  1. Hi everyone,

    I need help!

    I've got a library called "use" that let's you mixin methods from
    modules in a fine-grained fashion. Unfortunately, something broke it
    between Ruby 1.8.6-p111 and Ruby 1.8.6-p287.

    It may have something to do with the way I autogenerate some methods in
    the windows-api library, as simple cases still work fine, but I'm not
    sure how or why.

    Here's some sample code:

    # test.rb
    require 'use'
    require 'windows/path'
    require 'windows/msvcrt/io'

    class Foo
    use Windows::path
    use Windows::MSVCRT::IO, :tmpfile

    def initialize
    p PathIsRoot("C:\\")
    p tmpfile()
    end
    end

    Foo.new

    Using Ruby 1.8.6-p111 I get:

    true
    2009464032

    Using Ruby 1.8.6-p287 I get:

    (eval):3:in `PathIsRoot': uninitialized constant Class::pathIsRoot
    (NameError)
    from test.rb:10:in `initialize'
    from test.rb:15:in `new'
    from test.rb:15

    What the heck happened between p 111 and p 287?

    Below is the full source for use.rb.

    Regards,

    Dan

    class Class
    # The version of the 'use' library
    USE_VERSION = '1.2.2'

    # Allows you to include mixins in a fine grained manner. Instead of
    # including all methods from a given module, you can instead mixin
    # only those methods you want through a combination of the :include,
    # :exclude, and :alias options.
    #
    # Examples:
    #
    # # Defines a 'bar' and 'baz' method
    # module Foo
    # def bar
    # "hello"
    # end
    # def baz
    # "world"
    # end
    # end
    #
    # # Defines a 'bar', 'blah', and 'zap' methods
    # module Test
    # def bar
    # "goodbye"
    # end
    # def blah
    # "new york"
    # end
    # def zap
    # "zap"
    # end
    # end
    #
    # # From the Foo module, only mixin the 'bar' method. From the Test
    # # module exclude the 'bar' and 'zap' methods.
    # class Zap
    # use Foo, :bar
    # use Test, :exclude => [:bar, :zap]
    # end
    #
    # z = Zap.new
    #
    # z.bar # => "hello"
    # z.baz # => NoMethodError - wasn't mixed in
    # z.zap # => NoMethodError - wasn't mixed in
    # z.blah # =>"new york"
    #
    # # Alias a method on the fly
    # class MyKlass
    # use Foo :alias => {:bar, :test}
    # end
    #
    # m = MyKlass.new
    # m.test # => "hello"
    # m.bar # => NoMethodError - was aliased to 'test'
    #
    # If no options follow the module name this method is identical
    # to a standard include.
    #
    def use(*args)
    valid_keys = %w/include exclude alias/
    excluded = []
    included = []
    aliased = []

    mod = args.shift.clone

    # If no arguments follow the mod name, treat as a standard include
    if args.empty?
    included.concat(mod.instance_methods)
    end

    m = Module.new

    args.each{ |arg|
    if arg.kind_of?(Hash)
    arg.each{ |key, val|
    case key.to_s
    when "include"
    if val.respond_to?:)each)
    val.each{ |arg| included.push(arg.to_s) }
    else
    included.push(val.to_s)
    end
    when "exclude"
    if val.respond_to?:)each)
    val.each{ |arg| excluded.push(arg.to_s) }
    else
    excluded.push(val.to_s)
    end
    when "alias"
    aliased.push(val)
    else
    raise "invalid key '#{key}'"
    end
    }
    else
    included.push(arg.to_s)
    end
    }

    unless included.empty? || excluded.empty?
    err = "you cannot include and exclude in the same statement"
    raise ArgumentError, err
    end

    imethods = mod.instance_methods

    # Remove excluded methods
    unless excluded.empty?
    (imethods & excluded).each{ |meth|
    mod.module_eval{ remove_method(meth) }
    }
    end

    # Alias methods
    aliased.each{ |pair|
    pair.each{ |old, new|
    included.push(old) # Aliased methods automatically included
    mod.module_eval{
    alias_method(new, old)
    remove_method(old)
    }
    }
    }

    # Remove methods not specifically included. The rescue was needed
    # for cases where a module included another module. Also, don't
    # remove methods that already exist unless specifically included.
    unless included.empty?
    (imethods - included).each{ |meth|
    if superclass.instance_methods.include?(meth)
    if included.include?(meth)
    mod.module_eval{ undef_method(meth) rescue nil }
    else
    mod.module_eval{ remove_method(meth) rescue nil }
    end
    else
    mod.module_eval{ undef_method(meth) rescue nil }
    end
    }
    end

    m.module_eval{ include mod }

    # Raise a warning if methods are shadowed (in $VERBOSE mode)
    if $VERBOSE
    imethods = instance_methods(true)
    m.instance_methods.each{ |meth|
    next unless imethods.include?(meth)
    warn "method '#{meth}' aliased, shadows old '#{meth}'"
    }
    end

    include m
    end
    end
     
    Daniel Berger, Sep 27, 2008
    #1
    1. Advertising

  2. Re: Help, Ruby 1.8.6-p287 broke my "use" library and I don't knowwhy

    Hi,

    At Sun, 28 Sep 2008 05:42:59 +0900,
    Daniel Berger wrote in [ruby-talk:316199]:
    > It may have something to do with the way I autogenerate some methods in
    > the windows-api library, as simple cases still work fine, but I'm not
    > sure how or why.


    Reproduced with:

    module X
    XXX = 1
    def xxx
    XXX
    end
    end

    class Foo
    use X
    end

    Foo.new.xxx

    And worked fine with the SVN 1.8 branch head.

    --
    Nobu Nakada
     
    Nobuyoshi Nakada, Sep 27, 2008
    #2
    1. Advertising

  3. Re: Help, Ruby 1.8.6-p287 broke my "use" library and I don't knowwhy

    Hi Dan --

    On Sun, 28 Sep 2008, Daniel Berger wrote:

    > Hi everyone,
    >
    > I need help!
    >
    > I've got a library called "use" that let's you mixin methods from modules in
    > a fine-grained fashion. Unfortunately, something broke it between Ruby
    > 1.8.6-p111 and Ruby 1.8.6-p287.
    >
    > It may have something to do with the way I autogenerate some methods in the
    > windows-api library, as simple cases still work fine, but I'm not sure how or
    > why.


    Do you have a non-Windows example where it does this?


    David

    --
    Rails training from David A. Black and Ruby Power and Light:
    Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
    Advancing with Rails January 19-22 Fort Lauderdale, FL *
    * Co-taught with Patrick Ewing!
    See http://www.rubypal.com for details and updates!
     
    David A. Black, Sep 27, 2008
    #3
  4. Re: Help, Ruby 1.8.6-p287 broke my "use" library and I don't know why

    On Sep 27, 3:14 pm, "David A. Black" <> wrote:
    > Hi Dan --
    >
    > On Sun, 28 Sep 2008, Daniel Berger wrote:
    > > Hi everyone,

    >
    > > I need help!

    >
    > > I've got a library called "use" that let's you mixin methods from modules in
    > > a fine-grained fashion. Unfortunately, something broke it between Ruby
    > > 1.8.6-p111 and Ruby 1.8.6-p287.

    >
    > > It may have something to do with the way I autogenerate some methods inthe
    > > windows-api library, as simple cases still work fine, but I'm not sure how or
    > > why.

    >
    > Do you have a non-Windows example where it does this?


    Nobu's example summarizes the problem:

    require 'use'

    module X
    XXX = 1
    def xxx
    XXX
    end
    end

    class Foo
    use X
    end

    Foo.new.xxx

    Regards,

    Dan
     
    Daniel Berger, Sep 27, 2008
    #4
  5. Re: Help, Ruby 1.8.6-p287 broke my "use" library and I don't knowwhy

    David A. Black wrote:
    > Hi --
    >
    > On Sun, 28 Sep 2008, Daniel Berger wrote:
    >
    >> On Sep 27, 3:14?pm, "David A. Black" <> wrote:
    >>> Hi Dan --
    >>>
    >>> On Sun, 28 Sep 2008, Daniel Berger wrote:
    >>>> Hi everyone,
    >>>
    >>>> I need help!
    >>>
    >>>> I've got a library called "use" that let's you mixin methods from
    >>>> modules in
    >>>> a fine-grained fashion. Unfortunately, something broke it between Ruby
    >>>> 1.8.6-p111 and Ruby 1.8.6-p287.
    >>>
    >>>> It may have something to do with the way I autogenerate some methods
    >>>> in the
    >>>> windows-api library, as simple cases still work fine, but I'm not
    >>>> sure how or
    >>>> why.
    >>>
    >>> Do you have a non-Windows example where it does this?

    >>
    >> Nobu's example summarizes the problem:
    >>
    >> require 'use'
    >>
    >> module X
    >> XXX = 1
    >> def xxx
    >> XXX
    >> end
    >> end
    >>
    >> class Foo
    >> use X
    >> end
    >>
    >> Foo.new.xxx

    >
    > For what it's worth, here's an even simpler example, not involving
    > your "use" library:
    >
    > class Class
    > def myuse(mod)
    > include mod.clone
    > end
    > end
    >
    > module X
    > XXX = 1
    > def xxx
    > XXX
    > end
    > end
    >
    > class Foo
    > myuse X
    > end
    >
    > Foo.new.xxx
    >
    > This works with p230 but not p287. I guess it has to do with module
    > cloning and constants, but I haven't tracked it down beyond that.


    Thanks for that David. I was wondering what the underlying issue was.

    Regards,

    Dan
     
    Daniel Berger, Sep 28, 2008
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. DP
    Replies:
    0
    Views:
    1,178
  2. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,214
    Smokey Grindel
    Dec 2, 2006
  3. Urabe Shyouhei
    Replies:
    1
    Views:
    101
    Michal Suchanek
    Aug 12, 2008
  4. Chuck Remes
    Replies:
    9
    Views:
    135
    Daniel Berger
    Sep 13, 2009
  5. Andries

    I know, I know, I don't know

    Andries, Apr 23, 2004, in forum: Perl Misc
    Replies:
    3
    Views:
    276
    Gregory Toomey
    Apr 23, 2004
Loading...

Share This Page