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

**URL:** <https://www.ruby-forum.com/t/help-ruby-1-8-6-p287-broke-my-use-library-and-i-dont-know-why/149669>\
**Category:** Ruby\
**Created:** [September 27, 2008, 11:21pm UTC](https://www.ruby-forum.com/t/help-ruby-1-8-6-p287-broke-my-use-library-and-i-dont-know-why/149669 "2008-09-27T23:21:04Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [September 27, 2008, 11:21pm UTC](https://www.ruby-forum.com/t/help-ruby-1-8-6-p287-broke-my-use-library-and-i-dont-know-why/149669/1 "2008-09-27T23:21:04Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [September 27, 2008, 11:26pm UTC](https://www.ruby-forum.com/t/help-ruby-1-8-6-p287-broke-my-use-library-and-i-dont-know-why/149669/2 "2008-09-27T23:26:55Z")

</div>

Hi,

At Sun, 28 Sep 2008 05:42:59 +0900,  
Daniel B. 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.

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [September 27, 2008, 11:27pm UTC](https://www.ruby-forum.com/t/help-ruby-1-8-6-p287-broke-my-use-library-and-i-dont-know-why/149669/3 "2008-09-27T23:27:30Z")

</div>

Hi Dan –

On Sun, 28 Sep 2008, Daniel B. wrote:

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

David

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [September 28, 2008, 12:30am UTC](https://www.ruby-forum.com/t/help-ruby-1-8-6-p287-broke-my-use-library-and-i-dont-know-why/149669/4 "2008-09-28T00:30:44Z")

</div>

On Sep 27, 3:14 pm, “David A. Black” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > 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

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [September 28, 2008, 3:06am UTC](https://www.ruby-forum.com/t/help-ruby-1-8-6-p287-broke-my-use-library-and-i-dont-know-why/149669/5 "2008-09-28T03:06:55Z")

</div>

David A. Black wrote:

> > > > I need help!  
> > > > why.  
> > > > XXX  
> > > > your “use” library:  
> > > > XXX  
> > > > 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

---

<div class="post-metadata">

**Author:** ![danielb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/c57346/32.png) [@danielb](https://www.ruby-forum.com/u/danielb)\
**Post date:** [September 28, 2008, 2:48am UTC](https://www.ruby-forum.com/t/help-ruby-1-8-6-p287-broke-my-use-library-and-i-dont-know-why/149669/6 "2008-09-28T02:48:47Z")

</div>

Hi –

On Sun, 28 Sep 2008, Daniel B. wrote:

> > > 1.8.6-p111 and Ruby 1.8.6-p287.
> 
> 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.

David
