Вы можете объяснить, что происходит в этом коде Ruby?
Я пытаюсь выучить Ruby, а также Ruby on Rails прямо сейчас. Я следую вместе с Learning Rails, 1-е издание, но мне трудно понять некоторые части кода.
Я обычно работаю на C, C++ или Java, так что Ruby-это довольно большое изменение для меня.В настоящее время я озадачен следующим блоком кода для миграции базы данных:
def self.up
create_table :entries do |t|
t.string :name
t.timestamps
end
end
Откуда берется переменная t? Что же она на самом деле представляет? Это что-то вроде "Я" в a для оператора(i=0;i
Кроме того, где определяются записи:? (записи-это имя моего контроллера, но откуда эта функция знает об этом?)
10 ответов:
: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 Дэвида А. Блэка.
Я возьму эту штуку
t
. Методcreate_table
подобен функции C, которая берет указатель на функцию, которая принимает один аргумент, объект определения таблицы (простите мои несуществующие навыки C):Но в Ruby определение передаваемой функции может быть выполнено в момент вызова метода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
. Таким образом, бит междуdo
иend
подобен функцииentries_table_constructor
, а переменнаяt
подобна аргументуtable_definition
.Существует большая разница между функцией однако указатели в C и блоки в Ruby. В Ruby все локальные переменные вне блока доступны внутри блока:
a = 10 create_table :entries do |t| puts a ... end
Проверьте ключевое слово
yield
в Ruby, чтобы увидеть, как написать свои собственные методы, такие какcreate_table
.
:entries-ссылка на таблицу entries в 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
Create_table-это метод, который принимает лямбда-выражение (своего рода делегат), t-аргумент делегата. Поэтому, когда вы выполняете create_table, он выполняет
t.string :name t.timestamps
Что-то вроде псевдокода
Прямым аналогом в java являются анонимные классы..delegate d = funciton (t) { t.string :name t.timestamps } create_table(d);
addReturnBackListener(new Listener<EventObject>() { public void handle(EventObject e) { refreshAndShowAndList(); } });
": entries " вообще не определяется, это просто идентификатор. Вы можете рассматривать его как простую строку (но не тратя память на хранение символов).
Метод
create_table
- это то, что известно как блок в Ruby, аt
- это переменная, локальная для этого блока (t
- это просто соглашение в миграциях Rails, которое расшифровывается как "таблица"). Это еще один более очевидный пример блока Ruby:10.times do |i| print "i is #{i}" end
:entries
это символ Рубина, который является своего рода легкой строкой, используемой для именования вещей. Вы могли бы также использовать"entries"
. Одним из распространенных способов использования символов является указание ключей в хэше. В любом случае, создаваемая таблица является названные "записи".
Я работаю над приложением, которое также имеет
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()
и передача ему двух вещей:
Символ ("
:entries
"), который, как упоминалось выше, похож на строковый литерал. Это говорит ActiveRecord, что таблица, которую он создает, должна называться. Допустим, вы набрали этот код вручную-забудьте на минуту о генераторах. Вы набрали ":entries
", потому что знаете, что по соглашению таблицы в приложении Rails называются существительными множественного числа, и вы знаете, что класс модели, который подключается к этой таблице, будет называтьсяEntry
.Тоже проезжая квартал.
Блок может быть заключен...
`do ... end`
Или по
`{ ... }`
Блок может принимать параметры, заключенные в два "
|
"s. в этом случае метод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
Записи-это ссылка на вашу модель записи - каждая модель предполагает, что имя таблицы будет таким же, как и ее имя, за исключением таблицы.(http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/String/Inflections.html#M001653)
T-это параметр блока, передаваемый в метод create_table, см. http://www.rubycentral.com/book/tut_containers.html для лучшего примера. В этом случае t означает таблицу, которая была создана (http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#M002191)
Надеюсь, этого будет достаточно, чтобы помочь вам
Это типичное использование блоков в 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
:
entries
это определяется прямо там. Код вызывает методcreate_table
с двумя аргументами-желаемым именем таблицы и блоком кода.Create_table построит объект
TableDefinition
и затем уступит блоку кода, поставляя ему этот объект. Внутри блока кода он будет называтьсяt
. И, наконец, этот блок кода вызывает некоторые методы наt
для построения столбцов.
Поскольку, исходя из 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 обрабатывать это.