Hi Joe,<div><br></div><div>Thank you for asking interesting questions and staying involved. </div><div><br></div><div>One way to find this out for yourself is to run this code to step through what is happening (highlighting the two lines and hitting the PrintIt key combo):</div>
<div><div><font face="courier new, monospace">self halt. </font></div><div><font face="courier new, monospace">'123%s456' printf: ('s').</font></div></div><div><br></div><div>You'll find that the class ByteString also now has a <font face="courier new, monospace">#printf:</font> method inherited from String class. So, the ByteString class knows how to convert itself to a FormatString if it sees a <font face="courier new, monospace">#printf:</font> method.</div>
<div><div><font face="courier new, monospace">printf: arguments</font></div><div><font face="courier new, monospace"> ^ self asFormatString printf: arguments</font></div></div><div><br>The ' * ' in <font face="courier new, monospace">*printf</font> method category name is a visual clue that a load has added it to the default String class.</div>
<div><br></div><div>- Darius</div><div>_______________<br><br><div class="gmail_quote">On Mon, Oct 8, 2012 at 3:13 PM, Joseph J Alotta <span dir="ltr"><<a href="mailto:joseph.alotta@gmail.com" target="_blank">joseph.alotta@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Greetings:<br>
<br>
I filed in the below code. When I ask '%6.2e' what class it is, it replies ByteString.<br>
<br>
'%6.2e' class => ByteString<br>
<br>
When I send a ByteString the #printf, it somehow knows to look in the FormatString class for this<br>
method.<br></blockquote><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
'%6.2e' printf: 412.343434 => '412.34'<br>
<br>
My question is, where is the place in the below code where this gets redirected? i.e., Where the<br>
printf method gets added to the ByteString path of available methods.<br>
<br>
<br>
Thanks for your help,<br>
<br>
Joe.<br>
<br>
<br>
<br>
<br>
<br>
<br>
Object subclass: #FormatDescriptor<br>
instanceVariableNames: 'flush width precision'<br>
classVariableNames: 'Flags Operators'<br>
poolDictionaries: ''<br>
category: 'Printf'!<br>
<br>
!FormatDescriptor methodsFor: 'rendering'!<br>
applyOperator: object<br>
self subclassResponsibility! !<br>
<br>
!FormatDescriptor methodsFor: 'rendering' stamp: 'hjo 9/18/2011 00:31'!<br>
render: object<br>
| string |<br>
string := self applyOperator: object.<br>
self stringLength ~= 0<br>
ifTrue: [ string := string copyFrom: 1 to: (self stringLength min: string size) ].<br>
width == 0<br>
ifTrue: [ ^ string ].<br>
^ (String new: width withAll: self padding)<br>
copyReplaceFrom: (self startIndexOfCopyReplaceWithStringSize: string size)<br>
to: (self stopIndexOfCopyReplaceWithStringSize: string size)<br>
with: string! !<br>
<br>
!FormatDescriptor methodsFor: 'rendering' stamp: 'hjo 9/18/2011 00:31'!<br>
startIndexOfCopyReplaceWithStringSize: anInteger<br>
<br>
|start|<br>
flush == #leftFlush ifTrue: [start := 1].<br>
flush == #rightFlush ifTrue: [start := width - anInteger + 1].<br>
^(start max: 1)<br>
! !<br>
<br>
!FormatDescriptor methodsFor: 'rendering' stamp: 'hjo 9/18/2011 00:31'!<br>
stopIndexOfCopyReplaceWithStringSize: anInteger<br>
<br>
| stop |<br>
flush == #leftFlush ifTrue: [stop := anInteger].<br>
flush == #rightFlush ifTrue: [stop := width].<br>
^stop min: width! !<br>
<br>
<br>
!FormatDescriptor methodsFor: 'private'!<br>
flush<br>
^ flush! !<br>
<br>
!FormatDescriptor methodsFor: 'private' stamp: 'mir 6/6/2000 23:58'!<br>
operator: char<br>
| myself |<br>
myself := (Smalltalk at: (Operators at: char)) newFrom: self.<br>
myself setOperator: char.<br>
^ myself! !<br>
<br>
!FormatDescriptor methodsFor: 'private'!<br>
padding<br>
^ Character space! !<br>
<br>
!FormatDescriptor methodsFor: 'private'!<br>
precision<br>
^ precision! !<br>
<br>
!FormatDescriptor methodsFor: 'private'!<br>
precision: anInteger<br>
precision := anInteger! !<br>
<br>
!FormatDescriptor methodsFor: 'private'!<br>
setOperator: char! !<br>
<br>
!FormatDescriptor methodsFor: 'private'!<br>
stringLength<br>
^ precision isNil ifTrue: [0] ifFalse: [precision]! !<br>
<br>
!FormatDescriptor methodsFor: 'private'!<br>
width<br>
^ width! !<br>
<br>
!FormatDescriptor methodsFor: 'private'!<br>
width: anInteger<br>
width := anInteger! !<br>
<br>
<br>
!FormatDescriptor methodsFor: 'initialize-release'!<br>
initialize<br>
flush := #rightFlush.<br>
width := 0! !<br>
<br>
<br>
!FormatDescriptor methodsFor: 'scanning'!<br>
leftFlush<br>
flush := #leftFlush! !<br>
<br>
!FormatDescriptor methodsFor: 'scanning'!<br>
radix<br>
^ (NumberFormatDescriptor newFrom: self) radix! !<br>
<br>
!FormatDescriptor methodsFor: 'scanning'!<br>
rightFlush<br>
flush := #rightFlush! !<br>
<br>
!FormatDescriptor methodsFor: 'scanning'!<br>
space<br>
^ (NumberFormatDescriptor newFrom: self) space! !<br>
<br>
!FormatDescriptor methodsFor: 'scanning'!<br>
zero<br>
^ (NumberFormatDescriptor newFrom: self) zero! !<br>
<br>
<br>
!FormatDescriptor methodsFor: 'printing'!<br>
printOn: aStream<br>
aStream nextPut: $%.<br>
flush == #leftFlush ifTrue: [aStream nextPut: $-]! !<br>
<br>
!FormatDescriptor methodsFor: 'printing'!<br>
printWidthOn: aStream<br>
width ~= 0 ifTrue: [width printOn: aStream].<br>
precision isNil ifFalse: [aStream nextPut: $.. precision printOn: aStream]! !<br>
<br>
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!<br>
<br>
FormatDescriptor class<br>
instanceVariableNames: ''!<br>
<br>
!FormatDescriptor class methodsFor: 'class initialization' stamp: 'mir 6/7/2000 00:21'!<br>
initialize<br>
"FormatDescriptor initialize"<br>
Operators := Dictionary new.<br>
Operators at: $p put: #PrintStringFormatDescriptor.<br>
Operators at: $c put: #CharacterFormatDescriptor.<br>
Operators at: $s put: #StringFormatDescriptor.<br>
#($d $o $u $x $X)<br>
do: [:operator | Operators at: operator put: #NumberFormatDescriptor].<br>
#($e $E $f $g $G)<br>
do: [:operator | Operators at: operator put: #FloatFormatDescriptor].<br>
<br>
Flags := Dictionary new.<br>
Flags at: $- put: #leftFlush.<br>
Flags at: $+ put: #rightFlush.<br>
Flags at: $ put: #space.<br>
Flags at: $# put: #radix.<br>
Flags at: $0 put: #zero.<br>
! !<br>
<br>
<br>
!FormatDescriptor class methodsFor: 'instance creation'!<br>
new<br>
^ super new initialize! !<br>
<br>
!FormatDescriptor class methodsFor: 'instance creation'!<br>
newFrom: desc<br>
| myself |<br>
myself := self new.<br>
myself perform: desc flush.<br>
myself width: desc width.<br>
myself precision: desc precision.<br>
^ myself! !<br>
<br>
!FormatDescriptor class methodsFor: 'instance creation'!<br>
scanFrom: stream<br>
| desc |<br>
desc := self new.<br>
[Flags includesKey: stream peek]<br>
whileTrue: [desc := desc perform: (Flags at: stream next)].<br>
stream peek isDigit ifTrue: [desc width: (Integer readFrom: stream)].<br>
stream peek == $. ifTrue: [stream next. desc precision: (Integer readFrom: stream)].<br>
stream peek == $l ifTrue: [stream next].<br>
desc := desc operator: stream next.<br>
^ desc! !<br>
<br>
FormatDescriptor subclass: #CharacterFormatDescriptor<br>
instanceVariableNames: ''<br>
classVariableNames: ''<br>
poolDictionaries: ''<br>
category: 'Printf'!<br>
<br>
!CharacterFormatDescriptor methodsFor: 'rendering'!<br>
applyOperator: object<br>
^ String with: object asCharacter! !<br>
<br>
<br>
!CharacterFormatDescriptor methodsFor: 'printing'!<br>
printOn: aStream<br>
super printOn: aStream.<br>
self printWidthOn: aStream.<br>
aStream nextPut: $c! !<br>
<br>
Object subclass: #FormatString<br>
instanceVariableNames: 'format string composedString'<br>
classVariableNames: ''<br>
poolDictionaries: ''<br>
category: 'Printf'!<br>
!FormatString commentStamp: 'mir 6/7/2000 00:14' prior: 0!<br>
Format description<br>
syntax: %{flags}{width}{precision}{long}<operator><br>
<br>
flags<br>
- left flush<br>
+ right flush<br>
space non-negative number are preceeded by a blank<br>
# display integer with a radix indicator (0=octal, 0x=hex, float have .)<br>
0 0 is used as left padding character for numbers<br>
width minimum field width (rest is padded)<br>
.precision maximum field width or trailing digits<br>
long ignored<br>
operator<br>
c display object as character<br>
d display as integer<br>
e,E float in scientific notation<br>
f display as float<br>
g,G display as f or e,E using least amount of space<br>
o display as octal value<br>
s display as string<br>
u display as unsigned<br>
x,X display as hex value<br>
!<br>
<br>
<br>
!FormatString methodsFor: 'printf'!<br>
<< object<br>
"Render object according to next format descriptor in format.<br>
Append it to string"<br>
"Format description<br>
syntax: %{flags}{width}{precision}{long}<operator><br>
<br>
flags<br>
- left flush<br>
+ right flush<br>
space non-negative number are preceeded by a blank<br>
# display integer with a radix indicator (0=octal, 0x=hex, float have .)<br>
0 0 is used as left padding character for numbers<br>
width minimum field width (rest is padded)<br>
.precision maximum field width or trailing digits<br>
long ignored<br>
operator<br>
c display object as character<br>
d display as integer<br>
e,E float in scientific notation<br>
f display as float<br>
g,G display as f or e,E using least amount of space<br>
o display as octal value<br>
s display as string<br>
u display as unsigned<br>
x,X display as hex value<br>
"<br>
<br>
composedString nextPutAll: string next.<br>
composedString nextPutAll: (format next render: object).<br>
format atEnd<br>
ifTrue:<br>
[format reset.<br>
composedString nextPutAll: string next.<br>
string reset].<br>
^composedString contents! !<br>
<br>
!FormatString methodsFor: 'printf' stamp: 'hjo 9/17/2011 23:59'!<br>
printf: arguments<br>
<br>
"inst var string holds all text contained in the formatstring. %f blabla %d"<br>
"inst var format is a stream of FormatDescriptors"<br>
<br>
self reset.<br>
arguments asArgumentArrayForFormatString do:<br>
[:object |<br>
"put any text from the formatstring into composedstring"<br>
composedString nextPutAll: string next.<br>
"get next FormatDescriptor from format and render object as specified"<br>
format atEnd ifFalse: [composedString nextPutAll: (format next render: object)]].<br>
"any remainder is string, if so append to composedString"<br>
string atEnd ifFalse: [composedString nextPutAll: string next].<br>
^self stringWithReset.! !<br>
<br>
!FormatString methodsFor: 'printf'!<br>
string<br>
^composedString contents! !<br>
<br>
!FormatString methodsFor: 'printf' stamp: 'hjo 9/17/2011 23:59'!<br>
stringWithReset<br>
<br>
| result |<br>
result := self string.<br>
self reset.<br>
^result! !<br>
<br>
<br>
!FormatString methodsFor: 'initialize-release' stamp: 'hjo 9/18/2011 00:05'!<br>
collectFormatDescriptorsAndStrings: formatStream<br>
<br>
| done |<br>
format := ReadWriteStream on: (Array new: 10).<br>
string := ReadWriteStream on: (Array new: 10).<br>
done := false.<br>
[ done ]<br>
whileFalse: [<br>
"copy actual formatstrings to format"<br>
string nextPut: (self scanStringFrom: formatStream).<br>
(done := formatStream atEnd)<br>
ifFalse: [<br>
"copy any nonformating text to string"<br>
format nextPut: (FormatDescriptor scanFrom: formatStream) ] ].<br>
self reset! !<br>
<br>
!FormatString methodsFor: 'initialize-release' stamp: 'hjo 9/18/2011 00:05'!<br>
setFormat: aString<br>
| formatStream |<br>
"copy actual formatstrings to format"<br>
"copy any nonformating text to string"<br>
composedString := (String new: 20) writeStream.<br>
formatStream := ((aString copyReplaceAll: '\n' with: (String with: Character cr))<br>
copyReplaceAll: '\t'<br>
with: (String with: Character tab)) readStream.<br>
self collectFormatDescriptorsAndStrings: formatStream! !<br>
<br>
<br>
!FormatString methodsFor: 'private'!<br>
reset<br>
format reset.<br>
string reset.<br>
composedString reset! !<br>
<br>
!FormatString methodsFor: 'private' stamp: 'hjo 9/18/2011 00:00'!<br>
scanStringFrom: aStream<br>
| newString |<br>
newString := (String new: 40) writeStream.<br>
[aStream atEnd]<br>
whileFalse:<br>
[| next |<br>
next := aStream next.<br>
next == $% ifTrue: [^newString contents].<br>
next == $\<br>
ifTrue:<br>
[next := aStream next.<br>
next == $n ifTrue: [next := Character cr].<br>
next == $t ifTrue: [next := Character tab]].<br>
newString nextPut: next].<br>
^newString contents! !<br>
<br>
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!<br>
<br>
FormatString class<br>
instanceVariableNames: ''!<br>
<br>
!FormatString class methodsFor: 'examples' stamp: 'mir 6/7/2000 00:12'!<br>
examples<br>
self inform: ('Here is a string "%s".' printf: 'hello world').<br>
self inform: ('Here is a string "%s" and another shortened "%-14.7s".'<br>
printf: #('hello world' 'hello world')).<br>
<br>
self inform: ('Here is a number "%d".' printf: 42).<br>
self inform: ('Here is a string "%07.7d".' printf: 42).<br>
<br>
self inform: ('Here is a number "%e".' printf: 42.0).<br>
self inform: ('Here is a float "%e" and an integer "%d".' printf: #(42.0 42)).<br>
self inform: ('Here is a string "%013.5e".' printf: 42.1234567).<br>
<br>
self inform: ('Here is a %s string "%s" and the same shortened "%-14.7s" with left flush.\nThe new line has a number "%e" and a 0-padded limited precision one "%013.5e".'<br>
printf: ((Array with: 'long' with: 'hello world' with: 'hello world' with: 42.0) copyWith: 42.1234567)).! !<br>
<br>
TestCase subclass: #FormatStringTest<br>
instanceVariableNames: ''<br>
classVariableNames: ''<br>
poolDictionaries: ''<br>
category: 'Printf'!<br>
<br>
!FormatStringTest methodsFor: 'as yet unclassified' stamp: 'hjo 9/17/2011 23:41'!<br>
testManyArguments<br>
<br>
self assert: 'Here is a long string "hello world" and the same shortened "hello w " with left flush.<br>
The new line has a number "42.0" and a 0-padded limited precision one "0000042.12345".' equals: ('Here is a %s string "%s" and the same shortened "%-14.7s" with left flush.\nThe new line has a number "%e" and a 0-padded limited precision one "%013.5e".'<br>
printf: ((Array with: 'long' with: 'hello world' with: 'hello world' with: 42.0) copyWith: 42.1234567)).! !<br>
<br>
!FormatStringTest methodsFor: 'as yet unclassified' stamp: 'hjo 9/17/2011 23:41'!<br>
testOneExponent<br>
<br>
self assert: 'Here is a number "42.0".' equals: ('Here is a number "%e".' printf: 42.0).! !<br>
<br>
!FormatStringTest methodsFor: 'as yet unclassified' stamp: 'hjo 9/17/2011 23:41'!<br>
testOneExponentAndOneInteger<br>
<br>
self assert: 'Here is a float "42.0" and an integer "42".' equals: ('Here is a float "%e" and an integer "%d".' printf: #(42.0 42)).! !<br>
<br>
!FormatStringTest methodsFor: 'as yet unclassified' stamp: 'hjo 9/17/2011 23:41'!<br>
testOneExponentWithLength<br>
<br>
self assert: 'Here is a string "0000042.12345".' equals: ('Here is a string "%013.5e".' printf: 42.1234567).! !<br>
<br>
!FormatStringTest methodsFor: 'as yet unclassified' stamp: 'hjo 9/17/2011 23:40'!<br>
testOneInteger<br>
<br>
self assert: 'Here is a number "42".' equals: ('Here is a number "%d".' printf: 42).! !<br>
<br>
!FormatStringTest methodsFor: 'as yet unclassified' stamp: 'hjo 9/17/2011 23:40'!<br>
testOneIntegerWithLength<br>
<br>
self assert: 'Here is a string "0000042".' equals: ('Here is a string "%07.7d".' printf: 42).! !<br>
<br>
!FormatStringTest methodsFor: 'as yet unclassified' stamp: 'hjo 9/17/2011 23:40'!<br>
testOneString<br>
<br>
self assert: 'Here is a string "hello world".' equals: ('Here is a string "%s".' printf: 'hello world')! !<br>
<br>
!FormatStringTest methodsFor: 'as yet unclassified' stamp: 'hjo 9/17/2011 23:40'!<br>
testOneStringWithLength<br>
<br>
self assert: 'Here is a string "hello world" and another shortened "hello w ".' equals: ('Here is a string "%s" and another shortened "%-14.7s".' printf: #('hello world' 'hello world'))! !<br>
<br>
FormatDescriptor subclass: #NumberFormatDescriptor<br>
instanceVariableNames: 'operator padding radix space'<br>
classVariableNames: 'Base Radix'<br>
poolDictionaries: ''<br>
category: 'Printf'!<br>
<br>
!NumberFormatDescriptor methodsFor: 'rendering' stamp: 'mir 6/6/2000 23:56'!<br>
applyOperator: object<br>
"Character and Number are the only valid classes"<br>
<br>
| number string |<br>
object isNil ifTrue: [^'-'].<br>
"object isInteger ifFalse: [self halt].<br>
" number := object asInteger.<br>
string := number printStringBase: self base.<br>
radix ifTrue: [string := self radixString , string].<br>
(space and: [operator == $d and: [number < 0]])<br>
ifTrue: [string := ' ' , string].<br>
^ (width ~= 0 and: [string size > self stringLength])<br>
ifTrue: [String new: width withAll: $*]<br>
ifFalse: [string]! !<br>
<br>
<br>
!NumberFormatDescriptor methodsFor: 'private'!<br>
base<br>
^ Base at: operator! !<br>
<br>
!NumberFormatDescriptor methodsFor: 'private'!<br>
padding<br>
^ padding! !<br>
<br>
!NumberFormatDescriptor methodsFor: 'private'!<br>
radixString<br>
^ Radix at: operator! !<br>
<br>
!NumberFormatDescriptor methodsFor: 'private'!<br>
setOperator: char<br>
operator := char! !<br>
<br>
!NumberFormatDescriptor methodsFor: 'private'!<br>
setPadding: paddingChar<br>
padding := paddingChar! !<br>
<br>
!NumberFormatDescriptor methodsFor: 'private'!<br>
stringLength<br>
^precision isNil<br>
ifTrue: [SmallInteger maxVal]<br>
ifFalse: [precision]! !<br>
<br>
<br>
!NumberFormatDescriptor methodsFor: 'initialize-release'!<br>
initialize<br>
super initialize.<br>
padding := $ .<br>
radix := false.<br>
space := false! !<br>
<br>
<br>
!NumberFormatDescriptor methodsFor: 'printing'!<br>
printOn: aStream<br>
super printOn: aStream.<br>
padding == $0 ifTrue: [aStream nextPut: $0].<br>
radix ifTrue: [aStream nextPut: $#].<br>
space ifTrue: [aStream nextPut: $ ].<br>
self printWidthOn: aStream.<br>
aStream nextPut: operator! !<br>
<br>
<br>
!NumberFormatDescriptor methodsFor: 'scanning'!<br>
radix<br>
radix := true! !<br>
<br>
!NumberFormatDescriptor methodsFor: 'scanning'!<br>
space<br>
space := true! !<br>
<br>
!NumberFormatDescriptor methodsFor: 'scanning'!<br>
zero<br>
padding := $0! !<br>
<br>
"-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!<br>
<br>
NumberFormatDescriptor class<br>
instanceVariableNames: ''!<br>
<br>
!NumberFormatDescriptor class methodsFor: 'class initialization'!<br>
initialize<br>
"NumberFormatDescriptor initialize"<br>
Base := Dictionary new.<br>
Base at: $d put: 10.<br>
Base at: $o put: 8.<br>
Base at: $u put: 10.<br>
Base at: $x put: 16.<br>
Base at: $X put: 16.<br>
<br>
Radix := Dictionary new.<br>
Radix at: $d put: ''.<br>
Radix at: $o put: '0'.<br>
Radix at: $u put: ''.<br>
Radix at: $x put: '0x'.<br>
Radix at: $X put: '0X'.! !<br>
<br>
<br>
!NumberFormatDescriptor class methodsFor: 'instance creation'!<br>
newFrom: desc<br>
desc class == self ifTrue: [^ desc].<br>
^ (super newFrom: desc) setPadding: desc padding! !<br>
<br>
NumberFormatDescriptor subclass: #FloatFormatDescriptor<br>
instanceVariableNames: ''<br>
classVariableNames: ''<br>
poolDictionaries: ''<br>
category: 'Printf'!<br>
<br>
!FloatFormatDescriptor methodsFor: 'rendering' stamp: 'hjo 9/18/2011 00:47'!<br>
applyOperator: object<br>
"Number is the only valid class"<br>
<br>
| string |<br>
string := self zeroPaddedStringOfBase10ForFloat: object asFloat.<br>
string := string copyFrom: 1 to: ((string indexOf: $.) + (precision == 0<br>
ifTrue: [-1]<br>
ifFalse: [self precision]) min: string size).<br>
(space and: [object asFloat >= 0])<br>
ifTrue: [string := ' ' , string].<br>
^(width ~= 0 and: [string size > width])<br>
ifTrue: [String new: width withAll: $*]<br>
ifFalse: [string]! !<br>
<br>
!FloatFormatDescriptor methodsFor: 'rendering' stamp: 'hjo 9/18/2011 00:45'!<br>
zeroPaddedStringOfBase10ForFloat: aFloat<br>
<br>
| stream |<br>
stream := String new writeStream.<br>
aFloat printOn: stream base: 10.<br>
stream next: self precision-1 put: $0.<br>
^stream contents.<br>
! !<br>
<br>
<br>
!FloatFormatDescriptor methodsFor: 'private' stamp: 'mir 6/7/2000 00:01'!<br>
digits<br>
^ width == 0 ifTrue: [7] ifFalse: [width]! !<br>
<br>
!FloatFormatDescriptor methodsFor: 'private'!<br>
precision<br>
^ precision isNil ifTrue: [1] ifFalse: [precision]! !<br>
<br>
!FloatFormatDescriptor methodsFor: 'private'!<br>
stringLength<br>
^ width! !<br>
<br>
FormatDescriptor subclass: #StringFormatDescriptor<br>
instanceVariableNames: ''<br>
classVariableNames: ''<br>
poolDictionaries: ''<br>
category: 'Printf'!<br>
<br>
!StringFormatDescriptor methodsFor: 'rendering'!<br>
applyOperator: object<br>
^ object! !<br>
<br>
<br>
!StringFormatDescriptor methodsFor: 'printing'!<br>
printOn: aStream<br>
super printOn: aStream.<br>
self printWidthOn: aStream.<br>
aStream nextPut: $s! !<br>
<br>
StringFormatDescriptor subclass: #PrintStringFormatDescriptor<br>
instanceVariableNames: ''<br>
classVariableNames: ''<br>
poolDictionaries: ''<br>
category: 'Printf'!<br>
<br>
!PrintStringFormatDescriptor methodsFor: 'rendering'!<br>
applyOperator: object<br>
^ object printLeanString! !<br>
<br>
<br>
!PrintStringFormatDescriptor methodsFor: 'printing'!<br>
printOn: aStream<br>
aStream nextPut: $%.<br>
flush == #leftFlush ifTrue: [aStream nextPut: $-].<br>
self printWidthOn: aStream.<br>
aStream nextPut: $p! !<br>
<br>
FormatDescriptor initialize!<br>
NumberFormatDescriptor initialize!<br>
</blockquote></div><br></div>