[squeak-dev] Review Request: normalize-paths.2.cs

Marcel Taeumel marcel.taeumel at hpi.de
Mon Jul 11 11:16:43 UTC 2022


Hi Christoph --

Sounds reasonable. Especially for comparison, right? Where else would you need a normalized path? User interface?

Is #forPathParts: a public or rather private interface? Maybe add commentary and change message category?

Best,
Marcel
Am 09.07.2022 19:56:59 schrieb christoph.thiede at student.hpi.uni-potsdam.de <christoph.thiede at student.hpi.uni-potsdam.de>:
=============== Summary ===============

Change Set:        normalize-paths
Date:            9 July 2022
Author:            Christoph Thiede

Adds interface for path normalization on FileDirectory that removes path navigators such as '.' or '..'. Tests new #withNormalizedPath for Windows and Unix file directories. Applies path normlization in file dialogs so that entering '../' in the input field will trigger a correct selection of the parent node in the tree.

=============== Diff ===============

DosFileDirectory class>>forPathParts: {instance creation} · ct 7/9/2022 19:43
+ forPathParts: pathParts
+
+     | fileName partsStream |
+     fileName := String streamContents: [:stream |
+         partsStream := pathParts readStream.
+         (self isDriveLetterRoot: partsStream peek)
+             ifTrue: [stream nextPutAll: partsStream next]
+             ifFalse: ["UNC path/network drive" stream nextPutAll: self slash].
+         partsStream do: [:part |
+             stream
+                 nextPutAll: self slash;
+                 nextPutAll: part]].
+     ^ self on: fileName

DosFileDirectory class>>isDrive: {platform specific} · ct 7/9/2022 17:17 (changed)
isDrive: fullName
-     "Answer whether the given full name describes a 'drive', e.g., one of the root directories of a Win32 file system. We allow two forms here - the classic one where a drive is specified by a letter followed by a colon, e.g., 'C:', 'D:' etc. and the network share form starting with double-backslashes e.g., '\\server'."
-     ^ (fullName size = 2 and: [fullName first isLetter and: [fullName last = $:]])
-         or: [(fullName beginsWith: '\\') and: [(fullName occurrencesOf: $\) = 2]]
+     "Answer whether the given full name describes a 'drive', e.g., one of the root directories of a Win32 file system. We allow two forms here - the classic one where a drive is specified by a letter followed by a colon, e.g., 'C:', 'D:' etc., and the UNC/network share form starting with double-backslashes e.g., '\\server' or '\\localhost\c$\Users'."
+
+     ^ (self isDriveLetterRoot: fullName)
+         or: [self isUNCRoot: fullName]

DosFileDirectory class>>isDriveLetterRoot: {platform specific} · ct 7/9/2022 17:16
+ isDriveLetterRoot: fullName
+     "e.g., 'C:', 'D:' etc."
+
+     ^ fullName size = 2 and: [fullName first isLetter] and: [fullName second = $:]

DosFileDirectory class>>isUNCRoot: {platform specific} · ct 7/9/2022 17:17
+ isUNCRoot: fullName
+     "e.g., '\\server' or '\\localhost\c$\Users'"
+
+     ^ (fullName beginsWith: '\\') and: [(fullName occurrencesOf: $\) = 2]

DosFileDirectory>>withNormalizedPath {path access} · ct 7/9/2022 19:55
+ withNormalizedPath
+     "Answer a similar instance to the receiver with a normalized path, i.e., all path navigators such as . or .. will be eliminated."
+
+     | normalizedParts originalParts |
+     originalParts := self pathParts.
+     normalizedParts := OrderedCollection new: originalParts size.
+     originalParts do: [:part |
+         part
+             caseOf:
+                 {[self class parentDirectoryNickname] ->
+                     [normalizedParts size > 1 ifTrue:
+                         [normalizedParts removeLast]].
+                 [self class currentDirectoryNickname] -> []}
+             otherwise: [normalizedParts add: part]].
+     ^ self class forPathParts: normalizedParts

