RubyMotion: нативные iOS приложения на Ruby (перевод)


В 2007 году Лоран Сансонетти, разработчик из Apple, основал проект с открытым исходным кодом MacRuby. Его целью было создание интерпретатора Ruby поверх среды исполнения Objective-C, который бы обеспечивал прозрачное взаимодействие между Ruby и экосистемой OS X «Cocoa» — и ему это удалось. Теперь Сансонетти надеется сделать что-то подобное и под iOS.


С недавних пор Сансонетти уволился из Apple, где он работал последние семь лет, чтобы основать свой стартап под названием HipByte. Он анонсировал свой первый продукт сегодня [3 Мая — прим. перев.] — инструмент разработки под названием RubyMotion, который откроет возможности для написания нативных iOS приложений на языке программирования Ruby.

Я тестировал RubyMotion с Марта, когда Сансонетти дал мне доступ к ранней закрытой бете продукта. В этой статье я представлю эксклюзивный обзор RubyMotion из первых рук и опишу, как он может быть использован для написания ПО для iOS. Статья включает весь исходный код простой iOS демки, которую я создал, отображающей список топовых постов на reddit.

RubyMotion

RubyMotion создан поверх той самой реализации Objective-C Ruby, которая стоит за MacRuby, но использует новый LLVM компилятор для конвертации Ruby кода в оптимизированный машинный код. Компилятор RubyMotion дает на выходе эффективные нативные приложения, которые не имеют ограничений по быстродействию, присущих обычному Ruby коду.



Мобильные приложения, созданные при помощи RubyMotion, работают так же быстро, как и эквиваленты на Objective-C и используют соизмеримое количество аппаратных ресурсов. Более того, приложения RubyMotion полностью удовлетворяют требованиям App Store от Apple. Со слов Сансонетти, несколько RubyMotion приложений уже были приняты в App Store, пройдя все этапы валидации.

В RubyMotion доступны все стандартные API iOS, что означает — все возможности разработчиков Objective-C доступны и разработчикам Ruby. Помимо этого, приложения RubyMotion могут соответствовать внешнему виду остальной платформы, т.к. используют стандартный набор виджетов из UIKit.

Разработка ПО при помощи RubyMotion

Вместо того, что-бы попытаться встроить RubyMotion в IDE от Apple, Сансонетти решил пойти более традиционным для Ruby путем — использовать инструменты командной строки. Консольная команда motion генерирует новый проект по шаблону, который содержит болванку приложения с папками для кода, графики и других ресурсов. Любой файл .rb, который находится в директории app будет автоматически скомпилирован в конечную сборку. В RubyMotion вообще нет нужды использовать ключевое слово require.

Процесс сборки в RubyMotion опирается на инструмент Rake, знакомый большинству Ruby программистов. Опции сборки Rake используются для указания зависимостей и прочих настроек приложения. При запуске rake из командной строки, приложение будет скомпилировано и запущено на симуляторе iOS.

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



Также вы можете использовать цели в Rake для запуска приложения на устройстве или создания пакета .ipa с последующей дистрибуцией в App Store. Из-за ограничений по цифровой подписи кода вам нужно иметь подписку на Apple Developer Program, чтобы тестировать свое приложения на устройствах.

Компиляция и запуск на симуляторе моей RubyMotion reddit-демки заняло около пяти секунд на MacBook Air 2011. Время компиляции не слишком большое, но выглядит это необычно для Ruby разработчиков, которые привыкли видеть результат сразу после внесения изменений. В прибавку к компилятору RubyMotion поставляется со своей собственной командой ruby, позволяющей запускать скрипты Ruby в окружении RubyMotion.

Процесс разработки на RubyMotion вполне комфортный. Я пишу код в Vim и держу открытым терминал, запуская Rake для проверки работы программы. Один ключевой недостаток по сравнению с Xcode — невозможность использования инструментов визуального проектирования интерфейсов. Это может доставить проблемы начинающим разработчикам, потому что им придется углубляться в API UIKit.

Поговорим с Сансонетти

Я спросил его про несовместимость с визуальными инструментами Xcode, он ответил что интеграция с Xcode будет осуществлена, но не в ближайшем будущем.

