Ruby中方法名称的限制是什么?
例如,我发现方法名称bundler?
在下面的片段中,不知道是否是?
字符是专门的关键字或只是方法名称的一部分。
# This is a predicate useful for the doc:guides task of applications. def bundler? # Note that rake sets the cwd to the one that contains the Rakefile # being executed. File.exists?('Gemfile') end
Ruby中的方法名可能包含大写和小写字母,数字,下划线_
和标点符号!
, ?
, =
。
方法名称不能以数字开头,而且字符!
, ?
和=
只能出现在最后。
非ASCII字符可以在方法名称中使用,但是这会导致非常混乱的情况,不应该是常见的做法。
这是一个很好的做法,虽然不是强制性的,但用小写字母开始方法名,因为以大写字母开头的名字在Ruby中是常量。 对一个方法来说,仍然可以使用一个常量名,但是如果没有括号,你将无法调用它,因为interpeter会查找这个名字作为常量:
def Capital nil end Capital # NameError: uninitialized constant Capital Capital() # => nil
定义方法名称时,一些非常广泛和一贯使用的约定是:
-
方法名称全部为大写,下划线
_
表示分隔符(例如Math::sqrt
,Array#each_index
,…)。 -
谓词有一个问号
?
作为最后一个字符(例如Array#empty?
,Hash#has_key?
, …)。 虽然谓词通常返回布尔值,但并非总是如此:如果谓词的计算结果为false,则这些方法只需返回nil
或false,否则返回任何其他值(例如,如果文件不存在,File::size?
将返回nil
,否则为Integer
的文件的大小)。 -
修改被调用对象的状态或者有不正常行为的方法有一个感叹号
!
作为最后的字符; 这个方法有时被称为mutators,因为它们通常是破坏性的或其他方法的原地版本(例如Array#sort!
,Array#slice!
…)。 -
Setters有一个等号
=
作为最后一个字符(例如Array#[]=
,…); Ruby interpeter提供了调用setter方法的语法糖 :a = [4, 5, 6] a[0] = 3 # Shorthand for a.[]=(0, 3)
Ruby还允许使用运算符符号定义运算符作为方法名称:
╔═══════════════════════════╦═════════════════════════════════════════════╦═══════╗ ║ Operators (by precedence) ║ Operations ║ Arity ║ ╠═══════════════════════════╬═════════════════════════════════════════════╬═══════╣ ║ ! ~ + ║ Boolean NOT, bitwise complement, unary plus ║ 1 ║ ║ ║ (define with method name +@, Ruby 1.9+) ║ ║ ║ ║ ║ ║ ║ ** ║ Exponentiation ║ 2 ║ ║ ║ ║ ║ ║ - ║ Unary minus (define with method name -@) ║ 1 ║ ║ ║ ║ ║ ║ * / % ║ Multiplication, division, modulo ║ 2 ║ ║ ║ ║ ║ ║ + - ║ Addition, subtraction ║ 2 ║ ║ ║ ║ ║ ║ << >> ║ Bitwise shift ║ 2 ║ ║ ║ ║ ║ ║ & ║ Bitwise AND ║ 2 ║ ║ ║ ║ ║ ║ | ^ ║ Bitwise OR, Bitwise XOR ║ 2 ║ ║ ║ ║ ║ ║ < <= => > ║ Ordering ║ 2 ║ ║ ║ ║ ║ ║ == === != =~ !~ <=> ║ Equality, pattern matching, comparison ║ 2 ║ ╚═══════════════════════════╩═════════════════════════════════════════════╩═══════╝
一元运算符方法不传递任何参数; 二元运算符方法传递一个参数,并对其进行操作。
严格遵守经营者的宗旨是很重要的。 虽然可以使用不同的参数定义运算符方法(例如,带有两个参数的+
方法),但Ruby不允许使用运算符语法来调用方法(但它将使用点语法)。
尽可能地坚持操作符的原始语义是一个很好的习惯:对于那些知道操作符原来的意义的人来说,应该是直观的,它是如何与用户定义的类一起工作的。
该语言还为通常用于访问数组和散列值的特殊非运算符 []
方法提供语法糖。 []
方法可以用任意的arity来定义。
对于表中的每个二元运算符,除了sorting,相等,比较和模式匹配外,Ruby还提供缩写赋值的简写(例如, x += y
展开为x = x + y
)。 你不能将它们定义为方法,但你可以改变它们的定义它们所基于的操作符的行为。
这些字符在正常的方法名称中都不能使用(例如do&print
或start-up
不是有效的方法名称)。
别人说内置的语法是正确的,但是如果使用define_method
+ send
类的方法,似乎没有什么后端的限制。
define_method(:'$% ^&') { 0 } define_method(:'你好') { 1 } send(:'$% ^&') == 0 or raise send(:'你好') == 1 or raise
这个事实可能是有用的:例如,Rails的ActiveSupport :: Testing :: Declarative.test方法使用它,以避免在以下方面进行复杂的转换:
test 'Some Controller#Method' do
到一个更清晰的名字,这可能会与另一个名为:
test 'Some Controller_Method' do
这在testing指南中提到。
好奇心:类似的事情发生在Java中,其中字节码方法名称比Java语言提供更多select: 为什么JVM允许我们命名以字节码中的数字开头的函数?
方法名称可以结束!
, ?
或=
。 下划线也是允许的。 除此之外,还有几种看起来像运算符的方法(例如+
, *
, >>
, []
),你可以为自己的类定义。
要添加一件事:你也可以告诉一个对象运行一个没有名字的方法,它将尝试调用一个名为call
的方法:
#!/usr/bin/env ruby class Foo =begin def call(*args) puts "received call with #{args.join(' ')}" end =end def method_missing(m, *args, &block) puts "received method_missing on `#{m}(#{args.join(', ')})`" end end f = Foo.new f.('hi') # Not a syntax error! method_missing with m of :call f.send :'', 'hmm' # method_missing with m set to :'' f.send nil, 'bye' # raises an error
实际上并没有任何名为call
方法定义在Object
,但Method
和Proc
类中有一个。
在一些语言中()
是函数调用的一个操作符,这和这里发生的事情很相似。
这是用在例如Rails的JBuilder中:
https://github.com/rails/jbuilder
它被logging在O'Reilly Ruby书籍的第196页上:
Ruby 1.9提供了一个调用
Proc
对象的方法。 作为方括号的替代方法,可以使用以句点为前缀的括号:z = f.(x,y)
.()
看起来像缺less方法名称的方法调用。 这不是一个可以定义的运算符,而是调用call
方法的语法糖。 它可以与定义call
方法的任何对象一起使用,并且不限于Proc
对象。
允许的字符是: aZ,
0-9
,只要不在开头, _
和?
(用于布尔函数)和!
(对于破坏性function)和=
(对于设置者)。