Статьи

Создание Ruby Gem для плагина jQuery: расширенный

Снимок экрана 2014-10-12 11.39.13

В предыдущей статье мы создали «драгоценный камень» с нуля, который включает плагин jQuery и добавляет его в приложение Rails. В этом посте давайте рассмотрим некоторые продвинутые концепции, чтобы сделать наш камень еще лучше.

Мы будем использовать то же приложение gem и Rails, что и в предыдущем посте.

Пользовательский Помощник

До сих пор мы успешно применяли эффект масштабирования к изображениям, просто добавляя CSS-класс image_zoomer . Но вы не думаете, что наш драгоценный камень заслуживает специального помощника? Я имею в виду, не лучше ли использовать наш собственный вспомогательный тег и освободить пользователя от необходимости добавлять CSS-класс image_zoomer ?

Давайте создадим собственный помощник с именем zoom_image_tag . К изображениям, добавленным с помощью zoom_image_tag будет применен эффект масштабирования по умолчанию. Создайте файл с именем zoom_image_helper.rb в каталоге lib / image_zoomer в геме и вставьте следующий код:

 module ImageZoomer def zoom_image_tag(*args, &amp;block) options = insert_zoom_class(args.extract_options!) args << options image_tag(*args, &amp;block) end def insert_zoom_class(options) class_name = "image_zoomer" if options.key?(:class) options[:class] += " #{class_name}" elsif options.key?('class') options['class'] += " #{class_name}" else options[:class] = class_name end options end end 

Мы определили два метода в модуле ImageZoomer . Метод zoom_image_tag получает несколько аргументов и блок, как и помощник image_tag .

options = insert_zoom_class(args.extract_options!) вызывает extract_options! метод, предоставляемый ActiveSupport . Он используется для извлечения параметров из набора аргументов. Он удаляет и возвращает последний элемент в массиве, если это хеш, в противном случае он возвращает пустой хеш. insert_zoom_class хеш передается в insert_zoom_class .

insert_zoom_class — это простой метод, используемый для вставки class в предоставленный хеш. Ключ может быть символом, строкой или не предоставляться вообще. Здесь image_zoomer class image_zoomer возвращается как часть хэша.

args appends the хэш options к args . Так как extract_options! удаляет параметры из args , мы должны добавить их обратно.

image_tag(*args, &block) является стандартным помощником Rails image_tag с нашими измененными аргументами. zoom_image_tag здесь: zoom_image_tag — это просто обертка для image_tag . У пользователей нашего драгоценного камня теперь есть удобный способ облегчить их жизнь.

Перейдите в тестовое приложение Rails и откройте app / views / site / index.html.erb в вашем приложении Rails и замените image_tag на:

 <%= zoom_image_tag("test.jpg"); %> 

Запустите веб-сервер и откройте в браузере http: // localhost: 3000 / site / index . Вы увидите ошибку, в которой указано что-то вроде undefined method 'zoom_image_tag' . Что происходит?? Мы не говорили Rails, что zoom_image_tag — это вспомогательный метод. Давайте сделаем это сейчас.

Мы знаем, что помощник image_tag определен в ActionView::Helpers::AssetTagHelper . Мы можем просто снова открыть эти модули и добавить модуль ImageZoomer . Откройте lib / image_zoomer.rb (в геме) и добавьте:

 require "image_zoomer/zoom_image_helper" module ActionView module Helpers module AssetTagHelper include ImageZoomer end end end 

Теперь zoom_image_tag станет частью методов ActionView::Helpers::AssetTagHelper , присоединившись к лиге других помощников, таких как image_tag , javascript_include_tag и т. Д.

Перезагрузите веб-сервер и обновите страницу. Эффект масштабирования изображения применяется с помощью нашего нового помощника. Здорово.

Важный рефакторинг

Включение ImageZoomer в существующий модуль является разновидностью Monkey Patching и считается вредным. К счастью, Rails предоставляет элегантный способ добавления пользовательских помощников, называемых Railties, которые не используют Monkey Patching. Railties предоставляют несколько хуков для участия в процессе инициализации. Узнайте больше о Railtie здесь .

Сначала удалите недавно вставленный код из lib / image_zoomer.rb, чтобы он состоял только из трех операторов require . Создайте файл railtie.rb в каталоге lib / image_zoomer / с помощью:

 class Railtie < Rails::Railtie initializer "image_zoomer.initialize_zoom_image_helper" do |app| ActiveSupport.on_load(:action_view) do include ImageZoomer end end end 

Вот наш класс Railtie который Railtie от Rails::Railtie в соответствии с документацией Rails. Вызов метода initializer принимает имя и блок. Блок делает нашу магию, вызывая ActiveSupport.on_load(:action_view) и передавая другой блок для включения модуля ImageZoomer . Наш модуль ImageZoomer будет включен только ActionView полной загрузки ActionView . Это стандартный способ добавления помощников начиная с Rails 3. Подробнее об этом здесь .