Вместо этого он создает набор Ruby библиотек для программного создания интерфейсов iOS. Эти библиотеки будут высокоуровневыми обертками над API UIKit, которые значительно легче использовать. Этот подход такой же как и у библиотеки HotCocoa для MacRuby, но с более высоким уровнем абстракции.

«Мы фокусируемся над созданием набора высокоуровневых Ruby гемов для RubyMotion. Один из них — легковесная обертка над UIKit», сказал мне Сансонетти. «Мы решили реализовать систему разметки интерфейса с использованием предметно-ориентированного языка, немного похожего на CSS, так что Ruby разработчики будут чувствовать себя как дома. Наша идея схожа с автоматической разметкой Cocoa [Cocoa auto layout — прим. перев.], которая построена на ASCII-подобном языке, но мы можем сделать это на Ruby еще лучше. Мы считаем что это более верный путь создания UI, нежели Interface Builder, т.к. вы можете все это визуально представить в коде.»

Вместо того, чтобы встраивать эти библиотеки в RubyMotion, Сансонетти собирается выложить их на GitHub под пермиссивной лицензией. Он считает, что приверженцы RubyMotion будут создавать свои варианты библиотек разметки с разными стилями. А у разработчиков приложений будет большой выбор — использовать родные обертки или сторонние.

Я спросил Сансонетти о его взаимодействии с проектом MacRuby, который он основал как open source проект от Apple, и как теперь проект будет развиваться после того как он сфокусировался над разработкой RubyMotion. Он объяснил, что стремление дальше работать над MacRuby было основной причиной его ухода из Apple и создания своей компании.

«Как главный разработчик команды Core OS в Apple, я создал и развивал MacRuby, но MacRuby был только одной частью всех моих обязанностей», сказал он. «После того как MacRuby стал достаточно стабильным, я осознал, что мне придется оставить его разработку. Я не хотел бросать проект и его изумительное сообщество, поэтому я, подумав над этим некоторое время, понял, что создание стартапа RubyMotion будет лучшим, что я мог сделать — я буду продолжать работать над MacRuby и зарабатывать на жизнь одновременно.»

Хотя он и был вынужден временно перестать принимать участие в разработке MacRuby в течение шестимесячного переходного периода после ухода из Apple, теперь он вернулся обратно и не собирается останавливать работу. На данный момент он единственный сотрудник его новой компании, но в планах собрать команду, наняв «несколько участников из сообщества MacRuby ближе к концу года».

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

«Самое сложное было — это реализация совершенно нового статического компилятора и модели памяти для RubyMotion», сказал он. «Также сложна была реализация ARM ABI и низкоуровневых протоколов. Это отняло значительное время для доводки скорости выполнения на устройствах».

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

«Одна из наиболее важных фитч — интерактивная среда, что рубисты принимают как должное, которая отсутствует на многих других платформах. Иметь возможность наблюдать за изменениями в реальном времени очень полезно при отладке и тестировании приложения», сказал он. «Ruby краткий и выразительный язык. Приложение iOS, написанное на Ruby будет содержать значительно меньше строк кода, чем аналогичное приложение на Objective-C. Меньше кода означает более короткий цикл разработки, меньше багов, легче в сопровождении, а значит больше времени на игру в Skyrim».

Наводим мосты

Перед тем как мы создадим рабочее приложение, давайте немного взглянем на то, как RubyMotion наводит мосты между Ruby и средой исполнения Objective-C.

Objective-C это расширение C, которое добавляет такие возможности, как опциональное динамическое типизирование и объектно-ориентированное программирование. NeXT лицензировали этот язык программирования у Stepstone, который был у истоков языка, и использовали его для создания фреймворков под NeXTstep OS, которая позже стала Mac OS X. С тех пор Apple продолжает дорабатывать и улучшать Objective-C.

Objective-C имеет несколько общих свойств с Ruby, которые облегчают взаимодейтсвие между языками. Ruby и Objective-C имеют похожий механизм вызова методов, взятый из Smalltalk — отправка сообщений. Их объектные модели похожи в том, что соблюдают одиночное наследование и имеют большие возможности интроспекции. С недавних пор Objective-C получил новый синтаксический механизм для создания легких анонимных функций схожих с блоками Ruby.

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

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

