2008-10-30 14 views
6

Ich habe eine Befehlszeile Ruby-App, die ich entwickle, und ich möchte es einem Benutzer ermöglichen, Code, der als Filter für einen Teil des Prozesses ausgeführt wird, zu ermöglichen. Grundsätzlich ist die Anwendung tut dies:Skript eine Ruby-Kommandozeilen-App; beste Möglichkeit, dies zu tun?

  1. Lese in einigen Daten
  2. Wenn ein Filter angegeben wird, verwenden Sie es zum Filtern von Daten
  3. Prozess die Daten

ich den Filterprozess werden soll (Schritt 2) so flexibel wie möglich zu sein.

Mein Denken war, dass der Benutzer eine Ruby-Datei zur Verfügung stellen könnte, die eine bekannte Konstante auf ein Objekt zeigen eine Schnittstelle implementiert, definiere ich, zum Beispiel:

# 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 

Code Meine App wäre dann so etwas tun:

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 

Während dies funktionieren würde, fühlt es sich kitschig und es scheint, wie es sollte eine bessere Art und Weise, es zu tun. Ich erwog auch, den Filter in der Form zu haben, einer bekannten Klasse eine Methode eines bekannten Namens hinzuzufügen, aber das schien auch nicht ganz richtig zu sein.

Gibt es ein besseres Idiom in Ruby dafür?

Antwort

4

Ich würde nur eine Kombination aus Befehlszeile und Konvention verwenden.

Wenn ein Filter angegeben wird, verwenden sie Daten zu filtern

Ich gehe davon aus Sie einen Filter auf der Kommandozeile angeben würde? Also würden Sie die Anwendung so aufrufen?

ruby dataprocessor.rb custom_filter 

Wenn ja, könnten Sie eine „api“ definieren, wobei ein Klassenname muss passen würde, was in übergeben wurde - so ziemlich genau, wie Sie in Ihrem Beispiel beschrieben haben.

Um es einen Schritt allerdings weiter, man eine gewisse Logik haben könnte, die für die CustomFilter Klasse sah Ruby mit defined?, und wenn es nicht gefunden wurde, gehen für custom_filter.rb (oder alle geeigneten Variationen) suchen und versuchen, diese Datei zu laden , dann versuche es erneut.

Dies gibt Ihnen große Erweiterbarkeit, wie Sie so viele Filterklassen schreiben können, wie Sie möchten, chuck sie in ihre eigenen .rb-Dateien, und legen Sie sie überall, dass Rubin sie finden können. Sie werden nicht entweder eine vordefinierte Konstanten haben müssen, sind die einzigen Einschränkungen

  1. Der Klassenname den Dateinamen übereinstimmen (eine Variante) muss sein - Dies ist in Ruby-Konvention so sind Sie wahrscheinlich bereits mach es trotzdem.
  2. muss

übrigens einige vordefinierte Methode, wie Ihre do_filter Methode haben, ist dies ziemlich ähnlich, was Schienen tut für Ihre Modelle erfordern, und ist, warum Sie gerade SomeModel, ohne immer require app/models/some_model tun verwenden können, um zuerst :-) `

+0

Viel praktischer als meine allgemeine Antwort. +1 – VonC

0
# 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) 
Verwandte Themen