-1

If someone could shed a light for me, or show an equivalent (if one exists) in PHP-style code, I'd really love it.

This piece of code:

require 'sqlite3'
SQLite3::Database.new("metadata.db").execute("SELECT * from BOOKS") do |row|
        puts row
end

uses execute method to issue an SQL query. It's doing a loop, but on what? On the returned value of that query? Can you append a block of code to any expression and it will work on its return value? It seems like the loop isn't connected to anything, and |row| appears from nowhere.

For comparison, in PHP to access a database I would write

$db = new mysqli('details');
$results = $db->query("SELECT * FROM books");
while ($row = $results->fetch()) {
    echo $row[0];
}

which says to create a database, store the results of a query as results, then start a loop in which each row of that result is turned into an array to be accessed with array notation. Is that not how Rubyists would do it? What's going on here?

sawa
  • 165,429
  • 45
  • 277
  • 381
GreenTriangle
  • 2,382
  • 2
  • 21
  • 35
  • That is not how rubyists would do it, because it's verbose and ugly. Blocks don't just work automatically on return values, either. This type of operation is discussed in many Ruby tutorials, maybe it would be best to start there. You can also search for things like "writing ruby methods that range blocks" so you can see how to do your own, which may be more educational. – Dave Newton Feb 28 '14 at 11:32
  • And many JS libraries use similar techniques, btw, but with a function instead of a block. It's very similar. – Dave Newton Feb 28 '14 at 11:33
  • Consider block as an algorithm passed as parameter to method, method is able to execute it. Block might have some arguments and method should pass values to block when calling it. Why not read some book on Ruby? – taro Feb 28 '14 at 11:37
  • blocks/proc objects in ruby are synonymous to anonymous functions in JS – bjhaid Feb 28 '14 at 12:52

3 Answers3

1

It's doing a loop, but on what? On the returned value of that query?

Right. In your example row is whatever is generated by

SQLite3::Database.new("metadata.db").execute("SELECT * from BOOKS")

In this case row a reasonable thing to call this because any actions you do in the block will be based on that row from the db, but you can choose to call this 'block argument' anything you want.

Is this a thing that happens in Ruby, where you can immediately append a block of code to any expression and it'll work on its return value?

Not really, no. There are some methods that take block arguments - each is a good example.

If you have a collection of, say, cats at the animal hospital, you can loop through them and do operations on each cat because each takes a block argument.

#pretend these cats are objects and not just a string name
cats = [ "mrs. muffin face", "princess cupcake", "deathlord 666", ...]

cats.each do |cat|
  #do stuff with each cat here.  print their name, find their shoe size, etc
end

Blocks are a very fundamental ruby concept, so it's probably worth reading a bit more about them - this answer links to Why's (poignant) guide to ruby which is generally a good basic reference. I would also suggest Eloquent Ruby for more thorough examples of Ruby.

Community
  • 1
  • 1
dax
  • 10,779
  • 8
  • 51
  • 86
0

You seem to be assuming that a block is something that loops on a result, but that is not necessarily correct. A block in Ruby is opposed to arguments. Whereas arguments are evaluated before the execution of the main method, a block is not evaluated in advance. Whether to evaluate that block, under what bindings it is to be evaluated, what timing it is to be evaluated, and how many times it is to be evaluated, all is up to the main method. The block variable in | | is a parameter that the main method passes to the block. Often, elements of the value the main method would have returned without the block are passed one after another, which is the case you had in mind, but that is not always the case.

sawa
  • 165,429
  • 45
  • 277
  • 381
0

Here is how execute might be coded in Ruby

class SQLite3::Database
  def execute(query_str)
    results = db.query(query_str)
    while (row = results.fetch)
      yield row
    end
  end
end

(assuming db.query and results.fetch work as you would expect from PHP). As you can see, this is nearly identical to what you're used to from PHP except for that weird yield. As the method loops through the rows of the result, yield passes each row to the block.

This lets you focus on the important stuff (what to do with each row) while hiding away the incidental details (like iterating over a result variable).

Max
  • 21,123
  • 5
  • 49
  • 71