Статьи

Движущиеся картинки с Синатрой, часть I

mp_sinatra

Работа с файлами и каталогами.

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

Picture Viewer

Настройка среды.

Мне нравится RVM, потому что он хранит драгоценные камни в своем полушарии и не вызывает постоянных волн в других проектах. Установите gemset с именем movingPictures , используйте ruby ​​2.0, а затем убедитесь, что мы используем этот gemset. Вы можете сделать все это в одной простой строке.

$ rvm gemset use 2.0.0@movingPictures --create 

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

 $ mkdir movingPictures $ mkdir movingPictures/test $ cd movingPictures $ touch Gemfile $ touch main.rb $ touch test/test.rb 

Откройте Gemfile и добавьте драгоценные камни, которые нам понадобятся.

Gemfile

 source 'http://rubygems.org' gem 'sinatra' gem 'rack-test' 

Установить драгоценные камни

 $ gem install bundler $ bundle install 

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

Тест / test.rb

 require './main' require 'minitest/autorun' require 'rack/test' ENV['RACK_ENV'] = 'test' class MyTest < MiniTest::Unit::TestCase include Rack::Test::Methods def app Sinatra::Application end def test_for_echo get '/' assert last_response.ok? assert_equal "Echo", last_response.body end end 

Мы включаем файл main.rb , который запускает наше приложение, вместе с файлами для тестирования.

main.rb

 require 'sinatra' get '/' do "Echo" end 

Вперед, запустите тест.

 $ ruby test/test.rb 

Круто, все работает.

Очевидно, что приложение должно показывать несколько картинок. Как бы вы написали тест для этого?

Тест / test.rb

 … def test_for_pictures pictures = load_pictures assert pictures.length > 0 end … 

Видишь, что мы здесь сделали? Загрузите изображения и убедитесь, что количество изображений больше нуля.
Давайте попробуем это. Запустить тест

 $ ruby test/test.rb Run options: --seed 30840 # Running tests: .E Finished tests in 0.041759s, 47.8939 tests/s, 47.8939 assertions/s. 1) Error: test_for_pictures(MyTest): NameError: undefined local variable or method `load_pictures' for #<MyTest:0x97e398> test/test.rb:21:in `test_for_pictures' … 2 tests, 2 assertions, 0 failures, 1 errors, 0 skips 

Это хорошо. Что нужно сделать, чтобы избавиться от этой ошибки? Добавьте отсутствующий метод load_pictures в файл main.rb. После этого запустите тест и посмотрите, что вы получите.

main.rb

 require 'sinatra' def load_pictures end get '/' do "Echo" end 

Давайте снова запустим тест.

 $ ruby test/test.rb Run options: --seed 61820 # Running tests: E. Finished tests in 0.041278s, 48.4520 tests/s, 48.4520 assertions/s. 1) Error: test_for_pictures(MyTest): NoMethodError: undefined method `length' for nil:NilClass test/test.rb:22:in `test_for_pictures' … 2 tests, 2 assertions, 0 failures, 1 errors, 0 skips 

Потрясающие. Одна решенная ошибка показывает другую. Не важно, вы показали, что умеете исправлять ошибки. Давайте решим это.
Что-нибудь возвращается из нашего метода load_pictures ? В этом проблема.

Где фотографии? Я думаю, мы не думали об этом. Иногда мы просто не должны прыгать прямо в кодирование или нет? Так как мы используем TDD, если мы начнем что-то передвигать, мы узнаем, что что-то сломалось. Сладкий.

Вам нужно где-то хранить картинки. Как насчет в каталоге от корня приложения. Давайте использовать слайд-шоу pictures_ в качестве имени каталога. Да, это невероятно долго, но очевидно, что входит в этот каталог.

Идите и создайте этот каталог.

Подождите! Может быть, именно здесь нам нужно немного подумать об этом. Мы не хотим спешить ни с чем.

Если мы сделаем этот каталог вне корня, то нам придется выполнить некоторую работу по маршрутизации. Если мы создадим публичный каталог из корневого каталога и создадим в нем каталог images_ слайд-шоу pictures_, это решит некоторые ненужные задачи. Поднятие рук для того, кто в порядке с этим.

 $ mkdir public/ $ mkdir public/slideshow_pictures 

