プラクティス演習


プラクティス演習は、学習者がそれまでに学んだ概念を活かしながら、自由な問題を解けるように設計された演習です。

トラックに初めてのプラクティス演習を追加してみませんか? プラクティス演習を追加するドキュメントを確認するか、以下の解説動画をご覧ください👇

Note

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

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

詳しくは、configlet createのドキュメントをご覧ください

メタデータ

プラクティス演習のメタデータは、config.jsonファイルのexercises.practiceキーで定義します。メタデータには、演習のUUIDやslugなどが定義されます。

例

{
  "exercises": {
    "practice": [
      {
        "uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
        "slug": "leap",
        "name": "Leap",
        "practices": ["if-statements", "numbers", "operator-precedence"],
        "prerequisites": ["if-statements", "numbers"],
        "difficulty": 1
      }
    ]
  }
}

practices

practicesキーには、このプラクティス演習で学習者が積極的に練習できる概念のslugを列挙します。

  • これらはUIでは「Practice this Concept in: TwoFer, Leap, etc」のように表示されます。
  • 各概念を練習できる演習を3〜8個選ぶようにしましょう。
  • ある概念の基本を練習できる演習を少なくとも2つ選ぶようにしましょう。
  • なかにはstringsのように非常によく使われる概念もあります。その場合は、その概念について面白い視点で考えさせる、良質な演習をいくつか選ぶことをおすすめします。たとえば、UTF-8や文字列の連結、文字の列挙などを必要とする演習は、どれも良い例です。

prerequisites

prerequisitesキーには、このプラクティス演習に取り組むために学習者が完了していなければならない概念を列挙します。

  • これらはUIでは「Learn Strings to unlock TwoFer」のように表示されます。
  • 学習者が少なくとも1つの慣用的な方法でその演習を解けるようになるために、身につけておく必要のある概念をすべて含めるようにします。たとえば、RubyのTwoFer演習では、前提条件にstrings、optional-params、implicit-returnが含まれるかもしれません。
  • loopsやrecursionで解ける演習のように、別の概念を使って解答できる演習もあります。その場合メンテナーは、学習者のトラックでの歩みを考えながら、その演習をアンロックするのに使いたい1つの方法を選びます。たとえば先ほどのループと再帰の例では、この演習をloopsの早い段階の練習に良いと考えるかもしれませんし、再帰を教えるために後回しにしたいと考えるかもしれません。アナライザーを使って、別の方法を試すよう学習者に促すこともできます。「ループで解けましたね。よかったら、再帰を使った解き方も試してみてください。」

ファイル

各プラクティス演習は、トラックのexercises/practiceディレクトリ内にそれぞれ専用のディレクトリを持ちます。プラクティス演習のディレクトリ名は、config.jsonファイルで定義されている演習のslugプロパティと一致していなければなりません。

プラクティス演習には4種類のファイルがあります:

ドキュメントファイル

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

  • .docs/introduction.md: 演習の舞台設定と背景を紹介します(任意)
  • .docs/introduction.append.md: 既存のイントロダクションの後ろに追加する補足のイントロダクションテキストです(任意)
  • .docs/instructions.md: 演習の指示を提供します(必須)
  • .docs/instructions.append.md: 既存の指示の後ろに追加する補足テキストです(任意)
  • .docs/hints.md: 演習で行き詰まった学習者を助けるヒントを提供します(任意)

メタデータファイル

これらのファイルは学習者には提示されず、演習のメタデータを定義するために使われます。

  • .meta/config.json: 演習に関するメタ情報を含みます(必須)
  • .meta/design.md: 演習の設計を説明します(任意)
  • .meta/tests.toml: どのテストが実装されているかに関する情報を含みます(任意)

アプローチファイル

これらのファイルは、演習のアプローチを説明します。

  • .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
└── practice
    └── isogram
        ├── .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
        |   ├── tests.toml
        |   └── Example.cs(実装例)
        ├── Isogram.cs(スタブ実装)
        └── IsogramTests.cs(テスト)

ファイル: .docs/introduction.md

目的: 演習の舞台設定と背景を学習者に紹介します。

要否: 演習がintroduction.mdファイルを持つProblem Specificationsの演習を実装している場合は必須

演習がProblem Specificationsの演習を実装している場合、このファイルの内容はProblem Specificationsの演習のintroduction.mdファイルと一致している必要があります。configletには、このファイルの内容を自動的に同期する機能があります。

