Статьи

Использование помощников Синатры для очистки вашего кода

Изображение предоставлено Shutterstock

Пару месяцев назад я написал статью о том, как я быстро создал свой личный сайт с помощью Sinatra . Во время создания сайта я начал думать о том, как лучше всего добавить файлы JavaScript на страницы. Поработав с ним некоторое время, я использовал некоторые вспомогательные методы для добавления файлов JavaScript на любую страницу.

На самом деле очень легко добавлять файлы javascript на страницы в Sinatra с помощью файла макета. Например, если вы хотите включить JQuery и пользовательский файл JavaScript (называемый application.js ) на всех страницах, то все, что вам нужно сделать, это поместить следующие строки кода в файл макета:

<script srchttps://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js«></script>
<script src/javascripts/application.js«></script>

view raw
gistfile1.html
hosted with ❤ by GitHub

(Предполагается, что файлы Javascript находятся в общей папке).

Размещение этого кода в файле макета означает, что они будут включены на каждой странице. Однако некоторые файлы JavaScript могут понадобиться только на определенных страницах. Например, вы можете захотеть, чтобы файл email.js загружался только на странице контактов. Оказывается, есть простой способ динамически добавлять вещи в файлы макетов — переменные экземпляра. Они могут быть установлены в маршрутах и ​​затем сослаться на в представлениях. Я использую переменную экземпляра @js для добавления пользовательского файла JavaScript в маршрут:

get ‘/’ do
@js = «custom.js»
slim :index
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Затем я могу добавить в свой файл макета дополнительную строку, которая будет включать соответствующий тег сценария, если была @js переменная @js .

<script srchttps://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js«></script>
<script src/application.js«></script>
<%= «<script src=\«/#{@js}\»></script>» if @js %>

view raw
gistfile1.html
hosted with ❤ by GitHub

Это большое улучшение. Это означает, что вы можете добавить файл javascript на основе маршрута. Единственная проблема заключается в том, что вы можете добавить только один файл на маршрут. Чтобы обойти это, вы можете изменить переменную экземпляра на массив файлов JavaScript:

get ‘/’ do
@js = [«custom.js»,«sorter.js»,«colorpicker.js»]
slim :index
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Для этого также необходимо изменить строку в файле макета, чтобы она перебирала каждую строку в массиве и добавляла тег сценария для каждого файла JavaScript:

<% if @js %>
<% @js.each do |script| %>
<%= «<script src=\»/javascripts/#{script}.js\»></script>» %>
<% end %>
<% end %>

view raw
gistfile1.erb
hosted with ❤ by GitHub

Пока все хорошо — теперь мы можем вставлять пользовательские файлы JavaScript в схему отдельных маршрутов. Поскольку мы перебираем все пользовательские файлы JavaScript в массиве @js , почему бы просто не добавить в массив сценарии, которые появятся на всех страницах (application.js и JQuery)? Это может быть достигнуто путем создания другого массива, используя метод settings Sinatra, называемый settings.javascripts . Этот массив может быть размещен в любом месте вашего файла ruby ​​(мне нравится держать его в верхней части) и содержит все файлы JavaScript, которые должны быть включены на всех страницах:

settings.javascripts = [ «https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js», «application.js» ]

view raw
gistfile1.rb
hosted with ❤ by GitHub

Эти два массива необходимо сложить вместе, чтобы создать один большой массив для повторения. Метод uniq используется, чтобы избежать повторения в случае добавления файла в массив @js , который уже был помещен в массив settings.javascripts :

<% javascripts = (@js ? @js + settings.javascripts : settings.javascripts).uniq %>
<% javascripts.each do |script| %>
<%= «<script src=\»/javascripts/#{script}.js\»></script>» %>
<% end %>

view raw
gistfile1.erb
hosted with ❤ by GitHub

Такое количество логики в представлении выглядит грязно, что всегда является плохим признаком. Лучший способ справиться с большим количеством логики представления — это абстрагировать его во вспомогательный метод. Помощники легко настраиваются в Синатре, вы просто открываете блок и размещаете методы внутри. Эти методы затем доступны внутри маршрутов и видов. Вот помощник, который можно использовать для очистки макета:

