Les exercices d'apprentissage sont des exercices conçus pour enseigner des concepts (de programmation) précis. Les concepts enseignés par les exercices d'apprentissage forment un programme. Pour en savoir plus sur la conception d'un programme, consulte la documentation sur le programme.
Pour créer rapidement la structure d'un nouvel exercice d'apprentissage, exécute les commandes suivantes depuis le répertoire racine du parcours :
bin/fetch-configlet
bin/configlet create --concept-exercise <slug>
Pour en savoir plus, consulte la documentation de configlet create
Les métadonnées d'un exercice d'apprentissage sont définies dans la clé exercises.concept du fichier config.json. Ces métadonnées définissent l'UUID, le slug et d'autres informations de l'exercice.
{
"exercises": {
"concept": [
{
"uuid": "93fbc7cf-3a7e-4450-ad22-e30129c36bb9",
"slug": "cars-assemble",
"name": "Cars, Assemble!",
"concepts": ["if-statements", "numbers"],
"prerequisites": ["basics"]
}
]
}
}
Chaque exercice d'apprentissage possède son propre répertoire dans le répertoire exercises/concept du parcours. Le nom du répertoire de l'exercice d'apprentissage doit correspondre à la propriété slug de l'exercice, telle que définie dans le fichier config.json.
Un exercice d'apprentissage comporte quatre types de fichiers :
Ces fichiers sont présentés à l'apprenant pour l'aider à comprendre l'exercice.
.docs/introduction.md : présente le ou les concepts que l'exercice enseigne à l'apprenant (obligatoire).docs/instructions.md : fournit les instructions de l'exercice (obligatoire).docs/hints.md : fournit des indices à l'apprenant pour l'aider à se débloquer dans un exercice (obligatoire)Ces fichiers ne sont pas présentés à l'apprenant, mais servent à définir les métadonnées de l'exercice.
.meta/config.json : contient des méta-informations sur l'exercice (obligatoire).meta/design.md : décrit la conception de l'exercice (obligatoire)Ces fichiers décrivent les approches de l'exercice.
.approaches/introduction.md : introduction aux approches les plus courantes de l'exercice (facultatif).approaches/config.json : métadonnées des approches (facultatif).approaches/<approach-slug>/content.md : description de l'approche (facultatif).approaches/<approach-slug>/snippet.txt : extrait illustrant l'approche (facultatif)Ces fichiers décrivent les articles de l'exercice.
.articles/config.json : métadonnées des articles (facultatif).articles/<article-slug>/content.md : description de l'article (facultatif).articles/<article-slug>/snippet.md : extrait illustrant l'article (facultatif)Les fichiers propres au langage, comme les fichiers d'implémentation et de tests. Les noms de ces fichiers dépendent du parcours.
exercises
└── concept
└── cars-assemble
├── .approaches
| ├── for-loop
| | ├── content.md
| | └── snippet.txt
| ├── config.json
| └── introduction.md
├── .articles
| ├── performance
| | ├── content.md
| | └── snippet.md
| └── config.json
├── .docs
| ├── introduction.md
| ├── instructions.md
| └── hints.md
├── .meta
| ├── config.json
| ├── design.md
| └── Exemplar.cs (implémentation exemplaire)
├── CarsAssemble.cs (implémentation stub)
└── CarsAssemblyTests.cs (tests)
Nous privilégions une approche de « fusion optimiste » pour les nouveaux exercices, où les parcours peuvent développer des exercices à l'état de « travail en cours ». L'état minimal valide, qui passera configlet et permettra de fusionner, est le suivant :
config.json du parcours, avec le status défini sur wip..meta/config.json valide.docs/introduction.md.docs/instructions.md.docs/hints.md.docs/introduction.md
Objectif : présenter le ou les concepts que l'exercice enseigne à l'apprenant.
Présence : obligatoire
about.md du concept.À titre d'exemple, l'introduction d'un exercice sur les strings pourrait décrire une string comme une simple « séquence de caractères Unicode » ou une « série d'octets », expliquer comment créer une string et préciser qu'elle possède des méthodes servant à la manipuler. À moins que l'apprenant ait besoin de comprendre des détails plus subtils pour résoudre l'exercice, ce type d'explication brève (avec un exemple de sa syntaxe) devrait suffire à l'apprenant pour résoudre l'exercice.
# Introduction
There are two primary ways to assign objects to names in Ruby - using variables or constants. Variables are always written in snake case. A variable can reference different objects over its lifetime. For example, `my_first_variable` can be defined and redefined many times using the `=` operator:
```ruby
my_first_variable = 1
my_first_variable = "Some string"
my_first_variable = SomeComplexObject.new
```
.docs/introduction.md.tpl
Objectif : servir de modèle pour générer un fichier introduction.md.
Présence : facultatif
Le document introduction.md présente les concepts de l'exercice à l'apprenant. Chaque concept possède également son propre document introduction.md, qui n'est pas affiché en dehors du contexte d'un exercice.
Si l'introduction du concept doit être reprise telle quelle dans l'introduction de l'exercice, un fichier introduction.md.tpl peut être utilisé. Ce fichier permet de référencer les introductions des concepts au moyen d'espaces réservés : %{concept:<concept-slug>}.
configlet peut générer un fichier introduction.md à partir d'un fichier modèle. Dans le fichier généré, les espaces réservés aux concepts sont remplacés par le contenu introduction du concept.
Le site web d'Exercism ne connaît que le document introduction.md. C'est au parcours qu'il incombe de générer le introduction.md lorsqu'un fichier modèle est utilisé.
Chaque parcours peut décider, exercice par exercice, d'utiliser un modèle ou non. Dans certains cas, reprendre telle quelle l'introduction du concept n'est peut-être pas optimal. Choisis toujours ce qui offre la meilleure expérience d'apprentissage à l'apprenant.
# Introduction
%{concept:variables}
.docs/instructions.md
Objectif : fournir les instructions de l'exercice.
Présence : obligatoire
Ce fichier se divise en deux parties.
Chaque tâche doit respecter les règles suivantes :
## 1. Do X, ## 2. Do Y).## 1. Check if an appointment has already passed).Implement method X(...) that takes an A and returns a Z),Nous tenons beaucoup à ce que le contenu d'Exercism soit sûr pour tout le monde, et nous choisissons donc souvent la prudence lorsqu'il s'agit de décider si une histoire est appropriée ou non. Nous sommes attentifs à ce que nous fusionnons, mais nous savons qu'il est difficile d'avoir conscience de ce qui peut être perçu comme problématique ; nous supposerons donc toujours que tu agis de bonne foi et ferons de notre mieux pour repérer les problèmes lors de la relecture, sans confrontation. Si tu souhaites vérifier une histoire avec nous, mentionne @exercism/leadership et nous l'examinerons ensemble. Voici quelques repères :
# Instructions
In this exercise you're going to write some code to help you cook a brilliant lasagna from your favorite cooking book.
## 1. Calculate the remaining oven time in minutes
Define the `Lasagna#remaining_minutes_in_oven` method that takes the actual minutes the lasagna has been in the oven as a parameter and returns how many minutes the lasagna still has to remain in the oven, based on the expected oven time in minutes from the previous task.
```ruby
lasagna = Lasagna.new
lasagna.remaining_minutes_in_oven(30)
# => 10
```
.docs/hints.md
Objectif : fournir des indices à l'apprenant pour l'aider à se débloquer dans un exercice.
Présence : obligatoire
## General.instructions.md (par exemple ## 2. Do Y).## 2. Check if a book can be borrowed).Implement the 'canBorrowBook' function to check if a book can be borrowed. The function takes a book as its parameter and returns `true` if the book has not already been borrowed; otherwise, return `false`).Consulter les indices n'est pas un chemin « recommandé » et nous décourageons (gentiment) d'y recourir, sauf si l'apprenant ne peut pas avancer sans. Il faut donc garder à l'esprit que l'apprenant qui les lit sera un peu désorienté ou submergé, et peut-être frustré.
# Hints
## General
- You need to define a [constant][constant] which should contain the [integer][integers] value specified in the recipe.
## 1. Calculate the remaining oven time in minutes
- You need to define a [method][methods] with a single parameter for the actual time so far.
[constants]: https://www.rubyguides.com/2017/07/ruby-constants/
[integers]: https://ruby-doc.org/core-2.7.0/Integer.html
[methods]: https://launchschool.com/books/ruby/read/methods
Objectif : décrire la conception de l'exercice.
Présence : obligatoire
Ce fichier contient des informations sur la conception de l'exercice : son objectif, ses objectifs pédagogiques, ce qu'il ne faut pas enseigner, etc. Ces informations peuvent être reprises depuis l'issue GitHub correspondante de l'exercice.
Il existe pour informer les futurs mainteneurs ou contributeurs de la portée et des limites d'un exercice, afin d'éviter la tendance naturelle à rendre les exercices plus complexes avec le temps.
# Design
## Goal
The goal of this exercise is to teach the student the basics of programming in Ruby.
## Learning objectives
- Know what a variable is.
- Know how to define a variable.
- Know how to update a variable.
## Out of scope
- Memory and performance characteristics.
- Method overloads.
## Concepts
The Concepts this exercise unlocks are:
- `basics`: know what a variable is; know how to define a variable; know how to update a variable.
## Prerequisites
There are no prerequisites.
.meta/config.json
Objectif : contenir des méta-informations sur l'exercice.
Présence : obligatoire
Ce fichier contient des méta-informations sur l'exercice :
authors : le ou les noms d'utilisateur GitHub de l'auteur ou des auteurs de l'exercice (obligatoire)
contributors : le ou les noms d'utilisateur GitHub du ou des contributeurs de l'exercice (facultatif)
forked_from : l'exercice ou les exercices dont il est dérivé (obligatoire si l'exercice est dérivé d'un autre)files : les emplacements des fichiers utilisés dans cet exercice, relatifs au répertoire de l'exercice (obligatoire)
solution : le ou les fichiers d'implémentation stub (obligatoire)test : le ou les fichiers de tests (obligatoire)exemplar : le ou les fichiers d'implémentation exemplaire (obligatoire)editor : les autres fichiers affichés en lecture seule dans l'éditeur (facultatif)invalidator : les fichiers qui, lorsqu'ils sont modifiés, rendent une solution obsolète (facultatif)language_versions : les versions de langage requises (facultatif)blurb : une brève description de cet exercice. Sa longueur doit être <= 350. Markdown n'est pas pris en charge (obligatoire)source : la source sur laquelle cet exercice est basé (facultatif)source_url : l'URL de la source sur laquelle cet exercice est basé (facultatif)representer : les méta-informations liées à la façon dont le representer traite ce fichier (facultatif)
version : un entier indiquant la version du representer à utiliser pour l'exercice (obligatoire si la clé parente est présente)icon : le slug de l'icône (voir la liste complète des icônes). S'il n'est pas spécifié, le slug de l'exercice sera utilisé (facultatif)custom : des données non standard propres à l'exercice. Permet de personnaliser le comportement de l'outillage du parcours pour chaque exercice (facultatif)Si une personne est à la fois auteur et contributeur, ne la liste que comme auteur.
{
"authors": ["FSharpForever"],
"files": {
"solution": ["Lasagna.fs"],
"test": ["LasagnaTests.fs"],
"exemplar": [".meta/Exemplar.fs"]
},
"blurb": "Learn the basics of F# by cooking Lucian's Luscious Lasagna"
}
Supposons que l'utilisateur FSharpForever ait écrit un exercice appelé log-levels pour le parcours F#. PythonProfessor adapte l'exercice pour le parcours Python. Plus tard, l'utilisateur GladToHelp améliore l'exercice.
{
"authors": ["PythonProfessor"],
"contributors": ["GladToHelp"],
"files": {
"solution": ["log_levels.py"],
"test": ["log_levels_test.py"],
"exemplar": [".meta/exemplar.py"],
"editor": ["test_helper.py"]
},
"forked_from": ["fsharp/log-levels"],
"language_versions": ">=3.7",
"blurb": "Learn how to work with strings by processing log lines.",
"source": "Wikipedia",
"source_url": "https://en.wikipedia.org/wiki/Log_file",
"representer": {
"version": 2
},
"icon": "logs",
"custom": {
"parallel": true
}
}
À noter que :
forked_from est correct.language_versions est une string de forme libre que les parcours peuvent utiliser et interpréter comme ils le souhaitent..approaches/introduction.md
Objectif : présenter les approches les plus courantes de l'exercice
Présence : facultatif
Ce fichier décrit les approches les plus courantes de l'exercice. Consulte la documentation pour savoir ce que ce fichier doit contenir.
# Introduction
The key to this exercise is to deal with C# strings being immutable, which means that a `string`'s value cannot be changed.
Therefore, to reverse a string you'll need to create a _new_ `string`.
## Using LINQ
```csharp
public static string Reverse(string input)
{
return new string(input.Reverse().ToArray());
}
```
For more information, check the [LINQ approach][approach-linq].
## Which approach to use?
If readability is your primary concern (and it usually should be), the LINQ-based approach is hard to beat.
.approaches/config.json
Objectif : les métadonnées des approches
Présence : facultatif (obligatoire lorsqu'une introduction d'approche ou une approche existe)
Ce fichier contient des méta-informations sur les approches de l'exercice :
introduction : le ou les noms d'utilisateur GitHub du ou des auteurs de l'introduction des approches de l'exercice (facultatif)
authors : le ou les noms d'utilisateur GitHub du ou des auteurs de l'introduction des approches de l'exercice (obligatoire)
contributors : le ou les noms d'utilisateur GitHub du ou des contributeurs de l'introduction des approches de l'exercice (facultatif)
approaches : un tableau listant les approches détaillées (facultatif)
uuid : un UUID V4 qui identifie l'approche de façon unique. L'UUID doit être unique au sein du parcours comme sur l'ensemble des parcours, et ne doit jamais changerslug : le slug de l'approche, une string en minuscules au format kebab-case. Le slug doit être unique parmi tous les slugs d'approche du parcours. Sa longueur doit être <= 255.title : le titre de l'approche. Sa longueur doit être <= 255.blurb : une brève description de cette approche. Sa longueur doit être <= 350. Markdown n'est pas pris en charge (obligatoire)authors : le ou les noms d'utilisateur GitHub du ou des auteurs de l'approche (obligatoire)
contributors : le ou les noms d'utilisateur GitHub du ou des contributeurs de l'approche (facultatif)
tags : précisent les conditions dans lesquelles une soumission est liée à une approche. (facultatif)
all : un tableau de tags qui doivent tous être présents sur une soumission (facultatif, sauf si any n'a aucun élément)any : un tableau de tags dont au moins un doit être présent sur une soumission (facultatif, sauf si all n'a aucun élément)not : aucun des tags ne doit être présent sur une soumission (facultatif){
"introduction": {
"authors": ["erikschierboom"]
},
"approaches": [
{
"uuid": "448fb2b4-18ab-4e55-aa54-ad4ed6d5f7f6",
"slug": "span",
"title": "Use Span<T>",
"blurb": "Use Span<T> to efficiently reverse a string.",
"authors": ["erikschierboom"]
}
]
}
.approaches/<approach-slug>/content.md
Objectif : une description détaillée de l'approche
Présence : facultatif (obligatoire pour les approches)
Ce fichier contient une description détaillée de l'approche. Consulte la documentation pour savoir ce que ce fichier doit contenir.
# Span
```csharp
Span<char> chars = stackalloc char[input.Length];
for (var i = 0; i < input.Length; i++)
{
chars[input.Length - 1 - i] = input[i];
}
return new string(chars);
```
This `Span<T>` approach uses a `for` loop.
.approaches/<approach-slug>/snippet.txt
Objectif : un extrait illustrant l'approche
Présence : facultatif (obligatoire pour les approches)
Ce fichier contient un petit extrait qui illustre l'approche. Cet extrait est affiché sur la page « Creuse plus loin » de l'exercice.
Son nombre de lignes doit être <= 8.
Consulte la documentation pour savoir ce que ce fichier doit contenir.
Span<char> chars = stackalloc char[input.Length];
for (var i = 0; i < input.Length; i++)
{
chars[input.Length - 1 - i] = input[i];
}
return new string(chars);
.article/config.json
Objectif : les métadonnées des articles
Présence : facultatif (obligatoire lorsqu'un article existe)
Ce fichier contient des méta-informations sur les articles de l'exercice :
articles : un tableau listant les articles détaillés (facultatif)
uuid : un UUID V4 qui identifie l'article de façon unique. L'UUID doit être unique au sein du parcours comme sur l'ensemble des parcours, et ne doit jamais changerslug : le slug de l'article, une string en minuscules au format kebab-case. Le slug doit être unique parmi tous les slugs d'article du parcours. Sa longueur doit être <= 255.title : le titre de l'article. Sa longueur doit être <= 255.blurb : une brève description de cet article. Sa longueur doit être <= 350. Markdown n'est pas pris en charge (obligatoire)authors : le ou les noms d'utilisateur GitHub du ou des auteurs de l'article (obligatoire)
contributors : le ou les noms d'utilisateur GitHub du ou des contributeurs de l'article (facultatif)
{
"articles": [
{
"uuid": "6db71962-62d5-448b-a980-c20ae41013ed",
"slug": "performance",
"title": "Optimizing performance",
"blurb": "Explore how to most efficiently reverse a string and what the trade-offs are.",
"authors": ["erikschierboom"]
}
]
}
.articles/<article-slug>/content.md
Objectif : une description détaillée de l'approche
Présence : facultatif (obligatoire pour les approches)
Ce fichier contient une description détaillée de l'approche. Consulte la documentation pour savoir ce que ce fichier doit contenir.
# Performance
In this document, we'll find out which approach is the most performant one.
## Benchmark results
| Method | Mean | Error | StdDev | Median | Allocated |
| -----: | --------: | --------: | --------: | --------: | --------: |
| Linq | 29.133 ns | 0.5865 ns | 0.5486 ns | 28.984 ns | 80 B |
| Array | 4.806 ns | 0.4999 ns | 1.4739 ns | 3.967 ns | - |
.articles/<article-slug>/snippet.txt
Objectif : un extrait illustrant l'approche
Présence : facultatif (obligatoire pour les articles)
Ce fichier contient un petit extrait qui illustre l'article. Cet extrait est affiché sur la page « Creuse plus loin » de l'exercice.
Son nombre de lignes doit être <= 8.
Consulte la documentation pour savoir ce que ce fichier doit contenir.
| Method | Mean | Allocated |
| -----: | --------: | --------: |
| Linq | 29.133 ns | 80 B |
| Array | 4.806 ns | - |
Objectif : fournir un point de départ aux apprenants.
Présence : obligatoire
"files.solution" du fichier .meta/config.json.class Lasagna
def remaining_minutes_in_oven(actual_minutes_in_oven)
raise NotImplementedError, 'Please implement the Lasagna#remaining_minutes_in_oven method'
end
def preparation_time_in_minutes(layers)
raise NotImplementedError, 'Please implement the Lasagna#preparation_time_in_minutes method'
end
end
Objectif : vérifier l'exactitude d'une solution.
Présence : obligatoire
instructions.md."files.test" du fichier .meta/config.json.require 'minitest/autorun'
require_relative 'lasagna'
class LasagnaTest < Minitest::Test
def test_remaining_minutes_in_oven
assert_equal 15, Lasagna.new.remaining_minutes_in_oven(25)
end
def test_preparation_time_in_minutes_with_one_layer
assert_equal 2, Lasagna.new.preparation_time_in_minutes(1)
end
def test_preparation_time_in_minutes_with_multiple_layers
assert_equal 8, Lasagna.new.preparation_time_in_minutes(4)
end
end
Objectif : fournir l'implémentation cible que l'apprenant doit viser.
Présence : obligatoire
"files.exemplar" du fichier .meta/config.json.class Lasagna
EXPECTED_MINUTES_IN_OVEN = 40
PREPARATION_MINUTES_PER_LAYER = 2
def remaining_minutes_in_oven(actual_minutes_in_oven)
EXPECTED_MINUTES_IN_OVEN - actual_minutes_in_oven
end
def preparation_time_in_minutes(layers)
layers * PREPARATION_MINUTES_PER_LAYER
end
end
Objectif : garantir que les tests peuvent s'exécuter.
Présence : obligatoire si les fichiers par défaut ne suffisent pas à exécuter les tests
Certains langages nécessitent des fichiers supplémentaires pour que les tests s'exécutent. C'est par exemple le cas des fichiers de projet C# et des fichiers package.json de Node, sans lesquels il est impossible d'exécuter les tests.
Certains fichiers ne sont pas propres à un exercice en particulier, mais s'appliquent à tous les exercices. Consulte la documentation pour en savoir plus.
Les exercices d'apprentissage doivent être nommés d'après leur histoire ou leur thème, et non d'après leur ou leurs concepts.
Bons exemples de noms :
Tim from MarketingLucian's Luscious LasagnaCalculator ConundrumNoms interdits :
Booleans : utilise un nom de concept, pas un nom d'histoireExercise #1 : un exercice n'est pas une histoire ou un thèmeLorsque tu dérives un exercice sans changements majeurs, utilise le nom d'origine quand c'est possible.
Chaque exercice possède également un slug, qui est la version normalisée du nom de l'exercice selon les règles suivantes :
kebab-case.[a-z0-9-]+)two-fer plutôt que 2-fer)Bons exemples de slugs :
tim-from-marketinglucians-luscious-lasagnacalculator-conundrumSlugs interdits :
TIM-FROM-MARKETING : n'utilise pas les minuscules (c'est-à-dire tim-from-marketing)TimFromMarketing : n'utilise pas le format kebab-case (c'est-à-dire tim-from-marketing)floating-point-numbers : utilise un nom de concept, pas un nom d'histoireLa façon dont la documentation d'un exercice est présentée à l'apprenant diffère selon qu'il utilise l'éditeur en ligne ou la CLI. Consulte ce document pour en savoir plus.
Chaque exercice possède une icône associée.
Par défaut, l'icône affichée est celle dont le nom correspond au slug de l'exercice.
Tu peux la remplacer en spécifiant la propriété icon dans le fichier .meta/config.json de l'exercice.
Si tu dérives un exercice existant, il existe probablement déjà une icône pour cet exercice. Sinon, ouvre une issue dans le dépôt website-icons.