From c1318858ae3ec39f3d86dcad72380747ec550c3e Mon Sep 17 00:00:00 2001 From: Meatball Date: Mon, 5 Dec 2022 09:40:42 +0100 Subject: [PATCH 1/3] added micro_blog --- config.json | 16 +++++++ .../practice/micro-blog/.docs/instructions.md | 37 +++++++++++++++ .../practice/micro-blog/.meta/config.json | 19 ++++++++ .../practice/micro-blog/.meta/example.py | 2 + .../practice/micro-blog/.meta/template.j2 | 13 ++++++ .../practice/micro-blog/.meta/tests.toml | 46 +++++++++++++++++++ exercises/practice/micro-blog/micro_blog.py | 2 + .../practice/micro-blog/micro_blog_test.py | 45 ++++++++++++++++++ 8 files changed, 180 insertions(+) create mode 100644 exercises/practice/micro-blog/.docs/instructions.md create mode 100644 exercises/practice/micro-blog/.meta/config.json create mode 100644 exercises/practice/micro-blog/.meta/example.py create mode 100644 exercises/practice/micro-blog/.meta/template.j2 create mode 100644 exercises/practice/micro-blog/.meta/tests.toml create mode 100644 exercises/practice/micro-blog/micro_blog.py create mode 100644 exercises/practice/micro-blog/micro_blog_test.py diff --git a/config.json b/config.json index df8633bb8f..9c4b50be85 100644 --- a/config.json +++ b/config.json @@ -450,6 +450,21 @@ "prerequisites": ["basics", "bools", "conditionals", "strings"], "difficulty": 1 }, + { + "slug": "micro-blog", + "name": "Micro Blog", + "uuid": "09494d98-5a80-482f-bd97-924e4817eab5", + "practices": ["sequences"], + "prerequisites": [ + "basics", + "conditionals", + "lists", + "loops", + "numbers", + "strings" + ], + "difficulty": 1 + }, { "slug": "space-age", "name": "Space Age", @@ -729,6 +744,7 @@ ], "difficulty": 2 }, + { "slug": "phone-number", "name": "Phone Number", diff --git a/exercises/practice/micro-blog/.docs/instructions.md b/exercises/practice/micro-blog/.docs/instructions.md new file mode 100644 index 0000000000..d6c6cf6561 --- /dev/null +++ b/exercises/practice/micro-blog/.docs/instructions.md @@ -0,0 +1,37 @@ +# Instructions + +You have identified a gap in the social media market for very very short posts. +Now that Twitter allows 280 character posts, people wanting quick social media updates aren't being served. +You decide to create your own social media network. + +To make your product noteworthy, you make it extreme and only allow posts of 5 or less characters. +Any posts of more than 5 characters should be truncated to 5. + +To allow your users to express themselves fully, you allow Emoji and other Unicode. + +The task is to truncate input strings to 5 characters. + +## Text Encodings + +Text stored digitally has to be converted to a series of bytes. +There are 3 ways to map characters to bytes in common use. + +- **ASCII** can encode English language characters. + All characters are precisely 1 byte long. +- **UTF-8** is a Unicode text encoding. + Characters take between 1 and 4 bytes. +- **UTF-16** is a Unicode text encoding. + Characters are either 2 or 4 bytes long. + +UTF-8 and UTF-16 are both Unicode encodings which means they're capable of representing a massive range of characters including: + +- Text in most of the world's languages and scripts +- Historic text +- Emoji + +UTF-8 and UTF-16 are both variable length encodings, which means that different characters take up different amounts of space. + +Consider the letter 'a' and the emoji 'πŸ˜›'. +In UTF-16 the letter takes 2 bytes but the emoji takes 4 bytes. + +The trick to this exercise is to use APIs designed around Unicode characters (codepoints) instead of Unicode codeunits. diff --git a/exercises/practice/micro-blog/.meta/config.json b/exercises/practice/micro-blog/.meta/config.json new file mode 100644 index 0000000000..037232147a --- /dev/null +++ b/exercises/practice/micro-blog/.meta/config.json @@ -0,0 +1,19 @@ +{ + "blurb": "Given an input string, truncate it to 5 characters.", + "authors": [ + "meatball133", + "Bethanyg" + ], + "contributors": [], + "files": { + "solution": [ + "micro_blog.py" + ], + "test": [ + "micro_blog_test.py" + ], + "example": [ + ".meta/example.py" + ] + } +} diff --git a/exercises/practice/micro-blog/.meta/example.py b/exercises/practice/micro-blog/.meta/example.py new file mode 100644 index 0000000000..d8ef8a9ed1 --- /dev/null +++ b/exercises/practice/micro-blog/.meta/example.py @@ -0,0 +1,2 @@ +def truncate(string): + return string[:5] diff --git a/exercises/practice/micro-blog/.meta/template.j2 b/exercises/practice/micro-blog/.meta/template.j2 new file mode 100644 index 0000000000..fd37969955 --- /dev/null +++ b/exercises/practice/micro-blog/.meta/template.j2 @@ -0,0 +1,13 @@ +{%- import "generator_macros.j2" as macros with context -%} +{% macro test_case(case) -%} + def test_some(self): + self.assertEqual({{ case["property"] | to_snake }}("{{case["input"]["phrase"]}}"), + "{{case["expected"]}}" + ) +{%- endmacro %} +{{ macros.header()}} + +class {{ exercise | camel_case }}Test(unittest.TestCase): + {% for case in cases -%} + {{ test_case(case) }} + {% endfor %} diff --git a/exercises/practice/micro-blog/.meta/tests.toml b/exercises/practice/micro-blog/.meta/tests.toml new file mode 100644 index 0000000000..f23ff0bc22 --- /dev/null +++ b/exercises/practice/micro-blog/.meta/tests.toml @@ -0,0 +1,46 @@ +# 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. + +[b927b57f-7c98-42fd-8f33-fae091dc1efc] +description = "English language short" + +[a3fcdc5b-0ed4-4f49-80f5-b1a293eac2a0] +description = "English language long" + +[01910864-8e15-4007-9c7c-ac956c686e60] +description = "German language short (broth)" + +[f263e488-aefb-478f-a671-b6ba99722543] +description = "German language long (bear carpet β†’ beards)" + +[0916e8f1-41d7-4402-a110-b08aa000342c] +description = "Bulgarian language short (good)" + +[bed6b89c-03df-4154-98e6-a61a74f61b7d] +description = "Greek language short (health)" + +[485a6a70-2edb-424d-b999-5529dbc8e002] +description = "Maths short" + +[8b4b7b51-8f48-4fbe-964e-6e4e6438be28] +description = "Maths long" + +[71f4a192-0566-4402-a512-fe12878be523] +description = "English and emoji short" + +[6f0f71f3-9806-4759-a844-fa182f7bc203] +description = "Emoji short" + +[ce71fb92-5214-46d0-a7f8-d5ba56b4cc6e] +description = "Emoji long" + +[5dee98d2-d56e-468a-a1f2-121c3f7c5a0b] +description = "Royal Flush?" diff --git a/exercises/practice/micro-blog/micro_blog.py b/exercises/practice/micro-blog/micro_blog.py new file mode 100644 index 0000000000..d8ef8a9ed1 --- /dev/null +++ b/exercises/practice/micro-blog/micro_blog.py @@ -0,0 +1,2 @@ +def truncate(string): + return string[:5] diff --git a/exercises/practice/micro-blog/micro_blog_test.py b/exercises/practice/micro-blog/micro_blog_test.py new file mode 100644 index 0000000000..1113667c92 --- /dev/null +++ b/exercises/practice/micro-blog/micro_blog_test.py @@ -0,0 +1,45 @@ +import unittest + +from micro_blog import ( + truncate, +) + +# Tests adapted from `problem-specifications//canonical-data.json` + + +class MicroBlogTest(unittest.TestCase): + def test_some1(self): + self.assertEqual(truncate("Hi"), "Hi") + + def test_some2(self): + self.assertEqual(truncate("Hello there"), "Hello") + + def test_some3(self): + self.assertEqual(truncate("brΓΌhe"), "brΓΌhe") + + def test_some4(self): + self.assertEqual(truncate("BΓ€rteppich"), "BΓ€rte") + + def test_some5(self): + self.assertEqual(truncate("Π”ΠΎΠ±ΡŠΡ€"), "Π”ΠΎΠ±ΡŠΡ€") + + def test_some6(self): + self.assertEqual(truncate("υγΡιά"), "υγΡιά") + + def test_some7(self): + self.assertEqual(truncate("a=Ο€rΒ²"), "a=Ο€rΒ²") + + def test_some8(self): + self.assertEqual(truncate("βˆ…βŠŠβ„•βŠŠβ„€βŠŠβ„šβŠŠβ„βŠŠβ„‚"), "βˆ…βŠŠβ„•βŠŠβ„€") + + def test_some9(self): + self.assertEqual(truncate("Fly πŸ›«"), "Fly πŸ›«") + + def test_some10(self): + self.assertEqual(truncate("πŸ’‡"), "πŸ’‡") + + def test_some11(self): + self.assertEqual(truncate("β„πŸŒ‘πŸ€§πŸ€’πŸ₯πŸ•°πŸ˜€"), "β„πŸŒ‘πŸ€§πŸ€’πŸ₯") + + def test_some12(self): + self.assertEqual(truncate("πŸƒŽπŸ‚ΈπŸƒ…πŸƒ‹πŸƒπŸƒπŸƒŠ"), "πŸƒŽπŸ‚ΈπŸƒ…πŸƒ‹πŸƒ") From be58f08a7a96fdc9696da560f140d21f184b3fda Mon Sep 17 00:00:00 2001 From: Meatball Date: Mon, 5 Dec 2022 16:11:31 +0100 Subject: [PATCH 2/3] Updated jinja --- .../practice/micro-blog/.meta/example.py | 4 +-- .../practice/micro-blog/.meta/template.j2 | 6 +++- .../practice/micro-blog/micro_blog_test.py | 36 ++++++++++++------- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/exercises/practice/micro-blog/.meta/example.py b/exercises/practice/micro-blog/.meta/example.py index d8ef8a9ed1..20351a317a 100644 --- a/exercises/practice/micro-blog/.meta/example.py +++ b/exercises/practice/micro-blog/.meta/example.py @@ -1,2 +1,2 @@ -def truncate(string): - return string[:5] +def truncate(letters): + return letters[:5] diff --git a/exercises/practice/micro-blog/.meta/template.j2 b/exercises/practice/micro-blog/.meta/template.j2 index fd37969955..ec817bb456 100644 --- a/exercises/practice/micro-blog/.meta/template.j2 +++ b/exercises/practice/micro-blog/.meta/template.j2 @@ -1,6 +1,10 @@ {%- import "generator_macros.j2" as macros with context -%} {% macro test_case(case) -%} - def test_some(self): + {% if "β†’" in case["description"] %} + def test_german_language_long(self): + {% else %} + def test_{{case["description"] | to_snake}}(self): + {% endif %} self.assertEqual({{ case["property"] | to_snake }}("{{case["input"]["phrase"]}}"), "{{case["expected"]}}" ) diff --git a/exercises/practice/micro-blog/micro_blog_test.py b/exercises/practice/micro-blog/micro_blog_test.py index 1113667c92..93538a7745 100644 --- a/exercises/practice/micro-blog/micro_blog_test.py +++ b/exercises/practice/micro-blog/micro_blog_test.py @@ -8,38 +8,50 @@ class MicroBlogTest(unittest.TestCase): - def test_some1(self): + def test_english_language_short(self): + self.assertEqual(truncate("Hi"), "Hi") - def test_some2(self): + def test_english_language_long(self): + self.assertEqual(truncate("Hello there"), "Hello") - def test_some3(self): + def test_german_language_short_broth(self): + self.assertEqual(truncate("brΓΌhe"), "brΓΌhe") - def test_some4(self): + def test_german_language_long(self): + self.assertEqual(truncate("BΓ€rteppich"), "BΓ€rte") - def test_some5(self): + def test_bulgarian_language_short_good(self): + self.assertEqual(truncate("Π”ΠΎΠ±ΡŠΡ€"), "Π”ΠΎΠ±ΡŠΡ€") - def test_some6(self): + def test_greek_language_short_health(self): + self.assertEqual(truncate("υγΡιά"), "υγΡιά") - def test_some7(self): + def test_maths_short(self): + self.assertEqual(truncate("a=Ο€rΒ²"), "a=Ο€rΒ²") - def test_some8(self): + def test_maths_long(self): + self.assertEqual(truncate("βˆ…βŠŠβ„•βŠŠβ„€βŠŠβ„šβŠŠβ„βŠŠβ„‚"), "βˆ…βŠŠβ„•βŠŠβ„€") - def test_some9(self): + def test_english_and_emoji_short(self): + self.assertEqual(truncate("Fly πŸ›«"), "Fly πŸ›«") - def test_some10(self): + def test_emoji_short(self): + self.assertEqual(truncate("πŸ’‡"), "πŸ’‡") - def test_some11(self): + def test_emoji_long(self): + self.assertEqual(truncate("β„πŸŒ‘πŸ€§πŸ€’πŸ₯πŸ•°πŸ˜€"), "β„πŸŒ‘πŸ€§πŸ€’πŸ₯") - def test_some12(self): + def test_royal_flush(self): + self.assertEqual(truncate("πŸƒŽπŸ‚ΈπŸƒ…πŸƒ‹πŸƒπŸƒπŸƒŠ"), "πŸƒŽπŸ‚ΈπŸƒ…πŸƒ‹πŸƒ") From 2176d0d82b3464c4627f8de3ed5a9f960d4ce1b1 Mon Sep 17 00:00:00 2001 From: Meatball Date: Mon, 5 Dec 2022 16:14:36 +0100 Subject: [PATCH 3/3] fix --- config.json | 1 - 1 file changed, 1 deletion(-) diff --git a/config.json b/config.json index c907eeb75e..aeaba2223b 100644 --- a/config.json +++ b/config.json @@ -753,7 +753,6 @@ ], "difficulty": 2 }, - { "slug": "phone-number", "name": "Phone Number",