Статьи

Польский ваши драгоценные камни

Как разработчики Ruby, мы часто забываем, насколько мы хороши. У нас есть замечательная система распространения библиотек в Rubygems, мы используем мощный и гибкий язык, который просто нужно использовать для DSL, а также культуру открытой разработки и улучшения сообщества. В этой статье я расскажу о том, как вы можете добавить этот дополнительный блеск в свой новый полезный камень. Мы рассмотрим некоторые распространенные шаблоны использования и то, как они достигаются в популярных драгоценных камнях.

Ни один из этих советов не предоставляет каких-либо дополнительных функций для вашего драгоценного камня, но они обеспечивают хороший пользовательский опыт. Если у вас есть амбиции, чтобы ваш драгоценный камень стал популярным, UI имеет значение, а код — это интерфейс для программистов.

Блок конфигурации

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

#Usage:
# Awesome.configure do |a|
# a.magic_number = 3
# end
module Awesome
class << self
attr_accessor :configuration
def config
self.configuration ||= Configuration.new
end
def configure
yield(config)
end
end
# The configuration object.
class Configuration < Hashie::Mash
end
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Итак, здесь есть несколько вещей, на которые стоит обратить внимание. Во-первых, я решил, что объект Configuration наследуется от фантастического камня hashie mash . Это позволяет нам рассматривать наш объект Configuration как хеш-код внутри, но означает, что мы можем предоставить хороший синтаксис точек в самом блоке. В примере a.magic_number = 3 приводит к эквиваленту a[:magic_number] = 3 . Во-вторых, метод config действует так же, как метод instance который вы написали бы, если бы создавали одноэлементный класс, поэтому нам не нужно беспокоиться о множественных экземплярах конфигурации, которые могут возникнуть.

Цепная реакция

Если вы пишете гем, который выполняет какой-то поиск в интерфейсе, то вы сталкиваетесь с некоторой проблемой API: как я могу позволить своим пользователям создавать сложные поиски, избегая при этом неправильного хеширования? Чтобы проиллюстрировать, что я имею в виду, давайте посмотрим на Active Record 2 против 3:

##AR 2
Person.find(:all, :conditions => {:name => «Joe», :is_admin => true}, :limit => 10)
##=> Array
#AR 3
Person.where(:name => ‘joe’, :is_admin => true).limit(10)
##=> ActiveRecord::Relation

view raw
gistfile1.rb
hosted with ❤ by GitHub

В примере Active Record 3 цепочка методов используется вместо потенциально массивного хэша для определения нашего запроса. Это также дает дополнительное преимущество, позволяя нам легко определять наш запрос с течением времени и выполнять его только тогда, когда мы уверены, что он нам нужен, вызывая метод, который вызывает фактическое выполнение запроса — например, each .

Давайте создадим действительно простой метод цепочки поиска объекта:

class Search
class << self
def where(args)
Search.new(args)
end
end
def initialize(args)
@search_arguments = args
end
def where(args)
@search_arguments.merge!(args)
self
end
def each
results.each{|a| yield(a)}
end
def results
#Go and get some results!
end
end
#irb(main):084:0> Search.where(:foo => ‘bar’).where(:magic_number => 3)
#=> #<Search:0x10aa5e9d8 @search_arguments={:foo=>»bar», :magic_number=>3}>

view raw
gistfile1.rb
hosted with ❤ by GitHub

Как вы можете видеть, мы создали довольно убедительный поисковый интерфейс, который на первый взгляд выглядит как синтаксис запросов в Active Records 3. Все, что вам нужно сделать, это вернуть self в конце цепных методов, чтобы получить эффект. Обратите внимание, что each является хорошим дополнением, поскольку он устраняет необходимость явного вызова results .

Включите все, где это уместно.

Как я уверен, вы знаете, что вы можете include модуль для добавления методов экземпляра модуля в класс или extend модуль для добавления методов класса. Часто при написании драгоценных камней нам нужно делать и то, и другое. Добавление нескольких строк в документацию, чтобы объяснить пользователям, что нам нужно включить Library::InstanceMethods и расширить Library::ClassMethods — это один из подходов, но это еще одна вещь, о которой пользователь должен беспокоиться, и нет никаких причин, по которым пользователь может Library::ClassMethods не улучшится

HTTParty , пожалуй, наиболее часто используемый пример этого шаблона.

Использование HTTPart по умолчанию выглядит примерно так:

class Thingy
include HTTParty
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

Класс Thingy теперь будет иметь очень удобный экземпляр метода post для запросов POST, но также будет иметь возможность вызывать post класса, если вашему приложению на самом деле не нужно создавать новые Thingy а просто использовать их.

Как это работает? Давайте посмотрим на источник — скопированный с github с некоторыми битами, вырезанными для ясности:

module HTTParty
def self.included(base)
base.extend ClassMethods
#snip
base.instance_variable_set(«@default_options», {})
end
end

view raw
gistfile1.rb
hosted with ❤ by GitHub

self.included — это метод, определенный в self.included классе Module Ruby, который вызывается при включении модуля в другой класс. base , в данном примере, является класс Thingy . Переопределив его, мы теперь можем расширять Thingy с помощью HTTPart::ClassMethods сохраняя пользователю дополнительное расширение.

Кроме того, поскольку у нас есть дескриптор Thingy мы можем выполнить некоторую настройку объекта — как в приведенном здесь примере, мы установили некоторые значения по умолчанию.

included метод и его extended аналог действительно эффективны, но им легко злоупотреблять. В тех местах, где вам не нужно включать и расширять, на самом деле нет необходимости мутить воду, переопределяя included просто чтобы вы могли использовать include, чтобы ввести методы класса — там будут драконы.

Оказаться полезным

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

Дружественные исключения — один из способов помочь. Попробуйте заменить сообщение об исключении «Файл конфигурации не найден» на «Не удается найти файл конфигурации: config / awesome.yml» — возможно, вы могли бы даже вставить URL-адрес в документацию там.

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

Мне было бы интересно услышать ваши опыты с популярными жемчужинами. Есть ли что-то, что недавно привлекло внимание программиста? Есть ли что-то, что из больших драгоценных камней делает это раздражающим? Как всегда, я буду скрываться в разделе комментариев или на машине Tweet — свяжитесь с нами.