2009-07-04 2 views
6

Я сейчас изучаю Ruby, а также Ruby on Rails. Я следую вместе с Learning Rails, 1-е издание, но мне сложно понять некоторые из кода.Можете ли вы объяснить, что происходит в этом коде Ruby?

Как правило, я работаю на C, C++ или Java, поэтому Ruby для меня очень большой.

Я сейчас озадачен со следующим блоком кода для Migrator базы данных:

def self.up 
    create_table :entries do |t| 
     t.string :name 
     t.timestamps 
    end 
    end 

Где приходит переменная т от? Что это на самом деле представляет? Разве это похоже на «i» в выражении for (i = 0; i < 5; i ++)?

Кроме того, где: записи определены в? (записи - это имя моего контроллера, но как эта функция знает об этом?)

+0

Не обманывайтесь, думая, что Ruby do ... end или {} блоки такие же, как {} в C/C++/Java: хотя иногда их можно использовать таким образом, они действительно работают по-разному, поскольку вы заметили. –

ответ

9

:entries является символом буквальным, это буквенное значение, как 7 или "a string". Нечего определять (кстати, функция не знает о имени вашего контроллера).

t - это параметр для блока, который вы передали методу create_tables.То, что вы здесь написали, примерно аналогично примерно:

void anonymous_block(Table *t) { 
    t->string("name"); 
    t->timestamps(); 
} 

... 

create_table("entries", &anonymous_block); 

в C++. create_table вызывает ваш блок и передает ему параметр, который вы назвали t. Я предлагаю вам получить вступительную книгу для ruby ​​ в отличие от рельсов. Я рекомендую Ruby For Rails автор David A. Black.

1

create_table - метод, который принимает лямбда-выражение (некий делегат), t - аргумент делегата. Поэтому, когда вы выполняете create_table это выполнить

t.string :name 
t.timestamps 

что-то вроде псевдо-код

delegate d = funciton (t) { 
    t.string :name 
    t.timestamps 
} 
create_table(d); 

Прямой аналог в Java является Anonimous классы ..

addReturnBackListener(new Listener<EventObject>() { 
    public void handle(EventObject e) { 
    refreshAndShowAndList(); 
    } 
}); 

": записи" не определен вообще , это просто идентификатор. Вы можете рассматривать его как простую строку (но не тратя память на сохранение символов).

+0

Выражение Lambada? ;-) –

+0

yep, нужно что-то исправить мои ошибки :) –

2

Я возьму t вещь. Метод create_table подобен функции C, которая принимает указатель на функцию, которая принимает один аргумент, объект определения таблицы (простят мои несуществующие навыки C):

void entries_table_constructor(TableDef table_definition) { 
    table_def_add_string_column(table_definition, "name"); 
    table_def_add_timestamps_column(table_definition); 
}  

create_table("entries", entries_table_constructor); 

Но в Рубине, определение пройденного функции может выполняться в момент вызова метода create_table. Поэтому бит между и end похож на функцию entries_table_constructor, а переменная t похожа на аргумент table_definition.

Существует большая разница между указателями функций в C и блоками в Ruby. В Ruby, все локальные переменные вне блока доступны внутри блока:

a = 10 
create_table :entries do |t| 
    puts a 
    ... 
end 

Отъезда yield ключевого слова в Ruby, чтобы увидеть, как писать свои собственные методы, как create_table.

0

Это типичное использование блоков в Ruby. Метод create_table определен в ActiveRecord, как:

def create_table(table_name) 
    table_object = some_table_setup 
    yield(table_object) # your code block which was passed implicitly is invoked here 
    create_table(table_object) 
end 
1

: записи относятся к таблице записей в Rails.

Мигратор знал бы об этом, когда команда «генерировать контроллер» была дана, насколько я понимаю (профессионально работал с Rails в течение года, но все еще учился).

Что касается | t | это блок. Цитирую книгу Кирка (который вы должны получить копию либо PDF или версии мертвого дерева сразу):

Блоки могут быть использованы для определения кусок кода, который должен быть запущен под какой-то транзакционных управления. Например, вы часто открываете файл, делаете что-то с его содержимым, а затем хотите, чтобы файл был закрыт, когда вы закончите. Хотя вы можете сделать это с помощью обычного кода, есть аргумент в пользу того, что файл отвечает за закрытие. Мы можем сделать это с помощью блоков.

Итак, что происходит с выше, это то, что | t | это блок, который обрабатывает настройку соединения с базой данных, создание строк в соответствии с их конкретными типами, а затем закрытие соединения.

Вот еще один пример:

