【问题标题】:How do you define & call a "variable.my_function" method in Ruby within a class?如何在类中定义和调用 Ruby 中的“variable.my_function”方法?
【发布时间】:2017-01-19 22:32:51
【问题描述】:

所以基本设置如下:

在 app/services/SomeService/ABC.rb 中

class SomeService::ABC 
 FORBIDDEN_CHARS = {" " => "+", "'" => "%27", "/" => "%2F", ":" => "%3A", "&" => "%26"}
 def my_function(input)
  #now do something fancy with the input
  var = .... #a String is created
  var.to_linkable
 # continue with something fancy
 end

 def to_linkable
  FORBIDDEN_CHARS.each{|key,value| self.gsub!(key,value)}
 end
end

这会导致错误:undefined method `to_linkable' for "bla bla":String

但是以这种方式工作:

def to_linkable(link)
    FORBIDDEN_CHARS.each{|key,value| link.gsub!(key,value)}
end

但我必须用 'to_linkable(link)' 来调用它,而不是仅仅放置 'link.to_linkable'。如果我以第一种方式将代码复制粘贴到终端中,则调用“link.to_linkable”时不会出错。

所以我的问题是:我如何(以及在​​哪里?)正确地创建这样一个 to_linkable 方法?我以后可能想使用它,这就是为什么我希望它是一种易于使用的方法。非常感谢 :) 是的,我是来自 Matlab 的 Ruby 新手:D

【问题讨论】:

  • 猴子补丁
  • 哇,感谢您提供如此快速而有帮助的回复!扩展字符串类有效(URI 替换字符的方式与我不同)并且我理解了更多内容 :-)
  • 是的,Uri.escape 的行为与您的略有不同。但这有关系吗?除非您有充分的理由不使用它(这当然可能只是为了好玩/作为学习练习!),否则请始终使用“标准”解决方案:)

标签: ruby class methods


【解决方案1】:

首先,不要重新发明轮子。使用URI.escape,而不是尝试手动定义要替换的字符。

但是,为了学习,如果我们按照您的实现...

var 是一个字符串。如果您希望在字符串上调用方法,那么它必须在String 类中定义。通常不建议像这样向核心类添加方法,但以下方法会起作用:

class String
  FORBIDDEN_LINK_CHARS = {" " => "+", ...}
  def to_linkable
    FORBIDDEN_LINK_CHARS.each{|key,value| self.gsub!(key,value)}
    self
  end
end

"hello world".to_linkable # => "hello+world"

或者,如果您不想扩展String 类,但仍希望在不传递变量的情况下调用实例方法,那么您需要在某处将var 设置为实例变量强>在课堂上。这可能是一个好主意,也可能不是一个好主意,具体取决于类的结构。

例如,以下工作:

class SomeService::ABC 
  FORBIDDEN_CHARS = {" " => "+", ...}
  def my_function(input)
    @var = .... #a String is created
    make_var_linkable
  end

  def make_var_linkable
    FORBIDDEN_CHARS.each{|key,value| @var.gsub!(key,value)}
  end
end

...但是,回到我原来的观点,我推荐的 实际 实现不是上述任何一种。做吧:

require 'uri'

class SomeService::ABC 
  def my_function(input)
    var = URI.escape(....)
  end
end

【讨论】:

    【解决方案2】:

    到目前为止给出的两个答案都使用了FORBIDDEN_LINK_CHARS.length 数量的gsub 操作,这不是很理想。

    module StringWithForbiddenChars
      FORBIDDEN_LINK_CHARS = {" " => "+", ...}
      def to_linkable
        gsub Regexp.union(FORBIDDEN_LINK_CHARS.keys), FORBIDDEN_LINK_CHARS
      end
      def to_linkable!
        self.tap do |s|
          s.gsub! Regexp.union(FORBIDDEN_LINK_CHARS.keys), FORBIDDEN_LINK_CHARS
        end
      end
    end
    String.prepend StringWithForbiddenChars
    # or to extend the specific instance of a string:
    # (str = "hello world").extend(StringWithForbiddenChars)
    
    "hello world".to_linkable
    #⇒ "hello+world"
    

    【讨论】:

    • 谢谢,接下来将深入研究Ruby的模块内容!
    • 我发布这篇文章的主要原因不是模块。我的代码有 1 个gsub 调用,而所有其他给出答案的调用gsub N 次,其中N 是要替换的字符数。
    【解决方案3】:

    当您在另一个类中编写 class String; ...; end 时,您正在创建新类,而不是编辑现有的 ruby​​ 核心 String 类。基本上可以说是String::ABC != String。所以你应该首先像这样定义你的新 String 方法:

    class String
      FORBIDDEN_CHARS = {" " => "+", "'" => "%27", "/" => "%2F", ":" => "%3A", "&" => "%26"}
    
      def to_linkable
        FORBIDDEN_CHARS.each{ |key, value| self.gsub!(key,value) }
        self
      end      
    end
    

    之后,您可以在任何带有字符串对象的地方使用此方法。例如在你的SomeService 类中

    class SomeService
      def my_function(input)
        #now do something fancy with the input
        var = "#{input}    " #a String is created
        var.to_linkable
        # continue with something fancy
      end
    end
    

    所以最后你可以这样做:

    SomeService.new.my_function("': 123123&")
    # =>"%27%3A+123123%26++++"
    

    【讨论】:

    • @Ilya Ofc,给我一分钟)
    【解决方案4】:

    如果你不想“污染”整个字符串class,你可以extend带有模块的特定字符串instance

    module SomeService
      FORBIDDEN_CHARS = {" " => "+", "'" => "%27", "/" => "%2F", ":" => "%3A", "&" => "%26"}
    
      class ABC
        def my_function(input)
          # ...
          var = # a String is created
          var.extend(Linkable)
          var.to_linkable
          # ...
        end
      end
    
      module Linkable
        def to_linkable
          FORBIDDEN_CHARS.each { |key, value| gsub!(key,value) }
        end
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-28
      • 2016-10-29
      • 1970-01-01
      • 1970-01-01
      • 2016-06-30
      • 1970-01-01
      • 2015-03-02
      • 1970-01-01
      相关资源
      最近更新 更多