helpers do
def javascripts
javascripts = (@js ? @js + settings.javascripts : settings.javascripts).uniq
javascripts.each do |script|
html << «<script src=/#{script}></script>»
end.join
end
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Теперь все, что нужно в файле макета, это строка:

<%= javascripts %>

view raw
gistfile1.erb
hosted with ❤ by GitHub

Гораздо чище.

Поскольку мы сейчас используем вспомогательный метод, почему бы не разрешить ему иметь аргументы? Это позволило бы нам добавлять файлы JavaScript из файла макета, как и раньше. Это не требует особых усилий — добавление звездочки перед именем параметра метода позволяет методу принимать столько аргументов, сколько необходимо. Это означает, что мы можем добавить столько файлов JavaScript, сколько нам нужно для каждого маршрута. Каждый аргумент является частью массива args , который теперь может быть просто добавлен в большой массив файлов JavaScript, который повторяется в макете (в данном случае бонус заключается в том, что нам не нужно проверять, существует ли он, поскольку по умолчанию пустой массив, если аргументы не заданы):

helpers do
def javascripts *scripts
javascripts = (@js ? @js + settings.javascripts + args : settings.javascripts + args).uniq
javascripts.each do |script|
html << «<script src=/#{script}></script>»
end.join
end
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Теперь у нас есть три способа добавить файлы JavaScript на страницу:

  1. В настройках (это для файлов JavaScript, которые являются глобальными для всего сайта)
  2. В файле макета используется помощник javascripts . Это используется для файлов JavaScript, которые являются общими для всех страниц, использующих этот макет.
  3. В обработчике используется переменная экземпляра @js . Это используется для добавления файлов JavaScript по маршруту на основе маршрута.

Сначала может показаться, что методы 1 и 2 — это практически одно и то же — способ добавления глобальных файлов JavaScript. Но весьма часто иметь разные макеты для сайта, и вполне вероятно, что каждый макет потребует определенных файлов JavaScript. Массив settings.javascripts должен использоваться только для действительно глобального JavaScript, который используется по всему сайту. Помощник javascripts может быть использован для добавления файлов JavaScript на основе макета.

Мы можем улучшить это дальше, используя вспомогательный метод для установки метода @js instansce. Вместо того, чтобы устанавливать его непосредственно в обработчике, мы можем использовать вспомогательный метод js который можно использовать для добавления любых пользовательских js-файлов, необходимых для этого маршрута. Это также хорошая возможность очистить вспомогательный метод javascripts как он выглядит немного хрупким (предполагается, что на данный момент существует settings.javascripts ).

helpers do
def js *scripts
@js ||= []
@js = scripts
end
def javascripts(*args)
js = []
js << settings.javascripts if settings.respond_to?(‘javascripts’)
js << args
js << @js if @js
js.flatten.uniq.map do |script|
«<script src=#{path_to script}></script>»
end.join
end
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Наш новый вспомогательный метод js означает, что при вызове в обработчике все выглядит немного лучше. Это особенно верно, так как файлы больше не должны помещаться в массив:

get ‘/’ do
js «custom.js»,«sorter.js»,«colorpicker.js»
slim :index
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

В заключение давайте упростим добавление JQuery и других популярных библиотек, когда они требуются. Это включает в себя написание другого вспомогательного метода, который использует символы быстрого доступа вместо полного URL:

helpers do
def js *scripts
@js ||= []
@js = scripts
end
def javascripts(*args)
js = []
js << settings.javascripts if settings.respond_to?(‘javascripts’)
js << args
js << @js if @js
js.flatten.uniq.map do |script|
«<script src=#{path_to script}></script>»
end.join
end
def path_to script
case script
when :jquery then ‘https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js’
when :rightjs then ‘http://cdn.rightjs.org/right-2.3.0.js’
when :backbone then ‘http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.0/backbone-min.js’
when :underscore then ‘http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.1/underscore-min.js’
else script.to_s + ‘.js’
end
end
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Теперь, если вы хотите добавить определенную библиотеку, все, что вам нужно, это следующий код внутри обработчика маршрута:

get ‘/’ do
js :backbone, :custom
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Обратите внимание, что пользовательские файлы JavaScript теперь можно вводить в виде символов и не нужно path_to в конец «.js», поскольку все это делается с path_to вспомогательного метода path_to .

