Я действительно новичок в рубине, так что это вопрос начального уровня.
Короткий ответ: метод экземпляра login() в классе Bob скрывает метод toplevel login(). Простое решение: изменить имя одного из методов.
Вот некоторые вещи, которые вы должны попробовать, чтобы узнать:
1) В рубина, каждый метод вызывается с объекта на левой стороне, например,
some_obj.login
Объект на левой стороне, называется приемник.
2) Если вы явно не указываете приемник, например,
login('bob',pass) #No receiver is specified on the left hand side
... рубин использует переменную собственной на левой стороне, например:
self.login('bob', pass)
3) Внутри метода внутри класса, например:
class Bob
def login(pass)
#IN HERE
end
end
...self равно объекту, называемому методом. В вашем случае, у вас есть этот код:
bob = Bob.new
bob.login('world')
Так боб является объектом, который вызов метода экземпляра Логин(), и поэтому у вас есть это:
class Bob
def login(pass)
#IN HERE, self is equal to bob
end
end
Поэтому, рубин делает это:
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
Одно решение вашей проблемы, как Гильерме Карлос предложил, чтобы использовать модуль - но вы можете сделать это более простым способом:
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) Все разработчики прикрепляются к классу . Текущий класс определяется значением переменной self: если self является классом, то текущий класс является просто значением self, но когда self не является классом, то текущий класс является классом self. Хорошо, давайте посмотрим, эти принципы в действии:
class Bob
puts self #=>Bob
def login(pass)
...
end
end
Потому что само это класс, текущий класс равен себе, и Защита привязывается к классу Боба.
Что происходит на верхнем уровне?
puts self #=> main
def login(user,pass)
end
Опытные Рубисты знакомы с main
; это объект, который ruby присваивает себе на верхнем уровне, то есть вне любых определений классов или методов - то, что вы вызываете global. Важным моментом является то, что main
не является классом. В результате Войти верхний уровень() Защита присоединяется к классу главных, который является:
puts self #=>main
puts self.class #=>Object
def login(user,pass)
end
Брайан Дрисколл отметил, что рубин не имеет глобальный масштаб - но это не действительно важно, потому что в любом случае def создает новую область действия, которая закрывает внешнюю область видимости, поэтому внутри def не видно ничего, что существует за пределами def (кроме констант).
То, что вы пытаетесь сделать, часто делается в рубине с так называемыми блоками. Блоки позволяют вам передать второй метод первому методу, а затем в первом методе вы можете вызвать второй метод. Вот пример:
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
... который выглядит вроде как определение метода - но без имени. Это означает, что вы используете метод входа() верхнего уровня. Рубин автоматически переходит в блок методы, указанной перед блоком:
This method!
|
V
bob.login('my password')
И внутри методы Логина(), вы вызываете блок, используя слово yield
--Оы, как будто yield
были именем метода.
Обратите внимание, что это фактически sytnax ruby, то есть запись блока после вызова метода, который заставляет второй метод передаваться первому методу, а в первом методе вы можете вызвать переданный метод простым написанием yield(arg1, arg2, etc.)
,
Ruby действительно не имеет глобального масштаба. Ваше первое определение логина будет фактически привязано к объекту. Ознакомьтесь с принятым ответом на этот вопрос: http://stackoverflow.com/questions/1042384/how-do-you-use-global-variables-or-constant-values-in-ruby –
@BrianDriscoll: Вы имеете в виду к неправильному вопросу. Этот вопрос дублирует [этот вопрос] (https://stackoverflow.com/questions/9593514/how-to-call-a-method-from-the-global-scope-with-same-name-as-an- instance-method). – Surya
или этот вопрос: https://stackoverflow.com/questions/2681895/how-to-access-a-shadowed-global-function-in-ruby – Surya