From 15f39c5c5b86fed2a9613cb518cb8a53e59c3ad1 Mon Sep 17 00:00:00 2001 From: Danylo Negrienko Date: Thu, 27 Jun 2024 13:45:50 -0400 Subject: [PATCH] pig-latin --- elixir/pig-latin/.exercism/config.json | 28 ++++++ elixir/pig-latin/.exercism/metadata.json | 1 + elixir/pig-latin/.formatter.exs | 4 + elixir/pig-latin/.gitignore | 24 ++++++ elixir/pig-latin/HELP.md | 75 +++++++++++++++++ elixir/pig-latin/README.md | 80 ++++++++++++++++++ elixir/pig-latin/lib/pig_latin.ex | 27 ++++++ elixir/pig-latin/mix.exs | 28 ++++++ elixir/pig-latin/test/pig_latin_test.exs | 103 +++++++++++++++++++++++ elixir/pig-latin/test/test_helper.exs | 2 + 10 files changed, 372 insertions(+) create mode 100644 elixir/pig-latin/.exercism/config.json create mode 100644 elixir/pig-latin/.exercism/metadata.json create mode 100644 elixir/pig-latin/.formatter.exs create mode 100644 elixir/pig-latin/.gitignore create mode 100644 elixir/pig-latin/HELP.md create mode 100644 elixir/pig-latin/README.md create mode 100644 elixir/pig-latin/lib/pig_latin.ex create mode 100644 elixir/pig-latin/mix.exs create mode 100644 elixir/pig-latin/test/pig_latin_test.exs create mode 100644 elixir/pig-latin/test/test_helper.exs diff --git a/elixir/pig-latin/.exercism/config.json b/elixir/pig-latin/.exercism/config.json new file mode 100644 index 0000000..bc3e105 --- /dev/null +++ b/elixir/pig-latin/.exercism/config.json @@ -0,0 +1,28 @@ +{ + "authors": [ + "DoggettCK" + ], + "contributors": [ + "alarregoity", + "angelikatyborska", + "Cohen-Carlisle", + "devonestes", + "moxley", + "neenjaw", + "sotojuan" + ], + "files": { + "solution": [ + "lib/pig_latin.ex" + ], + "test": [ + "test/pig_latin_test.exs" + ], + "example": [ + ".meta/example.ex" + ] + }, + "blurb": "Implement a program that translates from English to Pig Latin.", + "source": "The Pig Latin exercise at Test First Teaching by Ultrasaurus", + "source_url": "https://github.com/ultrasaurus/test-first-teaching/blob/master/learn_ruby/pig_latin/" +} diff --git a/elixir/pig-latin/.exercism/metadata.json b/elixir/pig-latin/.exercism/metadata.json new file mode 100644 index 0000000..d73e0cb --- /dev/null +++ b/elixir/pig-latin/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"elixir","exercise":"pig-latin","id":"3bcf481d20874254afa072bd2aabe30d","url":"https://exercism.org/tracks/elixir/exercises/pig-latin","handle":"negrienko","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/elixir/pig-latin/.formatter.exs b/elixir/pig-latin/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/elixir/pig-latin/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/elixir/pig-latin/.gitignore b/elixir/pig-latin/.gitignore new file mode 100644 index 0000000..504d3a8 --- /dev/null +++ b/elixir/pig-latin/.gitignore @@ -0,0 +1,24 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +pig_latin-*.tar + diff --git a/elixir/pig-latin/HELP.md b/elixir/pig-latin/HELP.md new file mode 100644 index 0000000..19bff39 --- /dev/null +++ b/elixir/pig-latin/HELP.md @@ -0,0 +1,75 @@ +# Help + +## Running the tests + +From the terminal, change to the base directory of the exercise then execute the tests with: + +```bash +$ mix test +``` + +This will execute the test file found in the `test` subfolder -- a file ending in `_test.exs` + +Documentation: + +* [`mix test` - Elixir's test execution tool](https://hexdocs.pm/mix/Mix.Tasks.Test.html) +* [`ExUnit` - Elixir's unit test library](https://hexdocs.pm/ex_unit/ExUnit.html) + +## Pending tests + +In test suites of practice exercises, all but the first test have been tagged to be skipped. + +Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol. + +For example: + +```elixir +# @tag :pending +test "shouting" do + assert Bob.hey("WATCH OUT!") == "Whoa, chill out!" +end +``` + +If you wish to run all tests at once, you can include all skipped test by using the `--include` flag on the `mix test` command: + +```bash +$ mix test --include pending +``` + +Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the file `test/test_helper.exs`. + +```elixir +# ExUnit.configure(exclude: :pending, trace: true) +``` + +## Useful `mix test` options + +* `test/.exs:LINENUM` - runs only a single test, the test from `.exs` whose definition is on line `LINENUM` +* `--failed` - runs only tests that failed the last time they ran +* `--max-failures` - the suite stops evaluating tests when this number of test failures +is reached +* `--seed 0` - disables randomization so the tests in a single file will always be ran +in the same order they were defined in + +## Submitting your solution + +You can submit your solution using the `exercism submit lib/pig_latin.ex` 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 [Elixir track's documentation](https://exercism.org/docs/tracks/elixir) +- The [Elixir track's programming category on the forum](https://forum.exercism.org/c/programming/elixir) +- [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/elixir/resources) out there where answers might be found. \ No newline at end of file diff --git a/elixir/pig-latin/README.md b/elixir/pig-latin/README.md new file mode 100644 index 0000000..8654987 --- /dev/null +++ b/elixir/pig-latin/README.md @@ -0,0 +1,80 @@ +# Pig Latin + +Welcome to Pig Latin on Exercism's Elixir Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +Your parents have challenged you and your sibling to a game of two-on-two basketball. +Confident they'll win, they let you score the first couple of points, but then start taking over the game. +Needing a little boost, you start speaking in [Pig Latin][pig-latin], which is a made-up children's language that's difficult for non-children to understand. +This will give you the edge to prevail over your parents! + +[pig-latin]: https://en.wikipedia.org/wiki/Pig_latin + +## Instructions + +Your task is to translate text from English to Pig Latin. +The translation is defined using four rules, which look at the pattern of vowels and consonants at the beginning of a word. +These rules look at each word's use of vowels and consonants: + +- vowels: the letters `a`, `e`, `i`, `o`, and `u` +- consonants: the other 21 letters of the English alphabet + +## Rule 1 + +If a word begins with a vowel, or starts with `"xr"` or `"yt"`, add an `"ay"` sound to the end of the word. + +For example: + +- `"apple"` -> `"appleay"` (starts with vowel) +- `"xray"` -> `"xrayay"` (starts with `"xr"`) +- `"yttria"` -> `"yttriaay"` (starts with `"yt"`) + +## Rule 2 + +If a word begins with a one or more consonants, first move those consonants to the end of the word and then add an `"ay"` sound to the end of the word. + +For example: + +- `"pig"` -> `"igp"` -> `"igpay"` (starts with single consonant) +- `"chair"` -> `"airch"` -> `"airchay"` (starts with multiple consonants) +- `"thrush"` -> `"ushthr"` -> `"ushthray"` (starts with multiple consonants) + +## Rule 3 + +If a word starts with zero or more consonants followed by `"qu"`, first move those consonants (if any) and the `"qu"` part to the end of the word, and then add an `"ay"` sound to the end of the word. + +For example: + +- `"quick"` -> `"ickqu"` -> `"ay"` (starts with `"qu"`, no preceding consonants) +- `"square"` -> `"aresqu"` -> `"aresquay"` (starts with one consonant followed by `"qu`") + +## Rule 4 + +If a word starts with one or more consonants followed by `"y"`, first move the consonants preceding the `"y"`to the end of the word, and then add an `"ay"` sound to the end of the word. + +Some examples: + +- `"my"` -> `"ym"` -> `"ymay"` (starts with single consonant followed by `"y"`) +- `"rhythm"` -> `"ythmrh"` -> `"ythmrhay"` (starts with multiple consonants followed by `"y"`) + +## Source + +### Created by + +- @DoggettCK + +### Contributed to by + +- @alarregoity +- @angelikatyborska +- @Cohen-Carlisle +- @devonestes +- @moxley +- @neenjaw +- @sotojuan + +### Based on + +The Pig Latin exercise at Test First Teaching by Ultrasaurus - https://github.com/ultrasaurus/test-first-teaching/blob/master/learn_ruby/pig_latin/ \ No newline at end of file diff --git a/elixir/pig-latin/lib/pig_latin.ex b/elixir/pig-latin/lib/pig_latin.ex new file mode 100644 index 0000000..52e3e56 --- /dev/null +++ b/elixir/pig-latin/lib/pig_latin.ex @@ -0,0 +1,27 @@ +defmodule PigLatin do + @doc """ + Given a `phrase`, translate it a word at a time to Pig Latin. + """ + + @vowels ~w(a e i o u) + + @spec translate(phrase :: String.t()) :: String.t() + def translate(phrase) do + phrase + |> String.split() + |> Enum.map(&String.graphemes/1) + |> Enum.map(&translate_word/1) + |> Enum.join(" ") + end + + @spec translate_word(word :: [String.t()]) :: String.t() + defp translate_word(["q", "u" | rest]), do: rest ++ ~w(quay) + defp translate_word(["x", "r" | _rest] = word), do: ay(word) + defp translate_word(["y", "t" | _rest] = word), do: ay(word) + defp translate_word([hd | _rest] = word) when hd in @vowels, do: ay(word) + defp translate_word([hd, x | _rest] = word) when hd in ~w(x y) and x not in @vowels, do: ay(word) + defp translate_word([hd | rest]), do: translate_word(rest ++ [hd]) + + @spec ay(word :: [String.t()]) :: [String.t()] + defp ay(list), do: list ++ ~w(ay) +end diff --git a/elixir/pig-latin/mix.exs b/elixir/pig-latin/mix.exs new file mode 100644 index 0000000..3b4e2ce --- /dev/null +++ b/elixir/pig-latin/mix.exs @@ -0,0 +1,28 @@ +defmodule PigLatin.MixProject do + use Mix.Project + + def project do + [ + app: :pig_latin, + version: "0.1.0", + # elixir: "~> 1.8", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger] + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + # {:dep_from_hexpm, "~> 0.3.0"}, + # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} + ] + end +end diff --git a/elixir/pig-latin/test/pig_latin_test.exs b/elixir/pig-latin/test/pig_latin_test.exs new file mode 100644 index 0000000..b55d0c9 --- /dev/null +++ b/elixir/pig-latin/test/pig_latin_test.exs @@ -0,0 +1,103 @@ +defmodule PigLatinTest do + use ExUnit.Case + + describe "ay is added to words that start with vowels" do + test "word beginning with a" do + assert PigLatin.translate("apple") == "appleay" + end + + test "word beginning with e" do + assert PigLatin.translate("ear") == "earay" + end + + test "word beginning with i" do + assert PigLatin.translate("igloo") == "iglooay" + end + + test "word beginning with o" do + assert PigLatin.translate("object") == "objectay" + end + + test "word beginning with u" do + assert PigLatin.translate("under") == "underay" + end + + test "word beginning with a vowel and followed by a qu" do + assert PigLatin.translate("equal") == "equalay" + end + end + + describe "first letter and ay are moved to the end of words that start with consonants" do + test "word beginning with p" do + assert PigLatin.translate("pig") == "igpay" + end + + test "word beginning with k" do + assert PigLatin.translate("koala") == "oalakay" + end + + test "word beginning with x" do + assert PigLatin.translate("xenon") == "enonxay" + end + + test "word beginning with q without a following u" do + assert PigLatin.translate("qat") == "atqay" + end + end + + describe "some letter clusters are treated like a single consonant" do + test "word beginning with ch" do + assert PigLatin.translate("chair") == "airchay" + end + + test "word beginning with qu" do + assert PigLatin.translate("queen") == "eenquay" + end + + test "word beginning with qu and a preceding consonant" do + assert PigLatin.translate("square") == "aresquay" + end + + test "word beginning with th" do + assert PigLatin.translate("therapy") == "erapythay" + end + + test "word beginning with thr" do + assert PigLatin.translate("thrush") == "ushthray" + end + + test "word beginning with sch" do + assert PigLatin.translate("school") == "oolschay" + end + end + + describe "some letter clusters are treated like a single vowel" do + test "word beginning with y, followed by a consonant" do + assert PigLatin.translate("yttria") == "yttriaay" + end + + test "word beginning with xr" do + assert PigLatin.translate("xray") == "xrayay" + end + end + + describe "position of y in a word determines if it is a consonant or a vowel" do + test "y is treated like a consonant at the beginning of a word" do + assert PigLatin.translate("yellow") == "ellowyay" + end + + test "y is treated like a vowel at the end of a consonant cluster" do + assert PigLatin.translate("rhythm") == "ythmrhay" + end + + test "y as second letter in two letter word" do + assert PigLatin.translate("my") == "ymay" + end + end + + describe "phrases are translated" do + test "a whole phrase" do + assert PigLatin.translate("quick fast run") == "ickquay astfay unray" + end + end +end diff --git a/elixir/pig-latin/test/test_helper.exs b/elixir/pig-latin/test/test_helper.exs new file mode 100644 index 0000000..35fc5bf --- /dev/null +++ b/elixir/pig-latin/test/test_helper.exs @@ -0,0 +1,2 @@ +ExUnit.start() +ExUnit.configure(exclude: :pending, trace: true)