Git Product home page Git Product logo

crystal's Introduction


Exercism Crystal Track

                          Discourse topics  Exercism_II  Exercism_III  Build Status


Hi.  👋🏽  👋  We are happy you are here.  🎉 🌟


exercism/Crystal is one of many programming language tracks on exercism(dot)org. This repo holds all the instructions, tests, code, & support files for Crystal exercises currently under development or implemented & available for students.

🌟   Track tooling (test-runner, representer, analyzer, and Continuous Integration) runs on Crystal 1.11.2.
🌟   Most exercises are solvable with Crystal 1.0.0 or higher.

This track is made up of Practice Exercises. Practice exercises are open-ended, and can be used to practice concepts learned, try out new techniques, and play.



🌟🌟  Please take a moment to read our Code of Conduct 🌟🌟 
It might also be helpful to look at Being a Good Community Member & The words that we use.

                         Some defined roles in our community: Contributors | Mentors | Maintainers | Admins


We 💛 💙  Pull Requests. But our maintainers generally can't accept unsolicited PRs. Check our help wanted list or open an issue for discussion first. If it is your first time contributing to Exercism, check for good first patch or first-timers only labels.


Here to suggest a new feature or new exercise?? Hooray!  🎉  
We'd love if you did that via our Exercism Community Forum.
Please keep in mind Chesterton's Fence.
                          Thoughtful suggestions will likely result in faster & more enthusiastic responses from volunteers.


✨ 🦄  Want to jump directly into Exercism specifications & detail?
     Structure | Tasks | Concepts | Concept Exercises | Practice Exercises | Presentation
     Writing Style Guide | Markdown Specification (✨ version in contributing on exercism.org)



Crystal Software and Documentation

Copyright © 2012-2024 Manas Technology Solutions. All rights reserved.

Crystal software and documentation are licensed under the Apache License v2.0.

Exercism Crystal License

This repository uses the MIT License.

Final Note

Thanks to Bethany for the allowing us to use her template for this README.

crystal's People

Contributors

amscotti avatar bmulvihill avatar chastell avatar dependabot[bot] avatar derekgottlieb avatar dscottboggs avatar ee7 avatar elorest avatar erikschierboom avatar exercism-bot avatar f-fr avatar ilmanzo avatar jhass avatar joeltaylor avatar kahgoh avatar kytrinyx avatar ls1955 avatar marksiemers avatar marksiemers-msr avatar martinwalsh avatar mattkimmel avatar mdaubs avatar meatball133 avatar mhelmetag avatar neenjaw avatar petertseng avatar rjpgt avatar ryanplusplus avatar steffan153 avatar tejasbubane avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

crystal's Issues

crystal tool format

I noticed in the email notifications on PR #22 that @asterite said: I would suggest running crystal tool format on the whole project to automatically make the code follow the recommended style.

First of all: I love it when languages have a tool to autoformat for the recommended style. (Thank you for that!)

Second: we should recommend this in the docs for the language track.

Third: We could implement a service like for Go (gofmt) where we check if their submission matches the output from the tool and if it doesn't add a friendly comment from rikki about the tool and the value of consistency etc.

