SystemOrganization addCategory: #'TextLint-Model'! SystemOrganization addCategory: #'TextLint-Model-Parser'! SystemOrganization addCategory: #'TextLint-Model-Rules'! SystemOrganization addCategory: #'TextLint-Model-Runner'! PPCompositeParser subclass: #TLCachedParser instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Parser'! TLCachedParser class instanceVariableNames: 'instance'! TLCachedParser class instanceVariableNames: 'instance'! !TLCachedParser class methodsFor: 'private' stamp: 'lr 5/4/2011 23:32'! compile: aTextString classified: aCategorySymbol withStamp: aStampString notifying: aRequestor logSource: aBoolean self flush. ^ super compile: aTextString classified: aCategorySymbol withStamp: aStampString notifying: aRequestor logSource: aBoolean! ! !TLCachedParser class methodsFor: 'private' stamp: 'lr 5/4/2011 23:29'! flush self subclasses do: [ :each | each flush ]. instance := nil! ! !TLCachedParser class methodsFor: 'instance creation' stamp: 'lr 5/4/2011 23:29'! newStartingAt: aSymbol ^ instance ifNil: [ instance := super newStartingAt: aSymbol ]! ! TLCachedParser subclass: #TLDocumentPhraser instanceVariableNames: 'document documentTerminator paragraph paragraphTerminator sentence sentenceTerminator' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Parser'! !TLDocumentPhraser methodsFor: 'grammar' stamp: 'lr 11/3/2010 16:28'! document ^ (paragraph starLazy: documentTerminator) , (documentTerminator optional)! ! !TLDocumentPhraser methodsFor: 'grammar' stamp: 'JorgeRessia 6/12/2010 12:19'! documentTerminator ^ PPPredicateObjectParser on: [ :token | token isEndOfDocument ] message: 'End of document expected'! ! !TLDocumentPhraser methodsFor: 'grammar' stamp: 'lr 11/3/2010 16:28'! paragraph ^ (sentence starLazy: paragraphTerminator / documentTerminator) , (paragraphTerminator optional) ! ! !TLDocumentPhraser methodsFor: 'grammar' stamp: 'JorgeRessia 6/12/2010 12:20'! paragraphTerminator ^ PPPredicateObjectParser on: [ :token | token isWhitespace and: [ token isEndOfParagraph ] ] message: 'End of paragraph expected'! ! !TLDocumentPhraser methodsFor: 'grammar' stamp: 'lr 11/3/2010 16:29'! sentence ^ (#any asParser starLazy: sentenceTerminator / paragraphTerminator / documentTerminator) , (sentenceTerminator optional)! ! !TLDocumentPhraser methodsFor: 'grammar' stamp: 'JorgeRessia 6/12/2010 12:20'! sentenceTerminator ^ PPPredicateObjectParser on: [ :token | token isPunctuation and: [ token isEndOfSentence ] ] message: 'End of sentence expected'! ! !TLDocumentPhraser methodsFor: 'accessing' stamp: 'lr 4/6/2010 21:43'! start ^ document end! ! TLDocumentPhraser subclass: #TLTextPhraser instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Parser'! !TLTextPhraser methodsFor: 'accessing' stamp: 'lr 11/3/2010 16:28'! document ^ super document ==> [ :nodes | TLDocument withAll: nodes first ]! ! !TLTextPhraser methodsFor: 'accessing' stamp: 'lr 11/3/2010 16:28'! paragraph ^ super paragraph ==> [ :nodes | TLParagraph withAll: (nodes last isNil ifFalse: [ nodes first copyWith: nodes last ] ifTrue: [ nodes first ]) ]! ! !TLTextPhraser methodsFor: 'accessing' stamp: 'lr 11/3/2010 16:29'! sentence ^ super sentence ==> [ :nodes | TLSentence withAll: (nodes last isNil ifFalse: [ nodes first copyWith: nodes last ] ifTrue: [ nodes first ]) ]! ! TLCachedParser subclass: #TLTextTokenizer instanceVariableNames: 'elementList element markup word whitespace punctuation punctuationGroups unknown punctuationCharacters' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Parser'! TLTextTokenizer subclass: #TLPatternTokenizer instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Parser'! !TLPatternTokenizer methodsFor: 'grammar' stamp: 'lr 9/5/2011 18:36'! elementList "We need at least one term, otherwise we would match anything." ^ element plus foldLeft: [ :a :b | a , b ]! ! !TLPatternTokenizer methodsFor: 'token' stamp: 'lr 9/5/2011 18:45'! markup ^ ${ asParser , #word asParser plus token , $} asParser map: [ :open :token :close | | type | type := token value asSymbol. (TLWordClassifier types includes: type) ifFalse: [ PPFailure message: 'Invalid word type: ' , token value at: token start ] ifTrue: [ PPPredicateObjectParser on: [ :each | each isWord and: [ each classification includes: type ] ] message: token value , ' expected' ] ]! ! !TLPatternTokenizer methodsFor: 'token' stamp: 'lr 9/5/2011 18:26'! punctuation ^ super punctuation ==> [ :token | PPPredicateObjectParser on: [ :each | each isPunctuation and: [ each text = token value ] ] message: token value printString , ' expected' ]! ! !TLPatternTokenizer methodsFor: 'token' stamp: 'lr 9/5/2011 18:53'! punctuationCharacters "Remove the open and close curly-braces." ^ PPPredicateObjectParser chars: '''"[]():,-!!.?;/&@' message: 'Punctuation expected'! ! !TLPatternTokenizer methodsFor: 'accessing' stamp: 'lr 9/5/2011 18:36'! start ^ super start ==> [ :node | node flatten ]! ! !TLPatternTokenizer methodsFor: 'token' stamp: 'lr 9/5/2011 18:28'! unknown ^ PPFailingParser message: 'Invalid query character'! ! !TLPatternTokenizer methodsFor: 'token' stamp: 'lr 11/30/2010 19:38'! whitespace ^ super whitespace ==> [ :token | (PPPredicateObjectParser on: [ :each | each isWhitespace or: [ each isMarkup ] ] message: 'whitespace expected') star ]! ! !TLPatternTokenizer methodsFor: 'token' stamp: 'lr 11/3/2010 16:36'! word ^ super word ==> [ :token | PPPredicateObjectParser on: [ :each | each isWord and: [ each text sameAs: token value ] ] message: token value printString , ' expected' ]! ! TLTextTokenizer subclass: #TLPlainTokenizer instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Parser'! TLPlainTokenizer subclass: #TLHtmlTokenizer instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Parser'! !TLHtmlTokenizer methodsFor: 'tokens' stamp: 'lr 5/31/2010 07:38'! markup ^ (($< asParser , $> asParser negate plus , $> asParser) / ($& asParser , $; asParser negate plus , $; asParser)) token ==> [ :token | TLMarkup with: token ]! ! TLPlainTokenizer subclass: #TLLatexTokenizer instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Parser'! !TLLatexTokenizer methodsFor: 'private' stamp: 'lr 5/31/2010 07:36'! consumeCommand: aStream | counter char | ('{[' includes: aStream peek) ifFalse: [ ^ self ]. counter := 0. [ char := aStream next. (char = ${ or: [ char = $[ ]) ifTrue: [ counter := counter + 1 ] ifFalse: [ (char = $} or: [ char = $] ]) ifTrue: [ counter := counter - 1 ] ]. aStream atEnd or: [ counter = 0 ] ] whileFalse. self consumeCommand: aStream! ! !TLLatexTokenizer methodsFor: 'private' stamp: 'lr 5/31/2010 07:35'! consumeEnvironment: aStream aStream upToAll: '\end{' , (aStream upTo: $}) , '}'! ! !TLLatexTokenizer methodsFor: 'configuration' stamp: 'lr 9/30/2010 08:27'! ignoredCommands ^ #('newcommand' 'renewcommand' 'newenviornment' 'lstset' 'index') asSet asParser! ! !TLLatexTokenizer methodsFor: 'configuration' stamp: 'lr 5/31/2010 07:34'! ignoredEnvironments ^ #('lstlisting' 'figure' 'table') asSet asParser! ! !TLLatexTokenizer methodsFor: 'tokens' stamp: 'JorgeRessia 6/12/2010 12:18'! markup ^ ((PPPredicateObjectParser anyOf: '{}[]`-') / ('\begin{' asParser , self ignoredEnvironments and , [ :stream | self consumeEnvironment: stream ] asParser) / ($\ asParser , self ignoredCommands , [ :stream | self consumeCommand: stream ] asParser) / ($\ asParser , #any asParser , #word asParser star) / ($% asParser , #newline asParser negate star)) token ==> [ :token | TLMarkup with: token ]! ! !TLLatexTokenizer methodsFor: 'tokens' stamp: 'lr 9/5/2011 18:35'! punctuationGroups ^ super punctuationGroups / '``' asParser / '''''' asParser / '---' asParser / '--' asParser! ! !TLPlainTokenizer methodsFor: 'accessing' stamp: 'lr 11/3/2010 16:31'! elementList ^ super elementList ==> [ :nodes | nodes copyWith: (TLTerminatorMark with: '') ]! ! !TLPlainTokenizer methodsFor: 'accessing' stamp: 'lr 11/3/2010 16:32'! punctuation ^ super punctuation ==> [ :node | TLPunctuationMark with: node ]! ! !TLPlainTokenizer methodsFor: 'accessing' stamp: 'lr 9/5/2011 18:34'! unknown ^ super unknown ==> [ :token | TLMarkup with: token ]! ! !TLPlainTokenizer methodsFor: 'accessing' stamp: 'lr 11/3/2010 16:33'! whitespace ^ super whitespace ==> [ :node | TLWhitespace with: node ]! ! !TLPlainTokenizer methodsFor: 'accessing' stamp: 'lr 11/3/2010 16:32'! word ^ super word ==> [ :node | TLWord with: node ]! ! !TLTextTokenizer methodsFor: 'grammar' stamp: 'lr 9/5/2011 18:20'! element ^ markup / word / whitespace / punctuation / unknown! ! !TLTextTokenizer methodsFor: 'grammar' stamp: 'lr 11/3/2010 16:31'! elementList ^ element star! ! !TLTextTokenizer methodsFor: 'tokens' stamp: 'lr 5/27/2010 16:27'! markup ^ PPFailingParser message: 'Markup expected'! ! !TLTextTokenizer methodsFor: 'tokens' stamp: 'lr 9/5/2011 18:21'! punctuation ^ (punctuationGroups / punctuationCharacters) token! ! !TLTextTokenizer methodsFor: 'tokens' stamp: 'lr 9/5/2011 18:24'! punctuationCharacters ^ PPPredicateObjectParser chars: '''"[](){}:,-!!.?;/&@' message: 'Punctuation expected'! ! !TLTextTokenizer methodsFor: 'tokens' stamp: 'lr 5/28/2010 11:59'! punctuationGroups ^ '...' asParser! ! !TLTextTokenizer methodsFor: 'accessing' stamp: 'lr 9/5/2011 18:31'! start ^ elementList end! ! !TLTextTokenizer methodsFor: 'tokens' stamp: 'lr 9/5/2011 18:34'! unknown ^ #any asParser token! ! !TLTextTokenizer methodsFor: 'tokens' stamp: 'lr 11/3/2010 16:32'! whitespace ^ #space asParser plus token! ! !TLTextTokenizer methodsFor: 'tokens' stamp: 'lr 11/3/2010 16:32'! word ^ #word asParser plus token! ! Object subclass: #TLElement instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model'! TLElement subclass: #TLDocument instanceVariableNames: 'paragraphs' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model'! !TLDocument class methodsFor: 'instance creation' stamp: 'lr 3/31/2010 11:15'! withAll: aCollection ^self new initializeWithAll: aCollection! ! !TLDocument methodsFor: 'accessing' stamp: 'JorgeRessia 5/26/2010 09:27'! allElements ^OrderedCollection new add: self; addAll: paragraphs; addAll: self sentences; addAll: self words; yourself.! ! !TLDocument methodsFor: 'checking' stamp: 'JorgeRessia 5/26/2010 10:12'! checkWith: aTextLintChecker ^aTextLintChecker checkDocument: self! ! !TLDocument methodsFor: 'accessing' stamp: 'lr 4/6/2010 21:15'! children ^ paragraphs! ! !TLDocument methodsFor: 'initialization' stamp: 'lr 3/31/2010 11:16'! initializeWithAll: aCollection paragraphs := aCollection! ! !TLDocument methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 12:11'! isDocument ^ true! ! !TLDocument methodsFor: 'accessing' stamp: 'lr 3/31/2010 11:22'! paragraphs ^paragraphs ! ! !TLDocument methodsFor: 'visiting' stamp: 'JorgeRessia 6/16/2010 15:30'! processFor: aVisitor ^ aVisitor processDocument: self! ! !TLDocument methodsFor: 'accessing' stamp: 'lr 3/31/2010 11:24'! sentences ^ self paragraphs gather: [ :each | each sentences ]! ! !TLDocument methodsFor: 'accessing' stamp: 'lr 3/31/2010 11:24'! words ^self sentences gather: [ :each | each words ]! ! !TLElement methodsFor: 'checking' stamp: 'lr 5/27/2010 16:25'! checkWith: aTextLintChecker self subclassResponsibility! ! !TLElement methodsFor: 'accessing' stamp: 'lr 4/6/2010 20:30'! children "Answer the children nodes." ^ #() ! ! !TLElement methodsFor: 'accessing' stamp: 'lr 4/9/2010 10:54'! interval "Answer the interval in the text in which the receiver is defined." ^ self start to: self stop! ! !TLElement methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 12:11'! isDocument ^ false! ! !TLElement methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 11:44'! isEndOfDocument ^ false! ! !TLElement methodsFor: 'testing' stamp: 'lr 5/27/2010 16:24'! isMarkup ^ false! ! !TLElement methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 12:11'! isParagraph ^ false! ! !TLElement methodsFor: 'testing' stamp: 'JorgeRessia 4/9/2010 14:06'! isPhrase ^ false! ! !TLElement methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 11:44'! isPunctuation ^ false! ! !TLElement methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 12:10'! isSentence ^ false! ! !TLElement methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 11:44'! isWhitespace ^ false! ! !TLElement methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 11:44'! isWord ^ false! ! !TLElement methodsFor: 'printing' stamp: 'JorgeRessia 4/8/2010 10:49'! printContentOn: aStream self children do: [ :each | aStream nextPutAll: each text ]! ! !TLElement methodsFor: 'printing' stamp: 'lr 4/8/2010 13:29'! printOn: aStream super printOn: aStream. aStream nextPutAll: ' ('. self printContentOn: aStream. aStream nextPut: $)! ! !TLElement methodsFor: 'accessing' stamp: 'lr 4/9/2010 10:56'! start "Answer the start position of the receiver." ^ self children isEmpty ifFalse: [ self children first start ] ifTrue: [ 1 ]! ! !TLElement methodsFor: 'accessing' stamp: 'lr 4/9/2010 11:02'! stop "Answer the end position of the receiver." ^ self children isEmpty ifFalse: [ self children last stop ] ifTrue: [ 0 ]! ! !TLElement methodsFor: 'accessing' stamp: 'lr 4/6/2010 22:09'! text ^ String streamContents: [ :stream | self printContentOn: stream ]! ! !TLElement methodsFor: 'accessing' stamp: 'lr 6/16/2010 08:18'! token "Answer the first token in the receiver or nil." ^ self children isEmpty ifFalse: [ self children first token ]! ! TLElement subclass: #TLParagraph instanceVariableNames: 'sentences' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model'! !TLParagraph class methodsFor: 'instance creation' stamp: 'JorgeRessia 4/7/2010 11:13'! withAll: aCollection ^self new initializeWithAll: aCollection! ! !TLParagraph methodsFor: 'checking' stamp: 'JorgeRessia 5/26/2010 10:20'! checkWith: aTextLintChecker ^aTextLintChecker checkParagraph: self! ! !TLParagraph methodsFor: 'accessing' stamp: 'lr 4/6/2010 21:15'! children ^ sentences! ! !TLParagraph methodsFor: 'initialization' stamp: 'lr 3/31/2010 11:17'! initializeWithAll: aCollection sentences := aCollection! ! !TLParagraph methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 12:11'! isParagraph ^ true! ! !TLParagraph methodsFor: 'visiting' stamp: 'JorgeRessia 6/16/2010 15:30'! processFor: aVisitor ^ aVisitor processParagraph: self! ! !TLParagraph methodsFor: 'accessing' stamp: 'JorgeRessia 4/7/2010 11:13'! sentences ^sentences reject: [:eachElement | eachElement isWhitespace]! ! !TLParagraph methodsFor: 'accessing' stamp: 'JorgeRessia 4/12/2010 10:48'! words ^self sentences gather: [ :each | each words ]! ! TLElement subclass: #TLPhrase instanceVariableNames: 'syntacticElements' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model'! !TLPhrase class methodsFor: 'instance creation' stamp: 'JorgeRessia 4/8/2010 14:52'! withAll: aCollection ^self new initializeWithAll: aCollection! ! !TLPhrase methodsFor: 'accessing' stamp: 'JorgeRessia 4/8/2010 14:57'! children ^ syntacticElements! ! !TLPhrase methodsFor: 'initialization' stamp: 'JorgeRessia 4/8/2010 14:56'! initializeWithAll: aCollection syntacticElements := aCollection! ! !TLPhrase methodsFor: 'testing' stamp: 'JorgeRessia 4/9/2010 14:06'! isPhrase ^ true! ! !TLPhrase methodsFor: 'accessing' stamp: 'JorgeRessia 9/3/2010 10:04'! phraseWithoutMarkups ^ TLPhrase withAll: (syntacticElements select: [:eachToken | eachToken isMarkup not ])! ! !TLPhrase methodsFor: 'visiting' stamp: 'JorgeRessia 6/16/2010 15:31'! processFor: aVisitor ^ aVisitor processPhrase: self! ! !TLPhrase methodsFor: 'accessing' stamp: 'JorgeRessia 9/23/2010 22:02'! size ^self words size! ! !TLPhrase methodsFor: 'accessing' stamp: 'JorgeRessia 4/8/2010 14:56'! words ^ syntacticElements select: [:eachToken | eachToken isWord ]! ! TLElement subclass: #TLSentence instanceVariableNames: 'syntacticElements phrasesCache sequencesCache' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model'! !TLSentence class methodsFor: 'instance creation' stamp: 'lr 3/31/2010 11:17'! withAll: aCollection ^self new initializeWithAll: aCollection! ! !TLSentence methodsFor: 'accessing' stamp: 'JorgeRessia 5/26/2010 13:49'! allPhrasesOfSize: aSmallInteger | phrases words | phrasesCache at: aSmallInteger ifPresent: [:element | ^element]. phrases := OrderedCollection new. words := self words. 1 to: words size do: [ :index | ((index + aSmallInteger - 1) <= words size) ifTrue: [ phrases add: (TLPhrase withAll: ( syntacticElements copyFrom: (syntacticElements indexOf: (words at: index )) to: (syntacticElements indexOf: (words at: index + aSmallInteger - 1))))] ifFalse: [ phrasesCache at: aSmallInteger put: phrases. ^phrases] ]. phrasesCache at: aSmallInteger put: phrases. ^phrases ! ! !TLSentence methodsFor: 'accessing' stamp: 'JorgeRessia 6/10/2010 15:45'! allSequencesOfSize: aSmallInteger | sequences children| sequencesCache at: aSmallInteger ifPresent: [:element | ^element]. sequences := OrderedCollection new. children := self children. 1 to: children size do: [ :index | ((index + aSmallInteger - 1) <= children size) ifTrue: [ sequences add: (TLPhrase withAll: ( syntacticElements copyFrom: (syntacticElements indexOf: (children at: index )) to: (syntacticElements indexOf: (children at: index + aSmallInteger - 1))))] ifFalse: [ sequencesCache at: aSmallInteger put: sequences. ^sequences] ]. sequencesCache at: aSmallInteger put: sequences. ^sequences ! ! !TLSentence methodsFor: 'checking' stamp: 'JorgeRessia 5/26/2010 10:41'! checkWith: aTextLintChecker ^aTextLintChecker checkSentence: self! ! !TLSentence methodsFor: 'accessing' stamp: 'JorgeRessia 4/8/2010 11:08'! children ^ syntacticElements! ! !TLSentence methodsFor: 'testing' stamp: 'lr 4/5/2010 10:25'! containsPhrase: aString ^ self wordsAsString includesSubstring: aString caseSensitive: false! ! !TLSentence methodsFor: 'initialization' stamp: 'JorgeRessia 6/10/2010 15:30'! initializeWithAll: aCollection syntacticElements := aCollection. phrasesCache := Dictionary new. sequencesCache := Dictionary new.! ! !TLSentence methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 12:12'! isSentence ^ true! ! !TLSentence methodsFor: 'visiting' stamp: 'JorgeRessia 6/16/2010 15:31'! processFor: aVisitor ^ aVisitor processSentence: self! ! !TLSentence methodsFor: 'accessing' stamp: 'JorgeRessia 4/8/2010 11:08'! words ^ syntacticElements select: [:eachToken | eachToken isWord ]! ! !TLSentence methodsFor: 'accessing' stamp: 'JorgeRessia 4/7/2010 15:24'! wordsAsString ^self words inject: '' into: [:count :each | count, ' ', each text] ! ! TLElement subclass: #TLSyntacticElement instanceVariableNames: 'token' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model'! TLSyntacticElement subclass: #TLMarkup instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model'! !TLMarkup methodsFor: 'testing' stamp: 'lr 5/27/2010 16:24'! isMarkup ^ true! ! TLSyntacticElement subclass: #TLPunctuationMark instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model'! !TLPunctuationMark methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 13:58'! isEndOfSentence ^ '.:;!!?' includes: (token collection at: token start)! ! !TLPunctuationMark methodsFor: 'testing' stamp: 'lr 4/6/2010 20:44'! isPunctuation ^ true! ! !TLSyntacticElement class methodsFor: 'instance creation' stamp: 'lr 4/8/2010 13:31'! with: aToken ^ self new initializeWith: aToken! ! !TLSyntacticElement methodsFor: 'initialization' stamp: 'lr 4/8/2010 13:31'! initializeWith: aToken token := aToken! ! !TLSyntacticElement methodsFor: 'printing' stamp: 'lr 4/8/2010 13:52'! printContentOn: aStream aStream nextPutAll: self text! ! !TLSyntacticElement methodsFor: 'visiting' stamp: 'JorgeRessia 6/16/2010 15:32'! processFor: aVisitor ^ aVisitor processSyntacticElement: self! ! !TLSyntacticElement methodsFor: 'accessing' stamp: 'lr 4/9/2010 10:57'! start ^ self token start! ! !TLSyntacticElement methodsFor: 'accessing' stamp: 'lr 4/9/2010 10:57'! stop ^ self token stop! ! !TLSyntacticElement methodsFor: 'accessing' stamp: 'JorgeRessia 4/7/2010 13:54'! text ^ token value! ! !TLSyntacticElement methodsFor: 'accessing' stamp: 'JorgeRessia 4/8/2010 10:56'! token ^ token! ! TLSyntacticElement subclass: #TLTerminatorMark instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model'! !TLTerminatorMark methodsFor: 'testing' stamp: 'lr 4/6/2010 22:04'! isEndOfDocument ^ true! ! TLSyntacticElement subclass: #TLWhitespace instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model'! !TLWhitespace class methodsFor: 'instance creation' stamp: 'JorgeRessia 5/9/2010 11:06'! new ^self basicNew initializeWith: (PPToken on: ' ') ! ! !TLWhitespace methodsFor: 'testing' stamp: 'JorgeRessia 4/7/2010 15:09'! isEndOfParagraph token start to: token stop do: [ :index | (String crlf includes: (token collection at: index)) ifTrue: [ ^ true ] ]. ^ false! ! !TLWhitespace methodsFor: 'testing' stamp: 'lr 4/6/2010 21:45'! isWhitespace ^ true! ! TLSyntacticElement subclass: #TLWord instanceVariableNames: 'type' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model'! !TLWord methodsFor: 'checking' stamp: 'lr 5/26/2010 14:17'! checkWith: aTextLintChecker ^ aTextLintChecker checkWord: self! ! !TLWord methodsFor: 'accessing' stamp: 'lr 5/4/2011 20:47'! classification ^ TLWordClassifier classify: self text! ! !TLWord methodsFor: 'testing' stamp: 'lr 9/6/2011 22:20'! classifiesAs: aSymbol "Answer if the receiving word classifies with a certainty of 1.0." | classifications | classifications := self classification. ^ classifications size = 1 and: [ classifications first = aSymbol ]! ! !TLWord methodsFor: 'testing' stamp: 'lr 9/6/2011 22:19'! classifiesAs: aSymbol withCertainty: aFloat "Answer if the receiving word classifies as aSymbol with a certainty of aFloat (0.0 - 1.0)." | classifications | classifications := self classification. (classifications includes: aSymbol) ifFalse: [ ^ false ]. (classifications size = 1) ifTrue: [ ^ true ]. ^ 1.0 / classifications size >= aFloat! ! !TLWord methodsFor: 'testing' stamp: 'lr 4/6/2010 20:44'! isWord ^ true! ! Object subclass: #TLMassPaperAnalysis instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Runner'! !TLMassPaperAnalysis class methodsFor: 'tools' stamp: 'lr 6/11/2010 15:28'! analyzeAllHistory: aDirectory "self analyzeAllHistory: (FileDirectory on: '/Users/renggli/University/git/papers/TextLint/TextLint-IWST2010/casestudy')" aDirectory directoryNames asSortedCollection do: [ :each | self analyzeHistory: (aDirectory directoryNamed: each) ] displayingProgress: 'Analyzing Directories'! ! !TLMassPaperAnalysis class methodsFor: 'tools' stamp: 'lr 9/8/2010 18:46'! analyzeEffectiveness: aDirectory "self analyzeEffectiveness: (FileDirectory on: '/Users/renggli/University/git/papers/TextLint/TextLint-IWST2010/casestudy')" | checker results | checker := TLTextLintChecker new. results := OrderedCollection new. (TLWritingStyle scientificPaperStyle rules asSortedCollection: [ :a :b | a name < b name ]) do: [ :each | checker addRule: each ]. (aDirectory fileNames asSortedCollection select: [ :each | each endsWith: '.txt' ]) do: [ :filename | | stream count last size average | stream := MultiByteFileStream new initialize. stream open: (aDirectory fullNameFor: filename) forWrite: false. stream nextLine. count := 0. average := Array new: checker rules size + 1 withAll: 0. [ stream atEnd ] whileFalse: [ count := count + 1. last := stream nextLine splitOn: String tab. size := (last at: 3) asNumber asFloat. last := (last allButFirst: 3) collect: [ :each | each asNumber / size ]. average keysAndValuesDo: [ :key :value | average at: key put: value + (last at: key) ] ]. average keysAndValuesDo: [ :key :value | average at: key put: value / count asFloat ]. results addLast: (Array with: filename) , (Array streamContents: [ :output | average with: last do: [ :a :l | output nextPut: (a isZero ifTrue: [ 0 ] ifFalse: [ (100.0 - (100.0 * l / a)) rounded ]) ] ]) ] displayingProgress: 'Calculating Effectiveness'. FileStream forceNewFileNamed: (aDirectory containingDirectory fullNameFor: 'casestudy-effectiveness/effectiveness.txt') do: [ :stream | stream nextPutAll: 'Filename'; tab; nextPutAll: 'Total'; tab. checker rules do: [ :rule | stream nextPutAll: rule name ] separatedBy: [ stream tab ]. stream cr. results do: [ :row | row do: [ :col | stream nextPutAll: col asString ] separatedBy: [ stream tab ] ] separatedBy: [ stream cr ] ]. ^ results! ! !TLMassPaperAnalysis class methodsFor: 'tools' stamp: 'lr 11/3/2010 16:28'! analyzeHistory: aDirectory "self analyzeHistory: (FileDirectory on: '/Users/renggli/University/git/papers/TextLint/TextLint-IWST2010/casestudy-history/petitparser')" "self analyzeHistory: (FileDirectory on: '/Users/renggli/University/git/papers/TextLint/TextLint-IWST2010/casestudy-history/J2EE')" "self analyzeHistory: (FileDirectory on: '/Users/renggli/University/git/papers/TextLint/TextLint-IWST2010/casestudy-history/cop')" "self analyzeHistory: (FileDirectory on: '/Users/renggli/University/git/papers/TextLint/TextLint-IWST2010/casestudy-history/pinocchio')" | checker results | checker := TLTextLintChecker new. results := OrderedCollection new. (TLWritingStyle scientificPaperStyle rules asSortedCollection: [ :a :b | a name < b name ]) do: [ :each | checker addRule: each ]. aDirectory fileNames asSortedCollection do: [ :filename | | stream contents document failures | stream := MultiByteFileStream new initialize. stream open: (aDirectory fullNameFor: filename) forWrite: false. contents := [ stream basicNext: stream size ] ensure: [ stream close ]. document := TLTextPhraser parse: (TLLatexTokenizer parse: contents). failures := document allElements gather: [ :each | each checkWith: checker ]. results addLast: (Array with: (filename) with: (contents size) with: (document sentences detectSum: [ :sentence | sentence children detectSum: [ :element | element class = TLMarkup ifTrue: [ 0 ] ifFalse: [ element token size ] ] ]) with: (failures size)) , (checker rules collect: [ :each | failures count: [ :failure | failure rule == each ] ]) ] displayingProgress: 'Analyzing History'. FileStream forceNewFileNamed: (aDirectory containingDirectory fullNameFor: aDirectory localName , '.txt') do: [ :stream | stream nextPutAll: 'Filename'; tab; nextPutAll: 'Filesize'; tab; nextPutAll: 'Textsize'; tab; nextPutAll: 'Failures'; tab. checker rules do: [ :rule | stream nextPutAll: rule name ] separatedBy: [ stream tab ]. stream cr. results do: [ :row | row do: [ :col | stream nextPutAll: col asString ] separatedBy: [ stream tab ] ] separatedBy: [ stream cr ] ]. ^ results! ! !TLMassPaperAnalysis methodsFor: 'private' stamp: 'lr 5/11/2011 21:07'! analyze | paperNames allFailures aChecker file fileContents results author checker | aChecker := TLTextLintChecker new. TLWritingStyle scientificPaperStyle rules do: [:rule | aChecker addRule: rule]. allFailures := Dictionary new. paperNames := (FileDirectory on: '/Users/ressia/temp/Papers/Helvetia') fullNamesOfAllFilesInSubtree select: [:each | each endsWith: '.tex']. paperNames do: [:each | fileContents := (StandardFileStream readOnlyFileNamed: each) contentsOfEntireFile. fileContents := (fileContents copyReplaceAll: String crlf with: String cr) copyReplaceAll: String lf with: String cr. author := nil. (fileContents findString: '% $Author:' startingAt: 1 ) = 0 ifFalse: [author := fileContents copyFrom: (fileContents findString: '% $Author:' startingAt: 1 ) to: (fileContents findDelimiters: '$' startingAt: (fileContents findString: '% $Author:' startingAt: 1 ) )]. (fileContents findString: '\author{' startingAt: 1 ) = 0 ifFalse: [author := fileContents copyFrom: (fileContents findString: '\author{' startingAt: 1 ) to: (fileContents findDelimiters: '}' startingAt: (fileContents findString: '\author{' startingAt: 1 ) )]. checker := aChecker parse: fileContents. allFailures at: each put: checker results ]. file := CrLfFileStream forceNewFileNamed: '/Users/ressia/temp/SCGPapersTextLintFailures.txt'. ^ allFailures keysAndValuesDo: [:key :value | value do: [:eachFailure | file nextPutAll: key; nextPutAll: ' '; nextPutAll: author asString; nextPutAll: ' '; nextPutAll: eachFailure rule class name; nextPutAll: ' '; nextPutAll: eachFailure element text; nextPutAll: ' ']] ! ! Object subclass: #TLRuleFailure instanceVariableNames: 'rule element' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Runner'! !TLRuleFailure class methodsFor: 'instance creation' stamp: 'JorgeRessia 4/6/2010 15:54'! on: aRule at: anElement ^self new initializeOn: aRule at: anElement! ! !TLRuleFailure methodsFor: 'accessing' stamp: 'JorgeRessia 4/6/2010 16:00'! element ^ element! ! !TLRuleFailure methodsFor: 'initialization' stamp: 'JorgeRessia 4/6/2010 15:55'! initializeOn: aRule at: anElement rule := aRule. element := anElement! ! !TLRuleFailure methodsFor: 'testing' stamp: 'JorgeRessia 5/26/2010 11:40'! isRuleFailure ^true! ! !TLRuleFailure methodsFor: 'printing' stamp: 'lr 4/8/2010 15:36'! printOn: aStream super printOn: aStream. aStream cr; tab; print: self rule. aStream cr; tab; print: self element! ! !TLRuleFailure methodsFor: 'accessing' stamp: 'JorgeRessia 4/6/2010 16:00'! rule ^ rule! ! Object subclass: #TLTextLintChecker instanceVariableNames: 'rules document results' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Runner'! !TLTextLintChecker methodsFor: 'accessing' stamp: 'JorgeRessia 3/31/2010 16:49'! addRule: aRule rules add: aRule! ! !TLTextLintChecker methodsFor: 'accessing' stamp: 'lr 10/25/2010 19:40'! addStyle: aStyle aStyle rules do: [ :each | self addRule: each ]! ! !TLTextLintChecker methodsFor: 'mocking' stamp: 'JorgeRessia 5/26/2010 11:35'! checkDocument: aDocument |results | results := OrderedCollection new. rules do: [:each | results addAll: (each runOnDocument: aDocument)]. ^results ! ! !TLTextLintChecker methodsFor: 'mocking' stamp: 'JorgeRessia 5/26/2010 10:23'! checkParagraph: aParagraph | results | results := OrderedCollection new. rules do: [:each | results addAll: (each runOnParagraph: aParagraph)]. ^results ! ! !TLTextLintChecker methodsFor: 'mocking' stamp: 'lr 5/26/2010 15:09'! checkSentence: aSentence ^ rules gather: [ :each | each runOnSentence: aSentence ]! ! !TLTextLintChecker methodsFor: 'mocking' stamp: 'JorgeRessia 5/26/2010 10:23'! checkWord: aWord | results | results := OrderedCollection new. rules do: [:each | results addAll: (each runOnWord: aWord)]. ^results ! ! !TLTextLintChecker methodsFor: 'accessing' stamp: 'FabrizioPerin 5/31/2010 14:40'! document ^ document! ! !TLTextLintChecker methodsFor: 'initializing' stamp: 'lr 5/11/2011 21:06'! initialize rules := OrderedCollection new! ! !TLTextLintChecker methodsFor: 'public' stamp: 'lr 5/11/2011 21:04'! parse: aString self parse: aString tokenizer: ( (#('\documentclass' '\usepackage' '\section' '\begin{') anySatisfy: [ :each | aString includesSubString: each ]) ifTrue: [ TLLatexTokenizer ] ifFalse: [ (#(' self repetitionLimit ifTrue: [ results addAll: phrases ] ]! ! !TLConnectorRepetitionInParagraphRule methodsFor: 'running' stamp: 'lr 5/4/2011 20:02'! checkWordsIn: aParagraph addingFailuresTo: results | failingWords value wordsCounter | wordsCounter := Dictionary new. failingWords := OrderedCollection new. aParagraph words do: [ :eachWord | value := wordsCounter at: eachWord text ifAbsentPut: [ 0 ]. wordsCounter at: eachWord text put: value + 1 ]. wordsCounter keysAndValuesDo: [ :aKey :aValue | (aValue > self repetitionLimit and: [ self connectorWords includes: aKey ]) ifTrue: [ failingWords add: aKey ] ]. aParagraph words do: [ :eachWord | (failingWords includes: eachWord text) ifTrue: [ results add: eachWord ] ]! ! !TLConnectorRepetitionInParagraphRule methodsFor: 'accessing' stamp: 'JorgeRessia 9/23/2010 22:01'! connectorPhrases | phrases aPhrase elements | phrases := OrderedCollection new. elements := OrderedCollection new. elements add: (TLWord with: (PPToken on: 'in')). elements add: (TLWhitespace new). elements add: (TLWord with: (PPToken on: 'contrast')). elements add: (TLWhitespace new). elements add: (TLWord with: (PPToken on: 'to')). aPhrase := TLPhrase withAll: elements. phrases add: aPhrase. elements := OrderedCollection new. elements add: (TLWord with: (PPToken on: 'in')). elements add: (TLWhitespace new). elements add: (TLWord with: (PPToken on: 'addition')). aPhrase := TLPhrase withAll: elements. phrases add: aPhrase. elements := OrderedCollection new. elements add: (TLWord with: (PPToken on: 'on')). elements add: (TLWhitespace new). elements add: (TLWord with: (PPToken on: 'the')). elements add: (TLWhitespace new). elements add: (TLWord with: (PPToken on: 'other')). elements add: (TLWhitespace new). elements add: (TLWord with: (PPToken on: 'hand')). aPhrase := TLPhrase withAll: elements. phrases add: aPhrase. ^ phrases! ! !TLConnectorRepetitionInParagraphRule methodsFor: 'accessing' stamp: 'JorgeRessia 9/23/2010 21:16'! connectorWords ^ #('however' 'furthermore' 'still' 'nevertheless')! ! !TLConnectorRepetitionInParagraphRule methodsFor: 'accessing' stamp: 'JorgeRessia 9/23/2010 21:11'! name ^ 'Avoid connectors repetition'! ! !TLConnectorRepetitionInParagraphRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:40'! rationale ^ 'The constant repetition of the same connectors in a paragraph is weakening.'! ! !TLConnectorRepetitionInParagraphRule methodsFor: 'accessing' stamp: 'JorgeRessia 9/23/2010 21:56'! repetitionLimit ^1! ! !TLConnectorRepetitionInParagraphRule methodsFor: 'running' stamp: 'JorgeRessia 9/29/2010 09:55'! runOnParagraph: aParagraph | results failures | results := OrderedCollection new. self checkWordsIn: aParagraph addingFailuresTo: results. self checkPhrasesIn: aParagraph addingFailuresTo: results. failures := OrderedCollection new. results do: [:each | failures add: (TLRuleFailure on: self at: each) ]. ^ failures! ! TLTextLintRule subclass: #TLJoinedSentencesWithCommasRule instanceVariableNames: 'wordsBeforeCommaExceptions' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLJoinedSentencesWithCommasRule methodsFor: 'initialization' stamp: 'JorgeRessia 5/27/2010 16:55'! initialize super initialize. self initializeWordsBeforeComma! ! !TLJoinedSentencesWithCommasRule methodsFor: 'initialization' stamp: 'lr 5/30/2010 19:27'! initializeWordsBeforeComma wordsBeforeCommaExceptions := OrderedCollection new add: 'or'; add: 'and'; add: 'since'; add: 'however'; add: 'but'; add: 'because'; add: 'though'; add: 'still'; add: 'yet'; add: 'as'; yourself.! ! !TLJoinedSentencesWithCommasRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:54'! name ^ 'Avoid joined sentences'! ! !TLJoinedSentencesWithCommasRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:40'! rationale ^ 'Do not join sentences with commas, instead use colons, semi-colons, dashes, or conjunctions.'! ! !TLJoinedSentencesWithCommasRule methodsFor: 'running' stamp: 'JorgeRessia 5/27/2010 17:05'! runOnSentence: aSentence | results numberOfCommas children commaIndex wordsBeforeComma wordsAfterComma | results := OrderedCollection new. children := aSentence children. numberOfCommas := children inject: 0 into: [:count :each | (each text = ',') ifTrue: [ count + 1 ] ifFalse: [ count ]]. (numberOfCommas = 1) ifFalse: [^results]. commaIndex := children indexOf: (children detect: [:each | each isPunctuation and: [each text = ',']]). wordsAfterComma := children select: [:each | each isWord and: [ (children indexOf: each) > commaIndex ]]. (wordsAfterComma size > 0 ) ifFalse: [^results]. (self wordsBeforeComma anySatisfy: [:each | wordsAfterComma first text sameAs: each] ) ifTrue: [^results]. wordsBeforeComma := children select: [:each | each isWord and: [ (children indexOf: each) < commaIndex ]]. ((wordsBeforeComma size > 4) and: [wordsAfterComma size > 4]) ifTrue: [ results add: (TLRuleFailure on: self at: aSentence) ]. ^results ! ! !TLJoinedSentencesWithCommasRule methodsFor: 'initialization' stamp: 'JorgeRessia 5/27/2010 17:03'! wordsBeforeComma ^wordsBeforeCommaExceptions ! ! TLTextLintRule subclass: #TLLongParagraphRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLLongParagraphRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/28/2010 11:17'! maxSentencesPerParagraph ^10! ! !TLLongParagraphRule methodsFor: 'running' stamp: 'lr 9/8/2010 10:54'! name ^ 'Avoid long paragraph'! ! !TLLongParagraphRule methodsFor: 'accessing' stamp: 'lr 11/30/2010 19:39'! rationale ^ 'Paragraphs with more than ' , self maxSentencesPerParagraph asString , ' sentences are too long, they should be split into multiple paragraphs.'! ! !TLLongParagraphRule methodsFor: 'running' stamp: 'JorgeRessia 5/28/2010 11:17'! runOnParagraph: aParagraph | results | results := OrderedCollection new. (aParagraph sentences size > self maxSentencesPerParagraph ) ifTrue: [results add: (TLRuleFailure on: self at: aParagraph)]. ^results ! ! TLTextLintRule subclass: #TLLongSentenceRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLLongSentenceRule methodsFor: 'accessing' stamp: 'lr 5/28/2010 11:50'! maxWordsPerSentence ^ 40! ! !TLLongSentenceRule methodsFor: 'running' stamp: 'lr 9/8/2010 10:54'! name ^ 'Avoid long sentence'! ! !TLLongSentenceRule methodsFor: 'accessing' stamp: 'lr 11/30/2010 19:39'! rationale ^ 'Sentences of more than ' , self maxWordsPerSentence asString , ' words are too long, they should be split into multiple sentences.'! ! !TLLongSentenceRule methodsFor: 'running' stamp: 'JorgeRessia 5/28/2010 10:40'! runOnSentence: aSentence | results | results := OrderedCollection new. (aSentence words size > self maxWordsPerSentence ) ifTrue: [results add: (TLRuleFailure on: self at: aSentence)]. ^results ! ! TLTextLintRule subclass: #TLPatternRule instanceVariableNames: 'pattern' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! TLPatternRule subclass: #TLALotRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLALotRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:38'! matchingString ^ 'a lot'! ! !TLALotRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:47'! name ^ 'Avoid "a lot"'! ! !TLALotRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:41'! rationale ^ 'Avoid using "a lot", it weakens the sentence.'! ! TLPatternRule subclass: #TLARule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLARule methodsFor: 'private' stamp: 'lr 10/31/2010 14:34'! exceptions ^ #('union' 'united' 'unified' 'unifying' 'us' 'one' 'unit' 'user' 'usage' 'universal' 'unique' 'unit' 'useful' 'uniform')! ! !TLARule methodsFor: 'accessing' stamp: 'JorgeRessia 5/10/2011 14:58'! matchingPattern ^ (self word: 'a') , (self separators) , (self wordIn: self exceptions) not , (self wordTextSatisfying: [ :value | value first isVowel ])! ! !TLARule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:54'! name ^ 'Avoid "a"'! ! !TLARule methodsFor: 'accessing' stamp: 'lr 10/31/2010 14:37'! rationale ^ 'After "a" only words beginning without a vowel are allowed.'! ! TLPatternRule subclass: #TLAdjectiveSynonymRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLAdjectiveSynonymRule methodsFor: 'accessing' stamp: 'lr 9/6/2011 22:36'! matchingPattern | firstWord | ^ (self wordSatisfying: [ :word | (firstWord := word) classifiesAs: #adjective ]) , (self separators) , (self wordSatisfying: [ :word | (TLThesaurus synonymsOf: firstWord text) includes: word text ]) ! ! !TLAdjectiveSynonymRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/10/2011 16:35'! name ^ 'Avoid similar adjective synonyms'! ! !TLAdjectiveSynonymRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/10/2011 16:35'! rationale ^ 'Avoid using an adjective followed by any word that has a similar meaning.'! ! TLPatternRule subclass: #TLAdverbSynonymRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLAdverbSynonymRule methodsFor: 'accessing' stamp: 'lr 9/6/2011 22:36'! matchingPattern | firstWord | ^ (self wordSatisfying: [ :word | (firstWord := word) classifiesAs: #adverb ]) , (self separators) , (self wordSatisfying: [ :word | (TLThesaurus synonymsOf: firstWord text) includes: word text ]) ! ! !TLAdverbSynonymRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/10/2011 16:36'! name ^ 'Avoid similar adverb synonyms'! ! !TLAdverbSynonymRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/10/2011 16:35'! rationale ^ 'Avoid using an adverb followed by any word that has a similar meaning.'! ! TLPatternRule subclass: #TLAllowToRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLAllowToRule methodsFor: 'accessing' stamp: 'lr 10/31/2010 14:03'! matchingPattern ^ (self word: 'allow') / (self word: 'allows') , (self separators) , (self word: 'to')! ! !TLAllowToRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:53'! name ^ 'Avoid "allow to"'! ! !TLAllowToRule methodsFor: 'accessing' stamp: 'JorgeRessia 4/4/2010 10:19'! rationale ^ 'Never use the expressions "allow/s to". This expression requires a direct object.'! ! TLPatternRule subclass: #TLAnRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLAnRule methodsFor: 'private' stamp: 'lr 10/31/2010 14:37'! exceptions ^ #('honorable' 'honest' 'hour' 'xml' 'hybrid' 'html' 'http')! ! !TLAnRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/10/2011 14:58'! matchingPattern ^ (self word: 'an') , (self separators) , (self wordIn: self exceptions) not , (self wordTextSatisfying: [ :value | value first isVowel not ])! ! !TLAnRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:54'! name ^ 'Avoid "an"'! ! !TLAnRule methodsFor: 'accessing' stamp: 'lr 10/31/2010 14:37'! rationale ^ 'After "an" only words beginning with a vowel are allowed.'! ! TLPatternRule subclass: #TLAsToWhetherRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLAsToWhetherRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:38'! matchingString ^ 'as to whether'! ! !TLAsToWhetherRule methodsFor: 'accessing' stamp: 'JorgeRessia 10/28/2010 13:10'! name ^ 'Avoid "as to whether"'! ! !TLAsToWhetherRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:42'! rationale ^ '"as to whether" is commonly misued, it is enough to write "whether".'! ! TLPatternRule subclass: #TLAvoidMultipleWordsUsageRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLAvoidMultipleWordsUsageRule methodsFor: 'running' stamp: 'JorgeRessia 11/1/2010 15:00'! matchingPattern ^ self wordIn: self wordsToAvoid! ! !TLAvoidMultipleWordsUsageRule methodsFor: 'running' stamp: 'JorgeRessia 11/1/2010 14:54'! wordsToAvoid ^ self subclassResponsibility! ! TLAvoidMultipleWordsUsageRule subclass: #TLQualifiersRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLQualifiersRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:09'! name ^ 'Avoid qualifier'! ! !TLQualifiersRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:43'! rationale ^ 'Qualifiers are the leeches that infest the pond of prose, sucking the blood of words.'! ! !TLQualifiersRule methodsFor: 'accessing' stamp: 'lr 11/2/2010 07:42'! wordsToAvoid ^ #('clearly' 'completely' 'exceedingly' 'excellent' 'extremely' 'fairly' 'few' 'huge' 'interestingly' 'largely' 'little' 'many' 'mostly' 'pretty' 'quite' 'rather' 'really' 'relatively' 'remarkably' 'several' 'significantly' 'substantially' 'surprisingly' 'tiny' 'various' 'vast' 'very')! ! TLAvoidMultipleWordsUsageRule subclass: #TLStuffRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLStuffRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:59'! name ^ 'Avoid "stuff"'! ! !TLStuffRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:43'! rationale ^ 'Avoid using the word "stuff". Is too general and weakens the sentence.'! ! !TLStuffRule methodsFor: 'running' stamp: 'JorgeRessia 11/1/2010 15:03'! wordsToAvoid ^ #('stuff' 'stuffs') ! ! TLAvoidMultipleWordsUsageRule subclass: #TLThingRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLThingRule methodsFor: 'running' stamp: 'lr 9/8/2010 11:00'! name ^ 'Avoid "thing"'! ! !TLThingRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:43'! rationale ^ 'Avoid using the word "thing". Is too general and weakens the sentence.'! ! !TLThingRule methodsFor: 'running' stamp: 'JorgeRessia 11/1/2010 15:21'! wordsToAvoid ^ #('thing' 'things') ! ! TLPatternRule subclass: #TLCannotRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLCannotRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:39'! matchingString ^ 'can not'! ! !TLCannotRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:53'! name ^'Avoid "can not"'! ! !TLCannotRule methodsFor: 'accessing' stamp: 'JorgeRessia 9/2/2010 19:32'! rationale ^ '"Can not" as a two word phrase is used for stressing an impossibility, otherwise "cannot" should be used.'! ! TLPatternRule subclass: #TLCaseRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLCaseRule methodsFor: 'accessing' stamp: 'lr 11/30/2010 19:29'! matchingPattern ^ (self wordIn: #('case' 'cases')) , (self separators) , (self punctuation: '-') optional , (self separators) , (self wordIn: #('grammar' 'grammars' 'harden' 'histories' 'history' 'knife' 'knives' 'law' 'mod' 'sensitive' 'shot' 'stated' 'studies' 'study' 'system')) not! ! !TLCaseRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:01'! name ^ 'Avoid "case"'! ! !TLCaseRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:43'! rationale ^ 'Often unnecessarey, e.g. "In many cases, the room lacked air conditioning" can be replaced with "Many of the rooms lacked air conditioning".'! ! TLPatternRule subclass: #TLCertainlyRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLCertainlyRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:44'! matchingString ^ 'certainly' ! ! !TLCertainlyRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:01'! name ^ 'Avoid "certainly"'! ! !TLCertainlyRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:43'! rationale ^ 'Is a manerism that is used indicriminately by some speakers and writers. Avoid its usage if possible.'! ! TLPatternRule subclass: #TLClichesRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLClichesRule methodsFor: 'accessing' stamp: 'lr 5/4/2011 19:49'! matchingPattern ^ (TLPatternTokenizer parse: 'all things being equal') / (TLPatternTokenizer parse: 'all things considered') / (TLPatternTokenizer parse: 'as a matter of fact') / (TLPatternTokenizer parse: 'as far as I am concerned') / (TLPatternTokenizer parse: 'at the end of the day') / (TLPatternTokenizer parse: 'at the present time') / (TLPatternTokenizer parse: 'due to the fact that') / (TLPatternTokenizer parse: 'for all intents and purposes') / (TLPatternTokenizer parse: 'for the most part') / (TLPatternTokenizer parse: 'for the purpose of') / (TLPatternTokenizer parse: 'in a manner of speaking') / (TLPatternTokenizer parse: 'in my opinion') / (TLPatternTokenizer parse: 'in the event of') / (TLPatternTokenizer parse: 'in the final analysis') / (TLPatternTokenizer parse: 'it seems that') / (TLPatternTokenizer parse: 'the point that I am trying to make') / (TLPatternTokenizer parse: 'type of') / (TLPatternTokenizer parse: 'what I am trying to say') / (TLPatternTokenizer parse: 'what I want to make clear')! ! !TLClichesRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/4/2011 11:29'! name ^ 'Avoid cliches'! ! !TLClichesRule methodsFor: 'accessing' stamp: 'lr 9/6/2011 22:26'! rationale ^ 'Avoid empty phrases (cliches). These phrases mean little. Just cut them off your writing.'! ! TLPatternRule subclass: #TLContinuousWordRepetitionRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLContinuousWordRepetitionRule methodsFor: 'running' stamp: 'JorgeRessia 5/10/2011 14:58'! matchingPattern | aWord | ^ (self wordTextSatisfying: [ :value | aWord := value. value isAllDigits not ]) , (self wordTextSatisfying: [ :value | aWord sameAs: value]) ! ! !TLContinuousWordRepetitionRule methodsFor: 'running' stamp: 'lr 9/8/2010 11:01'! name ^ 'Avoid continuous word repetition'! ! !TLContinuousWordRepetitionRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:46'! rationale ^ 'Continous word repetition is mostly a sign of copy-and-paste text.'! ! TLPatternRule subclass: #TLCouldRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLCouldRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:45'! matchingString ^ 'could' ! ! !TLCouldRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:01'! name ^ 'Avoid "could"'! ! !TLCouldRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:44'! rationale ^ 'Avoid using the word "could" because it weakens the sentence.'! ! TLPatternRule subclass: #TLCurrentlyRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLCurrentlyRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:45'! matchingString ^ 'currently' ! ! !TLCurrentlyRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:01'! name ^ 'Avoid "currently"'! ! !TLCurrentlyRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:44'! rationale ^ 'In the sense of now with a verb in the present tense, "currently" is usually redundant. Emphasis is better achieved through a more precise reference to time.'! ! TLPatternRule subclass: #TLDifferentThanRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLDifferentThanRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:40'! matchingString ^ 'different than'! ! !TLDifferentThanRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:57'! name ^ 'Avoid "different than"'! ! !TLDifferentThanRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:46'! rationale ^ 'Here logic supports stablished usage: one thing differs from another, hence, different from.'! ! TLPatternRule subclass: #TLDoubtButRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLDoubtButRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:40'! matchingString ^ 'doubt but'! ! !TLDoubtButRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:57'! name ^ 'Avoid "doubt but"'! ! !TLDoubtButRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:46'! rationale ^ '"But" is unnecessary after "doubt".'! ! TLPatternRule subclass: #TLEachAndEveryOneRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLEachAndEveryOneRule methodsFor: 'running' stamp: 'lr 11/4/2010 10:40'! matchingString ^ 'each and every one'! ! !TLEachAndEveryOneRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:58'! name ^ 'Avoid "each and every one"'! ! !TLEachAndEveryOneRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:46'! rationale ^ 'Jargon, avoid except in dialog.'! ! TLPatternRule subclass: #TLEnormityRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLEnormityRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:45'! matchingString ^ 'enormity' ! ! !TLEnormityRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:02'! name ^ 'Avoid "enormity"'! ! !TLEnormityRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:44'! rationale ^ 'Use only in the sense of monstrous wickedness. Misleading, if not wrong, when used to express bigness.'! ! TLPatternRule subclass: #TLExcessOfAdjectivesRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLExcessOfAdjectivesRule methodsFor: 'accessing' stamp: 'lr 9/6/2011 22:25'! matchingPattern ^ (self wordSatisfying: [ :word | word classifiesAs: #adjective ]) , (self whitespace) , (self wordSatisfying: [ :word | word classifiesAs: #adjective ]) ! ! !TLExcessOfAdjectivesRule methodsFor: 'accessing' stamp: 'JorgeRessia 4/30/2011 20:24'! name ^ 'Avoid excess of adjectives'! ! !TLExcessOfAdjectivesRule methodsFor: 'accessing' stamp: 'JorgeRessia 4/30/2011 20:25'! rationale ^ 'Avoid using two or more continuous adjectives, be concise and clear.'! ! TLPatternRule subclass: #TLFactorRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLFactorRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:45'! matchingString ^ 'factor' ! ! !TLFactorRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:07'! name ^ 'Avoid "factor"'! ! !TLFactorRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:44'! rationale ^ 'A hackneyed word. The expression can be rephased without it.'! ! TLPatternRule subclass: #TLFunnyRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLFunnyRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:45'! matchingString ^ 'funny'! ! !TLFunnyRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:08'! name ^ 'Avoid "funny"'! ! !TLFunnyRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:44'! rationale ^ 'Avoid it as a means of introduction. Do not announce that something is funny, it should be by itself.'! ! TLPatternRule subclass: #TLHelpButRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLHelpButRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:40'! matchingString ^ 'help but'! ! !TLHelpButRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:58'! name ^ 'Avoid "help but"'! ! !TLHelpButRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:47'! rationale ^ '"But" is unnecessary after "help".'! ! TLPatternRule subclass: #TLHelpToRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLHelpToRule methodsFor: 'accessing' stamp: 'lr 10/31/2010 14:07'! matchingPattern ^ (self word: 'help') / (self word: 'helps') , (self separators) , (self word: 'to')! ! !TLHelpToRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:53'! name ^'Avoid "help to"'! ! !TLHelpToRule methodsFor: 'accessing' stamp: 'JorgeRessia 4/4/2010 10:41'! rationale ^ 'Never use the expressions "help/s to". This expression requires a direct object.'! ! TLPatternRule subclass: #TLHoweverRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLHoweverRule methodsFor: 'accessing' stamp: 'lr 11/2/2010 12:27'! matchingPattern ^ (self anchorBegin) , (self word: 'however')! ! !TLHoweverRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:47'! name ^ 'Avoid "however"'! ! !TLHoweverRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:47'! rationale ^ 'Avoid starting a sentence with "however" when the meaning is nevertheless.'! ! TLPatternRule subclass: #TLImportantlyRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLImportantlyRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:46'! matchingString ^ 'importantly' ! ! !TLImportantlyRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:08'! name ^ 'Avoid "importantly"'! ! !TLImportantlyRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:44'! rationale ^ 'Avoid by rephrasing.'! ! TLPatternRule subclass: #TLInOrderToRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLInOrderToRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:41'! matchingString ^ 'in order to'! ! !TLInOrderToRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:55'! name ^ 'Avoid "in order to"'! ! !TLInOrderToRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/13/2010 19:55'! rationale ^ 'This expression is pure clutter and most of the time can be avoided.'! ! TLPatternRule subclass: #TLInRegardsToRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLInRegardsToRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:41'! matchingString ^ 'in regards to'! ! !TLInRegardsToRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:59'! name ^ 'Avoid "in regards to"'! ! !TLInRegardsToRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:47'! rationale ^ 'Often wrongly written "in regards to", should be "in regard to".'! ! TLPatternRule subclass: #TLInTermsOfRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLInTermsOfRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:41'! matchingString ^ 'in terms of'! ! !TLInTermsOfRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:59'! name ^ 'Avoid "in terms of"'! ! !TLInTermsOfRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:47'! rationale ^ 'A piece of padding usually best omitted.'! ! TLPatternRule subclass: #TLInsightfulRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLInsightfulRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:46'! matchingString ^ 'insightful' ! ! !TLInsightfulRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:08'! name ^ 'Avoid "insightful"'! ! !TLInsightfulRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:44'! rationale ^ 'The word is a suspicious overstatement for perceptive. Only used for remarkable visions.'! ! TLPatternRule subclass: #TLInterestingRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLInterestingRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:46'! matchingString ^ 'interesting' ! ! !TLInterestingRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:09'! name ^ 'Avoid "interesting"'! ! !TLInterestingRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:45'! rationale ^ 'Avoid it as a means of introduction. Do not announce that something is interesting.'! ! TLPatternRule subclass: #TLIrregardlessRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLIrregardlessRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:46'! matchingString ^ 'irregardless' ! ! !TLIrregardlessRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:09'! name ^ 'Avoid "irregardless"'! ! !TLIrregardlessRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:45'! rationale ^ 'Should be "regardless". Irregardless is avoided by careful users of English.'! ! TLPatternRule subclass: #TLLetsRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLLetsRule methodsFor: 'accessing' stamp: 'JorgeRessia 4/26/2011 13:45'! matchingString ^ 'lets'! ! !TLLetsRule methodsFor: 'accessing' stamp: 'JorgeRessia 4/26/2011 13:43'! name ^ 'Avoid lets'! ! !TLLetsRule methodsFor: 'accessing' stamp: 'JorgeRessia 4/26/2011 13:44'! rationale ^ 'Let plus a subject should be used instead of using lets.'! ! TLPatternRule subclass: #TLNegativeFormRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLNegativeFormRule methodsFor: 'accessing' stamp: 'lr 5/4/2011 19:53'! longRationale ^ 'Make definite assertions. Avoid tame, colorless, hesitating, non-committal language.'! ! !TLNegativeFormRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/4/2011 10:25'! matchingString ^ 'not' ! ! !TLNegativeFormRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/4/2011 10:29'! name ^ 'Avoid negative form'! ! !TLNegativeFormRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/4/2011 10:29'! rationale ^ 'When possible, put statements in positive form.'! ! TLPatternRule subclass: #TLNoCommaBeforeThatRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLNoCommaBeforeThatRule methodsFor: 'accessing' stamp: 'lr 10/31/2010 14:11'! matchingPattern ^ (self word) , (self separators) , (self punctuation: ',') , (self separators) , (self word: 'that')! ! !TLNoCommaBeforeThatRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:55'! name ^ 'Avoid comma'! ! !TLNoCommaBeforeThatRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:47'! rationale ^ 'In German, you must put a comma before "dass". Not in English.'! ! TLPatternRule subclass: #TLNoContinuousPunctuationMarksRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLNoContinuousPunctuationMarksRule methodsFor: 'running' stamp: 'lr 11/4/2010 10:41'! matchingPattern ^ (self punctuationIn: self punctuationsToAvoid) , (self punctuationIn: self punctuationsToAvoid)! ! !TLNoContinuousPunctuationMarksRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:00'! name ^ 'Avoid continuous punctuation'! ! !TLNoContinuousPunctuationMarksRule methodsFor: 'running' stamp: 'JorgeRessia 11/2/2010 08:56'! punctuationsToAvoid ^ #(',' '.' ':' ';' '!!' '?') ! ! !TLNoContinuousPunctuationMarksRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:47'! rationale ^ 'There should be no continuous punctuation marks.'! ! TLPatternRule subclass: #TLNoContractionsRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLNoContractionsRule methodsFor: 'accessing' stamp: 'JorgeRessia 4/26/2011 13:32'! matchingPattern ^ (self word) , (self punctuation: '''') , (self wordIn: #('ve' 't' 'd' 'll' 're' 'm' 's'))! ! !TLNoContractionsRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:55'! name ^ 'Avoid contraction'! ! !TLNoContractionsRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:48'! rationale ^ 'Contractions are not allowed since they could be ambiguous.'! ! TLPatternRule subclass: #TLNoSpacesBeforePunctuationMarkRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLNoSpacesBeforePunctuationMarkRule methodsFor: 'running' stamp: 'lr 11/3/2010 14:46'! matchingPattern ^ (self whitespace) , (self punctuationIn: self punctuationsToAvoid) ! ! !TLNoSpacesBeforePunctuationMarkRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:54'! name ^ 'Avoid whitespace'! ! !TLNoSpacesBeforePunctuationMarkRule methodsFor: 'running' stamp: 'JorgeRessia 11/2/2010 08:58'! punctuationsToAvoid ^ #(',' '.' ':' ';' '!!' '?') ! ! !TLNoSpacesBeforePunctuationMarkRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:48'! rationale ^ 'There should be no whitespaces before any punctuation mark.'! ! TLPatternRule subclass: #TLNounsAndAdjectivesListRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLNounsAndAdjectivesListRule methodsFor: 'accessing' stamp: 'lr 9/6/2011 22:34'! matchingPattern | classification | ^ (self wordSatisfying: [ :word | classification := (word classifiesAs: #adjective) ifTrue: [ #adjective ] ifFalse: [ (word classifiesAs: #noun) ifTrue: [ classification := #noun ] ifFalse: [ nil ] ]. classification notNil ]) , (self separators) , (self wordSatisfying: [ :word | word classifiesAs: classification ]) , (self separators) , (self wordTextSatisfying: [ :value | value = 'and' or: [ value = 'or' ] ]) , (self separators) , (self wordSatisfying: [ :word | word classifiesAs: classification ])! ! !TLNounsAndAdjectivesListRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/11/2011 21:36'! name ^ 'Avoid list of terms without comma'! ! !TLNounsAndAdjectivesListRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/11/2011 20:00'! rationale ^ 'In a serie of three or more terms (adjectives or nouns) with a single conjunction, use a comma after each term except the last.'! ! TLPatternRule subclass: #TLOftenEnoughRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLOftenEnoughRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:42'! matchingString ^ 'often enough'! ! !TLOftenEnoughRule methodsFor: 'accessing' stamp: 'JorgeRessia 11/2/2010 15:58'! name ^ 'Avoid "offen enough"'! ! !TLOftenEnoughRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:48'! rationale ^ 'Avoid using "often enough" it is pure clutter. Use "often" instead.'! ! TLPatternRule subclass: #TLOneOfTheMostRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLOneOfTheMostRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:42'! matchingString ^ 'one of the most'! ! !TLOneOfTheMostRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:55'! name ^ 'Avoid "one of the most"'! ! !TLOneOfTheMostRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:48'! rationale ^ 'Avoid this feeble formula. There is nothing wrong with the grammar the formula is simple threadbare.'! ! TLPatternRule subclass: #TLPassiveVoiceRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLPassiveVoiceRule methodsFor: 'private' stamp: 'lr 11/2/2010 12:46'! irregularWords ^ #('awoken' 'been' 'born' 'beat' 'become' 'begun' 'bent' 'beset' 'bet' 'bid' 'bidden' 'bound' 'bitten' 'bled' 'blown' 'broken' 'bred' 'brought' 'broadcast' 'built' 'burnt' 'burst' 'bought' 'cast' 'caught' 'chosen' 'clung' 'come' 'cost' 'crept' 'cut' 'dealt' 'dug' 'dived' 'done' 'drawn' 'dreamt' 'driven' 'drunk' 'eaten' 'fallen' 'fed' 'felt' 'fought' 'found' 'fit' 'fled' 'flung' 'flown' 'forbidden' 'forgotten' 'foregone' 'forgiven' 'forsaken' 'frozen' 'gotten' 'given' 'gone' 'ground' 'grown' 'hung' 'heard' 'hidden' 'hit' 'held' 'hurt' 'kept' 'knelt' 'knit' 'known' 'laid' 'led' 'leapt' 'learnt' 'left' 'lent' 'let' 'lain' 'lighted' 'lost' 'made' 'meant' 'met' 'misspelt' 'mistaken' 'mown' 'overcome' 'overdone' 'overtaken' 'overthrown' 'paid' 'pled' 'proven' 'put' 'quit' 'read' 'rid' 'ridden' 'rung' 'risen' 'run' 'sawn' 'said' 'seen' 'sought' 'sold' 'sent' 'set' 'sewn' 'shaken' 'shaven' 'shorn' 'shed' 'shone' 'shod' 'shot' 'shown' 'shrunk' 'shut' 'sung' 'sunk' 'sat' 'slept' 'slain' 'slid' 'slung' 'slit' 'smitten' 'sown' 'spoken' 'sped' 'spent' 'spilt' 'spun' 'spit' 'split' 'spread' 'sprung' 'stood' 'stolen' 'stuck' 'stung' 'stunk' 'stridden' 'struck' 'strung' 'striven' 'sworn' 'swept' 'swollen' 'swum' 'swung' 'taken' 'taught' 'torn' 'told' 'thought' 'thrived' 'thrown' 'thrust' 'trodden' 'understood' 'upheld' 'upset' 'woken' 'worn' 'woven' 'wed' 'wept' 'wound' 'won' 'withheld' 'withstood' 'wrung' 'written')! ! !TLPassiveVoiceRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/10/2011 14:58'! matchingPattern "http://matt.might.net/articles/shell-scripts-for-passive-voice-weasel-words-duplicates/" ^ (self wordIn: self verbWords) , (self separators) , ((self wordTextSatisfying: [ :value | value endsWith: 'ed' ]) / (self wordIn: self irregularWords))! ! !TLPassiveVoiceRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:09'! name ^ 'Avoid passive voice'! ! !TLPassiveVoiceRule methodsFor: 'accessing' stamp: 'lr 9/5/2010 21:58'! rationale ^ 'Passive voice often hides relevant or explanatory information.'! ! !TLPassiveVoiceRule methodsFor: 'private' stamp: 'lr 11/2/2010 12:45'! verbWords ^ #('am' 'are' 'were' 'being' 'is' 'been' 'was' 'be')! ! !TLPatternRule methodsFor: 'factory' stamp: 'lr 11/2/2010 12:24'! anchorBegin ^ [ :stream | stream position = 0 ifFalse: [ PPFailure message: 'begin of input expected' at: stream position ] ] asParser! ! !TLPatternRule methodsFor: 'factory' stamp: 'lr 11/3/2010 14:45'! markup ^ PPPredicateObjectParser on: [ :element | element isMarkup ] message: 'markup expected'! ! !TLPatternRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:38'! matchingPattern "Override in subclasses to answer a custom pattern parser." ^ TLPatternTokenizer parse: self matchingString! ! !TLPatternRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:37'! matchingString "Override in subclasses to answer a string pattern." self error: 'Override #matchingPattern or #matchingString in subclasses to provide pattern.'! ! !TLPatternRule methodsFor: 'private' stamp: 'lr 9/5/2011 19:03'! newPattern | result | result := self matchingPattern. (result isKindOf: PPFlattenParser) ifFalse: [ result := result flatten ]. ^ result ! ! !TLPatternRule methodsFor: 'accessing' stamp: 'lr 9/5/2011 19:03'! pattern "Answer the lazily initialized pattern. Do not override in subclasses." ^ pattern ifNil: [ pattern := self newPattern ]! ! !TLPatternRule methodsFor: 'factory' stamp: 'lr 10/31/2010 14:19'! punctuation ^ PPPredicateObjectParser on: [ :element | element isPunctuation ] message: 'punctuation expected'! ! !TLPatternRule methodsFor: 'factory' stamp: 'lr 10/31/2010 14:19'! punctuation: aString ^ PPPredicateObjectParser on: [ :element | element isPunctuation and: [ element text = aString ] ] message: 'punctuation expected'! ! !TLPatternRule methodsFor: 'factory' stamp: 'JorgeRessia 11/1/2010 10:23'! punctuationIn: aCollection ^ PPPredicateObjectParser on: [ :element | element isPunctuation and: [ aCollection anySatisfy: [ :each | element text sameAs: each ] ] ] message: 'punctuation expected'! ! !TLPatternRule methodsFor: 'factory' stamp: 'JorgeRessia 11/1/2010 10:17'! punctuationSatisfying: aBlock ^ PPPredicateObjectParser on: [ :element | element isPunctuation and: [ aBlock value: element text ] ] message: 'punctuation expected'! ! !TLPatternRule methodsFor: 'running' stamp: 'JorgeRessia 11/1/2010 11:23'! runOnSentence: aSentence ^ (self pattern matchesIn: aSentence children) collect: [ :each | TLRuleFailure on: self at: (TLPhrase withAll: each) ]! ! !TLPatternRule methodsFor: 'factory' stamp: 'lr 11/3/2010 14:45'! separator ^ self whitespace / self markup! ! !TLPatternRule methodsFor: 'factory' stamp: 'lr 10/31/2010 13:58'! separators ^ self separator star! ! !TLPatternRule methodsFor: 'factory' stamp: 'lr 11/3/2010 14:45'! whitespace ^ PPPredicateObjectParser on: [ :element | element isWhitespace ] message: 'whitespace expected'! ! !TLPatternRule methodsFor: 'factory' stamp: 'lr 10/31/2010 14:19'! word ^ PPPredicateObjectParser on: [ :element | element isWord ] message: 'word expected'! ! !TLPatternRule methodsFor: 'factory' stamp: 'lr 10/31/2010 14:20'! word: aString ^ PPPredicateObjectParser on: [ :element | element isWord and: [ element text sameAs: aString ] ] message: 'word expected'! ! !TLPatternRule methodsFor: 'factory' stamp: 'lr 10/31/2010 14:20'! wordIn: aCollection ^ PPPredicateObjectParser on: [ :element | element isWord and: [ aCollection anySatisfy: [ :each | element text sameAs: each ] ] ] message: 'word expected'! ! !TLPatternRule methodsFor: 'factory' stamp: 'JorgeRessia 5/10/2011 14:57'! wordSatisfying: aBlock ^ PPPredicateObjectParser on: [ :element | element isWord and: [ aBlock value: element ] ] message: 'word expected'! ! !TLPatternRule methodsFor: 'factory' stamp: 'JorgeRessia 5/10/2011 14:57'! wordTextSatisfying: aBlock ^ PPPredicateObjectParser on: [ :element | element isWord and: [ aBlock value: element text ] ] message: 'word expected'! ! TLPatternRule subclass: #TLRegardedAsBeingRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLRegardedAsBeingRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:42'! matchingString ^ 'regarded as being'! ! !TLRegardedAsBeingRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:55'! name ^ 'Avoid "regarded as"'! ! !TLRegardedAsBeingRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:48'! rationale ^ '"Being" is not appropriate after "regard as".'! ! TLPatternRule subclass: #TLRequireToRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLRequireToRule methodsFor: 'accessing' stamp: 'lr 10/31/2010 14:21'! matchingPattern ^ (self word: 'require') / (self word: 'requires') , (self separators) , (self word: 'to')! ! !TLRequireToRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:56'! name ^ 'Avoid "required to"'! ! !TLRequireToRule methodsFor: 'accessing' stamp: 'JorgeRessia 4/4/2010 10:25'! rationale ^ 'Never use the expressions "require/s to". This expression requires a direct object.'! ! TLPatternRule subclass: #TLSoCalledRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLSoCalledRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:42'! matchingString ^ 'so called'! ! !TLSoCalledRule methodsFor: 'accessing' stamp: 'JorgeRessia 11/2/2010 15:53'! name ^ 'Avoid "so called"'! ! !TLSoCalledRule methodsFor: 'accessing' stamp: 'JorgeRessia 11/2/2010 15:53'! rationale ^ 'Avoid using "so called" it is a general expression that adds nothing to the sentence.'! ! TLPatternRule subclass: #TLSoOnRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLSoOnRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:43'! matchingString ^ 'so on'! ! !TLSoOnRule methodsFor: 'accessing' stamp: 'JorgeRessia 11/2/2010 15:47'! name ^ 'Avoid "so on"'! ! !TLSoOnRule methodsFor: 'accessing' stamp: 'JorgeRessia 11/2/2010 15:48'! rationale ^ 'Avoid using "so on" it is a general expression that adds nothing to the sentence.'! ! TLPatternRule subclass: #TLSomehowRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLSomehowRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:46'! matchingString ^ 'somehow' ! ! !TLSomehowRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:59'! name ^ 'Avoid "somehow"'! ! !TLSomehowRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:45'! rationale ^ 'Avoid using the word "somehow". Is too general and weakens the sentence.'! ! TLPatternRule subclass: #TLTheFactIsRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLTheFactIsRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:43'! matchingString ^ 'the fact is'! ! !TLTheFactIsRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:56'! name ^ 'Avoid "the fact is"'! ! !TLTheFactIsRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:49'! rationale ^ 'A bad beginning for a sentence. If you think you are possessed of the truth or fact state it.'! ! TLPatternRule subclass: #TLTheFactThatRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLTheFactThatRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:43'! matchingString ^ 'the fact that'! ! !TLTheFactThatRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:56'! name ^ 'Avoid "the fact that"'! ! !TLTheFactThatRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:49'! rationale ^ '"The fact that" is an especially debilitating expression.'! ! TLPatternRule subclass: #TLTheTruthIsRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLTheTruthIsRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:43'! matchingString ^ 'the truth is'! ! !TLTheTruthIsRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:56'! name ^ 'Avoid "the truth is"'! ! !TLTheTruthIsRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:49'! rationale ^ 'A bad beginning for a sentence. If you think you are possessed of the truth or fact state it.'! ! TLPatternRule subclass: #TLThereIsAreOpenerRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLThereIsAreOpenerRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/4/2011 11:09'! matchingPattern ^ (self anchorBegin) , (self word: 'there') , (self separators) , ( (self word: 'is') / (self word: 'are') )! ! !TLThereIsAreOpenerRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/4/2011 10:59'! name ^'Avoid "There is/are" openers'! ! !TLThereIsAreOpenerRule methodsFor: 'accessing' stamp: 'JorgeRessia 5/4/2011 11:16'! rationale ^ 'Avoid the use of There is/are as openers. There are two security guards at the gate -> Two security guards stand at the gate.'! ! TLPatternRule subclass: #TLThusRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLThusRule methodsFor: 'accessing' stamp: 'lr 11/2/2010 12:25'! matchingPattern ^ (self anchorBegin) , (self word: 'thus')! ! !TLThusRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:09'! name ^ 'Avoid "thus"'! ! !TLThusRule methodsFor: 'accessing' stamp: 'JorgeRessia 9/2/2010 19:35'! rationale ^ 'Avoid starting a sentence with "thus". This word should be used for implication between two statements.'! ! TLPatternRule subclass: #TLTrueFactRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLTrueFactRule methodsFor: 'accessing' stamp: 'lr 10/31/2010 14:24'! matchingPattern ^ (self word: 'true') , (self separators) , ((self word: 'fact') / (self word: 'facts'))! ! !TLTrueFactRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:57'! name ^ 'Avoid "true fact"'! ! !TLTrueFactRule methodsFor: 'accessing' stamp: 'JorgeRessia 6/10/2010 14:20'! rationale ^ 'Never use the expressions "true fact/s". It is a tautology.'! ! TLPatternRule subclass: #TLWouldRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLWouldRule methodsFor: 'accessing' stamp: 'lr 11/4/2010 10:46'! matchingString ^ 'would' ! ! !TLWouldRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:09'! name ^ 'Avoid "would"'! ! !TLWouldRule methodsFor: 'accessing' stamp: 'JorgeRessia 9/2/2010 19:36'! rationale ^ 'Avoid using the word "would" because it weakens the sentence.'! ! TLTextLintRule subclass: #TLSerialCommaRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLSerialCommaRule methodsFor: 'private' stamp: 'DamienCassou 9/5/2011 14:37'! cutAt: aBlock in: aCollection | result current| result := OrderedCollection new. current := OrderedCollection new. aCollection do: [:e | e isWhitespace ifFalse: [ (aBlock value: e) ifTrue: [current isEmpty ifFalse: [result add: current. current:= OrderedCollection new]] ifFalse: [current add: e]] ]. current isEmpty ifFalse: [result add: current]. ^ result! ! !TLSerialCommaRule methodsFor: 'accessing' stamp: 'DamienCassou 9/5/2011 14:15'! name ^ 'Use the serial comma'! ! !TLSerialCommaRule methodsFor: 'accessing' stamp: 'DamienCassou 9/5/2011 14:15'! rationale ^ 'Use a comma after the next-to-last item in a series of three or more elements.'! ! !TLSerialCommaRule methodsFor: 'running' stamp: 'lr 9/6/2011 22:56'! runOnSentence: aSentence | parts last average match | parts := self cutAt: [ :each | each text = ',' ] in: aSentence children. parts size < 2 ifTrue: [ ^ #() ]. last := self cutAt: [ :each | each text = 'and' or: [ each text = 'or' ] ] in: parts last. last size < 2 ifTrue: [ ^ #() ]. parts := parts allButLast , last. parts size < 3 ifTrue: [ ^ #() ]. parts := parts allButFirst. "only consider it, if all parts have roughly the same number of words" average := (parts inject: 0 into: [ :count :part | count + part size ]) / parts size asFloat. (parts allSatisfy: [ :part | part size between: average - 1.5 and: average + 1.5 ]) ifFalse: [ ^ #() ]. ^ Array with: (TLRuleFailure on: self at: aSentence)! ! !TLTextLintRule class methodsFor: 'accessing' stamp: 'lr 10/25/2010 19:38'! allRules ^ self subclasses isEmpty ifTrue: [ Array with: self new ] ifFalse: [ self subclasses gather: [ :each | each allRules ] ]! ! !TLTextLintRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 10:44'! name ^ self subclassResponsibility ! ! !TLTextLintRule methodsFor: 'accessing' stamp: 'JorgeRessia 4/2/2010 17:44'! rationale ^ self subclassResponsibility! ! !TLTextLintRule methodsFor: 'running' stamp: 'lr 11/2/2010 07:43'! runOn: aDocument ^ OrderedCollection new addAll: (self runOnDocument: aDocument); addAll: (self runOnParagraphsIn: aDocument); addAll: (self runOnSentencesIn: aDocument); addAll: (self runOnWordsIn: aDocument); yourself! ! !TLTextLintRule methodsFor: 'running' stamp: 'lr 11/2/2010 07:43'! runOnDocument: aDocument ^ #()! ! !TLTextLintRule methodsFor: 'running' stamp: 'lr 11/2/2010 07:43'! runOnParagraph: aParagraph ^ #()! ! !TLTextLintRule methodsFor: 'running' stamp: 'JorgeRessia 6/3/2010 18:29'! runOnParagraphsIn: aDocument ^ aDocument paragraphs gather: [ :each | self runOnParagraph: each ]! ! !TLTextLintRule methodsFor: 'running' stamp: 'lr 11/2/2010 07:42'! runOnSentence: aSentence ^ #()! ! !TLTextLintRule methodsFor: 'running' stamp: 'JorgeRessia 6/3/2010 18:30'! runOnSentencesIn: aDocument ^ aDocument sentences gather: [ :each | self runOnSentence: each ]! ! !TLTextLintRule methodsFor: 'running' stamp: 'lr 11/2/2010 07:42'! runOnWord: aWord ^ #()! ! !TLTextLintRule methodsFor: 'running' stamp: 'JorgeRessia 6/3/2010 18:28'! runOnWordsIn: aDocument ^ aDocument words gather: [ :each | self runOnWord: each ]! ! TLTextLintRule subclass: #TLWordRepetitionInParagraphRule instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLWordRepetitionInParagraphRule methodsFor: 'accessing' stamp: 'lr 9/8/2010 11:00'! name ^ 'Avoid word repetition'! ! !TLWordRepetitionInParagraphRule methodsFor: 'accessing' stamp: 'lr 11/3/2010 19:49'! rationale ^ 'The constant repetition of the same words in a paragraph is weakening.'! ! !TLWordRepetitionInParagraphRule methodsFor: 'running' stamp: 'lr 5/4/2011 20:06'! runOnParagraph: aParagraph | counts results | counts := Bag new. aParagraph words do: [ :word | counts add: word text ]. results := OrderedCollection new. aParagraph words do: [ :word | self wordRepetitionLimit < (counts occurrencesOf: word text) ifTrue: [ results add: word ] ]. ^ results! ! !TLWordRepetitionInParagraphRule methodsFor: 'accessing' stamp: 'JorgeRessia 4/12/2010 10:53'! wordRepetitionLimit ^2! ! Object subclass: #TLThesaurus instanceVariableNames: 'groups' classVariableNames: 'ThesaurusTable defaultDictionary' poolDictionaries: '' category: 'TextLint-Model'! !TLThesaurus class methodsFor: 'private' stamp: 'lr 5/11/2011 19:10'! createData: aString "Create the thesarus from http://www.gutenberg.org/ebooks/3202" "self createData: '/Users/renggli/Downloads/mthesaur.txt'" | input output zipped | input := FileStream fileNamed: aString. input converter: Latin1TextConverter new. output := self directory forceNewFileNamed: self filename. zipped := ZLibWriteStream on: output binary. [ input atEnd ] whileFalse: [ | words | words := ((input nextLine findTokens: $,) reject: [ :each | each anySatisfy: [ :char | char = $ ] ]) collect: [ :each | each asLowercase ]. words isEmpty ifFalse: [ zipped nextInt32Put: words size. words do: [ :word | zipped nextPut: word size; nextPutAll: (ByteArray withAll: word) ] ] ]. zipped close. output close! ! !TLThesaurus class methodsFor: 'accessing' stamp: 'lr 5/11/2011 19:12'! data ^ ThesaurusTable ifNil: [ ThesaurusTable := self loadData ]! ! !TLThesaurus class methodsFor: 'configuration' stamp: 'lr 5/11/2011 18:57'! directory ^ FileDirectory default! ! !TLThesaurus class methodsFor: 'private' stamp: 'lr 5/11/2011 18:55'! downloadData "Download data from a server." | response stream | response := [ HTTPSocket httpGet: self url ] on: Error do: [ :err | err messageText ]. response isString ifTrue: [ ^ self ]. stream := self directory forceNewFileNamed: self filename. [ stream binary; nextPutAll: (response binary; contents) ] ensure: [ stream close ]! ! !TLThesaurus class methodsFor: 'configuration' stamp: 'lr 5/11/2011 18:57'! filename ^ 'tl-thesaurus.dat'! ! !TLThesaurus class methodsFor: 'initialization' stamp: 'lr 5/11/2011 18:56'! initialize Smalltalk addToShutDownList: self! ! !TLThesaurus class methodsFor: 'private' stamp: 'lr 5/12/2011 20:46'! loadData "Load data from an external file as fast as possible." | result stream | (self directory fileExists: self filename) ifFalse: [ self downloadData ]. (self directory fileExists: self filename) ifFalse: [ self error: 'The thesaurus cannot be downloaded from <' , self url , '>.' ]. result := Dictionary new. stream := self directory oldFileNamed: self filename. [ | zstream | zstream := ZLibReadStream on: stream binary. [ zstream atEnd ] whileFalse: [ | words count | words := OrderedCollection new: (count := zstream nextInt32). count timesRepeat: [ words addLast: (String withAll: (zstream next: zstream next)) ]. result at: words first put: words sorted asArray ] ] ensure: [ stream close ]. result keysAndValuesDo: [ :key :values | result at: key put: values sorted ]. ^ result! ! !TLThesaurus class methodsFor: 'initialization' stamp: 'lr 5/11/2011 18:56'! shutDown ThesaurusTable := nil! ! !TLThesaurus class methodsFor: 'accessing' stamp: 'lr 5/11/2011 19:33'! synonymsOf: aString ^ self data at: aString asLowercase ifAbsent: [ #() ]! ! !TLThesaurus class methodsFor: 'configuration' stamp: 'lr 5/11/2011 18:57'! url ^ 'http://www.lukas-renggli.ch/smalltalk/tl-thesaurus.dat'! ! Object subclass: #TLWordClassifier instanceVariableNames: '' classVariableNames: 'ClassificationTable' poolDictionaries: '' category: 'TextLint-Model'! !TLWordClassifier class methodsFor: 'accessing' stamp: 'lr 9/6/2011 22:10'! classify: aString "Answer the possibly classifications of aString." ^ self data at: aString asLowercase ifAbsent: [ #() ]! ! !TLWordClassifier class methodsFor: 'private' stamp: 'lr 5/10/2011 00:17'! createData: aString "Create the wordlist. The wordlist we use is from English Wiktionary. The contents of these files is Copyright to the contributors of the English Wiktionary under CC-SA-BY , see for more information. As a source we started from the latest english words available at and processed them with awk -F '\t' '{ printf ""%s\t%s\n"", tolower($2), tolower($3) }' enwikt-defs-latest-en.tsv | egrep '^[A-Za-z]+.[a-z ]+$' | sed -e 's/proper noun/noun/' -e 's/cardinal number/number/' -e 's/verb form/verb/' -e 's/ordinal number/number/' | grep -v ' ' | sort | uniq | awk -F '\t' '{ printf ""%s\n%s\n"", $1, $2 }' > tl-words.txt" "self createData: '/Users/renggli/Downloads/tl-words.txt'" | input output zipped | input := FileStream fileNamed: aString. input converter: Latin1TextConverter new. output := self directory forceNewFileNamed: self filename. zipped := ZLibWriteStream on: output binary. [ input atEnd ] whileFalse: [ | word | word := input nextLine. zipped nextPut: word size; nextPutAll: (ByteArray withAll: word) ]. zipped close. output close! ! !TLWordClassifier class methodsFor: 'accessing' stamp: 'lr 5/9/2011 23:47'! data ^ ClassificationTable ifNil: [ ClassificationTable := self loadData ]! ! !TLWordClassifier class methodsFor: 'configuration' stamp: 'lr 5/9/2011 23:35'! directory ^ FileDirectory default! ! !TLWordClassifier class methodsFor: 'accessing' stamp: 'lr 9/6/2011 21:51'! distributionOfMatches ^ self data inject: Bag new into: [ :bag :types | bag add: types size; yourself ]! ! !TLWordClassifier class methodsFor: 'accessing' stamp: 'lr 9/6/2011 21:51'! distributionOfTypes ^ self data inject: Bag new into: [ :bag :types | bag addAll: types; yourself ]! ! !TLWordClassifier class methodsFor: 'private' stamp: 'lr 5/9/2011 23:37'! downloadData "Download data from a server." | response stream | response := [ HTTPSocket httpGet: self url ] on: Error do: [ :err | err messageText ]. response isString ifTrue: [ ^ self ]. stream := self directory forceNewFileNamed: self filename. [ stream binary; nextPutAll: (response binary; contents) ] ensure: [ stream close ]! ! !TLWordClassifier class methodsFor: 'configuration' stamp: 'lr 5/9/2011 23:38'! filename ^ 'tl-words.dat'! ! !TLWordClassifier class methodsFor: 'initialization' stamp: 'lr 5/9/2011 23:47'! initialize Smalltalk addToShutDownList: self! ! !TLWordClassifier class methodsFor: 'private' stamp: 'lr 5/10/2011 00:16'! loadData "Load data from an external file as fast as possible." | result stream | (self directory fileExists: self filename) ifFalse: [ self downloadData ]. (self directory fileExists: self filename) ifFalse: [ self error: 'The word classification cannot be downloaded from <' , self url , '>.' ]. result := Dictionary new. stream := self directory oldFileNamed: self filename. [ | zstream | zstream := ZLibReadStream on: stream binary. [ zstream atEnd ] whileFalse: [ (result at: (String withAll: (zstream next: zstream next)) ifAbsentPut: [ Set new ]) add: (String withAll: (zstream next: zstream next)) asSymbol ] ] ensure: [ stream close ]. result keysAndValuesDo: [ :key :values | result at: key put: values sorted ]. ^ result! ! !TLWordClassifier class methodsFor: 'initialization' stamp: 'lr 5/9/2011 23:43'! shutDown ClassificationTable := nil! ! !TLWordClassifier class methodsFor: 'accessing' stamp: 'lr 5/10/2011 00:02'! types ^ self data inject: Set new into: [ :set :types | set addAll: types; yourself ]! ! !TLWordClassifier class methodsFor: 'configuration' stamp: 'lr 5/9/2011 23:37'! url ^ 'http://www.lukas-renggli.ch/smalltalk/tl-words.dat'! ! Object subclass: #TLWritingStyle instanceVariableNames: 'name rules' classVariableNames: '' poolDictionaries: '' category: 'TextLint-Model-Rules'! !TLWritingStyle class methodsFor: 'instance creation' stamp: 'JorgeRessia 5/10/2010 11:52'! named: aString formedBy: anArray ^self new initializeNamed: aString formedBy: anArray ! ! !TLWritingStyle class methodsFor: 'accessing' stamp: 'lr 10/25/2010 19:39'! scientificPaperStyle | rules | rules := TLTextLintRule allRules reject: [ :each | each class = TLWordRepetitionInParagraphRule ]. ^ TLWritingStyle named: 'Scientific Paper Style' formedBy: rules! ! !TLWritingStyle methodsFor: 'composing' stamp: 'JorgeRessia 5/12/2010 20:29'! + aWritingStyle ^TLWritingStyle named: (self name, ' + ', aWritingStyle name) formedBy: (self rules addAll: aWritingStyle rules; yourself)! ! !TLWritingStyle methodsFor: 'composing' stamp: 'JorgeRessia 5/12/2010 20:35'! - aWritingStyle ^TLWritingStyle named: (self name, ' - ', aWritingStyle name) formedBy: (self rules removeAllFoundIn: aWritingStyle rules; yourself)! ! !TLWritingStyle methodsFor: 'testing' stamp: 'JorgeRessia 5/10/2010 11:55'! includes: aRule ^rules includes: aRule! ! !TLWritingStyle methodsFor: 'initialization' stamp: 'JorgeRessia 5/10/2010 11:58'! initializeNamed: aString formedBy: aCollection name := aString. rules := aCollection asOrderedCollection! ! !TLWritingStyle methodsFor: 'accessing' stamp: 'JorgeRessia 5/10/2010 11:54'! name ^ name! ! !TLWritingStyle methodsFor: 'accessing' stamp: 'JorgeRessia 5/10/2010 11:59'! rules ^ OrderedCollection withAll: rules! ! TLThesaurus initialize! TLWordClassifier initialize!