Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create: allow specifying author and difficulty #864

Merged
merged 6 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ Options for create:
--concept-exercise <slug> The slug of the concept exercise
-e, --exercise <slug> Only operate on this exercise
-o, --offline Do not update the cached 'problem-specifications' data
-a, --author The author of the exercise, approach or article
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is deliberately singular, as 99.99% of the time there is only one author.

-d, --difficulty The difficulty of the exercise (default: 1)

Options for fmt:
-e, --exercise <slug> Only operate on this exercise
Expand Down
17 changes: 16 additions & 1 deletion src/cli.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import std/[os, parseutils, strformat, strutils, terminal]
import std/[options, os, parseutils, strformat, strutils, terminal]
import pkg/supersnappy
import patched_libs/parseopt3

Expand Down Expand Up @@ -47,6 +47,8 @@ type
# in object variants.
exerciseCreate*: string
offlineCreate*: bool
author*: string
difficulty*: Option[int]
of actFmt:
# We can't name these fields `exercise`, `update`, and `yes` because we
# use those names in `actSync`, and Nim doesn't yet support duplicate
Expand Down Expand Up @@ -88,6 +90,8 @@ type
optCreateArticle = "article"
optCreateConceptExercise = "conceptExercise"
optCreatePracticeExercise = "practiceExercise"
optCreateAuthor = "author"
optCreateDifficulty = "difficulty"

# Options for `completion`
optCompletionShell = "shell"
Expand Down Expand Up @@ -244,6 +248,8 @@ func genHelpText: string =
optCreateArticle: "The slug of the article",
optCreateConceptExercise: "The slug of the concept exercise",
optCreatePracticeExercise: "The slug of the practice exercise",
optCreateAuthor: "The author of the exercise, approach or article",
optCreateDifficulty: "The difficulty of the exercise (default: 1)",
optCompletionShell: &"Choose the shell type (required)\n" &
&"{paddingOpt}{allowedValues(Shell)}",
optFmtSyncCreateExercise: "Only operate on this exercise",
Expand Down Expand Up @@ -552,6 +558,15 @@ proc handleOption(conf: var Conf; kind: CmdLineKind; key, val: string) =
setActionOpt(practiceExerciseSlug, val)
of optInfoSyncCreateOffline:
setActionOpt(offlineCreate, true)
of optCreateAuthor:
setActionOpt(author, val)
of optCreateDifficulty:
var num = -1
discard parseSaturatedNatural(val, num)
if num notin 1..10:
showError(&"value for {formatOpt(kind, key)} is not between " &
&" 1 to 10: {val}")
setActionOpt(difficulty, some(num))
else:
discard
of actFmt:
Expand Down
15 changes: 14 additions & 1 deletion src/create/create.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import std/[os, strformat]
import std/[options, os, strformat]
import ".."/[cli, helpers, sync/sync, types_track_config]
import "."/[approaches, articles, exercises]

Expand All @@ -13,6 +13,10 @@ proc create*(conf: Conf) =
let msg = &"Both --approach and --article were provided. Please specify only one."
stderr.writeLine msg
quit QuitFailure
if conf.action.difficulty.isSome:
let msg = "The difficulty argument is not supported for approaches"
stderr.writeLine msg
quit QuitFailure
let trackConfigPath = conf.trackDir / "config.json"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be a failure, or is a warning sufficient?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We tend to error for arguments that are not supported.

let trackConfig = parseFile(trackConfigPath, TrackConfig)
let trackExerciseSlugs = getSlugs(trackConfig.exercises, conf, trackConfigPath)
Expand All @@ -36,6 +40,10 @@ proc create*(conf: Conf) =
let msg = "Please specify an exercise to create an article for, using --exercise <slug>"
stderr.writeLine msg
quit QuitFailure
if conf.action.difficulty.isSome:
let msg = "The difficulty argument is not supported for articles"
stderr.writeLine msg
quit QuitFailure
let trackConfigPath = conf.trackDir / "config.json"
let trackConfig = parseFile(trackConfigPath, TrackConfig)
let trackExerciseSlugs = getSlugs(trackConfig.exercises, conf, trackConfigPath)
Expand All @@ -55,6 +63,11 @@ proc create*(conf: Conf) =