Главный вывод для пользователей RubyMotion в том, что API Objective-C представлены в немного непривычном формате при их использовании на Ruby. Для иллюстрации проблемы, я собираюсь показать вам пример из UIKit, который будет использоваться в демонстрационном reddit приложении далее в статье. В этом приложении мне нужно было снять выделение со строки в таблице. В Objective-C это выглядит так:

[tableView deselectRowAtIndexPath:indexPath animated:YES]


Фактическое название метода такое deselectRowAtIndexPath:animated. Значения параметров, которые имеют тип NSIndexPath* и BOOL встроены в имя функции на месте их следования при вызове. Ruby не имеет такого синтаксиса. Вы по прежнему следуете соглашению об именованных параметрах, но в более традиционном стиле со скобками:

tableView.deselectRowAtIndexPath(indexPath, animated:true)


MacRuby и RubyMotion имеют гибридную систему, которая позволяет им быть на одном уровне с Objective-C. В этой гибридной системе все стандартные типы Ruby реализованы поверх стандартных типов Objective-C. К примеру, все Ruby объекты наследуют у NSObject, а любая строка в Ruby — это NSMutableString. Вы можете получить представление о том, что это значит, вызвав команду String.ancestors в консоли приложения MacRuby:

=> [String, NSMutableString, NSString, Comparable, NSObject, Kernel]


Такой вид эквивалентности типов очень эффективен в рамках среды исполнения. Нет нужды производить тяжелые вычисления по конвертированию комплексных типов данных между Ruby и API Objective-C.

Другим преимуществом является то, что все часто используемые и полезные методы, которые идут с этими базовыми классами, стали повсеместно доступными. Это дает большое преимущество при работе с контейнерами, например, при использовании chained методов NSMutableArray map, group_by и sort_by с блоками.

Демонстрационное приложение

За последний месяц я создал несколько приложений на RubyMotion, а также использовал его, чтобы портировать простые MacRuby приложения на iOS. В этой статье я хочу показать вам простое демо приложение, которое я написал, пока разбирался с некоторыми API UIKit.

Это приложение — простой клиент для сайта Reddit. Оно скачивает список текущих топовых постов через Reddit JSON API, затем парсит данные и отображает их в табличном виде на экране. Когда пользователь тапает по элементу в списке, соответствующая ссылка открывается в мобильном Safari.

class RedditPost
  attr_accessor :title, :url, :author
  attr_accessor :comments, :score
  attr_accessor :subreddit

  def initialize(data)
    @url = data["url"]
    @title = data["title"]
    @author = data["author"]
    @comments = data["num_comments"]
    @link = data["permalink"]
    @score = data["score"]
    @subreddit = data["subreddit"]
  end
end

class RedditController < UITableViewController
  def viewDidLoad
    @posts = []
    view.dataSource = view.delegate = self
    refresh "top.json"
  end

  def tableView(tv, numberOfRowsInSection:section)
    @posts.size
  end

  def tableView(tv, cellForRowAtIndexPath:indexPath)
    cid = "PostCell"
    cell = tv.dequeueReusableCellWithIdentifier(cid) ||
           UITableViewCell.alloc.initWithStyle(
                UITableViewCellStyleSubtitle,
                reuseIdentifier:cid)

    p = @posts[indexPath.row]

    cell.textLabel.text = p.title
    cell.detailTextLabel.text = "Posted by #{p.author} in #{p.subreddit}"
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator

    cell
  end

  def tableView(tv, didSelectRowAtIndexPath:indexPath)
    url = NSURL.URLWithString @posts[indexPath.row].url
    UIApplication.sharedApplication.openURL url
    tv.deselectRowAtIndexPath(indexPath, animated:true)
  end

  def get(address)
    err = Pointer.new_with_type "@"
    url = NSURL.URLWithString address

    raise "Loading Error: #{err[0].description}" unless
      data = NSData.alloc.initWithContentsOfURL(
        url, options:0, error:err)

    raise "Parsing Error: #{err[0].description}" unless
      json = NSJSONSerialization.JSONObjectWithData(
        data, options:0, error:err)

    json
  end

  def refresh(endpoint)
    Dispatch::Queue.concurrent.async do
      begin
        response = get "http://reddit.com/#{endpoint}"
        data = response["data"]["children"].map {|i| RedditPost.new i["data"] }
        Dispatch::Queue.main.sync { @posts = data; view.reloadData }
      rescue Exception => msg
        puts "Loading Failed: #{msg}"
      end
    end
  end
