关于 ruby 中常量的说明
Clarification about constants in ruby
我正在尝试构建一个休息客户端,因为很多几乎相同,我想我应该将操作放入一个模块中,然后扩展模块以获得那组操作并保留唯一位通过将它们定义为常量来分开,相同的常量但每条路线的设置不同所以最终结果是不同的 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
是常数,它永远不会改变,所以使用起来感觉不对一个实例变量,即使它确实有效。
我做过类似的事情,我在模块中定义了几个控制器操作(索引、创建等),然后在我想要的控制器中定义了 include MyModule
使用它们。
此时,在我的模块中,我可以调用 self.controller_name
来获取我的实际来源。
因此,与其尝试设置 Route_Name
,不如使用 self.controller_name.tableize
或 self.class.tableize
之类的方法推导它
正如您提到的 @route_name
是一个实例变量并且可以工作,但我认为您实际要寻找的是 @@route_name
这将使它成为 class 级别变量(每个 class,而不是每个实例一个)。
改用const_get
。这是一个方法调用(与通过静态名称查找相比)。意思是,它将从祖先层次结构的底部开始不断查找。
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"
@mtamhankar 关于从 class 名称派生路线有一个很好的观点。可能是这样的(使用来自 ActiveSupport 的 tableize
)
module Common
def list
"some_url/#{name.tableize}.json"
end
end
A ruby 方法从该方法的 owner
查找常量,而不是接收方或接收方的 class。当您访问常量时,ruby 解释器沿着调用模块的 Module.nesting
或 class.
查找常量
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 尝试在命名空间 A::B
中查找常量 X
(即尝试查找 A::B::X
),如果找到后,它会立即停止查找并 returns 该值。如果找不到,那么 ruby 会尝试在 A
中寻找 X
,如果仍然找不到,ruby 会尝试在顶级命名空间中寻找 X
,这是 Object
.
因为 classes 和模块有一个 class/module 方法 name
其中 returns class/module 的名称,你可以重构你的 Common
像这样的模块:
module Common
def list
"some_url/#{name.downcase}.json"
end
end
并歼灭所有Route_Name = 'xxx'
Ruby does constant lookup 首先按名称空间(大致:您嵌套它们的位置)然后按祖先(您继承的)。因为 list
是在 Common
中声明的,查找从 Common::Route_Name
开始,不能再继续了。
但是,当调用 list
时,它会在 Comments
或 Posts
上调用,让您可以通过 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
我正在尝试构建一个休息客户端,因为很多几乎相同,我想我应该将操作放入一个模块中,然后扩展模块以获得那组操作并保留唯一位通过将它们定义为常量来分开,相同的常量但每条路线的设置不同所以最终结果是不同的 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
是常数,它永远不会改变,所以使用起来感觉不对一个实例变量,即使它确实有效。
我做过类似的事情,我在模块中定义了几个控制器操作(索引、创建等),然后在我想要的控制器中定义了 include MyModule
使用它们。
此时,在我的模块中,我可以调用 self.controller_name
来获取我的实际来源。
因此,与其尝试设置 Route_Name
,不如使用 self.controller_name.tableize
或 self.class.tableize
@route_name
是一个实例变量并且可以工作,但我认为您实际要寻找的是 @@route_name
这将使它成为 class 级别变量(每个 class,而不是每个实例一个)。
改用const_get
。这是一个方法调用(与通过静态名称查找相比)。意思是,它将从祖先层次结构的底部开始不断查找。
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"
@mtamhankar 关于从 class 名称派生路线有一个很好的观点。可能是这样的(使用来自 ActiveSupport 的 tableize
)
module Common
def list
"some_url/#{name.tableize}.json"
end
end
A ruby 方法从该方法的 owner
查找常量,而不是接收方或接收方的 class。当您访问常量时,ruby 解释器沿着调用模块的 Module.nesting
或 class.
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 尝试在命名空间 A::B
中查找常量 X
(即尝试查找 A::B::X
),如果找到后,它会立即停止查找并 returns 该值。如果找不到,那么 ruby 会尝试在 A
中寻找 X
,如果仍然找不到,ruby 会尝试在顶级命名空间中寻找 X
,这是 Object
.
因为 classes 和模块有一个 class/module 方法 name
其中 returns class/module 的名称,你可以重构你的 Common
像这样的模块:
module Common
def list
"some_url/#{name.downcase}.json"
end
end
并歼灭所有Route_Name = 'xxx'
Ruby does constant lookup 首先按名称空间(大致:您嵌套它们的位置)然后按祖先(您继承的)。因为 list
是在 Common
中声明的,查找从 Common::Route_Name
开始,不能再继续了。
但是,当调用 list
时,它会在 Comments
或 Posts
上调用,让您可以通过 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