Set Ruby Variable If It Is Not Already Defined

Set Ruby variable if it is not already defined

While x ||= value is a way to say "if x contains a falsey value, including nil (which is implicit in this construct if x is not defined because it appears on the left hand side of the assignment), assign value to x", it does just that.

It is roughly equivalent to the following. (However, x ||= value will not throw a NameError like this code may and it will always assign a value to x as this code does not -- the point is to see x ||= value works the same for any falsey value in x, including the "default" nil value):

if !x
x = value
end

To see if the variable has truly not been assigned a value, use the defined? method:

>> defined? z
=> nil
>> z = nil
=> nil
>> defined? z
=> "local-variable"
>> defined? @z
=> nil
>> @z = nil
=> nil
>> defined? @z
=> "instance-variable"

However, in almost every case, using defined? is code smell. Be careful with power. Do the sensible thing: give variables values before trying to use them :)

Happy coding.

Set variable if not defined

You can do the following, beware of false values though

a ||= 100

Assign variable to backup if first condition is nil - ruby

EDIT:

I see now from the error that the problem isn't with your || operator, it's with your rsvp.purchases.map(&:coupon) method chaining. It's not finding a coupon for one of the purchases.

You can solve this by ensuring that purchases always have coupons with validations, or you can use the .try method from Rails.

Try method in Rails

Original

In Ruby, nil and false are the only things that are not truthy. So,
coupon will be equal to rsvp.purchases.map(&:coupon) unless rsvp.purchases.map(&:coupon) is equal to nil or false.

Can you be more specific and give examples about the error(s) that you are receiving?

Examples Below:

irb(main):019:0> coupon = nil || 1
=> 1
irb(main):020:0> coupon = "" || 1
=> ""
irb(main):021:0> coupon = false || 1
=> 1
irb(main):022:0> coupon = 4 || 1
=> 4
irb(main):023:0> coupon = OpenStruct.new || 1
=> #<OpenStruct>
irb(main):024:0> coupon = false || OpenStruct.new
=> #<OpenStruct>
irb(main):025:0> coupon = nil || OpenStruct.new
=> #<OpenStruct>

Checking if a variable is defined?

Use the defined? keyword (documentation). It will return a String with the kind of the item, or nil if it doesn’t exist.

>> a = 1
=> 1
>> defined? a
=> "local-variable"
>> defined? b
=> nil
>> defined? nil
=> "nil"
>> defined? String
=> "constant"
>> defined? 1
=> "expression"

As skalee commented: "It is worth noting that variable which is set to nil is initialized."

>> n = nil  
>> defined? n
=> "local-variable"

Set a Ruby variable and never be able to change it again?

They are called constants. A constant in Ruby is defined by a UPPER_CASE name.

VARIABLE = "foo"

It is worth to mention that, technically, in Ruby there is no way to prevent a variable to be changed. In fact, if you try to re-assign a value to a constant you will get a warning, not an error.

➜  ~  irb
2.1.5 :001 > VARIABLE = "foo"
=> "foo"
2.1.5 :002 > VARIABLE = "bar"
(irb):2: warning: already initialized constant VARIABLE
(irb):1: warning: previous definition of VARIABLE was here
=> "bar"

It's also worth to note that using constants will warn you if you try to replace the value of the constant, but not if you change the constant value in place.

2.1.5 :001 > VARIABLE = "foo"
=> "foo"
2.1.5 :002 > VARIABLE.upcase!
=> "FOO"
2.1.5 :003 > VARIABLE
=> "FOO"

In order to prevent changes to the value referenced by the constant, you can freeze the value once assigned.

2.1.5 :001 > VARIABLE = "foo".freeze
=> "foo"
2.1.5 :002 > VARIABLE.upcase!
RuntimeError: can't modify frozen String
from (irb):2:in `upcase!'
from (irb):2
from /Users/weppos/.rvm/rubies/ruby-2.1.5/bin/irb:11:in `<main>'
2.1.5 :003 > VARIABLE
=> "foo"

Here's an example inside a class.

class MyClass
MY_CONSTANT = "foo"
end

MyClass::MY_CONSTANT
# => "foo"

Ruby variable assignment in a conditional if modifier

Read it carefully :

Another commonly confusing case is when using a modifier if:

