Этот пост был вдохновлен этим блестящим видео , где Константин Хаазе , сопровождающий Sinatra, создает полностью работающее приложение и развертывает его на Heroku с тестами на Travis (там, где он работает).
Я решил сделать аналогичный пример, который проходит через каждый этап создания службы API, которая демонстрирует типичный рабочий цикл цикла разработки Sinatra — напишите свои тесты, напишите свой код, отправьте код в GitHub и проверьте, работает ли он при развертывании в Heroku с непрерывным интеграция на Трэвис.
Пост будет идти от начала до конца и будет охватывать следующее:
- Написание тестов с использованием MiniTest
- Создание Sinatra API, который возвращает информацию в формате JSON
- Использование Bundler для управления зависимостями
- Использование Git для управления контролем версий
- Хостинг код на GitHub
- Развертывание и размещение сайта на Heroku
- Выполнение непрерывной интеграции с Travis CI
Определите проблему
Приложение, которое я хочу построить, называется Number Cruncher. Он будет возвращать информацию о числах, таких как факторы, будь то нечетное или четное, и если это простое число.
Первое, что я хочу сделать, — это Integer
класс Integer
чтобы добавить метод, который возвращает множители числа в виде массива. Я тоже хочу добавить prime?
метод для проверки, является ли число простым. После этого я буду использовать Sinatra для предоставления API, который будет возвращать информацию о числе в формате JSON.
- Number Cruncher работает в прямом эфире на Heroku
- Вы можете увидеть тесты непрерывной интеграции, работающие на Travis
- Код есть на GitHub
тестирование
Прежде чем писать какой-либо код, мы должны написать несколько тестов, которые охватывают описание выше. Прежде всего, создайте файл с именем «number_cruncher.rb» и другой файл с именем «test.rb». Затем добавьте следующий код установки MiniTest в ‘test.rb’:
ENV['RACK_ENV'] = 'test' require 'minitest/autorun' require 'rack/test' require_relative 'number_cruncher.rb' include Rack::Test::Methods def app Sinatra::Application end
Теперь мы напишем спецификацию для проверки некоторых функций, описанных выше. Добавьте следующий код в конец test.rb:
describe "Number Cruncher" do it "should return the factors of 6" do 6.factors.must_equal [1,2,3,6] end it "should say that 2 is prime" do assert 2.prime? end it "should say that 10 is not prime" do refute 10.prime? end it "should return json" do get '/6' last_response.headers['Content-Type'].must_equal 'application/json;charset=utf-8' end it "should return the correct info about 6 as json" do get '/6' six_info = { number: 6, factors: 6.factors, odd: 6.odd?, even: 6.even?, prime: 6.prime? } six_info.to_json.must_equal last_response.body end end
Первый тест для метода factors
который я планирую добавить в класс Integer
. Мы проверяем, что если целое число 6
вызывает метод factors
за которым следует, если факторы 6 возвращаются в виде массива.
Далее проверить prime?
метод, который также будет добавлен в класс Integer
. Прежде всего, проверьте, возвращает ли 2 значение true
а затем, если 10 возвращает значение false
.
Последние два теста относятся к API. Четвертый тест проверяет, возвращает ли приложение JSON. Это делается путем выполнения запроса get
с ‘6’ в качестве параметра. last_response.headers
проверяются на предмет типа «application / json; charset = utf-8». В последнем тесте мы проверяем, верна ли правильная информация, сравнивая строку JSON с методом last_response.body
.
Чтобы запустить наши тесты, введите в окне терминала следующее:
$ ruby test.rb
Это дает следующий вывод:
# Running: EEEEE Finished in 0.008729s, 572.8333 runs/s, 0.0000 assertions/s. 5 runs, 0 assertions, 0 failures, 5 errors, 0 skips
Все пять наших тестов приводят к ошибкам, что ожидается, так как мы еще не написали код. Посмотрим, сможем ли мы сдать эти тесты.
Код числовой дробилки
Начните с добавления factors
и prime?
методы к классу Integer. Добавьте следующий код в number_cruncher.rb:
class Integer def factors square_root = self**0.5 (1..square_root).map{ |n| [n,self/n] if self/n*n == self }.compact.flatten.sort end def prime? self.factors.size == 2 ? true : false end end
Попробуйте снова запустить тесты.
$ ruby test.rb
Это дает следующий вывод:
5 runs, 3 assertions, 0 failures, 2 errors, 0 skips
Это лучше — наши первые три теста пройдены, но последние два все еще не пройдены, потому что мы еще не реализовали API. Мы будем использовать Синатру, чтобы сделать это. Это подразумевает использование sinatra
и json
, поэтому добавьте следующее в number_cruncher.rb:
require 'sinatra' require 'json'
Нам также понадобится маршрут, который люди могут использовать для доступа к API. Это простой GET
который принимает число в качестве параметра. Будет возвращена информация о номере:
get '/:number' do content_type :json number = params[:number].to_i { number: number, factors: number.factors, odd: number.odd?, even: number.even?, prime: number.prime? }.to_json end
Сначала измените тип контента на JSON, используя удобный вспомогательный метод content_type
который предоставляет Sinatra. Затем возьмите число из хэша params
и преобразуйте его в целое число (все, что введено в маршрут, является строкой). Затем создайте хэш информации о числе, включая его факторы. Хеш включает в себя, является ли число нечетным или четным и является ли оно простым с использованием наших новых методов Integer
. Хеш преобразуется в JSON с использованием метода to_json
предоставленного to_json
json
. Поскольку это последняя строка обработчика маршрута, он будет возвращен автоматически.
Давайте снова запустим тесты:
$ ruby test.rb
На этот раз мы получаем следующий вывод:
5 runs, 5 assertions, 0 failures, 0 errors, 0 skips
Это здорово, наш код работает! Мы можем проверить его, проверив некоторые факты о пятом числе Ферма, используя curl . Сначала запустите сервер:
$ ruby number_cruncher.rb
Теперь откройте другое окно терминала и введите:
$ curl http://localhost:4567/4294967297
Это дает нам следующую информацию, подтверждающую то, что Эйлер обнаружил в 1732 году:
{"number":4294967297,"factors":[1,641,6700417,4294967297],"odd":true,"even":false,"prime":false}
Контроль версий с помощью Git
Всегда полезно держать ваш код под контролем версий. Git практически вездесущ в сообществе Ruby и не без причины (это круто!). Сначала убедитесь, что Git установлен в вашей системе, а затем выполните следующие команды:
$git init
Это должно дать вам сообщение, подобное приведенному ниже:
Initialized empty Git repository in /path/to/number cruncher/.git/
Используйте add .
Команда для добавления всех файлов в каталоге :.
git add . git commit -m 'initial commit'
Вы получите сообщение, подобное приведенному ниже, с подробным описанием файлов, которые были изменены:
[master (root-commit) 6674d0c] initial commit 2 files changed, 56 insertions(+) create mode 100644 number_cruncher.rb create mode 100644 test.rb
Поскольку мы используем Git для контроля версий, имеет смысл разместить наш код на GitHub. Если вы еще не создали учетную запись, зайдите туда и создайте ее . Существует полезный гем под названием ‘hub’ для взаимодействия с GitHub через терминал. Чтобы установить его, просто введите в терминал следующее:
$ gem install hub
Теперь вы сможете создать новый репозиторий для своего кода, используя следующую команду:
$ hub create number_cruncher
Это должно дать вам следующий вывод:
Updating origin created repository: daz4126/number_cruncher
Вставьте код в наш новый репозиторий GitHub, что делается так:
$ git push origin master
Если все пойдет по плану, вы увидите нечто похожее на следующий результат:
Counting objects: 4, done. Delta compression using up to 4 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 914 bytes, done. Total 4 (delta 0), reused 0 (delta 0) To [email protected]:daz4126/number_cruncher.git * [new branch] master -> master
Bundler
Далее мы используем Bundler для управления нашими зависимостями. Это включает в себя создание файла с именем «Gemfile», который содержит следующий код:
source 'https://rubygems.org' gem "sinatra" gem "json" gem "rack-test", :group => :test
Чтобы использовать Bundler, используйте следующую команду в терминале:
$ bundle install
Вы должны увидеть следующую информацию, поскольку Bundler получает и устанавливает все необходимые гемы:
Fetching gem metadata from https://rubygems.org/........... Fetching gem metadata from https://rubygems.org/.. Resolving dependencies... Using json (1.8.0) Using rack (1.5.2) Using rack-protection (1.5.0) Using rack-test (0.6.2) Using tilt (1.4.1) Using sinatra (1.4.3) Using bundler (1.3.5) Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
Так как мы внесли некоторые изменения в наш код, нам нужно добавить и зафиксировать их в git перед отправкой обновленного кода в GitHub. Это легко достигается с помощью следующих трех команд в терминале:
$ git add . $ git commit -m 'Added Gemfile and bundled gems' $ git push origin master
Развернуть в Heroku
Теперь пришло время развернуть наш код на работающем сервере, используя сервис Heroku . Для этого нам нужно будет создать файл «rackup». Создайте файл с именем config.ru, содержащий следующий код:
require './number_cruncher' run Sinatra::Application
Чтобы проверить, что это работает, запустите команду, которую Heroku будет использовать в терминале:
$ bundle exec rackup
Это приводит к запуску сервера, и вы увидите вывод, подобный показанному ниже:
[2013-08-29 13:27:36] INFO WEBrick 1.3.1 [2013-08-29 13:27:36] INFO ruby 2.0.0 (2013-06-27) [i686-linux] [2013-08-29 13:27:36] INFO WEBrick::HTTPServer#start: pid=4188 port=9292
Еще раз, мы внесли некоторые изменения в код, так что добавьте, зафиксируйте и нажмите танец с Git:
$ git add . $ git commit -m 'Added config.ru' $ git push origin master
Теперь пришло время создать приложение в Heroku. Если вы еще не создали учетную запись, зайдите туда и получите ее . Вы также должны убедиться, что у вас установлен пояс Heroku . Как только это будет сделано, введите следующую команду в терминале:
$ heroku create
Git используется для развертывания кода в Heroku с помощью push
, например:
$ git push heroku master
Если все пойдет хорошо, вы увидите нечто похожее на вывод ниже:
Creating number-cruncher... done, stack is cedar http://number-cruncher.herokuapp.com/ | [email protected]:number-cruncher.git Git remote heroku added
Запишите URL-адрес, созданный для вашего приложения, а затем протестируйте его, посетив его, указав свой любимый номер в качестве параметра:
http://number-cruncher.herokuapp.com/10
Непрерывная интеграция с Travis
Непрерывная интеграция — это практика запуска тестов в одном централизованном хранилище кода. Travis предоставляет эту услугу, выполняя тесты кода в репозитории GitHub каждый раз, когда код отправляется в GitHub. Это означает, что вы всегда можете проверить статус своего кода. Вы даже можете настроить его для развертывания своего кода после успешной сборки!
Для начала установите travis
gem:
$ gem install travis
Вам также необходимо войти в Travis, используя свою учетную запись GitHub.
Travis работает, выполняя задачу rake, поэтому создайте файл с именем ‘Rakefile’, который содержит следующий код:
task(:default) { require_relative 'test' }
Это в основном говорит ему запускать файл ‘test.rb’ при запуске Rakefile. Вы можете проверить, работает ли это, введя в терминал следующее:
$ rake
Вы увидите тот же результат, что и при запуске наших тестов:
Run options: --seed 58513 # Running tests: ..... Finished tests in 0.092591s, 54.0009 tests/s, 54.0009 assertions/s. 5 tests, 5 assertions, 0 failures, 0 errors, 0 skips
Вам также нужно добавить ‘rake’ в наш Gemfile, отредактируйте его так, чтобы он выглядел следующим образом:
source 'https://rubygems.org' ruby '2.0.0' gem "sinatra" gem "json" group :test do gem "rack-test" gem "rake" end
Вам нужно снова запустить bundle install
, так как мы изменили наш Gemfile:
$ bundle install
Теперь мы готовы настроить Travis для нашего проекта. Это можно сделать, введя следующую команду в терминале:
$ travis init ruby --rvm 2.0.0
Это дает следующий вывод:
repository not known to Travis CI (or no access?) triggering sync: ........ done .travis.yml file created! daz4126/number_cruncher: enabled :)
Будет создан файл с именем .travis.yml, содержащий информацию о нашем приложении. Сборка на Travis инициализируется, когда вы нажимаете на свою учетную запись Github, так что сделайте это сейчас:
$ git add . $ git commit -m 'Created a Rakefile and set up Travis' $ git push origin master
Чтобы проверить состояние сборки, выполните следующую команду в терминале:
$ travis show
Трэвису может потребоваться некоторое время, чтобы запустить сборку, поэтому вы можете получить следующее сообщение:
no build yet for daz4126/Sinatra-API
Но наберитесь терпения, приготовьте чашку чая, затем вернитесь и попробуйте снова:
$ travis show
Надеюсь, на этот раз вы получите подтверждение, что сборка прошла успешно:
Job #1.1: Created a Rakefile and set up Travis State: passed Type: push Branch: master Compare URL: https://github.com/daz4126/number_cruncher/compare/4f55d5f9cd32...86c181d96f5d Duration: 30 sec Started: 2013-09-28 18:22:56 Finished: 2013-09-28 18:23:26 Allow Failure: false Config: rvm: 2.0.0
Вы также получите приятное письмо от прекрасных людей из Трэвиса, чтобы подтвердить успешную сборку.
Это все люди!
Мы подошли к концу этого учебного руководства, где мы завершили полный цикл разработки, который можно повторять каждый раз, когда мы хотим добавить новый фрагмент кода: писать тесты, писать код, фиксировать изменения в Git, передавать код в GitHub, тестировать код с использованием Travis, и развернуть в Heroku Промыть и повторить.
Я надеюсь, что вы сочли полезным. Я хотел бы услышать любые отзывы о вашем рабочем процессе в комментариях ниже.