Требуйте railtie.rb в lib / image_zoomer.rb со следующим кодом:

 require "image_zoomer/railtie" 

Сохраните изменения, перезапустите веб-сервер и обратите внимание, что эффект масштабирования все еще работает. Теперь zoom_image_tag вставляется встроенными хуками Rails, и мы исключили Monkey Patching.

Наша окончательная версия lib / image_zoomer.rb выглядит так:

 require "image_zoomer/version" require "image_zoomer/engine" require "image_zoomer/zoom_image_helper" require "image_zoomer/railtie" 

Переопределение конфигураций по умолчанию

Наш драгоценный камень работает нормально, и мы можем назвать его «готовым», но действительно ли он расширяемый? Под «расширяемым» я имею в виду, может ли разработчик изменить стандартную конфигурацию плагина jQuery? По умолчанию height и width зум-объектива составляет 90px а zoom-level1.5 . Если разработчик не может обновить эти настройки, наша жемчужина не расширяема. Другими словами, мы еще не закончили.

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

Класс конфигурации

Создайте класс для хранения нашей конфигурации в файле с именем lib / image_zoomer / configuration.rb в вашем геме и добавьте:

 module ImageZoomer class Configuration attr_accessor :width, :height, :zoom_level def initialize @width = 90 @height = 90 @zoom_level = 1.5 end end end 

Мы просто создали класс в нашем модуле ImageZoomer . Класс Configuration имеет три свойства: width , height и zoom_level . Экземпляры этого класса получат значения по умолчанию, которые соответствуют определенным плагином jQuery.

Требуется файл configuration.rb в lib / image_zoomer.rb :

 require "image_zoomer/configuration" 

Лучшее место для создания экземпляра этого класса — в lib / image_zoomer / railtie.rb . Добавьте следующий код в наш класс Railtie :

 initializer "image_zoomer.configuration" do |app| app.config.image_zoomer = ImageZoomer::Configuration.new end 

Мы снова вызываем метод initializer и передаем ему имя и блок. app здесь представляет Rails.application а app.config является экземпляром Rails::Application::Configuration используемым для хранения всей конфигурации приложения. Мы создали экземпляр ImageZoomer::Configuration и присвоили его app.config.image_zoomer .

Теперь доступ к Rails.application.config.image_zoomer представит экземпляр ImageZoomer::Configuration . Перезагрузите веб-сервер, обновите браузер и убедитесь, что мы ничего не сломали.

Чтобы немедленно поиграть с экземпляром ImageZoomer::Configuration , запустите консоль ( rails console ) и введите Rails.application.config.image_zoomer . Если все настроено правильно, вы увидите наш ImageZoomer::Configuration в действии.

Предоставление настроек плагину

У драгоценного камня теперь есть класс конфигурации, нам нужно только использовать его. Создайте новый файл с именем image_zoomer_options.js.erb в app / assets / javascripts под гемом с помощью:

 var __ImageZoomer = { options: { width: "<%= Rails.application.config.image_zoomer.width %>", height: "<%= Rails.application.config.image_zoomer.height %>", zoom_level: "<%= Rails.application.config.image_zoomer.zoom_level %>" } } 

Приведенный выше код довольно прост. __ImageZoomer переменную JavaScript ( __ImageZoomer ) и __ImageZoomer ей объект со свойством с именем options . У объекта options есть три свойства, которые соответствуют свойству объекта Rails.application.config.image_zoomer . Это шаблон erb потому что мы хотим выполнить некоторый код Ruby, а Sprockets автоматически обрабатывает выполнение динамического кода в файлах ресурсов. Таким образом, image_zoomer_options.js.erb укажет результат в /assets/image_zoomer_options.js в ответе HTML и будет выглядеть так:

 var __ImageZoomer = { options: { width: "90", height: "90", zoom_level: "1.5" } } 

Как видите, наш динамический код выполняется, а width , height и zoom_level имеют значения по умолчанию, которые мы определили в конструкторе ImageZoomer::Configuration .

С нашим новым объектом JavaScript, содержащим значения конфигурации, пришло время изменить код инициализации плагина jQuery для его использования. Откройте app / assets / javascripts / image_zoomer_initializer.js под вашим гемом и замените существующий код на:

 $(function() { if (typeof __ImageZoomer == "undefined") { __ImageZoomer = {options: {}}; } $(".image_zoomer").each(function() { $(this).image_zoomer(__ImageZoomer.options); }); }); 