演習がProblem Specificationsの演習に基づいて_いない_場合は、次の点を検討してください:

Exercismでは、コンテンツを誰にとっても安全なものにすることを重視しています。そのため、ストーリーが適切かどうかを判断するときは、慎重な側に倒すことがよくあります。マージする内容には気を配っていますが、何が問題だと捉えられうるかを知るのは難しいものです。そこで、良識をもって行動していることを常に前提とし、レビューで問題があれば、対立的にならない形で見つけられるよう最善を尽くします。ストーリーについて確認したい場合は、@exercism/leadershipにメンションしてください。一緒に確認しましょう。以下はいくつかの指針です:

  • ストーリーが誰にとっても親しみやすく、誰にでも理解できるものになるように心がけましょう。ストーリーに内輪ネタや地域のスラングが含まれる場合は、別の言い回しを考えてみましょう。
  • 誰にとっても排他的でない例を書くように心がけましょう。たとえば、さまざまな文化の名前や、男女混合の名前を使うことを検討しましょう。
  • 身近に、そのストーリーを不快に思う人がいるかどうか、自問してみましょう。もし心当たりがあるなら、それを避けるために変更を検討しましょう。

例

# Introduction

Bob is a lackadaisical teenager. In conversation, his responses are very limited.

ファイル: .docs/introduction.append.md

目的: 既存のイントロダクションの後ろに追加する補足のイントロダクションテキストです。

要否: 任意

まれなケースですが、演習のintroduction.mdファイルに内容を追加したいことがあります。たとえば、既存の指示ではカバーされていないテストを演習が実装している場合などです。

Bobに非ASCIIメッセージを扱わせたくないトラックでは、次のように追記するかもしれません:

# Introduction append

## Note

As part of his teenage rebellion, Bob has decided to only communicate using ASCII.

appendファイルはH1見出しで始める必要があります。 この見出しは表示されませんが、それでも存在している必要があります。 H1見出しの後にはH2見出しが続くことが多く、これが汎用的な内容とトラック固有の内容を分ける助けになります。

ファイル: .docs/instructions.md

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

要否: 必須

演習がProblem Specificationsの演習を実装している場合、このファイルの内容はProblem Specificationsの演習のinstructions.mdファイル(instructions.mdファイルがない場合はdescription.mdファイル)と一致している必要があります。configletには、このファイルの内容を自動的に同期する機能があります。

演習がProblem Specificationsの演習に基づいて_いない_場合は、次の点を検討してください:

Exercismでは、コンテンツを誰にとっても安全なものにすることを重視しています。そのため、ストーリーが適切かどうかを判断するときは、慎重な側に倒すことがよくあります。マージする内容には気を配っていますが、何が問題だと捉えられうるかを知るのは難しいものです。そこで、良識をもって行動していることを常に前提とし、レビューで問題があれば、対立的にならない形で見つけられるよう最善を尽くします。ストーリーについて確認したい場合は、@exercism/leadershipにメンションしてください。一緒に確認しましょう。以下はいくつかの指針です:

  • ストーリーが誰にとっても親しみやすく、誰にでも理解できるものになるように心がけましょう。ストーリーに内輪ネタや地域のスラングが含まれる場合は、別の言い回しを考えてみましょう。
  • 誰にとっても排他的でない例を書くように心がけましょう。たとえば、さまざまな文化の名前や、男女混合の名前を使うことを検討しましょう。
  • 身近に、そのストーリーを不快に思う人がいるかどうか、自問してみましょう。もし心当たりがあるなら、それを避けるために変更を検討しましょう。

例

# Instructions

Bob answers 'Sure.' if you ask him a question, such as "How are you?".

He answers 'Whoa, chill out!' if you YELL AT HIM (in all capitals).

He answers 'Calm down, I know what I'm doing!' if you yell a question at him.

He says 'Fine. Be that way!' if you address him without actually saying anything.

He answers 'Whatever.' to anything else.

ファイル: .docs/instructions.append.md

目的: 既存の指示の後ろに追加する補足の指示テキストです。

要否: 任意

まれなケースですが、演習のinstructions.mdファイルに内容を追加したいことがあります。たとえば、既存の指示ではカバーされていないテストを演習が実装している場合などです。

# Instructions append

## Note

Bob's conversational partner is a purist when it comes to written communication and always follows normal rules regarding sentence punctuation in English.

