【问题标题】:Ruby: Singleton method of an instance variable inside a classRuby:类中实例变量的单例方法
【发布时间】:2017-09-21 07:04:15
【问题描述】:

我正在接受 ruby​​-kickstart (Josh Cheek) 挑战,即使我设法通过了所有测试,但有一件事我无法理解。

在练习中,您被要求覆盖实例变量的

在 Ruby on Rails 中,当有人访问您网站上的某个 URL 时,您的 应用程序查看 url,并将其映射到控制器方法以 处理请求

我的老板希望能够指定正文的 CSS 类 HTML 输出应该有,基于哪个控制器方法是 访问。我有责任提供一种方法,当被调用时, 将返回一个可以处理请求的字符串有一些 不过,细微差别。您返回的字符串必须在 对象的整个生命周期中的方法必须能够被多次调用 次你返回的字符串应该知道如何添加新的类:每个 类用空格隔开唯一需要担心的方法 被调用的是

controller = ApplicationController.new   
controller.body_class                  
#=> ""    
controller.body_class << 'admin'    
controller.body_class     
#=> "admin"   
controller.body_class << 'category'    
controller.body_class        
#=> "admin category"    
controller.body_class << 'page' << 'order'    
controller.body_class                  
#=> "admin category page order"

我的工作解决方案:

class ApplicationController 

  def initialize
    @body_class = ""
  end

  def body_class
    def @body_class.<<(str)
      puts "self is:"+self
      return self if self=~/\b#{Regexp.escape(str)}\b/
      if self==""
        self.concat(str)
      else
        self.concat(" ")
        self.concat(str)
      end
    end

    return @body_class
  end
end

一切正常。 但是我给出的一个较早的解决方案(它没有工作)如下

class ApplicationController 
  attr_accessor :body_class
  def initialize
    @body_class = ""
  end

  def @body_class.<<(str)
    puts "self is:"+self
    return self if self=~/\b#{Regexp.escape(str)}\b/


    if self==""
      self.concat(str)
    else
      self.concat(" ")
      self.concat(str)
    end

  end

  def body_class                #Even this for the way I work it out on my mind is unnecessary 
    return @body_class
  end



end

当有人在第二个不工作的解决方案上运行时

obj = ApplicationController.new
obj.body_class << "Hi"

谁能给我指点一下! 谢谢!

【问题讨论】:

  • 另一方面,您可能需要考虑该正则表达式的作用。许多框架使用 css 样式,例如 messagemessage-importantmessage-warning,连字符将被视为单词边界,因此如果 @body_class"admin-log",然后您想要附加 logadmin不会发生
  • 嗨@engineersmnky,感谢您的cmets。此示例来自初学者教程,用于学习 ruby​​ 的基础知识。 rspec 正在检查一些挑战。我不认为该代码旨在用于真正的应用程序:) 可以找到该教程here

标签: ruby-on-rails ruby attributes accessor singleton-methods


【解决方案1】:

我不明白为什么我必须将单例方法包装在 body_class 方法中。

访问正确的实例变量。当您尝试在方法之外覆盖它时,您就处于类上下文中。此代码在类加载时运行。尚未创建任何实例。 (即使此时确实存在实例,@body_class 实例变量也属于类ApplicationController,它本身就是类Class 的一个实例。

您需要实例上下文。


我也很确定这个问题可以在没有任何方法修补巫毒的情况下解决。只需提供不同的对象(符合相同的 API。这称为“鸭子类型”)。

class ApplicationController

  def body_class
    @body_class ||= CompositeClass.new
  end

  class CompositeClass
    def initialize
      @classes = []
    end

    def <<(new_class)
      @classes << new_class
    end

    # I imagine, this is what is ultimately called on ApplicationController#body_class,
    # when it's time to render the class in the html.
    def to_s
      @classes.join(' ')
    end
  end
end

自然没有测试这段代码。

【讨论】:

  • 委托给一个数组很好。我实际上怀疑CompositeClass 是否需要,只需委托给本机Array 并提供一种build_class_string 方法。
  • @mudasobwa:请随时改进您的答案:)
  • 我都在打猴子补丁!我什至拒绝提炼!
  • 谢谢@SergioTulentsev !!
  • 我更喜欢这种组合而不是单例方法,尤其是当单例方法覆盖现有的记录方法 String#&lt;&lt; 时。但值得注意的区别是String#&lt;&lt;String#concat 在给定整数时会将其转换为字符,而您的解决方案将在输出时将其转换为String (#to_s)。我真正感兴趣的是如何不自然地测试代码? ;)
【解决方案2】:

顺便说一句,正确的做法是显式地extend 实例变量:

class A
  attr_reader :body_class
  def initialize
    @body_class = "".extend(Module.new do
      def <<(other)
        return self if self[/\b#{Regexp.escape(other)}\b/]
        concat(' ') unless empty?
        concat(other)
      end
    end)    
  end  
end

【讨论】:

    猜你喜欢
    • 2014-09-21
    • 2012-03-07
    • 2011-08-27
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-15
    • 2013-05-28
    相关资源
    最近更新 更多