Un_include and un_extend


#1

How do I un_include a module from a class/module, or un_extend a module
from
an object?

Thanks.


#2

Hi,

In message “Re: un_include and un_extend”
on Wed, 5 Apr 2006 01:58:46 +0900, “itsme213” removed_email_address@domain.invalid
writes:

|How do I un_include a module from a class/module, or un_extend a module from
|an object?

You can’t, under the current implementation.

						matz.

#3

Thanks. Will 2.0 allow this?

In 1.8 are there any fancy libraries or evil hacks to accomplish this?

“Yukihiro M.” removed_email_address@domain.invalid wrote in message
news:removed_email_address@domain.invalid…


#4

Hi,

In message “Re: un_include and un_extend”
on Wed, 5 Apr 2006 09:03:47 +0900, “itsme213” removed_email_address@domain.invalid
writes:

|Thanks. Will 2.0 allow this?

No plan. Currently I have no reason to allow it.

						matz.

#5

itsme213 schrieb:

In 1.8 are there any fancy libraries or evil hacks to accomplish this?

I think it’s not included in the “evil” library [1], but it shouldn’t be
too hard to do so. Unfortunately, I don’t have much time at the moment.
If you really, really need this and can’t find someone else, write me
again next week…

Regards,
Pit

[1] http://rubyforge.org/projects/evil


#6

On 4/6/06, Yukihiro M. removed_email_address@domain.invalid wrote:

In message “Re: un_include and un_extend”
on Wed, 5 Apr 2006 09:03:47 +0900, “itsme213” removed_email_address@domain.invalid writes:
| Thanks. Will 2.0 allow this?
No plan. Currently I have no reason to allow it.

I’d love to change your mind about that. One reason is
Transaction::Simple. My preferred use of Transaction::Simple will not
be including it into a class, but extending an object with it like so:

foo = “mystring”
Transaction::Simple.start(foo) do |t_foo|
t_foo.gsub!(/my/, “your”)
t_foo.rewind_transaction
t_foo.gsub!(/string/, “test”)
end
t_foo.start_transaction # I want this to throw an exception.

It would make certain things easier to manage in classes that use
Transaction::Simple. I understand that it wouldn’t be easy, and it
would be almost impossible to automate, so perhaps only allowing it on
modules that have an #unextended method?

I think that most modules are things that you only want to add to an
object or class. But I think that there are transient things which
would benefit from this.

-austin


#7

On 4/6/06, Austin Z. removed_email_address@domain.invalid wrote:

foo = “mystring”
Transaction::Simple.start(foo) do |t_foo|
t_foo.gsub!(/my/, “your”)
t_foo.rewind_transaction
t_foo.gsub!(/string/, “test”)
end
t_foo.start_transaction # I want this to throw an exception.

Er. This last should be:

foo # contains “mytest”
foo.start_transaction # this should throw an exception

-austin


#8

On 4/6/06, Yukihiro M. removed_email_address@domain.invalid wrote:

| t_foo.gsub!(/string/, “test”)
but being out of transaction, I guess. PStore does similar thing, but
it doesn’t raise NoMethodError but PStore::Error for the reason. Am I
missing something?

Actually, as Austin mentions in a followup email, that last line was a
typo. It would actually be:

foo.start_transaction

The idea, I’m guessing (I don’t know the internals of
Transaction::Simple) is that Transaction::Simple.start(foo) extends
foo with a module which includes the #start_transaction method, then
calls foo.start_transaction with the block provided. It would be nice
if you could then unextend the module so that foo.start_transaction
once again throws NoMethodError (since it did initially) after leaving
Transaction::Simple::start.

Jacob F.


#9

Hi,

In message “Re: un_include and un_extend”
on Fri, 7 Apr 2006 00:46:47 +0900, “Jacob F.” removed_email_address@domain.invalid
writes:

