Создание гемов — Руководство

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

    Как же на самом деле надо создавать, развивать и публиковать свои гемы?

    Современный подход заключается в использовании Bundler совместно с другими инструментами, такими, как Git, YARD и RSpec-2.

    Создание базовой структуры


    Итак, чтобы создать новый гем, достаточно выполнить команду
    bundle gem YOUR-GEM-NAME
    

    Естественно, у Вас до выполнения этой команды уже должен быть установлен гем bundler (gem install bundler).

    После этого вы получите базовую структуру Вашего нового гема в каталоге YOUR-GEM-NAME с уже готовыми командами для построения гема, его инсталляции и публикации в rubygems:
    cd YOUR-GEM-NAME
    rake -T
    rake build    # Build YOUR-GEM-NAME-0.0.1.gem into the pkg directory
    rake install  # Build and install YOUR-GEM-NAME-0.0.1.gem into system gems
    rake release  # Create tag v0.0.1 and build and push YOUR-GEM-NAME-0.0.1.gem to Ru...
    


    Важно отметить, что исходный библиотечный код не должен замусоривать глобальное пространство имен. Пожалуйста, располагайте все ваши классы внутри класса или модуля с именем, предложенным Bundler, в подкаталоге lib/YOUR-GEM-NAME, подключая их из файла lib/YOUR-GEM-NAME.rb. Старайтесь не использовать autoload, так как эта возможность объявлена устаревшей для Ruby 2.0.

    По возможности все файлы документации должны использовать разметку Markdown (желательно наличие файла README.md).

    Документирование кода


    Современным инструментом документирования кода является YARD в режиме markdown с использованием модуля redcarpet для поддержки подсветки кода с использованием синтаксиса GitHub. При этом Вы автоматически получаете публикацию документации на rubydoc.info (пример).

    Подключить его достаточно просто:
    • Добавляем зависимость времени разработки в gemspec:
        s.add_development_dependency "redcarpet", "~> 1.17"
        s.add_development_dependency "yard", "~> 0.7.5"
      

      Если используем ruby версии 1.8, то желательно также использовать также гем ripper, который добавит полезный функционал для YARD. Подключить его лучше через Gemfile:
      gem "ripper", :platforms => :ruby_18, :group => :development
      

    • Выполняем установку гемов
      bundle install
      

    • Настраиваем YARD, создав файл .yardopts с таким содержимым:
      --markup markdown
      --markup-provider redcarpet
      --charset utf-8
      --readme README.md
      -
      README.md
      LICENSE
      

      Здесь после однострочного дефиса мы указываем список файлов, которые надо дополнительно включить в документацию (обычно readme и лицензию).
    • И добавляем задачу rake yard для генерации документации в Rakefile:
      require 'yard'
      YARD::Rake::YardocTask.new
      


    Теперь по команде rake yard мы получим полную документацию по библиотеке в каталоге doc.

    Кстати, не забудьте добавить doc/, .yardoc/ и Gemfile.lock в .gitignore.

    Начинаем писать спеки


    Лично я предпочитаю использовать для спеков RSpec 2 совместно с RR. Добавим соответствующие зависимости в gemspec:
       s.add_development_dependency "rspec-core", "~> 2.0"
       s.add_development_dependency "rspec-expectations", "~> 2.0"
       s.add_development_dependency "rr", "~> 1.0"
    


    Выполняем установку гемов и создание базовых файлов RSpec 2
    bundle install
    bundle exec rspec --init
    


    Добавляем задачу rake spec в Rakefile:
    require 'rspec/core/rake_task'
    RSpec::Core::RakeTask.new
    

    И просим использовать по умолчанию RR в spec/spec_helper.rb:
      config.mock_with :rr
    

    Все, теперь можно писать спеки и код.

    Немного об исполняемых файлах


    Файлы, которые Вы кладете в каталог bin вашего гема, при инсталляции гема инсталлируются как исполняемые файлы целевой операционной системы.

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

    В связи с этим, наилучшей практикой при создании исполняемого файла является перенос всей логики в библиотеку, с тем, чтобы бинарный файл your-gem-exec выглядел где-то так:

    require 'rubygems' # не нужно для ruby 1.9 и выше
    require 'your-gem'
    require 'your-gem/exec'
    

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

    Контроль версий


    Общее правило заключается в использовании Git в качестве репозитория и семантического версионирования при формировании номеров версий гемов. rake release будет автоматически создавать необходимые тэги в репозитории и публиковать гем в rubygems.

    Удаление ошибочных версий гемов


    Иногда возникает задача удалить какую-либо версию гема с rubygems в связи с проблемами конкретной версии (ошибки в коде или неправильное версионирование). Эта задача выполняется с помощью команды

    gem yank gemname -v version
    

    Эта команда по умолчанию не поставляется вместе с rubygems, поэтому для ее использования надо установить гем jeweler.

    gem install jeweler
    
    Поделиться публикацией
    Похожие публикации
    Ой, у вас баннер убежал!

    Ну. И что?
    Реклама
    Комментарии 12
    • 0
      А версионирование от jeweler чем хуже?
      • 0
        Это разные вещи. Bundler — современный способ использования, создания и разработки гемов. jeweler — несколько устаревший способ упаковки гемов и набор расширений rubygems.
        • 0
          Одно другого не отменяет. Bundler не поддерживает rake version bump, и не собирается.
          • +1
            Jeweler не умеет бампать версии гемов, которые содержат версию в исходном коде.

            Кстати, неплохая идея для нового гема.
        • +3
          Добавлю 2 момента:

          1) в Rakefile можно добавить следующую конструкцию:

          task :default => :spec

          тогда можно будет писать не rake spec, а просто rake.

          2) rake release перед отправкой гема в rubygems пытается сделать git push, и если в репозитории еще не задан origin, он ничего не скажет и крепко задумается. Пару раз на этом попадался.
          • 0
            А как можно добавить скомпилированную версию гема (не своего) на rubygems? Подойдет ли данный метод или связываться с разработчиками?
            • 0
              НУжно быть авторизованным разработчиком гема н аrubygems. Для добавления в список нужно связаться с авторами гема. Либо создаете гем с другим именем.
            • 0
              >Старайтесь не использовать autoload, так как эта возможность объявлена устаревшей для Ruby 2.0.
              А что там на смену пришло, не подскажите?
              • 0
                Пока неясно. Процитирую ruby-core:

                Hi,

                Today, I talked with NaHi about enhancing const_missing to enable
                autoload-like feature with nested modules. But autoload itself has
                fundamental flaw under multi-thread environment. I should have remove
                autoload when I added threads to the language (threads came a few
                months after autoload).

                So I hereby declare the future deprecation of autoload. Ruby will
                keep autoload for a while, since 2.0 should keep compatibility to 1.9.
                But you don't expect it will survive further future, e.g. 3.0.

                I strongly discourage the use of autoload in any standard libraries.

                matz.
            • 0
              Еще неплохо в spec_helper.rb написать:

              require "bundler"
              Bundler.require :default, :development


              Во избежание внезапных спецэффектов.

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

              Самое читаемое