appendファイルはH1見出しで始める必要があります。 この見出しは表示されませんが、それでも存在している必要があります。 H1見出しの後にはH2見出しが続くことが多く、これが汎用的な内容とトラック固有の内容を分ける助けになります。

ファイル: .docs/hints.md

目的: 演習で行き詰まった学習者を助けるヒントを提供します。

要否: 任意

  • 学習者が行き詰まると、ヒントをリクエストするボタンをクリックできるようになります。クリックすると、ファイルの該当部分が表示されます。
  • ヒントは、見出しの下に箇条書きで書きます。
  • ヒントは、ほとんどどの学習者でも先に進めるようにするのに十分な内容にします。
  • ヒントでは解答そのものを書かず、解答を説明しているリソースを示すようにします(たとえば、使うべき関数のドキュメントにリンクするなど)。
  • ヒントでは、概念を説明するためにコード例を使ってもかまいませんが、解答の骨組みを示すために使ってはいけません。たとえば、配列の演習であれば、ある配列関数がどう動くかのスニペットを示すことはできますが、それをそのまま解答にコピー&ペーストできる形にしてはいけません。
  • ヒントは、Markdownのリストとして## Generalという見出しの下に書く必要があります。
  • ヒントがない場合は、この見出しは省きます。

ヒントを見ることは「推奨される」道ではありません。学習者がそれなしでは先に進めない場合を除いて、ヒントの使用は(やんわりと)控えてもらうようにします。そのため、ヒントを読む学習者は少し戸惑ったり圧倒されたり、もしかするとイライラしているかもしれないことを念頭に置いておきましょう。

例

## General

- There are many [built-in methods][integers] to simplify working with integers.

[integers]: https://ruby-doc.org/core-2.7.0/Integer.html

ファイル: .meta/design.md

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

要否: 任意

このファイルには、演習の設計に関する情報が含まれます。たとえば、その目標、指導上の目標、教えないことなどです。

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

例

# Design

## Goal

The goal of this exercise is help students practice how to work with strings.

## Notes

This exercise does not contain any error handling tests.

ファイル: .meta/config.json

目的: 演習に関するメタ情報を含みます。

要否: 必須

このファイルには、演習に関するメタ情報が含まれます:

  • authors: 演習の作者のGitHubユーザー名(任意)
    • レビューが演習を大きく変える場合(「一緒に作り上げた」と感じられるほど)には、レビュアーも含めます。
  • contributors: 演習のコントリビューターのGitHubユーザー名(任意)
    • レビューが意義深い、実行に移せる、または実行された場合は、レビュアーも含めます。
  • files: この演習で使われるファイルの場所(演習のディレクトリからの相対パス)(必須)
  • language_versions 言語のバージョン要件(任意)
  • blurb: この演習の短い説明です。長さは350以下でなければなりません。Markdownはサポートされて_いません_(必須)
  • source: この演習の基になった出典(任意)
  • source_url: この演習の基になった出典のURL(任意)
  • test_runner: この演習の解答をテストランナーでテストするかどうかを示します。指定しない場合のデフォルトはtrueです。(任意)
  • representer: リプレゼンターがこのファイルをどう処理するかに関するメタ情報(任意)
    • version: 演習で使用するリプレゼンターのバージョンを表す整数(親キーが存在する場合は必須)
  • icon: アイコンのslug(アイコンの一覧を参照)。指定しない場合は、演習のslugが使われます(任意)
  • custom: 演習固有の非標準データ。トラックのツールの動作を演習ごとにカスタマイズするのに使えます(任意)

ある人が作者_かつ_コントリビューターである場合は、その人を作者としてのみ記載します。

例

{
  "authors": ["FSharpForever"],
  "files": {
    "solution": ["Bob.fs"],
    "test": ["BobTests.fs"],
    "example": [".meta/Example.fs"]
  },
  "blurb": "Bob is a lackadaisical teenager. In conversation, his responses are very limited"
}

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

  • authorsとcontributorsの順序に意味はなく、重要ではありません。
  • language_versionsは自由形式の文字列で、トラックが自由に使ったり解釈したりできます。

ファイル: .meta/tests.toml

目的: どのテストが実装されているかに関する情報を含みます。

要否: 任意

このファイルには、どのテストが実装されているかに関する情報を書きます。ただし、演習がproblem-specificationsリポジトリ内のcanonical-data.jsonファイルにテストを定義している場合に限ります。

これは、メンテナーがどのテストが実装されているかを把握しやすくし、(任意で)あるテストが実装されていない理由を記録するために存在します。 実装されていないテストを検出するのにも使えます。