The go stuff is implemented directly in rikki- (because I'm lazy), but if it's simple enough to spin up a small API somewhere with crystal installed on the command-line, rikki- could ask the service and report back, like it does in Ruby. https://github.com/exercism/rikki/tree/master/analysis

Generate exercises using x-common

Looks like this track is about to be launched soon (with almost 9 exercises now).

I think we should generate all exercises from x-common. I see a lot of PRs in x-ruby changing the static exercise files to dynamically generated ones. Using it from the start in a new repo like this is better instead of converting them later.

Not sure if this should be enforced on all PRs. What are your views regarding this?

Fix getting started instructions for crystal

Some exercise README templates contain links to pages which no longer exist in v2 Exercism.

For example, C++'s README template had a link to /languages/cpp for instructions on running tests. The correct URLs to use can be found in the 'Still stuck?' sidebar of exercise pages on the live site. You'll need to join the track and go to the first exercise to see them.

Please update any broken links in the 'config/exercise_readme.go.tmpl' file, and run 'configlet generate .' to generate new exercise READMEs with the fixes.

Instructions for generating READMEs with configlet can be found at:
https://github.com/exercism/docs/blob/master/language-tracks/exercises/anatomy/readmes.md#generating-a-readme

Instructions for installing configlet can be found at:
https://github.com/exercism/docs/blob/bc29a1884da6c401de6f3f211d03aabe53894318/language-tracks/launch/first-exercise.md#the-configlet-tool

Tracking exercism/exercism#4102

New spec failures because of possibly changed method signature/interface

In a recent automatic build, I saw a spec failure.

Here's the output from travis:

running formatting check for: binary
moving files around
running tests for: binary
Error in line 1: while requiring "./spec/binary_spec.cr"
in spec/binary_spec.cr:42: wrong number of arguments for macro 'expect_raises' (given 0, expected 1, 2, 3, 4)
    expect_raises do
    ^~~~~~~~~~~~~
make[2]: *** [test-exercise] Error 1
make[1]: *** [test-exercises] Error 1
make: *** [test] Error 2
The command "make test" exited with 2.
Done. Your build exited with 1.

Seems like we might need to do some fiddling here:

Remove obsolete version tracking assertions in exercises

Some tracks have added assertions to the exercise test suites that ensure that the solution has a hard-coded version in it.
In the old version of the site, this was useful, as it let commenters see what version of the test suite the code had been written against, and they wouldn't accidentally tell people that their code was wrong, when really the world had just moved on since it was submitted.

If this track does not have any assertions that track versions in the exercise tests, please close this issue.

If this track does have this bookkeeping code, then please remove it from all the exercises.

See exercism/exercism#4266 for the full explanation of this change.

Build analyzer

In Exercism v3, we are making increased use of our v2 analyzers. Analyzers automatically assess student's submissions and provide mentor-style commentary. They can be used to catch common mistakes and/or do complex solution analysis that can't easily be done directly in a test suite.

Each analyzer is track-specific. When a new solution is submitted, we run the track's analyzer, which outputs a JSON file that contains the analysis results.

In v2, analyzer comments were given to a mentor to pass to a student. In v3, the analyzers will normally output directly to students, although we have added an extra key to output suggestions to mentors. If your track already has an analyzer, the only requisite change is updating the outputted copy to be student-facing.

The analyzer is an optional tool though, which means that if a track does not have an analyzer, it will still function normally.

Goal

Build an analyzer for your track according to the spec. Check this page to help you get started with building an analyzer.

It can be very useful to check how other tracks have implemented their analyzer.

If your track already has a working analyzer, please close this issue and ensure that the .status.analyzer key in the track config.json file is set to true.

Choosing between representer and analyzer

There is some overlap between the goals of the representer and the analyzer. If you want to build both, we recommend starting by building the representer for the following reasons:

  • Representers are usually (far) easier to implement
  • Representers can have a far bigger impact on the mentoring load than analyzers by empowering mentors
  • Representers apply to all exercises, whereas analyzers usually target specific exercises or a subset

Tracking

exercism/v3-launch#53

Where are the Crystal communities and enthusiasts?

As we move towards the launch of the new version of Exercism we are going to be ramping up on actively recruiting people to help provide feedback.

Our goal is to get to 100%: everyone who submits a solution and wants feedback should get feedback. Good feedback. You can read more about this aspect of the new site here: http://mentoring.exercism.io/

To do this, we're going to need a lot more information about where we can find language enthusiasts.

  • Is Crystal supported by one or more large organizations?
  • Does Crystal have an official community manager?
  • Do you know of specific communities (online or offline) that are enthusiastic about Crystal? (Chat communities, forums, meetups, student clubs, etc)
  • Are there popular conferences for Crystal? (If so, what are some examples?)
  • Are there any organizations who are targeted specifically at getting certain subgroups or demographics interested in Crystal? (e.g. kids, teenagers, career changers, people belonging to various groups that are typically underrepresented in tech?)
  • Are there specific groups or programs dedicated to mentoring people in Crystal?
  • Are there popular newsletters for Crystal?
  • Is Crystal taught at programming bootcamps? (If so, what are some examples?)
  • Is Crystal taught at universities? (If so, what are some examples?)

In other words: where do people care a lot and/or know a lot about Crystal?

This is part of the project being tracked in exercism/meta#103

Build Representer and Analyzer

This issue is part of the migration to v3. You can read full details about the various changes here.

Representer

In Exercism v3, we're introducing a new (optional) tool: the representer. The goal of the representer is to take a solution and returning a representation, which is an extraction of a solution to its essence with normalized names, comments, spacing, etc. but still uniquely identifying the approach taken. Two different ways of solving the same exercise must not have the same representation.

Each representer is track-specific. When a new solution is submitted, we run the track's representer, which outputs two JSON files that describe the representation.

Once we have a normalized representation for a solution, a team of vetted mentors will look at the solution and comment on it (if needed). These comments will then automatically be submitted to each new solution with the same representation. A notification will be sent for old solutions with a matching representation.

Each track should build a representer according to the spec. For tracks building a representer from scratch, we have a starting guide.

The representer is an optional tool though, which means that if a track does not have a representer, it will still function normally.

Analyzer

In Exercism v3, we are making increased use of our v2 analyzers. Analyzers automatically assess student's submissions and provide mentor-style commentary. They can be used to catch common mistakes and/or do complex solution analysis that can't easily be done directly in a test suite.

Each analyzer is track-specific. When a new solution is submitted, we run the track's analyzer, which outputs a JSON file that contains the analysis results.

In v2, analyzer comments were given to a mentor to pass to a student. In v3, the analyzers will normally output directly to students, although we have added an extra key to output suggestions to mentors. If your track already has an analyzer, the only requisite change is updating the outputted copy to be student-facing.

Each track should build an analyzer according to the spec. For tracks building an analyzer from scratch, we have a starting guide.

The analyzer is an optional tool though, which means that if a track does not have an analyzer, it will still function normally.

Goal 1

Build a representer for your track according to the spec. Check this page to help you get started with building a representer.

Note that the simplest representer is one that merely returns the solution's source code.

It can be very useful to check how other tracks have implemented their representer.

Goal 2

Build an analyzer for your track according to the spec. Check this page to help you get started with building an analyzer.

It can be very useful to check how other tracks have implemented their analyzer.

Choosing between representer and analyzer

If you want to build both, we recommend starting by building the representer for the following reasons:

  • Representers are usually (far) easier to implement
  • Representers can have a far bigger impact on the mentoring load than analyzers by empowering mentors
  • Representers apply to all exercises, whereas analyzers usually target specific exercises or a subset

Tracking

exercism/v3-launch#8

The master branch will be renamed to main

In line with our new org-wide policy, the master branch of this repo will be renamed to main. All open PRs will be automatically repointed.

GitHub will show you a notification about this when you look at this repo after renaming:

Screenshot 2021-01-27 at 15 31 45

In case it doesn't, this is the command it suggests:

git branch -m master main
git fetch origin
git branch -u origin/main main

You may like to update the primary branch on your forks too, which you can do under Settings->Branches and clicking the pencil icon on the right-hand-side under Default Branch:

Screenshot 2021-01-27 at 18 50 08

We will post a comment below when this is done. We expect it to happen within the next 12 hours.

Extract track-specific help instructions from `config/exercise_readme.go.tmpl`

Each track needs a file that contains track-specific instructions on how to get help. The contents of this document are only presented to the student when using the CLI. This file lives at exercises/shared/.docs/help.md. You almost certainly already have this information, but need to move it to the correct place.

For v2 tracks, this information was (usually) included in the readme template found at config/exercise_readme.go.tmpl. As such, tracks can extract the help instructions from the config/exercise_readme.go.tmpl file to the exercises/shared/.docs/help.md file.

See https://github.com/exercism/csharp/pull/1557/files for an example PR.

Tracking

exercism/v3-launch#50

Override probot/stale defaults, if necessary

Per the discussion in exercism/discussions#128 we
will be installing the probot/stale integration on the Exercism organization on
April 10th, 2017.

By default, probot will comment on issues that are older than 60 days, warning
that they are stale. If there is no movement in 7 days, the bot will close the issue.
By default, anything with the labels security or pinned will not be closed by
probot.

If you wish to override these settings, create a .github/stale.yml file as described
in https://github.com/probot/stale#usage, and make sure that it is merged
before April 10th.

If the defaults are fine for this repository, then there is nothing further to do.
You may close this issue.

[v3] Add tags

This issue is part of the migration to v3. You can read full details about the various changes here.

In Exercism v3, tracks can be annotated with tags. This allows searching for tracks with a certain tag combination, making it easy for students to find an interesting track to join.

Tags are specified in the top-level "tags" field in the track's config.json file and are defined as an array of strings, as specified in the spec.

Goal

The "tags" field in the config.json file should be updated to contain the tags that are relevant to this track. The list of tags that can be used is listed in the spec.

Example

{
  "tags": [
    "runtime/jvm",
    "platform/windows",
    "platform/linux",
    "paradigm/declarative",
    "paradigm/functional",
    "paradigm/object_oriented"
  ]
}

Tracking

exercism/v3-launch#1

Create stub files for all exercises

We have decided to require all file-based tracks to provide stubs for their exercises.

The lack of stub file generates an unnecessary pain point within Exercism, contributing a significant proportion of support requests, making things more complex for our students, and hindering our ability to automatically run test-suites and provide automated analysis of solutions.

We believe that it’s essential to understand error messages, know how to use an IDE, and create files. However, getting this right as you’re just getting used to a language can be a frustrating distraction, as it can often require a lot of knowledge that tends to seep in over time. At the start, it can be challenging to google for all of these details: what file extension to use, what needs to be included, etc. Getting people up to speed with these things are not Exercism’s focus, and we’ve decided that we are better served by removing this source of confusion, letting people get on with actually solving the exercises.

The original discussion for this is at exercism/discussions#238.

Therefore, we’d like this track to provide a stub file for each exercise.

  • If this track already provides stub files for all exercises, please close this issue.
  • If this track already has an open issue for creating stubs, then my apologies. Please close one as a duplicate.
  • Otherwise, please respond to this issue with useful details about what needs to be done to complete this task in this track so that people who are not familiar with the track may easily contribute.

Moving from Travis to GitHub Actions

Hello 🙂

Over the last few months we've been transferring all our CI from Travis to GitHub Actions (GHA). We've found that GHA are easier to work with, more reliable, and much much faster.

Based on our success with GHA and increasing intermittent failures on Travis, we have now decided to try and remove Travis from Exercism's org altogether and shift everything to GHA. This issue acts as a call to action if your track is still using Travis.

For most CI checks this should be a transposing from Travis' syntax to GHA syntax, and hopefully quite straightforward (see this PR for an example). However, if you do encounter any issues doing this, please ask on Slack where lots of us now have experience with GHA, or post a comment here and I'll tag relevant people. This would also make a good Hacktoberfest issue for anyone interested in making their first contribution 🙂

If you've already switched this track to GHA, please feel free to close this issue and ignore it.

Thanks!

Update status of track

This issue is part of the migration to v3. You can read full details about the various changes here.

There are several new features in Exercism v3 for tracks to build. To selectively enable these features on the Exercism v3 website, each track must keep track of the status of the following features:

The status of these features is specified in the top-level "status" field in the track's config.json, as specified in the spec.

Goal

The "status" field in the config.json file should be updated to indicate the status of the features for this track. The list of features is defined in the spec.

Example

{
  "status": {
    "concept_exercises": true,
    "test_runner": true,
    "representer": false,
    "analyzer": false
  }
}

Tracking

exercism/v3-launch#12

Follow the Crystal convention of placing tests in a spec/ directory

According to the Crystal Spec module documentation:

By convention, specs live in the spec directory of a project. You can compile and run the specs of a project by running:

crystal spec

Also, you can compile and run individual spec files by providing their path:

crystal spec spec/my/test/file_spec.cr

In addition, you can also run individual specs by optionally providing a line number:

crystal spec spec/my/test/file_spec.cr:14

Are we interested in following this convention? One reason I'm interested in this is that the excellent vim-crystal plugin has keybindings to run specs, but it only works if your project follows the convention of having your spec files in a spec/ directory.

If we're agreed, I'd be happy to contribute a PR updating the existing exercises.

[Important] The current website is about to enter maintenance mode to aid with v3 launch

TL;DR; At the end of Jan 2021, all tracks will enter v3 staging mode. Updates will no longer sync with the current live website, but instead sync with the staging website. The Crystal section of the v3 repo will be extracted and PR'd into this track (if appropriate). Further issues and information will follow over the coming weeks to prepare Crystal for the launch of v3.

Over the last 12 months, we've all been hard at work developing Exercism v3. Up until this point, all v3 tracks have been under development in a single repository - the v3 repository. As we get close to launch, it is time for us to explode that monorepo back into the normal track repos. Therefore, at the end of this month (January 2021), we will copy the v3 tracks contents from the v3 repository back to the corresponding track repositories.

As v3 tracks are structured differently than v2 tracks, the current (v2) website cannot work with v3 tracks. To prevent the v2 website from breaking, we'll disable syncing between track repositories and the website. This will effectively put v2 in maintenance mode, where any changes in the track repos won't show up on the website. This will then allow tracks to work on preparing for the Exercism v3 launch.

Where possible, we will script the changes needed to prepare tracks for v3. For any manual changes that need to be happening, we will create issues on the corresponding track repositories. We will be providing lots of extra information about this in the coming weeks.

We're really excited to enter the next phase of building Exercism v3, and to finally get it launched! 🙂

Verify contents and format of track documentation

Each language track has documentation in the docs/ directory, which gets included on the site
on each track-specific set of pages under /languages.

We've added some general guidelines about how we'd like the track to be documented in exercism/exercism#3315
which can be found at https://github.com/exercism/exercism.io/blob/master/docs/writing-track-documentation.md

Please take a moment to look through the documentation about documentation, and make sure that
the track is following these guidelines. Pay particularly close attention to how to use images
in the markdown files.

Lastly, if you find that the guidelines are confusing or missing important details, then a pull request
would be greatly appreciated.

bob: Update to clarify ambiguity regarding shouted questions

TL;DR: the problem specification for the Bob exercise has been updated. Consider updating the test suite for Bob to match.


Details

The problem description for the Bob exercise lists four conditions:

  • asking a question
  • shouting
  • remaining silent
  • anything else

There's an ambiguity, however, for shouted questions: should they receive the "asking" response or the "shouting" response?

In exercism/problem-specifications#1025 this ambiguity was resolved by adding an additional rule for shouted questions.

If this track uses exercise generators to update test suites based on the canonical-data.json file from problem-specifications, then now would be a good time to regenerate 'bob'. If not, then it will require a manual update to the test case with input "WHAT THE HELL WERE YOU THINKING?".

See the most recent canonical-data.json file for the exact changes.

Remember to regenerate the exercise README after updating the test suite:

configlet generate . --only=bob --spec-path=<path to your local copy of the problem-specifications repository>

You can download the most recent configlet at https://github.com/exercism/configlet/releases/latest if you don't have it.

Note that pull request #102 locks the problem description for 'bob' to match the current implementation by adding the exercises/bob/.meta/description.md file. If that PR is merged before this issue is resolved, then you will need to delete the exercises/bob/.meta/description.md file as part of the change.

Verify that nothing links to help.exercism.io

The old help site was deprecated in December 2015. We now have content that is displayed on the main exercism.io website, under each individual language on http://exercism.io/languages.

The content itself is maintained along with the language track itself, under the docs/ directory.

We decided on this approach since the maintainers of each individual language track are in the best position to review documentation about the language itself or the language track on Exercism.

Please verify that nothing in docs/ refers to the help.exercism.io site. It should instead point to http://exercism.io/languages/:track_id (at the moment the various tabs are not linkable, unfortunately, we may need to reorganize the pages in order to fix that).

Also, some language tracks reference help.exercism.io in the SETUP.md file, which gets included into the README of every single exercise in the track.

We may also have referenced non-track-specific content that lived on help.exercism.io. This content has probably been migrated to the Contributing Guide of the x-common repository. If it has not been migrated, it would be a great help if you opened an issue in x-common so that we can remedy the situation. If possible, please link to the old article in the deprecated help repository.

If nothing in this repository references help.exercism.io, then this can safely be closed.

What's the purpose of the solved exercises in this repo?

Since users are to solve the exercises and contrast them with other users, when do they get to see the solutions in this repo?

And, what should the solutions in this repo show? Should they aim for clarity, brevity, performance?

I personally think, given that this is a website for learning to program, to use code that's as clear as possible, even if it's a bit longer, and efficient if possible.

(Yesterday I also read, just by chance, the sample of 99 bottles of OOP and I think the overall idea of the book should be applied to solutions here)

For example, I'll take a random exercise, brackets push. Nothing against that code or the author, I'm just using it as an example to discuss this issue. The current code is this:

module Brackets
  extend self
  MAP = {'}' => '{', ']' => '[', ')' => '('}

  def are_valid?(str : String)
    create_stack(filter_brackets(str)).size == 0
  end

  private def filter_brackets(brackets : String) : Array(Char)
    brackets.chars.select { |c| (MAP.keys + MAP.values).includes?(c) }
  end

  private def create_stack(brackets : Array(Char)) : Array(Char)
    brackets.reduce([] of Char) do |stack, b|
      MAP[b]? && MAP[b]? == stack.last? ? stack[0..-2] : stack << b
    end
  end
end

One solution I came to is this:

module Brackets
  def self.valid?(string)
    stack = [] of Char
    string.each_char do |char|
      case char
      when '(', '[', '{'
        stack.push char
      when ')'
        return false unless stack.pop? == '('
      when ']'
        return false unless stack.pop? == '['
      when '}'
        return false unless stack.pop? == '{'
      end
    end
    stack.empty?
  end
end

It has the same number of lines, but:

  • The algorithm is clear: we use a stack, push to it on open brackets, pop and check on closing brackets (we ignore other chars)
  • There's just one method to follow, not three
  • There are no type annotations: type annotations are OK for method overloads or sometimes for public APIs, but they are not mandatory and in most cases they make code longer and harder to read. For example, in def valid?(string) it's pretty clear that the argument should be a String, and that it will return a (kind-of) boolean value.
  • It's efficient: the first algorithm uses a Hash (MAP), creates many intermediate structures (the call to chars, the call to select, MAP.keys and MAP.values create intermediate arrays, which are then added to create another intermediate array (and this is done for every character in the string!), etc.). If you benchmark both methods, the second version is 80 times faster, and allocates just one array for the stack of brackets.

So, my worry is that people take this code as idiomatic Crystal code. Later they find that it's maybe slow or hard to understand, and maybe that's not very good for the language.

What was it like to learn Crystal?

We’ve recently started a project to find the best way to design our tracks, in order to optimize the learning experience of students.

As a first step, we’ll be examining the ways in which languages are unique and the ways in which they are similar. For this, we’d really like to use the knowledge of everyone involved in the Exercism community (students, mentors, maintainers) to answer the following questions:

  1. How was your experience learning Crystal? What was helpful while learning Crystal? What did you struggle with? How did you tackle problems?
  2. In what ways did Crystal differ from other languages you knew at the time? What was hard to learn? What did you have to unlearn? What syntax did you have to remap? What concepts carried over nicely?

Could you spare 5 minutes to help us by answering these questions? It would greatly help us improve the experience students have learning Crystal :)

