Ruby 1.9.2:如何更改块的范围/绑定

时间:2012-01-25 08:37:30

标签: ruby block ruby-1.9.2

嗨,我有类似的事情:

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

问题是compose块trial_email内部未定义:

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

这是Ruby 1.9问题还是gmail gem问题?

我应该如何在compose块的范围内使这个方法“可见”?

更新 这是gmail gem的问题/特性 - ruby​​ 1.9块已经改变但不是这么多! 除了接受的答案之外,另一种解决方法是将数据作为方法参数传递:

def create(trial_email)
  ...
end

3 个答案:

答案 0 :(得分:4)

看起来像GMail问题给我。在块内,self将是来自GMail gem的一些对象,因此您可以拥有tofrom和类似的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
    #...

答案 1 :(得分:0)

您期望(正如您有权获得)该块应保留self的值,就像通常那样。看起来gmail gem在这里使用instance_exec,它允许它将块的self值更改为Mail::Message的实例(这就是为什么你可以调用to和{{即使你没有定义这样的方法,也可以在那个块中使用1}}

虽然from对于生成漂亮的DSL很方便,但它并非没有缺点。局部变量范围不受影响,因此您可以在块之前的本地变量中存储instance_exectrial_email,然后在块内使用该局部变量

答案 2 :(得分:0)

问题是你传递给compose方法的块后来被传递给Mail.new,最后传递给Message.new(如果我正确地跟踪了链),那么这个块被评估为那here

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