コンセプト演習


コンセプト演習は、特定の(プログラミングの)概念を教えるために設計された演習です。 コンセプト演習で教える概念は、_シラバス_を構成します。 シラバスの設計方法の詳細は、シラバスのドキュメントを参照してください。

Note

トラックのルートディレクトリで次のコマンドを実行すると、新しいコンセプト演習の雛形をすばやく作成できます:

bin/fetch-configlet
bin/configlet create --concept-exercise <slug>

詳細は、configlet createのドキュメントを参照してください。

メタデータ

コンセプト演習のメタデータは、config.jsonファイルのexercises.conceptキーで定義します。このメタデータでは、演習のUUIDやスラグなどが定義されます。

例

{
  "exercises": {
    "concept": [
      {
        "uuid": "93fbc7cf-3a7e-4450-ad22-e30129c36bb9",
        "slug": "cars-assemble",
        "name": "Cars, Assemble!",
        "concepts": ["if-statements", "numbers"],
        "prerequisites": ["basics"]
      }
    ]
  }
}

ファイル

各コンセプト演習は、トラックのexercises/conceptディレクトリの中にそれぞれ専用のディレクトリを持ちます。コンセプト演習のディレクトリ名は、config.jsonファイルで定義するコンセプト演習のslugプロパティと一致している必要があります。

コンセプト演習のファイルには、4つの種類があります。

ドキュメントファイル

これらのファイルは、演習の説明のために学習者に表示されます。

  • .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 (exemplar implementation)
        ├── CarsAssemble.cs (stub implementation)
        └── CarsAssemblyTests.cs (tests)

有効な最小構成

新しい演習には「楽観的マージ」という方針を採っており、トラックは「作業中」の状態で演習を開発できます。configletを通過し、マージできる最小の有効な状態は次のとおりです。

  • トラックのconfig.jsonに有効なエントリーがあり、statusがwipに設定されていること。
  • 有効な.meta/config.jsonファイルがあること。
  • 次のファイルが存在すること(空でもかまいません):
    • .docs/introduction.md
    • .docs/instructions.md
    • .docs/hints.md
    • スタブ実装
    • テストファイル

ファイル:.docs/introduction.md

目的: 演習で学習者に教える概念を紹介します。

有無: 必須

  • 提供する情報は、学習者が自分で解答を導き出せるだけの、ちょうどよい文脈にとどめるべきです。
  • 概念の基本を理解し演習を解くために必要な情報だけを提供します。それ以外の情報は、その概念のabout.mdドキュメントに譲ります。
  • リンクは、使うとしても控えめにします。再帰のような複雑なトピックを説明するリンクは役立つこともありますが、ほとんどの概念では、リンクは必要以上の情報を与えてしまいます。そのため、その場で簡潔に説明することを心がけましょう。
  • 学習者が簡単に情報を検索できるように、適切な専門用語を使います。
  • コード例は、新しい構文を紹介するときだけに使います(学習者が構文の例をウェブで探す必要がないようにするためです)。それ以外の場合は、コードの代わりに説明やリンクを示します。

例として、「strings」演習のイントロダクションでは、文字列を『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

目的: 演習の指示を提供します。

有無: 必須

このファイルは2つの部分に分かれます。

  1. 前半では、演習の「ストーリー」や「テーマ」を説明します。通常、コード例は含めません。
  2. 後半では、学習者が何をする必要があるかを、1つ以上のタスクの形で明確に指示します。