output_string = "Let's print this to file" 

File.open('outputfile.txt','w') do |f| #f for file 
    f.print output_string 
end 

Как для итератора, да, вы можете сделать это, а также:

an_array = [1,2,3,4] 
an_array.each do |line|#line is the block for the elements of the array during iteration 
    puts "Now we are at: #{line.to_s}!" 
end 
+0

Вот ссылка на первое издание книги «Программирование рубинов» (так называемая книга «Пикакс») http://www.rubycentral.com/book –

1

Метод create_table является то, что известно как блок в Рубине и t является переменная, которая является локальной для этого блока (t - это всего лишь соглашение в миграциях Rails, которое означает «таблица»). Это еще более очевидный пример блока Рубина:

10.times do |i| 
    print "i is #{i}" 
end 

:entries является символом рубина, который является своим родом легких строк, который используется для обозначения вещей. Вы могли бы в равной степени использовать "entries". Одно общее использование символов - это указание ключей в хеше. В любом случае создаваемая таблица называется «записями».

+0

Nice краткий хороший +1 –

0

записей является ссылкой на модель входа - каждая модель предполагает, что имя таблицы будет таким же, как его имя, кроме tableized (http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/String/Inflections.html#M001653)

Т является параметр блока передается в create_table методы см http://www.rubycentral.com/book/tut_containers.html для лучшего примера. В этом случае т означает таблицу, которая была создана (http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#M002191)

Хотелось бы надеяться, что должно быть достаточно, чтобы помочь вам

1

Я случиться, чтобы работать над приложением, которое также имеет Entry модель/entries таблицу.Вот моя миграция:

class CreateEntries < ActiveRecord::Migration 
    def self.up 
    create_table :entries do |t| 
     t.string :title 
     t.text :entry 
     # ... 
    end 
    end 

    def self.down 
    drop_table :entries 
    end 
end 

Очень похоже на то, что вы смотрите.

Прежде всего, первая строка, объявляющая класс CreateEntries, который распространяется ActiveRecord::Migration.

Далее, объявив метод класса up(). Метод класса, в отличие от метода экземпляра, относится к классу, а не к конкретным объектам класса. Это ключевое слово «self», которое вызывает его метод класса.

Следующая вызова create_table() и передавая ему две вещи:

  1. символ (":entries"), который, как уже упоминалось выше, является как струна буквальным. Это говорит ActiveRecord, что должна быть вызвана создаваемая таблица. Допустим, вы набрали этот код вручную - забудьте о генераторах на минуту. Вы набрали «:entries», потому что знаете, что по таблицам конвенций в приложении Rails называются множественными именами, и вы знаете, что класс модели, который подключается к этой таблице, будет называться Entry.

  2. Прохождение блока.

Блок может быть заключен ...

`do ... end` 

или

`{ ... }` 

Блок может принимать параметры, заключенные двумя "|" с. В этом случае метод create_table передает блоку объект класса TableDefinition, поэтому, чтобы ответить на один из ваших вопросов, t - это var, удерживающий этот объект. Затем внутри блока мы вызываем различные методы экземпляра TableDefinition.

Откуда взялся объект TableDefinition? Это происходит в методе create_table(). Он содержит код, который создает новый объект TableDefinition и «выходы» его блок ....

ActiveRecord исходный код ...

def create_table(table_name, options = {}) 
    table_definition = TableDefinition.new(self) 
    table_definition.primary_key(options[:primary_key] || "id") unless options[:id] == false 

    yield table_definition 

    # ... 

end 
0

: entries это определяется прямо там. Код вызывает метод create_table с двумя аргументами - нужным именем таблицы и блоком кода.

create_table будет строить объект TableDefinition, а затем перейти к блоку кода, предоставив ему этот объект. В блоке кода он будет называться t. И, наконец, этот блок кода вызывает некоторые методы на t для построения столбцов.

0

Так как, исходя из Python, я изо всех сил пытался понять эту конструкцию, я дам непитонический перевод фрагмента кода.

Во-первых, вы должны определить функцию create_table как этот (это просто скелет):

def create_table(name, setup): 
    t = Table(name) 
    setup(t) 

Затем для каждой таблицы, вы можете создать функцию настройки как:

def setup_entries(t): # <-- here is your |t|, just a function argument 
    t.string("name") 
    t.timestamps() 

И, наконец, вы можете создать таблицу по телефону:

create_table("entries", setup_entries) 

это не так, было бы сделано с Python. Если вы заинтересованы в том, как создавать таблицы в Python, вы должны посмотреть на то, как это обрабатывает django, или sqlalchemy.