Рубиновая путаница с блоками - PullRequest
2 голосов
/ 11 августа 2010

Я изучаю Ruby (использую книгу Pickaxe), и я столкнулся с небольшой путаницей в операции с блоком, которая выглядит примерно так:

class CsvReader
  def initialize
    @book_in_stock = []
  end

  def read_in_csv_data(csv_file_name)
    CSV.foreach(csv_file_name, headers: true) do |row| # 1.
      @book_in_stock << BookinStock.new(row["ISBN"], row["Amount"]) # 2.
    end
  end
end

Моя путаница с комментариями "#1 "и" # 2 ", я не понимаю, как мы получаем" 123 "и" 456 "из csv_file_name файла" test.csv ", содержащего данные:

"ISBN","Amount"
"123","456"

Как эта строка["ISBN"] знает, что ему соответствует следующий ряд?Все ли блоки ведут себя так?Как они на самом деле называются?Может ли кто-нибудь объяснить их немного лучше?

Ответы [ 5 ]

2 голосов
/ 11 августа 2010

Блоки - это рубиновая идиома для описания замыкания или блок кода, имеющий собственную область видимости (ему не нужно знать о других частях кода). Блоки имеют два стиля: если код занимает более одной строки, вы используете синтаксис do (с учетом структуры данных или некоторого перечислимого имени @entries)

@entries.each do |entry|
  #do something
end

если он в одной строке, вы можете упростить блок как таковой

@entries.each{|entry| execute something here}

в явном виде, то, что делает любой блок кода, - это передавать по одной записи за раз, назначаться записи и выполнять над ней операцию. Это как анонимная внутренняя функция.

Поначалу их немного сложно понять, но они действительно полезны во всем мире рубинов. У нас иногда бывает блокит.

В качестве варианта использования учтите, что мы хотим что-то сделать с каждым значением в массиве.

[1,2,3].map{|item| item+1} #=> takes each item in the array gets one added to it

что не так очевидно, так это то, что эта функция возвращает массив [2,3,4], потому что внутренняя функция заботится об итерации по структуре данных. Это гораздо удобнее и декларативнее, чем иметь другую функцию, которая работает над массивом, и еще одну, чтобы добавить одну к каждому элементу.

в примере csv вы берете каждую строку и добавляете ее в структуру данных с именем @books_in_stock, но это не так явно, я думаю, как в приведенном мной примере. Посмотрите класс Enumearble http://apidock.com/ruby/Enumerable, где приведено много хороших примеров использования блоков.

1 голос
/ 11 августа 2010

Лично я не использовал класс CSV в Ruby, но, похоже, поскольку ему говорят, что «headers: true», предполагается, что первая строка содержит заголовки, а каждая следующая строка представляет собой данные, соответствующие заголовку над ним.

0 голосов
/ 11 августа 2010

поступающая строка обрабатывается как хеш, поэтому row["ISBN"] вызывает ISBN-ключ, который устанавливается в первый раз через блок, потому что вы устанавливаете заголовки в true как один из параметров foreach CSV. поэтому значение ключа для ISBN равно 123. Синтаксис Ruby выглядит как "isbn" => "123" или key => value

в этом случае каждая входящая строка обрабатывается как отдельный хеш, где ключ задается строкой заголовка, а значение получается из размещения в строке csv.

0 голосов
/ 11 августа 2010

Хорошо, поэтому, когда вы создаете блок с использованием do...end или {...}, вы фактически создаете анонимный метод:

my_method do |arg1,arg2|
  ...
end

- это то же самое, что и

def ... arg1, arg2
  ...
end

Дело в том, что метод, который вы вызываете (foreach), может вызывать код кода внутри вашего блока do...end в любое время и с любыми аргументами, которые он выберет.Для метода foreach он будет вызывать ваш блок один раз для каждой строки, с которой он имеет дело, и строка будет доступна внутри переменной row (по-разному каждый раз), как если бы это был аргумент метода

РЕДАКТИРОВАТЬ

Ответ на ваш конкретный вопрос заключается в тип переменной, которая передается в строку.Похоже, что это объект CSV :: Row, который определяет метод row.[], который позволяет вам получить значение для той строки, которая появляется под заголовком, который вы передаете в

0 голосов
/ 11 августа 2010

Это особенность встроенного модуля CSV, который поставляется с Ruby.При создании объекта CSV вы передаете флаг headers: true, который сообщает объекту csv имена или столбцы, а также количество столбцов.После этого метод foreach, определенный в классе cvs, устанавливает строку псевдонимов для каждой строки в таблице.строка хеша затем заполняется данными в каждой строке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...