DEV Community

Discussion on: Ruby Blocks

Collapse
 
cescquintero profile image
Francisco Quintero 🇨🇴 • Edited

Hi Maryna, nice explanation here.

I've been coding in Ruby for many years and until last year found myself that I don't use blocks in the code I write in a daily basis xD

I don't feel bad for that but I do wonder what's the real use case of blocks when we create our own functions? I mean, I know how to use the ones in the Ruby API but I don't see cases where a function I wrote would benefit from a block.

Example, I know I can do:

result = ary.map { |item| # some calculation }

but when I write something like this

def my_function(args)
end

I've never added a block to the functions I write xD

I'd like to extent the question to you to know your opinion :)

Collapse
 
marynanogtieva profile image
Maryna Nogtieva • Edited

Hi Francisco,

Thank you for your feedback and an interesting question 🙂
I also do not write custom methods that yield blocks too often. One example that currently comes to my mind is when I was working with Net::SFTP to perform various operations for sftp files: download, upload, rename, get all files.

We also had different ways to connect to SFTP server - via user/password or via ssh/no password.

It could result into something like this

Net::SFTP.start(server, username, { password: password, port: port}) do |sftp|
  sftp.upload!("/local/file.tgz", "/remote/file.tgz")
end

Net::SFTP.start(server, username, { keys: [ssh_key_path] }) do |sftp|
  sftp.upload!("/local/file.tgz", "/remote/file.tgz")
end

One way to make it less redundant would be to create a method that accepts a block (with syntactic sugar parameter &block):

# Some pseudocode will be here
def flexible_sftp(&block)
   if use_ssh?
      return Net::SFTP.start(server, username, { keys: [ssh_key_path] }, &block)
   else
     return Net::SFTP.start(server, username, { password: password, port: port }, &block)
   end
end

 flexible_sftp do |sftp|
    sftp.upload!("/local/file.tgz", "/remote/file.tgz")
 end

Of course, it might be possible to avoid using a custom method here and instead pass some sort of argument hash or object into the method. But the code above is one way to solve the problem.

Another time I used yield is when I used to run performance metrics with RubyProf

RubyProf.measure_mode = RubyProf::WALL_TIME

INITIAL_DATA_FILE = 'fixtures/small.json'
OUTPUT_DIR = 'tmp/data'


def flat_profile
  run_profiler do |result|
    printer = RubyProf::FlatPrinterWithLineNumbers.new(result)
    printer.print(File.open("#{OUTPUT_DIR}/ruby_prof_flat_demo.txt", 'w+'))   
  end
end

def graph_profile
  run_profiler do |result|
    printer = RubyProf::GraphHtmlPrinter.new(result)
    printer.print(File.open("#{OUTPUT_DIR}/ruby_prof_graph_demo.html", "w+"))
  end
end

def run_profiler
  RubyProf.measure_mode = RubyProf::WALL_TIME
  result = RubyProf.profile { JsonImporter.new.import_json_to_db(file_path: INITIAL_DATA_FILE) }
  yield result
end
Collapse
 
cescquintero profile image
Francisco Quintero 🇨🇴 • Edited

Awesome. Thanks for your answer.

I've been asking this question to every one I can (last's year RubyConfColombia I even asked Aaron Patterson 😅) and the answers is almost the same: "not [too] often".

Your examples are really good and this was precisely why I asked. Getting to see blocks being used outside the Ruby API is a way to experience their benefit or possibilities.

Thanks again!