Вы можете объяснить, что происходит в этом коде 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 обрабатывать это.