2016-09-14 37 views
1

我想重构一个现有的代码来简化。最初我在Java中调用模块方法,如静态实用程序方法。为什么我不能从另一个模块调用实例方法来初始化Ruby中的lambda?

这是新代码:

module Module1 
    def mod1() 1; end 
end 

module Module2 
    include Module1 
    def mod2 
    puts mod1() 
    puts 2 
    end 
    Constant = lambda { mod1() } # This line fails 
end 

class Sample 
    include Module2 
    def go 
    mod2 
    Constant.call # <module:Module2>': undefined method `mod1' for Module2:Module (NoMethodError) 
    end 
end 

Sample.new.go 

我可以做,如果只是在Module1代码复制到Module2它的工作。有更好的解决方案吗?

编辑:此外,我应该能够从直接包含它的类中调用Module1中的方法。例如:

class Sample2 
    include Module1 
    def go 
    puts mod1() 
    end 
end 
Sample2.new.go 

实际模块1:

module HtmlUtils 
    def wrap(tag = :span, class_names, text) 
    %(<#{ tag } class="#{ class_names }">#{ text }</#{ tag }>) 
    end 
end 

实际模块2的问题是在从最后一个代码的第三复制代码。它可以用HtmlUtils#wrap方法替换。

module Markdown 
    include HtmlUtils 
    BOLD = { 
    regexp: /(_{2}|\*{2})(.*?)\1/, 
    lambda: ->(token, regexp) { "<b>#{ token[regexp, 2] }</b>" } 
    } 
    NUMBER = {    
    regexp: /(?<=\s|\()[+-]?(?:[1-9]\d*|0)(?:\.\d+)?(?!-|\.|\d|,\d)/, 
    lambda: ->(token, regexp) { %(<span class="num">#{ token }</span>) } # Redundant Code 
    } 
end 

Client1包含Markdown,实际上是HtmlUtils。

@parser.regexter('bold', BOLD[:regexp], BOLD[:lambda]); 
@parser.regexter('numbers', NUMBER[:regexp], NUMBER[:lambda]) 
puts @parser.parse('some **string** 1') # => some <b>string</b> <span class="num">1</span> 

客户端2包括HtmlUtils

@parser.regexter('quote', /(?<=)((["']).*?\2)/, ->(token, regexp) { wrap(:quote, token)); 
puts @parser.parse('s="Hello"') # => s=<span class="quote">"Hello"</span> 
+1

'Sample :: Constant'不知道通过'Sample.new'创建的实例。假设你有两个实例,'s1 = Sample.new'和's2 = Sample.new'。哪个'mod1'应该通过'Sample :: Constant.call'调用? – Stefan

+0

在我的要求中,我不需要'mod1'的特定实例。它应该为每个实例返回相同的值,尽管它在实际中具有参数来进行区分。原谅我的无知,但你是否建议我应该留在使用模块方法? –

+0

我不确定。为什么你想首先将一个proc/lamda分配给一个常量? 'Sample :: Constant.call'对我来说看起来很奇怪。 – Stefan

回答

1

注意试图回答原来的问题(被张贴实际的代码之前)。

嗯,这取决于。如果模块提供了他们自己需要的所有东西,那么可以使mod1成为模块函数并明确地调用它(然后不需要包含模块)。但是我担心你确实需要上下文。

module Module1 
    def self.mod1() 1; end 
end 

module Module2 
    def mod2 
    puts Module1.mod1() 
    puts 2 
    end 
    Constant = lambda { puts Module1.mod1() } 
end 

class Sample 
    include Module2 
    def go 
    mod2 
    Constant.call 
    end 
end 

Sample.new.go 

输出

#=> 
1 
2 
1 

否则你可以unconstantize拉姆达:

module Module1 
    def mod1() inmod2 ; end 
end 

module Module2 
    include Module1 

    def inmod2 
    1 
    end 

    def mod2 
    puts mod1() 
    puts 2 
    end 
    def constant 
    lambda { puts self.mod1() } 
    end 
end 

class Sample 
    include Module2 
    def go 
    mod2 
    constant.call 
    end 
end 

Sample.new.go 

其中一期工程(相同的输出)。不幸的是,我无法解释你为什么。很高兴阅读包含解释的答案(随意复制我的代码)。

+0

第一个可以工作,但是直接包含'Module1'的类必须完全有资格访问'Module1'方法,这与原始方法有些类似。第二个不适用于相同的场景。对不起,如果我没有提到'Module1'可以被其他类直接包含。我会更新这个问题。 –

+0

@JohnDoe为什么第二个不起作用?可以包含“Module1”,并可以从中调用方法。 – Felix

+0

我得到这个错误:'

相关问题