Статьи

Руби Микрофреймворк Сводка новостей

ruby_microframeworks

Попросите кого-нибудь назвать фреймворки Ruby, и большинство людей ответят «Ruby on Rails». Если вы попросите меньшую платформу, они, вероятно, ответят «Синатра» (которая технически не является платформой, это язык, специфичный для предметной области, но давайте не будем слишком технически). Rails и Sinatra — это любимые люди в мире веб-разработки Ruby. Вместе они, кажется, покрывают все основы, которые я заключил в этом посте . Учитывая успех этих двух «рамок», есть ли необходимость в других?

Что ж, получается, что на самом деле существует немало микросхем Ruby, которые работают (с технической точки зрения, некоторые из них тоже DSL, но термин «микрос каркас», похоже, застрял). Вот шесть проектов, которые я нашел на GitHub:

Моей первой реакцией было то, что они, казалось, занимали место, очень похожее на Sinatra, которое, как мне показалось, охватывало область «веб-разработки на микрокадрах». Я задавался вопросом, почему существуют все эти микрофреймы. В чем смысл?

Итак, чтобы выяснить это, я связался с создателями этих микрофреймов и задал им следующие вопросы:

  • Что вдохновило вас на создание собственной платформы Ruby?
  • Как ты придумал имя?
  • Sinatra — это очень минималистичный фреймворк для Ruby, который уже обладает большой популярностью. Что отличает ваш каркас от Sinatra?
  • Почему вы не добавили в Sinatra дополнительные функции, предлагаемые вашей платформой, в виде исправления или расширения?
  • Что вы приобрели, написав свой собственный фреймворк? Это улучшило ваши навыки Ruby?
  • Что ждет вас в будущем?

Я также попросил их предоставить несколько фрагментов кода, демонстрирующих, как работает их микрофрейм.

