Todo.txt TDD Part 3
As mentioned at the end of Part 2, after the creation date, the rest of the string is called the Description. It can contain projects that start with a plus sign(+) or contexts that start with an at symbol(@) or key/value pairs with a colon(:). We’ll test the projects piece now.
Sub TEST_Projects()
Dim clsTodo As CTodo
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-04-30 Call Mom+Dad due:2016-05-30"
Debug.Assert clsTodo.Projects.Count = 0
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-05-20 2016-04-30 Call Mom @Phone +Family due:2016-05-30"
Debug.Assert clsTodo.Projects.Count = 1
Debug.Assert clsTodo.Projects(1).Tag = "Family"
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-04-30 Call Mom +Phone +Family due:2016-05-30"
Debug.Assert clsTodo.Projects.Count = 2
Debug.Print "TEST_Projects"
End Sub
I’m testing zero, one, and two projects. Now let’s update Raw to make this pass
Public Property Let Raw(ByVal sRaw As String)
Dim vaSplit As Variant
Dim lNext As Long
Dim i As Long
Dim clsProject As CProject
vaSplit = Split(sRaw, Space(1))
Me.Complete = vaSplit(0) = "x"
If vaSplit(0) = "x" Then
lNext = lNext + 1
End If
If vaSplit(lNext) Like "([A-Z])" Then
Me.Priority = Mid$(vaSplit(lNext), 2, 1)
lNext = lNext + 1
End If
If IsDate(vaSplit(lNext)) Then
If IsDate(vaSplit(lNext + 1)) Then
Me.CompleteDate = DateValue(vaSplit(lNext))
Me.CreationDate = DateValue(vaSplit(lNext + 1))
lNext = lNext + 2
Else
Me.CreationDate = DateValue(vaSplit(lNext))
lNext = lNext + 1
End If
End If
For i = lNext To UBound(vaSplit)
If Left$(vaSplit(i), 1) = "+" Then
Set clsProject = New CProject
clsProject.Tag = Mid$(vaSplit(i), 2, Len(vaSplit(i)))
Me.Projects.Add clsProject
End If
Next i
End Property
This loops through the rest of the elements of the split array and looks for a plus sign at the start. If it finds one, it creates a Project instance and adds it to the Projects collection class. The contexts will be handled similarly.
Sub TEST_Contexts()
Dim clsTodo As CTodo
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-04-30 Call Mom@home due:2016-05-30"
Debug.Assert clsTodo.Contexts.Count = 0
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-05-20 2016-04-30 Call Mom @Phone +Family due:2016-05-30"
Debug.Assert clsTodo.Contexts.Count = 1
Debug.Assert clsTodo.Contexts(1).Tag = "Phone"
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-04-30 Call Mom @Phone @Family due:2016-05-30"
Debug.Assert clsTodo.Contexts.Count = 2
Debug.Print "TEST_Contexts"
End Sub
Public Property Let Raw(ByVal sRaw As String)
Dim vaSplit As Variant
Dim lNext As Long
Dim i As Long
Dim clsProject As CProject
Dim clsContext As CContext
vaSplit = Split(sRaw, Space(1))
Me.Complete = vaSplit(0) = "x"
If vaSplit(0) = "x" Then
lNext = lNext + 1
End If
If vaSplit(lNext) Like "([A-Z])" Then
Me.Priority = Mid$(vaSplit(lNext), 2, 1)
lNext = lNext + 1
End If
If IsDate(vaSplit(lNext)) Then
If IsDate(vaSplit(lNext + 1)) Then
Me.CompleteDate = DateValue(vaSplit(lNext))
Me.CreationDate = DateValue(vaSplit(lNext + 1))
lNext = lNext + 2
Else
Me.CreationDate = DateValue(vaSplit(lNext))
lNext = lNext + 1
End If
End If
For i = lNext To UBound(vaSplit)
If Left$(vaSplit(i), 1) = "+" Then
Set clsProject = New CProject
clsProject.Tag = Mid$(vaSplit(i), 2, Len(vaSplit(i)))
Me.Projects.Add clsProject
ElseIf Left$(vaSplit(i), 1) = "@" Then
Set clsContext = New CContext
clsContext.Tag = Mid$(vaSplit(i), 2, Len(vaSplit(i)))
Me.Contexts.Add clsContext
End If
Next i
End Property
The final special case inside the description is key/value pairs.
Sub TEST_KeyValue()
Dim clsTodo As CTodo
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-04-30 Call Mom@home"
Debug.Assert clsTodo.KeyValues.Count = 0
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-05-20 2016-04-30 Call Mom @Phone +Family due:2016-05-30"
Debug.Assert clsTodo.KeyValues.Count = 1
Debug.Assert clsTodo.KeyValues(1).Key = "due"
Debug.Assert clsTodo.KeyValues(1).Value = "2016-05-30"
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-04-30 Call Mom @Phone @Family due:2016-05-30 key:val:ue"
Debug.Assert clsTodo.KeyValues.Count = 2
Debug.Print "TEST_KeyValue"
End Sub
Again I’m testing zero, one, and two instances.
Public Property Let Raw(ByVal sRaw As String)
Dim vaSplit As Variant
Dim lNext As Long
Dim i As Long
Dim clsProject As CProject
Dim clsContext As CContext
Dim clsKeyValue As CKeyValue
Dim vaKeys As Variant
vaSplit = Split(sRaw, Space(1))
Me.Complete = vaSplit(0) = "x"
If vaSplit(0) = "x" Then
lNext = lNext + 1
End If
If vaSplit(lNext) Like "([A-Z])" Then
Me.Priority = Mid$(vaSplit(lNext), 2, 1)
lNext = lNext + 1
End If
If IsDate(vaSplit(lNext)) Then
If IsDate(vaSplit(lNext + 1)) Then
Me.CompleteDate = DateValue(vaSplit(lNext))
Me.CreationDate = DateValue(vaSplit(lNext + 1))
lNext = lNext + 2
Else
Me.CreationDate = DateValue(vaSplit(lNext))
lNext = lNext + 1
End If
End If
For i = lNext To UBound(vaSplit)
If Left$(vaSplit(i), 1) = "+" Then
Set clsProject = New CProject
clsProject.Tag = Mid$(vaSplit(i), 2, Len(vaSplit(i)))
Me.Projects.Add clsProject
ElseIf Left$(vaSplit(i), 1) = "@" Then
Set clsContext = New CContext
clsContext.Tag = Mid$(vaSplit(i), 2, Len(vaSplit(i)))
Me.Contexts.Add clsContext
ElseIf InStr(1, vaSplit(i), ":") > 1 Then
vaKeys = Split(vaSplit(i), ":", 2)
Set clsKeyValue = New CKeyValue
clsKeyValue.Key = vaKeys(0)
clsKeyValue.Value = vaKeys(1)
Me.KeyValues.Add clsKeyValue
End If
Next i
End Property
Everything else is the description
Sub TEST_Description()
Dim clsTodo As CTodo
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-04-30 Call Mom@home"
Debug.Assert clsTodo.Desc = "Call Mom@home"
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-05-20 2016-04-30 Call Mom @Phone +Family due:2016-05-30"
Debug.Assert clsTodo.Desc = "Call Mom"
Set clsTodo = New CTodo
clsTodo.Raw = "(A) 2016-04-30 Call Mom @Phone and Dad @Family due:2016-05-30 key:val:ue"
Debug.Assert clsTodo.Desc = "Call Mom and Dad"
Debug.Print "TEST_Description"
End Sub
Here are the changes to the bottom of Raw
For i = lNext To UBound(vaSplit)
If Left$(vaSplit(i), 1) = "+" Then
Set clsProject = New CProject
clsProject.Tag = Mid$(vaSplit(i), 2, Len(vaSplit(i)))
Me.Projects.Add clsProject
ElseIf Left$(vaSplit(i), 1) = "@" Then
Set clsContext = New CContext
clsContext.Tag = Mid$(vaSplit(i), 2, Len(vaSplit(i)))
Me.Contexts.Add clsContext
ElseIf InStr(1, vaSplit(i), ":") > 1 Then
vaKeys = Split(vaSplit(i), ":", 2)
Set clsKeyValue = New CKeyValue
clsKeyValue.Key = vaKeys(0)
clsKeyValue.Value = vaKeys(1)
Me.KeyValues.Add clsKeyValue
Else
Me.Desc = Me.Desc & vaSplit(i) & Space(1)
End If
Next i
'remove the trailing space
If Len(Me.Desc) > 1 Then
Me.Desc = Left$(Me.Desc, Len(Me.Desc) - 1)
End If
And that’s it. A properly parsed Todo.txt string ready to be used in your application. And if I make an changes to my app, I can run these tests to make sure I didn’t break anything.
You can download TodoTxt.zip
Series:




