I am trying to create a class with string trimming functions:
Object subclass: Trimmer [
trimleading: str [ |ch ret|
ch := (str first: 1). "get first character"
ret := str. "make a copy of sent string"
[ch = ' '] whileTrue: [ "while first char is space"
ret := (ret copyFrom: 2). "copy from 2nd char"
ch := ret first: 1. "again test first char"
].
^ret "return value is modified string"
].
trim: str [ |ret|
ret := str.
ret := (trimleading value: ret). "trim leading spaces"
ret := (trimleading value: (ret reverse)). "reverse string and repeat trim leading"
^(ret reverse) "return reverse string"
]
].
oristr := ' this is a test '
('ORI..>>',oristr,'<<') displayNl.
('FINAL>>',((Trimmer new) trim: oristr),'<<') displayNl.
However, it is not running and giving following error:
$ gst trimstring_class.st
trimstring_class.st:10: invalid class body element
trimstring_class.st:17: expected expression
Where is the problem and how can this be solved?
If I remove the .
after trimleading method block, as in following code:
Object subclass: Trimmer [
trimleading: str [ |ch ret flag|
ret := str. "make a copy of sent string"
flag := true.
[flag] whileTrue: [ "while first char is space"
ch := ret first: 1. "again test first char"
ch = ' '
ifTrue: [ ret := (ret copyFrom: 2 to: ret size)] "copy from 2nd char"
ifFalse: [flag := false]
].
^ret "value is modified string"
] "<<<<<<< PERIOD/DOT REMOVED FROM HERE."
trim: str [ |ret|
ret := str.
ret := (trimleading value: ret). "trim leading spaces"
ret := (trimleading value: (ret reverse)). "reverse string and repeat trim leading"
^(ret reverse) "return reverse string"
]
].
Then the code starts to run but stops with following error:
$ gst trimstring_class.st
trimstring_class.st:15: undefined variable trimleading referenced
ORI..>> this is a test <<
Object: Trimmer new "<0x7f1c787b4750>" error: did not understand #trim:
MessageNotUnderstood(Exception)>>signal (ExcHandling.st:254)
Trimmer(Object)>>doesNotUnderstand: #trim: (SysExcept.st:1448)
UndefinedObject>>executeStatements (trimstring_class.st:23)
Why trimleading
method is undefined now and why gnu-smalltalk did not understand #trim:
?
Usually it is wise for a such common use case to check if such functionallity was already implemented. You can take an inspiration from it for your code (you will improve as Smalltalk programmer too). Take a look at trimBlanksFrom: from sports.st
:
SpStringUtilities class >> trimBlanksFrom: aString [
"^a String
I return a copy of aString with all leading and trailing blanks removed."
<category: 'services'>
| first last |
first := 1.
last := aString size.
[last > 0 and: [(aString at: last) isSeparator]]
whileTrue: [last := last - 1].
^last == 0
ifTrue: [String new]
ifFalse: [
[first < last and: [(aString at: first) isSeparator]]
whileTrue: [first := first + 1].
aString copyFrom: first to: last
]
]
If you want to trim only leading spaces you can just take the second part, where it is trimming the leading spaces.
EDIT The OP own code a fixes applied:
Object subclass: Trimmer [
trimleading: str [ |ch ret flag|
ret := str. "make a copy of sent string"
flag := true.
[flag] whileTrue: [ "while first char is space"
ch := ret first: 1. "again test first char"
ch = ' '
ifTrue: [ ret := (ret copyFrom: 2 to: ret size) ] "copy from 2nd char"
ifFalse: [flag := false ]
].
^ret "value is modified string"
] "<<<<<<< PERIOD/DOT REMOVED FROM HERE."
trim: str [ |ret|
ret := str.
ret := self trimleading: (ret copy). "trim leading spaces"
ret := self trimleading: (ret copy reverse). "reverse string and repeat trim leading"
^ (ret reverse) "return reverse string"
]
].
oristr := ' this is a test '
('ORI..>>',oristr,'<<') displayNl.
('FINAL>>',((Trimmer new) trim: oristr),'<<') displayNl.
The were some mistakes that needed to be fixed. If you want to address a selector #trimleading:
you have to use self
keyword which searches the local class (for own classes or inherited). Next you should not change a variable that you are assigning to you should use a #copy
otherwise strange result can be expected.