Работа с файлами и каталогами.
Сегодня я хотел бы сделать сайт, который отображает фотографии из каталога. Я думаю, что Синатра будет хорошо работать для этого. Мы это настроим.
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_?». Это следующая часть.