Ruby - код, кто-то объяснит следующий код - PullRequest
0 голосов
/ 01 апреля 2019

У меня есть следующий фрагмент кода в библиотеке . Может ли кто-нибудь объяснить, что означает код ("# {k} =") в следующем фрагменте кода?

if respond_to?("#{k}=")
  public_send("#{k}=", v)
else
  raise UnknownAttributeError.new(self, k)
end

Я понимаю, что response_to - это функция по умолчанию в Ruby, но для этого синтаксиса нет определения / объяснения, пожалуйста, помогите нам.

Отредактировано:

Я получаю исключение (unknown attribute 'token' for PersonalAccessToken. (ActiveModel::UnknownAttributeError)) для вышеуказанного кода

/opt/gitlab/embedded/lib/ruby/gems/2.5.0/gems/activemodel-5.0.7.1/lib/active_model/attribute_assignment.rb:40:in `block in _assign_attributes'
/opt/gitlab/embedded/lib/ruby/gems/2.5.0/gems/activemodel-5.0.7.1/lib/active_model/attribute_assignment.rb:48:in `_assign_attribute': unknown attribute 'token' for PersonalAccessToken. (ActiveModel::UnknownAttributeError)

поэтому рассматривая k как 'токен', в каком сценарии я получу исключение (в каком сценарии он переходит в состояние else?)

Ответы [ 3 ]

1 голос
/ 01 апреля 2019

Этот код public_send("#{k}=", v) динамически вызывает установщик того, что хранится в переменной k.Рассмотрим следующий пример:

class FooBarBaz
  attr_accessor :foo, :bar, :baz

  def set_it what, value
    public_send("#{what}=", value)
  end
end

Это примерно эквивалентно:

  def set_it what, value
    case what
    when "foo" then public_send("foo=", value)
    when "bar" then public_send("bar=", value)
    when "baz" then public_send("baz=", value)
    end
  end

Это примерно эквивалентно:

  def set_it what, value
    case what
    when "foo" then self.foo=(value)
    ...
    end
  end

Это примерно эквивалентно:

  def set_it what, value
    case what
    when "foo" then self.foo = value
    ...
    end
  end

respond_to? вызывается заранее, чтобы проверить, действительно ли сеттер определен для этого k в этом случае, чтобы предотвратить что-то вроде:

FooBarBaz.new.set_it :inexisting, 42
#⇒ NoMethodError: undefined method `inexisting=' for #<FooBarBaz:0x0056247695a538>

Измененная, правильная версия класса в этом ответе:

class FooBarBaz
  attr_accessor :foo, :bar, :baz

  def set_it what, value
    public_send("#{what}=", value) if respond_to?("#{what}=")
  end
end

Не выдает исключение.

FooBarBaz.new.set_it :inexisting, 42
#⇒ nil
0 голосов
/ 02 апреля 2019

Я думаю, что вы видели _assign_attribute метод в этом документе

k - это аббревиатура, означающая «ключ», v - это то же самое, что и «значение»

"#{k}=" - это некое имя метода для динамического метода в виде строкового литерала.

Это может быть "update" или "create", "split", что угодно еще.

EqualСимвол ("=") означает, что они являются методами присвоения чего-то подобного user.attributes = { :username => 'Phusion', :is_admin => true }

. В вышеприведенном случае "k" равно .attributes, а "k =" равно attributes= и "v"is { :username => 'Phusion', :is_admin => true }

и public_send - это метод для отправки метода в публичной области.

В результате public_send("#{k}=", v) означает вызов метода с именем как" k "в публичном методе, и этому методу будет присвоено значение "v".

Я надеюсь, что это объяснение поможет вам.


Добавьте пример для комментария

k является вводом от программиста, поэтому он не совпадает с именем метода в классе или модуле.

В реальности существуют распространенные ошибки.

class User
  # this attribute can be called from a instance of User
  attr_accessor :name
end

# this causes a error when call assign_attribute
User.new.wrong_name

# this is fine
User.new.name

ссылка на метод присвоения

0 голосов
/ 01 апреля 2019

"# {}" - интерполяция строки в ruby.так, например:

k = 'world'
puts "hello #{k}"
# hello world

Итак, в вашем примере это выглядит как создание строки со значением k и =

например,

k = 'something'
"#{k}="
# something=

Если выЕсли вы хотите узнать, что такое k, вы можете добавить puts k.to_s в строке выше, затем запустить код и проверить вашу консоль.

Еще лучше, если вы используете что-то вроде RubyMine, просто используйте отладчик и вставьте точку останована этой линии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...