p a if a = 0.zero?

Rather than printing true you receive a NameError, “undefined local variable or method 'a'”. Since Ruby parses the bare a left of the if first and has not yet seen an assignment to a it assumes you wish to call a method. Ruby then sees the assignment to a and will assume you are referencing a local method.

The confusion comes from the out-of-order execution of the expression. First the local variable is assigned-to then you attempt to call a nonexistent method.

As you said - None return foo if (foo = bar.some_method) and return foo if (true && (foo = bar.some_method)) will work, I bet you, it wouldn't work, if you didn't define foo before this line.

In Ruby why won't `foo = true unless defined?(foo)` make the assignment?

Apparently, ruby creates local variable at parse time setting them to nilso it is defined and this is done whether the code is executed or not.

When the code is evaluated at your first line, it doesn't execute the assignment part since foo is set to nil. In the second line, because fooo has not been parsed yet, defined?returns nil letting the code inside the block execute and assign fooo.

As an example you can try this:

if false  
foo = 43
end
defined? foo
=> "local-variable"

This is taken from a forum post at ruby-forum.

Ruby variable definition

In Ruby, there is an ambiguity between referencing a local variable and a message send to the implicit receiver without an argument list. That means

foo

can either mean "dereference a local variable" or "send message foo to self without arguments", i.e. it could either be equivalent to

binding.local_variable_get(:foo)

or

self.foo()
# or
public_send(:foo)

This ambiguity is resolved at parse time. When the parser encounters an assignment to foo, it will, from that point on, treat foo as a local variable, regardless of whether or not the assignment actually gets executed. (That's something the parser cannot determine statically, after all. Just think about if rand > 0.5 then foo = 42 end.)

In a compiled language this wouldn't even compile.

There is no such thing as a compiled language. Compilation and interpretation are traits of the compiler or interpreter (duh!) not the language. Languages are neither compiled nor interpreted. They just are.

Every language can be implemented with a compiler and every language can be implemented with an interpreter. Most languages have both compiled and interpreted implementations (e.g. C has GCC and Clang, which are compilers, and Cint and Cling, which are interpreters, Haskell has GHC, which is a compiler, and Hugs, which is an interpreter).

Many modern language implementations have both in the same implementation, either in different phases (e.g. YARV and MRuby compile Ruby sourcecode to internal bytecode, and then interpret that bytecode), or in a mixed-mode engine (e.g. the HotSpot JVM both interprets and compiles JVM bytecode, depending on which makes more sense), or both (e.g. Rubinius compiles Ruby sourcecode to Rubinius bytecode in the first phase, and then both compiles that bytecode to native code and interprets it, depending on what makes more sense).

In fact, all currently existing Ruby implementations are compiled: YARV and MRuby compile to their own internal bytecode formats, Rubinius, MacRuby, MagLev and Topaz compile to their own internal bytecode formats, then compile that to native code, JRuby compiles to JVM bytecode (which the JVM may or may not compile further), IronRuby compiles to CIL bytecode (which the VES may or may not compile further).

The fact that Ruby behaves this way is because the language specification says so. Not because Ruby is "interpreted", because, actually, it is not. The only purely interpreted implementation of Ruby was MRI and very early versions of JRuby, and both have long since been retired.

Ruby: Variables defined in If/else statement are accessible outside of if/else?

Variables are local to a function, class or module defintion, a proc, a block.

In ruby if is an expression and the branches don't have their own scope.

Also note that whenever the parser sees a variable assignment, it will create a variable in the scope, even if that code path isn't executed:

def test
if false
a = 1
end
puts a
end

test
# ok, it's nil.

It's bit similar to JavaScript, though it doesn't hoist the variable to the top of the scope:

def test
puts a
a = 1
end

test
# NameError: undefined local variable or method `a' for ...

So even if what you were saying were true, it still wouldn't be nil.

Undeclared instance variables default to nil?

Per the Ruby doc:

Instance variables of ruby do not need declaration. This implies a flexible structure of objects. In fact, each instance variable is dynamically appended to an object when it is first referenced.

https://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/instancevars.html

You can also get a list of all previously defined instance variables:

ClassName.instance_variables

or

a = ClassName.new 
a.instance_variables #specific to instance


Related Topics



Leave a reply



Submit