Прочитав их ответы, стало ясно, что многие из создателей думали, что Синатра не был маленьким или недостаточно сосредоточенным. Все эти проекты имеют гораздо меньшую кодовую базу, чем Sinatra (и они микроскопичны по сравнению с Rails!) Многие из них также сообщают, что они быстрее, чем Sinatra, в тестах производительности. В ряде случаев это было достигнуто за счет прилипания ближе к Rack и избегания синтаксического сахара, предоставляемого многими помощниками Синатры (например, непосредственным использованием метода render В других случаях (например, в Бруклине) это происходило путем сохранения гораздо более узкой области действия, чем у Sinatra, и избежания поддержки со стороны наследия. Некоторые из них, в частности Куба и Scorched, руководствовались желанием использовать иную методологию, нежели Синатра, в частности, в отношении обработки маршрутов. Было также интересно услышать, как многие разработчики сообщают, что их знания о Rack улучшились в результате разработки этих проектов.

Вот ответы:

Вопрос 1 — Что вдохновило вас на создание вашей собственной среды Ruby?

Патрисио Мак Адден, создатель Хоббита:

Я помог Синатре с прошлого года. Это заставило меня погрузиться в Rack, и я хотел поэкспериментировать с созданием каркаса как можно меньше и как можно ближе к Rack.

Итак, это были мои рекомендации:

  • Хоббит должен быть быстрым.
  • Хоббит должен иметь в своей основе только основные вещи: определять маршруты.
  • Хоббит должен быть расширяемым стандартными классами и модулями ruby. Эти расширения (т. Е. Представления рендеринга, сеансы обработки, фильтры, обработка исключений) не будут загружаться по умолчанию.
  • Нулевая конфигурация

Андрей Лисник, создатель New York New York:

Я думаю, что главная причина, по которой я это написал, — учиться Я веб-разработчик, и я хотел знать, как работает вся магия Rack.

Луис Лавена, создатель Бруклина:

Для проекта в нашей компании нам пришлось вывести большую гистограмму в формате JSON (128 КБ). Мы заметили, что даже при высоком уровне кэширования количество запросов, которое наше приложение могло обслуживать, было недостаточным для того, что нам было нужно.

Мы обнаружили, что Синатра брал большой кусок производительности, даже работая в производственном режиме.

Поскольку единственная цель приложения состояла в том, чтобы обслуживать этот JSON, мы начали изучать, в чем может быть проблема, и разобрали почти все на вершине Rack.

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

Том Уордроп, создатель Scorched:

Как бы мне ни нравился Синатра, были некоторые ограничения, которые я нахожу разочаровывающими и ненужными при использовании его в реальном мире. В основном это были проблемы управления кодом и масштабируемости. Вы должны были либо поместить все свои маршруты для всего приложения в один «контроллер», в котором они совместно использовали помощников, фильтры, конфигурацию и т. Д., Либо иным образом попытаться разбить ваше приложение на несколько приложений mini Sinatra и смонтировать их. при разных отображениях с помощью Rack. Ни одно из решений не было элегантным. Я думал, что Падрино может решить некоторые из этих проблем, но нашел это одинаково, если не больше, разочаровывающим.

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

Мишель Мартенс, создатель Кубы:

Я обнаружил небольшой сценарий под названием Rum , созданный автором Rack Кристианом Нойкирхеном. У него были, как мне кажется, две отличные идеи: во-первых, вы можете создавать пути кода в своем приложении на основе любого аспекта запроса, а не только метода HTTP и URI запроса. Это очень мощно, потому что, например, вы можете выбрать другой маршрут в зависимости от того, аутентифицирован ли посетитель, что вы не можете догадаться, взглянув только на метод HTTP и URI. И это всего лишь пример, потому что конструкция onon default ...on 2 + 2 ...

Вторая идея заключается в том, что, вложив on Это означает, например, что после того, как вы сопоставили часть запроса, вам не нужно снова сопоставлять ее. Это делает его очень быстрым в реальных сценариях.

Существует несколько сайтов с открытым исходным кодом, созданных с использованием Кубы, таких как Redis и Punchgirls Jobs Board , а также есть несколько слайдов, объясняющих некоторые основные концепции .

Гильермо Игуаран, создатель Нэнси:

Меня вдохновили некоторые статьи, доклады и книги о простоте авторов, таких как Ричард Габриэль , Рич Хикки и Джон Маеда, рекомендованные Мишелем Мартенсом и некоторыми другими членами сообщества #rubysur. Работа Мишеля Мартенса (@soveran) и Сирила Дэвида (@cyx) в их микроуровне Куба была и остается большим вдохновением.

Вопрос 2 — Как вы пришли к названию?

Патрисио Мак Адден, создатель Хоббита:

Сначала я назвал его «бонсай», но «бонсай» с этим именем уже существовал. Назвать вещи действительно сложно, но, к счастью, разговаривая с моим другом, я придумал имя Хоббит.

Андрей Лисник, создатель New York New York:

Изначально NYNY позиционировался как маленький клон Синатры, поэтому и название (Нью-Йорк, Нью-Йорк — песня Фрэнка Синатры). На данный момент, однако, NYNY имеет другой набор функций.

Луис Лавена, создатель Бруклина:

Компания, в которой я работаю (AREA 17), имеет офис в Нью-Йорке, точнее, в Бруклине. Существует тенденция создания фреймворков, похожих на Синатру, на тему Фрэнка Синатры, штат Нью-Йорк, тогда почему не в другом районе Нью-Йорка? 😉

Том Уордроп, создатель Scorched:

Это игра на СУХОЙ аббревиатуре. Большая часть Scorched предназначена для того, чтобы предоставить разработчикам широкие возможности для сокращения повторений.

Мишель Мартенс, создатель Кубы:

Поскольку это вдохновлено Ромом, я думал о Кубе немедленно. А Куба маленькая и эффективная, и это общие черты библиотеки.

Гильермо Игуаран, создатель Нэнси:

Я считаю Нэнси «ребенком» Синатры, поэтому я выбрала Нэнси в качестве имени, это отсылка к Нэнси Синатре, дочери Фрэнка Синатры. Кроме того, я большой поклонник музыки Нэнси Синатра.

Вопрос 3 — Что отличает ваш каркас от Синатры?

Патрисио Мак Адден, создатель Хоббита:

Это быстрее и выделяет меньше памяти, чем Синатра. Если вы хотите увидеть некоторые тесты, я рекомендую вам посмотреть https://github.com/luislavena/bench-micro Луиса Лавены.

Андрей Лисник, создатель New York New York:

Если Синатра очень минималистичен, то я бы сказал, что NYNY очень, ОЧЕНЬ минималистичен. Исходный код Синатры имеет ~ 2 тыс. Строк. Напротив, у NYNY есть только 300. В то же время, у NYNY не так много вещей, которых не хватает, и Синатра предоставляет. NYNY также на ~ 25% быстрее и имеет более мощный маршрутизатор (он использует маршрутизатор Rails), но не имеет большого количества вспомогательных помощников, которые есть у Sinatra. (например, erb: что-то, что является сахаром поверх рендера)

Луис Лавена, создатель Бруклина:

Синатра реализовал кучу вещей, которые я считаю плохой практикой. К счастью, более новые версии поощряют использование классов Sinatra::Base

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

То, что делает Бруклин, даже близко не похоже на то, что предоставляет Sinatra, и никогда не будет, оно было рождено для того, чтобы обслуживать некоторый тип контента (JSON) и не слишком задумываться о представлениях или других вещах.

Он предназначен для монтирования и объединения с другим промежуточным программным обеспечением Rack в более крупное приложение, а не для самостоятельного создания программного обеспечения.

Том Уордроп, создатель Scorched:

Scorched очень похож на Sinatra с точки зрения DSL, поэтому на первый взгляд люди задаются вопросом, почему я, кажется, только что переписал Sinatra. Основным отличием от Sinatra является введение концепции контроллера. Эти контроллеры могут быть составлены и вложены многими творческими способами и позволяют вам включать помощников, фильтры, обработчики ошибок, условия, конфигурацию и т. Д. В связанные группы маршрутов.

Другое отличие состоит в том, что Scorched пытается быть еще проще и более предсказуемым, чем Sinatra, и, если это возможно, быть еще менее самоуверенным. В Синатре есть несколько вещей, которые могут вас удивить. Синатра иногда делает немного больше, чем вы могли ожидать. Мне бы хотелось думать, что я достиг этих целей благодаря более продуманному дизайну, не поддаваясь искушению добавить слишком много смартов, и не предоставляя функциональность, которая перекрывает Rack. Синатра, как и большинство фреймворков, предоставляет множество помощников, которые абстрагируют Rack. С помощью Scorched я хочу максимально приблизить разработчиков к Rack. Идея в том, что знание Rack переносимо между средами, а помощники и DSL — нет. Если кто-то уже знаком с Rack, этот опыт можно использовать для снижения кривой обучения для Scorched, и наоборот.

Мишель Мартенс, создатель Кубы:

В прошлом я много использовал Sinatra и даже создал несуществующий фреймворк, который называется Monk. Но то, что заставило меня переехать на Кубу, было гибкостью, которую она обеспечивает с очень небольшими накладными расходами. Теперь я нахожу, что Синатра слишком сосредоточен на путях, и на Кубе я могу создавать множество подпрограмм, которые можно монтировать в любом месте и на основе любых критериев. Как побочный продукт, идея вложенного потока управления и тот факт, что у него меньше кода и меньше обязанностей, делают его более производительным, и, вероятно, эти причины облегчают обучение и понимание.

Гильермо Игуаран, создатель Нэнси:

Я бы не стал считать Sinatra «очень минималистской» средой, вам нужно 22 страницы, чтобы напечатать полный код на бумаге, и даже главный сопровождающий может потеряться, копаясь в коде !! Напротив, вы можете напечатать полный код Нэнси всего за 1 страницу.

Нэнси очень мала по сравнению с Sinatra и другими минималистскими фреймворками и в 2 раза быстрее, чем Sinatra.

Вопрос 4 — Почему вы не добавили дополнительные функции, которые ваша платформа предлагает Sinatra?

Патрисио Мак Адден, создатель Хоббита:

Я уже помогаю Синатре. Большинство функций Хоббита вдохновлены Синатрой, но цель Хоббита иная, и большинство из них не совместимы с Синатрой.

Андрей Лисник, создатель New York New York:

Все функции, которыми обладает NYNY, уже есть в Sinatra (кроме маршрутизатора Rails, который использует NYNY), либо в ядре, в пакетах contrib. Я просто реализовал их более простым способом. (опять же, цель состояла в том, чтобы научиться заново изобретать колесо)

Луис Лавена, создатель Бруклина:

Sinatra — это один файл с ~ 1700 SLoC, который определяет несколько классов и соединяет их вместе. Попытки удалить некоторые из унаследованных вещей, которые делает Синатра, или немного изменить эти вещи, возможно, не будут приняты из-за размера таких изменений.

Том Уордроп, создатель Scorched:

Потому что основные черты Scorched — архитектурные. Применение таких изменений к Sinatra нарушило бы обратную совместимость, хотя мне нравится представлять Scorched как подходящую отправную точку для Sinatra 2.0.

Мишель Мартенс, создатель Кубы:

Синатра пытается сделать что-то одно и сделать это хорошо, и для этого нужен очень специфический подход. Такой подход очень хорош, и Куба предлагает другой подход. Я против идеи добавления функций для решения разных задач одним и тем же инструментом. То, что делает Куба, может быть приготовлено в Синатре и наоборот, но в результате получится более сложный и хрупкий инструмент.

Гильермо Игуаран, создатель Нэнси:

У Нэнси нет никаких дополнительных функций, которые Sinatra уже не предлагает, у Нэнси есть «подмножество» функций Sinatra.

Вопрос 5 — Что вы приобрели, написав свой собственный фреймворк? Это улучшило ваши навыки Ruby?

Патрисио Мак Адден, создатель Хоббита:

Да, конечно. Написание собственных библиотек и участие в библиотеках других людей определенно улучшает ваши навыки. В моем случае я многому научился у Луиса Лавены, который просмотрел Хоббит и указал мне много вещей.

Андрей Лисник, создатель New York New York:

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

Луис Лавена, создатель Бруклина:

Я многое узнал о Rack Framework и составе промежуточного программного обеспечения. Я узнал о наследовании переменных класса и сокращении выделения объектов. И последнее, но не менее важное: я узнал о безопасности потоков, вызванной повторным использованием одного и того же экземпляра объекта для обслуживания нескольких запросов.

Том Уордроп, создатель Scorched:

Во-первых, это заставляет вас ценить объем работы, который нужно выполнять даже в относительно простых фреймворках и библиотеках. Теперь я гораздо лучше знаком с Rack и его ограничениями. Это, безусловно, вызвало мой интерес к потенциальной Rack 2.0. Я полагаю, что мои навыки Ruby также были непреднамеренно усовершенствованы. Неважно, над каким проектом я работаю, мне всегда нравится искать как можно больше креативных решений, пытаясь найти это идеальное решение, сталкиваясь с ограничениями языка, которых в Ruby так мало, поэтому почему я люблю это

Мишель Мартенс, создатель Кубы:

Я получил возможность экспериментировать с идеями Рома. Первой версией Кубы был Rum с некоторыми исправлениями и несколькими дополнениями, чтобы упаковать его в драгоценный камень. Позже некоторые коллеги начали использовать его, и он ему понравился, а затем некоторые люди начали работать с клиентом, что доказало, что другие люди также интересовались подходом Рума.

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

Гильермо Игуаран, создатель Нэнси:

Я значительно улучшил свои навыки Ruby. Благодаря проекту, я много узнал о Rack, это помогло мне понять более крупные фреймворки, такие как Rails, и стать членом основной команды Rails .

Вопрос 6 — Что ждет вас в будущем?

Патрисио Мак Адден, создатель Хоббита:

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

Я также написал Hat , шаблон приложения для Hobbit:. Это своего рода более полная структура поверх Хоббита.

Андрей Лисник, создатель New York New York:

На данный момент я чувствую, что NYNY довольно завершен. Я использую его как на работе, так и в свободное время для хобби-проектов. Философия заключается в том, что NYNY должен оставаться простым и понятным. Все, что приходит мне в голову, я реализую как расширение NYNY. (например, интеграция звездочек)

Луис Лавена, создатель Бруклина:

Я думаю, что это не вырастет за пределы того, что сейчас. Он служил своей цели и делает то, к чему стремился. На некоторых путях производительности это может стать немного лучше (попытка уменьшить распределение объектов и методы сопоставления URL)

Том Уордроп, создатель Scorched:

Нет никаких причин, по которым он не может достичь популярности Sinatra, хотя для этого потребуется значительное количество документации, адаптированной для тех, кто менее опытен в Ruby и других веб-инфраструктурах Ruby. Мне было бы трудно представить, что кому-то может понравиться Синатра, но не Scorched. На данный момент Scorched ориентирован на более опытных веб-разработчиков на Ruby; те, кто уже знаком с Rack и Sinatra.

Что касается будущего развития. Я надеюсь выпустить v1.0 в ближайшее время. Мне по-прежнему нужно проверять структуру в некоторых реальных приложениях, чтобы не было очевидных вещей, которые я пропустил. Библиотека contrib также есть на картах, хотя, вероятно, не раньше выпуска v1.0. Скорее всего, я на данный момент просто добавлю в ядро ​​все дополнения в стиле contrib, например мою упрощенную реализацию content_for для шаблонов ERB, которую мне пришлось создать для проекта, который я портирую из Padrino в Scorched.

Мишель Мартенс, создатель Кубы:

Это небольшой инструмент, и он стабилен, впереди нет никакой работы. Мы находимся в версии 3.1.1, которая вышла около месяца назад, но было только одно маленькое изменение по сравнению с предыдущей версией. За два года в нем не было каких-либо серьезных изменений, и это признак того, что он работает нормально.

Гильермо Игуаран, создатель Нэнси:

В последнее время фреймворк привлек к себе некоторое внимание и интерес, есть некоторый интерес к тому, чтобы рассматривать его как один из проектов для Rails Girls Summer of Code в этом году, надеюсь, я буду работать над наставничеством для группы студентов, улучшая его этим летом !! !

Образцы кода

Я хотел увидеть несколько примеров использования этих микрофреймов, поэтому попросил каждого из создателей предоставить два фрагмента кода, которые достигли тех же результатов, что и приложение Sinatra, которое я написал.

Фрагмент 1 — Привет

Первым примером кода была простая программа «Hello World», которая взяла именованный параметр из URL. Я использовал помощник и встроенные представления в Синатре. Было интересно отметить, что только одна из этих платформ (NYNY) обеспечивала встроенные представления, и все они использовали основанный на классах стиль приложения, который похож на модульный стиль Синатры. С Синатрой, безусловно, много общего, и многие из микрофреймов использовали схожие идеи в некоторых случаях. Например, и Hobbit, и Scorched рассматривают все методы класса как помощники:

 require 'sinatra'

helpers do
  def greeting name
    "Howdy #{name}"
  end
end

get '/:name' do
  @message = greeting params[:name]
  erb :hello
end

__END__
@@hello
<h1><%= @message %></h1>

Хоббит

 require 'hobbit'
require 'hobbit/contrib'

class App < Hobbit::Base
  include Hobbit::Render

  # all methods in this class are helpers!
  def greeting(name)
    "Howdy #{name}"
  end

  get '/:name' do
    @message = greeting request.params[:name]
    render 'hello', {}, layout: false
  end
end

run App.new

просмотров / hello.erb:

 <h1><%= @message %></h1>

NYNY

 require 'nyny'
TEMPLATE = Tilt::ERBTemplate.new { DATA.read }

class App < NYNY::App
  helpers do
    def greeting name
      "Howdy #{name}"
    end
  end

  get '/:name' do
    @message = greeting params[:name]
    TEMPLATE.render(self)
  end
end

App.run!

__END__
<h1><%= @message %></h1>

Brooklyn

 require "brooklyn"

class HelloApp < Brooklyn::App
  helpers do
    def greeting(name)
      "Howdy #{name}"
    end
  end

  get "/:name" do
    "<h1>#{greeting(params[:name])}</h1>"
  end
end

выжженный

 require 'scorched'

class App < Scorched::Controller
  get '/:name' do
    @message = greeting(captures[:name])
    render :hello
  end

  def greeting(name)
    "Howdy #{name}"
  end
end

просмотров / hello.erb:

 <h1><%= @message %></h1>

Куба

 require "cuba"
require "hache"

def greeting(name)
  "Howdy #{Hache.h(name)}"
end

Cuba.define do
  on get, :name do |name|
    res.write sprintf('<h1>%s</h1>', greeting(name))
  end
end

Нэнси

 require 'nancy'
require 'nancy/render'

module Helpers
  def greeting name
    "Howdy #{name}"
  end
end

class App < Nancy::Base
  include Nancy::Render
  include Helpers

  get '/:name' do
    @message = greeting params['name']
    render 'hello.erb'
  end
end

hello.erb

 <h1><%= @message %></h1>

Фрагмент 2 — список дел

Второй фрагмент кода был примером приложения RESTful To Do List, в котором использовался сервер базы данных (я использовал DataMapper, который по общему признанию устарел, но работает!). Вот мой пример в Синатре:

 require 'sinatra'
require 'datamapper-core'

DataMapper.setup(:default, ENV['DATABASE_URL'] || "sqlite3://#{Dir.pwd}/development.db")
class Task
  include DataMapper::Resource
  property :id, Serial
  property :name, String, :required => true
  property :completed_at, DateTime
end

get '/tasks' do
  @tasks = Task.all
  erb :index


get '/task/:id' do
  @task = Task.get(params[:id])
  erb :task
end

post '/task' do

  Task.create(:name => params[:name])
  redirect '/tasks'

end

put '/task/:id' do
 task = Task.get(params[:id])
 task.completed_at = params[:completed] ? Time.now : nil task.name = (params[:name])

  redirect '/tasks'

end

delete '/task/:id' do
  Task.get(params[:id]).destroy
  redirect '/tasks' 
end

А вот примеры из микрофреймворка. Интересно отметить, что некоторые авторы использовали разные адаптеры баз данных. Аналогичным образом, некоторые из них также использовали дополнительные драгоценные камни или плагины для достижения некоторых результатов, которых Синатра достигает «из коробки», что соответствует их минималистическим амбициям. Некоторые из этих фреймворков даже имеют свои собственные жемчужины ‘contrib’, которые при необходимости добавляют дополнительную функциональность (что и делает Sinatra).

Хоббит

 require 'hobbit'
require 'hobbit/contrib'
require 'datamapper-core'

DataMapper.setup(:default, ENV['DATABASE_URL'] || "sqlite3://#{Dir.pwd}/development.db")

class Task
  include DataMapper::Resource
  property :id, Serial
  property :name, String, :required => true
  property :completed_at, DateTime
end

class App < Hobbit::Base
  include Hobbit::Render

  use Rack::MethodOverride

  get '/tasks' do
    @tasks = Task.all
    render 'index'
  end

  get '/task/:id' do
    @task = Task.get(request.params[:id])
    render 'task'
  end

  post '/task' do
    Task.create(:name => request.params[:name])
    redirect '/tasks'
  end

  put '/task/:id' do
    task = Task.get(request.params[:id])
    task.completed_at = request.params[:completed] ? Time.now : nil task.name = (request.params[:name])
    response.redirect '/tasks'
  end

  delete '/task/:id' do
    Task.get(request.params[:id]).destroy
    response.redirect '/tasks'
  end
end

run App.new

NYNY

 require 'nyny'
require 'data_mapper'

DataMapper.setup(:default, ENV['DATABASE_URL'] || "sqlite3://#{Dir.pwd}/development.db")
class Task
  include DataMapper::Resource
  property :id, Serial
  property :name, String, :required => true
  property :completed_at, DateTime
end

class App < NYNY::App
  get '/tasks' do
    @tasks = Task.all
    render 'index.erb'
  end

  get '/task/:id' do
    @task = Task.get(params[:id])
    render 'index.erb'
  end

  post '/task' do
    Task.create(:name => params[:name])
    redirect '/tasks'
  end

  put '/task/:id' do
    task = Task.get(params[:id])
    task.completed_at = params[:completed] ? Time.now : nil
    task.name = (params[:name])
    task.save!
    redirect '/tasks'
  end

  delete '/task/:id' do
    Task.get(params[:id]).destroy
    redirect '/tasks'
  end
end

App.run!

Brooklyn

Луис Лавена сказал, что Бруклин не предназначен для создания подобного приложения, и предложил использовать Хоббит.

выжженный

 require 'scorched'
require 'sequel'

Sequel::Model.db = Sequel.sqlite("development.db")

class Tasks < Sequel::Model
  db.create_table? :tasks do
    primary_key :id
    String :name
    DateTime :completed_at
  end
end

class App < Scorched::Controller
  controller '/tasks' do
    get '/' do
      @tasks = Tasks.all
      render :index
    end

    get '/:id' do
      render :task, locals: {task: task}
    end

    post '/' do
      id = Tasks.insert(:name => request.POST['name'])
      redirect "/tasks/#{id}" 
    end

    put '/:id' do
      task.update(completed_at: (request.POST['completed'] ? Time.now : nil), name: request.POST['name'])
      redirect "/tasks/#{captures[:id]}" 
    end

    delete '/:id' do
      task.delete
      redirect "/tasks" 
    end

    def task(id = captures[:id])
      Tasks[id] || halt(404)
    end
  end
end

Куба

 require "cuba"
require "cuba/contrib"
require "mote"
require "ohm"

# Plugins
Cuba.plugin Cuba::Mote
Cuba.plugin Cuba::TextHelpers

# Middlewares
Cuba.use Rack::MethodOverride

# Ohm is an object-hash mapper for Redis.
class Task < Ohm::Model
  attribute :name
  attribute :completed_at
end

Cuba.define do

  # Here we match the path "tasks" no matter which HTTP method is
  # used. Later on we will inspect the method to decide what to do.
  on "tasks" do

    # This matcher (a symbol) captures a segment in the requested
    # path. In our case, it will match the id of the task.
    on :id do |id|

      # As the `on` blocks are closures, we can fetch the task here
      # and use it in the subsequent blocks.
      task = Task[id]

      # This block will match only if we found a task.
      on task do

        # If the request method was a GET...
        on get do
          res.write view("task", task: task)
        end

        # If the request method was a DELETE...
        on delete do
          task.delete

          res.redirect "/tasks"
        end

        # If the request method was a PUT...
        on put do

          # Check if we got the `completed` parameter.
          on param(:completed) do
            task.update(completed_at: Time.now)
            res.redirect "/tasks"
          end

          # Check if we got the `name` parameter.
          on param(:name) do |name|
            task.update(name: name)
            res.redirect "/tasks"
          end

          # If no block matched so far, it was a bad request.
          on default do
            res.status = 400
            res.write "Bad request"
          end
        end
      end

      # If we didn't find a task, we return 404.
      on default do
        res.status = 404
        res.write "Not Found"
      end
    end

    # This matches "/" from the place the route is mounted. In this
    # case, as this block is nested inside "tasks", it will match if
    # nothing else comes after "/tasks/".
    on root do

      # If the request method was a GET...
      on get do
        res.write view("tasks", tasks: Task.all)
      end

      # If the request method was a POST...
      on post do |name|
        Task.create(name: req[:name])

        res.redirect "/tasks"
      end

      # If no other block matched...
      on default do
        res.status = 404
        res.write "Not Found"
      end
    end
  end

  # This matches "/".
  on root do
    res.write view("home")
  end
end

Нэнси

 require 'nancy'
require 'nancy/render'
require 'data_mapper'

DataMapper.setup(:default, ENV['DATABASE_URL'] || "sqlite3://#{Dir.pwd}/development.db")

class Task
  include DataMapper::Resource
  property :id, Serial
  property :name, String, required: true
  property :completed_at, DateTime
end

DataMapper.finalize

class TaskApp < Nancy::Base
  include Nancy::Render
  use Rack::MethodOverride
  use Rack::Static, :urls => ["/javascripts", "/stylesheets"], root: 'public'

  get '/' do
    redirect '/tasks'
  end

  get '/tasks' do
    @tasks = Task.all
    render('views/layout.erb'){ render 'views/index.erb' }
  end

  get '/task/:id' do
    @task = Task.get(params['id'])
    render('views/layout.erb'){ render('views/task.erb', { task: @task }) }
  end

  post '/task' do
    Task.create(name: params['task']['name'])
    redirect '/tasks'
  end

  put '/task/:id' do
    task = Task.get(params['id'])
    task.completed_at = params['task']['completed'] ? Time.now : nil
    task.name = params['task']['name'] if params['task']['name']
    task.save
    redirect '/tasks'
  end

  delete '/task/:id' do
    Task.get(params['id']).destroy
    redirect '/tasks'
  end
end

Есть еще кое-что!

Пока я писал эту статью, я обнаружил еще больше микрофреймов Ruby, которые, возможно, стоит изучить — вот они:

Это все люди

На этом мой вихревой взгляд на микрорамки Руби завершается, надеюсь, вам было интересно. Слышали ли вы о каком-либо из них раньше или даже использовали их? Вы знаете что-нибудь, что я пропустил?

Вы испытывали желание попробовать некоторые из них? Может быть, вы могли бы переписать проект, используя один из них? Вам понравился звук какой-либо из конвенций, которые некоторые из них использовали? С Sinatra 2.0 на горизонте, возможно, он мог бы позаимствовать некоторые концепции, используемые в них.

Вы думаете, что Ruby нужно так много «фреймворков»? Или вас даже вдохновило заняться написанием вашей собственной микрофреймы Ruby (или вы уже сделали это)?

Как обычно, оставляйте свои ответы в комментариях ниже.