|Actually, as Austin mentions in a followup email, that last line was a
|typo. It would actually be:
|
| foo.start_transaction
|
|The idea, I’m guessing (I don’t know the internals of
|Transaction::Simple) is that Transaction::Simple.start(foo) extends
|foo with a module which includes the #start_transaction method, then
|calls foo.start_transaction with the block provided. It would be nice
|if you could then unextend the module so that foo.start_transaction
|once again throws NoMethodError (since it did initially) after leaving
|Transaction::Simple::start.

It still sounds like bad manner for the same reason. Besides it’s not
thread safe. If I were designing Transaction::Simple, I’d create
t_foo as a delegation object to the original foo. But I might be
still missing something.

						matz.

#10

On 4/6/06, Yukihiro M. removed_email_address@domain.invalid wrote:

It still sounds like bad manner for the same reason. Besides it’s not
thread safe. If I were designing Transaction::Simple, I’d create
t_foo as a delegation object to the original foo. But I might be
still missing something.

That might work and I can investigate that. Ultimately, the trick with
that mode of operation is that changes to the t_foo object must be
reflected to the foo object, but only if the block exits without error
or an explicit #commit_transaction call is made.

The other thing that would make me happy is the ability to not have
Marshal#dump break if I have a Proc. :wink:

-austin


#11

On Apr 6, 2006, at 12:16 PM, Austin Z. wrote:

The other thing that would make me happy is the ability to not have
Marshal#dump break if I have a Proc. :wink:

Theoretically YARV could archive the byte-code, alternatively the AST
could be saved with ParseTree.


#12

Hi,

In message “Re: un_include and un_extend”
on Thu, 6 Apr 2006 21:28:46 +0900, “Austin Z.”
removed_email_address@domain.invalid writes:

|I’d love to change your mind about that. One reason is
|Transaction::Simple. My preferred use of Transaction::Simple will not
|be including it into a class, but extending an object with it like so:
|
| foo = “mystring”
| Transaction::Simple.start(foo) do |t_foo|
| t_foo.gsub!(/my/, “your”)
| t_foo.rewind_transaction
| t_foo.gsub!(/string/, “test”)
| end
| t_foo.start_transaction # I want this to throw an exception.
|
|It would make certain things easier to manage in classes that use
|Transaction::Simple. I understand that it wouldn’t be easy, and it
|would be almost impossible to automate, so perhaps only allowing it on
|modules that have an #unextended method?

Hmm, raising NoMethodError for such case sounds like bad manner for
me, since the real reason of the error is non-existence of the method,
but being out of transaction, I guess. PStore does similar thing, but
it doesn’t raise NoMethodError but PStore::Error for the reason. Am I
missing something?

						matz.

#13

On Apr 6, 2006, at 12:16 PM, Austin Z. wrote:

or an explicit #commit_transaction call is made.

The other thing that would make me happy is the ability to not have
Marshal#dump break if I have a Proc. :wink:

-austin

Austin Z. * removed_email_address@domain.invalid
* Alternate: removed_email_address@domain.invalid

Incidentally the last time someone asked this question I wrote this
code:

% cat quasiextender.rb
require ‘delegate’
module QuasiExtender
def quasi_extend(mod)
@__quasi_extensions ||= []
@__quasi_extensions << mod
end

def quasi_retract(mod)
@__quasi_extensions ||= []
@__quasi_extensions.delete_if { |ext| ext == mod }
end

def method_missing(name, *args, &block)
@__quasi_extensions ||= []
meth = nil
found_mod = nil
@__quasi_extensions.each do |ext|
begin
meth = ext.instance_method(name.to_sym)
found_mod = ext
rescue NameError, NoMethodError
next
else
break
end
end

 if meth.nil? # we didn't find it
    super
 else
    sneaky_class = Class.new(SimpleDelegator) {
             include(found_mod)
    }
    sneaky_obj = sneaky_class.new(self)

    meth.bind(sneaky_obj).call(*args, &block)
 end

end
end

It of course has various disadvantages, and you can’t use it on
itself :-p