I have run to the following code and I have no idea what it does. Why do they use = to compare values or are they assigning values and checking if the value is true after being assigned?
if value = (key rescue nil)
..
end
This is equivalent to:
value = key rescue nil
if value
..
end
or
value = begin
key
rescue
nil
end
if value
..
end
Remember nil and false are the only two objects that are falsey in ruby and since value here could be nil, that if statement could return false.
Related
Can someone please explain this behavior? Why does nil return true when result = true if i but returns false when result = false unless i
unless case screenshot
def my_all?(pattern = nil)
result = true
my_each do |i|
case pattern
when nil
p result, i
result = false unless i
when Regexp
result = false unless i.to_s.match(pattern)
when Class
result = false unless i.is_a?(pattern)
when String, Numeric
result = false unless i == pattern
end
result = yield(i) if block_given? && pattern.nil?
break if !result
end
result
end
if case screenshot
def my_all?(pattern = nil)
result = false
my_each do |i|
case pattern
when nil
p result, i
result = true if i
when Regexp
result = true if i.to_s.match(pattern)
when Class
result = true if i.is_a?(pattern)
when String, Numeric
result = true if i == pattern
end
result = yield(i) if block_given? && pattern.nil?
break if !result
end
result
end
In your second example, once result is set to true, nothing ever sets it to false again. So if the first value yielded from my_each is truthy, then the my_all? method will return true.
This second example seems like more like an implementation of any?, rather than all?. Except it is actually only checking the first element. If the first i is falsey, then the loop will be broken and it will return false. If the first i is truthy, then it will be set to true and nothing will set it back to false, and the method will return `true.
See these two examples, where the only difference is the values yielded by my_each:
Returns true (first value is truthy)
Returns false (first value is falsey)
If a = false and b = 2 is there a concise way to accomplish this? Using just return a unless b returns 'nil' instead of '2'.
I have
def checkit
return a unless b
b
end
Will this statement call b twice?
A real life case for this is:
def current_user
#current_user ||= authenticate_user
end
def authenticate_user
head :unauthorized unless authenticate_from_cookie
end
def authenticate_from_cookie
.
if user && secure_compare(user.cookie, cookie)
return user
else
return nil
end
end
Try this:
( b == true ) ? a : false
where a is a value you need to return
I do not know why you have false stored in the variable a, so I omitted that. As I understand, you want to pass a value to the method checkit, which should return the value if its boolean value is true (which means everything except values nil and false), and otherwise return the value. In that case, just use this:
def checkit(value)
value || false
end
checkit(1) # => 1
checkit(false) # => false
checkit('value') # => "value"
checkit(nil) # => false
I have seen and used by myself lots of ||= in Ruby code, but I have almost never seen or used &&= in practical application. Is there a use case for &&=?
Not to be glib, but the obvious use case is any time you would say x && foo and desire the result stored back into x. Here's one:
list = [[:foo,1],[:bar,2]]
result = list.find{ |e| e.first == term }
result &&= result.last # nil or the value part of the found tuple
any sort of iteration where you want to ensure that the evaluation of a boolean condition on all elements returns true for all the elements.
e.g.
result = true
array.each do |elem|
# ...
result &&= condition(elem) # boolean condition based on element value
end
# result is true only if all elements return true for the given condition
Validation of the document such as,
a = {'a' => ['string',123]}
where the element in a['a'] should be a String. To validate them, I think you can use,
def validate(doc, type)
valid = true
doc.each{|x|
valid &&= x.is_a? type
}
valid
end
1.9.3p392 :010 > validate(a['a'],String) => false
In Ruby, how do you set a variable to a certain value if it is not already defined, and leave the current value if it is 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.
#variable ||= "set value if not set"
So false variables will get overridden
> #test = true
=> true
> #test ||= "test"
=> true
> #test
=> nil
> #test ||= "test"
=> "test"
> #test = false
=> false
> #test ||= "test"
=> "test"
As you didn't specify what kind of variable:
v = v
v ||= 1
Don't recommend doing this with local variables though.
Edit: In fact v=v is not needed
If the variable is not defined (declared?) it doesn't exist, and if it is declared then you know how you initialized it, right?
Usually, if I just need a variable whose use I don't yet know---that I know will never use as a Boolean---I initialize it by setting its value to nil. Then you can test if it has been changed later quite easily
x = nil
some code
if x do
[code that will only run if x has changed]
end
that's all.
This question already has answers here:
How to avoid NoMethodError for missing elements in nested hashes, without repeated nil checks?
(16 answers)
Closed 7 years ago.
What's the most concise way to determine if #hash[:key1][:key2] is defined, that does not throw an error if #hash or #hash[:key1] are nil?
defined?(#hash[:key1][:key2]) returns True if #hash[:key1] exists (it does not determine whether :key2 is defined)
When using ActiveSupport (Rails) or Backports, you can use try:
#hash[:key1].try(:fetch, :key2)
You could even handle #hash being nil:
#hash.try(:fetch, :key1).try(:fetch, :key2)
If you want #hash to always return a hash for a missing key:
#hash = Hash.new { |h,k| h[k] = {} }
#hash[:foo] # => {}
You could also define this recursive:
def recursive_hash
Hash.new { |h,k| h[k] = recursive_hash }
end
#hash = recursive_hash
#hash[:foo][:bar][:blah] = 10
#hash # => {:foo => {:bar => {:blah => 10}}}
But to answer your question:
module HasNestedKey
Hash.send(:include, self)
def has_nested_key?(*args)
return false unless sub = self[args.shift]
return true if args.empty?
sub.respond_to?(:has_nested_key?) and sub.has_nested_key?(*args)
end
end
#hash.has_nested_key? :key1, :key2
Perhaps I am missing something, but if all you care about is concise...why not:
#hash && #hash[:key1] && #hash[:key1][:key2]
or if you want to save a few characters
#hash && (h = #hash[:key1]) && h[:key2]
if any part of this fails, it returns nil otherwise it returns the value associated with :key2 or true.
The reason the defined? returns true even if :key2 is not there is because it just checks whether the object you are referencing exists, which in that case is the method [] which is an alias for the method fetch which does exist on the hash #hash[:key1] but if that were to return nil, there is no fetch method on nil and it would return nil. That being said, if you had to go n deep into an embedded hash, at some point it would become more efficient to call:
defined?(#hash[:key1][:key2][:key3]) && #hash[:key1][:key2][:key3]
Using Hash#fetch
You can use the Hash#fetch method with a default of {} so that it is safe to call has_key? even if the first level key doesn't exist. e.g.
!hash.nil? && hash.fetch(key1, {}).has_key?(key2)
Alternative
Alternatively you can use the conditional operator e.g.
!hash.nil? && (hash.has_key?(key1) ? hash[key1].has_key?(key2) : false)
i.e. if hash doesn't have key key1 then just return false without looking for the second level key. If it does have key1 then return the result of checking key1's value for key2.
Also, if you want to check that hash[key1]'s value has a has_key? method before calling it:
!hash.nil? && (hash.has_key?(key1) ? hash[key1].respond_to?(:has_key?) &&
hash[key1].has_key?(key2) : false)
#hash[:key1].has_key? :key2
If you don't care about distinguishing nonexistent #hash[:key1][:key2] (at any of 3 levels) from #hash[:key1][:key2] == nil, this is quite clean and works for any depth:
[:key1,:key2].inject(hash){|h,k| h && h[k]}
If you want nil to be treated as existing, use this instead:
(hash[:key1].has_key?(:key2) rescue false)
Another option, one that I just discovered, is to extend Hash with a seek method. Technique comes from Corey O'Daniel.
Stick this in an initializer:
class Hash
def seek(*_keys_)
last_level = self
sought_value = nil
_keys_.each_with_index do |_key_, _idx_|
if last_level.is_a?(Hash) && last_level.has_key?(_key_)
if _idx_ + 1 == _keys_.length
sought_value = last_level[_key_]
else
last_level = last_level[_key_]
end
else
break
end
end
sought_value
end
end
Then just call:
#key_i_need = #hash.seek :one, :two, :three
You'll get the value, or nil if it doesn't exist.