Ruby: Method Inexplicably Overwritten and Set to Nil

Ruby: method inexplicably overwritten and set to nil

Names on the left hand side of assignments get set to nil, even if the code can't be reached as in the if false case.

>> foo
NameError: undefined local variable or method `foo' for main:Object
...
>> if false
.. foo = 1
.. end #=> nil
>> foo #=> nil

When Ruby tries to resolve barewords, it first looks for local variables (there's a reference to that in the Pickaxe book, which I can't seem to find at the moment). Since you now have one called foo it displays nil. As Mischa noted, the method still can be called as foo().

Pass url params hash in controller to another method, becomes nil

The Ruby interpreter is treating params as a local variable and initializing it with nil when it sees the assignment. This happens before it executes the retrieve_id_if_missing.

This is why explicitly assigning a value to the local variable before calling the method avoids the error, because the initialization to nil by Ruby doesn't happen.

The following examples demonstrate this:

Example #1

def foo(bar)
puts "foo bar: #{bar.class}"
end
bar = foo(bar) # => nil
puts "bar: #{bar.class}"

# Outputs:
# foo bar: NilClass
# bar: bar: NilClass

Example #2

a = a # => nil
puts "a: #{a.class}"

# Outputs:
# a: NilClass

Example #3

a = 123 if a # => nil
puts "a: #{a.class}"

# Outputs:
# a: NilClass

References:

Why is a = a nil in Ruby?

Ruby interpreter initializes a local variable with nil when it sees an
assignment to it. It initializes the local variable before it executes
the assignment expression or even when the assignment is not reachable
(as in the example below). This means your code initializes a with nil
and then the expression a = nil will evaluate to the right hand value.

a = 1 if false a.nil? # => true The first assignment expression is not
executed, but a is initialized with nil.

Ruby: method inexplicably overwritten and set to nil

Here's another example:

a = 123 if a # => nil a # => nil We shouldn't be able to say if a
because we never set a, but Ruby sees the a = 123 and initializes a,
then gets to if a at which point a is nil

I'd consider it a quirk of the interpreter, really. Gary Bernhardt
makes fun of it in wat (https://www.destroyallsoftware.com/talks/wat)
with a = a

Variable declaration behavior in if clause Ruby

In ruby, the variables declared inside the if block have the exact same scope as the variables which are declared at the top level inside a method. Since the interpreter has gone through the line where it has seen bar, its fine with it.

What does the equal ('=') symbol do when put after the method name in a method definition?

That snippet defines a Virtual Attribute (or a "setter" method) so that "express_token" looks like an attribute, even though it's just the name of the method. For example:

class Foo
def foo=(x)
puts "OK: x=#{x}"
end
end
f = Foo.new
f.foo = 123 # => 123
# OK: x=123

Note that the object "f" has no attribute or instance variable named "foo" (nor does it need one), so the "foo=" method is just syntactic sugar for allowing a method call that looks like an assignment. Note also that such setter methods always return their argument, regardless of any return statement or final value.

If you're defining a top-level setter method, for example, in "irb", then the behavior may be a little confusing because of the implicit addition of methods to the Object class. For example:

def bar=(y)
puts "OK: y=#{y}"
end
bar = 123 # => 123, sets the variable "bar".
bar # => 123
Object.new.bar = 123 # => 123, calls our method
# OK: y=123
Object.public_methods.grep /bar/ # => ["bar="]

Rspec: object isn't receiving method call from class method test

The problem is that you set expectation on one user, but method call happens on another user. This one.

user = from_token token

You didn't show implementation of from_token, but I'm willing to bet that it loads user from database. Now, there may be only one user in the database and, logically, these two variables represent the same entity. But physically, they're still two different objects in memory. So, naturally, the expectation is not met.

rspec not_to change from not behaving as expected

I don't think it does quite what you expect, but the way the tests are written doesn't really expose this. Your last value fails because it was never defined as 1.

The main step in revealing this is inverting the test.

describe "stuff" do

it "should not change i" do
i = 0
expect {
i = 2
}.to change { i }
end

it "should not change i" do
i = 0
expect {
i = 2
}.to change { i }.from( 0 )
end

it "should not change i" do
i = 0
expect {
i = 2
}.to change { i }.from( 1 )
end

end

This results in the first two tests passing, and the last test failing with the error result should have initially been 1, but was 0

So if we take the problem test as it was, you are saying is i should not change from 1 and since i is never 1, this test will never fail.

it "should not change i" do
i = 0
expect {
i = 2
}.not_to change { i }.from( 1 ) # i goes from 0 to 2, not 1 to 2, so the test is valid
end

How can I run PHP script in certain interval (e.g. once a day)?

If you can't or don't want to use use cron and it's ok to update it only when the page is accessed. You could cache the result of the HTTP request and only update it on a page load it if the cache is older than a day or whatever interval you choose.



Related Topics



Leave a reply



Submit