2016-06-27 2 views
0

Ich bin auf der Suche nach einem geeigneten Muster für eine Anwendung, die verschiedene Dateien verwendet. Der grundlegende Prozess wird sein, das Skript ausführen, die Datendatei (en) laden, Zeug machen, einen Bericht oder eine neue Datendatei ausgeben (keine Änderung der Eingabedateien).Ruby-Muster für die Dateidatenerfassung und einzelne Datensätze

Die Dateien sind verschiedene Formate, aber aus Gründen, sagen wir, sie sind CSV - das Format spielt hier keine Rolle.

Ich bin angezogen von der ActiveRecord Stilmuster, wo Sie eine Klasse haben, die eine Datenmenge darstellt. Es gibt Klassenmethoden, über die Sie Daten abrufen können, und jeder Datensatz ist eine Instanz mit Instanzmethoden für jedes Feld.

In meinem Fall, dass so etwas

class People 
    attr_accessor :first_name, :last_name, :addresss, :city, :country 
    def self.load(file) 
    rtn = self.new 
    @cache = [] 
    # load data into @cache instance var, each row of data is an instance of self 
    rtn 
    end 
    def all_people 
    @cache 
    end 
    def people_in_city(city) 
    # search @cache for matching records 
    end 
    def people_with_last_name(name) 
    # search @cache for matching records 
    end 
    # etc, etc 
end 

Diese Art von Arbeiten aussehen würde, aber es fühlt sich klobig. Jede Instanz hat nicht nur individuelle Datensatzdaten, sondern auch einen Verweis auf alle Daten in der Datei (d. H. @cache). Das ist also eine große Pause von ActiveRecord, wo die tatsächlichen Daten an anderer Stelle (d. H. In der Datenbank) gespeichert werden. In meinem Fall möchte ich alle Daten laden, abfragen und abbrechen.

Mein anderer Ansatz besteht darin, zwei Klassen zu verwenden, eine für die individuelle Aufzeichnung und eine andere für die Sammlung, z.B.

class Person 
    attr_accessor :first_name, :last_name, :addresss, :city, :country 
end 
class PeopleCollection 
    def initialize(file) 
    @cache = [] 
    # load file and place each record into @cache as a Person instance 
    end 
    def all_people 
    @cache 
    end 
    def people_in_city(city) 
    # search @cache for matching records 
    end 
    def people_with_last_name(name) 
    # search @cache for matching records 
    end 
    # etc, etc 
end 

Ich weiß, ich nur CSV::Row für meine Platten Klasse verwenden könnte, oder Hash, aber ich will Accessoren Punktnotation liefern. Ich sah auch OpenStruct, indem es auf method_missing welche nervt mich im Hinblick auf die Auswirkungen auf die Leistung (aber nicht ein Deal Breaker) beruht und auch ich möchte eine erhöhte Ausnahme, wenn ich getroffen record.some_missspelled_attribute_accezzor

aktualisieren

Ein dritter Art und Weise aufgetreten ist, nämlich eine einzige Klasse zu haben, wobei die Sammlung in einer Klassenvariablen gehalten wird. Ähnlich wie bei meinem oben beschriebenen Ansatz für eine einzelne Klasse, wobei die Sammlung jedoch explizit geteilt wird.

+0

die zweite scheint gut, ich habe vor kurzem etwas ähnliches getan –

+0

'OpenStruct' ist wirklich langsam. Verwenden Sie 'Struct', wenn Sie die Struktur kennen:' Person = Struct.new (: Vorname,: Nachname,: Adresse,: Stadt,: Land) ' – Amadan

Antwort

0

Denken Sie zuerst an die Abstraktionsebene, an der Sie arbeiten möchten. Mit method_missing ist nichts falsch. ActiveRecord selbst verwendet method_missing (viel) - es ist nur das method_missing ist eine Sache, die in der Ruby-Welt stark genutzt wird, wenn Sie Metaprogrammieren.

Wenn Sie in CSV-Dateien laden können Sie voran gehen und benutzen Sie einfach den Parser, der mit dem stdlib kommt: http://ruby-doc.org/stdlib-2.3.0/libdoc/csv/rdoc/CSV.html

Wenn Sie andere Arten von Dateien verarbeiten, und CSV wurde als Beispiel ausgewählt, können Sie Verwenden Sie auch Leseleitungen: http://ruby-doc.org/core-2.3.0/IO.html#method-c-readlines

Eine Sache, um vorsichtig zu sein, ist das Laden der gesamten Datei in Speicher vs Stream-Verarbeitung. Wann immer es möglich ist, sollten Sie auf die Stream-Verarbeitung abzielen (dh laden Sie einfach die aktuelle Zeile, die Sie gerade bearbeiten). Der Geschwindigkeitsunterschied ist für kleine Dateien vernachlässigbar und funktioniert unabhängig von der Dateigröße (wenn Sie alles im Speicher laden, werden die Dinge für große Eingabedateien zum Stillstand kommen).

Persönlich würde ich mit dem OpenStruct weitermachen, da ich nichts falsches mit der fehlenden Methode sehe.Wenn Sie das nicht tun möchten, können Sie die Metaprogrammierung selbst tun: schauen Sie sich define_method http://ruby-doc.org/core-2.3.0/Module.html#method-i-define_method

+0

Danke Mircea. Zur Klarstellung, ich kenne CSV, IO usw. nur zu gut. Wie ich bereits erwähnt habe, geht es hier nicht um Dateiformate oder deren Analyse, sondern darum, die Daten im Speicher zu modellieren. Wie bereits erwähnt, ist 'method_missing' für mich kein Deal-Breaker, aber die Art, wie 'OpenStruct' für einen undefinierten Schlüssel nil zurückgibt, ist unerwünscht (in diesem Fall für mich). Was ich wirklich frage, ist, brauche ich zwei Klassen (Sammlung, Aufzeichnung) oder kann ich irgendwie mit einer durchkommen oder gibt es ein anderes Muster, das ich betrachten sollte? – Rob

+0

meine Intuition wäre es, eine integrierte Sammlung zu verwenden und nur den Datensatz zu modellieren. YMMV und Sie möchten vielleicht etwas erstellen, das Enumerable enthält und die Daten bei Bedarf laden. – Mircea

Verwandte Themen