澄清红宝石中的常数

时间:2015-08-05 13:53:51

标签: ruby constants

我正在尝试构建一个休息客户端,因为很多事情几乎相同,我认为我将这些操作放入模块中,只是扩展模块以获取该组操作并保持通过将它们定义为常量,相同的常量来分隔唯一的位,但每条路径的设置都不同,因此最终结果是不同的URL,但操作相同。

module Common
    def list
        "some_url/#{Route_Name}.json"
    end
end

class Posts
    extend Common
    Route_Name = 'posts'
end

class Comments
    extend Common
    Route_Name = 'comments'
end


Comments.list
#=> "some_url/comments.json"  what I expect to be outputted

但它只是错误,在这个例子中它会错误uninitialized constant Common::Route_Name

如何让Route_Name成为我期望的目标?

编辑:

我通过将Route_Name更改为@route_name来解决了这个问题,但问题是Route_Name是不变的,它永远不会改变,所以感觉不对实例变量,即使它确实有效。

5 个答案:

答案 0 :(得分:2)

Ruby does constant lookup首先是命名空间(粗略地说:你已经嵌套了它们),然后是祖先(你从中继承过的)。由于在list中声明Common,因此查询以Common::Route_Name开头,无法继续查询。

但是,当list被调用时,它会在CommentsPosts上被调用,让您通过self访问这些内容。您可以使用self::Route_Name在您想要的地方进行查找,而不是让Ruby自己查找常量。

module Common
  def list
    "some_url/#{self::Route_Name}.json"
  end
end

class Posts
  extend Common
  Route_Name = 'posts'
end

class Comments
  extend Common
  Route_Name = 'comments'
end

puts Comments.list #=> some_url/comments.json
puts Posts.list    #=> some_url/posts.json

答案 1 :(得分:1)

我做过类似的事情,我在模块中定义了几个控制器动作(索引,创建等等),然后在控制器中只有include MyModule想要使用它们。

此时,在我的模块中,我可以致电self.controller_name以获取我实际来自的地方。

因此,您可以使用Route_Nameself.controller_name.tableize

之类的内容来设置self.class.tableize,而不是尝试设置setBackgroundDrawable()

答案 2 :(得分:1)

请改用@@route_name。这是一个方法调用(与静态名称查找相比)。这意味着,它将从祖先层次结构的底部开始持续查找。

const_get

@mtamhankar关于从类名派生路线有一个很好的观点。也许是这样的(使用ActiveSupport中的module Common def list "some_url/#{const_get('Route_Name')}.json" end end class Posts extend Common Route_Name = 'posts' end class Comments extend Common Route_Name = 'comments' end Comments.list # => "some_url/comments.json"

tableize

答案 3 :(得分:0)

你提到的

-ExpandProperty是一个实例变量并且可以工作,但我认为你实际需要的是@route_name,它会使它成为一个类级变量(每个类一个,而不是每个实例)。

答案 4 :(得分:0)

ruby​​方法从该方法的owner中查找常量,而不是接收器或接收器的类。当您访问常量时,ruby解释器会在调用模块或类的Module.nesting中查找常量。

X = 0

module A
  X = 1

  module B
    p Module.nesting  #=> [A::B, A]

    X = 2

    def self.x
      X
    end
  end
end

A::B.x  # Try commenting out any 'X = ?' to see the difference

当您调用A::B.x时,ruby会尝试在命名空间X中找到常量A::B(即尝试查找A::B::X),如果找到,则会停止查找并立即返回该值。如果找不到,那么ruby会尝试在X内找到A,如果仍然不是fount,则ruby会尝试在顶级命名空间中找到X,即Object。< / p>

由于类和模块有一个类/模块方法name,它返回类/模块的名称,你可以像这样重构Common模块:

module Common
  def list
    "some_url/#{name.downcase}.json"
  end
end

并消灭所有Route_Name = 'xxx'