Концепт-вправи - це вправи, покликані навчати конкретних концепцій (програмування). Концепції, яких навчають концепт-вправи, формують силабус. Щоб дізнатися більше про те, як проєктувати силабус, перегляньте документацію про силабус.
Можна швидко створити каркас нової концепт-вправи, виконавши такі команди з кореневого каталогу треку:
bin/fetch-configlet
bin/configlet create --concept-exercise <slug>
Докладніше див. у документації про configlet create
Метадані концепт-вправи визначаються в ключі exercises.concept у файлі config.json. Метадані визначають UUID, слаг вправи та інше.
{
"exercises": {
"concept": [
{
"uuid": "93fbc7cf-3a7e-4450-ad22-e30129c36bb9",
"slug": "cars-assemble",
"name": "Cars, Assemble!",
"concepts": ["if-statements", "numbers"],
"prerequisites": ["basics"]
}
]
}
}
Кожна концепт-вправа має власний каталог у каталозі exercises/concept треку. Назва каталогу концепт-вправи має збігатися з властивістю slug концепт-вправи, визначеною у файлі config.json.
Концепт-вправа має чотири типи файлів:
Ці файли подаються учневі, щоб допомогти пояснити вправу.
.docs/introduction.md: знайомить учня з концепціями, яких навчає вправа (обовʼязковий).docs/instructions.md: містить інструкції до вправи (обовʼязковий).docs/hints.md: містить підказки, що допомагають учневі, коли той застряг у вправі (обовʼязковий)Ці файли не подаються учневі, а використовуються для визначення метаданих вправи.
.meta/config.json: містить метаінформацію про вправу (обовʼязковий).meta/design.md: описує дизайн вправи (обовʼязковий)Ці файли описують підходи до вправи.
.approaches/introduction.md: вступ до найпоширеніших підходів до вправи (необовʼязковий).approaches/config.json: метадані підходів (необовʼязковий).approaches/<approach-slug>/content.md: опис підходу (необовʼязковий).approaches/<approach-slug>/snippet.txt: фрагмент, що демонструє підхід (необовʼязковий)Ці файли описують статті до вправи.
.articles/config.json: метадані статей (необовʼязковий).articles/<article-slug>/content.md: опис статті (необовʼязковий).articles/<article-slug>/snippet.md: фрагмент, що демонструє статтю (необовʼязковий)Файли, специфічні для мови, як-от файли реалізації та тестів. Назви цих файлів залежать від треку.
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 (еталонна реалізація)
├── CarsAssemble.cs (заглушка)
└── CarsAssemblyTests.cs (тести)
Ми надаємо перевагу підходу «оптимістичного злиття» для нових вправ, за якого треки можуть розробляти вправи у стані «робота в процесі». Мінімальний припустимий стан, який пройде перевірку configlet і дозволить злити зміни, такий:
config.json треку з status, установленим у wip..meta/config.json
.docs/introduction.md.docs/instructions.md.docs/hints.md.docs/introduction.md
Призначення: Познайомити учня з концепціями, яких навчає вправа.
Наявність: Обовʼязковий
about.md цієї концепції.Наприклад, вступ до вправи «рядки» міг би описувати рядок тексту (англ. string) просто як «послідовність символів Unicode» або «низку байтів», розповідати користувачам, як створити рядок тексту, і пояснювати, що рядок тексту має методи, які можна використовувати для роботи з ним. Якщо учневі не потрібно розуміти тонших деталей, щоб розвʼязати вправу, такого короткого пояснення (разом із прикладом його синтаксису) має бути достатньо для розвʼязання.
# 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
Призначення: Шаблон, з якого генерується файл introduction.md.
Наявність: Необовʼязковий
Документ introduction.md знайомить учня з концепціями вправи. Кожна концепція також має власний документ introduction.md, який не показують поза контекстом вправи.
Якщо вступ концепції має бути дослівно включений у вступ вправи, можна використати файл introduction.md.tpl. Цей файл дозволяє посилатися на вступи концепцій через заповнювачі: %{concept:<concept-slug>}.
configlet може згенерувати файл introduction.md із файлу-шаблону. У згенерованому файлі заповнювачі концепцій буде замінено вмістом introduction цієї концепції.
Сайт Exercism знає лише про документ introduction.md. Відповідальність за генерацію introduction.md, коли використовується файл-шаблон, лежить на треку.
Треки можуть вирішувати для кожної вправи окремо, використовувати шаблон чи ні. У деяких випадках дослівне використання вступу концепції може бути не найкращим. Завжди варто обирати те, що дає учневі найкращий досвід навчання.
# Introduction
%{concept:variables}
.docs/instructions.md
Призначення: Надати інструкції до вправи.
Наявність: Обовʼязковий
Цей файл поділено на дві частини.
Кожне завдання має відповідати таким вимогам:
## 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),Ми дуже цінуємо безпечність контенту Exercism для всіх, тож часто схиляємося до обережності, вирішуючи, чи доречна та чи інша історія. Ми уважно ставимося до того, що зливаємо, але розуміємо, що важко усвідомлювати, що може здатися проблематичним, тож ми завжди припускаємо добрі наміри й робимо все можливе, щоб помітити будь-які проблеми під час рецензування, не створюючи конфронтації. Якщо є бажання перевірити історію разом із нами, згадайте @exercism/leadership, і ми розглянемо її разом. Ось кілька орієнтирів:
# 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
Призначення: Надати учневі підказки, які допомагають подолати труднощі у вправі.
Наявність: Обовʼязковий
## General.instructions.md (наприклад, ## 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`).Перегляд підказок не вважатиметься «рекомендованим» шляхом, і ми (мʼяко) відраджуватимемо його використання, якщо учень не може просунутися без них. Тож варто зважати, що учень, який їх читає, буде трохи спантеличеним, перевантаженим і, можливо, розчарованим.
# 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
Призначення: Описати дизайн вправи.
Наявність: Обовʼязковий
Цей файл містить інформацію про дизайн вправи, зокрема її мету, навчальні цілі, те, чого не слід навчати, тощо. Цю інформацію можна взяти з відповідного issue на GitHub.
Він існує, щоб поінформувати майбутніх супровідників чи контрибʼюторів про обсяг і обмеження вправи, аби уникнути природної тенденції до ускладнення вправ із часом.
# 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
Призначення: Містить метаінформацію про вправу.
Наявність: Обовʼязковий
Цей файл містить метаінформацію про вправу:
authors: імʼя користувача GitHub автора (авторів) вправи (обовʼязково)
contributors: імʼя користувача GitHub контрибʼютора (контрибʼюторів) вправи (необовʼязково)
forked_from: з якої вправи (вправ) зроблено форк (обовʼязково, якщо вправу форкнуто)files: розташування файлів, використаних у цій вправі, відносно каталогу вправи (обовʼязково)
solution: файл (файли) заглушки (обовʼязково)test: файл (файли) тестів (обовʼязково)exemplar: файл (файли) еталонної реалізації (обовʼязково)editor: інші файли, показані в редакторі лише для читання (необовʼязково)invalidator: файли, зміна яких робить рішення застарілим (необовʼязково)language_versions: вимоги до версії мови (необовʼязково)blurb: короткий опис цієї вправи. Його довжина має бути <= 350. Markdown не підтримується (обовʼязково)source: джерело, на якому ґрунтується ця вправа (необовʼязково)source_url: URL джерела, на якому ґрунтується ця вправа (необовʼязково)representer: метаінформація про те, як репрезентер обробляє цей файл (необовʼязково)
version: ціле число, версія репрезентера, яку слід використати для вправи (обовʼязково, якщо наявний батьківський ключ)icon: слаг іконки (див. повний список іконок). Якщо не вказано, буде використано слаг вправи (необовʼязково)custom: будь-які нестандартні дані, специфічні для вправи. Можна використовувати для налаштування поведінки інструментарію треку для окремої вправи (необовʼязково)Якщо хтось є одночасно і автором, і контрибʼютором, його слід зазначати лише як автора.
{
"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"
}
Припустімо, що користувач FSharpForever написав вправу log-levels для треку F#. PythonProfessor адаптує цю вправу для треку Python. Згодом користувач GladToHelp покращує вправу.
{
"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
}
}
Зауваження:
forked_from був правильний.language_versions - це рядок тексту довільної форми, який треки можуть використовувати й тлумачити як завгодно..approaches/introduction.md
Призначення: Вступ до найпоширеніших підходів до вправи
Наявність: Необовʼязковий
Цей файл описує найпоширеніші підходи до вправи. Докладніше про те, що має бути в цьому файлі, див. у документації.
# 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
Призначення: Метадані підходів
Наявність: Необовʼязковий (обовʼязковий, коли існує вступ до підходів або підхід)
Цей файл містить метаінформацію про підходи до вправи:
introduction: імʼя користувача GitHub автора (авторів) вступу до підходів вправи (необовʼязково)
authors: імʼя користувача GitHub автора (авторів) вступу до підходів вправи (обовʼязково)
contributors: імʼя користувача GitHub контрибʼютора (контрибʼюторів) вступу до підходів вправи (необовʼязково)
approaches: масив, що перелічує докладні підходи (необовʼязково)
uuid: UUID версії 4, який унікально ідентифікує підхід. UUID має бути унікальним як у межах треку, так і серед усіх треків, і ніколи не повинен змінюватисяslug: слаг підходу, рядок тексту в нижньому регістрі у форматі kebab-case. Слаг має бути унікальним серед усіх слагів підходів у межах треку. Його довжина має бути <= 255.title: назва підходу. Її довжина має бути <= 255.blurb: короткий опис цього підходу. Його довжина має бути <= 350. Markdown не підтримується (обовʼязково)authors: імʼя користувача GitHub автора (авторів) підходу до вправи (обовʼязково)
contributors: імʼя користувача GitHub контрибʼютора (контрибʼюторів) підходу до вправи (необовʼязково)
tags: визначає умови, за яких подання повʼязують із підходом (необовʼязково)
all: масив тегів, які всі мають бути присутні в поданні (необовʼязково, окрім випадку, коли any не має елементів)any: масив тегів, принаймні один з яких має бути присутній у поданні (необовʼязково, окрім випадку, коли all не має елементів)not: жоден із тегів не має бути присутній у поданні (необовʼязково){
"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
Призначення: Докладний опис підходу
Наявність: Необовʼязковий (обовʼязковий для підходів)
Цей файл містить докладний опис підходу. Докладніше про те, що має бути в цьому файлі, див. у документації.
# 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
Призначення: Фрагмент, що демонструє підхід
Наявність: Необовʼязковий (обовʼязковий для підходів)
Цей файл містить невеликий фрагмент, що демонструє підхід. Фрагмент показується на сторінці «Dig Deeper» вправи.
Кількість його рядків має бути <= 8.
Докладніше про те, що має бути в цьому файлі, див. у документації.
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
Призначення: Метадані статей
Наявність: Необовʼязковий (обовʼязковий, коли існує стаття)
Цей файл містить метаінформацію про статті до вправи:
articles: масив, що перелічує докладні статті (необовʼязково)
uuid: UUID версії 4, який унікально ідентифікує статтю. UUID має бути унікальним як у межах треку, так і серед усіх треків, і ніколи не повинен змінюватисяslug: слаг статті, рядок тексту в нижньому регістрі у форматі kebab-case. Слаг має бути унікальним серед усіх слагів статей у межах треку. Його довжина має бути <= 255.title: назва статті. Її довжина має бути <= 255.blurb: короткий опис цієї статті. Його довжина має бути <= 350. Markdown не підтримується (обовʼязково)authors: імʼя користувача GitHub автора (авторів) статті до вправи (обовʼязково)
contributors: імʼя користувача GitHub контрибʼютора (контрибʼюторів) статті до вправи (необовʼязково)
{
"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
Призначення: Докладний опис підходу
Наявність: Необовʼязковий (обовʼязковий для підходів)
Цей файл містить докладний опис підходу. Докладніше про те, що має бути в цьому файлі, див. у документації.
# 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
Призначення: Фрагмент, що демонструє підхід
Наявність: Необовʼязковий (обовʼязковий для статей)
Цей файл містить невеликий фрагмент, що демонструє статтю. Фрагмент показується на сторінці «Dig Deeper» вправи.
Кількість його рядків має бути <= 8.
Докладніше про те, що має бути в цьому файлі, див. у документації.
| Method | Mean | Allocated |
| -----: | --------: | --------: |
| Linq | 29.133 ns | 80 B |
| Array | 4.806 ns | - |
Призначення: Надати учням відправну точку.
Наявність: Обовʼязковий
"files.solution" файлу .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
Призначення: Перевірити правильність рішення.
Наявність: Обовʼязковий
instructions.md."files.test" файлу .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
Призначення: Надати цільову реалізацію, до якої має прагнути учень.
Наявність: Обовʼязковий
"files.exemplar" файлу .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
Призначення: Забезпечити можливість запуску тестів.
Наявність: Обовʼязкові, якщо типових файлів недостатньо для запуску тестів
Деякі мови вимагають додаткових файлів для запуску тестів. Прикладом таких файлів є файли проєктів C# і файли package.json Node, без яких запустити тести неможливо.
Деякі файли не є специфічними для окремих вправ, а стосуються натомість всіх вправ. Докладніше див. у документації.
Концепт-вправи слід називати за їхньою історією чи темою, а не за їхніми концепціями.
Хороші приклади назв:
Tim from MarketingLucian's Luscious LasagnaCalculator ConundrumНеприпустимі назви:
Booleans: використовує назву концепції, а не назву історіїExercise #1: вправа не є історією чи темоюКоли робимо форк вправи без суттєвих змін, за можливості використовуймо оригінальну назву.
Кожна вправа також має слаг: нормалізовану версію назви вправи, отриману за такими правилами:
[a-z0-9-]+)two-fer, а не 2-fer)Хороші приклади слагів:
tim-from-marketinglucians-luscious-lasagnacalculator-conundrumНеприпустимі слаги:
TIM-FROM-MARKETING: не використовує нижній регістр (тобто tim-from-marketing)TimFromMarketing: не використовує kebab-case (тобто tim-from-marketing)floating-point-numbers: використовує назву концепції, а не назву історіїЄ різниця в тому, як документація вправи подається учневі під час використання редактора в браузері та CLI. Докладніше див. у цьому документі.
Кожна вправа має супровідну іконку.
Типово показується іконка, назва якої збігається зі слагом вправи.
Це можна змінити, указавши властивість icon у файлі .meta/config.json вправи.
Якщо робимо форк наявної вправи, для неї, ймовірно, вже є іконка. Якщо ні, відкрийте issue в репозиторії website-icons.