2012-05-10 24 views
40

例如,我在下面的代码片段中找到方法名称bundler?,并且不知道?字符是专用关键字还是方法名称的一部分。Ruby中方法名称的限制是什么?

# 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 

回答

72

Ruby中的方法名可能包含大写和小写字母,数字,下划线_和标点符号!,?,=

方法名称不能以数字开头,字符!,?=只能出现在最后。

非ASCII字符可以在方法名称中使用,但是这可能会导致非常混乱的情况下,不应该是普遍的做法。

这是很好的做法,而不是强制性的,用小写字母开头的方法的名称,因为以大写字母开头的名称是用Ruby常量。它仍然可以使用恒定的名称的方法,但你不能调用它没有括号,因为interpeter将查找的名称为常量:

def Capital 
    nil 
end 

Capital # NameError: uninitialized constant Capital 
Capital() # => nil 

一些非常广泛和坚持使用约定当定义方法的名称是:

  1. 方法名是全降的情况下,用下划线_作为的话将其命名为分隔符(如Math::sqrtArray#each_index,...)。

  2. 谓词有一个问号?作为最后一个字符(例如Array#empty?Hash#has_key?,...)。虽然谓语通常返回布尔值,这并非总是如此:这些方法只需要返回nilfalse如果谓词为假,任何其他值,否则(例如File::size?返回nil如果文件不存在,的大小否则为Integer)。

  3. 修改其被调用对象的状态或具有不正常行为的方法的最后一个字符为感叹号!;这种方法有时被称为变异体,因为它们通常是破坏性或其他方法的原地版本(例如Array#sort!,Array#slice!,...)。

  4. 塞特斯具有等号=作为最后一个字符(例如Array#[]=,...);红宝石interpeter提供语法糖用于setter方法invokation:

    a = [4, 5, 6] 
    a[0] = 3 # Shorthand for a.[]=(0, 3) 
    

红宝石还允许使用操作符号作为方法名定义操作符:

╔═══════════════════════════╦═════════════════════════════════════════════╦═══════╗ 
║ Operators (by precedence) ║     Operations     ║ Arity ║ 
╠═══════════════════════════╬═════════════════════════════════════════════╬═══════╣ 
║ ! ~ +      ║ Boolean NOT, bitwise complement, unary plus ║  1 ║ 
║       ║ (define with method name [email protected], Ruby 1.9+)  ║  ║ 
║       ║            ║  ║ 
║ **      ║ Exponentiation        ║  2 ║ 
║       ║            ║  ║ 
║ -       ║ Unary minus (define with method name [email protected]) ║  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 ║ 
╚═══════════════════════════╩═════════════════════════════════════════════╩═══════╝ 

一元运算符的方法是没有任何争论;二元运算符方法传递一个参数,并对其进行操作并在self上运行。

严格遵守运营商的元数是很重要的;虽然可以使用不同的参数定义运算符方法(例如,带有两个参数的+方法),但Ruby不允许您使用运算符语法调用该方法(但它可以使用点语法)。

这是坚持以尽可能多地运营商的原始语义很好的做法:它应该是直观的人谁知道它是如何使用用户定义的类运营商的本义。

该语言还为特殊语言提供语法糖,非运算符,[]通常用于访问数组和散列值的方法。 []方法可以用任意的arity来定义。对于表中的每个二元运算符,除了排序,相等,比较和模式匹配外,Ruby还提供缩写赋值的简写(例如,x += y扩展为x = x + y);你不能将它们定义为方法,但你可以改变它们的定义它们所基于的操作符的行为。

这些字符都不能在常规方法名称内使用(例如,do&printstart-up不是有效的方法名称)。

+1

很好的答案!稍作说明:谓词方法(带'?')返回falsey('nil'或'false')或truethy(其他所有)值是习惯性的,而不是必须的'true'和'false'。返回值旨在用于'if'语句,其行为就像'true'和'false'一样,但实际返回值通常不是预期的方法接口的一部分,只是它是真实或虚假的属性。 –

+0

感谢您的建议,我做了相应的编辑。 –

+0

还有一些字符只能用作整个方法的名字,也就是说你可以定义一个名为 - + * ** /(如果你重载了那些运算符)的方法,而不是一个叫做foo + bar的方法 –

0

允许的字符是:a-Z,0-9只要不是开头,_,并?(布尔函数)和!(破坏性功能)和=(对于设置器)。

2

方法名称可以在!,?=处结束。下划线也是允许的。除此之外,还有几种看起来像您可以为您自己的类定义的运算符(例如,+,*,>>,[])。

4

别人说什么是真正的内置语法,但有似乎是,如果你使用的方法是什么,可以使用任何后端限制像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 Guide上提到的。

好奇:类似的事情发生在Java中,当字节码方法名让位更多的选择比Java语言:Why does the JVM allow us to name a function starting with a digit in bytecode?

2

要补充说明一两件事:你也可以告诉一个对象与运行的方法没有名都,它会尝试调用的方法命名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 

没有实际命名上Object定义call任何方法,但有一个在MethodProc类。

在某些语言中,()是一个函数调用的运算符,它看起来与这里发生的事情非常相似。

这用于例如在Rails的JBuilder中:

https://github.com/rails/jbuilder

据记载O'Reilly的红宝石书的196页:

的Ruby 1.9提供了一个额外的方式来调用一个Proc对象;作为替代方括号中,你可以使用一个周期前缀括号:

z = f.(x,y) 

.()看起来像一个方法调用缺少方法名。这不是一个可以定义的运算符,而是调用call方法的语法糖。它可以用于定义方法的任何对象,并且不限于Proc对象。

相关问题