Os Exercícios de Conceito são exercícios concebidos para ensinar conceitos (de programação) específicos. Os conceitos ensinados pelos Exercícios de Conceito formam um programa de estudos. Para mais informações sobre como conceber um programa de estudos, consulta a documentação do programa de estudos.
Podes criar rapidamente a estrutura de um novo Exercício de Conceito executando os seguintes comandos a partir do diretório raiz do percurso:
bin/fetch-configlet
bin/configlet create --concept-exercise <slug>
Para mais informações, consulta a documentação do configlet create
Os metadados de um Exercício de Conceito são definidos na chave exercises.concept do ficheiro config.json. Os metadados definem o UUID, o slug e muito mais do exercício.
{
"exercises": {
"concept": [
{
"uuid": "93fbc7cf-3a7e-4450-ad22-e30129c36bb9",
"slug": "cars-assemble",
"name": "Cars, Assemble!",
"concepts": ["if-statements", "numbers"],
"prerequisites": ["basics"]
}
]
}
}
Cada Exercício de Conceito tem o seu próprio diretório dentro do diretório exercises/concept do percurso. O nome do diretório do Exercício de Conceito tem de corresponder à propriedade slug do Exercício de Conceito, tal como definida no ficheiro config.json.
Um Exercício de Conceito tem quatro tipos de ficheiros:
Estes ficheiros são apresentados ao estudante para ajudar a explicar o exercício.
.docs/introduction.md: apresenta ao estudante o(s) conceito(s) que o exercício ensina (obrigatório).docs/instructions.md: fornece as instruções do exercício (obrigatório).docs/hints.md: fornece pistas ao estudante para o ajudar a desbloquear-se num exercício (obrigatório)Estes ficheiros não são apresentados ao estudante, mas são usados para definir os metadados do exercício.
.meta/config.json: contém meta-informação sobre o exercício (obrigatório).meta/design.md: descreve a conceção do exercício (obrigatório)Estes ficheiros descrevem abordagens para o exercício.
.approaches/introduction.md: introdução às abordagens mais comuns para o exercício (opcional).approaches/config.json: metadados das abordagens (opcional).approaches/<approach-slug>/content.md: descrição da abordagem (opcional).approaches/<approach-slug>/snippet.txt: fragmento que mostra a abordagem (opcional)Estes ficheiros descrevem artigos para o exercício.
.articles/config.json: metadados dos artigos (opcional).articles/<article-slug>/content.md: descrição do artigo (opcional).articles/<article-slug>/snippet.md: fragmento que mostra o artigo (opcional)Os ficheiros específicos da linguagem, como os ficheiros de implementação e de testes. Os nomes destes ficheiros são específicos de cada percurso.
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 (implementação exemplar)
├── CarsAssemble.cs (implementação stub)
└── CarsAssemblyTests.cs (testes)
Preferimos uma abordagem de "fusão otimista" para novos exercícios, em que os percursos podem desenvolver exercícios num estado de "trabalho em curso". O estado mínimo válido, que passa no configlet e te permite fazer a fusão, é:
config.json do percurso, com o status definido como wip..meta/config.json válido.docs/introduction.md.docs/instructions.md.docs/hints.md.docs/introduction.md
Objetivo: Apresentar ao estudante o(s) conceito(s) que o exercício ensina.
Presença: Obrigatório
about.md do conceito.Por exemplo, a introdução de um exercício de "strings" pode descrever uma string apenas como uma "sequência de carateres Unicode" ou uma "série de bytes", dizer aos utilizadores como criar uma string e explicar que uma string tem métodos que podem ser usados para a manipular. A menos que o estudante precise de compreender detalhes mais subtis para resolver o exercício, este tipo de explicação breve (juntamente com um exemplo da sua sintaxe) deve ser informação suficiente para o estudante resolver o exercício.
# 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
Objetivo: Modelo a partir do qual se gera um ficheiro introduction.md.
Presença: Opcional
O documento introduction.md apresenta ao estudante o(s) conceito(s) do exercício. Cada conceito tem também o seu próprio documento introduction.md, que não é mostrado fora do contexto de um exercício.
Se a introdução do conceito deve ser incluída palavra a palavra na introdução do exercício, pode usar-se um ficheiro introduction.md.tpl. Este ficheiro permite referir as introduções dos conceitos através de marcadores: %{concept:<concept-slug>}.
O configlet pode gerar um ficheiro introduction.md a partir de um ficheiro modelo. No ficheiro gerado, os marcadores dos conceitos são substituídos pelo conteúdo introduction do conceito.
O site do Exercism só conhece o documento introduction.md. É responsabilidade do percurso gerar o introduction.md quando se usa um ficheiro modelo.
Os percursos podem decidir, exercício a exercício, se usam um modelo ou não. Em alguns casos, usar a introdução do conceito palavra a palavra pode não ser o ideal. Opta sempre pelo que proporciona a melhor experiência de aprendizagem ao estudante.
# Introduction
%{concept:variables}
.docs/instructions.md
Objetivo: Fornecer as instruções do exercício.
Presença: Obrigatório
Este ficheiro divide-se em duas partes.
Cada tarefa tem de cumprir as seguintes normas:
## 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),Damos grande importância a que o conteúdo do Exercism seja seguro para todos e, por isso, muitas vezes pecamos por excesso de prudência ao decidir se as histórias são apropriadas ou não. Embora tenhamos cuidado com o que fundimos, sabemos que é difícil ter consciência do que pode ser visto como problemático, por isso assumimos sempre que estás a agir de boa-fé e fazemos os possíveis por detetar quaisquer problemas na revisão de forma não confrontacional. Se quiseres verificar uma história connosco, menciona @exercism/leadership e analisamo-la em conjunto. Aqui ficam alguns pontos orientadores:
# 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
Objetivo: Fornecer pistas ao estudante para o ajudar a desbloquear-se num exercício.
Presença: Obrigatório
## General.instructions.md (por exemplo, ## 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`).Ver as pistas não será um caminho "recomendado" e vamos desaconselhá-lo (com delicadeza), a não ser que o estudante não consiga avançar sem elas. Como tal, vale a pena ter em conta que o estudante que as lê estará um pouco confuso/sobrecarregado e talvez frustrado.
# 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
Objetivo: Descrever a conceção do exercício.
Presença: Obrigatório
Este ficheiro contém informação sobre a conceção do exercício, que inclui coisas como o seu objetivo, os seus objetivos de ensino, o que não ensinar e muito mais. Esta informação pode ser extraída da issue do GitHub correspondente ao exercício.
Existe para informar futuros responsáveis pela manutenção ou contribuidores sobre o âmbito e as limitações de um exercício, de modo a evitar a tendência natural para tornar os exercícios mais complexos com o tempo.
# 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
Objetivo: Conter meta-informação sobre o exercício.
Presença: Obrigatório
Este ficheiro contém meta-informação sobre o exercício:
authors: O(s) nome(s) de utilizador do GitHub do(s) autor(es) do exercício (obrigatório)
contributors: O(s) nome(s) de utilizador do GitHub do(s) contribuidor(es) do exercício (opcional)
forked_from: De que exercício(s) foi derivado (obrigatório se o exercício for derivado)files: As localizações dos ficheiros usados neste exercício, relativas ao diretório do exercício (obrigatório)
solution: o(s) ficheiro(s) da implementação stub (obrigatório)test: o(s) ficheiro(s) de teste (obrigatório)exemplar: o(s) ficheiro(s) da implementação exemplar (obrigatório)editor: outros ficheiros mostrados como só de leitura no editor (opcional)invalidator: ficheiros que, quando alterados, fazem com que uma solução fique desatualizada (opcional)language_versions: Requisitos de versão da linguagem (opcional)blurb: Uma descrição breve deste exercício. O comprimento tem de ser <= 350. O Markdown não é suportado (obrigatório)source: A fonte em que este exercício se baseia (opcional)source_url: O URL da fonte em que este exercício se baseia (opcional)representer: Meta-informação relacionada com a forma como o representer processa este ficheiro (opcional)
version: Um número inteiro para a versão do representer a usar no exercício (obrigatório se a chave pai estiver presente)icon: O slug do ícone (vê a lista completa de ícones). Se não for especificado, será usado o slug do exercício (opcional)custom: Quaisquer dados não padrão específicos do exercício. Pode ser usado para personalizar o comportamento das ferramentas do percurso para cada exercício (opcional)Se alguém for simultaneamente autor e contribuidor, indica essa pessoa apenas como autor.
{
"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"
}
Imagina que o utilizador FSharpForever escreveu um exercício chamado log-levels para o percurso de F#. O PythonProfessor adapta o exercício para o percurso de Python. Mais tarde, o utilizador GladToHelp melhora o exercício.
{
"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
}
}
Repara que:
forked_from está correto.language_versions é uma string de formato livre que os percursos podem usar e interpretar como quiserem..approaches/introduction.md
Objetivo: Introdução às abordagens mais comuns para o exercício
Presença: Opcional
Este ficheiro descreve as abordagens mais comuns para o exercício. Consulta a documentação para mais informações sobre o que deve constar deste ficheiro.
# 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
Objetivo: Metadados das abordagens
Presença: Opcional (obrigatório quando existe uma introdução das abordagens ou uma abordagem)
Este ficheiro contém meta-informação sobre as abordagens do exercício:
introduction: O(s) nome(s) de utilizador do GitHub do(s) autor(es) da introdução das abordagens do exercício (opcional)
authors: O(s) nome(s) de utilizador do GitHub do(s) autor(es) da introdução das abordagens do exercício (obrigatório)
contributors: O(s) nome(s) de utilizador do GitHub do(s) contribuidor(es) da introdução das abordagens do exercício (opcional)
approaches: Um array com as abordagens detalhadas (opcional)
uuid: um UUID V4 que identifica de forma única a abordagem. O UUID tem de ser único tanto dentro do percurso como em todos os percursos, e nunca pode mudarslug: o slug da abordagem, que é uma string em minúsculas e em kebab-case. O slug tem de ser único entre todos os slugs de abordagens do percurso. O seu comprimento tem de ser <= 255.title: o título da abordagem. O seu comprimento tem de ser <= 255.blurb: Uma descrição breve desta abordagem. O comprimento tem de ser <= 350. O Markdown não é suportado (obrigatório)authors: O(s) nome(s) de utilizador do GitHub do(s) autor(es) da abordagem do exercício (obrigatório)
contributors: O(s) nome(s) de utilizador do GitHub do(s) contribuidor(es) da abordagem do exercício (opcional)
tags: Especifica as condições em que uma submissão é associada a uma abordagem. (opcional)
all: Um array de etiquetas que têm de estar todas presentes numa submissão (opcional, a menos que any não tenha elementos)any: Um array de etiquetas das quais pelo menos uma tem de estar presente numa submissão (opcional, a menos que all não tenha elementos)not: nenhuma das etiquetas pode estar presente numa submissão (opcional){
"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
Objetivo: Descrição detalhada da abordagem
Presença: Opcional (obrigatório para as abordagens)
Este ficheiro contém uma descrição detalhada da abordagem. Consulta a documentação para mais informações sobre o que deve constar deste ficheiro.
# 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
Objetivo: Fragmento que mostra a abordagem
Presença: Opcional (obrigatório para as abordagens)
Este ficheiro contém um pequeno fragmento que mostra a abordagem. O fragmento é mostrado na página de aprofundamento do exercício.
O seu número de linhas tem de ser <= 8.
Consulta a documentação para mais informações sobre o que deve constar deste ficheiro.
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
Objetivo: Metadados dos artigos
Presença: Opcional (obrigatório quando existe um artigo)
Este ficheiro contém meta-informação sobre os artigos do exercício:
articles: Um array com os artigos detalhados (opcional)
uuid: um UUID V4 que identifica de forma única o artigo. O UUID tem de ser único tanto dentro do percurso como em todos os percursos, e nunca pode mudarslug: o slug do artigo, que é uma string em minúsculas e em kebab-case. O slug tem de ser único entre todos os slugs de artigos do percurso. O seu comprimento tem de ser <= 255.title: o título do artigo. O seu comprimento tem de ser <= 255.blurb: Uma descrição breve deste artigo. O comprimento tem de ser <= 350. O Markdown não é suportado (obrigatório)authors: O(s) nome(s) de utilizador do GitHub do(s) autor(es) do artigo do exercício (obrigatório)
contributors: O(s) nome(s) de utilizador do GitHub do(s) contribuidor(es) do artigo do exercício (opcional)
{
"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
Objetivo: Descrição detalhada da abordagem
Presença: Opcional (obrigatório para as abordagens)
Este ficheiro contém uma descrição detalhada da abordagem. Consulta a documentação para mais informações sobre o que deve constar deste ficheiro.
# 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
Objetivo: Fragmento que mostra a abordagem
Presença: Opcional (obrigatório para os artigos)
Este ficheiro contém um pequeno fragmento que mostra o artigo. O fragmento é mostrado na página de aprofundamento do exercício.
O seu número de linhas tem de ser <= 8.
Consulta a documentação para mais informações sobre o que deve constar deste ficheiro.
| Method | Mean | Allocated |
| -----: | --------: | --------: |
| Linq | 29.133 ns | 80 B |
| Array | 4.806 ns | - |
Objetivo: Fornecer um ponto de partida aos estudantes.
Presença: Obrigatório
"files.solution" do ficheiro .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
Objetivo: Verificar a correção de uma solução.
Presença: Obrigatório
instructions.md."files.test" do ficheiro .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
Objetivo: Fornecer a implementação-alvo que o estudante deve procurar alcançar.
Presença: Obrigatório
"files.exemplar" do ficheiro .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
Objetivo: Garantir que os testes podem ser executados.
Presença: Obrigatório se os ficheiros predefinidos não forem suficientes para executar os testes
Algumas linguagens exigem ficheiros adicionais para que os testes possam ser executados. Exemplos disso são os ficheiros de projeto de C# e os ficheiros package.json do Node, sem os quais não será possível executar os testes.
Alguns ficheiros não são específicos de exercícios individuais, mas aplicam-se a todos os exercícios. Consulta a documentação para mais informações.
Os Exercícios de Conceito devem ser nomeados a partir da sua história/tema, não a partir do(s) seu(s) conceito(s).
Bons exemplos de nomes:
Tim from MarketingLucian's Luscious LasagnaCalculator ConundrumNomes não permitidos:
Booleans: usa um nome de conceito, não um nome de históriaExercise #1: um exercício não é uma história/temaAo derivar um exercício sem alterações significativas, usa o nome original quando possível.
Cada exercício tem também um slug, que é uma versão normalizada do nome do exercício segundo as seguintes regras:
[a-z0-9-]+)two-fer em vez de 2-fer)Bons exemplos de slugs:
tim-from-marketinglucians-luscious-lasagnacalculator-conundrumSlugs não permitidos:
TIM-FROM-MARKETING: não usa letras minúsculas (ou seja, tim-from-marketing)TimFromMarketing: não usa kebab-case (ou seja, tim-from-marketing)floating-point-numbers: usa um nome de conceito, não um nome de históriaHá uma diferença na forma como a documentação do exercício é apresentada ao estudante quando se usa o editor no navegador em comparação com a CLI. Consulta este documento para mais informações.
Cada exercício tem um ícone de acompanhamento.
Por predefinição, o ícone apresentado é aquele cujo nome corresponde ao slug do exercício.
É possível substituir esta escolha especificando a propriedade icon no ficheiro .meta/config.json do exercício.
Se estiveres a derivar um exercício existente, provavelmente já existe um ícone para esse exercício. Se não existir, abre uma issue no repositório website-icons.