Note: this issue is not meant as a discussion, just as a place for people to post their own, personal experiences.

Want to keep your thoughts private but still help? Feel free to email me at [email protected]

Thank you!

No src directory when pulling exercise

When pulling a new exercise from exercism it isn't immediately apparent that one needs to create a src directory to hold their code file, should this be handled for the user? Or should we update the docs to explicitly mention a src directory should be created with any applicable code files? Or am I missing something and this is already handled 😄 ?

🤖 Sync error for commit 0f2ac7

We hit an error trying to sync the latest commit (0f2ac72) to the website.

The error was:

Mysql2::Error: Deadlock found when trying to get lock; try restarting transaction

/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.3/lib/mysql2/client.rb:131:in `_query'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.3/lib/mysql2/client.rb:131:in `block in query'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.3/lib/mysql2/client.rb:130:in `handle_interrupt'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.3/lib/mysql2/client.rb:130:in `query'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:206:in `block (2 levels) in execute'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/dependencies/interlock.rb:47:in `permit_concurrent_loads'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:205:in `block in execute'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract_adapter.rb:696:in `block (2 levels) in log'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26:in `block (2 levels) in synchronize'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract_adapter.rb:695:in `block in log'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract_adapter.rb:687:in `log'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:204:in `execute'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/mysql/database_statements.rb:50:in `execute'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:215:in `execute_and_free'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/mysql/database_statements.rb:76:in `block in exec_delete'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26:in `block (2 levels) in synchronize'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/mysql/database_statements.rb:75:in `exec_delete'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract/database_statements.rb:179:in `update'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract/query_cache.rb:22:in `update'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/relation.rb:468:in `update_all'
/opt/exercism/website/current/app/models/user/reputation_token.rb:39:in `block in <class:ReputationToken>'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:427:in `instance_exec'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:427:in `block in make_lambda'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:235:in `block in halting_and_conditional'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:516:in `block in invoke_after'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:516:in `each'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:516:in `invoke_after'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:107:in `run_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/bugsnag-6.19.0/lib/bugsnag/integrations/rails/active_record_rescue.rb:25:in `run_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:824:in `_run_save_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/callbacks.rb:457:in `create_or_update'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/timestamp.rb:126:in `create_or_update'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/persistence.rb:507:in `save!'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/validations.rb:53:in `save!'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/transactions.rb:302:in `block in save!'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/transactions.rb:354:in `block in with_transaction_returning_status'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract/database_statements.rb:318:in `transaction'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/transactions.rb:350:in `with_transaction_returning_status'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/transactions.rb:302:in `save!'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/suppressor.rb:48:in `save!'
/opt/exercism/website/current/app/commands/user/reputation_token/create.rb:15:in `block in call'
/opt/exercism/website/current/app/commands/user/reputation_token/create.rb:14:in `tap'
/opt/exercism/website/current/app/commands/user/reputation_token/create.rb:14:in `call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/mandate-1.0.0.beta1/lib/mandate/call_injector.rb:17:in `call'
/opt/exercism/website/current/app/commands/exercise/contributorship/create.rb:15:in `call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/mandate-1.0.0.beta1/lib/mandate/call_injector.rb:17:in `call'
/opt/exercism/website/current/app/commands/git/sync_exercise_contributors.rb:13:in `block (2 levels) in call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/relation/batches.rb:71:in `block (2 levels) in find_each'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/relation/batches.rb:71:in `each'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/relation/batches.rb:71:in `block in find_each'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/relation/batches.rb:138:in `block in find_in_batches'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/relation/batches.rb:245:in `block in in_batches'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/relation/batches.rb:229:in `loop'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/relation/batches.rb:229:in `in_batches'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/relation/batches.rb:137:in `find_in_batches'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/relation/batches.rb:70:in `find_each'
/opt/exercism/website/current/app/commands/git/sync_exercise_contributors.rb:13:in `block in call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract/database_statements.rb:320:in `block in transaction'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract/transaction.rb:310:in `block in within_new_transaction'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26:in `block (2 levels) in synchronize'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract/transaction.rb:308:in `within_new_transaction'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/connection_adapters/abstract/database_statements.rb:320:in `transaction'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activerecord-6.1.3.1/lib/active_record/transactions.rb:209:in `transaction'
/opt/exercism/website/current/app/commands/git/sync_exercise_contributors.rb:11:in `call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/mandate-1.0.0.beta1/lib/mandate/call_injector.rb:17:in `call'
/opt/exercism/website/current/app/commands/git/sync_practice_exercise.rb:30:in `call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/mandate-1.0.0.beta1/lib/mandate/call_injector.rb:15:in `call'
/opt/exercism/website/current/app/commands/git/sync_track.rb:120:in `block in sync_practice_exercises!'
/opt/exercism/website/current/app/commands/git/sync_track.rb:101:in `each'
/opt/exercism/website/current/app/commands/git/sync_track.rb:101:in `each_with_index'
/opt/exercism/website/current/app/commands/git/sync_track.rb:101:in `sync_practice_exercises!'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/mandate-1.0.0.beta1/lib/mandate/memoize.rb:47:in `block (2 levels) in __mandate_memoize'
/opt/exercism/website/current/app/commands/git/sync_track.rb:36:in `call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/mandate-1.0.0.beta1/lib/mandate/call_injector.rb:15:in `call'
/opt/exercism/website/current/app/jobs/sync_track_job.rb:5:in `perform'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/execution.rb:48:in `block in perform_now'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:117:in `block in run_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/i18n-1.8.9/lib/i18n.rb:314:in `with_locale'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/translation.rb:9:in `block (2 levels) in <module:Translation>'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:126:in `instance_exec'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/core_ext/time/zones.rb:66:in `use_zone'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/timezones.rb:9:in `block (2 levels) in <module:Timezones>'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:126:in `instance_exec'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/instrumentation.rb:21:in `block in instrument'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/notifications.rb:203:in `block in instrument'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/notifications.rb:203:in `instrument'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/instrumentation.rb:31:in `instrument'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/instrumentation.rb:14:in `block (2 levels) in <module:Instrumentation>'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:126:in `instance_exec'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/logging.rb:22:in `block in tag_logger'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/tagged_logging.rb:99:in `block in tagged'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/tagged_logging.rb:37:in `tagged'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/tagged_logging.rb:99:in `tagged'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/logging.rb:22:in `tag_logger'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/logging.rb:15:in `block (2 levels) in <module:Logging>'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:126:in `instance_exec'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:137:in `run_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/execution.rb:47:in `perform_now'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/execution.rb:25:in `block in execute'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:117:in `block in run_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/railtie.rb:47:in `block (4 levels) in <class:Railtie>'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/execution_wrapper.rb:88:in `wrap'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/reloader.rb:72:in `block in wrap'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/execution_wrapper.rb:84:in `wrap'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/reloader.rb:71:in `wrap'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/railtie.rb:46:in `block (3 levels) in <class:Railtie>'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:126:in `instance_exec'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:126:in `block in run_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/callbacks.rb:137:in `run_callbacks'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/execution.rb:23:in `execute'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activejob-6.1.3.1/lib/active_job/queue_adapters/sidekiq_adapter.rb:42:in `perform'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:196:in `execute_job'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:164:in `block (2 levels) in process'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/middleware/chain.rb:138:in `block in invoke'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/bugsnag-6.19.0/lib/bugsnag/integrations/sidekiq.rb:24:in `call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/middleware/chain.rb:140:in `block in invoke'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-failures-1.0.0/lib/sidekiq/failures/middleware.rb:9:in `call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/middleware/chain.rb:140:in `block in invoke'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/skylight-5.1.1/lib/skylight/sidekiq.rb:33:in `block in call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/skylight-5.1.1/lib/skylight.rb:150:in `block in trace'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/skylight-5.1.1/lib/skylight/instrumenter.rb:224:in `trace'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/skylight-5.1.1/lib/skylight.rb:149:in `trace'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/skylight-5.1.1/lib/skylight/sidekiq.rb:32:in `call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/middleware/chain.rb:140:in `block in invoke'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/middleware/chain.rb:143:in `invoke'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:163:in `block in process'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:136:in `block (6 levels) in dispatch'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/job_retry.rb:112:in `local'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:135:in `block (5 levels) in dispatch'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/rails.rb:14:in `block in call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/execution_wrapper.rb:88:in `wrap'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/reloader.rb:72:in `block in wrap'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/execution_wrapper.rb:88:in `wrap'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/activesupport-6.1.3.1/lib/active_support/reloader.rb:71:in `wrap'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/rails.rb:13:in `call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:131:in `block (4 levels) in dispatch'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:257:in `stats'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:126:in `block (3 levels) in dispatch'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/job_logger.rb:13:in `call'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:125:in `block (2 levels) in dispatch'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/job_retry.rb:79:in `global'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:124:in `block in dispatch'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/logger.rb:11:in `with'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/job_logger.rb:33:in `prepare'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:123:in `dispatch'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:162:in `process'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:78:in `process_one'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/processor.rb:68:in `run'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/util.rb:43:in `watchdog'
/opt/exercism/website/current/vendor/bundle/ruby/2.6.0/gems/sidekiq-6.2.1/lib/sidekiq/util.rb:52:in `block in safe_thread'

Please tag @iHiD if you require more information.

Track introduction is missing

The Crystal track page is missing an introduction; the default "TODO: The maintainers have not provided an introduction for this track" message is displayed instead.

I think the only change required is for a non-empty string to be added in the "blurb" property of the track configuration JSON file. I'd be willing to fix this if a maintainer would help me come up with an appropriate description!

Recruiting additional maintainers for Crystal

We're about to start a big push towards version 3 (v3) of Exercism. This is going to be a really exciting step forward for Exercism, with in-browser coding, new Concept Exercises with automated feedback, improved mentoring and much more.

This to be a big community effort, with the work spread out among hundreds of volunteers across Exercism. One key thing is going to be each track having enough maintainers who have the time to manage that community effort. We are therefore putting out a call for new maintainers to bolster our numbers. We're hoping that our existing maintainers will be able to act as mentors to the newer maintainers we add, and take on a parental role in the tracks.

If you are an existing maintainer, could you please reply to this letting us know that you think you'll have time (2-3hrs/week) to help with this over the next 6 months. If you won't have that time, but still want to be a maintainer and just help where you can instead, please tell us that too. If you have come to the end of the road as a maintainer, then we totally understand that and appreciate all your effort, so just let us know.

For anyone new who's interested in becoming a maintainer, thanks for your interest! Being an Exercism maintainer is also a great opportunity to work with some other smart people, learn more about your language of choice, and gain useful skills and experience that are useful for growing your career in the technical leadership direction. Please write a comment below introducing yourself along with your Exercism handle, and telling us why you're interested in becoming a maintainer, and any relevant experience. We will then evaluate every application and contact you using your exercism email address once we have finished the evaluation process.

Thank you!

See also exercism/exercism#5161

[hamming] Levenshtein is not the same as Hamming distance

Levenshtein-distance is not the same as Hamming-distance.

From Wikipedia, I have the following snippet of ruby code which does calculate the Hamming-Distance:

def hammingDistance(s1, s2)
    raise "ERROR: Hamming: Non equal lengths" if s1.length != s2.length
    (s1.chars.zip(s2.chars)).count {|l, r| l != r}
end

Translating this to crystal yields the following:

module Hamming
  def self.compute(l, r)
    raise(ArgumentError.new()) if l.size != r.size
    l.chars.zip(r.chars).count { |x| x[0] != x[1] }
  end
end

But running the test yields a fail:

Failures:

  1) Hamming #compute computes a distance for large strands
     Failure/Error: Hamming.compute("GGACGGATTCTG", "AGGACGGATTCT").should eq 2

       expected: 2
            got: 9

Counting this by hand, I do get a distance of 9, like my code.

Also looking at the site of Levenshtein distance on Wikipedia, it seems that L-distance is comparing everything with everything.

According to my observations the difference is especially visible when having rotatet sequences. H-distance of "abcdefgh" and "bcdefgha" is 8, since there is not a single character as the one on the same index on the other string, while the L-distance of both is 2!

rna-transcription: don't transcribe both ways

I can't remember the history of this, but we ended up with a weird non-biological thing in the RNA transcription exercise, where some test suites also have tests for transcribing from RNA back to DNA. This makes no sense.

If this track does have tests for the reverse transcription, we should remove them, and also simplify the reference solution to match.

If this track doesn't have any tests for RNA->DNA transcription, then this issue can be closed.

See exercism/problem-specifications#148

Add prerequisites to Practice Exercises

This issue is part of the migration to v3. You can read full details about the various changes here.

Exercism v3 introduces a new type of exercise: Concept Exercises. All existing (V2) exercises will become Practice Exercises.

Concept Exercises and Practice Exercises are linked to each other via Concepts. Concepts are taught by Concept Exercises and practiced in Practice Exercises. Each Exercise (Concept or Practice) has prerequisites, which must be met to unlock an Exercise - once all the prerequisite Concepts have been "taught" by a Concept Exercise, the exercise itself becomes unlocked.

For example, in some languages completing the Concept Exercises that teach the "String Interpolation" and "Optional Parameters" concepts might then unlock the two-fer Practice Exercise.

Each Practice Exercise has two fields containing concepts: a practices field and a prerequisites field.

Practices

The practices key should list the slugs of Concepts that this Practice Exercise actively allows a student to practice.

  • These show up in the UI as "Practice this Concept in: TwoFer, Leap, etc"
  • Try and choose 3 - 8 Exercises that practice each Concept.
  • Try and choose at least two Exercises that allow someone to practice the basics of a Concept.
  • Some Concepts are very common (for example strings). In those cases we recommend choosing a few good exercises that make people think about those Concepts in interesting ways. For example, exercises that require UTF-8, string concatenation, char enumeration, etc, would all be good examples.
  • There should be one or more Concepts to practice per exercise.

Prerequisites

The prerequisites key lists the Concept Exercises that a student must have completed in order to access this Practice Exercise.

  • These show up in the UI as "Learn Strings to unlock TwoFer"
  • It should include all Concepts that a student needs to have covered to be able to complete the exercise in at least one idiomatic way. For example, for the TwoFer exercise in Ruby, prerequisites might include strings, optional-params, implicit-return.
  • For Exercises that can be completed using alternative Concepts (e.g. an Exercise solvable by loops or recursion), the maintainer should choose the one approach that they would like to unlock the Exercise, considering the student's journey through the track. For example, the loops/recursion example, they might think this exercise is a good early practice of loops or that they might like to leave it later to teach recursion. They can also make use of an analyzer to prompt the student to try an alternative approach: "Nice work on solving this via loops. You might also like to try solving this using Recursion."
  • There should be one or more prerequisites Concepts per exercise.

Although ideally all Concepts should be taught by Concept Exercises, we recognise that it will take time for tracks to achieve that. Any Practice Exercises that have prerequisites which are not taught by Concept Exercises, will become unlocked once the final Concept Exercise has been completed.

Goal

Practices

The "practices" field of each element in the "exercises.practice" field in the config.json file should be updated to contain the practice concepts. See the spec.

To help with identifying the practice concepts, the "topics" field can be used (if it has any contents). Once prerequisites have been defined for a Practice Exercise, the "topics" field should be removed.

Each practice concept should have its own entry in the top-level "concepts" array. See the spec.

Prerequisites

The "prerequisites" field of each element in the "exercises.practice" field in the config.json file should be updated to contain the prerequisite concepts. See the spec.

To help with identifying the prerequisites, the "topics" field can be used (if it has any contents). Once prerequisites have been defined for a Practice Exercise, the "topics" field should be removed.

Each prerequisite concept should have its own entry in the top-level "concepts" array. See the spec.

Example

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

Tracking

exercism/v3-launch#6

Problem with Resistor-Color-Duo

This particular exercise (at least in Crystal track) has a logic error.
https://exercism.io/my/solutions/bd58d29f62564188a2cb39e716d7d797

The test suite expects output as an int, however, it will fail for this particular test:

  it "Black and Yellow" do
    ResistorColorDuo.value(["black", "yellow"]).should eq(04)
  end

If the first color in the input is black => 0 according to the instructions, which will result in 4 as output since the string "04", when cast into an integer, will return 4. Thus causing electrocution or spaceship explosion, or some other unintended result.

Either the instructions need to change and say "black" will never be the first color or the test suite should check for string rather than int

largest-series-product: Should it raise on invalid inputs?

Currently, the largest-series-product tests expect a value of -1 if the input is invalid in some way (non-digit in digit sequence, negative window size, too-large window size). Should it raise an exception instead? Not sure what the idiomatic way is in Crystal to test for errors, whether it is normal to expect impossible values, but it seems if exceptions are available they can be used.

test-generator fails in Travis

The test-generator task is failing in the Travis environment. I'm unable to reproduce the issue locally.

This is the relevant test output I see in Travis:

Fetching https://github.com/manastech/webmock.cr.git
Installing webmock (0.10.0 at master)
..EFF..
Failures:
  1) RemoteDataFile #path when successful raises a not found exception if status is 404
     Failure/Error: expect_raises(Exception, error_message) do
       Expected Exception with "A canonical-data.json doesn't exist for test-exercise in problem-specifications. Go make one!", got #<KeyError: Missing hash key: HTTP::Headers::Key(@name="Host")> with backtrace:
         # /usr/share/crystal/src/hash.cr:0:9 in 'fetch'
         # /usr/share/crystal/src/http/headers.cr:129:5 in 'fetch'
         # /usr/share/crystal/src/http/headers.cr:66:5 in '[]'
         # lib/webmock/src/webmock/stub.cr:61:16 in 'matches_host?'
         # lib/webmock/src/webmock/stub.cr:44:7 in 'matches?'
         # lib/webmock/src/webmock/stub_registry.cr:17:19 in 'find_stub'
         # lib/webmock/src/webmock.cr:32:5 in 'find_stub'
         # lib/webmock/src/webmock/core_ext.cr:11:5 in 'exec_internal'
         # /usr/share/crystal/src/http/client.cr:481:5 in 'exec'
         # /usr/share/crystal/src/http/client.cr:599:5 in 'exec'
         # /usr/share/crystal/src/http/client.cr:627:7 in 'exec'
         # /usr/share/crystal/src/http/client.cr:329:3 in 'get'
         # src/remote_data_file.cr:41:16 in 'body'
         # src/remote_data_file.cr:18:5 in 'remote_file'
         # src/remote_data_file.cr:13:7 in 'path'
         # spec/remote_data_file_spec.cr:38:11 in '->'
         # /usr/share/crystal/src/spec/methods.cr:255:3 in 'it'
         # spec/remote_data_file_spec.cr:31:7 in '->'
         # /usr/share/crystal/src/spec/context.cr:255:3 in 'describe'
         # /usr/share/crystal/src/spec/methods.cr:16:5 in 'describe'
         # /usr/share/crystal/src/spec/methods.cr:25:5 in 'context'
         # spec/remote_data_file_spec.cr:30:5 in '->'
         # /usr/share/crystal/src/spec/context.cr:255:3 in 'describe'
         # /usr/share/crystal/src/spec/methods.cr:16:5 in 'describe'
         # spec/remote_data_file_spec.cr:10:3 in '->'
         # /usr/share/crystal/src/spec/context.cr:255:3 in 'describe'
         # /usr/share/crystal/src/spec/methods.cr:16:5 in 'describe'
         # spec/exercise_test_case_spec.cr:1:1 in '__crystal_main'
         # /usr/share/crystal/src/crystal/main.cr:97:5 in 'main_user_code'
         # /usr/share/crystal/src/crystal/main.cr:86:7 in 'main'
         # /usr/share/crystal/src/crystal/main.cr:106:3 in 'main'
         # __libc_start_main
         # ???
         # ???
     # spec/remote_data_file_spec.cr:37
  2) RemoteDataFile #path when successful raises a unexpected exception if status is other than 200 or 404
     Failure/Error: expect_raises(Exception, error_message) do
       Expected Exception with "Error while requesting the test-exercise data file from GitHub... Status was 500", got #<KeyError: Missing hash key: HTTP::Headers::Key(@name="Host")> with backtrace:
         # /usr/share/crystal/src/hash.cr:0:9 in 'fetch'
         # /usr/share/crystal/src/http/headers.cr:129:5 in 'fetch'
         # /usr/share/crystal/src/http/headers.cr:66:5 in '[]'
         # lib/webmock/src/webmock/stub.cr:61:16 in 'matches_host?'
         # lib/webmock/src/webmock/stub.cr:44:7 in 'matches?'
         # lib/webmock/src/webmock/stub_registry.cr:17:19 in 'find_stub'
         # lib/webmock/src/webmock.cr:32:5 in 'find_stub'
         # lib/webmock/src/webmock/core_ext.cr:11:5 in 'exec_internal'
         # /usr/share/crystal/src/http/client.cr:481:5 in 'exec'
         # /usr/share/crystal/src/http/client.cr:599:5 in 'exec'
         # /usr/share/crystal/src/http/client.cr:627:7 in 'exec'
         # /usr/share/crystal/src/http/client.cr:329:3 in 'get'
         # src/remote_data_file.cr:41:16 in 'body'
         # src/remote_data_file.cr:18:5 in 'remote_file'
         # src/remote_data_file.cr:13:7 in 'path'
         # spec/remote_data_file_spec.cr:48:11 in '->'
         # /usr/share/crystal/src/spec/methods.cr:255:3 in 'it'
         # spec/remote_data_file_spec.cr:42:7 in '->'
         # /usr/share/crystal/src/spec/context.cr:255:3 in 'describe'
         # /usr/share/crystal/src/spec/methods.cr:16:5 in 'describe'
         # /usr/share/crystal/src/spec/methods.cr:25:5 in 'context'
         # spec/remote_data_file_spec.cr:30:5 in '->'
         # /usr/share/crystal/src/spec/context.cr:255:3 in 'describe'0m
         # /usr/share/crystal/src/spec/methods.cr:16:5 in 'describe'
         # spec/remote_data_file_spec.cr:10:3 in '->'
         # /usr/share/crystal/src/spec/context.cr:255:3 in 'describe'
         # /usr/share/crystal/src/spec/methods.cr:16:5 in 'describe'
         # spec/exercise_test_case_spec.cr:1:1 in '__crystal_main'
         # /usr/share/crystal/src/crystal/main.cr:97:5 in 'main_user_code'
         # /usr/share/crystal/src/crystal/main.cr:86:7 in 'main'
         # /usr/share/crystal/src/crystal/main.cr:106:3 in 'main'
         # __libc_start_main
         # ???
         # ???
     # spec/remote_data_file_spec.cr:47
  3) RemoteDataFile #path when successful returns the response body if status is 200
       Missing hash key: HTTP::Headers::Key(@name="Host") (KeyError)
         from /usr/share/crystal/src/hash.cr:0:9 in 'fetch'
         from /usr/share/crystal/src/http/headers.cr:129:5 in 'fetch'
         from /usr/share/crystal/src/http/headers.cr:66:5 in '[]'
         from lib/webmock/src/webmock/stub.cr:61:16 in 'matches_host?'
         from lib/webmock/src/webmock/stub.cr:44:7 in 'matches?'
         from lib/webmock/src/webmock/stub_registry.cr:17:19 in 'find_stub'
         from lib/webmock/src/webmock.cr:32:5 in 'find_stub'
         from lib/webmock/src/webmock/core_ext.cr:11:5 in 'exec_internal'
         from /usr/share/crystal/src/http/client.cr:481:5 in 'exec'
         from /usr/share/crystal/src/http/client.cr:599:5 in 'exec'
         from /usr/share/crystal/src/http/client.cr:627:7 in 'exec'
         from /usr/share/crystal/src/http/client.cr:329:3 in 'get'
         from src/remote_data_file.cr:41:16 in 'body'
         from src/remote_data_file.cr:18:5 in 'remote_file'
         from src/remote_data_file.cr:13:7 in 'path'
         from spec/remote_data_file_spec.cr:26:9 in '->'
         from /usr/share/crystal/src/spec/methods.cr:255:3 in 'it'
         from spec/remote_data_file_spec.cr:21:7 in '->'
         from /usr/share/crystal/src/spec/context.cr:255:3 in 'describe'
         from /usr/share/crystal/src/spec/methods.cr:16:5 in 'describe'
         from /usr/share/crystal/src/spec/methods.cr:25:5 in 'context'
         from spec/remote_data_file_spec.cr:11:5 in '->'
         from /usr/share/crystal/src/spec/context.cr:255:3 in 'describe'
         from /usr/share/crystal/src/spec/methods.cr:16:5 in 'describe'
         from spec/remote_data_file_spec.cr:10:3 in '->'
         from /usr/share/crystal/src/spec/context.cr:255:3 in 'describe'
         from /usr/share/crystal/src/spec/methods.cr:16:5 in 'describe'
         from spec/exercise_test_case_spec.cr:1:1 in '__crystal_main'
         from /usr/share/crystal/src/crystal/main.cr:97:5 in 'main_user_code'
         from /usr/share/crystal/src/crystal/main.cr:86:7 in 'main'
         from /usr/share/crystal/src/crystal/main.cr:106:3 in 'main'
         from __libc_start_main
         from ???
         from ???
       
Finished in 121.97 milliseconds
7 examples, 2 failures, 1 errors, 0 pending
Failed examples:
crystal spec spec/remote_data_file_spec.cr:31 # RemoteDataFile #path when successful raises a not found exception if status is 404
crystal spec spec/remote_data_file_spec.cr:42 # RemoteDataFile #path when successful raises a unexpected exception if status is other than 200 or 404
crystal spec spec/remote_data_file_spec.cr:21 # RemoteDataFile #path when successful returns the response body if status is 200

Launch Checklist

In order to launch we should have:

  • Crystal as a submodule in x-api
  • At least 10 problems
  • Documentation (see below)
  • One to a handful of people willing to check exercism regularly (daily?) to review. This will ensure that the track gets off on the right foot.
  • Add track implementors and other designated code reviewers as mentors to the track. This gives you access to all the solutions in Crystal whether or not you've submitted the problem to the site.
  • Add a language icon or logo (see below)
  • Toggle "active" to true in config.json
  • Send an email to the mailing list.

Documentation

The documentation lives in the docs/ directory here in this repository, and gets served to the site via the x-api. It should contain at minimim:

  • INSTALLATION.md - about how to get the language set up locally.
  • TESTS.md - about how to run the tests for the exercises.

Some nice to haves:

  • ABOUT.md - a short, friendly blurb about the language. What types of problems does it solve really well? What is it typically used for?
  • LEARNING.md - a few notes about where people might want to go to learn the language from scratch.
  • RESOURCES.md - references and other useful resources.

Logo/Icon

We try to create a language icon that has the exercism colors, and is recognizably similar to the language icon. Sometimes this isn't possible due to copyright issues. See http://exercism.io/languages for all the existing icons.

The logo should live under /public/img/tracks/ in the exercism/exercism.io repository.
https://github.com/exercism/exercism.io/tree/master/public/img/tracks

Attribution goes in https://github.com/exercism/exercism.io/blob/master/ATTRIBUTION.md

If image assets are not your strong suit, just find a reasonable image to start from, along with the information about the licensing, and we'll figure out the colorization thing (I've written some scripts to help me do this part).

Some icons are the official language logo (tweaked). Where a language doesn't seem to have an official logo, or where the official logo has copyright issues, we just make something up.

Successful Launches

Some tracks have been more successful than others, and I believe the key features of the successful tracks are:

  • Each submission receives feedback quickly, preferably within the first 24 hours.
  • The nitpicks do not direct users to do specific things, but rather ask questions challenging people to think about different aspects of their solution, or explore new aspects of the language.

For more about contributing to language tracks on exercism, check out the Problem API Contributing guide: https://github.com/exercism/x-api/blob/master/CONTRIBUTING.md

Investigate track health and status of the track

I've used Sarah Sharp's FOSS Heartbeat project to generate stats for each of the language track repositories, as well as the x-common repository.

The Exercism heartbeat data is published here: https://exercism.github.io/heartbeat/

When looking at the data, please disregard any activity from me (kytrinyx), as I would like to get the language tracks to a point where they are entirely maintained by the community.

Please take a look at the heartbeat data for this track, and answer the following questions:

  • To what degree is the track maintained?
  • Who (if anyone) is merging pull requests?
  • Who (if anyone) is reviewing pull requests?
  • Is there someone who is not merging pull requests, but who comments on issues and pull requests, has thoughtful feedback, and is generally helpful? If so, maybe we can invite them to be a maintainer on the track.

I've made up the following scale:

  • ORPHANED - Nobody (other than me) has merged anything in the past year.
  • ENDANGERED - Somewhere between ORPHANED and AT RISK.
  • AT RISK - Two people (other than me) are actively discussing issues and reviewing and merging pull requests.
  • MAINTAINED - Three or more people (other than me) are actively discussing issues and reviewing and merging pull requests.

It would also be useful to know if there a lot of activity on the track, or just the occasional issue or comment.

Please report the current status of the track, including your best guess on the above scale, back to the top-level issue in the discussions repository: exercism/discussions#97

Configure online editor

This issue is part of the migration to v3. You can read full details about the various changes here.

In Exercism v3, students can now choose to work on exercises directly from their browser, instead of having to download exercises to their local machine. The track-specific settings for the in-browser editor are defined in the top-level "online_editor" field in the track's config.json file. This field is defined as an object with two fields:

  • "indent_style": the indent style, either "space" or "tab".
  • "indent_size": the indent size, which is an integer (e.g. 4).

You can find a full description of these fields in the spec.

Goal

The "online_editor" field should be updated to correspond to the track's best practices regarding indentation.

Example

"online_editor": {
  "indent_style": "space",
  "indent_size": 4
}

Tracking

exercism/v3-launch#2

[v3] Build Test Runner

This issue is part of the migration to v3. You can read full details about the various changes here.

In Exercism v3, one of the biggest changes is that we'll automatically check if a submitted solution passes all the tests.

We'll check this via a new, track-specific tool: the Test Runner. Each test runner is track-specific. When a new solution is submitted, we run the track's test runner, which outputs a JSON file that describes the test results.

The test runner must be able to run the tests suites of both Concept Exercises and Practice Exercises. Depending on the test runner implementation, this could mean having to update the Practice Exercises to the format expected by the test runner.

Goal

Build a test runner for your track according to the spec.

If you are building a test runner from scratch, we have a starting guide and a generic test runner that can be used as the base for the new test runner.

If a test runner has already been built for this track, please check if it works on both Concept Exercises and Practice Exercises.

It can be very useful to check how other tracks have implemented their test runner.

Tracking

exercism/v3-launch#4

Drop `is_` prefix in predicate methods?

In PR #11, the question was raised whether Crystal had a preference for including prefixes in predicate methods (e.g., is_pangram?) or drop them like in Ruby. The coding style section of the Crystal docs is pretty short at this point, so I didn't see any style preference for predicate methods. I did find the following commit from a recent PR that was merged to the core language that would suggest they also prefer to drop the is_ prefix too:

Various cleanups #2668

Would you like me to go through the existing exercises and drop any prefixes on predicate methods (e.g., is_leap)?

Pass linting checks

This issue is part of the migration to v3. You can read full details about the various changes here.

The configlet tool has a lint command that checks if a track's configuration files are properly structured - both syntactically and semantically. Misconfigured tracks may not sync correctly, may look wrong on the website, or may present a suboptimal user experience, so configlet's guards play an important part in maintaining the integrity of Exercism.

We're updating configlet to work with v3 tracks, which have a different set of requirements than v2 tracks.

The full list of rules that will be checked by the linter can be found in this spec.

⚠ Note that only a subset of the linting rules has been implemented at this moment. This means that while your track may be passing the checks at this moment, it might fail later. We thus strongly suggest you keep this issue open until we let you know otherwise.

Goal

Ensure that the track passes all the (v3 track) checks defined in configlet lint.

To help verify that the track passes all the linting rules, the v3 preparation PR has added a GitHub Actions workflow that automatically runs configlet lint.

It is also possible to run configlet lint locally by running the ./bin/fetch-configlet (or ./bin/fetch-configlet.ps1) script to download a local copy of the configlet binary. Once downloaded, you can then do ./bin/configlet lint to run the linting on your own machine.

Tracking

exercism/v3-launch#3

[v3] Add key features

This issue is part of the migration to v3. You can read full details about the various changes here.

In Exercism v3, each track must specify exactly six "key features". Exercism uses these features to highlight the most interesting, unique or "best" features of a language to a student.

Key features are specified in the top-level "key_features" field in the track's config.json file and are defined as an array of objects, as specified in the spec.

Goal

The "key_features" field in the config.json file should be updated to describe the six "key features" of this track. See the spec.

Example

{
  "key_features": [
    {
      "icon": "features-oop",
      "title": "Modern",
      "content": "C# is a modern, fast-evolving language."
    },
    {
      "icon": "features-strongly-typed",
      "title": "Cross-platform",
      "content": "C# runs on almost any platform and chipset."
    },
    {
      "icon": "features-functional",
      "title": "Multi-paradigm",
      "content": "C# is primarily an object-oriented language, but also has lots of functional features."
    },
    {
      "icon": "features-lazy",
      "title": "General purpose",
      "content": "C# can be used for a wide variety of workloads, like websites, console applications, and even games."
    },
    {
      "icon": "features-declarative",
      "title": "Tooling",
      "content": "C# has excellent tooling, with linting and advanced refactoring options built-in."
    },
    {
      "icon": "features-generic",
      "title": "Documentation",
      "content": "Documentation is excellent and exhaustive, making it easy to get started with C#."
    }
  ]
}

Tracking

exercism/v3-launch#5

Use JSON.mapping for Generators

I believe we should be using JSON.mapping to simplify our Generator classes and make the code a bit cleaner. We can simply map the canonical_data.json and create our Generator/Test Cases.

Example:

class HelloWorldGenerator < ExerciseGenerator
  JSON.mapping(
    exercise: String,
    version: String,
    cases: Array(HelloWorldTestCase)
  )
end


class HelloWorldTestCase < ExerciseTestCase
  JSON.mapping(
    description: String,
    property: String,
    expected: String
  )

  def workload
    "HelloWorld.hello.should eq(\"#{expected}\")"
  end

  def test_name
    description
  end
end

Ensure Crystal track is ready for v2 launch

There are a number of things we're going to want to check before the v2 site goes live. There are notes below that flesh out all the checklist items.

  • The track has a page on the v2 site: https://v2.exercism.io/tracks/crystal
  • The track page has a short description under the name (not starting with TODO)
  • The "About" section is a friendly, colloquial, compelling introduction
  • The "About" section follows the formatting guidelines
  • The code example gives a good taste of the language and fits within the boundaries of the background image
  • There are exercises marked as core
  • Exercises have rough estimates of difficulty
  • Exercises have topics associated with them
  • The first exercise is auto_approve: true

Track landing page

The v2 site has a landing page for each track, which should make people want to join it. If the track page is missing, ping @kytrinyx to get it added.

Blurb

If the header of the page starts with TODO, then submit a pull request to https://github.com/exercism/crystal/blob/master/config.json with a blurb key. Remember to get configlet and run configlet fmt . from the root of the track before submitting.

About section

If the "About" section feels a bit dry, then submit a pull request to https://github.com/exercism/crystal/blob/master/docs/ABOUT.md with suggested tweaks.

Formatting guidelines

In order to work well with the design of the new site, we're restricting the formatting of the ABOUT.md. It can use:

  • Bold
  • Italics
  • Links
  • Bullet lists
  • Number lists

Additionally:

  • Each sentence should be on its own line
  • Paragraphs should be separated by an empty line
  • Explicit <br/> can be used to split a paragraph into lines without spacing between them, however this is discouraged.

Code example

If the code example is too short or too wide or too long or too uninteresting, submit a pull request to https://github.com/exercism/ocaml/blob/master/docs/SNIPPET.txt with a suggested replacement.

Exercise metadata

Where the v1 site has a long, linear list of exercises, the v2 site has organized exercises into a small set of required exercises ("core").

If you update the track config, remember to get configlet and run configlet fmt . from the root of the track before submitting.

Topic and difficulty

Core exercises unlock optional additional exercises, which can be filtered by topic an difficulty, however that will only work if we add topics and difficulties to the exercises in the track config, which is in https://github.com/exercism/crystal/blob/master/config.json

Auto-approval

We've currently made any hello-world exercises auto-approved in the backend of v2. This means that you don't need mentor approval in order to move forward when you've completed that exercise.

Not all tracks have a hello-world, and some tracks might want to auto approve other (or additional) exercises.

Track mentors

There are no bullet points for this one :)

As we move towards the launch of the new version of Exercism we are going to be ramping up on actively recruiting people to help provide feedback. Our goal is to get to 100%: everyone who submits a solution and wants feedback should get feedback. Good feedback.

If you're interested in helping mentor the track, check out http://mentoring.exercism.io/

When all of the boxes are ticked off, please close the issue.

Tracking progress in exercism/meta#104

Update generators

A lot of problem specifications have been updated to a new format and the generators need to follow suite. Some generators have been updated but I would think that 2/3 of them still need to be checked/updated.

To do this, I would run make generate-exercises and see which ones error out and go from there.

You can find the problem specifications for each exercise here: https://github.com/exercism/problem-specifications.

Update status of Concept Exercises

This issue is part of the migration to v3. You can read full details about the various changes here.

Concept Exercises can have a status specified in their "status" field in their config.json entry, as specified in the spec. This status can be one of four values:

  • "wip": A work-in-progress exercise not ready for public consumption. Exercises with this tag will not be shown to students on the UI or be used for unlocking logic. They may appear for maintainers.
  • "beta": This signifies active exercises that are new and which we would like feedback on. We show a beta label on the site for these exercise, with a Call To Action of "Please give us feedback."
  • "active": The normal state of active exercises
  • "deprecated": Exercises that are no longer shown to students who have not started them (not usable at this stage).

The "status" key can also be omitted, which is the equivalent of setting it to "active".

Goal

The "status" field of Concept Exercises in the config.json file should be updated to reflect the status of the Concept Exercises. See the spec for more information.

If your track doesn't have any Concept Exercises, this issue can be closed.

Example: removed wip status

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

Example: replaced wip status with active

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

Tracking

exercism/v3-launch#14

Extract track-specific test instructions from `config/exercise_readme.go.tmpl`

Each track needs a file that contains track-specific instructions on how to manually run the tests. The contents of this document are only presented to the student when using the CLI. This file lives at exercises/shared/.docs/tests.md. You almost certainly already have this information, but need to move it to the correct place.

For v2 tracks, this information was (usually) included in the readme template found at config/exercise_readme.go.tmpl. As such, tracks can extract the test instructions from the config/exercise_readme.go.tmpl file to the exercises/shared/.docs/tests.md file.

See https://github.com/exercism/csharp/pull/1557/files for an example PR.

Tracking

exercism/v3-launch#51

Launch Tracker 🔴

This issue is part of the migration to v3. You can read full details about the various changes here.

To get your track ready for Exercism v3, the following needs to be done:

This issue may be automatically added to over time. While track maintainers should check off completed items, please do not add/edit items in the list.

Tracking

exercism/v3-launch#7

Copy track icon into language track repository

Right now all of the icons used for the language tracks (which can be seen at http://exercism.io/languages) are stored in the exercism/exercism.io repository in public/img/tracks/. It would make a lot more sense to keep these images along with all of the other language-specific stuff in each individual language track repository.

There's a pull request that is adding support for serving up the track icon from the x-api, which deals with language-specific stuff.

In order to support this change, each track will need to

In other words, at the end of it you should have the following file:

./img/icon.png

See exercism/exercism#2925 for more details.

Update README for new generator

I updated the test generator a few commits ago and the README needs some love.

Mostly about where the generator now lives, the make commands for it, and how it works (with the newly added remote data file).

Update config.json to match new specification

For the past three years, the ordering of exercises has been done based on gut feelings and wild guesses. As a result, the progression of the exercises has been somewhat haphazard.

In the past few months maintainers of several tracks have invested a great deal of time in analyzing what concepts various exercises require, and then reordering the tracks as a result of that analysis.

It would be useful to bake this data into the track configuration so that we can adjust it over time as we learn more about each exercise.

To this end, we've decided to add a new key exercises in the config.json file, and deprecate the problems key.

See exercism/discussions#60 for details about this decision.

Note that we will not be removing the problems key at this time, as this would break the website and a number of tools.

The process for deprecating the old problems array will be:

  • Update all of the track configs to contain the new exercises key, with whatever data we have.
  • Simultaneously change the website and tools to support both formats.
  • Once all of the tracks have added the exercises key, remove support for the old key in the site and tools.
  • Remove the old key from all of the track configs.

In the new format, each exercise is a JSON object with three properties:

  • slug: the identifier of the exercise
  • difficulty: a number from 1 to 10 where 1 is the easiest and 10 is the most difficult
  • topics: an array of strings describing topics relevant to the exercise. We maintain
    a list of common topics at https://github.com/exercism/x-common/blob/master/TOPICS.txt. Do not feel like you need to restrict yourself to this list;
    it's only there so that we don't end up with 20 variations on the same topic. Each
    language is different, and there will likely be topics specific to each language that will
    not make it onto the list.

The difficulty rating can be a very rough estimate.

The topics array can be empty if this analysis has not yet been done.

Example:

"exercises": [
  {
    "slug": "hello-world" ,
    "difficulty": 1,
    "topics": [
        "control-flow (if-statements)",
        "optional values",
        "text formatting"
    ]
  },
  {
    "difficulty": 3,
    "slug": "anagram",
    "topics": [
        "strings",
        "filtering"
    ]
  },
  {
    "difficulty": 10,
    "slug": "forth",
    "topics": [
        "parsing",
        "transforming",
        "stacks"
    ]
  }
]

It may be worth making the change in several passes:

  1. Add the exercises key with the array of objects, where difficulty is 1 and topics is empty.
  2. Update the difficulty settings to reflect a more accurate guess.
  3. Add topics (perhaps one-by-one, in separate pull requests, in order to have useful discussions about each exercise).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.