С вспомогательным методом, работающим так, как мы хотим, пришло время перейти к модульному и переместить его в отдельный файл. Сначала нам нужно создать файл с именем javascripts.rb и сохранить его в папке с именем «sinatra» в корневом каталоге приложения. Весь код внутри блока помощников затем помещается в модуль под названием JavaScripts . Этот модуль затем помещается в модуль под названием Sinatra (что считается наилучшей практикой при расширении Sinatra модулями). Последнее, что нужно сделать, это указать Sinatra::Base в верхней части файла.

require ‘sinatra/base’
module Sinatra
module JavaScripts
def js *scripts
@js ||= []
@js = scripts
end
def javascripts(*args)
js = []
js << settings.javascripts if settings.respond_to?(‘javascripts’)
js << args
js << @js if @js
js.flatten.uniq.map do |script|
«<script src=#{path_to script}></script>»
end.join
end
def path_to script
case script
when :jquery then ‘https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js’
when :rightjs then ‘http://cdn.rightjs.org/right-2.3.0.js’
when :backbone then ‘http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.0/backbone-min.js’
when :underscore then ‘http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.1/underscore-min.js’
else script.to_s + ‘.js’
end
end
end
helpers JavaScripts
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Строка helpers JavaScripts прямо в конце модуля Sinatra регистрирует вспомогательные методы, чтобы они были доступны для использования в приложении.

Чтобы использовать эти вспомогательные методы, все, что вам нужно, это следующая строка кода в главном файле приложения ( main.rb ):

require ‘./sinatra/helpers’

view raw
gistfile1.rb
hosted with ❤ by GitHub

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

get ‘/’
js :backbone, :application
js :admin if logged_in?
slim :index
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Больше вспомогательных методов

Метод, описанный выше, не ограничивается файлами JavaScript. Подобный метод может быть использован для добавления CSS в мелкозернистом виде:

module Sinatra
module JavaScripts
def js *scripts
@js ||= []
@js = scripts
end
def javascripts(*args)
js = []
js << settings.javascripts if settings.respond_to?(‘javascripts’)
js << args
js << @js if @js
js.flatten.uniq.map do |script|
«<script src=#{path_to script}></script>»
end.join
end
def path_to script
case script
when :jquery then ‘https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js’
when :rightjs then ‘http://cdn.rightjs.org/right-2.3.0.js’
when :backbone then ‘http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.0/backbone-min.js’
when :underscore then ‘http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.1/underscore-min.js’
else script.to_s + ‘.js’
end
end
end
module StyleSheets
def css *files
@css ||= []
@css = files
end
def styles(*args)
css = []
css << settings.css if settings.respond_to?(‘css’)
css << args
css << @css if @css
css.flatten.uniq.map do |stylesheet|
«<link href=/#{stylesheet}.css media=screen, projection rel=stylesheet />»
end.join
end
end
helpers JavaScripts, StyleSheets
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Я HeadCleaner всю концепцию дальше и создал модуль под названием HeadCleaner который имеет вспомогательный метод для всех общих элементов, находящихся внутри title html-страницы, таких как meta , title , webfont s и т. Д. Это означает, что вы можете просто использовать метод вызывает создание очень миниатюрного раздела заголовка файла макета, такого как показан ниже:

<head>
<%= meta %>
<%= title_tag %>
<%= favicon %>
<%= ie_shim %>
<%= webfonts %>
<%= javascripts %>
<%= styles :mobile,:general,:ie %>
</head>

view raw
gistfile1.erb
hosted with ❤ by GitHub

Вы можете увидеть код здесь .

Это ни в коем случае не идеально, и я буду признателен за любые отзывы или помощь в дальнейшей разработке (разветвите код на github!). У меня есть идеи для развития этого:

  • Разрешить пользователям устанавливать путь к javascripts
  • Иметь отдельный файл yaml с ярлыками для внешних библиотек, чтобы его можно было легко редактировать
  • Интегрируйте с загрузчиком JavaScript вместо того, чтобы иметь отдельный тег сценария для каждого файла JavaScript.

Я надеюсь, что эти помощники, ну, в общем, полезны. Если вы разработали каких-либо помощников в разработке Синатры, сообщите об этом в комментариях. Ура!

(Главное изображение любезно предоставлено Shutterstock )