Skip to content

Commit 19e2cde

Browse files
committed
WIP Add ExercismProblemSpecification
1 parent de121a8 commit 19e2cde

File tree

3 files changed

+535
-99
lines changed

3 files changed

+535
-99
lines changed

dev/src/ExercismDev/ExercismExerciseGenerator.class.st

+74-99
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ Class {
1010
#superclass : #Object,
1111
#instVars : [
1212
'numberGenerated',
13-
'testCounter'
14-
],
15-
#classVars : [
16-
'LastPath'
13+
'testCounter',
14+
'problems'
1715
],
1816
#category : #'ExercismDev-TestGenerator'
1917
}
@@ -24,51 +22,21 @@ ExercismExerciseGenerator class >> convertLegacyTagsToPackages [
2422
do: [ :t | t promoteAsExercismRPackage ]
2523
]
2624

27-
{ #category : #'as yet unclassified' }
28-
ExercismExerciseGenerator class >> defaultSourcePath [
29-
|builder|
30-
[ builder := IceRepositoryCreator new
31-
url: 'git@github.com:exercism/problem-specifications.git';
32-
commitishName: 'master';
33-
yourself.
34-
builder createRepository.
35-
] on: IceDuplicatedRepository
36-
do: [ :error | "don nothing" ].
37-
^ builder locationToUse exists
38-
ifTrue: [ (builder locationToUse / 'exercises') fullName ]
39-
]
40-
4125
{ #category : #examples }
4226
ExercismExerciseGenerator class >> generate [
4327
"This is the entry point for generating exercism compatible source files that can be checked into
4428
the exercism/pharo project. e.g. self generate"
4529

4630
<example>
47-
| sourcePath defaultSourcePath |
48-
49-
50-
defaultSourcePath := self defaultSourcePath.
51-
sourcePath := defaultSourcePath ifNotNil: [
52-
(self confirm: 'Generate from default source location?' , String cr, defaultSourcePath)
53-
ifTrue: [ defaultSourcePath ]
54-
].
55-
sourcePath ifNil: [
56-
UIManager default
57-
chooseDirectory: 'Select source "problem-specifications/exercises" folder to read from'
58-
path: self lastPath.
59-
].
6031

61-
sourcePath ifNotNil: [ self new generateFrom: (self lastPath: sourcePath) asFileReference ]
32+
self new generateFrom: ExercismProblemSpecification all "or allNeedingGeneration ?? ask user ??"
6233
]
6334

6435
{ #category : #examples }
65-
ExercismExerciseGenerator class >> lastPath [
66-
^ LastPath ifNil: [ LastPath := FileLocator home pathString]
67-
]
36+
ExercismExerciseGenerator class >> problemSpecificationsFrom: filePathReference [
37+
^ filePathReference entries
38+
collect: [ :entry | ExercismProblemSpecification newFromFileRef: entry reference ].
6839

69-
{ #category : #examples }
70-
ExercismExerciseGenerator class >> lastPath: pathString [
71-
^ LastPath := pathString
7240
]
7341

7442
{ #category : #examples }
@@ -196,10 +164,10 @@ ExercismExerciseGenerator >> generateCodeShouldRaiseOn: output variable: variabl
196164
]
197165

198166
{ #category : #generation }
199-
ExercismExerciseGenerator >> generateExerciseFrom: aFileSystemReference [
200-
| testName testDescription testSpecification testJson testClass testRoot testVariable testMetaData versionString |
167+
ExercismExerciseGenerator >> generateExerciseFrom: spec [
168+
| testMetaData testClass |
201169

202-
170+
" ExercismProblemSpecification newFromFileRef: aFileSystemReference.
203171
testRoot := '' join: ((aFileSystemReference basename splitOn: $-) collect: [ :w | w capitalized ]).
204172
testName := testRoot, 'Test'.
205173
testVariable := (testRoot, 'Calculator') asValidSelector asString.
@@ -216,19 +184,23 @@ ExercismExerciseGenerator >> generateExerciseFrom: aFileSystemReference [
216184
217185
testJson := STONJSON fromString: testSpecification.
218186
versionString := testJson at: 'version'.
219-
220-
testMetaData := (WriteStream on: '') nextPutAll: testMetaData;
221-
nextPutAll: ('exercise: "{1}"' format: {testRoot}); cr;
222-
nextPutAll: ('version: "{1}"' format: {versionString}); cr; contents.
223-
224-
testClass := self generateTestClass: testName tag: testRoot variable: testVariable.
187+
"
188+
Transcript crShow: 'Generating ', spec classNameForTest.
189+
spec hasCanonicalData ifFalse: [ ^self ].
190+
testClass := self generateTestClassUsing: spec.
225191
"self generateTestVariableAccessors: testVariable in: testClass."
226-
self generateSetupOn: testClass using: testVariable assigning: testRoot.
227-
self generateTestMethodsOn: testClass calling: testVariable using: testJson prefix: ''.
228-
self generateMetaDataFor: testClass description: testDescription version: versionString metaData: testMetaData.
192+
self generateSetupOn: testClass using: spec.
193+
self halt. "Work in progress. Step through next method to validate."
194+
self generateTestMethodsOn: testClass using: spec.
195+
196+
testMetaData := ''. "spec metaDataString".
197+
testMetaData := (WriteStream on: '') nextPutAll: testMetaData;
198+
nextPutAll: ('exercise: "{1}"' format: {spec mixedCaseName}); cr;
199+
nextPutAll: ('version: "{1}"' format: {spec version}); cr; contents.
200+
self generateMetaDataFor: testClass description: spec description version: spec version metaData: testMetaData.
229201

230202
self numberGenerated: self numberGenerated + 1.
231-
self log: 'successfully created' for: testName
203+
self log: 'successfully created' for: spec classNameForTest
232204

233205

234206

@@ -237,16 +209,14 @@ ExercismExerciseGenerator >> generateExerciseFrom: aFileSystemReference [
237209
]
238210

239211
{ #category : #generation }
240-
ExercismExerciseGenerator >> generateFrom: filePathReference [
212+
ExercismExerciseGenerator >> generateFrom: problemSpecifications [
241213
(RPackageOrganizer default
242214
includesPackageNamed: self defaultPackageName)
243215
ifFalse: [ RPackageOrganizer default createPackageNamed: self defaultPackageName ].
244216

245-
self crLog: 'Generating new TestCases from specification: ', filePathReference printString.
246-
247217
self numberGenerated: 0.
248-
filePathReference entries
249-
do: [ :entry | self generateExerciseFrom: entry reference ].
218+
(problemSpecifications select: #hasCanonicalData)
219+
do: [ :spec | self generateExerciseFrom: spec ].
250220

251221
self
252222
crLog: ('Generation complete. Created {1} Tests!'
@@ -289,65 +259,70 @@ ExercismExerciseGenerator >> generateMetaDataFor: testClass description: testDes
289259
]
290260

291261
{ #category : #generation }
292-
ExercismExerciseGenerator >> generateSetupOn: testClass using: testVariable assigning: testRoot [
293-
| output src |
262+
ExercismExerciseGenerator >> generateSetupOn: testClass using: spec [
263+
| methodSource |
294264

295-
output := (WriteStream on: '').
296-
output nextPutAll: 'setUp'; cr.
297-
output tab; nextPutAll: 'super setUp.'; cr.
298-
output tab; nextPutAll: testVariable, ' := '; nextPutAll: testRoot, ' new'.
265+
methodSource := (WriteStream on: '').
266+
methodSource
267+
nextPutAll: 'setUp'; cr;
268+
tab; nextPutAll: 'super setUp.'; cr;
269+
tab; nextPutAll: spec testVariable, ' := '; nextPutAll: spec classNameForSolution, ' new'.
299270

300-
src := output contents.
301-
self compile: src for: testClass selector: #setUp protocol: 'running'
271+
self
272+
compile: methodSource contents
273+
for: testClass
274+
selector: #setUp
275+
protocol: 'running'
302276

303277
]
304278

305279
{ #category : #generation }
306-
ExercismExerciseGenerator >> generateTestClass: testName tag: tagName variable: testVariable [
280+
ExercismExerciseGenerator >> generateTestClassUsing: spec [
307281

308282
self resetTestCounter.
309283

310284
^ExercismTest
311-
subclass: testName asSymbol
312-
instanceVariableNames: testVariable
285+
subclass: spec classNameForTest asSymbol
286+
instanceVariableNames: spec testVariable
313287
classVariableNames: ''
314288
poolDictionaries: ''
315-
package: 'ExercismWIP-', tagName
289+
package: 'ExercismWIP-', spec mixedCaseName
316290

317291
]
318292

319293
{ #category : #generation }
320-
ExercismExerciseGenerator >> generateTestMethodsOn: testClass calling: testVariable using: testJson prefix: aPrefixString [
321-
| instance methodName parameters testResult testPrefix methodNameSegment |
322-
323-
(testJson at: 'cases')
324-
do: [ :case |
325-
methodNameSegment := (((testJson at: 'cases') size > 1 ) or: [ aPrefixString notEmpty ])
326-
ifTrue: [ (case at: 'description') asCamelCase asValidKeyword capitalized ]
327-
ifFalse: [ '' ].
328-
methodName := aPrefixString
329-
ifEmpty: [ methodNameSegment withoutPrefix: 'And' ]
330-
ifNotEmpty: [ aPrefixString, methodNameSegment ].
331-
332-
(case includesKey: 'cases')
333-
ifTrue: [ self
334-
generateTestMethodsOn: testClass
335-
calling: testVariable
336-
using: case
337-
prefix: methodName ]
338-
ifFalse: [
339-
instance := case at: 'property'.
340-
parameters := case at: 'input'.
341-
testResult := case at: 'expected'.
342-
343-
testPrefix := 'test{1}_' format: {self nextTestCounter asTwoCharacterString}.
344-
self
345-
generateTestNamed: (testPrefix, methodName) asSymbol
346-
in: testClass
347-
variable: testVariable
348-
selector: instance
349-
parameters: parameters
350-
expecting: testResult ] ]
294+
ExercismExerciseGenerator >> generateTestMethodsOn: testClass calling: testVariable using: spec prefix: aPrefixString [
295+
"Processes... https://github.com/exercism/problem-specifications/blob/master/canonical-schema.json"
296+
| groups instance methodName parameters testResult testPrefix methodNameSegment |
297+
298+
groups := (spec tests collect: [ :test | test groupCount ]) max.
299+
spec tests
300+
do: [ :test |
301+
testPrefix := 'test{1}_' format: {self nextTestCounter asTwoCharacterString}.
302+
self
303+
generateTestNamed: (testPrefix, test methodNameSegment) asSymbol
304+
in: testClass
305+
variable: spec testVariable
306+
selector: test property
307+
parameters: test input
308+
expecting: test expected ]
309+
]
310+
311+
{ #category : #generation }
312+
ExercismExerciseGenerator >> generateTestMethodsOn: testClass using: spec [
313+
"Processes... https://github.com/exercism/problem-specifications/blob/master/canonical-schema.json"
314+
| testPrefix |
315+
316+
spec tests
317+
do: [ :test |
318+
testPrefix := 'test{1}_' format: {self nextTestCounter asTwoCharacterString}.
319+
self
320+
generateTestNamed: (testPrefix, test methodNameSegment) asSymbol
321+
in: testClass
322+
variable: spec testVariable
323+
selector: test property
324+
parameters: test input
325+
expecting: test expected ]
351326
]
352327

353328
{ #category : #generation }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
Class {
2+
#name : #ExercismLabeledTest,
3+
#superclass : #Object,
4+
#instVars : [
5+
'description',
6+
'property',
7+
'input',
8+
'expected',
9+
'comment',
10+
'groupPath',
11+
'exercise'
12+
],
13+
#category : #'ExercismDev-TestGenerator'
14+
}
15+
16+
{ #category : #'as yet unclassified' }
17+
ExercismLabeledTest >> comment: aString [
18+
comment := aString
19+
]
20+
21+
{ #category : #'as yet unclassified' }
22+
ExercismLabeledTest >> description [
23+
^description
24+
]
25+
26+
{ #category : #'as yet unclassified' }
27+
ExercismLabeledTest >> description: aString [
28+
description := aString
29+
]
30+
31+
{ #category : #'as yet unclassified' }
32+
ExercismLabeledTest >> exercise: aString [
33+
exercise := aString
34+
]
35+
36+
{ #category : #'as yet unclassified' }
37+
ExercismLabeledTest >> expected [
38+
^ expected
39+
]
40+
41+
{ #category : #'as yet unclassified' }
42+
ExercismLabeledTest >> expected: aString [
43+
expected := aString
44+
]
45+
46+
{ #category : #'as yet unclassified' }
47+
ExercismLabeledTest >> groupCount [
48+
^ groupPath size
49+
]
50+
51+
{ #category : #'as yet unclassified' }
52+
ExercismLabeledTest >> groupPath: aCollection [
53+
groupPath := aCollection
54+
]
55+
56+
{ #category : #'as yet unclassified' }
57+
ExercismLabeledTest >> input [
58+
^ input
59+
]
60+
61+
{ #category : #'as yet unclassified' }
62+
ExercismLabeledTest >> input: aString [
63+
input := aString
64+
]
65+
66+
{ #category : #'as yet unclassified' }
67+
ExercismLabeledTest >> methodName [
68+
| methodNameSegment |
69+
methodNameSegment := groupPath size > 1
70+
ifTrue: [ groupPath last key asCamelCase asValidKeyword asValidSelector ]
71+
ifFalse: [ '' ].
72+
73+
^ methodNameSegment , description asCamelCase asValidKeyword
74+
]
75+
76+
{ #category : #'as yet unclassified' }
77+
ExercismLabeledTest >> methodNameSegment [
78+
| methodNameSegment |
79+
methodNameSegment := groupPath isEmpty
80+
ifFalse: [ groupPath last key asCamelCase asValidKeyword ]
81+
ifTrue: [ '' ].
82+
83+
^ methodNameSegment , description asCamelCase asValidKeyword
84+
]
85+
86+
{ #category : #'as yet unclassified' }
87+
ExercismLabeledTest >> pathCount [
88+
^ groupPath size
89+
]
90+
91+
{ #category : #'as yet unclassified' }
92+
ExercismLabeledTest >> printOn: aStream [
93+
super printOn: aStream.
94+
aStream
95+
nextPutAll: '_';
96+
nextPutAll: self methodNameSegment asString;
97+
nextPutAll: ' <--( ';
98+
nextPutAll: exercise slug, ': '.
99+
groupPath do: [ :g | aStream nextPutAll: g key asString, ' / ' ].
100+
aStream
101+
nextPutAll: description asString;
102+
nextPutAll: ' )'.
103+
104+
]
105+
106+
{ #category : #'as yet unclassified' }
107+
ExercismLabeledTest >> property [
108+
^ property
109+
]
110+
111+
{ #category : #'as yet unclassified' }
112+
ExercismLabeledTest >> property: aString [
113+
property := aString
114+
]

0 commit comments

Comments
 (0)