Поскольку мы ищем изображения в каталоге, вам нужно написать код для этого. Если вы не знакомы с классом Dir в Ruby, проверьте его.

Давайте использовать Dir # glob . Тот кажется всемогущим.

main.rb

 … def load_pictures Dir.glob("public/slideshow_pictures/*") end … 

Запустите тесты.

 $ ruby test/test.rb Run options: --seed 25112 # Running tests: F. Finished tests in 0.016690s, 119.8322 tests/s, 179.7484 assertions/s. 1) Failure: test_for_pictures(MyTest) [test/test.rb:22]: Failed assertion, no message given. 2 tests, 3 assertions, 1 failures, 0 errors, 0 skips 

А? Неудачное утверждение, сообщение не передано. В моем коде строка 22 является assert pictures.length > 0

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

 assert pictures.length > 0, "There are no pictures" 

Запустите тест снова.

 $ ruby test/test.rb Run options: --seed 735 # Running tests: F. Finished tests in 0.016786s, 119.1469 tests/s, 178.7204 assertions/s. 1) Failure: test_for_pictures(MyTest) [test/test.rb:22]: There are no pictures 2 tests, 3 assertions, 1 failures, 0 errors, 0 skips 

Так-то лучше. Давайте вернемся к слайд-шоу. Выход из сцены слева.

В каталоге слайд-шоу pictures_ ничего нет. Затем добавьте файл в этот каталог и снова запустите тест.

 $ touch public/slideshow_pictures/temp.txt $ ruby test/test.rb Run options: --seed 1658 # Running tests: .. Finished tests in 0.023275s, 85.9291 tests/s, 128.8937 assertions/s. 2 tests, 3 assertions, 0 failures, 0 errors, 0 skips 

Yippee! Теперь вы доказываете, что в каталоге слайд-шоу pictures_ что-то есть. Это всего лишь текстовый файл, но мы хотим JPG.

Знаете ли вы, что Dir # glob позволяет вам использовать регулярные выражения?

Идите дальше и измените метод load_pictures чтобы искать только load_pictures JPG и перезапустить тест.

 def load_pictures Dir.glob("public/slideshow_pictures/*.{jpg,JPG}") end 

Вы получили ошибку «Нет картинок»? Добавьте файл JPG в каталог слайд-шоу pictures_ и повторите тест. Помните, что регулярные выражения чувствительны к регистру по умолчанию.

Все тесты снова пройдены? Сладкий, что теперь? Я думаю, отобразить его на веб-странице. Вы знаете, что делать. Написать тест.

У меня есть изображение с именем test.jpg в каталоге слайдшоу pictures_. Когда я запускаю тест, источник изображения должен быть таким.

Тест / test.rb

 … def test_for_echo get '/' assert last_response.ok? assert_equal "slideshow_pictures/test.jpg", last_response.body end … 

Заметьте что-нибудь с assert_equal строки assert_equal ? Почему бы не публичные / слайд-шоу фотографии ? Файл *. / Public / pictures слайд-шоу / test.jpg * доступен как http://example.com/slideshow_pictures/test.jpg. Вот более техническое объяснение.
Идите вперед и запустите тесты.

 $ ruby test/test.rb Run options: --seed 3602 # Running tests: F. Finished tests in 0.020418s, 97.9528 tests/s, 146.9292 assertions/s. 1) Failure: test_moving_world(MyTest) [test/test.rb:17]: Expected: "slideshow_pictures/test.jpg" Actual: "Echo" 2 tests, 3 assertions, 1 failures, 0 errors, 0 skips 

Конечно, это не удалось. Вам нужно загрузить картинки, а затем выписать их «путь»

main.rb

 … get '/' do @pictures = load_pictures @pictures.each do |picture| picture end end … 

