我正在创建一个gem来支持命令行中的一些邮件.我用了一些宝石.我正在使用Mail Gem.正如你在描述中看到的那样mail gem是这样的.
mail = Mail.new do
from 'mikel@test.lindsaar.net'
to 'you@test.lindsaar.net'
subject 'This is a test email'
body File.read('body.txt')
end
Run Code Online (Sandbox Code Playgroud)
在块中,我从Mail类中调用方法(from,to,subject,body).这是有道理的,所以我在我自己的邮件程序类中构建它
def initialize(mail_settings, working_hours)
@mail_settings = mail_settings
@working_hours = working_hours
@mailer = Mail.new do
to mail_settings[:to]
from mail_settings[:from]
subject mail_settings[:subject]
body "Start #{working_hours[:start]} \n\
Ende #{working_hours[:end]}\n\
Pause #{working_hours[:pause]}"
end
end
Run Code Online (Sandbox Code Playgroud)
这看起来很直接.只需调用块并填写我通过构造函数获取的值.现在是我的问题.
我试图把邮件的主体结构分成一个单独的方法.但我不能Mail在gem 的构造函数中使用它.
module BossMailer
class Mailer
def initialize(mail_settings, working_hours)
@mail_settings = mail_settings
@working_hours = working_hours
@mailer = Mail.new do
to mail_settings[:to]
from mail_settings[:from]
subject mail_settings[:subject]
body mail_body
end
end
def mail
@mailer.delivery_method :smtp, address: "localhost", port: 1025
@mailer.deliver
end
def mail_body
"Start #{working_hours[:start]} \n\
Ende #{working_hours[:end]}\n\
Pause #{working_hours[:pause]}"
end
end
Run Code Online (Sandbox Code Playgroud)
结束
这意味着我不能@a在这个块中使用我的类方法或类变量(以...开头).
问题
块中执行的顺序是什么?如果我设置我的变量@mail_settings,我不能在块中使用它.Ruby @mail_settings在Mail类中我在哪里搜索块?为什么我可以BossMailer::Mailer通过块使用构造函数中的给定参数,并且不会出现错误?
如果我使用和变量将内容解析为块,为什么这会起作用?(body_content = mail_body)有效!
def initialize(mail_settings, working_hours)
@mail_settings = mail_settings
@working_hours = working_hours
body_content = mail_body
@mailer = Mail.new do
to mail_settings[:to]
from mail_settings[:from]
subject mail_settings[:subject]
body body_content
end
end
Run Code Online (Sandbox Code Playgroud)
这都是关于上下文的。
mail = Mail.new do
from 'mikel@test.lindsaar.net'
to 'you@test.lindsaar.net'
subject 'This is a test email'
body File.read('body.txt')
end
Run Code Online (Sandbox Code Playgroud)
from、to方法(以及其余的)是Mail::Message实例上的方法。为了能够以这种良好的 DSL 方式调用它们,传递给构造函数的块是instance_eval'ed。
这意味着在这个块内,self不再是您的邮件程序,而是邮件消息。因此,您的邮件程序方法无法访问。
instance_eval他们可以只使用yield或来代替block.call,但这不会使 DSL 成为可能。
至于局部变量起作用的原因:这是因为 ruby 块是词法范围的闭包(这意味着,它们保留其声明的局部上下文。如果有一个从定义块的位置可见的局部变量,它会记住该变量及其调用块时的值)
不要使用块形式。使用这个: https: //github.com/mikel/mail/blob/0f9393bb3ef1344aa76d6dac28db3a4934c65087/lib/mail/message.rb#L92-L96
mail = Mail.new
mail['from'] = 'mikel@test.lindsaar.net'
mail[:to] = 'you@test.lindsaar.net'
mail.subject 'This is a test email'
mail.body = 'This is a body'
Run Code Online (Sandbox Code Playgroud)
尝试注释/取消注释某些行。
class Mail
def initialize(&block)
# block.call(self) # breaks DSL
instance_eval(&block) # disconnects methods of mailer
end
def to(email)
puts "sending to #{email}"
end
end
class Mailer
def admin_mail
# get_recipient = 'vasya@example.com'
Mail.new do
to get_recipient
end
end
def get_recipient
'sergio@example.com'
end
end
Mailer.new.admin_mail
Run Code Online (Sandbox Code Playgroud)