Ruby File :: répertoire? Problèmes
Je suis tout à fait nouveau à ruby, mais en jouissant tellement loin tout à fait immensément. Il y a certaines choses qui m'ont donné quelques soucis et le suivant n'est pas une exception.
Ce que j'essaie de faire ici est de créer une sorte de "super-annuaire" par les sous-classing 'Dir'. J'ai ajouté une méthode appelée "sous-dossiers" qui est conçu pour lister le répertoire de l'objet de fichiers et de les pousser dans un tableau si le fichier est un répertoire lui-même. La question est, les résultats de mon test (Fichier.répertoire?) est étrange, voici mon code de la méthode:
def subdirs
subdirs = Array.new
self.each do |x|
puts "Evaluating file: #{x}"
if File.directory?(x)
puts "This file (#{x}) was considered a directory by File.directory?"
subdirs.push(x)
#yield(x) if block_given?
end
end
return subdirs
end
Et étrangement, même si il ya beaucoup de répertoires dans le répertoire, j'ai choisi ("/tmp") - le résultat de cet appel uniquement des listes de "." et ".."
puts "Testing new Directory custom class: FileOps/DirClass"
nd = Directory.new("/tmp")
subs = nd.subdirs
Et les résultats:
Evaluating file: mapping-root
Evaluating file: orbit-jvxml
Evaluating file: custom-directory
Evaluating file: keyring-9x4JhZ
Evaluating file: orbit-root
Evaluating file: .
This file (.) was considered a directory by File.directory?
Evaluating file: .gdmFDB11U
Evaluating file: .X0-lock
Evaluating file: hsperfdata_mishii
Evaluating file: .X11-unix
Evaluating file: .gdm_socket
Evaluating file: ..
This file (..) was considered a directory by File.directory?
Evaluating file: .font-unix
Evaluating file: .ICE-unix
Evaluating file: ssh-eqOnXK2441
Evaluating file: vesystems-package
Evaluating file: mapping-jvxml
Evaluating file: hsperfdata_tomcat
source d'informationauteur | 2009-11-17
Vous devez vous connecter pour publier un commentaire.
Êtes-vous d'exécuter le script à partir de l'intérieur de
/tmp
? Je suppose (je n'ai pas essayé) est que laFile.directory?(x)
est de tester pour voir si il y a un répertoire nommé " x " dans le répertoire courant -- donc, si vous exécutez ce à partir d'un autre répertoire, vous trouverez toujours.
et..
mais pas les autres répertoires.Essayez de changer
File.directory?(x)
àFile.directory?("#{path}/#{x}")
.Marque westling membres a déjà répondu à votre question, mais puisque vous parlez de vous qui sont nouveaux pour les Rubis, voici quelques autres suggestions de style:
Il est généralement préférable d'utiliser la syntaxe littérale, si possible, de sorte que la voie commune pour exprimer ce serait
subdirs = []
.self
est l'implicite récepteur en Ruby, de sorte que vous pouvez simplement laisser de côté. (Ce n'est pas Python, après tout.) Toutefois, le principal objectif du code est de la communication, de sorte que si vous croyez, il communique votre intention de mieux, la laisser à.Parlant de la communication:
x
est pas très communicatif nom, à moins que vous parlez de points dans un système de coordonnées cartésiennes. Que diriez -file
ou si vous êtes mal à l'aise avec les Unix notion que les répertoires sont également des fichiers, le plus neutreentry
? (En fait, le mieux serait probablementpath
mais nous verrons bientôt comment cela pourrait devenir source de confusion.)Ma troisième suggestion est en fait question de préférence personnelle qui est contraire à la commune de Ruby style: commune de Ruby style dicte une ligne de blocs sont délimités avec
{
/}
et multiligne blocs sont délimités avecdo
/end
tout comme vous l'avez fait. Je n'aime pas ça, parce que c'est une distinction arbitraire, qui ne rend pas tout sens. (Rappelez-vous que la "communication"?) Donc, en fait, je fais les choses différemment: si le bloc est impératif dans la nature et, par exemple, certains changements d'état global, j'utilise les mots clés (parce que le bloc est en faitdo
ing peu de travail) et si le bloc est de nature fonctionnelle et retourne un nouvel objet, je préfère utiliser des accolades (parce qu'ils sont joliment mathématique). Donc, dans ce cas, je voudrais utiliser des accolades.Comme Marque déjà expliqué, vous avez besoin de faire quelque chose comme
File.directory?(File.join(path, entry))
ici, oùDir#path
est un attribut public de laDir
classe de retourner le chemin quiDir.new
a été initialisé avec.Ici vous voyez aussi, pourquoi nous n'avons pas utilisé
path
comme le nom du bloc de paramètres. Sinon, nous aurions besoin d'écrireFile.directory?(File.join(self.path, path))
.La manière canonique pour ajouter un élément à un tableau, ou même ajouter à peu près tout ce à quoi que ce soit en Ruby, est le
<<
de l'opérateur. Donc, cela devrait liresubdirs << entry
.Array#push
est un alias deArray#<<
qui est principalement destiné à vous permettre d'utiliser unArray
comme une pile (en collaboration avecArray#pop
).Voici un autre décalage entre mon style personnel et commun Ruby style: Ruby, si ce n'est pas explicite
return
la valeur de retour est tout simplement la valeur de la dernière expression. Cela signifie que vous pouvez laisser tomber lereturn
mot-clé et la commune de Ruby style dit que vous devriez. Toutefois, je préfère utiliser ce similaires au bloc délimiteurs: utilisationreturn
pour les méthodes qui sont de nature fonctionnelle (parce qu'ils ont fait "retour" d'une valeur) et pas dereturn
pour impératif méthodes (parce que leur réel valeur de retour n'est pas ce qui vient après lareturn
mot-clé, mais de quel côté effets qu'ils ont sur l'environnement). Donc, comme vous, je voudrais utiliser unereturn
mot-clé ici, en dépit d'un style commun.Il est de coutume, pour séparer la valeur de retour du reste du corps de la méthode par une ligne vide. (Il en va de même pour le code d'installation, par le chemin.)
Donc, voilà où nous en sommes aujourd'hui:
Comme vous pouvez le voir, le
if
expression vraiment ne sert à sauter une itération de la boucle. C'est beaucoup mieux communiquées par l'aide de lanext
mot-clé:Comme vous pouvez le voir, nous avons réussi à supprimer un niveau d'imbrication de la structure de bloc, qui est toujours un bon signe.
Cet idiome est appelé le "gardien de l'article", et est très populaire dans la programmation fonctionnelle, où beaucoup de langues ont même garde construits, mais il est aussi largement utilisé dans à peu près toute autre langue sur la planète, car il simplifie considérablement le flux de contrôle: l'idée est analogue à un garde posté à l'extérieur d'un château: au lieu de laisser les méchants dans le château (méthode, procédure, fonction, bloc, ...) et puis, péniblement en essayant de suivre chacun de leurs mouvements et constamment peur de rater quelque chose ou perdez, il vous suffit de poster un garde à la entrée de votre château (le début de votre méthode, bloc, ...) qui ne leur laisse pas pour commencer (qui saute à la fin de la procédure, retourne au début de la méthode, saute une itération de la boucle, ...). En Ruby, vous pouvez utiliser
raise
return
next
etbreak
pour cela. Dans d'autres langues, mêmeGOTO
est très bien (c'est un de ces rares cas où unGOTO
peut effectivement clair jusqu' flux de contrôle).Cependant, nous pouvons simplifier encore plus loin, en reconnaissant l'itérateur motif: vous prenez une liste (les entrées du répertoire), puis vous "squash" cette liste à un seul objet (le
subdirs
tableau). Pour un théoricien de la catégorie, cela hurle "catamorphism", pour un hardcore programmeur fonctionnel "fold
", à un softcore programmeur fonctionnel "reduce
", à une Causerie programmeur "inject:into:
" et à un Rubyist "Enumerable#inject
":inject
utilise la valeur de retour de l'itération précédente pour les semences de la prochaine, c'est pourquoi nous devons retournersubdirs
même si nous sommes en sautant d'une itération, en utilisantnext subdirs
au lieu de la plainenext
(qui permettrait le retournil
de sorte que la prochaine itérationsubdirs
seraitnil
etsubdirs << entry
soulèverait unNoMethodError
.)(Remarquez que j'ai utilisé des accolades pour le bloc, même si le bloc modifie en fait son argument. J'ai l'impression que c'est encore un "fonctionnelle" du bloc, mais. YMMV.)
La dernière chose que nous pouvons faire est de reconnaître que ce que nous faisons est juste de filtrage (ou en d'autres termes la "sélection"), les éléments d'un tableau. Et Ruby a déjà une méthode construite en, qui fait exactement cela:
Enumerable#select
. Témoin de la ligne unique de trucs que l'utilisation de la pleine puissance de Ruby génère:Comme une pointe générale: découvrir les merveilles de
Enumerable
. Il est la cheval de bataille de programmation Ruby, semblable àIEnumerable<T>
.NET,dict
s en Python, les listes dans les langages fonctionnels ou de tableaux associatifs en PHP et Perl.J'ai fait quelques petites modifications...
Remplacer * par quelle que soit la voie que vous voulez et vous êtes bon pour aller. Glob vous reçoit tous les fichiers dans le chemin à l'aide de bash expansion de sorte que vous pouvez utiliser * et ** ainsi que les plages, etc. Assez doux.
Le sélectionner des œuvres comme le contraire de rejeter, cherry-picking uniquement les valeurs qui sont vraies dans le bloc.
Dir.glob("*").sélectionnez {|f| Fichier.répertoire?(f) }