我真的是 ruby 新手,所以这是一个入门级问题。
简短的回答是:Bob 类中的 login() 实例方法隐藏了顶层 login() 方法。简单的解决方案是:更改其中一种方法的名称。
以下是一些你应该尝试学习的东西:
1) 在 ruby 中,每个方法都使用左侧的对象调用,例如
some_obj.login
左侧的对象称为接收者。
2) 如果您没有明确指定接收者,例如
login('bob',pass) #No receiver is specified on the left hand side
...ruby 在左侧使用一个名为 self 的变量,例如:
self.login('bob', pass)
3) 在类内部定义的方法内,例如:
class Bob
def login(pass)
#IN HERE
end
end
...self 等于调用该方法的对象。在您的情况下,您有以下代码:
bob = Bob.new
bob.login('world')
所以 bob 是调用 login() 实例方法的对象,因此你有这个:
class Bob
def login(pass)
#IN HERE, self is equal to bob
end
end
因此,ruby 会这样做:
class Bob
def login(pass)
#login('bob', pass) =>This line gets converted to this:
self.login('bob',pass) #ERROR#
#IN HERE, self is equal to bob
#So ruby executes this:
#bob.login('bob', pass) #ERROR: too many arguments#
end
end
像 Guilherme Carlos 建议的那样,解决您的问题的一种方法是使用模块——但您可以通过更简单的方式做到这一点:
module MyAuthenticationMethods
def login(user, pass)
puts "user: #{user}, pass: #{pass}"
end
end
class Bob
def login(pass)
MyAuthenticationMethods::login('bob',pass)
end
end
然而,通常你把一个模块放在它自己的文件中,然后require它。模块解决您的问题的原因是模块名称以大写字母开头,这意味着它是一个常量——您可以从代码中的任何位置访问一个常量。
4) 所有 def 都将自己附加到 当前类。当前类由self变量的值决定:如果self是一个类,那么当前类就是self的值,但是当self不是一个类时,那么当前类就是self的类。好的,让我们看看这些原则的实际应用:
class Bob
puts self #=>Bob
def login(pass)
...
end
end
因为self是一个类,所以当前类等于self,def将自己附加到Bob类。
顶层会发生什么?
puts self #=> main
def login(user,pass)
end
经验丰富的红宝石师熟悉main;它是 ruby 在顶层分配给 self 的对象,即在任何类或方法定义之外——你称之为 global。重要的一点是main 不是一个类。结果,顶层 login() def 将自己附加到 main 的类,即:
puts self #=>main
puts self.class #=>Object
def login(user,pass)
end
Brian Driscoll 提到 ruby 没有全局作用域——但这并不重要,因为 def 创建了一个新的作用域来关闭外部作用域,因此在 def 之外存在的任何内容在def(常量除外)。
您尝试做的事情通常是在 ruby 中使用所谓的 blocks 完成的。块允许您将第二种方法传递给第一种方法,然后在第一种方法中您可以调用第二种方法。这是一个例子:
class Bob
def login(pass)
yield('bob', pass) #yield calls the block with the specified arguments
end
end
bob = Bob.new
bob.login('my password') do |username, pword|
puts username, pword
end
该代码中的块是这部分:
do |username, pword|
puts username, pword
end
...看起来有点像方法定义——但没有名称。那是您的* login() 方法的替代品。 Ruby 自动将块传递给块之前指定的方法:
This method!
|
V
bob.login('my password')
在 login() 方法中,您使用单词yield 调用块——就好像yield 是方法的名称。
注意实际上是ruby的sytnax,即在方法调用之后写一个块,导致第二个方法被传递给第一个方法,在第一个方法中你可以通过简单地写@987654340来调用传入的方法@。