end

class AppDelegate
  def application(app, didFinishLaunchingWithOptions:launchOptions)
    @win = UIWindow.alloc.initWithFrame(
            UIScreen.mainScreen.applicationFrame)

    @win.rootViewController = RedditController.alloc.initWithStyle(
                                  UITableViewStylePlain)

    @win.rootViewController.wantsFullScreenLayout = true
    @win.makeKeyAndVisible
    return true
  end
end


Все приложение разработано как один .rb файл с менее чем 100 строками кода. Метод application в классе AppDelegate вызывается при запуске приложения. Мы используем этот метод, чтобы создать и вывести на экран экземпляр вида, которой хотим показать пользователю при старте.

Почти вся логика приложения реализована в классе RedditController, являющимся подклассом UITableViewController. Метод viewDidLoad, который вызывается при загрузке класса в пользовательский интерфейс, устанавливает переменные экземпляра, содержащие посты, а потом вызывает метод refresh, который загружает данные.

Метод refresh вызывает get, который использует класс NSData для скачивания данных в формате JSON и использует NSJSONSerialization, чтобы преобразовать их в легко используемую структуру данных. Вы могли заметить, что метод refresh использует Grand Central Dispatch (GCD), чтобы загрузить и преобразовать данные в фоновом потоке.

Несколько методов tableView в классе RedditController обрабатывают различные аспекты поведения вида. Метод tableView:cellForRowAtIndexPath используется для создания объектов строк и заполнения их данными. Метод tableView:didSelectRowAtIndexPath вызывается, когда пользователь тапает по элементу в таблице. Код в этом методе определяет какой объект был выбран и открывает URL этого объекта в браузере, а потом убирает выделение с объекта.

Заключение

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

После некоторого времени, проведенного за разработкой приложений с помощью RubyMotion, единственным недостатком мне показалась нехватка интеграции с Xcode для создания пользовательского интерфейса. Для разработчиков без опыта работы с UIKit, написание кода вручную может оказаться долгим и сложным.

Хотя этот недочет не отрицает продуктивность работы с Ruby, новым разработчикам придется пройти начальный этап обучения, прежде чем они смогут в полном объеме получить пользу от RubyMotion. К счастью, библиотеки высокого уровня, которые уже скоро выйдут, должны исправить эту ситуацию.

Лицензия RubyMotion, включающая в себя годовую поддержку обновлений, стоит $199.99. Сейчас ее можно приобрести со скидкой за $149.99. Более подробную информацию можно найти на официальном сайте продукта. Там же вы можете посмотреть вступительный скринкаст от Pragmatic studio.

