This method does not have a description on the APIdock. I know instance_exec in Ruby is similar to the this binding mechanism in JavaScript.
def interpolate(sql, record = nil)
if sql.respond_to?(:to_proc)
owner.instance_exec(record, &sql)
else
sql
end
end
Could someone briefly describe it?
First of all, the check for respond_to?(:to_proc) is necessary to make sure sql might be converted to lambda (by ampersand & to be passed to instance_exec. To simplify things, one might treat sql here as being a lambda already:
def interpolate(sql, record = nil) # assume sql is lambda
owner.instance_exec(record, &sql)
end
As by documentation on instance_exec:
Executes the given block within the context of the receiver...
That said, lambda will be executed as it was the ordinal code, placed somewhere inside instance method of the receiver.
class Owner
def initialize
#records = [:zero, :one, :two]
end
end
record_by_index = ->(idx) { #records[idx] }
Owner.new.instance_exec 1, &record_by_index #⇒ :one
The code above is [more or less] an equivalent to:
class Owner
def initialize
#records = [:zero, :one, :two]
end
def record_by_index idx
#records[idx]
end
end
Owner.new.record_by_index(1) #⇒ :one
The actual parameters of call to instance_exec will be passed to the codeblock. In the context of Owner’s instance we have an access to instance variables, private methods, etc. Hope it helps.
Related
In my app that I am building to learn Rails and Ruby, I have below iteration/loop which is not functioning as it should.
What am I trying to achieve?
I am trying to find the business partner (within only the active once (uses a scope)) where the value of the field business_partner.bank_account is contained in the field self_extracted_data and then set the business partner found as self.sender (self here is a Document).
So once a match is found, I want to end the loop. A case exists where no match is found and sender = nil so a user needs to set it manually.
What happens now, is that on which ever record of the object I save (it is called as a callback before_save), it uses the last identified business partner as sender and the method does not execute again.
Current code:
def set_sender
BusinessPartner.active.where.not(id: self.receiver_id).each do |business_partner|
bp_bank_account = business_partner.bank_account.gsub(/\s+/, '')
rgx = /(?<!\w)(#{Regexp.escape(bp_bank_account)})?(?!\w)/
if self.extracted_data.gsub(/\s+/, '') =~ rgx
self.sender = business_partner
else
self.sender = nil
end
end
end
Thanks for helping me understand how to do this kind of case.
p.s. have the pickaxe book here yet this is so much that some help / guidance would be great. The regex works.
Using feedback from #moveson, this code works:
def match_with_extracted_data?(rgx_to_match)
extracted_data.gsub(/\s+/, '') =~ rgx_to_match
end
def set_sender
self.sender_id = matching_business_partner.try(:id) #unless self.sender.id.present? # Returns nil if no matching_business_partner exists
end
def matching_business_partner
BusinessPartner.active.excluding_receiver(receiver_id).find { |business_partner| sender_matches?(business_partner) }
end
def sender_matches?(business_partner)
rgx_registrations = /(#{Regexp.escape(business_partner.bank_account.gsub(/\s+/, ''))})|(#{Regexp.escape(business_partner.registration.gsub(/\s+/, ''))})|(#{Regexp.escape(business_partner.vat_id.gsub(/\s+/, ''))})/
match_with_extracted_data?(rgx_registrations)
end
In Ruby you generally want to avoid loops and #each and long, procedural methods in favor of Enumerable iterators like #map, #find, and #select, and short, descriptive methods that each do a single job. Without knowing more about your project I can't be sure exactly what will work, but I think you want something like this:
# /models/document.rb
class Document < ActiveRecord::Base
def set_sender
self.sender = matching_business_partner.try(:id) || BusinessPartner.active.default.id
end
def matching_business_partners
other_business_partners.select { |business_partner| account_matches?(business_partner) }
end
def matching_business_partner
matching_business_partners.first
end
def other_business_partners
BusinessPartner.excluding_receiver_id(receiver_id)
end
def account_matches?(business_partner)
rgx = /(?<!\w)(#{Regexp.escape(business_partner.stripped_bank_account)})?(?!\w)/
data_matches_bank_account?(rgx)
end
def data_matches_bank_account?(rgx)
extracted_data.gsub(/\s+/, '') =~ rgx
end
end
# /models/business_partner.rb
class BusinessPartner < ActiveRecord::Base
scope :excluding_receiver_id, -> (receiver_id) { where.not(id: receiver_id) }
def stripped_bank_account
bank_account.gsub(/\s+/, '')
end
end
Note that I am assigning an integer id, rather than an ActiveRecord object, to self.sender. I think that's what you want.
I didn't try to mess with the database relations here, but it does seem like Document could include a belongs_to :business_partner, which would give you the benefit of Rails methods to help you find one from the other.
EDIT: Added Document#matching_business_partners method and changed Document#set_sender method to return nil if no matching_business_partner exists.
EDIT: Added BusinessPartner.active.default.id as the return value if no matching_business_partner exists.
In debugging console, while app running (using binding.pry to interrupt it), I can see that my variable Rails.configuration.hardcoded_current_user_key is set:
pry(#<TasksController>)> Rails.configuration.hardcoded_current_user_key
=> "dev"
But it doesn't appear to be defined:
pry(#<TasksController>)> defined?(Rails.configuration.hardcoded_current_user_key)
=> nil
Yet it works fine to store and test its value:
pry(#<TasksController>)> tempVar = Rails.configuration.hardcoded_current_user_key
=> "dev"
pry(#<TasksController>)> defined?(tempVar)
=> "local-variable"
What is going on?
This is because Rails config implements respond_to? but not respond_to_missing?, and defined? only recognizes respond_to_missing?:
class X
def respond_to?(name, include_all = false)
name == :another_secret || super
end
private
def method_missing(name, *args, &block)
case name
when :super_secret
'Bingo!'
when :another_secret
'Nope.'
else
super
end
end
def respond_to_missing?(name, include_all = false)
name == :super_secret || super
end
end
x = X.new
puts x.super_secret # => Bingo!
p defined?(x.super_secret) # => "method"
puts x.another_secret # => Nope.
p defined?(x.another_secret) # => nil
It's recommended to implement respond_to_missing? along with method_missing, I too wonder why Rails did it that way.
You shouldn't be using defined? on anything but the "stub" of that, or in other words, merely this:
defined?(Rails)
Anything beyond that is highly unusual to see, and I'm not even sure it's valid.
defined? is not a method, but a construct that tests if the following thing is defined as a variable, constant or method, among other things. It won't evaluate your code, it will just test it as-is. This means method calls don't happen, and as such, can't be chained.
If you want to test that something is assigned, then you should use this:
Rails.configuration.hardcoded_current_user_key.nil?
I have a User model in a ROR application that has multiple methods like this
#getClient() returns an object that knows how to find certain info for a date
#processHeaders() is a function that processes output and updates some values in the database
#refreshToken() is function that is called when an error occurs when requesting data from the object returned by getClient()
def transactions_on_date(date)
if blocked?
# do something
else
begin
output = getClient().transactions(date)
processHeaders(output)
return output
rescue UnauthorizedError => ex
refresh_token()
output = getClient().transactions(date)
process_fitbit_rate_headers(output)
return output
end
end
end
def events_on_date(date)
if blocked?
# do something
else
begin
output = getClient().events(date)
processHeaders(output)
return output
rescue UnauthorizedError => ex
refresh_token()
output = getClient().events(date)
processHeaders(output)
return output
end
end
end
I have several functions in my User class that look exactly the same. The only difference among these functions is the line output = getClient().something(date). Is there a way that I can make this code look cleaner so that I do not have a repetitive list of functions.
The answer is usually passing in a block and doing it functional style:
def handle_blocking(date)
if blocked?
# do something
else
begin
output = yield(date)
processHeaders(output)
output
rescue UnauthorizedError => ex
refresh_token
output = yield(date)
process_fitbit_rate_headers(output)
output
end
end
end
Then you call it this way:
handle_blocking(date) do |date|
getClient.something(date)
end
That allows a lot of customization. The yield call executes the block of code you've supplied and passes in the date argument to it.
The process of DRYing up your code often involves looking for patterns and boiling them down to useful methods like this. Using a functional approach can keep things clean.
Yes, you can use Object#send: getClient().send(:method_name, date).
BTW, getClient is not a proper Ruby method name. It should be get_client.
How about a combination of both answers:
class User
def method_missing sym, *args
m_name = sym.to_s
if m_name.end_with? '_on_date'
prop = m_name.split('_').first.to_sym
handle_blocking(args.first) { getClient().send(prop, args.first) }
else
super(sym, *args)
end
end
def respond_to? sym, private=false
m_name.end_with?('_on_date') || super(sym, private)
end
def handle_blocking date
# see other answer
end
end
Then you can call "transaction_on_date", "events_on_date", "foo_on_date" and it would work.
New to Ruby and ROR and loving it each day, so here is my question since I have not idea how to google it (and I have tried :) )
we have method
def foo(first_name, last_name, age, sex, is_plumber)
# some code
# error happens here
logger.error "Method has failed, here are all method arguments #{SOMETHING}"
end
So what I am looking for way to get all arguments passed to method, without listing each one. Since this is Ruby I assume there is a way :) if it was java I would just list them :)
Output would be:
Method has failed, here are all method arguments {"Mario", "Super", 40, true, true}
In Ruby 1.9.2 and later you can use the parameters method on a method to get the list of parameters for that method. This will return a list of pairs indicating the name of the parameter and whether it is required.
e.g.
If you do
def foo(x, y)
end
then
method(:foo).parameters # => [[:req, :x], [:req, :y]]
You can use the special variable __method__ to get the name of the current method. So within a method the names of its parameters can be obtained via
args = method(__method__).parameters.map { |arg| arg[1].to_s }
You could then display the name and value of each parameter with
logger.error "Method failed with " + args.map { |arg| "#{arg} = #{eval arg}" }.join(', ')
Note: since this answer was originally written, in current versions of Ruby eval can no longer be called with a symbol. To address this, an explicit to_s has been added when building the list of parameter names i.e. parameters.map { |arg| arg[1].to_s }
Since Ruby 2.1 you can use binding.local_variable_get to read value of any local variable, including method parameters (arguments). Thanks to that you can improve the accepted answer to avoid evil eval.
def foo(x, y)
method(__method__).parameters.map do |_, name|
binding.local_variable_get(name)
end
end
foo(1, 2) # => 1, 2
One way to handle this is:
def foo(*args)
first_name, last_name, age, sex, is_plumber = *args
# some code
# error happens here
logger.error "Method has failed, here are all method arguments #{args.inspect}"
end
This is an interesting question. Maybe using local_variables? But there must be a way other than using eval. I'm looking in Kernel doc
class Test
def method(first, last)
local_variables.each do |var|
puts eval var.to_s
end
end
end
Test.new().method("aaa", 1) # outputs "aaa", 1
If you need arguments as a Hash, and you don't want to pollute method's body with tricky extraction of parameters, use this:
def mymethod(firstarg, kw_arg1:, kw_arg2: :default)
args = MethodArguments.(binding) # All arguments are in `args` hash now
...
end
Just add this class to your project:
class MethodArguments
def self.call(ext_binding)
raise ArgumentError, "Binding expected, #{ext_binding.class.name} given" unless ext_binding.is_a?(Binding)
method_name = ext_binding.eval("__method__")
ext_binding.receiver.method(method_name).parameters.map do |_, name|
[name, ext_binding.local_variable_get(name)]
end.to_h
end
end
This may be helpful...
def foo(x, y)
args(binding)
end
def args(callers_binding)
callers_name = caller[0][/`.*'/][1..-2]
parameters = method(callers_name).parameters
parameters.map { |_, arg_name|
callers_binding.local_variable_get(arg_name)
}
end
You can define a constant such as:
ARGS_TO_HASH = "method(__method__).parameters.map { |arg| arg[1].to_s }.map { |arg| { arg.to_sym => eval(arg) } }.reduce Hash.new, :merge"
And use it in your code like:
args = eval(ARGS_TO_HASH)
another_method_that_takes_the_same_arguments(**args)
If the function is inside some class then you can do something like this:
class Car
def drive(speed)
end
end
car = Car.new
method = car.method(:drive)
p method.parameters #=> [[:req, :speed]]
If you would change the method signature, you can do something like this:
def foo(*args)
# some code
# error happens here
logger.error "Method has failed, here are all method arguments #{args}"
end
Or:
def foo(opts={})
# some code
# error happens here
logger.error "Method has failed, here are all method arguments #{opts.values}"
end
In this case, interpolated args or opts.values will be an array, but you can join if on comma. Cheers
It seems like what this question is trying to accomplish could be done with a gem I just released, https://github.com/ericbeland/exception_details. It will list local variables and vlaues (and instance variables) from rescued exceptions. Might be worth a look...
Before I go further, you're passing too many arguments into foo. It looks like all of those arguments are attributes on a Model, correct? You should really be passing the object itself. End of speech.
You could use a "splat" argument. It shoves everything into an array. It would look like:
def foo(*bar)
...
log.error "Error with arguments #{bar.joins(', ')}"
end
I started learning Ruby on Rails and found myself confounded by the syntax, so I had to read about somet of the Ruby syntax. I learned the syntax from http://www.cs.auckland.ac.nz/references/ruby/doc_bundle/Manual/man-1.4/syntax.html:
method_call do [`|' expr...`|'] expr...end
They call it an Iterator. I understand an iterator runs through a loop, but I don't understand how exactly I'm supposed to read this or what's going on in in this syntax. I see it all the time in RoR screencasts and the words make sense, but I actually have no idea what's going on. Could anyone explain this to me?
edit: example
respond_to do |format|
format.json
format.xml { render :xml => #posts }
end
Methods can take a construct called "Blocks". These are anonymous methods that get passed into the method.
Another syntax for this is:
method_call { |var| do_something(var) }
Basically, you are saying that for each item in an iteration, name it "var" and do something with that item. The method simply calls your block that you passed in as it "yields" items to it.
Does this help?
edit: In your example, you they are using the iterator pattern in a funny way... probably only passing one format object into your block, so you can then tell it which formats to handle, and what to do when you see it.
In other words, they are using the pattern to create a DSL of sorts that lets you configure what you respond to.
In the case of iterators, think of them like an interface in Java: you can do a for-loop in Ruby, but all the objects that you might want to iterate over (should) implement the 'each' method which takes a block (i.e. a closure, an anonymous function).
Blocks are used all over the place in Ruby. Imagine you have this array:
[1, 2, 3, 4, 5, 6].each do |i| puts i.to_s end
Here, you are creating the array and then you are calling the 'each' method on it. You pass the block to it. You could separate this out, like this:
arr = [1, 2, 3, 4, 5, 6]
string_printer = lambda do |i| puts i.to_s end
arr.each(&string_printer)
This kind of interface is implemented in other things: the Hash collection lets you iterate over the key-value pairs:
{:name => "Tom", :gender => :male}.each do |key, value| puts key end
The do..end can be replaced with braces, like this:
[1, 2, 3, 4, 5, 6].each {|i| puts i.to_s }
This kind of iteration is made possible because of the functional-programming that Ruby employs: if you are creating a class that needs to iterate over something, you can also implement the each method. Consider:
class AddressBook
attr_accessor :addresses
def each(&block)
#addresses.each {|i| yield i }
end
end
All sorts of classes implement interesting functionality through this block pattern: look at String's each_line and each_byte method, for instance.
method_call do [`|' expr...`|'] expr...end
Is not limited to iteration functions.
In ruby, any method can take a block as an argument. The block can then be called by the method. In the case of an iterator, the method looks something like this:
def iter
for i in [:x,:y,:z]
yield i
end
end
If you call iter with a block, it will loop over [:x, :y, :z] and yield each of them to the block, which can then do whatever you want. e.g. to print them out:
iter { |z| puts z }
You can also use this to hide init and cleanup steps, like opening and closing files. e.g. File.open. File.open, if it were implemented in pure ruby(it's in C for performance) would do something like this.
def File.open filename, opts
f = File.new filename, opts
yield f
f.close
end
Which is why you can use
File.open 'foobar', 'w' do |f|
f.write 'awesome'
end
respond_to is similar. It works something like this:( check out the real implementation here)
def respond_to
responder = Responder.new(self)
block.call(responder)
responder.respond
end
It creates a responder object that has methods like html that take a block and passes it to you. This turns out to be really handy, because it lets you do things like:
def action
#foo = Foo.new params[:foo]
respond_to do |format|
if #foo.save
format.html { redirect_to foo_path #foo }
format.xml { render :xml => #foo.to_xml }
else
flash[:error] = "Foo could not be saved!"
format.html { render :new }
format.xml { render :xml => {:errors => #foo.errors }.to_xml}
end
end
end
See how I change the behavior dependent on save inside the block? Doing this would be much more annoying without it.
<function> do |<temp variable>|
<code to operate on temp variable>
end
This creates a temporary anonymous function which accepts an item into a temporary variable, and then lets things operate on that item. The anonymous function is passed in to the original <function> specified to operate on the items yielded by that function.
What you see there is a block of code, the syntax is a bit awkward when you first see it.
So, basically, with iterators your have a "thing" that may be repeated, and it receives a block to know what to do.
For instance the Range class has a method called "each" which receives the block of code to execute on each element in the range.
Let's say you want to print it:
range = 1..10 #range literal
range.each {|i|
puts i
}
The code: {|i| puts i} is a block that says what to do when this range iterates over each one of its elements. The alternate syntax is the one you posted:
range.each do |i|
puts i
end
These blocks are used with iterators, but they are not limited to "iteration" code, you can use them in other scenarios, for instance:
class Person
def initialize( with_name )
#name = with_name
end
# executes a block
def greet
yield #name #passes private attribute name to the block
end
end
p = Person.new "Oscar"
p.greet { |n|
puts "Name length = #{n.length}"
puts "Hello, #{n}"
}
Prints:
Name length = 5
Hello, Oscar
So, instead of having a greet method with a fixed behavior, using block let the developer specify what to do, which is very helpful with iterators, but as you have just witness not the only place. In your case, that block is letting you specify what to do in the respond_to method.
The documentation you are reading is ancient -- practically prehistoric. If it were possible for web pages to gather dust, that one would have a thick layer.
Try the reference material at the ruby-lang website. Also, the Programming Ruby (pickaxe) book is an essential reference.
I think you could call it iterator, because often, the block function is called more than once. As in:
5.times do |i|
puts "#{i} "
end
"Behind the scenes", the following steps are made:
The method times of the object instance 5 is called, passing the code puts "#{i} " in a Proc object instance.
Inside the times method, this code is called inside a loop, passing the current index as a parameter. That's what times could look like (it's in C, actually):
class Fixnum
def times_2(&block) # Specifying &block as a parameter is optional
return self unless block_given?
i = 0
while(i < self) do
yield i # Here the proc instance "block" is called
i += 1
end
return self
end
end
Note that the scope (i.e. local variables etc.) is copied into the block function:
x = ' '
5.times do { |i| puts "#{i}" + x }