diff --git a/config.json b/config.json index 4f21bc3..07fd0d5 100644 --- a/config.json +++ b/config.json @@ -260,6 +260,14 @@ "prerequisites": [], "difficulty": 2 }, + { + "slug": "strain", + "name": "Strain", + "uuid": "1306a71c-5ddb-4421-a119-c4b5f2f38efe", + "practices": [], + "prerequisites": [], + "difficulty": 2 + }, { "slug": "triangle", "name": "Triangle", diff --git a/config.yaml b/config.yaml index 40a5be2..fb135d0 100644 --- a/config.yaml +++ b/config.yaml @@ -239,6 +239,13 @@ exercises: prerequisites: [] difficulty: 2 + - slug: strain + name: Strain + uuid: 1306a71c-5ddb-4421-a119-c4b5f2f38efe + practices: [] + prerequisites: [] + difficulty: 2 + - slug: triangle name: Triangle uuid: 494f403b-3bd7-47f1-a866-d07e9faea677 diff --git a/exercises/practice/strain/.docs/instructions.md b/exercises/practice/strain/.docs/instructions.md new file mode 100644 index 0000000..3469ae6 --- /dev/null +++ b/exercises/practice/strain/.docs/instructions.md @@ -0,0 +1,29 @@ +# Instructions + +Implement the `keep` and `discard` operation on collections. +Given a collection and a predicate on the collection's elements, `keep` returns a new collection containing those elements where the predicate is true, while `discard` returns a new collection containing those elements where the predicate is false. + +For example, given the collection of numbers: + +- 1, 2, 3, 4, 5 + +And the predicate: + +- is the number even? + +Then your keep operation should produce: + +- 2, 4 + +While your discard operation should produce: + +- 1, 3, 5 + +Note that the union of keep and discard is all the elements. + +The functions may be called `keep` and `discard`, or they may need different names in order to not clash with existing functions or concepts in your language. + +## Restrictions + +Keep your hands off that filter/reject/whatchamacallit functionality provided by your standard library! +Solve this one yourself using other basic tools instead. diff --git a/exercises/practice/strain/.meta/.yamlscript/exercise.mk b/exercises/practice/strain/.meta/.yamlscript/exercise.mk new file mode 100644 index 0000000..2506034 --- /dev/null +++ b/exercises/practice/strain/.meta/.yamlscript/exercise.mk @@ -0,0 +1 @@ +YS_VERSION := 0.1.75 diff --git a/exercises/practice/strain/.meta/Makefile b/exercises/practice/strain/.meta/Makefile new file mode 100644 index 0000000..9314ec0 --- /dev/null +++ b/exercises/practice/strain/.meta/Makefile @@ -0,0 +1,28 @@ +SHELL := bash + +BASE := $(shell pwd) + +export YS_VERSION := 0.1.80 + +YS_LOCAL_PREFIX := ../../../../.local/v$(YS_VERSION) + +YS_LOCAL_BIN := $(YS_LOCAL_PREFIX)/bin + +YS_BIN := $(YS_LOCAL_BIN)/ys-$(YS_VERSION) + +TEST_FILE ?= $(wildcard *-test.ys) + + +export PATH := $(YS_LOCAL_BIN):$(PATH) + +export YSPATH := $(BASE) + + +default: + +test: $(YS_BIN) + prove -v $(TEST_FILE) + +$(YS_BIN): + curl -s https://yamlscript.org/install | \ + BIN=1 VERSION=$(YS_VERSION) PREFIX=$(YS_LOCAL_PREFIX) bash >/dev/null diff --git a/exercises/practice/strain/.meta/config.json b/exercises/practice/strain/.meta/config.json new file mode 100644 index 0000000..a4c2cee --- /dev/null +++ b/exercises/practice/strain/.meta/config.json @@ -0,0 +1,23 @@ +{ + "authors": [ + "ingydotnet" + ], + "files": { + "solution": [ + "strain.ys" + ], + "test": [ + "strain-test.ys", + "GNUmakefile", + "Makefile", + ".yamlscript/exercise.mk", + ".yamlscript/exercism-ys-installer" + ], + "example": [ + ".meta/strain.ys" + ] + }, + "blurb": "Implement the `keep` and `discard` operation on collections.", + "source": "Conversation with James Edward Gray II", + "source_url": "http://graysoftinc.com/" +} diff --git a/exercises/practice/strain/.meta/strain-test.ys b/exercises/practice/strain/.meta/strain-test.ys new file mode 100644 index 0000000..1608436 --- /dev/null +++ b/exercises/practice/strain/.meta/strain-test.ys @@ -0,0 +1,125 @@ +#!/usr/bin/env ys-0 + +require ys::taptest: :all + +use: strain + +test:: +- name: Keep on empty list returns empty list + code: keep([] \(true)) + want: [] + uuid: 26af8c32-ba6a-4eb3-aa0a-ebd8f136e003 + +- name: Keeps everything + code: keep([1 3 5] \(true)) + want: + - 1 + - 3 + - 5 + uuid: f535cb4d-e99b-472a-bd52-9fa0ffccf454 + +- name: Keeps nothing + code: keep([1 3 5] \(false)) + want: [] + uuid: 950b8e8e-f628-42a8-85e2-9b30f09cde38 + +- name: Keeps first and last + code: keep([1 2 3] \((_ % 2) == 1)) + want: + - 1 + - 3 + uuid: 92694259-6e76-470c-af87-156bdf75018a + +- name: Keeps neither first nor last + code: keep([1 2 3] \((_ % 2) == 0)) + want: + - 2 + uuid: 938f7867-bfc7-449e-a21b-7b00cbb56994 + +- name: Keeps strings + code: keep( + qw(apple zebra banana zombies cherimoya zealot) + \(starts?(_ 'z'))) + want: + - zebra + - zombies + - zealot + uuid: 8908e351-4437-4d2b-a0f7-770811e48816 + +- name: Keeps lists + code: keep( + [[1 2 3] [5 5 5] [5 1 2] [2 1 2] [1 5 2] [2 2 1] [1 2 5]] + \(has?(_ 5))) + want: + - - 5 + - 5 + - 5 + - - 5 + - 1 + - 2 + - - 1 + - 5 + - 2 + - - 1 + - 2 + - 5 + uuid: 2728036b-102a-4f1e-a3ef-eac6160d876a + +- name: Discard on empty list returns empty list + code: discard([] \(true)) + want: [] + uuid: ef16beb9-8d84-451a-996a-14e80607fce6 + +- name: Discards everything + code: discard([1 3 5] \(true)) + want: [] + uuid: 2f42f9bc-8e06-4afe-a222-051b5d8cd12a + +- name: Discards nothing + code: discard([1 3 5] \(false)) + want: + - 1 + - 3 + - 5 + uuid: ca990fdd-08c2-4f95-aa50-e0f5e1d6802b + +- name: Discards first and last + code: discard([1 2 3] \((_ % 2) == 1)) + want: + - 2 + uuid: 71595dae-d283-48ca-a52b-45fa96819d2f + +- name: Discards neither first nor last + code: discard([1 2 3] \((_ % 2) == 0)) + want: + - 1 + - 3 + uuid: ae141f79-f86d-4567-b407-919eaca0f3dd + +- name: Discards strings + code: discard( + qw(apple zebra banana zombies cherimoya zealot) + \(starts?(_ 'z'))) + want: + - apple + - banana + - cherimoya + uuid: daf25b36-a59f-4f29-bcfe-302eb4e43609 + +- name: Discards lists + code: discard( + [[1 2 3] [5 5 5] [5 1 2] [2 1 2] [1 5 2] [2 2 1] [1 2 5]] + \(has?(_ 5))) + want: + - - 1 + - 2 + - 3 + - - 2 + - 1 + - 2 + - - 2 + - 2 + - 1 + uuid: a38d03f9-95ad-4459-80d1-48e937e4acaf + +done: 14 diff --git a/exercises/practice/strain/.meta/strain.ys b/exercises/practice/strain/.meta/strain.ys new file mode 100644 index 0000000..ce5a740 --- /dev/null +++ b/exercises/practice/strain/.meta/strain.ys @@ -0,0 +1,7 @@ +!yamlscript/v0 + +defn keep(list predicate): + mapcat \(when(predicate(_) [_])): list + +defn discard(list predicate): + mapcat \(when-not(predicate(_) [_])): list diff --git a/exercises/practice/strain/.meta/tests.toml b/exercises/practice/strain/.meta/tests.toml new file mode 100644 index 0000000..3a617b4 --- /dev/null +++ b/exercises/practice/strain/.meta/tests.toml @@ -0,0 +1,52 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[26af8c32-ba6a-4eb3-aa0a-ebd8f136e003] +description = "keep on empty list returns empty list" + +[f535cb4d-e99b-472a-bd52-9fa0ffccf454] +description = "keeps everything" + +[950b8e8e-f628-42a8-85e2-9b30f09cde38] +description = "keeps nothing" + +[92694259-6e76-470c-af87-156bdf75018a] +description = "keeps first and last" + +[938f7867-bfc7-449e-a21b-7b00cbb56994] +description = "keeps neither first nor last" + +[8908e351-4437-4d2b-a0f7-770811e48816] +description = "keeps strings" + +[2728036b-102a-4f1e-a3ef-eac6160d876a] +description = "keeps lists" + +[ef16beb9-8d84-451a-996a-14e80607fce6] +description = "discard on empty list returns empty list" + +[2f42f9bc-8e06-4afe-a222-051b5d8cd12a] +description = "discards everything" + +[ca990fdd-08c2-4f95-aa50-e0f5e1d6802b] +description = "discards nothing" + +[71595dae-d283-48ca-a52b-45fa96819d2f] +description = "discards first and last" + +[ae141f79-f86d-4567-b407-919eaca0f3dd] +description = "discards neither first nor last" + +[daf25b36-a59f-4f29-bcfe-302eb4e43609] +description = "discards strings" + +[a38d03f9-95ad-4459-80d1-48e937e4acaf] +description = "discards lists" diff --git a/exercises/practice/strain/.yamlscript/exercise.mk b/exercises/practice/strain/.yamlscript/exercise.mk new file mode 100644 index 0000000..2506034 --- /dev/null +++ b/exercises/practice/strain/.yamlscript/exercise.mk @@ -0,0 +1 @@ +YS_VERSION := 0.1.75 diff --git a/exercises/practice/strain/.yamlscript/exercism-ys-installer b/exercises/practice/strain/.yamlscript/exercism-ys-installer new file mode 100644 index 0000000..ae3fa01 --- /dev/null +++ b/exercises/practice/strain/.yamlscript/exercism-ys-installer @@ -0,0 +1,127 @@ +#!/env/bin/env bash + +set -euo pipefail + +intro-prompt() ( + cat <<... +-------------------------------------------------------------------------------- + +This YAMLScript Exercism exercise requires the YAMLScript version $version +interpreter command file to be installed here: + + $prefix/bin/ys + +You can install it by pressing Enter now, or by running this command: + + $make install-ys + +This should only take a few seconds and you only need to do this once. +Other exercises will use the same file. + +See https://yamlscript.org/doc/install/ for more YAMLScript installation info. + +-------------------------------------------------------------------------------- + +Would you like to install the 'ys' file now? + +... + + printf "Press Enter to install. Ctl-C to Quit."; read -r +) + +main() { + setup "$@" + + install-from-local + + $auto && intro-prompt + + installed || install-from-release || true + installed || install-from-build || true + installed || + die "Installing '$installed' failed. Giving up." \ + "Consider filing an issue at: $gh_issue_url" + + echo + echo 'Success!' + echo "$installed is now installed." + echo +} + +installed() { + [[ -f $installed ]] +} + +install-from-local() { + local path + path=$(command -v "$ysfq") || true + if [[ -f $path ]]; then + mkdir -p "$bin" + cp "$path" "$bin"/ + ln -fs "$ysfq" "$bin/ys-0" + ln -fs "$ysfq" "$bin/ys" + (installed && $auto) && exit + true + fi +} + +install-from-release() ( + set -x + curl -s https://yamlscript.org/install | + BIN=1 VERSION="$version" PREFIX="$prefix" bash +) + +install-from-build() ( + cat <<... + +The binary release installation failed. +We can attempt to build and install $ysfq now. +This can take from 1 to 5 minutes to complete. + +... + + printf "Press Enter to install. Ctl-C to Quit."; read -r + + [[ -d /tmp && -w /tmp ]] || + die "Can't write to /tmp" \ + 'Giving up.' + + set -x + + rm -fr "$yamlscript_clone" + + git clone --branch="$version" "$yamlscript_repo" "$yamlscript_clone" + + "$make" -C "$yamlscript_clone/ys" install PREFIX="$prefix" +) + +setup() { + version=$1 + prefix=$2 + make=$3 + auto=false + [[ ${4-} ]] && auto=true + + [[ $version =~ ^0\.1\.[0-9]+$ ]] || + die "Invalid YS_VERSION '$version'" + + bin=$prefix/bin + ysfq=ys-$version + installed=$bin/$ysfq + + if installed; then + echo "'$installed' is already installed." + exit + fi + + yamlscript_repo=https://github.com/yaml/yamlscript + yamlscript_clone=/tmp/yamlscript-exercism + gh_issue_url=https://github.com/exercism/yamlscript/issues +} + +die() { + printf '%s\n' "$@" >&2 + exit 1 +} + +main "$@" diff --git a/exercises/practice/strain/GNUmakefile b/exercises/practice/strain/GNUmakefile new file mode 100644 index 0000000..78a395a --- /dev/null +++ b/exercises/practice/strain/GNUmakefile @@ -0,0 +1,49 @@ +SHELL := bash + +BASE := $(shell pwd) + +export YS_VERSION := 0.1.80 + +YS_LOCAL_PREFIX := ../../../.local/v$(YS_VERSION) +ifeq (,$(shell [[ -d "$(YS_LOCAL_PREFIX)" ]] && echo ok)) +YS_LOCAL_PREFIX := $(shell cd .. && pwd -P)/.local/v$(YS_VERSION) +endif + +YS_LOCAL_BIN := $(YS_LOCAL_PREFIX)/bin +YS_BIN := $(YS_LOCAL_BIN)/ys-$(YS_VERSION) + +YS_INSTALLER := .yamlscript/exercism-ys-installer +YS_INSTALLER_CMD := \ + bash $(YS_INSTALLER) $(YS_VERSION) $(YS_LOCAL_PREFIX) $(MAKE) + +TEST_FILE ?= $(wildcard *-test.ys) + +export PATH := $(YS_LOCAL_BIN):$(PATH) +export YSPATH := $(BASE) + + +#------------------------------------------------------------------------------- +default: + @echo " No default make rule. Try 'make test'." + +test: $(YS_BIN) + prove -v $(TEST_FILE) + +install-ys: + @$(YS_INSTALLER_CMD) + +uninstall-ys: + rm -fr $(YS_LOCAL_PREFIX) + + +#------------------------------------------------------------------------------- +ifdef EXERCISM_YAMLSCRIPT_GHA +$(YS_BIN): + +else ifeq (/mnt/,$(dir $(BASE))) +$(YS_BIN): + +else +$(YS_BIN): + @$(YS_INSTALLER_CMD) auto +endif diff --git a/exercises/practice/strain/Makefile b/exercises/practice/strain/Makefile new file mode 100644 index 0000000..06b6f00 --- /dev/null +++ b/exercises/practice/strain/Makefile @@ -0,0 +1,8 @@ +# This Makefile is a decoy to attempt to detect when a non-GNU make is being +# used and alert the user. + +test: + @echo "You appear to be using a non-GNU version of the 'make' program." + @echo "The YAMLScript Exercism track requires you to use GNU make." + @echo "Please try 'make $@' again using GNU make." + @exit 1 diff --git a/exercises/practice/strain/strain-test.ys b/exercises/practice/strain/strain-test.ys new file mode 100644 index 0000000..45fbd6b --- /dev/null +++ b/exercises/practice/strain/strain-test.ys @@ -0,0 +1,111 @@ +#!/usr/bin/env ys-0 + +require ys::taptest: :all + +use: strain + +test:: +- name: Keep on empty list returns empty list + code: keep([] "fn([x] true)") + want: [] + +- name: Keeps everything + code: keep([1 3 5] "fn(x):\ true") + want: + - 1 + - 3 + - 5 + +- name: Keeps nothing + code: keep([1 3 5] "fn(x):\ false") + want: [] + +- name: Keeps first and last + code: keep([1 2 3] "fn(x):\ (x % 2) == 1") + want: + - 1 + - 3 + +- name: Keeps neither first nor last + code: keep([1 2 3] "fn(x):\ (x % 2) == 0") + want: + - 2 + +- name: Keeps strings + code: keep( + qw(apple zebra banana zombies cherimoya zealot) + "fn(x):\ starts?(x, 'z')") + want: + - zebra + - zombies + - zealot + +- name: Keeps lists + code: keep( + [[1 2 3] [5 5 5] [5 1 2] [2 1 2] [1 5 2] [2 2 1] [1 2 5]] + "fn(x):\ has?(x, 5)") + want: + - - 5 + - 5 + - 5 + - - 5 + - 1 + - 2 + - - 1 + - 5 + - 2 + - - 1 + - 2 + - 5 + +- name: Discard on empty list returns empty list + code: discard([] "fn(x):\ true") + want: [] + +- name: Discards everything + code: discard([1 3 5] "fn(x):\ true") + want: [] + +- name: Discards nothing + code: discard([1 3 5] "fn(x):\ false") + want: + - 1 + - 3 + - 5 + +- name: Discards first and last + code: discard([1 2 3] "fn(x):\ (x % 2) == 1") + want: + - 2 + +- name: Discards neither first nor last + code: discard([1 2 3] "fn(x):\ (x % 2) == 0") + want: + - 1 + - 3 + +- name: Discards strings + code: discard( + qw(apple zebra banana zombies cherimoya zealot) + "fn(x):\ starts?(x, 'z')") + want: + - apple + - banana + - cherimoya + +- name: Discards lists + code: discard( + [[1 2 3] [5 5 5] [5 1 2] [2 1 2] [1 5 2] [2 2 1] [1 2 5]] + "fn(x):\ has?(x, 5)") + want: + - - 1 + - 2 + - 3 + - - 2 + - 1 + - 2 + - - 2 + - 2 + - 1 + +done: 14 diff --git a/exercises/practice/strain/strain.ys b/exercises/practice/strain/strain.ys new file mode 100644 index 0000000..c1dfef9 --- /dev/null +++ b/exercises/practice/strain/strain.ys @@ -0,0 +1,7 @@ +!yamlscript/v0 + +defn keep(list predicate): + # Implement the 'keep' function. + +defn discard(list predicate): + # Implement the 'discard' function.