TPath

BlitzMax Forums/BlitzMax Module Tweaks/TPath

xacto(Posted 2004) [#1]
I've put together an example of how paths could be abstracted into a type. The type would eliminate the need to manually tweak strings and handle any cross platform issues automatically in one place. This would also clean up a lot of the modules where path$ = path$.Replace( "\", "/" ) is constantly repeated.

Here's the code:

Strict

Import BRL.Stream
Import BRL.FileSystem

Type TInvalidPathException
	Method ToString:String()
		Return "The specified path does not exist."
	End Method
End Type

Type TPath 
	Function FromString:TPath( path:String )
		Local aPath:TPath = New TPath
		aPath.SetPath( path )
		Return aPath
	End Function
	
	Method GetFileName:String()
		Local index:Int = m_path.FindLast( "/" )
		Local result:String = Null
		If index > -1 
			result = m_path[index + 1..m_path.length]
		End If
		Return result
	End Method

	Method GetFileNameWithoutExtension:String()
		Local temp:String = GetFileName()
		If temp <> Null
			Local index:Int = temp.FindLast( "." )
			If index > -1
				temp = temp[..index]
			End If
		End If
		Return temp
	End Method
	
	Method GetExtension:String()
		Local index:Int = m_path.FindLast( "." )
		Local result:String = Null
		If index > -1
			result = m_path[index + 1..m_path.length]
		End If
		Return result
	End Method
	
	Method Exists:Int()
		Return FileType( m_path ) <> FILETYPE_NONE 
	End Method
	
	Method ChangeExtension( extension:String )
		Local index:Int = m_path.FindLast( "." )
		If index > -1
			m_path = m_path[..index] + extension
		End If
	End Method
	
	Method GetDirectoryName:String()
		Local index:Int = m_path.FindLast( "/" )
		Local result:String = Null
		If index > -1
			result = m_path[..index]
		Else
			If FileType( m_path ) = FILETYPE_DIR
				result = m_path
			End If				
		End If
		Return result
	End Method
					
	Method SetPath( path:String )
		m_path = path.Replace( "\", "/" )	
		If FileType( m_path ) = FILETYPE_NONE
			Throw New TInvalidPathException
		ElseIf FileType( m_path ) = FILETYPE_DIR
			m_path:+"/"
		End If
?Linux
?MacOS
		Local cased:String = CasedFileName( m_path )
		If cased
			m_path = cased
		End If
		Local index:Int = m_path.Find( ":" )
		If index > -1 
			m_path = m_path[index + 1..m_path.length]
		End If
?
	End Method

	Method Append( path:String )
		Local temp:String = m_path
		If temp[temp.length - 1] <> "/"
			temp:+"/"
		End If
		temp:+path
		SetPath( temp )
	End Method
	
	Method ToString:String()
		Return m_path
	End Method
		
	Field m_path:String
End Type 

TestTPath()
Function TestTPath()
	Local testPath:TPath = TPath.FromString( "c:\temp" )
	testPath.Append( "form.dat" )
	Print testPath.ToString()
	Print testPath.GetDirectoryName()
	Print testPath.GetFileName()
	Print testPath.GetFileNameWithoutExtension()
	Print testPath.GetExtension()
	Print testPath.Exists()
End Function


Everything that accepts a String now for a path would instead accept a TPath. To make the impact on client code almost seamless BRL could add a ToPath() method on String, which would simply create a new instance of TPath via TPath.FromString.

An example might look like this:

Global anImage:TImage = LoadImage( "C:\gfx\balloon.png".ToPath() )


NOTES:

Since this is really the first class I've implemented in BlitzMax I'd like to pass on some comments/suggestions to BRL:

1. Private/Public should work within a Type. Without being able to set members to Private we lose true encapsulation. In the TPath example above, m_path is still publically accessible so a beginner might accidentially access it directly which would render the abstraction worthless. An alternative here would be to support encapsulated fields a.k.a properties a la .NET, Ruby.

2. The ability to add extensions to the base types would be wonderful. In the TPath example I would have loved to add a ToPath method on String. This is different from inheritence as it changes an existing type. This is similar but not quite the same as partial types.

3. Wishful thinking, I'm sure, but some form of simple reflection would be wonderful.