Why Can't The Mail Block See My Variable

Why can't the Mail block see my variable?

As Julik says, Mail#delivery executes your block using #instance_exec, which simply changes self while running a block (you wouldn't be able to call methods #to and #from inside the block otherwise).

What you really can do here is to use a fact that blocks are closures. Which means that it "remembers" all the local variables around it.

recipient = params[:email]
Mail.deliver do
to recipient # 'recipient' is a local variable, not a method, not an instance variable
...
end

Again, briefly:

  • instance variables and method calls depend on self
  • #instance_exec changes the self;
  • local variables don't depend on self and are remembered by blocks because blocks are closures.

Why i can't access my variable declared in package from sub declared in the same package in Perl?

You call Util::mysub() several lines prior to assigning to the file scoped $var.

If your package were in a seperate file, the use statement and its implied BEGIN block would give the assignment priority. Alternatively, you could put the package definition first or use your own BEGIN block.

Why outside of block swift can't see value assigned to a uninitialized variable in the block?

Well, the message is not very helpful, and that's the problem. This pattern (which I call computed initialization) is perfectly legal and useful and — amazingly — you can even use let instead of var. But you must initialize the uninitialized variable by all possible paths before you use it. So you have:

var v:String
if true {
v = "Hello"
}
print(v) // error

But hold my beer and watch this:

var v:String
if true {
v = "Hello"
} else {
v = "Goodbye"
}
print(v) // fine!

Or even:

let v:String
if true {
v = "Hello"
} else {
v = "Goodbye"
}
print(v) // fine!

Amazing, eh?

Now, you might say: OK, but true will always be true so it's silly to make me fulfill the "all paths" rule. Too bad! The compiler insists anyway, and then lets you off later with a warning that the else won't be executed. But a warning lets you compile; an error doesn't. The truth is that your example is very artificial. But this is a real-life possibility:

let v:String
if self.someBoolProperty {
v = "Hello"
} else {
v = "Goodbye"
}
print(v) // fine!

Not only is this sort of thing legal, it is actually the pattern that Apple recommends under certain slightly tricky circumstances. For instance, it is used in Apple's own example code showing how to use the Swift 5 Result struct:

let result: Result<Int, EntropyError>
if count < AsyncRandomGenerator.entropyLimit {
// Produce numbers until reaching the entropy limit.
result = .success(Int.random(in: 1...100))
} else {
// Supply a failure reason when the caller hits the limit.
result = .failure(.entropyDepleted)
}

Undefined Variable Inside Mail::send in Laravel 5

The block of the closure (your function that sends the email) has not visibility of the outside block's scope.

So, if you want to access the variable from inside the closure, you have to explicitly pass it to the closure with the use keyword; like this:

Mail::send( 'emails.signed-notif', 
['order_num' => $notif[0]->order_number],
function($m) use ($notif) /* here you're passing the variable */
{
$m->to('mis@qdf-phils.com', '')->subject('Customer Order'.$notif[0]->order_number.' is now signed');
} );

For more info on anonymous functions and closures check here

What is the order of using blocks in Ruby

It's all about the context.

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

from, to methods (and the rest) are methods on Mail::Message instance. For you to be able to call them in this nice DSL-manner, the block you pass to constructor is instance_eval'ed.

What this means is that inside of this block, self is no longer your mailer, but a mail message instead. As a result, your mailer method is not accessible.

Instead of instance_eval, they could have just yield or block.call, but this wouldn't make the DSL possible.

As to why the local variable works: it's because ruby blocks are lexically-scoped closures (meaning, they retain local context of their declaration. If there was a local variable visible from where the block is defined, it'll remember the variable and its value when the block is called)

Alternative approach

Don't use the block form. Use this: 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'

Code

Try commenting/uncommenting some lines.

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

Twig (Symfony2) doesn't see variable in 'extend' block

This will work:

{% set layout = app.request.isXmlHttpRequest ? '::base-ajax.html.twig' : '::base.html.twig' %}
{% extends layout %}


Related Topics



Leave a reply



Submit