SDSU CS 683 Emerging Technologies: Embracing Change
Spring Semester, 2001
Assignment 2 & 3 Comments
Previous    Lecture Notes Index    Next    
© 2001, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 27-Mar-01

Contents of Doc 16, Assignment 2 & 3 Comments


References

Smalltalk Best Practice Patterns, Kent Beck, Prentice Hall, 1997

Student papers


Doc 16, Assignment 2 & 3 Comments Slide # 2

Assignment 2 & 3 Comments

Testing and Readability


Which is easier to read?
Which shows the best shows the intent?

TestCase subclass: #StringTests

StringTests>>testPalidrome
   | result |
   result := 'mom' isPalidrome.
   self assert: result = true

StringTests>>testPalidrome
   | result |
   result := 'mom' isPalidrome.
   self assert: result

StringTests>>testPalidrome
   self assert: 'mom' isPalidrome


Doc 16, Assignment 2 & 3 Comments Slide # 3
Booleans, If statements, Readability

boolean result;
result = someMethod();
if (result = true )
   blah
else
   more blah

or

boolean result;
result = someMethod();
if (result)
   blah
else
   more blah

Style texts recommend the latter

Doc 16, Assignment 2 & 3 Comments Slide # 4
deny

StringTests>>testPalidrome
   | result |
   result := 'cat' isPalidrome.
   self assert: result = false

StringTests>>testPalidrome
   self deny: 'cat' isPalidrome.


Doc 16, Assignment 2 & 3 Comments Slide # 5

Assignment 3 Solution

Problem 1


String>>evaluate
   | result |
   result := Compiler evaluate: self.
   ^result isNil
      ifTrue:['']
      ifFalse:[result]

FileStream>>evaluate
   ^self contentsOfEntireFile evaluate

Problem 2


evaluateASP
   | result |
   result := WriteStream on: (String new).
   [self atEnd]
      whileFalse:
         [result
            nextPutAll: (self upToAll: '<%');
            nextPutAll: (self upToAll: '%>') evaluate stringRepresentation].
   self close.
   ^result contents


Doc 16, Assignment 2 & 3 Comments Slide # 6

Problem 3


Object subclass: #SampleWebApplication
   instanceVariableNames: ''
   classVariableNames: ''
   poolDictionaries: ''
   category: 'Whitney-ASP'

Class Methods
aspDirectory
   ^'Other/asp' 
         copyReplaceAll: '/'
         with: FileDirectory slash

startServerAction: aString port: anInteger
   PWS stopServer.
   PWS 
      link: aString
      to: SampleWebApplication new.
   PWS
      serveOnPort: anInteger
      loggingTo: 'log'.

Instance Methods

aspAt: aFileURL
   |  aspFile |
   aspFile := FileStream fileNamed: (self fullPathFor: aFileURL ).
   ^aspFile evaluateASP


Doc 16, Assignment 2 & 3 Comments Slide # 7

fullPathFor: aFileURL
   | partialPath |
   partialPath := aFileURL 
               copyReplaceAll: '/'
               with: FileDirectory slash.
   ^self class aspDirectory , partialPath

isFile: aFileURL
   ^FileStream isAFileNamed: (self fullPathFor: aFileURL)

process: aRequest
   (self isFile: aRequest url)
      ifTrue:[self processSuccess: aRequest]
      ifFalse:[self processFileNotFound: aRequest]

processFileNotFound: aRequest
   aRequest 
      reply: PWS notFound;
      reply: PWS contentHTML, PWS crlf;
      reply: ('File: ',  aRequest url , ' not found')

processSuccess: aRequest
   aRequest 
      reply: PWS success;
      reply: PWS contentHTML, PWS crlf;
      reply: (self aspAt: aRequest url)


Doc 16, Assignment 2 & 3 Comments Slide # 8

Assignment 3 Tests


TestCase subclass: #ASPTests
   instanceVariableNames: ''
   classVariableNames: ''
   poolDictionaries: ''
   category: 'Whitney-ASP'!

Private instance methods

createFile: aLocalFileName contents: aString
   | file |
   file := FileStream fileNamed: aLocalFileName.
   file nextPutAll: aString.
   file close

deleteFile: aFilePath
   FileDirectory deleteFilePath: aFilePath

simpleAsp
   ^'<HTML><BODY>hi <% 1 + 2 %></BODY></HTML>'

startServerAction: aString port: anInteger
   SampleWebApplication
      startServerAction: aString 
      port: anInteger

stopServer
   PWS stopServer


Doc 16, Assignment 2 & 3 Comments Slide # 9
Test Instance Methods

testASPFileEvaluate
   | asp result |
   self 
      createFile: 'testAsp' 
      contents: self simpleAsp.
   asp := FileStream fileNamed: 'testAsp'.
   result := asp evaluateASP.
   self assert: result = '<HTML><BODY>hi 3</BODY></HTML>'.
   self deleteFile: 'testAsp'