Данная статья является переводом. Оригинал доступен по ссылке.
Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 27
  • –1
    Новость прекрасная. Однако:
    Лицензия RubyMotion, включающая в себя годовую поддержку обновлений, стоит $199.99. Сейчас ее можно приобрести со скидкой за $149.99.

    Т.е. community-версии не ожидать? MacRuby-то был бесплатным.
    • 0
      У меня у самого к ним масса вопросов. Отправил заявку на вступление в гугл группу проекта. Хотелось бы пощупать, хотя-бы, какой-нибудь триал.
      • +2
        А вы как хотели? Mono вон тоже бесплатное, а MonoTouch денег стоит.
      • 0
        Выглядит как очень крутая штука. Давно хотел иметь возможность на ruby под ios писать.
        • +4
          «Есть» еще mobiRuby. Но он только в проекте и основываться будет на mRuby.

          Как человек который пробовал писать на macruby скажу честно — это не нужно. Cocoa все равно учить надо, на ruby синтаксис это не ложится как хотелось бы. В результате код получается менее читальным и не понятным. А так ак Obj-c весьма простой (а с ARC еще проще) и Cocoa учить все равно надо — в чем смысл?
          • +7
            Выглядит как очень крутая штука.

            На мой взгляд как раз наоборот. И вот почему.

            — Если посмотреть на примеры или предлагаемое видео, при этом иметь бэкграунд разработки под ios, то очень хорошо видно, что используя этот продукт вы просто пишите на Objective-C с помощью синтаксиса Ruby. То есть данный продукт даже нельзя сравнивать с Appcelerator Titanium. И тут возникает вопрос, если тут почти уже Objective-C, почему бы не писать на нём используя довольно продуманный XCode при этом оставив себе эти деньги на сертификат разработчика?

            — Компания предоставившая продукт не занимается созданием приложений, а как многие знают 99% проблем вылезают на реальных проектах, а не на тестовых примерах.

            — Все примеры приложений сделаны на уровне Hello world с первых 50 страниц книжки про программирование под iOS. К тому же нет триальной или демо версии. То есть не заплатив текущие $149.99 вы не знаете можете ли реализовать свою задумку с помощью данного продукта или нет.

            — «Interactive development» который позволяет ковырять исполняемые приложения хорош в том примере, что есть на сайте. Отдебажить таким образом что-то более-менее серьезное вы вряд ли сможете или захотите.

            — Заявление про то, что вы можете использовать именно тот редактор, какой захотите. Если вы хоть раз писали приложения не уровня Hello world, вас так же как и меня поставит в тупик такое заявление. Вот я лично серьезно не понимаю, как можно написать, что-то используя emacs или vim. Возможно они придумали, что-то супер-мега крутое, что изменит мое мнение, но на данный момент я считаю, что это возможно только при написании их примеров.
            • 0
              пардон, ответил не там habrahabr.ru/post/143332/#comment_4803502
              • 0
                Рассмотрел примеры на сайте, воодушевился и купил эту хрень. Теперь, после возникновения первых непонятных проблем, я с ужасом заметил что не могу найти ни одного достойного способа отследить что происходит с моим приложением. И вроде сделал все как в примерах (с небольшими изменениями: кнопку лишнюю добавил или еще какой контрол), но не работает как задумывалось. И появилось куча вопросов. Как это дело отлаживать? Как дебажить? Где вообще хоть какая-нибудь подробная информация как это работает? Никакой документации! Надеялся что она будет в комплекте с лицензией. Хренушки
                • 0
                  Да, забыл сказать, что интерактивная консоль не очень то удобная вещь, если пишешь что-то отличное от примеров. Нельзя просто тыкнуть в контрол и получить его в консоли. В итоге получаешь не те объекты, а докапаться до нужных новичку в разработке для iOS (а именно для них как я понял это и писалось) очень тяжко. Нет ни помощи в консоле, ни встроенной документации, как в pry например, ни автокомплита. Вроде бы для рубистов сделано, но никакого удобства не предоставленно. Разачарован.
                  • 0
                    Удалось применить как-нибудь?
              • 0
                Сейчас еще MobiRuby на базе mruby начали делать. Там и Android и iOS будут поддерживаться.
              • +2
                Вот я лично серьезно не понимаю, как можно написать, что-то используя emacs или vim.

                Это шутка? emacs и vim мощнейшие редакторы. Другой вопрос чтобы научится ими пользоваться нужно потрудиться.

                А по поводу сравнения с Obj-C согласен, пока это так. Но, во первых синтаксис ruby приятнее. И во вторых теперь есть возможность делать библиотеки аля ios on rails. Вот тогда это на полную мощность будет работать.
                • +2
                  emacs и vim мощнейшие редакторы

                  Вот именно. Редакторы. А XCode это IDE. И для разработки приложений средней и большой сложности нужна именно IDE. Я писал следуя из своего опыта написания iOS приложений, и опыта работы с vim и xcode. Если вы мне на конкретных примерах объясните как можно заменить все те действия с UI которые есть в XCode на какие-то действия в vim, и это не будет адовой дрочкой, я возьму свои слова обратно.

                  Но, во первых синтаксис ruby приятнее.

                  Вы готовы отдать $149 за любимый синтаксис? Лично я — нет. Во-вторых это надстройка над инфраструктурой iOS разработки и судя по всему трансляция вашего кода в obj-c и его конечная компиляция. Забудь они где-то символ в преобразовании кода, вы с ума сойдете пытаясь найти ошибку.

                  И во вторых теперь есть возможность делать библиотеки аля ios on rails.

                  Что значит аля ios on rails? Я работаю с Rails и слабо понимаю, при чем тут он.

                  Я говорил по своему опыту, я пишу и на obj-c и на ruby. И я не вижу ни одной объективной причины использовать данный продукт. Разве, что используя любимый синтаксис делать всё, что угодно, и сайты писать, и программы и ядра осей и так далее… но это не объективная причина.
                  • 0
                    vim для руби как IDE полноценный может использоваться, есть пакет плагинов, забыл, в общем все очень круто становится :)
                    • 0
                      Я говорил не про разработку на руби, а про создание приложений под ios.
                    • 0
                      … и судя по всему трансляция вашего кода в obj-c и его конечная компиляция.


                      Насколько я понял, там нет трансляции в obj-c, а написан полноценный статический компилятор для Руби. Чел пол года, пока ему нельзя было напрямую заниматься MacRuby создавал компилятор.
                      • 0
                        написан полноценный статический компилятор для Руби

                        Откуда такая информация? На сайте проекта написано, только про ихний рантайм и то как-то размыто. К тому же для работы требуется iOS SDK, явно не просто так.
                        • +1
                          В кратце: obj-c на iOS компилируется под llvm, macruby тоже под него компилируется в результате у них один рантаим и gc (на iOS нет GC, но это детали). Macruby не было на iOS потому, что там нет GC, а без него на нем не попишешь. Это не мост между языками, это единый рантаим.

                          А mobiRuby это я бы не стал называть это проектом. Когда состоялся публичный рулиз mRuby, как-то парень решил, что он сможет портануть это на iOS, тут же на бутсрапе зафигачил сайт, отписался на Hacker News, что он портанет mRuby на iOS и его выбили в топ.

                          Такие дела.
                          • +1
                            «It's not the case. RubyMotion compiles Ruby straight [1] to machine code and does not use Objective-C in the middle.

                            [1] Well, it's a bit more complicated, and looks like this: Ruby Source Code -> Ruby AST -> LLVM Bitcode -> Assembly -> Machine code.»


                            Цитата Лорана на этот вопрос. Наконец-то я получил доступ к их гугл группе и как раз наткнулся на обсуждение.
                        • 0
                          Fully compiled
                          RubyMotion transforms the Ruby source code of your project into optimized, blazing-fast machine code using a revolutionary, state-of-the-art static compiler, based on LLVM.
                        • +1
                          Синтаксис руби полностью теряет свою привлекательность когда его смешивают с Cocoa. Ну не пишут так на руби.
                          • 0
                            Тоже задумывался об этом. Но так ли много Cocoa будет в нормального размера iOS приложении?
                        • –1
                          Не стоит оно того…
                          • 0
                            Очень замечательно. Вот еще, например, о том как писать iOS-приложения на Pascal — web.me.com/macpgmr/ObjP/Xcode4/ObjP_Intro.html
                            • 0
                              Если честно — удивляюсь таким людям, и завидую. По доброму завидую. В одиночку проделать такую работу мне кажется практически не возможно. Тем более с учетом just for fun (если не считать эти $149.99).
                              • 0
                                Передовики практического применения ruby, несмотря на все предрассудки, рассматривают RubyMotion всерьез. thoughtbot рассказали в рассылке, что в ближайшее время в AppStore появится их первый продукт на RubyMotion www.stattleship.io/fanboat.html

                                В Rubymine внедрили поддержку RubyMotion.

                                Индустрия не боится, индустрия пробует.
                                • 0
                                  C публикацией на AppStore проблем возникнет?

                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.