Скрипт приложения ruby ​​для командной строки; лучший способ сделать это? - PullRequest
6 голосов
/ 30 октября 2008

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

  1. читать по некоторым данным
  2. Если указан фильтр, используйте его для фильтрации данных
  3. обработка данных

Я хочу, чтобы процесс фильтрации (шаг 2) был максимально гибким.

Я думал, что пользователь может предоставить файл Ruby, который устанавливает известную константу, указывающую на объект, реализующий определенный мной интерфейс, например ::

# user's filter

class MyFilter
  def do_filter(array_to_filter)
    filtered_array = Array.new
    # do my filtering on array_to_filter
    filtered_array
end 

FILTER = MyFilter.new

Код моего приложения будет выглядеть примерно так:

array_that_might_get_filtered = get_my_array()
if (options.filter_file)
  require options.filter_file
  array_that_might_get_filtered = FILTER.do_filter(array_that_might_get_filtered)
end

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

Есть ли лучшая идиома в Ruby для этого?

Ответы [ 3 ]

4 голосов
/ 30 октября 2008

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

Если указан фильтр, используйте его для фильтрации данных

Я полагаю, вы бы указали фильтр в командной строке? Так вы бы вызвали приложение, как это?

ruby dataprocessor.rb custom_filter

Если это так, вы можете определить «api», в котором имя класса должно совпадать с тем, что было передано - в точности так, как вы описали в своем примере.

Чтобы продвинуться еще дальше, у вас может быть логика, которая ищет класс CustomFilter, используя ruby's defined?, и, если он не найден, ищите custom_filter.rb (или любые подходящие варианты) и попытайтесь загрузить этот файл, затем повторите попытку.

Это дает вам большую расширяемость, поскольку вы можете написать столько классов фильтров, сколько захотите, поместить их в свои собственные файлы .rb и поместить их в любое место, где ruby ​​сможет их найти. Вам также не нужно иметь заранее определенные константы, единственными ограничениями будут

  1. Имя класса должно соответствовать (вариант) имени файла - это соглашение в ruby, так что вы, вероятно, уже делаете это в любом случае.
  2. он должен иметь какой-то предопределенный метод, такой как ваш do_filter метод

Кстати, это очень похоже на то, что делает rails для запроса ваших моделей, и поэтому вы можете просто использовать SomeModel, не всегда сначала require app/models/some_model :-) `

0 голосов
/ 30 октября 2008
# user code
USER_FILTER = lambda { |value| value != 0xDEADBEEF }

# script code
load( user_code );
FILTER = ( const_defined?(:USER_FILTER) ? USER_FILTER : lambda { true } )

output_array = input_array.filter(&FILTER)
0 голосов
/ 30 октября 2008

Выглядит как задание для паттерна стратегии , и поскольку ruby ​​имеет функции в качестве объектов первого класса , вы можете передать функцию фильтра для запоминания массивом, чтобы вызвать эту пользовательскую функцию фильтра по требованию.

...