DosFileDirectoryTests>>testWithNormalizedPath {tests} · ct 7/9/2022 19:41
+ testWithNormalizedPath
+
+     FileDirectory activeDirectoryClass == DosFileDirectory ifFalse:[^self].
+     
+     self assert: 'C:\plonk\griffle' equals: (FileDirectory on: 'C:\plonk\griffle') withNormalizedPath pathName.
+     
+     self assert: 'C:\plonk\griffle' equals: (FileDirectory on: 'C:\.\plonk\.\.\griffle\.\') withNormalizedPath pathName.
+     self assert: 'C:\plonk\wiffy' equals: (FileDirectory on: 'C:\..\..\plonk\..\plonk\griffle\..\wiffy\ziffy\..') withNormalizedPath pathName.
+     
+     self assert: '\\share\ziffy' equals: (FileDirectory on: '\\share\..\plonk\..\ziffy') withNormalizedPath pathName.

FileAbstractSelectionDialog>>directory: {directory tree} · ct 7/9/2022 18:58 (changed)
directory: aFileDirectory
    "Set the path of the directory to be displayed in the directory tree pane"

-     directory := aFileDirectory
+     | normalizedDirectory |
+     directory := aFileDirectory.
+     directory ifNil: [^ self].
+     
+     normalizedDirectory := directory withNormalizedPath.
+     normalizedDirectory pathName = directory pathName
+         ifFalse: [directory := normalizedDirectory].
+     self flag: #workaround. "Avoid reassigning the directory as long as possible because PluggableTreeMorph does not perform equality comparison when reselecting items. See comment in #setDirectoryTo:."

FileDirectory class>>forPathParts: {instance creation} · ct 7/9/2022 17:12
+ forPathParts: pathParts
+
+     | fileName |
+     fileName := String streamContents: [:stream |
+         pathParts do: [:part |
+             stream
+                 nextPutAll: self slash;
+                 nextPutAll: part]].
+     ^ self on: fileName

FileDirectory>>= {comparing} · ct 7/9/2022 17:24 (changed)
= aDirectory
    "Compare two FileDirectory instances."
    
    ^(aDirectory isKindOf: FileDirectory) and: [
+         self flag: #todo. "ct: Should we normalize paths here?"
        (pathName asString
            compare: aDirectory pathName asString
            caseSensitive: (self isCaseSensitive or: [ aDirectory isCaseSensitive ])) = 2 ]

FileDirectory>>withNormalizedPath {path access} · ct 7/9/2022 19:55
+ withNormalizedPath
+     "Answer a similar instance to the receiver with a normalized path, i.e., all path navigators such as . or .. will be eliminated."
+
+     | normalizedParts originalParts |
+     originalParts := self pathParts.
+     normalizedParts := OrderedCollection new: originalParts size.
+     originalParts do: [:part |
+         part
+             caseOf:
+                 {[self class parentDirectoryNickname] ->
+                     [normalizedParts size > 0 ifTrue:
+                         [normalizedParts removeLast]].
+                 [self class currentDirectoryNickname] -> []}
+             otherwise: [normalizedParts add: part]].
+     ^ self class forPathParts: normalizedParts

UnixFileDirectoryTests>>testWithNormalizedPath {tests} · ct 7/9/2022 19:46
+ testWithNormalizedPath
+
+     FileDirectory activeDirectoryClass == UnixFileDirectory ifFalse:[^self].
+     
+     self assert: '/media/plonk/griffle' equals: (FileDirectory on: '/media/plonk/griffle') withNormalizedPath pathName.
+     
+     self assert: '/media/plonk/griffle' equals: (FileDirectory on: '/media/./plonk/././griffle/./') withNormalizedPath pathName.
+     self assert: '/media/plonk/wiffy' equals: (FileDirectory on: '/media/../../media/plonk/../plonk/griffle/../wiffy/ziffy/..') withNormalizedPath pathName.

["normalize-paths.2.cs"]

---
Sent from Squeak Inbox Talk [https://github.com/hpi-swa-lab/squeak-inbox-talk]
["normalize-paths.2.cs"]
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20220711/39aefed4/attachment.html>


More information about the Squeak-dev mailing list