[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

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

Daniel Berger

9/27/2008 8:43:00 PM

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

4 Answers

Nobuyoshi Nakada

9/27/2008 9:13:00 PM

0

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

David A. Black

9/27/2008 9:14:00 PM

0

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.r... for details and updates!

Daniel Berger

9/27/2008 10:30:00 PM

0

On Sep 27, 3:14 pm, "David A. Black" <dbl...@rubypal.com> 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

Regards,

Dan

Daniel Berger

9/28/2008 1:06:00 AM

0

David A. Black wrote:
> Hi --
>
> On Sun, 28 Sep 2008, Daniel Berger wrote:
>
>> On Sep 27, 3:14?pm, "David A. Black" <dbl...@rubypal.com> 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