2017-10-17 3 views
1

Lorsque le chargement des fichiers, je l'habitude de faire une variante de:alternative à court de ternaire et de sauvetage sous forme de modification

first_file = "#{__dir__}/first_file.txt" 
first_data = File.exist?(first_file) ? File.readlines(first_file) : [] 

second_file = "#{__dir__}/second_file.yaml" 
second_data = File.exist?(second_file) ? YAML.load_file(second_file) : {} 

qui a toujours assis un peu de mal avec moi. Ayant besoin de la vérification pour voir si le fichier existe est quelque chose que a besoin de pour être là, mais ce qui m'importe vraiment est ce qui vient après.

Finalement, j'ai découvert en ligne rescue, et a commencé à le faire comme ceci:

first_file = "#{__dir__}/first_file.txt" 
first_data = File.readlines(firs_file) rescue [] 

second_file = "#{__dir__}/second_file.yaml" 
second_data = YAML.load_file(second_file) rescue {} 

Ce me est beaucoup plus claire - essayer de cette chose que vous voulez vraiment, et si vous ne pouvez pas faire autre chose que est exactement le repli que vous voulez. C'est à la fois plus court et plus clair que le ternaire.

Mais partout où je regarde le même conseil à avoid rescue in modifier form est répété. Je comprends pourquoi: cela peut cacher des erreurs que nous ne prévoyions pas.

Si je pouvais définir Errno::ENOENT comme l'erreur à rescue à partir de la forme en ligne, je le ferais. Mais autant que je peux dire, en ligne rescue ne peut pas spécifier de quelle erreur à sauver.

Alors, quelle est l'alternative? Que puis-je faire qui est aussi court et clair que le rescue en ligne, mais sans l'inconvénient?

+2

Revenez à votre ancienne façon. – sawa

+0

Je suis d'accord avec Sergio, les doublures intelligentes ne sont pas si lisible de nombreuses fois. Créez simplement des méthodes d'aide. –

+0

Je pense que j'ai été clair pourquoi je ne veux pas revenir à l'ancienne. Si le seul argument est de "revenir à l'ancienne", il vaut mieux s'en tenir au nouveau. – user137369

Répondre

2

Si j'étais vraiment préoccupé par la lisibilité de ces lignes, je voudrais créer quelques méthodes d'aide.

def read_with_fallback(filename, fallback) 
    File.exist?(filename) ? yield(File.open(filename)) : fallback 
end 

def safe_read_lines(filename) 
    read_with_fallback(first_file, []) {|file| file.readlines } 
end 

def safe_read_yaml(filename) 
    read_with_fallback(second_file, {}) {|file| YAML.parse(file.read) } 
end 

first_file = "#{__dir__}/first_file.txt" 
first_data = safe_read_lines(first_file) 

second_file = "#{__dir__}/second_file.yaml" 
second_data = safe_read_yaml(second_file) 

Mais si je devais seulement un ou deux de ceux-ci et ne pas les répéter dans toutes les autres méthodes, je ne voudrais pas déranger. Votre première forme est "assez bonne".

+1

"Je créerais des méthodes d'aide" - mes yeux saignent :) Est-ce que vous pensez vraiment, que mystérieux 'safe_read_lines' pour les futurs lecteurs de ce code (qui a accompli au moins le 1er niveau en ruby) est plus lisible que .readlines (firs_file) sauvetage [] '? – mudasobwa

+0

@mudasobwa: le nommage pourrait être amélioré, sans aucun doute. Mais oui, je crois que ce concept de "essayez de votre mieux à lire ce fichier yaml" se lit mieux lorsqu'on lui donne un nom. Niveau supérieur d'abstraction. 'YAML.load_file (second_file) rescue {}' - ceci est exprimé avec au moins 4 "bits" d'information, alors qu'en réalité il n'y en a qu'un, "lisez le fichier yaml". Pourquoi compiler le code dans votre tête. essayer de déduire le _neance_ du code quand vous pouvez l'éviter? Aussi, lisez la dernière partie :) –

+0

@mudasobwa: il n'y a rien de "mystérieux" à propos de cette méthode. Sa définition est une frappe loin (pour ceux avec des éditeurs alimentés) :) –