3

I have a small logic, that alows I18n 'inplace translation' with AJAX, directly on the page. Therefore I want to intercept I18n.translate

My investigations brought me to this - nice and clean looking - logic: based on this SO Answer (Method Wrapping) and some "how could it work" trial and errors

module I18n
    extend Module.new {
        old_translate=I18n.method(:translate)
        define_method(:translate) do |*args|
            InplaceTrans.translate(old_translate,*args)
        end
        alias :t :translate
    }
end

and

module InplaceTrans
    extend Module.new {
        def translate(old_translate,*args)
            Translator.new.translate(old_translate, *args)
        end
    }
end

the Translator.new.translate() is just a Trick, so i dont have to restart rails server when developing

All above is working fine and stable, but i don't realy know what I am doing ...

Question(s):

Is this a valid (and clean) approach?

What does the extend Model.new { ... } do?

what is the difference to extend Model.new DO ... END? (seems to do nothing in my case)
EDIT: answerd my self: according to DO/END vs {} and at end of question:

And why does InplaceTrans.translate inside I18n.newly_defined_method() resolve to my anonymous module.translate according to this:

Creates a new anonymous module. If a block is given, it is passed the module object, and the block is evaluated in the context of this module using module_eval.

So it works, but i realy would like to know why!

(RoR 1.9.3,3.2)

EDIT: partial answer

extend Module.new {} evolves to extend(Module.new {})

whereas

extend Module.new do/end evolves to extend(Module.new) do/end

so with do/end the block is bound to result of extend. if you want to use do/end you must use braces:

extend(Module.new do/end) same as extend Module.new {}

Community
  • 1
  • 1
halfbit
  • 3,773
  • 2
  • 34
  • 47

1 Answers1

1

The following is, what I figgured out, I dont know if there are other (side) effects I do not know.

lets start with a module:

module NiceOne
    def self.init_param(param)
        @base_param=param
    end

    def self.read_param
        @base_param
    end

    def util_func(in_string)
        in_string+NiceOne.read_param
    end
end

and lets include it in a Class.

class HomeController < SiteController
...
    include NiceOne

    def sandbox
        NiceOne.init_param(' the base param')
        # later:NiceOne.write_other_param(' the other param')

        puts NiceOne.read_param
        #later: puts NiceOne.read_other_param

        puts util_func('can we read')
    end
end

so util_func 'moves' into HomeController, whereas the 'selfed methods' do not, we all know that (or not); so we get:

 the base param
can we rad the base param

if you now extend NiceOne "manually" like that:

module NiceOne
    def self.write_other_param(param)
        @base_param=param
    end

    def self.read_other_param
        @base_param
    end
end

and uncomment the two lines in HomeController you get:

 the other param
 the other param
can we read the other param

So far so easy, and not the answer to the question, just intro

It would not be Ruby, if there wasn't a more elegant way to to this:

we keep the HomeController and NiceOne (original) untouched, but change the manual 'extend' to:

module NiceOneNicen
    def write_other_param(param)
        @base_param=param
    end

    def read_other_param
        @base_param
    end
end

module NiceOne
    extend NiceOneNicen
end

and we get the same Output as before. The two methods 'move' into (extend) OneNice like utli_func into HomeController. And this is usefull, if you want to extend more than one module with your beloved module!

But if we need that only once? Dont polute Namespace, we create the module on the fly, i.e Module.new. So

module NiceOne
    dummy=Module.new {
        def write_other_param(param)
          ...
        end
    }

    extend dummy
end

and finaly

module NiceOne
    extend Module.new {
        def write_other_param(param)
          ...
        end
    }
end

And if do/end is asked, we can use it, if we dont forget the braces ...

module NiceOne
    extend( Module.new do
        def write_other_param(param)
          ...
        end
    end)
end

so - to answer the last question: the anonymous module created with Module.new "exists only a short time" and is only used tu push its methods into OneNice

so you can read the

extend Module.new { .. } 

like

"put a self. before every method in following" {  }
halfbit
  • 3,773
  • 2
  • 34
  • 47