createArticle(Slug(conf.action.articleSlug), userExercise, exerciseDir)
elif conf.action.conceptExerciseSlug.len > 0:
if conf.action.difficulty.isSome:
let msg = "The difficulty argument is not supported for concept exercises"
stderr.writeLine msg
quit QuitFailure

createConceptExercise(conf)
elif conf.action.practiceExerciseSlug.len > 0:
createPracticeExercise(conf)
Expand Down
23 changes: 19 additions & 4 deletions src/create/exercises.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import std/[sets, options, os, strformat]
import ".."/[cli, helpers, logger, fmt/track_config, sync/probspecs, sync/sync,
sync/sync_filepaths, sync/sync_metadata, types_exercise_config,
types_track_config, uuid/uuid]
import ".."/[cli, helpers, logger, fmt/exercises, fmt/track_config,
sync/probspecs, sync/sync, sync/sync_common, sync/sync_filepaths,
sync/sync_metadata, types_exercise_config, types_track_config, uuid/uuid]

proc verifyExerciseDoesNotExist(conf: Conf, slug: string): tuple[trackConfig: TrackConfig, trackConfigPath: string, exercise: Slug] =
let trackConfigPath = conf.trackDir / "config.json"
Expand Down Expand Up @@ -53,10 +53,25 @@ proc syncExercise(conf: Conf, slug: Slug,) =
)
discard syncImpl(syncConf)

proc setAuthor(conf: Conf, slug: Slug, trackDir: string, exerciseKind: ExerciseKind) =
let configPath = trackDir / "exercises" / $exerciseKind / $slug / ".meta" / "config.json"
var exerciseConfig = ExerciseConfig.init(exerciseKind, configPath)
let formattedConfig =
case exerciseKind
of ekConcept:
exerciseConfig.c.authors.add conf.action.author
prettyExerciseConfig(exerciseConfig.c, pmFmt)
of ekPractice:
exerciseConfig.p.authors.add conf.action.author
prettyExerciseConfig(exerciseConfig.p, pmFmt)
writeFile(configPath, formattedConfig)

proc createFiles(conf: Conf, slug: Slug, trackConfig: TrackConfig, trackDir: string, exerciseKind: ExerciseKind) =
withLevel(verQuiet):
syncExercise(conf, slug)
syncFiles(trackConfig, conf.trackDir, slug, exerciseKind)
if conf.action.author.len > 0:
setAuthor(conf, slug, trackDir, exerciseKind)

proc createConceptExercise*(conf: Conf) =
var (trackConfig, trackConfigPath, userExercise) = verifyExerciseDoesNotExist(conf, conf.action.conceptExerciseSlug)
Expand Down Expand Up @@ -105,7 +120,7 @@ proc createPracticeExercise*(conf: Conf) =
uuid: $genUuid(),
practices: OrderedSet[string](),
prerequisites: OrderedSet[string](),
difficulty: 1,
difficulty: conf.action.difficulty.get(1),
status: sMissing
)

Expand Down
6 changes: 6 additions & 0 deletions tests/test_binary_create.nim
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ proc main =
""".unindent()
execAndCheck(1, &"{createBase} --concept-exercise=hangman", expectedOutput)

test "concept exercise with difficulty (prints the expected output, and exits with 1)":
const expectedOutput = fmt"""
The difficulty argument is not supported for concept exercises
""".unindent()
execAndCheck(1, &"{createBase} --concept-exercise=bar --difficulty 4", expectedOutput)

test "create concept exercise (creates the exercise files, and exits with 0)":
const expectedOutput = fmt"""
Updating cached 'problem-specifications' data...
Expand Down
Loading