各タスクは、次の基準に従う必要があります。

  • 番号で始まる第2レベルの見出しから始めます(例:## 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という見出しの下にMarkdownのリストとして書けます。
  • タスク固有のヒントは、instructions.mdのタスク見出しと一致する見出しの下に、Markdownのリストとして書きます(例:## 2. Do Y)。
  • 一般的なヒントがない場合や、特定のタスクのヒントがない場合は、その見出しを省略します。どの見出しにも、必ずMarkdownのリストを続けます。
  • タスク固有のヒントは、一般的なヒントよりも学習者の行き詰まりを解消しやすいので、一般的なヒントより優先します。
  • タスクの見出しには、そのタスクの_何を_書き、_どのように_は書きません。
  • タスクの見出しは、文頭のみを大文字にする通常の表記にします(例:## 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

ファイル:.meta/design.md

目的: 演習の設計を説明します。

有無: 必須

このファイルには、演習の設計に関する情報が入ります。目的、指導目標、教えないことなどが含まれます。これらの情報は、その演習に対応するGitHub issueから取り出せます。

これは、将来のメンテナーやコントリビューターに演習の範囲と限界を伝え、時間の経過とともに演習が複雑になっていく自然な流れを避けるために存在します。

例

# 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:この演習で使うファイルの場所。演習のディレクトリからの相対パスで指定します(必須)
  • language_versions:言語のバージョン要件(任意)
  • blurb:この演習の簡単な説明。長さは350文字以下でなければなりません。Markdownは_サポートされていません_(必須)
  • source:この演習の基になった出典(任意)
  • source_url:この演習の基になった出典のURL(任意)
  • representer:representerがこのファイルをどのように処理するかに関するメタ情報(任意)
    • version:この演習で使うrepresenterのバージョンを表す整数(親キーがある場合は必須)
  • 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がF#トラック向けにlog-levelsという演習を書いたとします。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
  }
}

次の点に注意してください。

  • authorsとcontributorsの順序は重要ではなく、意味を持ちません。
  • 演習をフォークする場合は、元の作者やコントリビューターを記載しないでください。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:アプローチを一意に識別するV4 UUID。UUIDはトラック内でも全トラックを通じても一意でなければならず、決して変更してはいけません。
    • slug:アプローチのスラグ。小文字のケバブケースの文字列です。スラグはトラック内のすべてのアプローチのスラグの中で一意でなければなりません。長さは255文字以下でなければなりません。
    • title:アプローチのタイトル。長さは255文字以下でなければなりません。
    • blurb:このアプローチの簡単な説明。長さは350文字以下でなければなりません。Markdownは_サポートされていません_(必須)
    • authors:演習のアプローチの作者のGitHubユーザー名(必須)
      • レビューによって演習のアプローチが大きく変わった場合(「一緒に作り上げた」と感じられるほど)は、レビュアーも含めます。
    • contributors:演習のアプローチのコントリビューターのGitHubユーザー名(任意)
      • レビューが有意義であったり、実行可能な指摘を含んだり、実際に反映されたりした場合は、レビュアーも含めます。
    • tags:提出物がどのような条件でアプローチに紐づけられるかを指定します(任意)。
      • all:提出物にすべて含まれていなければならないタグの配列(任意。ただしanyに要素がない場合を除く)
      • any:少なくとも1つが提出物に含まれていなければならないタグの配列(任意。ただし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:記事を一意に識別するV4 UUID。UUIDはトラック内でも全トラックを通じても一意でなければならず、決して変更してはいけません。
    • slug:記事のスラグ。小文字のケバブケースの文字列です。スラグはトラック内のすべての記事のスラグの中で一意でなければなりません。長さは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 |         - |

ファイル:スタブ実装

目的: 学習者に開始点を提供します。

有無: 必須

  • 学習者がどこにコードを追加すればよいかわかるように、スタブを設計します。
  • 演習で紹介していない構文については、スタブを定義します。ほとんどの演習では、スタブの関数やメソッドを定義することを意味します。
  • コンパイル言語では、コンパイルできるコードにしておくことを検討しましょう。言語を学び始めた学習者には、コンパイラーのメッセージがわかりにくいことがあるためです。
  • コードはできるだけシンプルにします。
  • 使ってよいのは、その演習またはその前提演習(さらにその前提演習…)で紹介された言語機能だけです。
  • スタブファイルは、ブラウザー内でコーディングするときには学習者に表示され、CLIを使うときには学習者のファイルシステムにダウンロードされます。
  • スタブ実装のファイルへの相対パスは、.meta/config.jsonファイルの"files.solution"キーで指定しなければなりません。

例

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ファイルにある例を使わないようにします。
  • コードはできるだけシンプルにします。
  • 使ってよいのは、その演習の前提演習(さらにその前提演習…)で紹介された言語機能だけです。
  • テストファイルは、ブラウザー内でコーディングするときには学習者に表示され_ません_が、CLIを使うときには学習者のファイルシステムにダウンロード_されます_。
  • テストファイルへの相対パスは、.meta/config.jsonファイルの"files.test"キーで指定しなければなりません。

例

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

ファイル:模範実装

目的: 学習者が目指すべき目標の実装を提供します。

有無: 必須

  • この実装は、学習者に目指してほしい目標のコードです。
  • メンターは、フィードバックを書くときにこのコードを「目標」として見ることになります。
  • 実装で使ってよいのは、その演習またはその前提演習(さらにその前提演習…)で紹介された言語機能だけです。
  • 模範実装ファイルは、ブラウザー内でコーディングするときには学習者に表示され_ず_、CLIを使うときにも学習者のファイルシステムにダウンロードされ_ません_。
  • 模範実装ファイルは、メンターが解答やrepresentationにコメントするときに表示されます。
  • 模範実装のファイルへの相対パスは、.meta/config.jsonファイルの"files.exemplar"キーで指定しなければなりません。

例

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#のプロジェクトファイルやNodeのpackage.jsonファイルで、これらがないとテストを実行できません。

共有ファイル

中には、個々の演習に固有のものではなく、_すべて_の演習に当てはまるファイルもあります。詳細は、ドキュメントを参照してください。

名前の付け方

コンセプト演習には、その概念では_なく_、ストーリーやテーマにちなんだ名前を付けます。

よい名前の例:

  • Tim from Marketing
  • Lucian's Luscious Lasagna
  • Calculator Conundrum

不適切な名前の例:

  • Booleans:ストーリー名ではなく概念名を使っている
  • Exercise #1:演習はストーリーやテーマではない

大きな変更を加えずに演習をフォークする場合は、できれば元の名前を使います。

スラグ

各演習には_スラグ_もあり、これは次のルールで演習名を正規化したものです。

  1. 小文字を使います。
  2. kebab-caseを使います。
  3. ラテン文字と数字、およびハイフンを使います(正規表現:[a-z0-9-]+)
  4. 数字は、特定の理由がない限り、算用数字より綴りで書く方を選びます(例:2-ferよりtwo-fer)

よいスラグの例:

  • tim-from-marketing
  • lucians-luscious-lasagna
  • calculator-conundrum

不適切なスラグの例:

  • TIM-FROM-MARKETING:小文字を使っていない(すなわちtim-from-marketing)
  • TimFromMarketing:kebab-caseを使っていない(すなわちtim-from-marketing)
  • floating-point-numbers:ストーリー名ではなく概念名を使っている

表示

演習のドキュメントは、ブラウザー内エディターを使う場合とCLIを使う場合で、学習者への表示のされ方が異なります。詳細は、こちらのドキュメントを参照してください。

アイコン

各演習には、対応するアイコンがあります。 デフォルトでは、名前が演習のスラグと一致するアイコンが表示されます。 これは、演習の.meta/config.jsonファイルでiconプロパティを指定することで上書きできます。

既存の演習をフォークする場合、その演習用のアイコンがすでにあることがほとんどです。 ない場合は、website-iconsリポジトリでissueを作成してください。