testStringEvaluate
   self 
      assert: '1 + 1' evaluate = 2;
      assert: '  ' evaluate isEmpty

testWebApplications
   | result |
   self startServerAction: 'test' port: 8080.
   self 
      createFile: SampleWebApplication aspDirectory , ':test:sample.asp' 
      contents: self simpleAsp.
   result := (HTTPSocket httpGet: '127.0.0.1:8080/test/sample.asp') contents. 
   self assert: result = '<HTML><BODY>hi 3</BODY></HTML>'.
   self deleteFile: SampleWebApplication aspDirectory , ':test:sample.asp'.

testWebApplicationsBadFile
   | result |
   self startServerAction: 'test' port: 8080.
   result := (HTTPSocket httpGet: '127.0.0.1:8080/test/crap.asp') contents. 
   self assert: (result includesSubString: 'not found').


Doc 16, Assignment 2 & 3 Comments Slide # 10

Formatting

Spaces & Tabs


The following is:

at: anInteger put: anObject
(smallKey ~= largeKey)
ifTrue:
[(anInteger < smallKey)    
ifTrue: [self atLeftTree: anInteger put: anObject]
ifFalse: [(smallKey = anInteger)
ifTrue: [smallValue := anObject]
ifFalse: [(anInteger < largeKey)
ifTrue: [self atMiddleTree: anInteger put: anObject]
ifFalse: [(largeKey = anInteger)
ifTrue: [largeValue := anObject]
ifFalse: [(largeKey < anInteger)
ifTrue: [self atRightTree: anInteger put: anObject]]]]]]
ifFalse:
[self addNewKey: anInteger with: anObject].

Squeak uses tabs to indent lines

Do not use spaces at the beginning of a line to indent!

Doc 16, Assignment 2 & 3 Comments Slide # 11

Line Wrap


Don't ever do this to anyone under any circumstance

Find the problem and fix it

I will no longer grade papers with line wrap

at: anInteger put: anObject
   (smallKey ~= largeKey)
      ifTrue:
         [(anInteger < smallKey)    
            ifTrue: [self atLeftTree: anInteger put:
 anObject]
            ifFalse: [(smallKey = anInteger)
               ifTrue: [smallValue := anObject]
               ifFalse: [(anInteger < largeKey)
                  ifTrue: [self atMiddleTree:
 anInteger put: anObject]
                  ifFalse: [(largeKey = anInteger)
                     ifTrue: [largeValue := 
anObject]
                     ifFalse: [(largeKey < 
anInteger)
                        ifTrue: [self atRightTree: 
anInteger put: anObject]]]]]]
      ifFalse:
         [self addNewKey: anInteger with: 
anObject].


Doc 16, Assignment 2 & 3 Comments Slide # 12

Formatting Patterns

Indented Control Flow[1]


How do you indent messages?



Examples

2 + 3
a < b ifTrue: [code ]
   
a < b
   ifTrue: [ code ]
   ifFalse: [ more code]
   
tree
   at: 5
   put: 'cat'


Doc 16, Assignment 2 & 3 Comments Slide # 13

Rectangular Block[2]


Make blocks rectangular

Use the square brackets as the upper left and bottom right corners of the rectangle

If the block contains a simple statement, the block can stay on one line

If the block contains a compound statement bring the block onto its own line and indent

angle isNil ifTrue: [self computeAngle]
   
self isDegrees ifTrue: [^angle * 90 + 270 degreesToRadians]
   
   
self isDirty 
   ifTrue: 
      [self clearCaches.
      self recomputeAngles]
   
self isNil
   ifTrue:
      [self
         at: each
         put: 0]


Doc 16, Assignment 2 & 3 Comments Slide # 14

Guard Clause[3]


How do you format code that should not execute if a condition holds?

connect
   self isConnected
      ifFalse: [self connectConnection]


Format the one-branch conditional with an explicit return

connect
   self isConnected ifTrue: [^self]
   self connectConnection


Doc 16, Assignment 2 & 3 Comments Slide # 15

Cascade[4]


How do you format multiple messages to the same receiver?

Use a cascade

Put each message on its own line and indent one tab

Only use cascades for messages with zero or one arguments

OrderedCollection new
   add: 5;
   add: 10


Doc 16, Assignment 2 & 3 Comments Slide # 16

Accessors


Smalltalk convention does not use getX setX for naming accessor methods



Doc 16, Assignment 2 & 3 Comments Slide # 17
[1] Beck 1997 pp. 175-177
[2] Beck 1997 pp. 177-178
[3] Beck 1997 pp. 178-179
[4] Beck 1997 pp. 183-185

Copyright ©, All rights reserved.
2001 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.

Previous    visitors since 27-Mar-01    Next