Вы загружаете картинки в @pictures экземпляра @pictures а затем зацикливаетесь. Давайте повторим тест.

 $ ruby test/test.rb Run options: --seed 52201 # Running tests: F. Finished tests in 0.062974s, 31.7591 tests/s, 47.6387 assertions/s. 1) Failure: test_moving_world(MyTest) [test/test.rb:17]: --- expected +++ actual @@ -1 +1 @@ -"slideshow_pictures/test.jpg" +"public/slideshow_pictures/test.jpg" 2 tests, 3 assertions, 1 failures, 0 errors, 0 skips 

Тьфу. Это как будто вам нужно заменить public / with »из пути картинок.
Есть идеи, как это сделать?

main.rb

 … @pictures.each do |picture| picture.sub!(/public\//, '') end … 

Вам не понадобится эта публика / поэтому мы от нее избавились. Это никогда не должно возвращаться, чтобы кусать нас, верно? 🙂
Запустите тест снова.

 $ ruby test/test.rb Run options: --seed 21438 # Running tests: .. Finished tests in 0.043231s, 46.2631 tests/s, 69.3946 assertions/s. 2 tests, 3 assertions, 0 failures, 0 errors, 0 skips 

Presto! Работает. Теперь вы можете написать код для браузера, чтобы отобразить картинку. С Sinatra мы можем использовать встроенные шаблоны для визуализации нашего вывода. Встроенные шаблоны определяются в самом основном файле приложения. Они расположены внизу файла.

main.rb

 require 'sinatra' def load_pictures Dir.glob("public/slideshow_pictures/*.{jpg,JPG}") end get '/' do @pictures = load_pictures erb :index end __END__ @@index <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="user-scalable=yes, width=device-width" /> <title>Moving Pictures</title> </head> <body> <% @pictures.each do |picture| %> <img src="<%= picture.sub!(/public\//, '') %>" /> <% end %> </body> </html> 

Мы сделали небольшую HTML-страницу. В методе get качестве языка шаблонов указывается Erb. Также обратите внимание, что имя представления является символом. Встроенные шаблоны требуют, чтобы вы создали переменную класса с тем же именем, чтобы Синатра знал, какой шаблон отображать. Мы увидим это позже.

Как вы думаете, если мы запустим наши тесты, они пройдут? Иди и беги.

 $ ruby test/test.rb Run options: --seed 24993 # Running tests: .F Finished tests in 0.027037s, 73.9727 tests/s, 110.9591 assertions/s. 1) Failure: test_moving_world(MyTest) [test/test.rb:17]: --- expected +++ actual @@ -1 +1,14 @@ -"slideshow_pictures/test.jpg" +"<!DOCTYPE html> +<html> + <head> + <meta charset=\"UTF-8\"> + <meta name=\"viewport\" content=\"user-scalable=yes, width=device-width\" /> +<title>Moving Pictures</title> +</head> +<body> + + <img src=\"slideshow_pictures/test.jpg\" /> + +</body> +</html> +" 2 tests, 3 assertions, 1 failures, 0 errors, 0 skips 

Да, мой тоже взорвался.
Теперь мы выводим HTML, а не только путь к картинке. Мы должны переписать тест, чтобы проверить, содержит ли тело «slideshow_pictures / test.jpg»

Тест / test.rb

 … def test_for_echo get '/' assert last_response.ok? assert last_response.body.include?("slideshow_pictures/test.jpg") end … 

Задержите дыхание, перезапустите тест.

 $ ruby test/test.rb Run options: --seed 48502 # Running tests: .. Finished tests in 0.043955s, 45.5011 tests/s, 68.2516 assertions/s. 2 tests, 3 assertions, 0 failures, 0 errors, 0 skips 

Это должно работать в браузере. Запустите Sinatra и проверьте это в браузере . Теперь весь мир — сцена.

тр-а-чуть-лайка

Давайте рассмотрим, что мы сделали.

  • Мы научились читать файлы из каталога.
  • Мы узнали, как искать определенные типы файлов.
  • Мы узнали о структуре папок по умолчанию в приложении Sinatra.
  • Мы научились устанавливать собственные сообщения об ошибках.

Что дальше?

Вы можете спросить: «Это аккуратно и все, кроме как загрузить изображения в каталог слайд-шоу pictures_?». Это следующая часть.