Object#tap question - ruby-on-rails

Why does
a = [].tap do |x|
x << 1
end
puts "a: #{a}"
work as expected
a: [1]
but
b = [].tap do |x|
x = [1]
end
puts "b: #{b}"
doesn't
b: []
?

The reason why the second snippet does not change the array is the same why this snippet:
def foo(x)
x = [1]
end
a = []
foo(a)
does not change variable a. Variable x in your code is local to the scope of the block, and because of that you can assign anything to it, but the assignment won't be visible outside (Ruby is a pass-by-value language).
Of course, blocks have also closures on the local variables where they were declared, so this will work:
def foo(x)
yield(x)
end
b = []
foo(123) do |x|
b = [1]
end
p b # outputs [1]

The first method put 1 on the end of an empty array. In the same way you cant say that an empty array is equal to 1. Rather you would try and replicate it...
b = [].tap do |x|
x.unshift(1)
end
This is just an example yet have a look at the method call you can use on an Array by typing.
Array.methods.sort
All the best and Good luck

This is slightly unrelated -- but that [].tap idiom is horrible. You should not use it. Even many of the people who used it in rails code now admit it's horrible and no longer use it.
Do not use it.

Related

What does ||= actually do in controller before_action? [duplicate]

What does the following code mean in Ruby?
||=
Does it have any meaning or reason for the syntax?
a ||= b is a conditional assignment operator. It means:
if a is undefined or falsey, then evaluate b and set a to the result.
Otherwise (if a is defined and evaluates to truthy), then b is not evaluated, and no assignment takes place.
For example:
a ||= nil # => nil
a ||= 0 # => 0
a ||= 2 # => 0
foo = false # => false
foo ||= true # => true
foo ||= false # => true
Confusingly, it looks similar to other assignment operators (such as +=), but behaves differently.
a += b translates to a = a + b
a ||= b roughly translates to a || a = b
It is a near-shorthand for a || a = b. The difference is that, when a is undefined, a || a = b would raise NameError, whereas a ||= b sets a to b. This distinction is unimportant if a and b are both local variables, but is significant if either is a getter/setter method of a class.
Further reading:
http://www.rubyinside.com/what-rubys-double-pipe-or-equals-really-does-5488.html
This question has been discussed so often on the Ruby mailing-lists and Ruby blogs that there are now even threads on the Ruby mailing-list whose only purpose is to collect links to all the other threads on the Ruby mailing-list that discuss this issue.
Here's one: The definitive list of ||= (OR Equal) threads and pages
If you really want to know what is going on, take a look at Section 11.4.2.3 "Abbreviated assignments" of the Ruby Language Draft Specification.
As a first approximation,
a ||= b
is equivalent to
a || a = b
and not equivalent to
a = a || b
However, that is only a first approximation, especially if a is undefined. The semantics also differ depending on whether it is a simple variable assignment, a method assignment or an indexing assignment:
a ||= b
a.c ||= b
a[c] ||= b
are all treated differently.
Concise and complete answer
a ||= b
evaluates the same way as each of the following lines
a || a = b
a ? a : a = b
if a then a else a = b end
-
On the other hand,
a = a || b
evaluates the same way as each of the following lines
a = a ? a : b
if a then a = a else a = b end
-
Edit: As AJedi32 pointed out in the comments, this only holds true if: 1. a is a defined variable. 2. Evaluating a one time and two times does not result in a difference in program or system state.
In short, a||=b means: If a is undefined, nil or false, assign b to a. Otherwise, keep a intact.
Basically,
x ||= y means
if x has any value leave it alone and do not change the value, otherwise
set x to y
It means or-equals to. It checks to see if the value on the left is defined, then use that. If it's not, use the value on the right. You can use it in Rails to cache instance variables in models.
A quick Rails-based example, where we create a function to fetch the currently logged in user:
class User > ActiveRecord::Base
def current_user
#current_user ||= User.find_by_id(session[:user_id])
end
end
It checks to see if the #current_user instance variable is set. If it is, it will return it, thereby saving a database call. If it's not set however, we make the call and then set the #current_user variable to that. It's a really simple caching technique but is great for when you're fetching the same instance variable across the application multiple times.
To be precise, a ||= b means "if a is undefined or falsy (false or nil), set a to b and evaluate to (i.e. return) b, otherwise evaluate to a".
Others often try to illustrate this by saying that a ||= b is equivalent to a || a = b or a = a || b. These equivalencies can be helpful for understanding the concept, but be aware that they are not accurate under all conditions. Allow me to explain:
a ||= b ⇔ a || a = b?
The behavior of these statements differs when a is an undefined local variable. In that case, a ||= b will set a to b (and evaluate to b), whereas a || a = b will raise NameError: undefined local variable or method 'a' for main:Object.
a ||= b ⇔ a = a || b?
The equivalency of these statements are often assumed, since a similar equivalence is true for other abbreviated assignment operators (i.e. +=,-=,*=,/=,%=,**=,&=,|=,^=,<<=, and >>=). However, for ||= the behavior of these statements may differ when a= is a method on an object and a is truthy. In that case, a ||= b will do nothing (other than evaluate to a), whereas a = a || b will call a=(a) on a's receiver. As others have pointed out, this can make a difference when calling a=a has side effects, such as adding keys to a hash.
a ||= b ⇔ a = b unless a??
The behavior of these statements differs only in what they evaluate to when a is truthy. In that case, a = b unless a will evaluate to nil (though a will still not be set, as expected), whereas a ||= b will evaluate to a.
a ||= b ⇔ defined?(a) ? (a || a = b) : (a = b)????
Still no. These statements can differ when a method_missing method exists which returns a truthy value for a. In this case, a ||= b will evaluate to whatever method_missing returns, and not attempt to set a, whereas defined?(a) ? (a || a = b) : (a = b) will set a to b and evaluate to b.
Okay, okay, so what is a ||= b equivalent to? Is there a way to express this in Ruby?
Well, assuming that I'm not overlooking anything, I believe a ||= b is functionally equivalent to... (drumroll)
begin
a = nil if false
a || a = b
end
Hold on! Isn't that just the first example with a noop before it? Well, not quite. Remember how I said before that a ||= b is only not equivalent to a || a = b when a is an undefined local variable? Well, a = nil if false ensures that a is never undefined, even though that line is never executed. Local variables in Ruby are lexically scoped.
If X does NOT have a value, it will be assigned the value of Y. Else, it will preserve it's original value, 5 in this example:
irb(main):020:0> x = 5
=> 5
irb(main):021:0> y = 10
=> 10
irb(main):022:0> x ||= y
=> 5
# Now set x to nil.
irb(main):025:0> x = nil
=> nil
irb(main):026:0> x ||= y
=> 10
x ||= y
is
x || x = y
"if x is false or undefined, then x point to y"
||= is a conditional assignment operator
x ||= y
is equivalent to
x = x || y
or alternatively
if defined?(x) and x
x = x
else
x = y
end
unless x
x = y
end
unless x has a value (it's not nil or false), set it equal to y
is equivalent to
x ||= y
Suppose a = 2 and b = 3
THEN, a ||= b will be resulted to a's value i.e. 2.
As when a evaluates to some value not resulted to false or nil.. That's why it ll not evaluate b's value.
Now Suppose a = nil and b = 3.
Then a ||= b will be resulted to 3 i.e. b's value.
As it first try to evaluates a's value which resulted to nil.. so it evaluated b's value.
The best example used in ror app is :
#To get currently logged in iser
def current_user
#current_user ||= User.find_by_id(session[:user_id])
end
# Make current_user available in templates as a helper
helper_method :current_user
Where, User.find_by_id(session[:user_id]) is fired if and only if #current_user is not initialized before.
||= is called a conditional assignment operator.
It basically works as = but with the exception that if a variable has already been assigned it will do nothing.
First example:
x ||= 10
Second example:
x = 20
x ||= 10
In the first example x is now equal to 10. However, in the second example x is already defined as 20. So the conditional operator has no effect. x is still 20 after running x ||= 10.
a ||= b
Signifies if any value is present in 'a' and you dont want to alter it the keep using that value, else if 'a' doesnt have any value, use value of 'b'.
Simple words, if left hand side if not null, point to existing value, else point to value at right side.
a ||= b
is equivalent to
a || a = b
and not
a = a || b
because of the situation where you define a hash with a default (the hash will return the default for any undefined keys)
a = Hash.new(true) #Which is: {}
if you use:
a[10] ||= 10 #same as a[10] || a[10] = 10
a is still:
{}
but when you write it like so:
a[10] = a[10] || 10
a becomes:
{10 => true}
because you've assigned the value of itself at key 10, which defaults to true, so now the hash is defined for the key 10, rather than never performing the assignment in the first place.
It's like lazy instantiation.
If the variable is already defined it will take that value instead of creating the value again.
Please also remember that ||= isn't an atomic operation and so, it isn't thread safe. As rule of thumb, don't use it for class methods.
This is the default assignment notation
for example: x ||= 1
this will check to see if x is nil or not. If x is indeed nil it will then assign it that new value (1 in our example)
more explicit:
if x == nil
x = 1
end
b = 5
a ||= b
This translates to:
a = a || b
which will be
a = nil || 5
so finally
a = 5
Now if you call this again:
a ||= b
a = a || b
a = 5 || 5
a = 5
b = 6
Now if you call this again:
a ||= b
a = a || b
a = 5 || 6
a = 5
If you observe, b value will not be assigned to a. a will still have 5.
Its a Memoization Pattern that is being used in Ruby to speed up accessors.
def users
#users ||= User.all
end
This basically translates to:
#users = #users || User.all
So you will make a call to database for the first time you call this method.
Future calls to this method will just return the value of #users instance variable.
As a common misconception, a ||= b is not equivalent to a = a || b, but it behaves like a || a = b.
But here comes a tricky case. If a is not defined, a || a = 42 raises NameError, while a ||= 42 returns 42. So, they don't seem to be equivalent expressions.
irb(main):001:0> a = 1
=> 1
irb(main):002:0> a ||= 2
=> 1
Because a was already set to 1
irb(main):003:0> a = nil
=> nil
irb(main):004:0> a ||= 2
=> 2
Because a was nil
This ruby-lang syntax. The correct answer is to check the ruby-lang documentation. All other explanations obfuscate.
Google
"ruby-lang docs Abbreviated Assignment".
Ruby-lang docs
https://docs.ruby-lang.org/en/2.4.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment
a ||= b is the same as saying a = b if a.nil? or a = b unless a
But do all 3 options show the same performance? With Ruby 2.5.1 this
1000000.times do
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
a ||= 1
end
takes 0.099 Seconds on my PC, while
1000000.times do
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
a = 1 unless a
end
takes 0.062 Seconds. That's almost 40% faster.
and then we also have:
1000000.times do
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
a = 1 if a.nil?
end
which takes 0.166 Seconds.
Not that this will make a significant performance impact in general, but if you do need that last bit of optimization, then consider this result.
By the way: a = 1 unless a is easier to read for the novice, it is self-explanatory.
Note 1: reason for repeating the assignment line multiple times is to reduce the overhead of the loop on the time measured.
Note 2: The results are similar if I do a=nil nil before each assignment.

Trying to get a total - Ruby

I'm trying to get the total cost in one of my field called "upgrade_cost" and store that in a variable called $tuc
def totalUpgradeCost
$e = Experience.all
$tuc = 0
(e.emf_assets).each do |i|
i.upgrade_cost += $tuc
end
return $tuc
end
I'm getting some error undefined local variable or method `e', new to ruby. Anyone help?
I am assuming that emf_assets are associated (via has_many) with an experience. That said I think the following could work for you:
def total_upgrade_cost
total = 0 # use a more descriptive variable names
all_experiences = Experience.all
all_experiences.each do |experience| # iterate over each `experiment`
experience.emf_assets.each do |asset| # load `emf_assets` for each `experiment`
# add the `upgrade_cost` (which might be `nil`) to `total`
total += asset.upgrade_cost.to_i
end
end
total # no need for an explicit `return`
end
Please note that this might work for smaller numbers of experiences and emf_assets, but in a next step performance will benefit from some optimization. But I think that optimization is out of the scope of this question at the moment. You will need to avoid the N+1 query problem and it might makes sense to do the whole calculation in your database.
What is the e in e.emf_assets? If you mean $e, you aren't allowed to drop the $. In Ruby, a $ at the start of a variable name indicates a global variable. If you aren't using $e outside of this function anyway, it would be better to call it simply e, so that it wouldn't be visible outside of the function. Regardless, you're getting an error because $e refers to a global, and e refers to a separate (undefined) local variable.
This is not PHP. $ sign isn't required everywhere. You've used $ with one e and left another empty, that's why the error.
This code should work:
def totalUpgradeCost
e = Experience.all
tuc = 0
e.emf_assets.each do |i|
tuc += i.upgrade_cost
end
return tuc
end
This is doable in shorter way:
def totalUpgradeCost
e = Experience.all
e.emf_assets.inject(0) {|sum, i| sum += i.upgrade_cost}
end

metaprograming String#scan and globals?

My goal is to replace methods in the String class with other methods that do additional work (this is for a research project). This works for many methods by writing code in the String class similar to
alias_method :center_OLD, :center
def center(args*)
r = self.send(*([:center_OLD] + args))
#do some work here
#return something
end
For some methods, I need to handle a Proc as well, which is no problem. However, for the scan method, invoking it has the side effect of setting special global variables from the regular expression match. As documented, these variables are local to the thread and the method.
Unfortunately, some Rails code makes calls to scan which makes use of the $& variable. That variable gets set inside my version of the scan method, but because it's local, it doesn't make it back to the original caller which uses the variable.
Does anyone know a way to work around this? Please let me know if the problem needs clarification.
If it helps at all, all the uses I've seen so far of the $& variable are inside a Proc passed to the scan function, so I can get the binding for that Proc. However, the user doesn't seem to be able to change $& at all, so I don't know how that will help much.
Current Code
class String
alias_method :scan_OLD, :scan
def scan(*args, &b)
begin
sargs = [:scan_OLD] + args
if b.class == Proc
r = self.send(*sargs, &b)
else
r = self.send(*sargs)
end
r
rescue => error
puts error.backtrace.join("\n")
end
end
end
Of course I'll do more things before returning r, but this even is problematic -- so for simplicity we'll stick with this. As a test case, consider:
"hello world".scan(/l./) { |x| puts x }
This works fine both with and without my version of scan. With the "vanilla" String class this produces the same thing as
"hello world".scan(/l./) { puts $&; }
Namely, it prints "ll" and "ld" and returns "hello world". With the modified string class it prints two blank lines (since $& was nil) and then returns "hello world". I'll be happy if we can get that working!
You cannot set $&, because it is derived from $~, the last MatchData.
However, $~ can be set and that actually does what you want.
The trick is to set it in the block binding.
The code is inspired by the old Ruby implementation of Pathname.
(The new code is in C and does not need to care about Ruby frame-local variables)
class String
alias_method :scan_OLD, :scan
def scan(*args, &block)
sargs = [:scan_OLD] + args
if block
self.send(*sargs) do |*bargs|
Thread.current[:string_scan_matchdata] = $~
eval("$~ = Thread.current[:string_scan_matchdata]", block.binding)
yield(*bargs)
end
else
self.send(*sargs)
end
end
end
The saving of the thread-local (well, actually fiber-local) variable seems unnecessary since it is only used to pass the value and the thread never reads any other value than the last one set. It probably is there to restore the original value (most likely nil, because the variable did not exist).
One way to avoid thread-locals at all is to create a setter of $~ as a lambda (but it does create a lambda for each call):
self.send(*sargs) do |*bargs|
eval("lambda { |m| $~ = m }", block.binding).call($~)
yield(*bargs)
end
With any of these, your example works!
I wrote simple code simulating the problem:
"hello world".scan(/l./) { |x| puts x }
"hello world".scan(/l./) { puts $&; }
class String
alias_method :origin_scan, :scan
def scan *args, &b
args.unshift :origin_scan
#mutex ||= Mutex.new
begin
self.send *args do |a|
break if !block_given?
#mutex.synchronize do
p $&
case b.arity
when 0
b.call
when 1
b.call a
end
end
end
rescue => error
p error, error.backtrace.join("\n")
end
end
end
"hello world".scan(/l./) { |x| puts x }
"hello world".scan(/l./) { puts $& }
And found the following. The change of containment of the variable $& became inside a :call function, i.e. on 3-rd step before :call $& contains a valid value, but inside the block it becomes the invalid. I guess this become due to the singularity stack and variable restoration during the change process/thread context, because, probably, :call function can't access the :scan local state.
I see two variants: the first is to avoid to use global variables in the specific function redefinitions, and second, may to dig sources of ruby more deeply.

In Ruby, how to write a method to display any object's instance variable names and its values

Given any object in Ruby (on Rails), how can I write a method so that it will display that object's instance variable names and its values, like this:
#x: 1
#y: 2
#link_to_point: #<Point:0x10031b298 #y=20, #x=38>
(Update: inspect will do except for large object it is difficult to break down the variables from the 200 lines of output, like in Rails, when you request.inspect or self.inspect in the ActionView object)
I also want to be able to print <br> to the end of each instance variable's value so as to print them out nicely on a webpage.
the difficulty now seems to be that not every instance variable has an accessor, so it can't be called with obj.send(var_name)
(the var_name has the "#" removed, so "#x" becomes "x")
Update: I suppose using recursion, it can print out a more advanced version:
#<Point:0x10031b462>
#x: 1
#y: 2
#link_to_point: #<Point:0x10031b298>
#x=38
#y=20
I would probably write it like this:
class Object
def all_variables(root=true)
vars = {}
self.instance_variables.each do |var|
ivar = self.instance_variable_get(var)
vars[var] = [ivar, ivar.all_variables(false)]
end
root ? [self, vars] : vars
end
end
def string_variables(vars, lb="\n", indent="\t", current_indent="")
out = "#{vars[0].inspect}#{lb}"
current_indent += indent
out += vars[1].map do |var, ivar|
ivstr = string_variables(ivar, lb, indent, current_indent)
"#{current_indent}#{var}: #{ivstr}"
end.join
return out
end
def inspect_variables(obj, lb="\n", indent="\t", current_indent="")
string_variables(obj.all_variables, lb, indent, current_indent)
end
The Object#all_variables method produces an array containing (0) the given object and (1) a hash mapping instance variable names to arrays containing (0) the instance variable and (1) a hash mapping…. Thus, it gives you a nice recursive structure. The string_variables function prints out that hash nicely; inspect_variables is just a convenience wrapper. Thus, print inspect_variables(foo) gives you a newline-separated option, and print inspect_variables(foo, "<br />\n") gives you the version with HTML line breaks. If you want to specify the indent, you can do that too: print inspect_variables(foo, "\n", "|---") produces a (useless) faux-tree format instead of tab-based indenting.
There ought to be a sensible way to write an each_variable function to which you provide a callback (which wouldn't have to allocate the intermediate storage); I'll edit this answer to include it if I think of something. Edit 1: I thought of something.
Here's another way to write it, which I think is slightly nicer:
class Object
def each_variable(name=nil, depth=0, parent=nil, &block)
yield name, self, depth, parent
self.instance_variables.each do |var|
self.instance_variable_get(var).each_variable(var, depth+1, self, &block)
end
end
end
def inspect_variables(obj, nl="\n", indent="\t", sep=': ')
out = ''
obj.each_variable do |name, var, depth, _parent|
out += [indent*depth, name, name ? sep : '', var.inspect, nl].join
end
return out
end
The Object#each_variable method takes a number of optional arguments, which are not designed to be specified by the user; instead, they are used by the recursion to maintain state. The given block is passed (a) the name of the instance variable, or nil if the variable is the root of the recursion; (b) the variable; (c) the depth to which the recursion has descended; and (d), the parent of the current variable, or nil if said variable is the root of the recursion. The recursion is depth-first. The inspect_variables function uses this to build up a string. The obj argument is the object to iterate through; nl is the line separator; indent is the indentation to be applied at each level; and sep separates the name and the value.
Edit 2: This doesn't really add anything to the answer to your question, but: just to prove that we haven't lost anything in the reimplementation, here's a reimplementation of all_variables in terms of each_variables.
def all_variables(obj)
cur_depth = 0
root = [obj, {}]
tree = root
parents = []
prev = root
obj.each_variable do |name, var, depth, _parent|
next unless name
case depth <=> cur_depth
when -1 # We've gone back up
tree = parents.pop(cur_depth - depth)[0]
when +1 # We've gone down
parents << tree
tree = prev
else # We're at the same level
# Do nothing
end
cur_depth = depth
prev = tree[1][name] = [var, {}]
end
return root
end
I feel like it ought to be shorter, but that may not be possible; because we don't have the recursion now, we have to maintain the stack explicitly (in parents). But it is possible, so the each_variable method works just as well (and I think it's a little nicer).
I see... Antal must be giving the advanced version here...
the short version then probably is:
def p_each(obj)
obj.instance_variables.each do |v|
puts "#{v}: #{obj.instance_variable_get(v)}\n"
end
nil
end
or to return it as a string:
def sp_each(obj)
s = ""
obj.instance_variables.each do |v|
s += "#{v}: #{obj.instance_variable_get(v)}\n"
end
s
end
or shorter:
def sp_each(obj)
obj.instance_variables.map {|v| "#{v}: #{obj.instance_variable_get(v)}\n"}.join
end
This is a quick adaptation of a simple JSON emitter I wrote for another question:
class Object
def inspect!(indent=0)
return inspect if instance_variables.empty?
"#<#{self.class}:0x#{object_id.to_s(16)}\n#{' ' * indent+=1}#{
instance_variables.map {|var|
"#{var}: #{instance_variable_get(var).inspect!(indent)}"
}.join("\n#{' ' * indent}")
}\n#{' ' * indent-=1}>"
end
end
class Array
def inspect!(indent=0)
return '[]' if empty?
"[\n#{' ' * indent+=1}#{
map {|el| el.inspect!(indent) }.join(",\n#{' ' * indent}")
}\n#{' ' * indent-=1}]"
end
end
class Hash
def inspect!(indent=0)
return '{}' if empty?
"{\n#{' ' * indent+=1}#{
map {|k, v|
"#{k.inspect!(indent)} => #{v.inspect!(indent)}"
}.join(",\n#{' ' * indent}")
}\n#{' ' * indent-=1}}"
end
end
That's all the magic, really. Now we only need some simple defaults for some types where a full-on inspect doesn't really make sense (nil, false, true, numbers, etc.):
module InspectBang
def inspect!(indent=0)
inspect
end
end
[Numeric, Symbol, NilClass, TrueClass, FalseClass, String].each do |klass|
klass.send :include, InspectBang
end
Like this?
# Get the instance variables of an object
d = Date.new
d.instance_variables.each{|i| puts i + "<br />"}
Ruby Documentation on instance_variables.
The concept is commonly called "introspection", (to look into oneself).

Inserting new item to instance variable in Ruby on Rails

#xs stores urls like www.yahoo.com, www.google.com
for x in #xs
y = x... #do something with x
#result += y #i want to do something like that. i want to store them in #result. What do i have to write in here?
end
Sorry for noob question. By the way how do you call #result ? Is it an instance variable or an array ?
You need to initialize #result first.
#result = []
for x in #xs
y = x...
#result << y
end
You should either do this:
#result << y
or this:
#result += [y]
The + operator expects two arrays, the << operator appends an object onto an array.
From what I can make out from the question, you want to mutate the contents of the already existing array
#mutated_xs = #xs.collect do |x|
y = x.do_something # some code for to do something to x returning y
x += y # mutate existing x here
end
puts #mutated_xs.inspect
If you want to take every element in an array and change it, the idiomatic Ruby way is to use map or collect:
#new_urls = #urls.map do |url|
# change url to its new value here
end
You don't need to manually assign it to #new_urls, just write a statement that returns the desired value, like url.upcase or whatever you want to do.

Resources