Сначала проверьте, существует ли переменная __ImageZoomer и создайте ее, если необходимо. В соответствии с использованием плагина jQuery мы можем передать объект в метод image_zoomer и свойства, определенные в этом объекте, будут применены. При __ImageZoomer.options наши настройки применяются для изменения режима масштабирования изображения.

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

Изменение значений по умолчанию в Rails

Rails использует инициализаторы для изменения конфигурации для гемов и основных настроек Rails. Мы тоже так сделаем. Во-первых, в ImageZoomer::Configuration должен быть элегантный способ обновления свойств. Откройте lib / image_zoomer / configuration.rb и добавьте в класс следующий метод:

 # Override default options with the provided ones in block def set_options(&amp;block) block.yield(self) end 

Мы создали метод set_options который принимает блок, который set_options self (текущий экземпляр конфигурации). Вызов этого метода с соответствующим блоком обновит значения по умолчанию Image_Zoomer::Configuration из нашего инициализатора Rails.application.config.image_zoomer .

В приложении Rails создайте config / initializer / image_zoomer.rb с помощью:

 Rails.application.config.image_zoomer.set_options do |options| options.width = 50 options.height = 50 end 

Когда этот код выполняется, width и height изменяются на 50 , а image_zoomer по-прежнему равен 1.5 потому что мы его не меняли. Разработчики могут легко изменить этот блок в соответствии со своими потребностями. Поскольку мы уже настроили наш код jQuery таким образом, чтобы он выбирал последние значения из нашего Rails.application.config.image_zoomer мы готовы к работе.

Перезапустите веб-сервер, обновите браузер и обратите внимание на width и height отличные от предыдущих.

Исправление предостережения

Подождите, ширина и высота не изменились. Что происходит? Это связано с одной оговоркой.

Sprockets кэширует ресурсы, чтобы им не приходилось обрабатывать их снова и снова. Когда любой ресурс обслуживается в первый раз, он кэшируется, и этот кеш будет обслуживаться при последующих запросах. Этот кеш не будет обновляться, даже когда мы перезапускаем веб-сервер. Один из способов обновить кэш для любого ресурса — это изменить его исходный код, но это может привести к бесполезным изменениям и глупым коммитам, полным пустых мест / строк. Давайте посмотрим на лучший способ. Откройте lib / image_zoomer / railtie.rb и измените блок image_zoomer.configuration следующим образом:

 initializer "image_zoomer.configuration" do |app| app.config.image_zoomer = ImageZoomer::Configuration.new # Clear the cache FileUtils.rm_rf("#{Rails.application.root}/tmp/cache/assets") if Rails.env.development? end 

Звездочки хранят кэши по указанному пути в нашем приложении Rails. Мы удаляем этот каталог, когда выполняется код в нашем lib / image_zoomer / railtie.rb (когда сервер запускается и гем загружается). Мы используем встроенные в Ruby методы для удаления этой папки в среде разработки.

Перезапустите веб-сервер, и вы, наконец, увидите зум-объектив с разными размерами. Идите вперед и измените настройки в config / initializers / image_zoomer.rb на свое усмотрение .

Публикация драгоценного камня

Наш драгоценный камень готов. Публиковать гем довольно просто, благодаря основной команде Rubygems. Bundler уже предоставил некоторые задачи, которые полезны при упаковке и распространении драгоценных камней. Во-первых, вы должны иметь учетную запись Rubygem. Зайдите на http://rubygems.org и зарегистрируйтесь.

После создания учетной записи обновите соответствующую информацию в файле image_zoomer.gemspec . Вы, вероятно, захотите перенести этот самоцвет в Github.

Перейдите в корневой каталог вашего драгоценного камня и введите следующую команду:

 rake release 

Эта команда скомпилирует все необходимые файлы в пакет .gem , передаст последний код вместе (с версией gem) в качестве тега в GitHub и загрузит гем в Rubygems. Во время публикации вам будет предложено ввести учетные данные Rubygems, предоставьте их и все готово. Как только камень будет успешно опубликован, вы увидите это в своей панели на Rubygems.

Если по какой-то причине не rake release , вы также можете собрать гем, используя rake build . Если это работает, вручную image_name-version.gem сгенерированный image_name-version.gem в Rubygems с помощью gem push path/to/image_name-version.gem .

Одна вещь, оставленная

Теперь осталось только одно — поделиться своей жемчужиной с коллегами, друзьями и другими рубиистами. Не забудьте написать письмо Питеру Куперу, чтобы опубликовать его в RubyWeekly, одном из самых читаемых информационных бюллетеней Ruby.

Вывод

Создание чего-то и содействие открытому исходному коду — потрясающий опыт, и каждый разработчик должен это делать. Я надеюсь, что вы узнали много в этих двух статьях. Идите вперед и сделайте драгоценный камень для вашего любимого плагина jQuery.