Parallel Letter Frequency
This commit is contained in:
parent
3ca9867a11
commit
af89290bbc
45 changed files with 2862 additions and 0 deletions
36
bash/hello-world/.exercism/config.json
Normal file
36
bash/hello-world/.exercism/config.json
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"authors": [],
|
||||||
|
"contributors": [
|
||||||
|
"adelcambre",
|
||||||
|
"bkhl",
|
||||||
|
"budmc29",
|
||||||
|
"coreygo",
|
||||||
|
"glennj",
|
||||||
|
"guygastineau",
|
||||||
|
"IsaacG",
|
||||||
|
"kenden",
|
||||||
|
"kotp",
|
||||||
|
"kytrinyx",
|
||||||
|
"MattLewin",
|
||||||
|
"platinumthinker",
|
||||||
|
"quartzinquartz",
|
||||||
|
"rootulp",
|
||||||
|
"sjwarner-bp",
|
||||||
|
"Smarticles101",
|
||||||
|
"ZapAnton"
|
||||||
|
],
|
||||||
|
"files": {
|
||||||
|
"solution": [
|
||||||
|
"hello_world.sh"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"hello_world.bats"
|
||||||
|
],
|
||||||
|
"example": [
|
||||||
|
".meta/example.sh"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".",
|
||||||
|
"source": "This is an exercise to introduce users to using Exercism",
|
||||||
|
"source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program"
|
||||||
|
}
|
||||||
142
bash/hello-world/HELP.md
Normal file
142
bash/hello-world/HELP.md
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
# Help
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
Each exercise contains a test file.
|
||||||
|
Run the tests using the `bats` program.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bats hello_world.bats
|
||||||
|
```
|
||||||
|
|
||||||
|
`bats` will need to be installed.
|
||||||
|
See the [Testing on the Bash track][tests] page for instructions to install `bats` for your system.
|
||||||
|
|
||||||
|
[tests]: https://exercism.org/docs/tracks/bash/tests
|
||||||
|
|
||||||
|
## Help for assert functions
|
||||||
|
|
||||||
|
The tests use functions from the [bats-assert][bats-assert] library.
|
||||||
|
Help for the various `assert*` functions can be found there.
|
||||||
|
|
||||||
|
[bats-assert]: https://github.com/bats-core/bats-assert
|
||||||
|
|
||||||
|
## Debugging output
|
||||||
|
|
||||||
|
```exercism/caution
|
||||||
|
This works locally with `bats`, but **not** in the Exercism online editor.
|
||||||
|
```
|
||||||
|
|
||||||
|
When running tests, `bats` captures both stdout and stderr for comparison with the expected output.
|
||||||
|
If you print debug messages to stdout (`echo`) or stderr (`>&2`), they will be included in the captured output and may cause the test to fail.
|
||||||
|
|
||||||
|
To print debug information without affecting the test results, `bats` provides file descriptor **3** for this purpose.
|
||||||
|
Anything redirected to `>&3` will be shown during the test run but will not be included in the captured output used for assertions.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# This debug message will not interfere with test output comparison
|
||||||
|
echo "debug message" >&3
|
||||||
|
|
||||||
|
# Normal program output (this is what your tests will see and compare)
|
||||||
|
echo "Hello, World!"
|
||||||
|
```
|
||||||
|
|
||||||
|
Example run:
|
||||||
|
|
||||||
|
```none
|
||||||
|
$ bats hello_world.bats
|
||||||
|
hello_world.bats
|
||||||
|
✓ Say Hi!
|
||||||
|
debug message
|
||||||
|
1 test, 0 failures
|
||||||
|
```
|
||||||
|
|
||||||
|
This allows you to see helpful debug output without affecting the tests.
|
||||||
|
|
||||||
|
## Skipped tests
|
||||||
|
|
||||||
|
Solving an exercise means making all its tests pass.
|
||||||
|
By default, only one test (the first one) is executed when you run the tests.
|
||||||
|
This is intentional, as it allows you to focus on just making that one test pass.
|
||||||
|
Once it passes, you can enable the next test by commenting out or removing the next annotation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[[ $BATS_RUN_SKIPPED == true ]] || skip
|
||||||
|
```
|
||||||
|
|
||||||
|
## Overriding skips
|
||||||
|
|
||||||
|
To run all tests, including the ones with `skip` annotations, you can run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
BATS_RUN_SKIPPED=true bats exercise_name.bats
|
||||||
|
```
|
||||||
|
|
||||||
|
It can be convenient to use a wrapper function to save on typing:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bats() {
|
||||||
|
BATS_RUN_SKIPPED=true command bats *.bats
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run tests with just:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bats
|
||||||
|
```
|
||||||
|
|
||||||
|
## Submitting your solution
|
||||||
|
|
||||||
|
You can submit your solution using the `exercism submit hello_world.sh` command.
|
||||||
|
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution which allows you to:
|
||||||
|
|
||||||
|
- See how others have completed the exercise
|
||||||
|
- Request help from a mentor
|
||||||
|
|
||||||
|
## Need to get help?
|
||||||
|
|
||||||
|
If you'd like help solving the exercise, check the following pages:
|
||||||
|
|
||||||
|
- The [Bash track's documentation](https://exercism.org/docs/tracks/bash)
|
||||||
|
- The [Bash track's programming category on the forum](https://forum.exercism.org/c/programming/bash)
|
||||||
|
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||||
|
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||||
|
|
||||||
|
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||||
|
|
||||||
|
Check your code for syntax errors: paste your code into
|
||||||
|
[https://shellcheck.net](https://shellcheck.net) (or [install it](https://github.com/koalaman/shellcheck#user-content-installing) on your machine).
|
||||||
|
|
||||||
|
Stack Overflow will be your first stop for bash questions.
|
||||||
|
|
||||||
|
* start with the [`bash` tag](https://stackoverflow.com/questions/tagged/bash) to search for your specific question: it's probably already been asked
|
||||||
|
* under the bash tag on Stackoverflow, the [Learn more...](https://stackoverflow.com/tags/bash/info) link has _tons_ of good information.
|
||||||
|
* the "Books and Resources" section is particularly useful.
|
||||||
|
* the [`bash` tag](https://unix.stackexchange.com/questions/tagged/bash) on Unix & Linux is also active
|
||||||
|
|
||||||
|
## External utilities
|
||||||
|
|
||||||
|
`bash` is a language to write "scripts" -- programs that can call
|
||||||
|
external tools, such as
|
||||||
|
[`sed`](https://www.gnu.org/software/sed/),
|
||||||
|
[`awk`](https://www.gnu.org/software/gawk/),
|
||||||
|
[`date`](https://www.gnu.org/software/coreutils/manual/html_node/date-invocation.html)
|
||||||
|
and even programs written in other programming languages,
|
||||||
|
like [`Python`](https://www.python.org/).
|
||||||
|
This track does not restrict the usage of these utilities, and as long
|
||||||
|
as your solution is portable between systems and does not require
|
||||||
|
installation of third party applications, feel free to use them to solve
|
||||||
|
the exercise.
|
||||||
|
|
||||||
|
For an extra challenge, if you would like to have a better understanding of
|
||||||
|
the language, try to re-implement the solution in pure bash, without using
|
||||||
|
any external tools. There are some types of problems that bash cannot solve,
|
||||||
|
such as floating point arithmetic and manipulating dates: for those, you
|
||||||
|
must call out to an external tool.
|
||||||
68
bash/hello-world/README.md
Normal file
68
bash/hello-world/README.md
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
# Hello World
|
||||||
|
|
||||||
|
Welcome to Hello World on Exercism's Bash Track.
|
||||||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
The classical introductory exercise.
|
||||||
|
Just say "Hello, World!".
|
||||||
|
|
||||||
|
["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment.
|
||||||
|
|
||||||
|
The objectives are simple:
|
||||||
|
|
||||||
|
- Modify the provided code so that it produces the string "Hello, World!".
|
||||||
|
- Run the test suite and make sure that it succeeds.
|
||||||
|
- Submit your solution and check it at the website.
|
||||||
|
|
||||||
|
If everything goes well, you will be ready to fetch your first real exercise.
|
||||||
|
|
||||||
|
[hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program
|
||||||
|
|
||||||
|
## Welcome to Bash!
|
||||||
|
|
||||||
|
Unlike many other languages here, bash is a bit of a special snowflake.
|
||||||
|
If you are on a Mac or other unix-y platform, you almost definitely
|
||||||
|
already have bash. In fact, anything you type into the terminal is
|
||||||
|
likely going through bash.
|
||||||
|
|
||||||
|
The downside to this is that there isn't much of a development
|
||||||
|
ecosystem around bash like there is for other languages, and there are
|
||||||
|
multiple versions of bash that can be frustratingly incompatible. Luckily
|
||||||
|
we shouldn't hit those differences for these basic examples, and if you
|
||||||
|
can get the tests to pass on your machine, we are doing great.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
Please follow [these instructions](https://exercism.org/docs/tracks/bash/installation) to install `bash` on your system.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
Please follow [these instructions](https://exercism.org/docs/tracks/bash/tests) to learn more about testing with `bash`.
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Contributed to by
|
||||||
|
|
||||||
|
- @adelcambre
|
||||||
|
- @bkhl
|
||||||
|
- @budmc29
|
||||||
|
- @coreygo
|
||||||
|
- @glennj
|
||||||
|
- @guygastineau
|
||||||
|
- @IsaacG
|
||||||
|
- @kenden
|
||||||
|
- @kotp
|
||||||
|
- @kytrinyx
|
||||||
|
- @MattLewin
|
||||||
|
- @platinumthinker
|
||||||
|
- @quartzinquartz
|
||||||
|
- @rootulp
|
||||||
|
- @sjwarner-bp
|
||||||
|
- @Smarticles101
|
||||||
|
- @ZapAnton
|
||||||
|
|
||||||
|
### Based on
|
||||||
|
|
||||||
|
This is an exercise to introduce users to using Exercism - https://en.wikipedia.org/wiki/%22Hello,_world!%22_program
|
||||||
637
bash/hello-world/bats-extra.bash
Normal file
637
bash/hello-world/bats-extra.bash
Normal file
|
|
@ -0,0 +1,637 @@
|
||||||
|
# This is the source code for bats-support and bats-assert, concatenated
|
||||||
|
# * https://github.com/bats-core/bats-support
|
||||||
|
# * https://github.com/bats-core/bats-assert
|
||||||
|
#
|
||||||
|
# Comments have been removed to save space. See the git repos for full source code.
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
#
|
||||||
|
# bats-support - Supporting library for Bats test helpers
|
||||||
|
#
|
||||||
|
# Written in 2016 by Zoltan Tombol <zoltan dot tombol at gmail dot com>
|
||||||
|
#
|
||||||
|
# To the extent possible under law, the author(s) have dedicated all
|
||||||
|
# copyright and related and neighboring rights to this software to the
|
||||||
|
# public domain worldwide. This software is distributed without any
|
||||||
|
# warranty.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the CC0 Public Domain Dedication
|
||||||
|
# along with this software. If not, see
|
||||||
|
# <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
(( $# == 0 )) && batslib_err || batslib_err "$@"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
batslib_is_caller() {
|
||||||
|
local -i is_mode_direct=1
|
||||||
|
|
||||||
|
# Handle options.
|
||||||
|
while (( $# > 0 )); do
|
||||||
|
case "$1" in
|
||||||
|
-i|--indirect) is_mode_direct=0; shift ;;
|
||||||
|
--) shift; break ;;
|
||||||
|
*) break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Arguments.
|
||||||
|
local -r func="$1"
|
||||||
|
|
||||||
|
# Check call stack.
|
||||||
|
if (( is_mode_direct )); then
|
||||||
|
[[ $func == "${FUNCNAME[2]}" ]] && return 0
|
||||||
|
else
|
||||||
|
local -i depth
|
||||||
|
for (( depth=2; depth<${#FUNCNAME[@]}; ++depth )); do
|
||||||
|
[[ $func == "${FUNCNAME[$depth]}" ]] && return 0
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
batslib_err() {
|
||||||
|
{ if (( $# > 0 )); then
|
||||||
|
echo "$@"
|
||||||
|
else
|
||||||
|
cat -
|
||||||
|
fi
|
||||||
|
} >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
batslib_count_lines() {
|
||||||
|
local -i n_lines=0
|
||||||
|
local line
|
||||||
|
while IFS='' read -r line || [[ -n $line ]]; do
|
||||||
|
(( ++n_lines ))
|
||||||
|
done < <(printf '%s' "$1")
|
||||||
|
echo "$n_lines"
|
||||||
|
}
|
||||||
|
|
||||||
|
batslib_is_single_line() {
|
||||||
|
for string in "$@"; do
|
||||||
|
(( $(batslib_count_lines "$string") > 1 )) && return 1
|
||||||
|
done
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
batslib_get_max_single_line_key_width() {
|
||||||
|
local -i max_len=-1
|
||||||
|
while (( $# != 0 )); do
|
||||||
|
local -i key_len="${#1}"
|
||||||
|
batslib_is_single_line "$2" && (( key_len > max_len )) && max_len="$key_len"
|
||||||
|
shift 2
|
||||||
|
done
|
||||||
|
echo "$max_len"
|
||||||
|
}
|
||||||
|
|
||||||
|
batslib_print_kv_single() {
|
||||||
|
local -ir col_width="$1"; shift
|
||||||
|
while (( $# != 0 )); do
|
||||||
|
printf '%-*s : %s\n' "$col_width" "$1" "$2"
|
||||||
|
shift 2
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
batslib_print_kv_multi() {
|
||||||
|
while (( $# != 0 )); do
|
||||||
|
printf '%s (%d lines):\n' "$1" "$( batslib_count_lines "$2" )"
|
||||||
|
printf '%s\n' "$2"
|
||||||
|
shift 2
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
batslib_print_kv_single_or_multi() {
|
||||||
|
local -ir width="$1"; shift
|
||||||
|
local -a pairs=( "$@" )
|
||||||
|
|
||||||
|
local -a values=()
|
||||||
|
local -i i
|
||||||
|
for (( i=1; i < ${#pairs[@]}; i+=2 )); do
|
||||||
|
values+=( "${pairs[$i]}" )
|
||||||
|
done
|
||||||
|
|
||||||
|
if batslib_is_single_line "${values[@]}"; then
|
||||||
|
batslib_print_kv_single "$width" "${pairs[@]}"
|
||||||
|
else
|
||||||
|
local -i i
|
||||||
|
for (( i=1; i < ${#pairs[@]}; i+=2 )); do
|
||||||
|
pairs[$i]="$( batslib_prefix < <(printf '%s' "${pairs[$i]}") )"
|
||||||
|
done
|
||||||
|
batslib_print_kv_multi "${pairs[@]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
batslib_prefix() {
|
||||||
|
local -r prefix="${1:- }"
|
||||||
|
local line
|
||||||
|
while IFS='' read -r line || [[ -n $line ]]; do
|
||||||
|
printf '%s%s\n' "$prefix" "$line"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
batslib_mark() {
|
||||||
|
local -r symbol="$1"; shift
|
||||||
|
# Sort line numbers.
|
||||||
|
set -- $( sort -nu <<< "$( printf '%d\n' "$@" )" )
|
||||||
|
|
||||||
|
local line
|
||||||
|
local -i idx=0
|
||||||
|
while IFS='' read -r line || [[ -n $line ]]; do
|
||||||
|
if (( ${1:--1} == idx )); then
|
||||||
|
printf '%s\n' "${symbol}${line:${#symbol}}"
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
printf '%s\n' "$line"
|
||||||
|
fi
|
||||||
|
(( ++idx ))
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
batslib_decorate() {
|
||||||
|
echo
|
||||||
|
echo "-- $1 --"
|
||||||
|
cat -
|
||||||
|
echo '--'
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
assert() {
|
||||||
|
if ! "$@"; then
|
||||||
|
batslib_print_kv_single 10 'expression' "$*" \
|
||||||
|
| batslib_decorate 'assertion failed' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal() {
|
||||||
|
if [[ $1 != "$2" ]]; then
|
||||||
|
batslib_print_kv_single_or_multi 8 \
|
||||||
|
'expected' "$2" \
|
||||||
|
'actual' "$1" \
|
||||||
|
| batslib_decorate 'values do not equal' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_failure() {
|
||||||
|
: "${output?}"
|
||||||
|
: "${status?}"
|
||||||
|
|
||||||
|
(( $# > 0 )) && local -r expected="$1"
|
||||||
|
if (( status == 0 )); then
|
||||||
|
batslib_print_kv_single_or_multi 6 'output' "$output" \
|
||||||
|
| batslib_decorate 'command succeeded, but it was expected to fail' \
|
||||||
|
| fail
|
||||||
|
elif (( $# > 0 )) && (( status != expected )); then
|
||||||
|
{ local -ir width=8
|
||||||
|
batslib_print_kv_single "$width" \
|
||||||
|
'expected' "$expected" \
|
||||||
|
'actual' "$status"
|
||||||
|
batslib_print_kv_single_or_multi "$width" \
|
||||||
|
'output' "$output"
|
||||||
|
} \
|
||||||
|
| batslib_decorate 'command failed as expected, but status differs' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_line() {
|
||||||
|
local -i is_match_line=0
|
||||||
|
local -i is_mode_partial=0
|
||||||
|
local -i is_mode_regexp=0
|
||||||
|
: "${lines?}"
|
||||||
|
|
||||||
|
# Handle options.
|
||||||
|
while (( $# > 0 )); do
|
||||||
|
case "$1" in
|
||||||
|
-n|--index)
|
||||||
|
if (( $# < 2 )) || ! [[ $2 =~ ^([0-9]|[1-9][0-9]+)$ ]]; then
|
||||||
|
echo "\`--index' requires an integer argument: \`$2'" \
|
||||||
|
| batslib_decorate 'ERROR: assert_line' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
is_match_line=1
|
||||||
|
local -ri idx="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-p|--partial) is_mode_partial=1; shift ;;
|
||||||
|
-e|--regexp) is_mode_regexp=1; shift ;;
|
||||||
|
--) shift; break ;;
|
||||||
|
*) break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if (( is_mode_partial )) && (( is_mode_regexp )); then
|
||||||
|
echo "\`--partial' and \`--regexp' are mutually exclusive" \
|
||||||
|
| batslib_decorate 'ERROR: assert_line' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Arguments.
|
||||||
|
local -r expected="$1"
|
||||||
|
|
||||||
|
if (( is_mode_regexp == 1 )) && [[ '' =~ $expected ]] || (( $? == 2 )); then
|
||||||
|
echo "Invalid extended regular expression: \`$expected'" \
|
||||||
|
| batslib_decorate 'ERROR: assert_line' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Matching.
|
||||||
|
if (( is_match_line )); then
|
||||||
|
# Specific line.
|
||||||
|
if (( is_mode_regexp )); then
|
||||||
|
if ! [[ ${lines[$idx]} =~ $expected ]]; then
|
||||||
|
batslib_print_kv_single 6 \
|
||||||
|
'index' "$idx" \
|
||||||
|
'regexp' "$expected" \
|
||||||
|
'line' "${lines[$idx]}" \
|
||||||
|
| batslib_decorate 'regular expression does not match line' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
elif (( is_mode_partial )); then
|
||||||
|
if [[ ${lines[$idx]} != *"$expected"* ]]; then
|
||||||
|
batslib_print_kv_single 9 \
|
||||||
|
'index' "$idx" \
|
||||||
|
'substring' "$expected" \
|
||||||
|
'line' "${lines[$idx]}" \
|
||||||
|
| batslib_decorate 'line does not contain substring' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ ${lines[$idx]} != "$expected" ]]; then
|
||||||
|
batslib_print_kv_single 8 \
|
||||||
|
'index' "$idx" \
|
||||||
|
'expected' "$expected" \
|
||||||
|
'actual' "${lines[$idx]}" \
|
||||||
|
| batslib_decorate 'line differs' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Contained in output.
|
||||||
|
if (( is_mode_regexp )); then
|
||||||
|
local -i idx
|
||||||
|
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||||
|
[[ ${lines[$idx]} =~ $expected ]] && return 0
|
||||||
|
done
|
||||||
|
{ local -ar single=( 'regexp' "$expected" )
|
||||||
|
local -ar may_be_multi=( 'output' "$output" )
|
||||||
|
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||||
|
batslib_print_kv_single "$width" "${single[@]}"
|
||||||
|
batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}"
|
||||||
|
} \
|
||||||
|
| batslib_decorate 'no output line matches regular expression' \
|
||||||
|
| fail
|
||||||
|
elif (( is_mode_partial )); then
|
||||||
|
local -i idx
|
||||||
|
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||||
|
[[ ${lines[$idx]} == *"$expected"* ]] && return 0
|
||||||
|
done
|
||||||
|
{ local -ar single=( 'substring' "$expected" )
|
||||||
|
local -ar may_be_multi=( 'output' "$output" )
|
||||||
|
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||||
|
batslib_print_kv_single "$width" "${single[@]}"
|
||||||
|
batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}"
|
||||||
|
} \
|
||||||
|
| batslib_decorate 'no output line contains substring' \
|
||||||
|
| fail
|
||||||
|
else
|
||||||
|
local -i idx
|
||||||
|
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||||
|
[[ ${lines[$idx]} == "$expected" ]] && return 0
|
||||||
|
done
|
||||||
|
{ local -ar single=( 'line' "$expected" )
|
||||||
|
local -ar may_be_multi=( 'output' "$output" )
|
||||||
|
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||||
|
batslib_print_kv_single "$width" "${single[@]}"
|
||||||
|
batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}"
|
||||||
|
} \
|
||||||
|
| batslib_decorate 'output does not contain line' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_output() {
|
||||||
|
local -i is_mode_partial=0
|
||||||
|
local -i is_mode_regexp=0
|
||||||
|
local -i is_mode_nonempty=0
|
||||||
|
local -i use_stdin=0
|
||||||
|
: "${output?}"
|
||||||
|
|
||||||
|
# Handle options.
|
||||||
|
if (( $# == 0 )); then
|
||||||
|
is_mode_nonempty=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
while (( $# > 0 )); do
|
||||||
|
case "$1" in
|
||||||
|
-p|--partial) is_mode_partial=1; shift ;;
|
||||||
|
-e|--regexp) is_mode_regexp=1; shift ;;
|
||||||
|
-|--stdin) use_stdin=1; shift ;;
|
||||||
|
--) shift; break ;;
|
||||||
|
*) break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if (( is_mode_partial )) && (( is_mode_regexp )); then
|
||||||
|
echo "\`--partial' and \`--regexp' are mutually exclusive" \
|
||||||
|
| batslib_decorate 'ERROR: assert_output' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Arguments.
|
||||||
|
local expected
|
||||||
|
if (( use_stdin )); then
|
||||||
|
expected="$(cat -)"
|
||||||
|
else
|
||||||
|
expected="${1-}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Matching.
|
||||||
|
if (( is_mode_nonempty )); then
|
||||||
|
if [ -z "$output" ]; then
|
||||||
|
echo 'expected non-empty output, but output was empty' \
|
||||||
|
| batslib_decorate 'no output' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
elif (( is_mode_regexp )); then
|
||||||
|
if [[ '' =~ $expected ]] || (( $? == 2 )); then
|
||||||
|
echo "Invalid extended regular expression: \`$expected'" \
|
||||||
|
| batslib_decorate 'ERROR: assert_output' \
|
||||||
|
| fail
|
||||||
|
elif ! [[ $output =~ $expected ]]; then
|
||||||
|
batslib_print_kv_single_or_multi 6 \
|
||||||
|
'regexp' "$expected" \
|
||||||
|
'output' "$output" \
|
||||||
|
| batslib_decorate 'regular expression does not match output' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
elif (( is_mode_partial )); then
|
||||||
|
if [[ $output != *"$expected"* ]]; then
|
||||||
|
batslib_print_kv_single_or_multi 9 \
|
||||||
|
'substring' "$expected" \
|
||||||
|
'output' "$output" \
|
||||||
|
| batslib_decorate 'output does not contain substring' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ $output != "$expected" ]]; then
|
||||||
|
batslib_print_kv_single_or_multi 8 \
|
||||||
|
'expected' "$expected" \
|
||||||
|
'actual' "$output" \
|
||||||
|
| batslib_decorate 'output differs' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_success() {
|
||||||
|
: "${output?}"
|
||||||
|
: "${status?}"
|
||||||
|
|
||||||
|
if (( status != 0 )); then
|
||||||
|
{ local -ir width=6
|
||||||
|
batslib_print_kv_single "$width" 'status' "$status"
|
||||||
|
batslib_print_kv_single_or_multi "$width" 'output' "$output"
|
||||||
|
} \
|
||||||
|
| batslib_decorate 'command failed' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
refute() {
|
||||||
|
if "$@"; then
|
||||||
|
batslib_print_kv_single 10 'expression' "$*" \
|
||||||
|
| batslib_decorate 'assertion succeeded, but it was expected to fail' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
refute_line() {
|
||||||
|
local -i is_match_line=0
|
||||||
|
local -i is_mode_partial=0
|
||||||
|
local -i is_mode_regexp=0
|
||||||
|
: "${lines?}"
|
||||||
|
|
||||||
|
# Handle options.
|
||||||
|
while (( $# > 0 )); do
|
||||||
|
case "$1" in
|
||||||
|
-n|--index)
|
||||||
|
if (( $# < 2 )) || ! [[ $2 =~ ^([0-9]|[1-9][0-9]+)$ ]]; then
|
||||||
|
echo "\`--index' requires an integer argument: \`$2'" \
|
||||||
|
| batslib_decorate 'ERROR: refute_line' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
is_match_line=1
|
||||||
|
local -ri idx="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-p|--partial) is_mode_partial=1; shift ;;
|
||||||
|
-e|--regexp) is_mode_regexp=1; shift ;;
|
||||||
|
--) shift; break ;;
|
||||||
|
*) break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if (( is_mode_partial )) && (( is_mode_regexp )); then
|
||||||
|
echo "\`--partial' and \`--regexp' are mutually exclusive" \
|
||||||
|
| batslib_decorate 'ERROR: refute_line' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Arguments.
|
||||||
|
local -r unexpected="$1"
|
||||||
|
|
||||||
|
if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then
|
||||||
|
echo "Invalid extended regular expression: \`$unexpected'" \
|
||||||
|
| batslib_decorate 'ERROR: refute_line' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Matching.
|
||||||
|
if (( is_match_line )); then
|
||||||
|
# Specific line.
|
||||||
|
if (( is_mode_regexp )); then
|
||||||
|
if [[ ${lines[$idx]} =~ $unexpected ]]; then
|
||||||
|
batslib_print_kv_single 6 \
|
||||||
|
'index' "$idx" \
|
||||||
|
'regexp' "$unexpected" \
|
||||||
|
'line' "${lines[$idx]}" \
|
||||||
|
| batslib_decorate 'regular expression should not match line' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
elif (( is_mode_partial )); then
|
||||||
|
if [[ ${lines[$idx]} == *"$unexpected"* ]]; then
|
||||||
|
batslib_print_kv_single 9 \
|
||||||
|
'index' "$idx" \
|
||||||
|
'substring' "$unexpected" \
|
||||||
|
'line' "${lines[$idx]}" \
|
||||||
|
| batslib_decorate 'line should not contain substring' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ ${lines[$idx]} == "$unexpected" ]]; then
|
||||||
|
batslib_print_kv_single 5 \
|
||||||
|
'index' "$idx" \
|
||||||
|
'line' "${lines[$idx]}" \
|
||||||
|
| batslib_decorate 'line should differ' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Line contained in output.
|
||||||
|
if (( is_mode_regexp )); then
|
||||||
|
local -i idx
|
||||||
|
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||||
|
if [[ ${lines[$idx]} =~ $unexpected ]]; then
|
||||||
|
{ local -ar single=( 'regexp' "$unexpected" 'index' "$idx" )
|
||||||
|
local -a may_be_multi=( 'output' "$output" )
|
||||||
|
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||||
|
batslib_print_kv_single "$width" "${single[@]}"
|
||||||
|
if batslib_is_single_line "${may_be_multi[1]}"; then
|
||||||
|
batslib_print_kv_single "$width" "${may_be_multi[@]}"
|
||||||
|
else
|
||||||
|
may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )"
|
||||||
|
batslib_print_kv_multi "${may_be_multi[@]}"
|
||||||
|
fi
|
||||||
|
} \
|
||||||
|
| batslib_decorate 'no line should match the regular expression' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
elif (( is_mode_partial )); then
|
||||||
|
local -i idx
|
||||||
|
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||||
|
if [[ ${lines[$idx]} == *"$unexpected"* ]]; then
|
||||||
|
{ local -ar single=( 'substring' "$unexpected" 'index' "$idx" )
|
||||||
|
local -a may_be_multi=( 'output' "$output" )
|
||||||
|
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||||
|
batslib_print_kv_single "$width" "${single[@]}"
|
||||||
|
if batslib_is_single_line "${may_be_multi[1]}"; then
|
||||||
|
batslib_print_kv_single "$width" "${may_be_multi[@]}"
|
||||||
|
else
|
||||||
|
may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )"
|
||||||
|
batslib_print_kv_multi "${may_be_multi[@]}"
|
||||||
|
fi
|
||||||
|
} \
|
||||||
|
| batslib_decorate 'no line should contain substring' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
local -i idx
|
||||||
|
for (( idx = 0; idx < ${#lines[@]}; ++idx )); do
|
||||||
|
if [[ ${lines[$idx]} == "$unexpected" ]]; then
|
||||||
|
{ local -ar single=( 'line' "$unexpected" 'index' "$idx" )
|
||||||
|
local -a may_be_multi=( 'output' "$output" )
|
||||||
|
local -ir width="$( batslib_get_max_single_line_key_width "${single[@]}" "${may_be_multi[@]}" )"
|
||||||
|
batslib_print_kv_single "$width" "${single[@]}"
|
||||||
|
if batslib_is_single_line "${may_be_multi[1]}"; then
|
||||||
|
batslib_print_kv_single "$width" "${may_be_multi[@]}"
|
||||||
|
else
|
||||||
|
may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" | batslib_prefix | batslib_mark '>' "$idx" )"
|
||||||
|
batslib_print_kv_multi "${may_be_multi[@]}"
|
||||||
|
fi
|
||||||
|
} \
|
||||||
|
| batslib_decorate 'line should not be in output' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
refute_output() {
|
||||||
|
local -i is_mode_partial=0
|
||||||
|
local -i is_mode_regexp=0
|
||||||
|
local -i is_mode_empty=0
|
||||||
|
local -i use_stdin=0
|
||||||
|
: "${output?}"
|
||||||
|
|
||||||
|
# Handle options.
|
||||||
|
if (( $# == 0 )); then
|
||||||
|
is_mode_empty=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
while (( $# > 0 )); do
|
||||||
|
case "$1" in
|
||||||
|
-p|--partial) is_mode_partial=1; shift ;;
|
||||||
|
-e|--regexp) is_mode_regexp=1; shift ;;
|
||||||
|
-|--stdin) use_stdin=1; shift ;;
|
||||||
|
--) shift; break ;;
|
||||||
|
*) break ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if (( is_mode_partial )) && (( is_mode_regexp )); then
|
||||||
|
echo "\`--partial' and \`--regexp' are mutually exclusive" \
|
||||||
|
| batslib_decorate 'ERROR: refute_output' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Arguments.
|
||||||
|
local unexpected
|
||||||
|
if (( use_stdin )); then
|
||||||
|
unexpected="$(cat -)"
|
||||||
|
else
|
||||||
|
unexpected="${1-}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( is_mode_regexp == 1 )) && [[ '' =~ $unexpected ]] || (( $? == 2 )); then
|
||||||
|
echo "Invalid extended regular expression: \`$unexpected'" \
|
||||||
|
| batslib_decorate 'ERROR: refute_output' \
|
||||||
|
| fail
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Matching.
|
||||||
|
if (( is_mode_empty )); then
|
||||||
|
if [ -n "$output" ]; then
|
||||||
|
batslib_print_kv_single_or_multi 6 \
|
||||||
|
'output' "$output" \
|
||||||
|
| batslib_decorate 'output non-empty, but expected no output' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
elif (( is_mode_regexp )); then
|
||||||
|
if [[ $output =~ $unexpected ]]; then
|
||||||
|
batslib_print_kv_single_or_multi 6 \
|
||||||
|
'regexp' "$unexpected" \
|
||||||
|
'output' "$output" \
|
||||||
|
| batslib_decorate 'regular expression should not match output' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
elif (( is_mode_partial )); then
|
||||||
|
if [[ $output == *"$unexpected"* ]]; then
|
||||||
|
batslib_print_kv_single_or_multi 9 \
|
||||||
|
'substring' "$unexpected" \
|
||||||
|
'output' "$output" \
|
||||||
|
| batslib_decorate 'output should not contain substring' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ $output == "$unexpected" ]]; then
|
||||||
|
batslib_print_kv_single_or_multi 6 \
|
||||||
|
'output' "$output" \
|
||||||
|
| batslib_decorate 'output equals, but it was expected to differ' \
|
||||||
|
| fail
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
14
bash/hello-world/hello_world.bats
Normal file
14
bash/hello-world/hello_world.bats
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#!/usr/bin/env bats
|
||||||
|
load bats-extra
|
||||||
|
|
||||||
|
# local version: 1.1.0.0
|
||||||
|
|
||||||
|
@test "Say Hi!" {
|
||||||
|
run bash hello_world.sh
|
||||||
|
|
||||||
|
# the program's exit status should be success (0)
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
# program's output should be the expected text
|
||||||
|
assert_output "Hello, World!"
|
||||||
|
}
|
||||||
3
bash/hello-world/hello_world.sh
Normal file
3
bash/hello-world/hello_world.sh
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
echo "Hello, World!"
|
||||||
47
rust/anagram/.exercism/config.json
Normal file
47
rust/anagram/.exercism/config.json
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"authors": [
|
||||||
|
"EduardoBautista"
|
||||||
|
],
|
||||||
|
"contributors": [
|
||||||
|
"andrewclarkson",
|
||||||
|
"ashleygwilliams",
|
||||||
|
"bobahop",
|
||||||
|
"chancancode",
|
||||||
|
"ClashTheBunny",
|
||||||
|
"coriolinus",
|
||||||
|
"cwhakes",
|
||||||
|
"Dimkar3000",
|
||||||
|
"EduardoBautista",
|
||||||
|
"efx",
|
||||||
|
"ErikSchierboom",
|
||||||
|
"gris",
|
||||||
|
"IanWhitney",
|
||||||
|
"kytrinyx",
|
||||||
|
"lutostag",
|
||||||
|
"mkantor",
|
||||||
|
"nfiles",
|
||||||
|
"petertseng",
|
||||||
|
"pminten",
|
||||||
|
"quartsize",
|
||||||
|
"rofrol",
|
||||||
|
"stevejb71",
|
||||||
|
"stringparser",
|
||||||
|
"xakon",
|
||||||
|
"ZapAnton"
|
||||||
|
],
|
||||||
|
"files": {
|
||||||
|
"solution": [
|
||||||
|
"src/lib.rs",
|
||||||
|
"Cargo.toml"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"tests/anagram.rs"
|
||||||
|
],
|
||||||
|
"example": [
|
||||||
|
".meta/example.rs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"blurb": "Given a word and a list of possible anagrams, select the correct sublist.",
|
||||||
|
"source": "Inspired by the Extreme Startup game",
|
||||||
|
"source_url": "https://github.com/rchatley/extreme_startup"
|
||||||
|
}
|
||||||
2
rust/anagram/.gitignore
vendored
Normal file
2
rust/anagram/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
Cargo.lock
|
||||||
9
rust/anagram/Cargo.toml
Normal file
9
rust/anagram/Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "anagram"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
# Not all libraries from crates.io are available in Exercism's test runner.
|
||||||
|
# The full list of available libraries is here:
|
||||||
|
# https://github.com/exercism/rust-test-runner/blob/main/local-registry/Cargo.toml
|
||||||
|
[dependencies]
|
||||||
86
rust/anagram/HELP.md
Normal file
86
rust/anagram/HELP.md
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
# Help
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
Execute the tests with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo test
|
||||||
|
```
|
||||||
|
|
||||||
|
All but the first test have been ignored. After you get the first test to
|
||||||
|
pass, open the tests source file which is located in the `tests` directory
|
||||||
|
and remove the `#[ignore]` flag from the next test and get the tests to pass
|
||||||
|
again. Each separate test is a function with `#[test]` flag above it.
|
||||||
|
Continue, until you pass every test.
|
||||||
|
|
||||||
|
If you wish to run _only ignored_ tests without editing the tests source file, use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo test -- --ignored
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using Rust 1.51 or later, you can run _all_ tests with
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo test -- --include-ignored
|
||||||
|
```
|
||||||
|
|
||||||
|
To run a specific test, for example `some_test`, you can use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo test some_test
|
||||||
|
```
|
||||||
|
|
||||||
|
If the specific test is ignored, use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo test some_test -- --ignored
|
||||||
|
```
|
||||||
|
|
||||||
|
To learn more about Rust tests refer to the online [test documentation][rust-tests].
|
||||||
|
|
||||||
|
[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html
|
||||||
|
|
||||||
|
## Submitting your solution
|
||||||
|
|
||||||
|
You can submit your solution using the `exercism submit src/lib.rs Cargo.toml` command.
|
||||||
|
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution which allows you to:
|
||||||
|
|
||||||
|
- See how others have completed the exercise
|
||||||
|
- Request help from a mentor
|
||||||
|
|
||||||
|
## Need to get help?
|
||||||
|
|
||||||
|
If you'd like help solving the exercise, check the following pages:
|
||||||
|
|
||||||
|
- The [Rust track's documentation](https://exercism.org/docs/tracks/rust)
|
||||||
|
- The [Rust track's programming category on the forum](https://forum.exercism.org/c/programming/rust)
|
||||||
|
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||||
|
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||||
|
|
||||||
|
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||||
|
|
||||||
|
## Rust Installation
|
||||||
|
|
||||||
|
Refer to the [exercism help page][help-page] for Rust installation and learning
|
||||||
|
resources.
|
||||||
|
|
||||||
|
## Submitting the solution
|
||||||
|
|
||||||
|
Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer.
|
||||||
|
|
||||||
|
## Feedback, Issues, Pull Requests
|
||||||
|
|
||||||
|
The GitHub [track repository][github] is the home for all of the Rust exercises. If you have feedback about an exercise, or want to help implement new exercises, head over there and create an issue. Members of the rust track team are happy to help!
|
||||||
|
|
||||||
|
If you want to know more about Exercism, take a look at the [contribution guide].
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
||||||
|
[help-page]: https://exercism.org/tracks/rust/learning
|
||||||
|
[github]: https://github.com/exercism/rust
|
||||||
|
[contribution guide]: https://exercism.org/docs/community/contributors
|
||||||
6
rust/anagram/HINTS.md
Normal file
6
rust/anagram/HINTS.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Hints
|
||||||
|
|
||||||
|
## General
|
||||||
|
|
||||||
|
The solution is case insensitive, which means `"WOrd"` is the same as `"word"` or `"woRd"`.
|
||||||
|
It may help to take a peek at the [std library](https://doc.rust-lang.org/std/primitive.char.html) for functions that can convert between them.
|
||||||
74
rust/anagram/README.md
Normal file
74
rust/anagram/README.md
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
# Anagram
|
||||||
|
|
||||||
|
Welcome to Anagram on Exercism's Rust Track.
|
||||||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||||
|
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
At a garage sale, you find a lovely vintage typewriter at a bargain price!
|
||||||
|
Excitedly, you rush home, insert a sheet of paper, and start typing away.
|
||||||
|
However, your excitement wanes when you examine the output: all words are garbled!
|
||||||
|
For example, it prints "stop" instead of "post" and "least" instead of "stale."
|
||||||
|
Carefully, you try again, but now it prints "spot" and "slate."
|
||||||
|
After some experimentation, you find there is a random delay before each letter is printed, which messes up the order.
|
||||||
|
You now understand why they sold it for so little money!
|
||||||
|
|
||||||
|
You realize this quirk allows you to generate anagrams, which are words formed by rearranging the letters of another word.
|
||||||
|
Pleased with your finding, you spend the rest of the day generating hundreds of anagrams.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
Given a target word and one or more candidate words, your task is to find the candidates that are anagrams of the target.
|
||||||
|
|
||||||
|
An anagram is a rearrangement of letters to form a new word: for example `"owns"` is an anagram of `"snow"`.
|
||||||
|
A word is _not_ its own anagram: for example, `"stop"` is not an anagram of `"stop"`.
|
||||||
|
|
||||||
|
The target word and candidate words are made up of one or more ASCII alphabetic characters (`A`-`Z` and `a`-`z`).
|
||||||
|
Lowercase and uppercase characters are equivalent: for example, `"PoTS"` is an anagram of `"sTOp"`, but `"StoP"` is not an anagram of `"sTOp"`.
|
||||||
|
The words you need to find should be taken from the candidate words, using the same letter case.
|
||||||
|
|
||||||
|
Given the target `"stone"` and the candidate words `"stone"`, `"tones"`, `"banana"`, `"tons"`, `"notes"`, and `"Seton"`, the anagram words you need to find are `"tones"`, `"notes"`, and `"Seton"`.
|
||||||
|
|
||||||
|
The Rust track extends the possible letters to be any unicode character, not just ASCII alphabetic ones.
|
||||||
|
|
||||||
|
You are going to have to adjust the function signature provided in the stub in order for the lifetimes to work out properly.
|
||||||
|
This is intentional: what's there demonstrates the basics of lifetime syntax, and what's missing teaches how to interpret lifetime-related compiler errors.
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Created by
|
||||||
|
|
||||||
|
- @EduardoBautista
|
||||||
|
|
||||||
|
### Contributed to by
|
||||||
|
|
||||||
|
- @andrewclarkson
|
||||||
|
- @ashleygwilliams
|
||||||
|
- @bobahop
|
||||||
|
- @chancancode
|
||||||
|
- @ClashTheBunny
|
||||||
|
- @coriolinus
|
||||||
|
- @cwhakes
|
||||||
|
- @Dimkar3000
|
||||||
|
- @EduardoBautista
|
||||||
|
- @efx
|
||||||
|
- @ErikSchierboom
|
||||||
|
- @gris
|
||||||
|
- @IanWhitney
|
||||||
|
- @kytrinyx
|
||||||
|
- @lutostag
|
||||||
|
- @mkantor
|
||||||
|
- @nfiles
|
||||||
|
- @petertseng
|
||||||
|
- @pminten
|
||||||
|
- @quartsize
|
||||||
|
- @rofrol
|
||||||
|
- @stevejb71
|
||||||
|
- @stringparser
|
||||||
|
- @xakon
|
||||||
|
- @ZapAnton
|
||||||
|
|
||||||
|
### Based on
|
||||||
|
|
||||||
|
Inspired by the Extreme Startup game - https://github.com/rchatley/extreme_startup
|
||||||
8
rust/anagram/src/lib.rs
Normal file
8
rust/anagram/src/lib.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
pub fn anagrams_for<'a>(
|
||||||
|
word: &str,
|
||||||
|
possible_anagrams: &[&str]
|
||||||
|
) -> HashSet<&'a str> {
|
||||||
|
todo!("For the '{word}' word find anagrams among the following words: {possible_anagrams:?}");
|
||||||
|
}
|
||||||
188
rust/anagram/tests/anagram.rs
Normal file
188
rust/anagram/tests/anagram.rs
Normal file
|
|
@ -0,0 +1,188 @@
|
||||||
|
use anagram::*;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_matches() {
|
||||||
|
let word = "diaper";
|
||||||
|
let inputs = &["hello", "world", "zombies", "pants"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter([]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn detects_two_anagrams() {
|
||||||
|
let word = "solemn";
|
||||||
|
let inputs = &["lemons", "cherry", "melons"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter(["lemons", "melons"]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn does_not_detect_anagram_subsets() {
|
||||||
|
let word = "good";
|
||||||
|
let inputs = &["dog", "goody"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter([]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn detects_anagram() {
|
||||||
|
let word = "listen";
|
||||||
|
let inputs = &["enlists", "google", "inlets", "banana"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter(["inlets"]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn detects_three_anagrams() {
|
||||||
|
let word = "allergy";
|
||||||
|
let inputs = &[
|
||||||
|
"gallery",
|
||||||
|
"ballerina",
|
||||||
|
"regally",
|
||||||
|
"clergy",
|
||||||
|
"largely",
|
||||||
|
"leading",
|
||||||
|
];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter(["gallery", "regally", "largely"]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn detects_multiple_anagrams_with_different_case() {
|
||||||
|
let word = "nose";
|
||||||
|
let inputs = &["Eons", "ONES"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter(["Eons", "ONES"]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn does_not_detect_non_anagrams_with_identical_checksum() {
|
||||||
|
let word = "mass";
|
||||||
|
let inputs = &["last"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter([]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn detects_anagrams_case_insensitively() {
|
||||||
|
let word = "Orchestra";
|
||||||
|
let inputs = &["cashregister", "Carthorse", "radishes"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter(["Carthorse"]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn detects_anagrams_using_case_insensitive_subject() {
|
||||||
|
let word = "Orchestra";
|
||||||
|
let inputs = &["cashregister", "carthorse", "radishes"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter(["carthorse"]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn detects_anagrams_using_case_insensitive_possible_matches() {
|
||||||
|
let word = "orchestra";
|
||||||
|
let inputs = &["cashregister", "Carthorse", "radishes"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter(["Carthorse"]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn does_not_detect_an_anagram_if_the_original_word_is_repeated() {
|
||||||
|
let word = "go";
|
||||||
|
let inputs = &["goGoGO"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter([]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn anagrams_must_use_all_letters_exactly_once() {
|
||||||
|
let word = "tapper";
|
||||||
|
let inputs = &["patter"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter([]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn words_are_not_anagrams_of_themselves() {
|
||||||
|
let word = "BANANA";
|
||||||
|
let inputs = &["BANANA"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter([]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn words_are_not_anagrams_of_themselves_even_if_letter_case_is_partially_different() {
|
||||||
|
let word = "BANANA";
|
||||||
|
let inputs = &["Banana"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter([]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn words_are_not_anagrams_of_themselves_even_if_letter_case_is_completely_different() {
|
||||||
|
let word = "BANANA";
|
||||||
|
let inputs = &["banana"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter([]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn words_other_than_themselves_can_be_anagrams() {
|
||||||
|
let word = "LISTEN";
|
||||||
|
let inputs = &["LISTEN", "Silent"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter(["Silent"]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn handles_case_of_greek_letters() {
|
||||||
|
let word = "ΑΒΓ";
|
||||||
|
let inputs = &["ΒΓΑ", "ΒΓΔ", "γβα", "αβγ"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter(["ΒΓΑ", "γβα"]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn different_characters_may_have_the_same_bytes() {
|
||||||
|
let word = "a⬂";
|
||||||
|
let inputs = &["€a"];
|
||||||
|
let output = anagrams_for(word, inputs);
|
||||||
|
let expected = HashSet::from_iter([]);
|
||||||
|
assert_eq!(output, expected);
|
||||||
|
}
|
||||||
42
rust/parallel-letter-frequency/.exercism/config.json
Normal file
42
rust/parallel-letter-frequency/.exercism/config.json
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"authors": [
|
||||||
|
"EduardoBautista"
|
||||||
|
],
|
||||||
|
"contributors": [
|
||||||
|
"andrewclarkson",
|
||||||
|
"ashleygwilliams",
|
||||||
|
"ccouzens",
|
||||||
|
"ClashTheBunny",
|
||||||
|
"coriolinus",
|
||||||
|
"cwhakes",
|
||||||
|
"EduardoBautista",
|
||||||
|
"efx",
|
||||||
|
"ErikSchierboom",
|
||||||
|
"etrepum",
|
||||||
|
"glennpratt",
|
||||||
|
"IanWhitney",
|
||||||
|
"kytrinyx",
|
||||||
|
"lutostag",
|
||||||
|
"mkantor",
|
||||||
|
"nfiles",
|
||||||
|
"petertseng",
|
||||||
|
"rofrol",
|
||||||
|
"sjwarner-bp",
|
||||||
|
"stringparser",
|
||||||
|
"xakon",
|
||||||
|
"ZapAnton"
|
||||||
|
],
|
||||||
|
"files": {
|
||||||
|
"solution": [
|
||||||
|
"src/lib.rs",
|
||||||
|
"Cargo.toml"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"tests/parallel_letter_frequency.rs"
|
||||||
|
],
|
||||||
|
"example": [
|
||||||
|
".meta/example.rs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"blurb": "Count the frequency of letters in texts using parallel computation."
|
||||||
|
}
|
||||||
2
rust/parallel-letter-frequency/.gitignore
vendored
Normal file
2
rust/parallel-letter-frequency/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
Cargo.lock
|
||||||
9
rust/parallel-letter-frequency/Cargo.toml
Normal file
9
rust/parallel-letter-frequency/Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "parallel_letter_frequency"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
# Not all libraries from crates.io are available in Exercism's test runner.
|
||||||
|
# The full list of available libraries is here:
|
||||||
|
# https://github.com/exercism/rust-test-runner/blob/main/local-registry/Cargo.toml
|
||||||
|
[dependencies]
|
||||||
89
rust/parallel-letter-frequency/HELP.md
Normal file
89
rust/parallel-letter-frequency/HELP.md
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
# Help
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
Execute the tests with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo test
|
||||||
|
```
|
||||||
|
|
||||||
|
All but the first test have been ignored. After you get the first test to
|
||||||
|
pass, open the tests source file which is located in the `tests` directory
|
||||||
|
and remove the `#[ignore]` flag from the next test and get the tests to pass
|
||||||
|
again. Each separate test is a function with `#[test]` flag above it.
|
||||||
|
Continue, until you pass every test.
|
||||||
|
|
||||||
|
If you wish to run _only ignored_ tests without editing the tests source file, use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo test -- --ignored
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using Rust 1.51 or later, you can run _all_ tests with
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo test -- --include-ignored
|
||||||
|
```
|
||||||
|
|
||||||
|
To run a specific test, for example `some_test`, you can use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo test some_test
|
||||||
|
```
|
||||||
|
|
||||||
|
If the specific test is ignored, use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo test some_test -- --ignored
|
||||||
|
```
|
||||||
|
|
||||||
|
To learn more about Rust tests refer to the online [test documentation][rust-tests].
|
||||||
|
|
||||||
|
[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html
|
||||||
|
|
||||||
|
## Submitting your solution
|
||||||
|
|
||||||
|
You can submit your solution using the `exercism submit src/lib.rs Cargo.toml` command.
|
||||||
|
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution which allows you to:
|
||||||
|
|
||||||
|
- See how others have completed the exercise
|
||||||
|
- Request help from a mentor
|
||||||
|
|
||||||
|
## Need to get help?
|
||||||
|
|
||||||
|
If you'd like help solving the exercise, check the following pages:
|
||||||
|
|
||||||
|
- The [Rust track's documentation](https://exercism.org/docs/tracks/rust)
|
||||||
|
- The [Rust track's programming category on the forum](https://forum.exercism.org/c/programming/rust)
|
||||||
|
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||||
|
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||||
|
|
||||||
|
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||||
|
|
||||||
|
## Rust Installation
|
||||||
|
|
||||||
|
Refer to the [exercism help page][help-page] for Rust installation and learning
|
||||||
|
resources.
|
||||||
|
|
||||||
|
## Submitting the solution
|
||||||
|
|
||||||
|
Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer.
|
||||||
|
|
||||||
|
## Feedback, Issues, Pull Requests
|
||||||
|
|
||||||
|
Head to [the forum](https://forum.exercism.org/c/programming/rust/) and create a post to provide feedback about an exercise or if you want to help implement new exercises.
|
||||||
|
Members of the rust track team are happy to help!
|
||||||
|
|
||||||
|
The GitHub [track repository][github] is the home for all of the Rust exercises.
|
||||||
|
|
||||||
|
If you want to know more about Exercism, take a look at the [contribution guide].
|
||||||
|
|
||||||
|
## Submitting Incomplete Solutions
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
||||||
|
[help-page]: https://exercism.org/tracks/rust/learning
|
||||||
|
[github]: https://github.com/exercism/rust
|
||||||
|
[contribution guide]: https://exercism.org/docs/community/contributors
|
||||||
76
rust/parallel-letter-frequency/README.md
Normal file
76
rust/parallel-letter-frequency/README.md
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Parallel Letter Frequency
|
||||||
|
|
||||||
|
Welcome to Parallel Letter Frequency on Exercism's Rust Track.
|
||||||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
Count the frequency of letters in texts using parallel computation.
|
||||||
|
|
||||||
|
Parallelism is about doing things in parallel that can also be done sequentially.
|
||||||
|
A common example is counting the frequency of letters.
|
||||||
|
Employ parallelism to calculate the total frequency of each letter in a list of texts.
|
||||||
|
|
||||||
|
## Parallel Letter Frequency in Rust
|
||||||
|
|
||||||
|
Learn more about concurrency in Rust here:
|
||||||
|
|
||||||
|
- [Concurrency](https://doc.rust-lang.org/book/ch16-00-concurrency.html)
|
||||||
|
|
||||||
|
## Bonus
|
||||||
|
|
||||||
|
This exercise also includes a benchmark, with a sequential implementation as a
|
||||||
|
baseline. You can compare your solution to the benchmark. Observe the
|
||||||
|
effect different size inputs have on the performance of each. Can you
|
||||||
|
surpass the benchmark using concurrent programming techniques?
|
||||||
|
|
||||||
|
As of this writing, test::Bencher is unstable and only available on
|
||||||
|
*nightly* Rust. Run the benchmarks with Cargo:
|
||||||
|
|
||||||
|
```
|
||||||
|
cargo bench
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using rustup.rs:
|
||||||
|
|
||||||
|
```
|
||||||
|
rustup run nightly cargo bench
|
||||||
|
```
|
||||||
|
|
||||||
|
- [Benchmark tests](https://doc.rust-lang.org/stable/unstable-book/library-features/test.html)
|
||||||
|
|
||||||
|
Learn more about nightly Rust:
|
||||||
|
|
||||||
|
- [Nightly Rust](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html)
|
||||||
|
- [Installing Rust nightly](https://rust-lang.github.io/rustup/concepts/channels.html#working-with-nightly-rust)
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Created by
|
||||||
|
|
||||||
|
- @EduardoBautista
|
||||||
|
|
||||||
|
### Contributed to by
|
||||||
|
|
||||||
|
- @andrewclarkson
|
||||||
|
- @ashleygwilliams
|
||||||
|
- @ccouzens
|
||||||
|
- @ClashTheBunny
|
||||||
|
- @coriolinus
|
||||||
|
- @cwhakes
|
||||||
|
- @EduardoBautista
|
||||||
|
- @efx
|
||||||
|
- @ErikSchierboom
|
||||||
|
- @etrepum
|
||||||
|
- @glennpratt
|
||||||
|
- @IanWhitney
|
||||||
|
- @kytrinyx
|
||||||
|
- @lutostag
|
||||||
|
- @mkantor
|
||||||
|
- @nfiles
|
||||||
|
- @petertseng
|
||||||
|
- @rofrol
|
||||||
|
- @sjwarner-bp
|
||||||
|
- @stringparser
|
||||||
|
- @xakon
|
||||||
|
- @ZapAnton
|
||||||
102
rust/parallel-letter-frequency/benches/benchmark.rs
Normal file
102
rust/parallel-letter-frequency/benches/benchmark.rs
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
#![feature(test)]
|
||||||
|
extern crate parallel_letter_frequency;
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use test::Bencher;
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_tiny_parallel(b: &mut Bencher) {
|
||||||
|
let tiny = &["a"];
|
||||||
|
b.iter(|| parallel_letter_frequency::frequency(tiny, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_tiny_sequential(b: &mut Bencher) {
|
||||||
|
let tiny = &["a"];
|
||||||
|
b.iter(|| frequency(tiny));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_small_parallel(b: &mut Bencher) {
|
||||||
|
let texts = all_texts(1);
|
||||||
|
b.iter(|| parallel_letter_frequency::frequency(&texts, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_small_sequential(b: &mut Bencher) {
|
||||||
|
let texts = all_texts(1);
|
||||||
|
b.iter(|| frequency(&texts));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_large_parallel(b: &mut Bencher) {
|
||||||
|
let texts = all_texts(30);
|
||||||
|
b.iter(|| parallel_letter_frequency::frequency(&texts, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_large_sequential(b: &mut Bencher) {
|
||||||
|
let texts = all_texts(30);
|
||||||
|
b.iter(|| frequency(&texts));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Simple sequential char frequency. Can it be beat?
|
||||||
|
pub fn frequency(texts: &[&str]) -> HashMap<char, usize> {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
|
for line in texts {
|
||||||
|
for chr in line.chars().filter(|c| c.is_alphabetic()) {
|
||||||
|
if let Some(c) = chr.to_lowercase().next() {
|
||||||
|
(*map.entry(c).or_insert(0)) += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map
|
||||||
|
}
|
||||||
|
|
||||||
|
fn all_texts(repeat: usize) -> Vec<&'static str> {
|
||||||
|
[ODE_AN_DIE_FREUDE, WILHELMUS, STAR_SPANGLED_BANNER]
|
||||||
|
.iter()
|
||||||
|
.cycle()
|
||||||
|
.take(3 * repeat)
|
||||||
|
.flat_map(|anthem| anthem.iter().cloned())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poem by Friedrich Schiller. The corresponding music is the European Anthem.
|
||||||
|
pub const ODE_AN_DIE_FREUDE: [&str; 8] = [
|
||||||
|
"Freude schöner Götterfunken",
|
||||||
|
"Tochter aus Elysium,",
|
||||||
|
"Wir betreten feuertrunken,",
|
||||||
|
"Himmlische, dein Heiligtum!",
|
||||||
|
"Deine Zauber binden wieder",
|
||||||
|
"Was die Mode streng geteilt;",
|
||||||
|
"Alle Menschen werden Brüder,",
|
||||||
|
"Wo dein sanfter Flügel weilt.",
|
||||||
|
];
|
||||||
|
|
||||||
|
// Dutch national anthem
|
||||||
|
pub const WILHELMUS: [&str; 8] = [
|
||||||
|
"Wilhelmus van Nassouwe",
|
||||||
|
"ben ik, van Duitsen bloed,",
|
||||||
|
"den vaderland getrouwe",
|
||||||
|
"blijf ik tot in den dood.",
|
||||||
|
"Een Prinse van Oranje",
|
||||||
|
"ben ik, vrij, onverveerd,",
|
||||||
|
"den Koning van Hispanje",
|
||||||
|
"heb ik altijd geëerd.",
|
||||||
|
];
|
||||||
|
|
||||||
|
// American national anthem
|
||||||
|
pub const STAR_SPANGLED_BANNER: [&str; 8] = [
|
||||||
|
"O say can you see by the dawn's early light,",
|
||||||
|
"What so proudly we hailed at the twilight's last gleaming,",
|
||||||
|
"Whose broad stripes and bright stars through the perilous fight,",
|
||||||
|
"O'er the ramparts we watched, were so gallantly streaming?",
|
||||||
|
"And the rockets' red glare, the bombs bursting in air,",
|
||||||
|
"Gave proof through the night that our flag was still there;",
|
||||||
|
"O say does that star-spangled banner yet wave,",
|
||||||
|
"O'er the land of the free and the home of the brave?",
|
||||||
|
];
|
||||||
41
rust/parallel-letter-frequency/src/lib.rs
Normal file
41
rust/parallel-letter-frequency/src/lib.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
use std::any::Any;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
pub fn frequency(input: &[&str], worker_count: usize) -> HashMap<char, usize> {
|
||||||
|
if input.is_empty() {
|
||||||
|
return HashMap::<char, usize>::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let worker_count = worker_count.max(1);
|
||||||
|
|
||||||
|
thread::scope(|s| {
|
||||||
|
let chunk_size = input.len().div_ceil(worker_count);
|
||||||
|
let mut handles: Vec<_> = input
|
||||||
|
.chunks(chunk_size)
|
||||||
|
.map(|chunk| {
|
||||||
|
s.spawn(move || {
|
||||||
|
let mut proxy_map = HashMap::new();
|
||||||
|
chunk
|
||||||
|
.iter()
|
||||||
|
.flat_map(|line| line.chars())
|
||||||
|
.filter(|char| char.is_alphabetic())
|
||||||
|
.flat_map(|char_slice| char_slice.to_lowercase())
|
||||||
|
.for_each(|char| {
|
||||||
|
*proxy_map.entry(char).or_insert(0) += 1;
|
||||||
|
});
|
||||||
|
proxy_map
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
handles
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| x.join().unwrap())
|
||||||
|
.fold(HashMap::new(), |mut acc, map| {
|
||||||
|
for (char, count) in map {
|
||||||
|
*acc.entry(char).or_insert(0) += count;
|
||||||
|
}
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,347 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use parallel_letter_frequency as frequency;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_texts() {
|
||||||
|
assert_eq!(frequency::frequency(&[], 4), HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one_text_with_one_letter() {
|
||||||
|
let mut hm = HashMap::new();
|
||||||
|
hm.insert('a', 1);
|
||||||
|
assert_eq!(frequency::frequency(&["a"], 4), hm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn one_text_with_multiple_letters() {
|
||||||
|
let mut hm = HashMap::new();
|
||||||
|
hm.insert('b', 2);
|
||||||
|
hm.insert('c', 3);
|
||||||
|
hm.insert('d', 1);
|
||||||
|
assert_eq!(frequency::frequency(&["bbcccd"], 4), hm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn two_texts_with_one_letter() {
|
||||||
|
let mut hm = HashMap::new();
|
||||||
|
hm.insert('e', 1);
|
||||||
|
hm.insert('f', 1);
|
||||||
|
assert_eq!(frequency::frequency(&["e", "f"], 4), hm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn two_texts_with_multiple_letters() {
|
||||||
|
let mut hm = HashMap::new();
|
||||||
|
hm.insert('g', 2);
|
||||||
|
hm.insert('h', 3);
|
||||||
|
hm.insert('i', 1);
|
||||||
|
assert_eq!(frequency::frequency(&["ggh", "hhi"], 4), hm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn case_insensitivity() {
|
||||||
|
let mut hm = HashMap::new();
|
||||||
|
hm.insert('a', 2);
|
||||||
|
assert_eq!(frequency::frequency(&["aA"], 4), hm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn many_empty_lines() {
|
||||||
|
let v = vec![""; 1000];
|
||||||
|
assert_eq!(frequency::frequency(&v[..], 4), HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ignore_whitespace() {
|
||||||
|
let v = [" ", "\t", "\r\n"];
|
||||||
|
assert_eq!(frequency::frequency(&v[..], 4), HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn many_times_same_text() {
|
||||||
|
let v = vec!["abc"; 1000];
|
||||||
|
let mut hm = HashMap::new();
|
||||||
|
hm.insert('a', 1000);
|
||||||
|
hm.insert('b', 1000);
|
||||||
|
hm.insert('c', 1000);
|
||||||
|
assert_eq!(frequency::frequency(&v[..], 4), hm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn punctuation_doesnt_count() {
|
||||||
|
assert!(!frequency::frequency(&WILHELMUS, 4).contains_key(&','));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn numbers_dont_count() {
|
||||||
|
assert!(!frequency::frequency(&["Testing, 1, 2, 3"], 4).contains_key(&'1'));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unicode_letters() {
|
||||||
|
let mut hm = HashMap::new();
|
||||||
|
hm.insert('本', 1);
|
||||||
|
hm.insert('φ', 1);
|
||||||
|
hm.insert('ほ', 1);
|
||||||
|
hm.insert('ø', 1);
|
||||||
|
let v = ["本", "φ", "ほ", "ø"];
|
||||||
|
assert_eq!(frequency::frequency(&v, 4), hm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn all_three_anthems_1_worker() {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
// These constants can be found under the last test if you wish to see them
|
||||||
|
for anthem in [ODE_AN_DIE_FREUDE, WILHELMUS, STAR_SPANGLED_BANNER].iter() {
|
||||||
|
for line in anthem.iter() {
|
||||||
|
v.push(*line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let freqs = frequency::frequency(&v[..], 1);
|
||||||
|
assert_eq!(freqs.get(&'a'), Some(&49));
|
||||||
|
assert_eq!(freqs.get(&'t'), Some(&56));
|
||||||
|
assert_eq!(freqs.get(&'ü'), Some(&2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn all_three_anthems_3_workers() {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
for anthem in [ODE_AN_DIE_FREUDE, WILHELMUS, STAR_SPANGLED_BANNER].iter() {
|
||||||
|
for line in anthem.iter() {
|
||||||
|
v.push(*line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let freqs = frequency::frequency(&v[..], 3);
|
||||||
|
assert_eq!(freqs.get(&'a'), Some(&49));
|
||||||
|
assert_eq!(freqs.get(&'t'), Some(&56));
|
||||||
|
assert_eq!(freqs.get(&'ü'), Some(&2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn non_integer_multiple_of_threads() {
|
||||||
|
let v = vec!["abc"; 999];
|
||||||
|
let mut hm = HashMap::new();
|
||||||
|
hm.insert('a', 999);
|
||||||
|
hm.insert('b', 999);
|
||||||
|
hm.insert('c', 999);
|
||||||
|
assert_eq!(frequency::frequency(&v[..], 4), hm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn large_texts() {
|
||||||
|
let expected: HashMap<char, usize> = [
|
||||||
|
('a', 845),
|
||||||
|
('b', 155),
|
||||||
|
('c', 278),
|
||||||
|
('d', 359),
|
||||||
|
('e', 1143),
|
||||||
|
('f', 222),
|
||||||
|
('g', 187),
|
||||||
|
('h', 507),
|
||||||
|
('i', 791),
|
||||||
|
('j', 12),
|
||||||
|
('k', 67),
|
||||||
|
('l', 423),
|
||||||
|
('m', 288),
|
||||||
|
('n', 833),
|
||||||
|
('o', 791),
|
||||||
|
('p', 197),
|
||||||
|
('q', 8),
|
||||||
|
('r', 432),
|
||||||
|
('s', 700),
|
||||||
|
('t', 1043),
|
||||||
|
('u', 325),
|
||||||
|
('v', 111),
|
||||||
|
('w', 223),
|
||||||
|
('x', 7),
|
||||||
|
('y', 251),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(frequency::frequency(&DOSTOEVSKY, 4), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poem by Friedrich Schiller. The corresponding music is the European Anthem.
|
||||||
|
const ODE_AN_DIE_FREUDE: [&str; 8] = [
|
||||||
|
"Freude schöner Götterfunken",
|
||||||
|
"Tochter aus Elysium,",
|
||||||
|
"Wir betreten feuertrunken,",
|
||||||
|
"Himmlische, dein Heiligtum!",
|
||||||
|
"Deine Zauber binden wieder",
|
||||||
|
"Was die Mode streng geteilt;",
|
||||||
|
"Alle Menschen werden Brüder,",
|
||||||
|
"Wo dein sanfter Flügel weilt.",
|
||||||
|
];
|
||||||
|
|
||||||
|
// Dutch national anthem
|
||||||
|
const WILHELMUS: [&str; 8] = [
|
||||||
|
"Wilhelmus van Nassouwe",
|
||||||
|
"ben ik, van Duitsen bloed,",
|
||||||
|
"den vaderland getrouwe",
|
||||||
|
"blijf ik tot in den dood.",
|
||||||
|
"Een Prinse van Oranje",
|
||||||
|
"ben ik, vrij, onverveerd,",
|
||||||
|
"den Koning van Hispanje",
|
||||||
|
"heb ik altijd geëerd.",
|
||||||
|
];
|
||||||
|
|
||||||
|
// American national anthem
|
||||||
|
const STAR_SPANGLED_BANNER: [&str; 8] = [
|
||||||
|
"O say can you see by the dawn's early light,",
|
||||||
|
"What so proudly we hailed at the twilight's last gleaming,",
|
||||||
|
"Whose broad stripes and bright stars through the perilous fight,",
|
||||||
|
"O'er the ramparts we watched, were so gallantly streaming?",
|
||||||
|
"And the rockets' red glare, the bombs bursting in air,",
|
||||||
|
"Gave proof through the night that our flag was still there;",
|
||||||
|
"O say does that star-spangled banner yet wave,",
|
||||||
|
"O'er the land of the free and the home of the brave?",
|
||||||
|
];
|
||||||
|
|
||||||
|
const DOSTOEVSKY: [&str; 4] = [
|
||||||
|
r#"
|
||||||
|
I am a sick man.... I am a spiteful man. I am an unattractive man.
|
||||||
|
I believe my liver is diseased. However, I know nothing at all about my disease, and do not
|
||||||
|
know for certain what ails me. I don't consult a doctor for it,
|
||||||
|
and never have, though I have a respect for medicine and doctors.
|
||||||
|
Besides, I am extremely superstitious, sufficiently so to respect medicine,
|
||||||
|
anyway (I am well-educated enough not to be superstitious, but I am superstitious).
|
||||||
|
No, I refuse to consult a doctor from spite.
|
||||||
|
That you probably will not understand. Well, I understand it, though.
|
||||||
|
Of course, I can't explain who it is precisely that I am mortifying in this case by my spite:
|
||||||
|
I am perfectly well aware that I cannot "pay out" the doctors by not consulting them;
|
||||||
|
I know better than anyone that by all this I am only injuring myself and no one else.
|
||||||
|
But still, if I don't consult a doctor it is from spite.
|
||||||
|
My liver is bad, well - let it get worse!
|
||||||
|
I have been going on like that for a long time - twenty years. Now I am forty.
|
||||||
|
I used to be in the government service, but am no longer.
|
||||||
|
I was a spiteful official. I was rude and took pleasure in being so.
|
||||||
|
I did not take bribes, you see, so I was bound to find a recompense in that, at least.
|
||||||
|
(A poor jest, but I will not scratch it out. I wrote it thinking it would sound very witty;
|
||||||
|
but now that I have seen myself that I only wanted to show off in a despicable way -
|
||||||
|
I will not scratch it out on purpose!) When petitioners used to come for
|
||||||
|
information to the table at which I sat, I used to grind my teeth at them,
|
||||||
|
and felt intense enjoyment when I succeeded in making anybody unhappy.
|
||||||
|
I almost did succeed. For the most part they were all timid people - of course,
|
||||||
|
they were petitioners. But of the uppish ones there was one officer in particular
|
||||||
|
I could not endure. He simply would not be humble, and clanked his sword in a disgusting way.
|
||||||
|
I carried on a feud with him for eighteen months over that sword. At last I got the better of him.
|
||||||
|
He left off clanking it. That happened in my youth, though. But do you know,
|
||||||
|
gentlemen, what was the chief point about my spite? Why, the whole point,
|
||||||
|
the real sting of it lay in the fact that continually, even in the moment of the acutest spleen,
|
||||||
|
I was inwardly conscious with shame that I was not only not a spiteful but not even an embittered man,
|
||||||
|
that I was simply scaring sparrows at random and amusing myself by it.
|
||||||
|
I might foam at the mouth, but bring me a doll to play with, give me a cup of tea with sugar in it,
|
||||||
|
and maybe I should be appeased. I might even be genuinely touched,
|
||||||
|
though probably I should grind my teeth at myself afterwards and lie awake at night with shame for
|
||||||
|
months after. That was my way. I was lying when I said just now that I was a spiteful official.
|
||||||
|
I was lying from spite. I was simply amusing myself with the petitioners and with the officer,
|
||||||
|
and in reality I never could become spiteful. I was conscious every moment in myself of many,
|
||||||
|
very many elements absolutely opposite to that. I felt them positively swarming in me,
|
||||||
|
these opposite elements. I knew that they had been swarming in me all my life and craving some outlet from me,
|
||||||
|
but I would not let them, would not let them, purposely would not let them come out.
|
||||||
|
They tormented me till I was ashamed: they drove me to convulsions and - sickened me, at last,
|
||||||
|
how they sickened me!
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
Gentlemen, I am joking, and I know myself that my jokes are not brilliant,
|
||||||
|
but you know one can take everything as a joke. I am, perhaps, jesting against the grain.
|
||||||
|
Gentlemen, I am tormented by questions; answer them for me. You, for instance, want to cure men of their
|
||||||
|
old habits and reform their will in accordance with science and good sense.
|
||||||
|
But how do you know, not only that it is possible, but also that it is
|
||||||
|
desirable to reform man in that way? And what leads you to the conclusion that man's
|
||||||
|
inclinations need reforming? In short, how do you know that such a reformation will be a benefit to man?
|
||||||
|
And to go to the root of the matter, why are you so positively convinced that not to act against
|
||||||
|
his real normal interests guaranteed by the conclusions of reason and arithmetic is certainly always
|
||||||
|
advantageous for man and must always be a law for mankind? So far, you know,
|
||||||
|
this is only your supposition. It may be the law of logic, but not the law of humanity.
|
||||||
|
You think, gentlemen, perhaps that I am mad? Allow me to defend myself. I agree that man
|
||||||
|
is pre-eminently a creative animal, predestined to strive consciously for an object and to engage in engineering -
|
||||||
|
that is, incessantly and eternally to make new roads, wherever
|
||||||
|
they may lead. But the reason why he wants sometimes to go off at a tangent may just be that he is
|
||||||
|
predestined to make the road, and perhaps, too, that however stupid the "direct"
|
||||||
|
practical man may be, the thought sometimes will occur to him that the road almost always does lead
|
||||||
|
somewhere, and that the destination it leads to is less important than the process
|
||||||
|
of making it, and that the chief thing is to save the well-conducted child from despising engineering,
|
||||||
|
and so giving way to the fatal idleness, which, as we all know,
|
||||||
|
is the mother of all the vices. Man likes to make roads and to create, that is a fact beyond dispute.
|
||||||
|
But why has he such a passionate love for destruction and chaos also?
|
||||||
|
Tell me that! But on that point I want to say a couple of words myself. May it not be that he loves
|
||||||
|
chaos and destruction (there can be no disputing that he does sometimes love it)
|
||||||
|
because he is instinctively afraid of attaining his object and completing the edifice he is constructing?
|
||||||
|
Who knows, perhaps he only loves that edifice from a distance, and is by no means
|
||||||
|
in love with it at close quarters; perhaps he only loves building it and does not want to live in it,
|
||||||
|
but will leave it, when completed, for the use of les animaux domestiques -
|
||||||
|
such as the ants, the sheep, and so on. Now the ants have quite a different taste.
|
||||||
|
They have a marvellous edifice of that pattern which endures for ever - the ant-heap.
|
||||||
|
With the ant-heap the respectable race of ants began and with the ant-heap they will probably end,
|
||||||
|
which does the greatest credit to their perseverance and good sense. But man is a frivolous and
|
||||||
|
incongruous creature, and perhaps, like a chess player, loves the process of the game, not the end of it.
|
||||||
|
And who knows (there is no saying with certainty), perhaps the only goal on earth
|
||||||
|
to which mankind is striving lies in this incessant process of attaining, in other words,
|
||||||
|
in life itself, and not in the thing to be attained, which must always be expressed as a formula,
|
||||||
|
as positive as twice two makes four, and such positiveness is not life, gentlemen,
|
||||||
|
but is the beginning of death.
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
But these are all golden dreams. Oh, tell me, who was it first announced,
|
||||||
|
who was it first proclaimed, that man only does nasty things because he does not know his own interests;
|
||||||
|
and that if he were enlightened, if his eyes were opened to his real normal interests,
|
||||||
|
man would at once cease to do nasty things, would at once become good and noble because,
|
||||||
|
being enlightened and understanding his real advantage, he would see his own advantage in the
|
||||||
|
good and nothing else, and we all know that not one man can, consciously, act against his own interests,
|
||||||
|
consequently, so to say, through necessity, he would begin doing good? Oh, the babe! Oh, the pure,
|
||||||
|
innocent child! Why, in the first place, when in all these thousands of years has there been a time
|
||||||
|
when man has acted only from his own interest? What is to be done with the millions of facts that bear
|
||||||
|
witness that men, consciously, that is fully understanding their real interests, have left them in the
|
||||||
|
background and have rushed headlong on another path, to meet peril and danger,
|
||||||
|
compelled to this course by nobody and by nothing, but, as it were, simply disliking the beaten track,
|
||||||
|
and have obstinately, wilfully, struck out another difficult, absurd way, seeking it almost in the darkness.
|
||||||
|
So, I suppose, this obstinacy and perversity were pleasanter to them than any advantage....
|
||||||
|
Advantage! What is advantage? And will you take it upon yourself to define with perfect accuracy in what the
|
||||||
|
advantage of man consists? And what if it so happens that a man's advantage, sometimes, not only may,
|
||||||
|
but even must, consist in his desiring in certain cases what is harmful to himself and not advantageous.
|
||||||
|
And if so, if there can be such a case, the whole principle falls into dust. What do you think -
|
||||||
|
are there such cases? You laugh; laugh away, gentlemen, but only answer me: have man's advantages been
|
||||||
|
reckoned up with perfect certainty? Are there not some which not only have not been included but cannot
|
||||||
|
possibly be included under any classification? You see, you gentlemen have, to the best of my knowledge,
|
||||||
|
taken your whole register of human advantages from the averages of statistical figures and
|
||||||
|
politico-economical formulas. Your advantages are prosperity, wealth, freedom, peace - and so on, and so on.
|
||||||
|
So that the man who should, for instance, go openly and knowingly in opposition to all that list would to your thinking,
|
||||||
|
and indeed mine, too, of course, be an obscurantist or an absolute madman: would not he? But, you know, this is
|
||||||
|
what is surprising: why does it so happen that all these statisticians, sages and lovers of humanity,
|
||||||
|
when they reckon up human advantages invariably leave out one? They don't even take it into their reckoning
|
||||||
|
in the form in which it should be taken, and the whole reckoning depends upon that. It would be no greater matter,
|
||||||
|
they would simply have to take it, this advantage, and add it to the list. But the trouble is, that this strange
|
||||||
|
advantage does not fall under any classification and is not in place in any list. I have a friend for instance ...
|
||||||
|
Ech! gentlemen, but of course he is your friend, too; and indeed there is no one, no one to whom he is not a friend!
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
Yes, but here I come to a stop! Gentlemen, you must excuse me for being over-philosophical;
|
||||||
|
it's the result of forty years underground! Allow me to indulge my fancy. You see, gentlemen, reason is an excellent thing,
|
||||||
|
there's no disputing that, but reason is nothing but reason and satisfies only the rational side of man's nature,
|
||||||
|
while will is a manifestation of the whole life, that is, of the whole human life including reason and all the impulses.
|
||||||
|
And although our life, in this manifestation of it, is often worthless, yet it is life and not simply extracting square roots.
|
||||||
|
Here I, for instance, quite naturally want to live, in order to satisfy all my capacities for life, and not simply my capacity
|
||||||
|
for reasoning, that is, not simply one twentieth of my capacity for life. What does reason know? Reason only knows what it has
|
||||||
|
succeeded in learning (some things, perhaps, it will never learn; this is a poor comfort, but why not say so frankly?)
|
||||||
|
and human nature acts as a whole, with everything that is in it, consciously or unconsciously, and, even it if goes wrong, it lives.
|
||||||
|
I suspect, gentlemen, that you are looking at me with compassion; you tell me again that an enlightened and developed man,
|
||||||
|
such, in short, as the future man will be, cannot consciously desire anything disadvantageous to himself, that that can be proved mathematically.
|
||||||
|
I thoroughly agree, it can - by mathematics. But I repeat for the hundredth time, there is one case, one only, when man may consciously, purposely,
|
||||||
|
desire what is injurious to himself, what is stupid, very stupid - simply in order to have the right to desire for himself even what is very stupid
|
||||||
|
and not to be bound by an obligation to desire only what is sensible. Of course, this very stupid thing, this caprice of ours, may be in reality,
|
||||||
|
gentlemen, more advantageous for us than anything else on earth, especially in certain cases. And in particular it may be more advantageous than
|
||||||
|
any advantage even when it does us obvious harm, and contradicts the soundest conclusions of our reason concerning our advantage -
|
||||||
|
for in any circumstances it preserves for us what is most precious and most important - that is, our personality, our individuality.
|
||||||
|
Some, you see, maintain that this really is the most precious thing for mankind; choice can, of course, if it chooses, be in agreement
|
||||||
|
with reason; and especially if this be not abused but kept within bounds. It is profitable and some- times even praiseworthy.
|
||||||
|
But very often, and even most often, choice is utterly and stubbornly opposed to reason ... and ... and ... do you know that that,
|
||||||
|
too, is profitable, sometimes even praiseworthy? Gentlemen, let us suppose that man is not stupid. (Indeed one cannot refuse to suppose that,
|
||||||
|
if only from the one consideration, that, if man is stupid, then who is wise?) But if he is not stupid, he is monstrously ungrateful!
|
||||||
|
Phenomenally ungrateful. In fact, I believe that the best definition of man is the ungrateful biped. But that is not all, that is not his worst defect;
|
||||||
|
his worst defect is his perpetual moral obliquity, perpetual - from the days of the Flood to the Schleswig-Holstein period.
|
||||||
|
"#,
|
||||||
|
];
|
||||||
19
sqlite/hello-world/.exercism/config.json
Normal file
19
sqlite/hello-world/.exercism/config.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"authors": [
|
||||||
|
"vaeng"
|
||||||
|
],
|
||||||
|
"files": {
|
||||||
|
"solution": [
|
||||||
|
"hello-world.sql"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"hello-world_test.sql"
|
||||||
|
],
|
||||||
|
"example": [
|
||||||
|
".meta/example.sql"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".",
|
||||||
|
"source": "This is an exercise to introduce users to using Exercism",
|
||||||
|
"source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program"
|
||||||
|
}
|
||||||
40
sqlite/hello-world/HELP.md
Normal file
40
sqlite/hello-world/HELP.md
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
# Help
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
Navigate to the directory containing the appropriate `${slug}_test.sql` file, where `${slug}` is the name of the exercise, using hyphens instead of spaces and all lowercase (e.g. `hello-world_test.sql` for the `Hello World` exercise).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sqlite3 -bail < ${slug}_test.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use `SELECT` statements for debugging.
|
||||||
|
The output will be forwarded to `user_output.md` and shown in the web-editor if tests fail.
|
||||||
|
|
||||||
|
You can find more information in the [sqlite track docs about testing](https://exercism.org/docs/tracks/sqlite/tests).
|
||||||
|
|
||||||
|
## Submitting your solution
|
||||||
|
|
||||||
|
You can submit your solution using the `exercism submit hello-world.sql` command.
|
||||||
|
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution which allows you to:
|
||||||
|
|
||||||
|
- See how others have completed the exercise
|
||||||
|
- Request help from a mentor
|
||||||
|
|
||||||
|
## Need to get help?
|
||||||
|
|
||||||
|
If you'd like help solving the exercise, check the following pages:
|
||||||
|
|
||||||
|
- The [SQLite track's documentation](https://exercism.org/docs/tracks/sqlite)
|
||||||
|
- The [SQLite track's programming category on the forum](https://forum.exercism.org/c/programming/sqlite)
|
||||||
|
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||||
|
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||||
|
|
||||||
|
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||||
|
|
||||||
|
If you're stuck on something, it may help to look at some of the [available resources](https://exercism.org/docs/tracks/sqlite/resources) or ask [The Exercism Community on Discord](https://exercism.org/r/discord).
|
||||||
|
|
||||||
|
Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/sqlite) is a good spot to search for your problem/question to see if it has been answered already.
|
||||||
|
If not, you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question.
|
||||||
31
sqlite/hello-world/README.md
Normal file
31
sqlite/hello-world/README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Hello World
|
||||||
|
|
||||||
|
Welcome to Hello World on Exercism's SQLite Track.
|
||||||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
The classical introductory exercise.
|
||||||
|
Just say "Hello, World!".
|
||||||
|
|
||||||
|
["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment.
|
||||||
|
|
||||||
|
The objectives are simple:
|
||||||
|
|
||||||
|
- Modify the provided code so that it produces the string "Hello, World!".
|
||||||
|
- Run the test suite and make sure that it succeeds.
|
||||||
|
- Submit your solution and check it at the website.
|
||||||
|
|
||||||
|
If everything goes well, you will be ready to fetch your first real exercise.
|
||||||
|
|
||||||
|
[hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Created by
|
||||||
|
|
||||||
|
- @vaeng
|
||||||
|
|
||||||
|
### Based on
|
||||||
|
|
||||||
|
This is an exercise to introduce users to using Exercism - https://en.wikipedia.org/wiki/%22Hello,_world!%22_program
|
||||||
3
sqlite/hello-world/create_fixture.sql
Normal file
3
sqlite/hello-world/create_fixture.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
DROP TABLE IF EXISTS hello_world;
|
||||||
|
|
||||||
|
CREATE TABLE hello_world (greeting TEXT);
|
||||||
4
sqlite/hello-world/hello-world.sql
Normal file
4
sqlite/hello-world/hello-world.sql
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
INSERT INTO
|
||||||
|
hello_world (greeting)
|
||||||
|
VALUES
|
||||||
|
('Hello, World!');
|
||||||
28
sqlite/hello-world/hello-world_test.sql
Normal file
28
sqlite/hello-world/hello-world_test.sql
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
-- Setup test table and read in student solution:
|
||||||
|
.read ./test_setup.sql
|
||||||
|
-- Test cases:
|
||||||
|
INSERT INTO
|
||||||
|
tests (name, uuid, expected)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
'Say Hi!',
|
||||||
|
'af9ffe10-dc13-42d8-a742-e7bdafac449d',
|
||||||
|
'Hello, World!'
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Comparison of user input and the tests updates the status for each test:
|
||||||
|
UPDATE tests
|
||||||
|
SET
|
||||||
|
status = 'pass'
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT
|
||||||
|
greeting
|
||||||
|
FROM
|
||||||
|
hello_world
|
||||||
|
) AS actual
|
||||||
|
WHERE
|
||||||
|
actual.greeting = tests.expected;
|
||||||
|
|
||||||
|
-- Write results and debug info:
|
||||||
|
.read ./test_reporter.sql
|
||||||
37
sqlite/hello-world/test_reporter.sql
Normal file
37
sqlite/hello-world/test_reporter.sql
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
-- Upadate message for failed tests to give helpful information:
|
||||||
|
UPDATE tests
|
||||||
|
SET
|
||||||
|
message = (
|
||||||
|
'Greeting' || ' is "' || COALESCE(actual.greeting, 'NULL') || '" but should be "' || tests.expected || '"'
|
||||||
|
)
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT
|
||||||
|
greeting
|
||||||
|
FROM
|
||||||
|
hello_world
|
||||||
|
) AS actual
|
||||||
|
WHERE
|
||||||
|
tests.status = 'fail';
|
||||||
|
|
||||||
|
-- Save results to ./output.json (needed by the online test-runner)
|
||||||
|
.mode json
|
||||||
|
.once './output.json'
|
||||||
|
SELECT
|
||||||
|
name,
|
||||||
|
status,
|
||||||
|
message,
|
||||||
|
output,
|
||||||
|
test_code,
|
||||||
|
task_id
|
||||||
|
FROM
|
||||||
|
tests;
|
||||||
|
|
||||||
|
-- Display test results in readable form for the student:
|
||||||
|
.mode table
|
||||||
|
SELECT
|
||||||
|
name,
|
||||||
|
status,
|
||||||
|
message
|
||||||
|
FROM
|
||||||
|
tests;
|
||||||
23
sqlite/hello-world/test_setup.sql
Normal file
23
sqlite/hello-world/test_setup.sql
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
-- Create database:
|
||||||
|
.read ./create_fixture.sql
|
||||||
|
-- Read user student solution and save any output as markdown in user_output.md:
|
||||||
|
.mode markdown
|
||||||
|
.output user_output.md
|
||||||
|
.read ./hello-world.sql
|
||||||
|
.output
|
||||||
|
-- Create a clean testing environment:
|
||||||
|
DROP TABLE IF EXISTS main.tests;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS main.tests (
|
||||||
|
-- uuid and name (description) are taken from the test.toml file
|
||||||
|
uuid TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
-- The following section is needed by the online test-runner
|
||||||
|
status TEXT DEFAULT 'fail',
|
||||||
|
message TEXT,
|
||||||
|
output TEXT,
|
||||||
|
test_code TEXT,
|
||||||
|
task_id INTEGER DEFAULT NULL,
|
||||||
|
-- Here are columns for the actual tests
|
||||||
|
expected TEXT NOT NULL
|
||||||
|
);
|
||||||
14
wasm/hello-world/.eslintrc
Normal file
14
wasm/hello-world/.eslintrc
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"root": true,
|
||||||
|
"extends": "@exercism/eslint-config-javascript",
|
||||||
|
"env": {
|
||||||
|
"jest": true
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": [".meta/proof.ci.js", ".meta/exemplar.js", "*.spec.js"],
|
||||||
|
"excludedFiles": ["custom.spec.js"],
|
||||||
|
"extends": "@exercism/eslint-config-javascript/maintainers"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
28
wasm/hello-world/.exercism/config.json
Normal file
28
wasm/hello-world/.exercism/config.json
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"authors": [
|
||||||
|
"bushidocodes"
|
||||||
|
],
|
||||||
|
"files": {
|
||||||
|
"solution": [
|
||||||
|
"hello-world.wat"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"hello-world.spec.js"
|
||||||
|
],
|
||||||
|
"example": [
|
||||||
|
".meta/proof.ci.wat"
|
||||||
|
],
|
||||||
|
"invalidator": [
|
||||||
|
"package.json"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".",
|
||||||
|
"source": "This is an exercise to introduce users to using Exercism",
|
||||||
|
"source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program",
|
||||||
|
"custom": {
|
||||||
|
"version.tests.compatibility": "jest-27",
|
||||||
|
"flag.tests.task-per-describe": false,
|
||||||
|
"flag.tests.may-run-long": false,
|
||||||
|
"flag.tests.includes-optional": false
|
||||||
|
}
|
||||||
|
}
|
||||||
1
wasm/hello-world/.npmrc
Normal file
1
wasm/hello-world/.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
audit=false
|
||||||
343
wasm/hello-world/HELP.md
Normal file
343
wasm/hello-world/HELP.md
Normal file
|
|
@ -0,0 +1,343 @@
|
||||||
|
# Help
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Go through the setup [instructions for WebAssembly][docs-exercism-wasm] to install the necessary dependencies.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Install assignment dependencies:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# Using npm
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Alternatively using yarn
|
||||||
|
yarn
|
||||||
|
```
|
||||||
|
|
||||||
|
## Making the test suite pass
|
||||||
|
|
||||||
|
All exercises come with a test suite to help you validate your solution before submitting.
|
||||||
|
You can execute these tests by opening a command prompt in the exercise's directory, and then running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Using npm
|
||||||
|
npm test
|
||||||
|
|
||||||
|
# Alternatively using yarn
|
||||||
|
yarn test
|
||||||
|
```
|
||||||
|
|
||||||
|
In some test suites all tests but the first have been skipped.
|
||||||
|
|
||||||
|
Once you get a test passing, you can enable the next one by changing `xtest` to `test`.
|
||||||
|
|
||||||
|
## Writing custom tests
|
||||||
|
|
||||||
|
If you wish to write additional, custom, tests, create a new file `custom.spec.js`, and submit it with your solution together with the new file:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
exercism submit numbers.wat custom.spec.js
|
||||||
|
```
|
||||||
|
|
||||||
|
[docs-exercism-wasm]: https://exercism.org/docs/tracks/wasm/installation
|
||||||
|
|
||||||
|
## Submitting your solution
|
||||||
|
|
||||||
|
You can submit your solution using the `exercism submit hello-world.wat` command.
|
||||||
|
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution which allows you to:
|
||||||
|
|
||||||
|
- See how others have completed the exercise
|
||||||
|
- Request help from a mentor
|
||||||
|
|
||||||
|
## Need to get help?
|
||||||
|
|
||||||
|
If you'd like help solving the exercise, check the following pages:
|
||||||
|
|
||||||
|
- The [WebAssembly track's documentation](https://exercism.org/docs/tracks/wasm)
|
||||||
|
- The [WebAssembly track's programming category on the forum](https://forum.exercism.org/c/programming/wasm)
|
||||||
|
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||||
|
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||||
|
|
||||||
|
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||||
|
|
||||||
|
To get help if you're having trouble, you can use one of the following resources:
|
||||||
|
|
||||||
|
- [/r/WebAssembly](https://www.reddit.com/r/WebAssembly/) is the WebAssembly subreddit.
|
||||||
|
- [Github issue tracker](https://github.com/exercism/wasm/issues) is where we track our development and maintenance of Javascript exercises in exercism. But if none of the above links help you, feel free to post an issue here.
|
||||||
|
|
||||||
|
## How to Debug
|
||||||
|
|
||||||
|
Unlike many languages, WebAssembly code does not automatically have access to global resources such as the console. Such functionality instead must be provided as imports.
|
||||||
|
|
||||||
|
In order to provide `console.log` like functionality and a few other niceties, the Exercism WebAssembly track exposes a standard library of functions across all exercises.
|
||||||
|
|
||||||
|
These functions must be imported at the top of your WebAssembly module and then can be called from within your WebAssembly code.
|
||||||
|
|
||||||
|
The `log_mem_*` functions expect to be able to access the linear memory of your WebAssembly module. By default, this is private state, so to make this accessible, you must export your linear memory under the export name `mem`. This is accomplished as follows:
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logging Locals and Globals
|
||||||
|
|
||||||
|
We provide logging functions for each of the primitive WebAssembly types. This is useful for logging global and local variables.
|
||||||
|
|
||||||
|
### log_i32_s - Log a 32-bit signed integer to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_i32_s" (func $log_i32_s (param i32)))
|
||||||
|
(func $main
|
||||||
|
;; logs -1
|
||||||
|
(call $log_i32_s (i32.const -1))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_i32_u - Log a 32-bit unsigned integer to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_i32_u" (func $log_i32_u (param i32)))
|
||||||
|
(func $main
|
||||||
|
;; Logs 42 to console
|
||||||
|
(call $log_i32_u (i32.const 42))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_i64_s - Log a 64-bit signed integer to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_i64_s" (func $log_i64_s (param i64)))
|
||||||
|
(func $main
|
||||||
|
;; Logs -99 to console
|
||||||
|
(call $log_i32_u (i64.const -99))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_i64_u - Log a 64-bit unsigned integer to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_i64_u" (func $log_i64_u (param i64)))
|
||||||
|
(func $main
|
||||||
|
;; Logs 42 to console
|
||||||
|
(call $log_i64_u (i32.const 42))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_f32 - Log a 32-bit floating point number to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_f32" (func $log_f32 (param f32)))
|
||||||
|
(func $main
|
||||||
|
;; Logs 3.140000104904175 to console
|
||||||
|
(call $log_f32 (f32.const 3.14))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_f64 - Log a 64-bit floating point number to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_f64" (func $log_f64 (param f64)))
|
||||||
|
(func $main
|
||||||
|
;; Logs 3.14 to console
|
||||||
|
(call $log_f64 (f64.const 3.14))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logging from Linear Memory
|
||||||
|
|
||||||
|
WebAssembly Linear Memory is a byte-addressable array of values. This serves as the equivalent of virtual memory for WebAssembly programs
|
||||||
|
|
||||||
|
We provide logging functions to interpret a range of addresses within linear memory as static arrays of certain types. This acts similar to the TypedArrays of JavaScript. The length parameters are not measured in bytes. They are measured in the number of consecutive elements of the type associated with the function.
|
||||||
|
|
||||||
|
**In order for these functions to work, your WebAssembly module must declare and export its linear memory using the named export "mem"**
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_mem_as_utf8 - Log a sequence of UTF8 characters to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_mem_as_utf8" (func $log_mem_as_utf8 (param $byteOffset i32) (param $length i32)))
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(data (i32.const 64) "Goodbye, Mars!")
|
||||||
|
(func $main
|
||||||
|
;; Logs "Goodbye, Mars!" to console
|
||||||
|
(call $log_mem_as_utf8 (i32.const 64) (i32.const 14))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_mem_as_i8 - Log a sequence of signed 8-bit integers to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_mem_as_i8" (func $log_mem_as_i8 (param $byteOffset i32) (param $length i32)))
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(func $main
|
||||||
|
(memory.fill (i32.const 128) (i32.const -42) (i32.const 10))
|
||||||
|
;; Logs an array of 10x -42 to console
|
||||||
|
(call $log_mem_as_u8 (i32.const 128) (i32.const 10))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_mem_as_u8 - Log a sequence of unsigned 8-bit integers to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_mem_as_u8" (func $log_mem_as_u8 (param $byteOffset i32) (param $length i32)))
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(func $main
|
||||||
|
(memory.fill (i32.const 128) (i32.const 42) (i32.const 10))
|
||||||
|
;; Logs an array of 10x 42 to console
|
||||||
|
(call $log_mem_as_u8 (i32.const 128) (i32.const 10))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_mem_as_i16 - Log a sequence of signed 16-bit integers to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_mem_as_i16" (func $log_mem_as_i16 (param $byteOffset i32) (param $length i32)))
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(func $main
|
||||||
|
(i32.store16 (i32.const 128) (i32.const -10000))
|
||||||
|
(i32.store16 (i32.const 130) (i32.const -10001))
|
||||||
|
(i32.store16 (i32.const 132) (i32.const -10002))
|
||||||
|
;; Logs [-10000, -10001, -10002] to console
|
||||||
|
(call $log_mem_as_i16 (i32.const 128) (i32.const 3))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_mem_as_u16 - Log a sequence of unsigned 16-bit integers to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_mem_as_u16" (func $log_mem_as_u16 (param $byteOffset i32) (param $length i32)))
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(func $main
|
||||||
|
(i32.store16 (i32.const 128) (i32.const 10000))
|
||||||
|
(i32.store16 (i32.const 130) (i32.const 10001))
|
||||||
|
(i32.store16 (i32.const 132) (i32.const 10002))
|
||||||
|
;; Logs [10000, 10001, 10002] to console
|
||||||
|
(call $log_mem_as_u16 (i32.const 128) (i32.const 3))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_mem_as_i32 - Log a sequence of signed 32-bit integers to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_mem_as_i32" (func $log_mem_as_i32 (param $byteOffset i32) (param $length i32)))
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(func $main
|
||||||
|
(i32.store (i32.const 128) (i32.const -10000000))
|
||||||
|
(i32.store (i32.const 132) (i32.const -10000001))
|
||||||
|
(i32.store (i32.const 136) (i32.const -10000002))
|
||||||
|
;; Logs [-10000000, -10000001, -10000002] to console
|
||||||
|
(call $log_mem_as_i32 (i32.const 128) (i32.const 3))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_mem_as_u32 - Log a sequence of unsigned 32-bit integers to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_mem_as_u32" (func $log_mem_as_u32 (param $byteOffset i32) (param $length i32)))
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(func $main
|
||||||
|
(i32.store (i32.const 128) (i32.const 100000000))
|
||||||
|
(i32.store (i32.const 132) (i32.const 100000001))
|
||||||
|
(i32.store (i32.const 136) (i32.const 100000002))
|
||||||
|
;; Logs [100000000, 100000001, 100000002] to console
|
||||||
|
(call $log_mem_as_u32 (i32.const 128) (i32.const 3))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_mem_as_i64 - Log a sequence of signed 64-bit integers to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_mem_as_i64" (func $log_mem_as_i64 (param $byteOffset i32) (param $length i32)))
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(func $main
|
||||||
|
(i64.store (i32.const 128) (i64.const -10000000000))
|
||||||
|
(i64.store (i32.const 136) (i64.const -10000000001))
|
||||||
|
(i64.store (i32.const 144) (i64.const -10000000002))
|
||||||
|
;; Logs [-10000000000, -10000000001, -10000000002] to console
|
||||||
|
(call $log_mem_as_i64 (i32.const 128) (i32.const 3))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_mem_as_u64 - Log a sequence of unsigned 64-bit integers to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_mem_as_u64" (func $log_mem_as_u64 (param $byteOffset i32) (param $length i32)))
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(func $main
|
||||||
|
(i64.store (i32.const 128) (i64.const 10000000000))
|
||||||
|
(i64.store (i32.const 136) (i64.const 10000000001))
|
||||||
|
(i64.store (i32.const 144) (i64.const 10000000002))
|
||||||
|
;; Logs [10000000000, 10000000001, 10000000002] to console
|
||||||
|
(call $log_mem_as_u64 (i32.const 128) (i32.const 3))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_mem_as_u64 - Log a sequence of 32-bit floating point numbers to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_mem_as_f32" (func $log_mem_as_f32 (param $byteOffset i32) (param $length i32)))
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(func $main
|
||||||
|
(f32.store (i32.const 128) (f32.const 3.14))
|
||||||
|
(f32.store (i32.const 132) (f32.const 3.14))
|
||||||
|
(f32.store (i32.const 136) (f32.const 3.14))
|
||||||
|
;; Logs [3.140000104904175, 3.140000104904175, 3.140000104904175] to console
|
||||||
|
(call $log_mem_as_u64 (i32.const 128) (i32.const 3))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### log_mem_as_f64 - Log a sequence of 64-bit floating point numbers to console
|
||||||
|
|
||||||
|
```wasm
|
||||||
|
(module
|
||||||
|
(import "console" "log_mem_as_f64" (func $log_mem_as_f64 (param $byteOffset i32) (param $length i32)))
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
(f64.store (i32.const 128) (f64.const 3.14))
|
||||||
|
(f64.store (i32.const 136) (f64.const 3.14))
|
||||||
|
(f64.store (i32.const 144) (f64.const 3.14))
|
||||||
|
;; Logs [3.14, 3.14, 3.14] to console
|
||||||
|
(call $log_mem_as_u64 (i32.const 128) (i32.const 3))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
```
|
||||||
21
wasm/hello-world/LICENSE
Normal file
21
wasm/hello-world/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Exercism
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
31
wasm/hello-world/README.md
Normal file
31
wasm/hello-world/README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Hello World
|
||||||
|
|
||||||
|
Welcome to Hello World on Exercism's WebAssembly Track.
|
||||||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
The classical introductory exercise.
|
||||||
|
Just say "Hello, World!".
|
||||||
|
|
||||||
|
["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment.
|
||||||
|
|
||||||
|
The objectives are simple:
|
||||||
|
|
||||||
|
- Modify the provided code so that it produces the string "Hello, World!".
|
||||||
|
- Run the test suite and make sure that it succeeds.
|
||||||
|
- Submit your solution and check it at the website.
|
||||||
|
|
||||||
|
If everything goes well, you will be ready to fetch your first real exercise.
|
||||||
|
|
||||||
|
[hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Created by
|
||||||
|
|
||||||
|
- @bushidocodes
|
||||||
|
|
||||||
|
### Based on
|
||||||
|
|
||||||
|
This is an exercise to introduce users to using Exercism - https://en.wikipedia.org/wiki/%22Hello,_world!%22_program
|
||||||
4
wasm/hello-world/babel.config.js
Normal file
4
wasm/hello-world/babel.config.js
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
export default {
|
||||||
|
presets: ["@exercism/babel-preset-javascript"],
|
||||||
|
plugins: [],
|
||||||
|
};
|
||||||
40
wasm/hello-world/hello-world.spec.js
Normal file
40
wasm/hello-world/hello-world.spec.js
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { compileWat, WasmRunner } from "@exercism/wasm-lib";
|
||||||
|
|
||||||
|
let wasmModule;
|
||||||
|
let currentInstance;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
try {
|
||||||
|
const watPath = new URL("./hello-world.wat", import.meta.url);
|
||||||
|
const { buffer } = await compileWat(watPath);
|
||||||
|
wasmModule = await WebAssembly.compile(buffer);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`Error compiling *.wat: \n${err}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Hello World", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
currentInstance = null;
|
||||||
|
|
||||||
|
if (!wasmModule) {
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
currentInstance = await new WasmRunner(wasmModule);
|
||||||
|
return Promise.resolve();
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`Error instantiating WebAssembly module: ${err}`);
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Say Hi!", () => {
|
||||||
|
expect(currentInstance).toBeTruthy();
|
||||||
|
const [offset, length] = currentInstance.exports.hello();
|
||||||
|
expect(length).toBe(13);
|
||||||
|
const greeting = currentInstance.get_mem_as_utf8(offset, length);
|
||||||
|
expect(greeting).toBe("Hello, World!");
|
||||||
|
});
|
||||||
|
});
|
||||||
16
wasm/hello-world/hello-world.wat
Normal file
16
wasm/hello-world/hello-world.wat
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
(module
|
||||||
|
(memory (export "mem") 1)
|
||||||
|
|
||||||
|
;; Initializes the WebAssembly Linear Memory with a UTF-8 string of 14 characters starting at offset 64
|
||||||
|
(data (i32.const 64) "Hello, World!")
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; Return a greeting
|
||||||
|
;;
|
||||||
|
;; Note: The final number (currently “14”) must match the length of the new string!
|
||||||
|
;;
|
||||||
|
;; @returns {(i32, i32)} The offset and length of the greeting
|
||||||
|
(func (export "hello") (result i32 i32)
|
||||||
|
(i32.const 64) (i32.const 13)
|
||||||
|
)
|
||||||
|
)
|
||||||
35
wasm/hello-world/package.json
Normal file
35
wasm/hello-world/package.json
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"name": "@exercism/wasm-hello-world",
|
||||||
|
"description": "Exercism exercises in WebAssembly.",
|
||||||
|
"author": "Sean McBride",
|
||||||
|
"type": "module",
|
||||||
|
"private": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/exercism/wasm",
|
||||||
|
"directory": "exercises/practice/hello-world"
|
||||||
|
},
|
||||||
|
"jest": {
|
||||||
|
"maxWorkers": 1
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.23.3",
|
||||||
|
"@exercism/babel-preset-javascript": "^0.4.0",
|
||||||
|
"@exercism/eslint-config-javascript": "^0.6.0",
|
||||||
|
"@types/jest": "^29.5.8",
|
||||||
|
"@types/node": "^20.9.1",
|
||||||
|
"babel-jest": "^29.7.0",
|
||||||
|
"core-js": "^3.33.2",
|
||||||
|
"eslint": "^8.54.0",
|
||||||
|
"jest": "^29.7.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js ./*",
|
||||||
|
"watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch ./*",
|
||||||
|
"lint": "eslint ."
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@exercism/wasm-lib": "^0.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
19
zig/hello-world/.exercism/config.json
Normal file
19
zig/hello-world/.exercism/config.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"authors": [
|
||||||
|
"massivelivefun"
|
||||||
|
],
|
||||||
|
"files": {
|
||||||
|
"solution": [
|
||||||
|
"hello_world.zig"
|
||||||
|
],
|
||||||
|
"test": [
|
||||||
|
"test_hello_world.zig"
|
||||||
|
],
|
||||||
|
"example": [
|
||||||
|
".meta/example.zig"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"blurb": "Exercism's classic introductory exercise. Just say \"Hello, World!\".",
|
||||||
|
"source": "This is an exercise to introduce users to using Exercism",
|
||||||
|
"source_url": "https://en.wikipedia.org/wiki/%22Hello,_world!%22_program"
|
||||||
|
}
|
||||||
53
zig/hello-world/HELP.md
Normal file
53
zig/hello-world/HELP.md
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Help
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
Write your code in `<exercise_name>.zig`.
|
||||||
|
|
||||||
|
To run the tests for an exercise, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
zig test test_exercise_name.zig
|
||||||
|
```
|
||||||
|
|
||||||
|
in the exercise's root directory (replacing `exercise_name` with the name of the exercise).
|
||||||
|
|
||||||
|
## Submitting your solution
|
||||||
|
|
||||||
|
You can submit your solution using the `exercism submit hello_world.zig` command.
|
||||||
|
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||||
|
|
||||||
|
It's possible to submit an incomplete solution which allows you to:
|
||||||
|
|
||||||
|
- See how others have completed the exercise
|
||||||
|
- Request help from a mentor
|
||||||
|
|
||||||
|
## Need to get help?
|
||||||
|
|
||||||
|
If you'd like help solving the exercise, check the following pages:
|
||||||
|
|
||||||
|
- The [Zig track's documentation](https://exercism.org/docs/tracks/zig)
|
||||||
|
- The [Zig track's programming category on the forum](https://forum.exercism.org/c/programming/zig)
|
||||||
|
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||||
|
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||||
|
|
||||||
|
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||||
|
|
||||||
|
- [The Zig Programming Language Documentation][documentation] is a great overview of all of the language features that Zig provides to those who use it.
|
||||||
|
- [Zig Guide][zig-guide] is an excellent primer that explains the language features that Zig has to offer.
|
||||||
|
- [Ziglings][ziglings] is highly recommended.
|
||||||
|
Learn Zig by fixing tiny broken programs.
|
||||||
|
- [The Zig Programming Language Discord][discord-zig] is the main [Discord][discord].
|
||||||
|
It provides a great way to get in touch with the Zig community at large, and get some quick, direct help for any Zig related problem.
|
||||||
|
- [#zig][irc] on irc.freenode.net is the main Zig IRC channel.
|
||||||
|
- [/r/Zig][reddit] is the main Zig subreddit.
|
||||||
|
- [Stack Overflow][stack-overflow] can be used to discover code snippets and solutions to problems that may have already asked and maybe solved by others.
|
||||||
|
|
||||||
|
[discord]: https://discordapp.com
|
||||||
|
[discord-zig]: https://discord.com/invite/gxsFFjE
|
||||||
|
[documentation]: https://ziglang.org/documentation/master
|
||||||
|
[irc]: https://webchat.freenode.net/?channels=%23zig
|
||||||
|
[reddit]: https://www.reddit.com/r/Zig
|
||||||
|
[stack-overflow]: https://stackoverflow.com/questions/tagged/zig
|
||||||
|
[zig-guide]: https://zig.guide/
|
||||||
|
[ziglings]: https://codeberg.org/ziglings/exercises
|
||||||
31
zig/hello-world/README.md
Normal file
31
zig/hello-world/README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Hello World
|
||||||
|
|
||||||
|
Welcome to Hello World on Exercism's Zig Track.
|
||||||
|
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||||
|
|
||||||
|
## Instructions
|
||||||
|
|
||||||
|
The classical introductory exercise.
|
||||||
|
Just say "Hello, World!".
|
||||||
|
|
||||||
|
["Hello, World!"][hello-world] is the traditional first program for beginning programming in a new language or environment.
|
||||||
|
|
||||||
|
The objectives are simple:
|
||||||
|
|
||||||
|
- Modify the provided code so that it produces the string "Hello, World!".
|
||||||
|
- Run the test suite and make sure that it succeeds.
|
||||||
|
- Submit your solution and check it at the website.
|
||||||
|
|
||||||
|
If everything goes well, you will be ready to fetch your first real exercise.
|
||||||
|
|
||||||
|
[hello-world]: https://en.wikipedia.org/wiki/%22Hello,_world!%22_program
|
||||||
|
|
||||||
|
## Source
|
||||||
|
|
||||||
|
### Created by
|
||||||
|
|
||||||
|
- @massivelivefun
|
||||||
|
|
||||||
|
### Based on
|
||||||
|
|
||||||
|
This is an exercise to introduce users to using Exercism - https://en.wikipedia.org/wiki/%22Hello,_world!%22_program
|
||||||
3
zig/hello-world/hello_world.zig
Normal file
3
zig/hello-world/hello_world.zig
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub fn hello() []const u8 {
|
||||||
|
return "Hello, World!";
|
||||||
|
}
|
||||||
10
zig/hello-world/test_hello_world.zig
Normal file
10
zig/hello-world/test_hello_world.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
const hello_world = @import("hello_world.zig");
|
||||||
|
|
||||||
|
test "say hi!" {
|
||||||
|
const expected = "Hello, World!";
|
||||||
|
const actual = hello_world.hello();
|
||||||
|
try testing.expectEqualStrings(expected, actual);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue