Ruby 1.9.2: Как изменить область видимости / привязку блока - PullRequest
1 голос
/ 25 января 2012

Привет, у меня есть что-то вроде следующего:

class TrialRequest

  attr_accessor :trial_email

  def initialize(email)
    @trial_email = email
    puts "Trial_email: #{trial_email}"
  end

  def create
    @email = ::Gmail.connect!(gmail_name, gmail_password) do |gmail|
      email = gmail.compose do
        to 'trial@domain.com'
        from trial_email
        subject trial_email
        text_part do
          content_type 'text/html; charset=UTF-8'
          body 'Sign me up.'
        end
      end
      #binding.pry
      gmail.deliver!(email)
    end
  end
end

Проблема в том, что внутри блока композита trial_email не определено:

NameError: undefined local variable or method `trial_email' for #<Mail::Message:0x0000000431b830>

Это проблема Ruby 1.9или проблема с гемом gmail?

Как мне сделать так, чтобы этот метод был "видимым" / в пределах блока создания?

Обновление: Это проблема/ особенность gmail gem - блоки ruby ​​1.9 изменились, но не так сильно!В дополнение к принятому ответу, другой обходной путь должен передать данные в качестве параметра метода:

def create(trial_email)
  ...
end

Ответы [ 3 ]

4 голосов
/ 25 января 2012

Похоже, проблема GMail для меня.Внутри блоков self будет некоторый объект из драгоценного камня GMail, так что вы можете иметь to, from и аналогичные возможности DSL.Вы должны иметь возможность поместить self.trial_email в локальную переменную и затем получить доступ к ней внутри блоков:

email_address = self.trial_email
@email = ::Gmail.connect!(gmail_name, gmail_password) do |gmail|
  email = gmail.compose do
    to 'trial@domain.com'
    from email_address
    subject email_address
    #...
0 голосов
/ 25 января 2012

Проблема в том, что блок, который вы передаете методу compose, позже передается в Mail.new и, наконец, в Message.new (если я правильно проследил цепочку), а затем этот блок оценивается как здесь * * 1006

instance_eval(&block)

Поскольку он выполняется внутри initialize метода другого объекта (экземпляр класса Message), у вас нет доступа к атрибутам вашего TrialRequest объекта.

Вы можете сделать то же самое, не испытывая подобных проблем:

email = gmail.compose
email.to = 'trial@domain.com'
email.from = trial_email
email.subject = trial_email

email.text_part do
  content_type 'text/html; charset=UTF-8'
  body 'Sign me up.'
end
0 голосов
/ 25 января 2012

Вы ожидаете (как вы имеете право), что блок должен сохранить значение себя, как обычно.Похоже, что гем gmail использует instance_exec, что позволяет ему изменить значение self для блока на экземпляр Mail::Message (именно поэтому вы можете вызывать to и from в этом блоке, даже есливы не определяете такие методы)

Хотя instance_exec удобен для создания хороших DSL, он не лишен недостатков.Область локальной переменной не затрагивается, поэтому вы можете сохранить либо trial_email, либо self в локальной переменной до блока, а затем использовать эту локальную переменную внутри блока

...