Forum: Ruby un_include and un_extend

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
itsme213 (Guest)
on 2006-04-04 20:59
(Received via mailing list)
How do I un_include a module from a class/module, or un_extend a module
from
an object?

Thanks.
Yukihiro M. (Guest)
on 2006-04-04 21:02
(Received via mailing list)
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.
itsme213 (Guest)
on 2006-04-05 04:05
(Received via mailing list)
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...
Pit C. (Guest)
on 2006-04-05 14:40
(Received via mailing list)
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
Yukihiro M. (Guest)
on 2006-04-06 13:13
(Received via mailing list)
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.
Austin Z. (Guest)
on 2006-04-06 16:31
(Received via mailing list)
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
Austin Z. (Guest)
on 2006-04-06 16:31
(Received via mailing list)
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
Yukihiro M. (Guest)
on 2006-04-06 19:36
(Received via mailing list)
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.
Jacob F. (Guest)
on 2006-04-06 19:49
(Received via mailing list)
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.
Yukihiro M. (Guest)
on 2006-04-06 19:55
(Received via mailing list)
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.
Austin Z. (Guest)
on 2006-04-06 20:16
(Received via mailing list)
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. ;)

-austin
Logan C. (Guest)
on 2006-04-07 08:09
(Received via mailing list)
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. ;)

Theoretically YARV could archive the byte-code, alternatively the AST
could be saved with ParseTree.
Logan C. (Guest)
on 2006-04-07 08:18
(Received via mailing list)
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. ;)
>
> -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
This topic is locked and can not be replied to.