configletツールは、configlet syncコマンドを使って、このファイルをproblem-specificationsリポジトリのデータと更新・同期します。 同期するとき、configletは実装されていないテストごとに、そのテストを含めるかどうかを尋ねます。

例

# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[3e5c30a8-87e2-4845-a815-a49671ade970]
description = "empty strand"

[a0ea42a6-06d9-4ac6-828c-7ccaccf98fec]
description = "can count one nucleotide in single-character input"

[eca0d565-ed8c-43e7-9033-6cefbf5115b5]
description = "strand with repeated nucleotide"

[40a45eac-c83f-4740-901a-20b22d15a39f]
description = "strand with multiple nucleotides"

[b4c47851-ee9e-4b0a-be70-a86e343bd851]
description = "strand with invalid nucleotides"
include = false
comment = "error handling omitted on purpose"

ファイル: .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: アプローチのslugで、小文字のケバブケースの文字列です。slugはトラック内のすべてのアプローチ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: 記事のslugで、小文字のケバブケースの文字列です。slugはトラック内のすべての記事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"キーで指定しなければなりません。

例

using System;

public static class Isogram
{
    public static bool IsIsogram(string word)
    {
        throw new NotImplementedException("You need to implement this function.");
    }
}

ファイル: テスト

目的: 解答が正しいことを検証します。

要否: 必須

  • コードはできるだけシンプルにします。
  • 演習の前提条件で導入される言語機能のみを使います(その前提条件のさらに前提条件も同様です)。
  • テストファイルは、ブラウザー上でコーディングするときは学習者に表示され、CLIを使うときは学習者のファイルシステムにダウンロードされます。
  • Exercismでは、プラクティス演習をテスト駆動開発で進めることを推奨しています。そのためには、2つの方法があります:
    • テストランナーがファイルで定義された順序でテストを実行し、かつテストスイートが最初の失敗で中断しなければならない。または
    • 最初のテスト以外は、デフォルトでスキップされるようにします。
  • テストファイルへの相対パスは、.meta/config.jsonファイルの"files.test"キーで指定しなければなりません。

例

using Xunit;

public class IsogramTest
{
    [Fact]
    public void Empty_string() =>
        Assert.True(Isogram.IsIsogram(""));

    [Fact(Skip = "Remove this Skip property to run this test")]
    public void Isogram_with_only_lower_case_characters() =>
        Assert.True(Isogram.IsIsogram("isogram"));

    [Fact(Skip = "Remove this Skip property to run this test")]
    public void Word_with_one_duplicated_character() =>
        Assert.False(Isogram.IsIsogram("eleven"));
}

ファイル: 実装例

目的: すべてのテストに通る実装例を提供します。

要否: 必須

  • この実装は、テストに通る実装が存在することを検証するために使われます。意図的に、学習者に目指してほしいコードとは_していません_。
  • 各トラックは、実装例がテストに通ることを継続的インテグレーション(CI)の設定で検証するべきです。
  • このコードはメンターには表示されません。
  • 実装例のファイルは、ブラウザー上でコーディングするときは学習者に表示され_ず_、CLIを使うときは学習者のファイルシステムにダウンロードされ_ません_。
  • 実装例のファイルへの相対パスは、.meta/config.jsonファイルの"files.example"キーで指定しなければなりません。

例

using System.Linq;

public static class Isogram
{
    public static bool IsIsogram(string word)
    {
        var lowerCaseLetters = word.ToLower().Where(char.IsLetter).ToList();
        return lowerCaseLetters.Distinct().Count() == lowerCaseLetters.Count;
    }
}

ファイル: 追加ファイル

目的: テストを実行するために必要な、追加のプロジェクトファイル、ビルドファイル、サポートファイルです。

要否: デフォルトのファイルだけではテストを実行できない場合に必須

テストを実行するために追加のファイルを必要とする言語もあります。たとえば、C#のプロジェクトファイルやNodeのpackage.jsonファイルで、これらがないとテストを実行できません。

共有ファイル

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

表示

演習のドキュメントを学習者に提示する方法は、ブラウザー内エディターを使う場合とCLIを使う場合とで異なります。詳細はこのドキュメントを確認してください。

アイコン

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

problem-specificationsのメタデータから演習を実装している場合、その演習にはすでにアイコンがある可能性が高いです。 ない場合は、website-iconsリポジトリでissueを作成してください。