diff --git a/cpp/hello-world/CMakeLists.txt b/cpp/hello-world/CMakeLists.txt new file mode 100644 index 0000000..97b347f --- /dev/null +++ b/cpp/hello-world/CMakeLists.txt @@ -0,0 +1,52 @@ +# Get the exercise name from the current directory +get_filename_component(exercise ${CMAKE_CURRENT_SOURCE_DIR} NAME) + +# Basic CMake project +cmake_minimum_required(VERSION 2.8.11) + +# Name the project after the exercise +project(${exercise} CXX) + +# Locate Boost libraries: unit_test_framework, date_time and regex +set(Boost_USE_STATIC_LIBS ON) +set(Boost_USE_MULTITHREADED ON) +set(Boost_USE_STATIC_RUNTIME OFF) +find_package(Boost 1.59 REQUIRED COMPONENTS unit_test_framework date_time regex) + +# Enable C++11 features on gcc/clang +if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(GNU|Clang)") + set(CMAKE_CXX_FLAGS "-std=c++11") +endif() + +# Configure to run all the tests? +if(${EXERCISM_RUN_ALL_TESTS}) + add_definitions(-DEXERCISM_RUN_ALL_TESTS) +endif() + +# Get a source filename from the exercise name by replacing -'s with _'s +string(REPLACE "-" "_" file ${exercise}) + +# Implementation could be only a header +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${file}.cpp) + set(exercise_cpp ${file}.cpp) +else() + set(exercise_cpp "") +endif() + +# Build executable from sources and headers +add_executable(${exercise} ${file}_test.cpp ${exercise_cpp} ${file}.h) + +# We need boost includes +target_include_directories(${exercise} PRIVATE ${Boost_INCLUDE_DIRS}) + +# We need boost libraries +target_link_libraries(${exercise} ${Boost_LIBRARIES}) + +# Tell MSVC not to warn us about unchecked iterators in debug builds +if(${MSVC}) + set_target_properties(${exercise} PROPERTIES + COMPILE_DEFINITIONS_DEBUG _SCL_SECURE_NO_WARNINGS) +endif() + +# Run the tests on every build +add_custom_command(TARGET ${exercise} POST_BUILD COMMAND ${exercise}) diff --git a/cpp/hello-world/README.md b/cpp/hello-world/README.md new file mode 100644 index 0000000..e9f9f99 --- /dev/null +++ b/cpp/hello-world/README.md @@ -0,0 +1,53 @@ +# Hello World + +The classical introductory exercise. Just say "Hello, World!". + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is +the traditional first program for beginning programming in a new language +or environment. + +The objectives are simple: + +- Write a function that returns 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. + +## Getting Started + +Make sure you have read [the C++ page](http://exercism.io/languages/cpp) on +exercism.io. This covers the basic information on setting up the development +environment expected by the exercises. + +## Passing the Tests + +Get the first test compiling, linking and passing by following the [three +rules of test-driven development](http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd). +Create just enough structure by declaring namespaces, functions, classes, +etc., to satisfy any compiler errors and get the test to fail. Then write +just enough code to get the test to pass. Once you've done that, +uncomment the next test by moving the following line past the next test. + +```C++ +#if defined(EXERCISM_RUN_ALL_TESTS) +``` + +This may result in compile errors as new constructs may be invoked that +you haven't yet declared or defined. Again, fix the compile errors minimally +to get a failing test, then change the code minimally to pass the test, +refactor your implementation for readability and expressiveness and then +go on to the next test. + +Try to use standard C++11 facilities in preference to writing your own +low-level algorithms or facilities by hand. [CppReference](http://en.cppreference.com/) +is a wiki reference to the C++ language and standard library. If you +are new to C++, but have programmed in C, beware of +[C traps and pitfalls](http://www.slideshare.net/LegalizeAdulthood/c-traps-and-pitfalls-for-c-programmers). + +## Source + +This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/cpp/hello-world/hello_world.h b/cpp/hello-world/hello_world.h new file mode 100644 index 0000000..6682921 --- /dev/null +++ b/cpp/hello-world/hello_world.h @@ -0,0 +1,12 @@ +#if !defined(HELLO_WORLD_H) +#define HELLO_WORLD_H + +#include + +namespace hello_world { + +std::string hello(); + +} + +#endif diff --git a/cpp/hello-world/hello_world_test.cpp b/cpp/hello-world/hello_world_test.cpp new file mode 100644 index 0000000..3e485bf --- /dev/null +++ b/cpp/hello-world/hello_world_test.cpp @@ -0,0 +1,8 @@ +#include "hello_world.h" +#define BOOST_TEST_MAIN +#include + +BOOST_AUTO_TEST_CASE(test_hello) +{ + BOOST_REQUIRE_EQUAL("Hello, World!", hello_world::hello()); +} diff --git a/crystal/hello-world/spec/hello_world_spec.cr b/crystal/hello-world/spec/hello_world_spec.cr new file mode 100644 index 0000000..2eb8c83 --- /dev/null +++ b/crystal/hello-world/spec/hello_world_spec.cr @@ -0,0 +1,16 @@ +require "spec" +require "../src/*" + +describe "HelloWorld" do + it "no name" do + HelloWorld.hello.should eq("Hello, World!") + end + + pending "sample name" do + HelloWorld.hello("Alice").should eq("Hello, Alice!") + end + + pending "other sample name" do + HelloWorld.hello("Bob").should eq("Hello, Bob!") + end +end diff --git a/crystal/hello-world/src/hello_world.cr b/crystal/hello-world/src/hello_world.cr new file mode 100644 index 0000000..4d25259 --- /dev/null +++ b/crystal/hello-world/src/hello_world.cr @@ -0,0 +1 @@ +# Please implement your solution to hello-world in this file diff --git a/csharp/sum-of-multiples/README.md b/csharp/sum-of-multiples/README.md new file mode 100644 index 0000000..68f9fdf --- /dev/null +++ b/csharp/sum-of-multiples/README.md @@ -0,0 +1,28 @@ +# Sum Of Multiples + +Given a number, find the sum of all the multiples of particular numbers up to +but not including that number. + +If we list all the natural numbers up to but not including 20 that are +multiples of either 3 or 5, we get 3, 5, 6 and 9, 10, 12, 15, and 18. + +The sum of these multiples is 78. + +Given a number, find the sum of the multiples of a given set of numbers, +up to but not including that number. + +## Hints +This exercise requires you to process a collection of data. You can simplify your code by using LINQ (Language Integrated Query). +For more information, see [this page](https://docs.microsoft.com/en-us/dotnet/articles/standard/using-linq). + +### Submitting Exercises + +Note that, when trying to submit an exercise, make sure the exercise file that you're submitting is in the `exercism/csharp/` directory. + +For example, if you're submitting `bob.cs` for the Bob exercise, the submit command would be something like `exercism submit /csharp/bob/bob.cs`. +## Source + +A variation on Problem 1 at Project Euler [http://projecteuler.net/problem=1](http://projecteuler.net/problem=1) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/csharp/sum-of-multiples/SumOfMultiples.cs b/csharp/sum-of-multiples/SumOfMultiples.cs new file mode 100644 index 0000000..789fc36 --- /dev/null +++ b/csharp/sum-of-multiples/SumOfMultiples.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +public static class SumOfMultiples +{ + public static int To(IEnumerable multiples, int max) + { + throw new NotImplementedException("You need to implement this function."); + } +} \ No newline at end of file diff --git a/csharp/sum-of-multiples/SumOfMultiples.csproj b/csharp/sum-of-multiples/SumOfMultiples.csproj new file mode 100644 index 0000000..51531ed --- /dev/null +++ b/csharp/sum-of-multiples/SumOfMultiples.csproj @@ -0,0 +1,18 @@ + + + + Exe + netcoreapp1.0 + + + + + + + + + + + + + diff --git a/csharp/sum-of-multiples/SumOfMultiplesTest.cs b/csharp/sum-of-multiples/SumOfMultiplesTest.cs new file mode 100644 index 0000000..cb6c31f --- /dev/null +++ b/csharp/sum-of-multiples/SumOfMultiplesTest.cs @@ -0,0 +1,46 @@ +using Xunit; + +public class SumOfMultiplesTest +{ + [Fact] + public void Sum_to_1() + { + Assert.Equal(0, SumOfMultiples.To(new[] { 3, 5 }, 1)); + } + + [Fact(Skip = "Remove to run test")] + public void Sum_to_3() + { + Assert.Equal(3, SumOfMultiples.To(new[] { 3, 5 }, 4)); + } + + [Fact(Skip = "Remove to run test")] + public void Sum_to_10() + { + Assert.Equal(23, SumOfMultiples.To(new[] { 3, 5 }, 10)); + } + + [Fact(Skip = "Remove to run test")] + public void Sum_to_100() + { + Assert.Equal(2318, SumOfMultiples.To(new[] { 3, 5 }, 100)); + } + + [Fact(Skip = "Remove to run test")] + public void Sum_to_1000() + { + Assert.Equal(233168, SumOfMultiples.To(new[] { 3, 5 }, 1000)); + } + + [Fact(Skip = "Remove to run test")] + public void Sum_to_20() + { + Assert.Equal(51, SumOfMultiples.To(new [] { 7, 13, 17 }, 20)); + } + + [Fact(Skip = "Remove to run test")] + public void Sum_to_10000() + { + Assert.Equal(2203160, SumOfMultiples.To(new [] { 43, 47 }, 10000)); + } +} diff --git a/elm/hello-world/package.json b/elm/hello-world/package.json new file mode 100644 index 0000000..31d6fb3 --- /dev/null +++ b/elm/hello-world/package.json @@ -0,0 +1,14 @@ +{ + "description": "Exercism/Elm", + "repository": "https://github.com/exercism/elm.git", + "license": "MIT", + "scripts": { + "postinstall": "elm-package install -y", + "watch": "elm-test --watch", + "test": "elm-test" + }, + "dependencies": { + "elm": "0.18.0", + "elm-test": "0.18.3" + } +} diff --git a/elm/hello-world/tests/Tests.elm b/elm/hello-world/tests/Tests.elm new file mode 100644 index 0000000..6e6ef2f --- /dev/null +++ b/elm/hello-world/tests/Tests.elm @@ -0,0 +1,26 @@ +module Tests exposing (..) + +import Test exposing (..) +import Expect +import HelloWorld exposing (helloWorld) + + +tests : Test +tests = + describe "Hello, World!" + [ test "Hello with no name" <| + \() -> + Expect.equal "Hello, World!" (helloWorld Nothing) + + -- Once you get the first test passing, remove the + -- `skip <|` (just leave the comma) on the next two + -- lines to continue! + , skip <| + test "Hello to a sample name" <| + \() -> + Expect.equal "Hello, Alice!" (helloWorld (Just "Alice")) + , skip <| + test "Hello to another sample name" <| + \() -> + Expect.equal "Hello, Bob!" (helloWorld (Just "Bob")) + ] diff --git a/elm/hello-world/tests/elm-package.json b/elm/hello-world/tests/elm-package.json new file mode 100644 index 0000000..3e92515 --- /dev/null +++ b/elm/hello-world/tests/elm-package.json @@ -0,0 +1,16 @@ +{ + "version": "3.0.0", + "summary": "Exercism problems in Elm.", + "repository": "https://github.com/exercism/elm.git", + "license": "BSD3", + "source-directories": [ + ".", + ".." + ], + "exposed-modules": [], + "dependencies": { + "elm-lang/core": "5.0.0 <= v < 6.0.0", + "elm-community/elm-test": "4.0.0 <= v < 5.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/erlang/hello-world/include/exercism.hrl b/erlang/hello-world/include/exercism.hrl new file mode 100644 index 0000000..cc152d9 --- /dev/null +++ b/erlang/hello-world/include/exercism.hrl @@ -0,0 +1,11 @@ +-include_lib("eunit/include/eunit.hrl"). + +sut(Module) -> + {ok, Files} = file:list_dir("./src"), + case lists:member("example.erl", Files) of + true -> example; + false -> Module + end. + +version_test() -> + ?assertMatch(?TEST_VERSION, ?TESTED_MODULE:test_version()). diff --git a/erlang/hello-world/rebar.config b/erlang/hello-world/rebar.config new file mode 100644 index 0000000..360f3d1 --- /dev/null +++ b/erlang/hello-world/rebar.config @@ -0,0 +1,30 @@ +%% Erlang compiler options +{erl_opts, [debug_info]}. + +{deps, []}. + +{dialyzer, [ + {warnings, [underspecs, no_return]}, + {get_warnings, true}, + {plt_apps, top_level_deps}, % top_level_deps | all_deps + {plt_extra_apps, []}, + {plt_location, local}, % local | "/my/file/name" + {plt_prefix, "rebar3"}, + {base_plt_apps, [stdlib, kernel, crypto]}, + {base_plt_location, global}, % global | "/my/file/name" + {base_plt_prefix, "rebar3"} +]}. + +%% eunit:test(Tests) +{eunit_tests, []}. +%% Options for eunit:test(Tests, Opts) +{eunit_opts, [verbose]}. + +%% == xref == + +{xref_warnings, true}. + +%% xref checks to run +{xref_checks, [undefined_function_calls, undefined_functions, + locals_not_used, exports_not_used, + deprecated_function_calls, deprecated_functions]}. diff --git a/erlang/hello-world/src/hello_world.app.src b/erlang/hello-world/src/hello_world.app.src new file mode 100644 index 0000000..7da03b1 --- /dev/null +++ b/erlang/hello-world/src/hello_world.app.src @@ -0,0 +1,9 @@ +{application, hello_world, + [{description, "exercism.io - hello-world"}, + {vsn, "0.0.1"}, + {modules, []}, + {registered, []}, + {applications, [kernel, + stdlib]}, + {env, []} + ]}. diff --git a/erlang/hello-world/src/hello_world.erl b/erlang/hello-world/src/hello_world.erl new file mode 100644 index 0000000..8e450ab --- /dev/null +++ b/erlang/hello-world/src/hello_world.erl @@ -0,0 +1,8 @@ +-module(hello_world). + +-export([hello/0, test_version/0]). + +hello() -> + undefined. + +test_version() -> 2. diff --git a/erlang/hello-world/test/hello_world_tests.erl b/erlang/hello-world/test/hello_world_tests.erl new file mode 100644 index 0000000..ca9f518 --- /dev/null +++ b/erlang/hello-world/test/hello_world_tests.erl @@ -0,0 +1,9 @@ +-module(hello_world_tests). + +-define(TESTED_MODULE, (sut(hello_world))). +-define(TEST_VERSION, 2). +-include("exercism.hrl"). + + +say_hi_test() -> + ?assertEqual("Hello, World!", ?TESTED_MODULE:hello()). diff --git a/go/pov/README.md b/go/pov/README.md new file mode 100644 index 0000000..09b46c2 --- /dev/null +++ b/go/pov/README.md @@ -0,0 +1,64 @@ +# Pov + +Reparent a graph on a selected node. + +# Tree Reparenting + +This exercise is all about re-orientating a graph to see things from a different +point of view. For example family trees are usually presented from the +ancestor's perspective: + +``` + +------0------+ + | | | + +-1-+ +-2-+ +-3-+ + | | | | | | + 4 5 6 7 8 9 +``` + +But the same information can be presented from the perspective of any other node +in the graph, by pulling it up to the root and dragging its relationships along +with it. So the same graph from 6's perspective would look like: + +``` + 6 + | + +-----2-----+ + | | + 7 +-----0-----+ + | | + +-1-+ +-3-+ + | | | | + 4 5 8 9 +``` + +This lets us more simply describe the paths between two nodes. So for example +the path from 6-9 (which in the first graph goes up to the root and then down to +a different leaf node) can be seen to follow the path 6-2-0-3-9 + +This exercise involves taking an input graph and re-orientating it from the point +of view of one of the nodes. + +## Running the tests + +To run the tests run the command `go test` from within the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +Keep in mind that each reviewer will run benchmarks on a different machine, with +different specs, so the results from these benchmark tests may vary. + +## Further information + +For more detailed information about the Go track, including how to get help if +you're having trouble, please visit the exercism.io [Go language page](http://exercism.io/languages/go/about). + +## Source + +Adaptation of exercise from 4clojure [https://www.4clojure.com/](https://www.4clojure.com/) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/go/pov/pov_test.go b/go/pov/pov_test.go new file mode 100644 index 0000000..6d7872d --- /dev/null +++ b/go/pov/pov_test.go @@ -0,0 +1,298 @@ +package pov + +import ( + "reflect" + "sort" + "testing" +) + +const targetTestVersion = 2 + +// POV / reparent / change root of a tree +// +// API: +// type Graph +// func New() *Graph +// func (*Graph) AddNode(nodeLabel string) +// func (*Graph) AddArc(from, to string) +// func (*Graph) ArcList() []string +// func (*Graph) ChangeRoot(oldRoot, newRoot string) *Graph +// +// The type name is Graph because you'll probably be implementing a general +// directed graph representation, although the test program will only use +// it to create a tree. The term "arc" is used here to mean a directed edge. +// +// The test program will create a graph with New, then use AddNode to add +// leaf nodes. After that it will use AddArc to construct the rest of the tree +// from the bottom up. That is, the `to` argument will aways specify a node +// that has already been added. +// +// ArcList is a dump method to let the test program see your graph. It must +// return a list of all arcs in the graph. Format each arc as a single string +// like "from -> to". The test program can then easily sort the list and +// compare it to an expected result. You do not need to bother with sorting +// the list yourself. +// +// All this graph construction and dumping must be working before you start +// on the interesting part of the exercise, so it is tested separately as +// a first test. +// +// API function ChangeRoot does the interesting part of the exercise. +// OldRoot is passed (as a convenience) and you must return a graph with +// newRoot as the root. You can modify the original graph in place and +// return it or create a new graph and return that. If you return a new +// graph you are free to consume or destroy the original graph. Of course +// it's nice to leave it unmodified. + +type arc struct{ fr, to string } + +type testCase struct { + description string + leaves []string + arcPairs []arc + root string + arcStrings []string + reRooted []string +} + +var testCases = []testCase{ + { + description: "singleton", + leaves: []string{"x"}, + arcPairs: nil, + root: "x", + arcStrings: nil, + reRooted: nil, + }, + { + description: "simple tree", + leaves: []string{"sibling", "x"}, + arcPairs: []arc{ + {"parent", "sibling"}, + {"parent", "x"}, + }, + root: "parent", + arcStrings: []string{ + "parent -> sibling", + "parent -> x", + }, + reRooted: []string{ + "parent -> sibling", + "x -> parent", + }, + }, + { + description: "large flat", + leaves: []string{"sib-a", "sib-b", "x", "sib-c", "sib-d"}, + arcPairs: []arc{ + {"parent", "sib-a"}, + {"parent", "sib-b"}, + {"parent", "x"}, + {"parent", "sib-c"}, + {"parent", "sib-d"}, + }, + root: "parent", + arcStrings: []string{ + "parent -> sib-a", + "parent -> sib-b", + "parent -> sib-c", + "parent -> sib-d", + "parent -> x", + }, + reRooted: []string{ + "parent -> sib-a", + "parent -> sib-b", + "parent -> sib-c", + "parent -> sib-d", + "x -> parent", + }, + }, + { + description: "deeply nested", + leaves: []string{"x"}, + arcPairs: []arc{ + {"level-4", "x"}, + {"level-3", "level-4"}, + {"level-2", "level-3"}, + {"level-1", "level-2"}, + {"level-0", "level-1"}, + }, + root: "level-0", + arcStrings: []string{ + "level-0 -> level-1", + "level-1 -> level-2", + "level-2 -> level-3", + "level-3 -> level-4", + "level-4 -> x", + }, + reRooted: []string{ + "level-1 -> level-0", + "level-2 -> level-1", + "level-3 -> level-2", + "level-4 -> level-3", + "x -> level-4", + }, + }, + { + description: "cousins", + leaves: []string{"sib-1", "x", "sib-2", "cousin-1", "cousin-2"}, + arcPairs: []arc{ + {"parent", "sib-1"}, + {"parent", "x"}, + {"parent", "sib-2"}, + {"aunt", "cousin-1"}, + {"aunt", "cousin-2"}, + {"grand-parent", "parent"}, + {"grand-parent", "aunt"}, + }, + root: "grand-parent", + arcStrings: []string{ + "aunt -> cousin-1", + "aunt -> cousin-2", + "grand-parent -> aunt", + "grand-parent -> parent", + "parent -> sib-1", + "parent -> sib-2", + "parent -> x", + }, + reRooted: []string{ + "aunt -> cousin-1", + "aunt -> cousin-2", + "grand-parent -> aunt", + "parent -> grand-parent", + "parent -> sib-1", + "parent -> sib-2", + "x -> parent", + }, + }, + { + description: "target with children", + leaves: []string{"child-1", "child-2", "nephew", "niece", + "2nd-cousin-1", "2nd-cousin-2", "2nd-cousin-3", "2nd-cousin-4"}, + arcPairs: []arc{ + {"x", "child-1"}, + {"x", "child-2"}, + {"sibling", "nephew"}, + {"sibling", "niece"}, + {"cousin-1", "2nd-cousin-1"}, + {"cousin-1", "2nd-cousin-2"}, + {"cousin-2", "2nd-cousin-3"}, + {"cousin-2", "2nd-cousin-4"}, + {"parent", "x"}, + {"parent", "sibling"}, + {"aunt", "cousin-1"}, + {"aunt", "cousin-2"}, + {"grand-parent", "parent"}, + {"grand-parent", "aunt"}, + }, + root: "grand-parent", + arcStrings: []string{ + "aunt -> cousin-1", + "aunt -> cousin-2", + "cousin-1 -> 2nd-cousin-1", + "cousin-1 -> 2nd-cousin-2", + "cousin-2 -> 2nd-cousin-3", + "cousin-2 -> 2nd-cousin-4", + "grand-parent -> aunt", + "grand-parent -> parent", + "parent -> sibling", + "parent -> x", + "sibling -> nephew", + "sibling -> niece", + "x -> child-1", + "x -> child-2", + }, + reRooted: []string{ + "aunt -> cousin-1", + "aunt -> cousin-2", + "cousin-1 -> 2nd-cousin-1", + "cousin-1 -> 2nd-cousin-2", + "cousin-2 -> 2nd-cousin-3", + "cousin-2 -> 2nd-cousin-4", + "grand-parent -> aunt", + "parent -> grand-parent", + "parent -> sibling", + "sibling -> nephew", + "sibling -> niece", + "x -> child-1", + "x -> child-2", + "x -> parent", + }, + }, +} + +func (tc testCase) graph() *Graph { + g := New() + for _, l := range tc.leaves { + g.AddNode(l) + } + for _, a := range tc.arcPairs { + g.AddArc(a.fr, a.to) + } + return g +} + +func (tc testCase) testResult(got, want []string, msg string, t *testing.T) { + if len(got)+len(want) == 0 { + return + } + gs := append([]string{}, got...) + sort.Strings(gs) + if reflect.DeepEqual(gs, want) { + return + } + // test has failed + t.Log(tc.description, "test case") + t.Log(msg) + t.Logf("got %d arcs:", len(got)) + for _, s := range got { + t.Log(" ", s) + } + t.Logf("that result sorted:") + for _, s := range gs { + t.Log(" ", s) + } + t.Logf("want %d arcs:", len(want)) + for _, s := range want { + t.Log(" ", s) + } + t.FailNow() +} + +func TestTestVersion(t *testing.T) { + if testVersion != targetTestVersion { + t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion) + } +} + +func TestConstruction(t *testing.T) { + for _, tc := range testCases { + got := tc.graph().ArcList() + want := tc.arcStrings + tc.testResult(got, want, "incorrect graph construction", t) + } +} + +func TestChangeRoot(t *testing.T) { + for _, tc := range testCases { + got := tc.graph().ChangeRoot(tc.root, "x").ArcList() + want := tc.reRooted + tc.testResult(got, want, "incorrect root change", t) + } +} + +func BenchmarkConstructOnlyNoChange(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, tc := range testCases { + tc.graph() + } + } +} + +func BenchmarkConstructAndChangeRoot(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, tc := range testCases { + tc.graph().ChangeRoot(tc.root, "x") + } + } +} diff --git a/go/transpose/README.md b/go/transpose/README.md new file mode 100644 index 0000000..c30d6d4 --- /dev/null +++ b/go/transpose/README.md @@ -0,0 +1,83 @@ +# Transpose + +Given an input text output it transposed. + +Roughly explained, the transpose of a matrix: + +``` +ABC +DEF +``` + +is given by: + +``` +AD +BE +CF +``` + +Rows become columns and columns become rows. See . + +If the input has rows of different lengths, this is to be solved as follows: + +- Pad to the left with spaces. +- Don't pad to the right. + +Therefore, transposing this matrix: + +``` +ABC +DE +``` + +results in: + +``` +AD +BE +C +``` + +And transposing: + +``` +AB +DEF +``` + +results in: + +``` +AD +BE + F +``` + +In general, all characters from the input should also be present in the transposed output. +That means that if a column in the input text contains only spaces on its bottom-most row(s), +the corresponding output row should contain the spaces in its right-most column(s). + +## Running the tests + +To run the tests run the command `go test` from within the exercise directory. + +If the test suite contains benchmarks, you can run these with the `-bench` +flag: + + go test -bench . + +Keep in mind that each reviewer will run benchmarks on a different machine, with +different specs, so the results from these benchmark tests may vary. + +## Further information + +For more detailed information about the Go track, including how to get help if +you're having trouble, please visit the exercism.io [Go language page](http://exercism.io/languages/go/about). + +## Source + +Reddit r/dailyprogrammer challenge #270 [Easy]. [https://www.reddit.com/r/dailyprogrammer/comments/4msu2x/challenge_270_easy_transpose_the_input_text](https://www.reddit.com/r/dailyprogrammer/comments/4msu2x/challenge_270_easy_transpose_the_input_text) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/go/transpose/cases_test.go b/go/transpose/cases_test.go new file mode 100644 index 0000000..aaf1dac --- /dev/null +++ b/go/transpose/cases_test.go @@ -0,0 +1,248 @@ +package transpose + +// Source: exercism/x-common +// Commit: 6dba022 transpose: Fix canonical-data.json formatting +// x-common version: 1.0.0 + +var testCases = []struct { + description string + input []string + expected []string +}{ + { + "empty string", + []string{}, + []string{}, + }, + { + "two characters in a row", + []string{ + "A1", + }, + []string{ + "A", + "1", + }, + }, + { + "two characters in a column", + []string{ + "A", + "1", + }, + []string{ + "A1", + }, + }, + { + "simple", + []string{ + "ABC", + "123", + }, + []string{ + "A1", + "B2", + "C3", + }, + }, + { + "single line", + []string{ + "Single line.", + }, + []string{ + "S", + "i", + "n", + "g", + "l", + "e", + " ", + "l", + "i", + "n", + "e", + ".", + }, + }, + { + "first line longer than second line", + []string{ + "The fourth line.", + "The fifth line.", + }, + []string{ + "TT", + "hh", + "ee", + " ", + "ff", + "oi", + "uf", + "rt", + "th", + "h ", + " l", + "li", + "in", + "ne", + "e.", + ".", + }, + }, + { + "second line longer than first line", + []string{ + "The first line.", + "The second line.", + }, + []string{ + "TT", + "hh", + "ee", + " ", + "fs", + "ie", + "rc", + "so", + "tn", + " d", + "l ", + "il", + "ni", + "en", + ".e", + " .", + }, + }, + { + "square", + []string{ + "HEART", + "EMBER", + "ABUSE", + "RESIN", + "TREND", + }, + []string{ + "HEART", + "EMBER", + "ABUSE", + "RESIN", + "TREND", + }, + }, + { + "rectangle", + []string{ + "FRACTURE", + "OUTLINED", + "BLOOMING", + "SEPTETTE", + }, + []string{ + "FOBS", + "RULE", + "ATOP", + "CLOT", + "TIME", + "UNIT", + "RENT", + "EDGE", + }, + }, + { + "triangle", + []string{ + "T", + "EE", + "AAA", + "SSSS", + "EEEEE", + "RRRRRR", + }, + []string{ + "TEASER", + " EASER", + " ASER", + " SER", + " ER", + " R", + }, + }, + { + "many lines", + []string{ + "Chor. Two households, both alike in dignity,", + "In fair Verona, where we lay our scene,", + "From ancient grudge break to new mutiny,", + "Where civil blood makes civil hands unclean.", + "From forth the fatal loins of these two foes", + "A pair of star-cross'd lovers take their life;", + "Whose misadventur'd piteous overthrows", + "Doth with their death bury their parents' strife.", + "The fearful passage of their death-mark'd love,", + "And the continuance of their parents' rage,", + "Which, but their children's end, naught could remove,", + "Is now the two hours' traffic of our stage;", + "The which if you with patient ears attend,", + "What here shall miss, our toil shall strive to mend.", + }, + []string{ + "CIFWFAWDTAWITW", + "hnrhr hohnhshh", + "o oeopotedi ea", + "rfmrmash cn t", + ".a e ie fthow ", + " ia fr weh,whh", + "Trnco miae ie", + "w ciroitr btcr", + "oVivtfshfcuhhe", + " eeih a uote ", + "hrnl sdtln is", + "oot ttvh tttfh", + "un bhaeepihw a", + "saglernianeoyl", + "e,ro -trsui ol", + "h uofcu sarhu ", + "owddarrdan o m", + "lhg to'egccuwi", + "deemasdaeehris", + "sr als t ists", + ",ebk 'phool'h,", + " reldi ffd ", + "bweso tb rtpo", + "oea ileutterau", + "t kcnoorhhnatr", + "hl isvuyee'fi ", + " atv es iisfet", + "ayoior trr ino", + "l lfsoh ecti", + "ion vedpn l", + "kuehtteieadoe ", + "erwaharrar,fas", + " nekt te rh", + "ismdsehphnnosa", + "ncuse ra-tau l", + " et tormsural", + "dniuthwea'g t ", + "iennwesnr hsts", + "g,ycoi tkrttet", + "n ,l r s'a anr", + "i ef 'dgcgdi", + "t aol eoe,v", + "y nei sl,u; e", + ", .sf to l ", + " e rv d t", + " ; ie o", + " f, r ", + " e e m", + " . m e", + " o n", + " v d", + " e .", + " ,", + }, + }, +} diff --git a/go/transpose/transpose.go b/go/transpose/transpose.go new file mode 100644 index 0000000..fff9db8 --- /dev/null +++ b/go/transpose/transpose.go @@ -0,0 +1,32 @@ +package transpose + +import ( + "strings" +) + +const testVersion = 1 + +func Transpose(inp []string) []string { + // find the longest length string in the slice + lng := 0 + for i := range inp { + if len(inp[i]) > lng { + lng = len(inp[i]) + } + } + ret := make([]string, lng, lng) + for i := range inp { + for j := 0; j < lng; j++ { + if len(inp[i]) > j { + ret[j] = ret[j] + string(inp[i][j]) + } else { + ret[j] = ret[j] + " " + } + } + } + if len(ret) > 0 { + // Trim the spaces off of the end of the last line + ret[len(ret)-1] = strings.TrimRight(ret[len(ret)-1], " ") + } + return ret +} diff --git a/go/transpose/transpose_test.go b/go/transpose/transpose_test.go new file mode 100644 index 0000000..907c715 --- /dev/null +++ b/go/transpose/transpose_test.go @@ -0,0 +1,52 @@ +package transpose + +import ( + "reflect" + "testing" +) + +const targetTestVersion = 1 + +func TestTestVersion(t *testing.T) { + if testVersion != targetTestVersion { + t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion) + } +} + +func TestTranspose(t *testing.T) { + for _, test := range testCases { + actual := Transpose(test.input) + if !reflect.DeepEqual(actual, test.expected) { + // check for zero length slices + if len(actual) == 0 || len(test.expected) == 0 { + t.Fatalf("\n\tTranspose(%q): %s\n\n\tExpected: %q\n\tGot: %q", + test.input, test.description, test.expected, actual) + } + // let's make the error more specific and find the row it's on + min := min(len(test.expected), len(actual)) + for i := 0; i < min; i++ { + if test.expected[i] != actual[i] { + t.Fatalf("\n\tTranspose(%q): %s\n\n\tExpected: %q\n\tGot: %q\n\n\tRow %d Expected: %q Got: %q", + test.input, test.description, test.expected, actual, i, test.expected[i], actual[i]) + } + } + } + } +} + +// helper function +// https://stackoverflow.com/questions/27516387/what-is-the-correct-way-to-find-the-min-between-two-integers-in-go +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func BenchmarkTranspose(b *testing.B) { + for _, test := range testCases { + for i := 0; i < b.N; i++ { + Transpose(test.input) + } + } +} diff --git a/haskell/hello-world/README.md b/haskell/hello-world/README.md new file mode 100644 index 0000000..6909507 --- /dev/null +++ b/haskell/hello-world/README.md @@ -0,0 +1,83 @@ +# Hello World + +The classical introductory exercise. Just say "Hello, World!". + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is +the traditional first program for beginning programming in a new language +or environment. + +The objectives are simple: + +- Write a function that returns 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. + +## Hints + +To complete this exercise, you need to implement the `hello` function. + +You will find the type signature for `hello` already in place, +but it is up to you to define the function. + + + +## Getting Started + +For installation and learning resources, refer to the +[exercism help page](http://exercism.io/languages/haskell). + +## Running the tests + +To run the test suite, execute the following command: + +```bash +stack test +``` + +#### If you get an error message like this... + +``` +No .cabal file found in directory +``` + +You are probably running an old stack version and need +to upgrade it. + +#### Otherwise, if you get an error message like this... + +``` +No compiler found, expected minor version match with... +Try running "stack setup" to install the correct GHC... +``` + +Just do as it says and it will download and install +the correct compiler version: + +```bash +stack setup +``` + +## Running *GHCi* + +If you want to play with your solution in GHCi, just run the command: + +```bash +stack ghci +``` + +## Feedback, Issues, Pull Requests + +The [exercism/haskell](https://github.com/exercism/haskell) repository on +GitHub is the home for all of the Haskell exercises. + +If you have feedback about an exercise, or want to help implementing a new +one, head over there and create an issue. We'll do our best to help you! + +## Source + +This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/haskell/hello-world/package.yaml b/haskell/hello-world/package.yaml new file mode 100644 index 0000000..cb71b1a --- /dev/null +++ b/haskell/hello-world/package.yaml @@ -0,0 +1,20 @@ +name: hello-world +version: 1.0.0.3 + +dependencies: + - base + +library: + exposed-modules: HelloWorld + source-dirs: src + dependencies: + # - foo # List here the packages you + # - bar # want to use in your solution. + +tests: + test: + main: Tests.hs + source-dirs: test + dependencies: + - hello-world + - hspec diff --git a/haskell/hello-world/src/HelloWorld.hs b/haskell/hello-world/src/HelloWorld.hs new file mode 100644 index 0000000..c574247 --- /dev/null +++ b/haskell/hello-world/src/HelloWorld.hs @@ -0,0 +1,4 @@ +module HelloWorld (hello) where + +hello :: String +hello = error "You need to implement this function." diff --git a/haskell/hello-world/stack.yaml b/haskell/hello-world/stack.yaml new file mode 100644 index 0000000..10da6ea --- /dev/null +++ b/haskell/hello-world/stack.yaml @@ -0,0 +1 @@ +resolver: lts-8.21 diff --git a/haskell/hello-world/test/Tests.hs b/haskell/hello-world/test/Tests.hs new file mode 100644 index 0000000..531f54d --- /dev/null +++ b/haskell/hello-world/test/Tests.hs @@ -0,0 +1,11 @@ +import Test.Hspec (Spec, it, shouldBe) +import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith) + +import HelloWorld (hello) + +main :: IO () +main = hspecWith defaultConfig {configFastFail = True} specs + +specs :: Spec +specs = it "hello" $ + hello `shouldBe` "Hello, World!" diff --git a/java/two-fer/README.md b/java/two-fer/README.md new file mode 100644 index 0000000..ca6b410 --- /dev/null +++ b/java/two-fer/README.md @@ -0,0 +1,99 @@ +# Two Fer + +`Two-fer` or `2-fer` is short for two for one. One for you and one for me. + +``` +"One for X, one for me." +``` + +When X is a name or "you". + +If the given name is "Alice", the result should be "One for Alice, one for me." +If no name is given, the result should be "One for you, one for me." + + +## Test-Driven Development + +As programmers mature, they eventually want to test their code. + +Here at Exercism we simulate [Test-Driven +Development](http://en.wikipedia.org/wiki/Test-driven_development) (TDD), where +you write your tests before writing any functionality. The simulation comes in +the form of a pre-written test suite, which will signal that you have solved +the problem. + +It will also provide you with a safety net to explore other solutions without +breaking the functionality. + +### A typical TDD workflow on Exercism: + +1. Run the test file and pick one test that's failing. +2. Write some code to fix the test you picked. +3. Re-run the tests to confirm the test is now passing. +4. Repeat from step 1. +5. Submit your solution (`exercism submit /path/to/file`) + +## Instructions + +Submissions are encouraged to be general, within reason. Having said that, it's +also important not to over-engineer a solution. + +It's important to remember that the goal is to make code as expressive and +readable as we can. + +Most Java exercises include multiple test cases. These cases are structured to +support a useful process known as +[test-driven development (TDD)](https://en.wikipedia.org/wiki/Test-driven_development). +TDD involves repeating a structured cycle that helps programmers build complex +functionality piece by piece rather than all at once. That cycle can be +described as follows: + +1. Add a test that describes one piece of desired functionality your code is +currently missing. +2. Run the tests to verify that this newly-added test fails. +3. Update your existing code until: + - All the old tests continue to pass; + - The new test also passes. +4. [Clean up](https://en.wikipedia.org/wiki/Code_refactoring) your code, making +sure that all tests continue to pass. This typically involves renaming +variables, removing duplicated chunks of logic, removing leftover logging, etc. +5. Return to step 1 until all desired functionality has been built! + +The test files in this track contain _all_ the tests your solution should pass +to be considered valid. That doesn't immediately seem to be compatible with the +cycle described above, in which tests are written one by one. However, the +tool that we use to write our tests, [JUnit](http://junit.org), provides an +[@Ignore](http://junit.sourceforge.net/javadoc/org/junit/Ignore.html) +[annotation](https://docs.oracle.com/javase/tutorial/java/annotations/) that +can be used to temporarily skip an already-written test. Using this annotation, +we make sure that the test files we deliver to you satisfy the following rules: + +- The first test in any test file is _not_ skipped by default. +- All but the first test in any test file _are_ skipped by default. + +This allows you to simulate the TDD cycle by following these slightly-modified +steps: + +1. Run the tests to verify that _at most one_ test currently fails. +2. Update your existing code until all the non-skipped tests pass. +3. Clean up your code, making sure that all non-skipped tests continue to pass. +4. Remove the topmost `@Ignore` annotation in the test file. +5. Return to step 1 until no tests are skipped and all tests pass! + + + +To run the tests: + +```sh +$ gradle test +``` + +For more detailed info about the Java track see the [help page](http://exercism.io/languages/java). + + +## Source + +This is an exercise to introduce users to basic programming constructs, just after hello World. [https://en.wikipedia.org/wiki/Two-fer](https://en.wikipedia.org/wiki/Two-fer) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/java/two-fer/build.gradle b/java/two-fer/build.gradle new file mode 100644 index 0000000..d019b23 --- /dev/null +++ b/java/two-fer/build.gradle @@ -0,0 +1,17 @@ +apply plugin: "java" +apply plugin: "eclipse" +apply plugin: "idea" + +repositories { + mavenCentral() +} + +dependencies { + testCompile "junit:junit:4.12" +} +test { + testLogging { + exceptionFormat = 'full' + events = ["passed", "failed", "skipped"] + } +} diff --git a/java/two-fer/src/main/java/Twofer.java b/java/two-fer/src/main/java/Twofer.java new file mode 100644 index 0000000..eeedaed --- /dev/null +++ b/java/two-fer/src/main/java/Twofer.java @@ -0,0 +1,5 @@ +public class Twofer { + public String twofer(String name) { + throw new UnsupportedOperationException("Delete this statement and write your own implementation."); + } +} \ No newline at end of file diff --git a/java/two-fer/src/test/java/TwoferTest.java b/java/two-fer/src/test/java/TwoferTest.java new file mode 100644 index 0000000..cf56fea --- /dev/null +++ b/java/two-fer/src/test/java/TwoferTest.java @@ -0,0 +1,41 @@ +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class TwoferTest { + + private Twofer twofer; + + @Before + public void setup() { + twofer = new Twofer(); + } + + @Test + public void noNameGiven() { + String input = null; + String expected = "One for you, one for me."; + + assertEquals(expected, twofer.twofer(input)); + } + + @Ignore("Remove to run test") + @Test + public void aNameGiven() { + String input = "Alice"; + String expected = "One for Alice, one for me."; + + assertEquals(expected, twofer.twofer(input)); + } + + @Ignore("Remove to run test") + @Test + public void anotherNameGiven() { + String input = "Bob"; + String expected = "One for Bob, one for me."; + + assertEquals(expected, twofer.twofer(input)); + } +} diff --git a/kotlin/hello-world/GETTING_STARTED.md b/kotlin/hello-world/GETTING_STARTED.md new file mode 100644 index 0000000..06b4f55 --- /dev/null +++ b/kotlin/hello-world/GETTING_STARTED.md @@ -0,0 +1,50 @@ +---- +# Quick Start Guide + +This guide picks-up where [Running the Tests (in Kotlin)](http://exercism.io/languages/kotlin/tests) +left off. If you haven't reviewed those instructions, do so now. + +Need more information? A **step-by-step tutorial** is available in this directory at TUTORIAL.md or you can read +the [HTML version](https://github.com/exercism/kotlin/blob/master/exercises/hello-world/TUTORIAL.md). + +The following instructions work equally well on Windows, Mac OS X and Linux. + +## Solve "Hello World" + +Try writing a solution that passes one test at a time, running Gradle each time: + + +``` +$ gradle test +``` + +## Iterate through the tests + +After your first test passes, remove the `@Ignore` from the next test, and iterate on your solution, +testing after each change. + +## All the tests pass? Submit your solution! + +With a working solution that we've reviewed, we're ready to submit it to +exercism.io. + +``` +$ exercism submit src/main/kotlin/HelloWorld.kt +``` + +## Next Steps + +From here, there are a number of paths you can take. + +1. Move on to the next exercise +2. Review (and comment on) others' submissions to this exercise +3. Submit another iteration +4. Contribute to Exercism + + +We sincerely hope you learn and enjoy being part of this community. If at any time you need assistance +do not hesitate to ask for help: + +http://exercism.io/languages/kotlin/help + +Cheers! diff --git a/kotlin/hello-world/TUTORIAL.md b/kotlin/hello-world/TUTORIAL.md new file mode 100644 index 0000000..c3ea818 --- /dev/null +++ b/kotlin/hello-world/TUTORIAL.md @@ -0,0 +1,692 @@ +NOTE: You can also view the HTML version of this file here: +https://github.com/exercism/kotlin/blob/master/exercises/hello-world/TUTORIAL.md + +* [Solving "Hello, World!"](#solving-hello-world) + * [Reading Gradle output](#reading-gradle-output) + * [Fixing the first failing test](#fixing-the-first-failing-test) + * [Enabling and fixing the second test](#enabling-and-fixing-the-second-test) + * [Enabling and fixing the third test](#enabling-and-fixing-the-third-test) + * [Enabling the last test](#enabling-the-last-test) + * [Refactoring](#refactoring) +* [Submitting your first iteration](#submitting-your-first-iteration) +* [Next Steps](#next-steps) + * [Review (and comment on) others' submissions to this exercise](#review-and-comment-on-others-submissions-to-this-exercise) + * [Extend an exercise](#extend-an-exercise) + * [Contribute to Exercism](#contribute-to-exercism) + +---- + +# Solving "Hello, World!" + +Welcome to the first exercise on the Kotlin track! + +This is a step-by-step guide to solving this exercise. + +Each exercise comes with a set of tests. The first pass through the +exercise is about getting all of the tests to pass, one at a time. + +If you have not installed the Java Development Kit and Gradle, you must do +so now. For help with this, see: http://exercism.io/languages/kotlin/installing + +---- + +This guide picks-up where [Running the Tests (in Kotlin)](http://exercism.io/languages/kotlin/tests) +left off. If you haven't reviewed those instructions, do so now. + +The following instructions work equally well on Windows, Mac OS X and Linux. + +## Reading Gradle output + +Use Gradle to run the tests: + +``` +$ gradle test +``` + +This command does a lot and displays a bunch of stuff. Let's break it down... + +``` +:compileKotlin +w: /Users/jtigger/exercism/exercises/kotlin/hello-world/src/main/kotlin/HelloWorld.kt: (1, 11): Parameter 'name' is never used +:compileJava UP-TO-DATE +:copyMainKotlinClasses +:processResources UP-TO-DATE +:classes UP-TO-DATE +``` + +Each line that begins with a colon (like `:compileKotlin`) is Gradle telling +us that it's starting that task. The first five tasks are about compiling +the source code of our *solution*. We've done you a favor and included just +enough code for the solution that it compiles. + +When a task is successful, it generally does not output anything. This is +why `:copyMainKotlinClasses` does not produce any additional output. + +A task may succeed but warn of a potential problem. This is what we see from +`:compileKotlin`. The Kotlin compiler tells us that on line 1, 11 characters in +of the `HelloWorld.kt` file, there is a parameter called `name` that was +declared but never used. Usually, warnings _are_ helpful and should be heeded. +We'll address this warning soon enough, but we're okay for now. + +The next five tasks are about compiling source code of the *tests*. + +``` +:compileTestKotlin +:compileTestJava UP-TO-DATE +:copyTestKotlinClasses +:processTestResources UP-TO-DATE +:testClasses UP-TO-DATE +``` + +... with both sets of source code successfully compiled, Gradle turns to +running the task you asked it to: executing the tests against the solution. + +``` +:test + +HelloWorldTest > helloSampleName SKIPPED + +HelloWorldTest > helloBlankName SKIPPED + +HelloWorldTest > helloNoName FAILED + org.junit.ComparisonFailure: expected:<[Hello, World!]> but was:<[]> + at org.junit.Assert.assertEquals(Assert.java:115) + at org.junit.Assert.assertEquals(Assert.java:144) + at HelloWorldTest.helloNoName(HelloWorldTest.kt:10) + +HelloWorldTest > helloAnotherSampleName SKIPPED + +4 tests completed, 1 failed, 3 skipped +:test FAILED + +FAILURE: Build failed with an exception. + +* What went wrong: +Execution failed for task ':test'. +> There were failing tests. See the report at: file:///Users/jtigger/exercism/exercises/kotlin/hello-world/build/reports/tests/index.html + +* Try: +Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. + +BUILD FAILED + +Total time: 7.473 secs +``` + +Seeing the word "fail" NINE TIMES might give you the impression you've done +something horribly wrong! You haven't. It's a whole lot of noise over +a single test not passing. + +Let's focus in on the important bits: + +``` +HelloWorldTest > helloNoName FAILED + org.junit.ComparisonFailure: expected:<[Hello, World!]> but was:<[]> +``` + +...is read: "Within the test class named `HelloWorldTest`, the test method +`helloNoName` did not pass because the solution did not satisfy an +assertion. Apparently, we expected to see the string 'Hello, World!' but +a blank string was returned instead. + +The last line of the stack trace tells us exactly where this unsatisfied +assertion lives: + +``` + at HelloWorldTest.helloNoName(HelloWorldTest.kt:10) +``` + +Looks like the scene of the crime is on line 10 in the test file. + +Knowing these two facts, + +1. the return value was not what was expected, and +2. the failure was on line 10 of the test, + +we can turn this failure into success. + + + +## Fixing the first failing test + +In your favorite text editor, open `src/test/kotlin/HelloWorldTest.kt` +and go to line 10. + +```kotlin +assertEquals("Hello, World!", hello("")) +``` + +The test is expecting that `hello()`, when given an empty string (`""`), +returns "Hello, World!". Instead, `hello()` is returning `""`. +Let's fix that. + +Open `src/main/kotlin/HelloWorld.kt`. + +```kotlin +fun hello(name: String = ""): String { + return "" +} +``` + +Let's change that to return the expected string: + +```kotlin +fun hello(name: String = ""): String { + return "Hello, World!" +} +``` + +Save the file and run the tests again: + +``` +$ gradle test +:compileKotlin +w: /Users/jtigger/exercism/exercises/kotlin/hello-world/src/main/kotlin/HelloWorld.kt: (1, 11): Parameter 'name' is never used +:compileJava UP-TO-DATE +:copyMainKotlinClasses +:processResources UP-TO-DATE +:classes UP-TO-DATE +:compileTestKotlin +:compileTestJava UP-TO-DATE +:copyTestKotlinClasses UP-TO-DATE +:processTestResources UP-TO-DATE +:testClasses UP-TO-DATE +:test + +HelloWorldTest > helloSampleName SKIPPED + +HelloWorldTest > helloBlankName SKIPPED + +HelloWorldTest > helloNoName PASSED + +HelloWorldTest > helloAnotherSampleName SKIPPED + +BUILD SUCCESSFUL + +Total time: 7.318 secs +``` + +"BUILD SUCCESSFUL"! Woohoo! :) You can see that `helloNoName()` test is +now passing. + +We still see the warning about `name` not being used; we'll get to that +next. + +With one win under our belt, we can turn our focus to some other messages +that we've been ignoring: the lines ending in "`SKIPPED`". + +Each test suite contains a series of tests, all of which have been marked +to be skipped/ignored except the first one. We did this to help you focus +on getting one test running at a time. + +Let's tackle the next test... + + + +## Enabling and fixing the second test + +Right now, that second test is being skipped/ignored. Let's enable it. + +(Re)open `src/test/kotlin/HelloWorldTest.kt` and find the second test: + +```kotlin +@Test +@Ignore +fun helloSampleName() { + assertEquals("Hello, Alice!", hello("Alice")) +} +``` + +When the JUnit test runner sees that `@Ignore` annotation on the test +method, it knows to skip over that test. Remove that line: + +```kotlin +@Test +fun helloSampleName() { + assertEquals("Hello, Alice!", hello("Alice")) +} +``` + +Now, when you run the tests, both tests run: + +``` +$ gradle test +:test + +HelloWorldTest > helloSampleName FAILED + org.junit.ComparisonFailure: expected: but was: + at org.junit.Assert.assertEquals(Assert.java:115) + at org.junit.Assert.assertEquals(Assert.java:144) + at HelloWorldTest.helloSampleName(HelloWorldTest.kt:15) + +HelloWorldTest > helloBlankName SKIPPED + +HelloWorldTest > helloNoName PASSED + +HelloWorldTest > helloAnotherSampleName SKIPPED + +4 tests completed, 1 failed, 2 skipped +``` + +The first test, `helloNoName()` continues to pass. We see that +`helloSampleName` -- the test we just un-`@Ignore`'d -- is now running and +failing. Yay, failing test! In fact, the "failure" message is just +describing the difference between what the program does now and what it +should do for us to call it "done." + +Right now, we've hardcoded the greeting. Enabling this second test has +unleashed a new expectation: that our program incorporate a name given +into that greeting. When given the name "`Alice`", that's who should be +greeted instead of "`World`". + +(Re)open `src/main/kotlin/HelloWorld.kt`. + +```kotlin +fun hello(name: String = ""): String { + return "Hello, World!" +} +``` + +While `hello()` does accept a reference to a string named `name`, it is not +using it in the output. Let's change that: + + +```kotlin +fun hello(name: String = ""): String { + return "Hello, $name!" +} +``` + +_(Kotlin allows you to embed expressions within strings, a feature known as +string interpolation. For more about this feature, see +https://kotlinlang.org/docs/reference/basic-types.html#string-templates )_ + +... and rerun the tests ... + +``` +$ gradle test +:test + +HelloWorldTest > helloSampleName PASSED + +HelloWorldTest > helloBlankName SKIPPED + +HelloWorldTest > helloNoName FAILED + org.junit.ComparisonFailure: expected: but was: + at org.junit.Assert.assertEquals(Assert.java:115) + at org.junit.Assert.assertEquals(Assert.java:144) + at HelloWorldTest.helloNoName(HelloWorldTest.kt:10) + +HelloWorldTest > helloAnotherSampleName SKIPPED + +4 tests completed, 1 failed, 2 skipped +``` + +Wait... didn't we just fix the test? Why is it failing? Take a closer look... + +In fact, `helloSampleName()` *is* passing. It's just that at the same time, +we just inadvertently broke that first test: `helloNoName()`. + +This is one tiny example of the benefit of maintaining a test suite: if we +use them to drive out our code, the second we break the program the tests +say so. Since we saw them passing just *before* our latest change, +whatever we *just* did most likely cause that regression. + +Our latest change was making the greeting dependent on the name given. If +no name is given, our function defaults to an empty string. The intent is +that when `hello()` is called on no one in particular, our function greets +the whole world. Sound like a job for a default value! + +`src/main/kotlin/HelloWorld.kt`: +```kotlin +fun hello(name: String = "World"): String { + return "Hello, $name!" +} +``` + +... and re-run the tests ... + +``` +$ gradle test +:compileKotlin +:compileJava UP-TO-DATE +:copyMainKotlinClasses +:processResources UP-TO-DATE +:classes UP-TO-DATE +:compileTestKotlin +:compileTestJava UP-TO-DATE +:copyTestKotlinClasses +:processTestResources UP-TO-DATE +:testClasses UP-TO-DATE +:test + +HelloWorldTest > helloSampleName PASSED + +HelloWorldTest > helloBlankName SKIPPED + +HelloWorldTest > helloNoName PASSED + +HelloWorldTest > helloAnotherSampleName SKIPPED + +BUILD SUCCESSFUL +``` + +Excellent! Not only are both our tests passing, but that pesky warning +about not using `name` has faded into the distant past. We're now +(at least) three-fourth the way done. Just two more tests to go... + + + +## Enabling and fixing the third test + +(Re)open `src/test/kotlin/HelloWorldTest.kt` and find the penultimate test: + +```kotlin +@Test +@Ignore +fun helloBlankName() { + assertEquals("Hello, World!", hello(" ")) +} +``` + +In this test, we're trying to be tricky. It's one thing to omit a +parameter completely; it's a whole other situation when we provide a blank +string for a name. This test is telling us that we'd like to treat these +cases the same way. + +... and remove it's `@Ignore` to enable it ... + +```kotlin +@Test +fun helloBlankName() { + assertEquals("Hello, World!", hello(" ")) +} +``` + +... and re-run the tests ... + +``` +$ gradle test +:test + +HelloWorldTest > helloSampleName PASSED + +HelloWorldTest > helloBlankName FAILED + org.junit.ComparisonFailure: expected: but was: + at org.junit.Assert.assertEquals(Assert.java:115) + at org.junit.Assert.assertEquals(Assert.java:144) + at HelloWorldTest.helloBlankName(HelloWorldTest.kt:20) + +HelloWorldTest > helloNoName PASSED + +HelloWorldTest > helloAnotherSampleName SKIPPED + +4 tests completed, 1 failed, 1 skipped +``` + +Since `" "` is an actual value, Kotlin does _not_ substitute in the +default value. + +(Re)open `src/main/kotlin/HelloWorld.kt`. + +```kotlin +fun hello(name: String = "World"): String { + return "Hello, $name!" +} +``` + +One way to handle this case is to check to see if `name` is blank. Let's +do that: + + +```kotlin +fun hello(name: String = "World"): String { + return "Hello, ${if (name.isBlank()) "World" else name}!" +} +``` + +As you can see, string templates can contain not just references to +variables, but entire expressions! This is appropriate in a case like this +where we want to apply a simple condition to a value. + +... and rerun the tests ... + +``` +$ gradle test +:test + +HelloWorldTest > helloSampleName PASSED + +HelloWorldTest > helloBlankName PASSED + +HelloWorldTest > helloNoName PASSED + +HelloWorldTest > helloAnotherSampleName SKIPPED + +BUILD SUCCESSFUL +``` + +We're almost there (perhaps closer than you think)! Just _one_ more test +to pass before we have a solution we can have real confidence in. + + + +## Enabling the last test + +(Re)open `src/test/kotlin/HelloWorldTest.kt` and find the last test: + +```kotlin +@Test +@Ignore +fun helloAnotherSampleName() { + assertEquals("Hello, Bob!", hello("Bob")) +} +``` + +... and pop-off that `@Ignore` ... + +```kotlin +@Test +fun helloAnotherSampleName() { + assertEquals("Hello, Bob!", hello("Bob")) +} +``` + +... then rerun the tests ... + +``` +:test + +HelloWorldTest > helloSampleName PASSED + +HelloWorldTest > helloBlankName PASSED + +HelloWorldTest > helloNoName PASSED + +HelloWorldTest > helloAnotherSampleName PASSED + +BUILD SUCCESSFUL +``` + +Oh, hello! Turns out, the solution we put into place didn't just apply for +"`Alice`" but for "`Bob`" equally well. In this case, the test succeeded +with no additional code on our part. + +Congratulations! + + + +## Refactoring + +Now that you've got all the tests passing, you might consider whether +the code is in the most readable/maintainable/efficient shape. What makes +for "good" design of software is a big topic. The pursuit of it underlies +much of what makes up the more valuable conversations on Exercism. + +Kotlin is such a concise language and this exercise is so small, there is +not much room for us to make adjustments. Most would leave this code, as +is. + +That said, we've taken such pains to illustrate two core parts of the +Test-Driven Development approach (i.e. "red", "green"), we'd be remiss if +we skipped the all important final part: "refactor". + +More on TDD at http://www.jamesshore.com/Blog/Red-Green-Refactor.html. + +The core responsibility of `hello()` is to produce a personalized greeting. +_How_ we determine whether or not a name is given (i.e. `name` is +effectively an empty string) is a lower-level detail. + +```kotlin +fun hello(name: String = "World"): String { + return "Hello, ${if (name.isBlank()) "World" else name}!" +} +``` + +How would things read if we extracted that detail into a separate method? + +```kotlin +fun hello(name: String = ""): String { + return "Hello, ${whom(name)}!" +} + +private fun whom(name: String):String { + return if(name.isBlank()) "World" else name +} +``` + +By extracting that logic into the `whom()` method, we've added a little +abstraction to our program — it's not as literal as it was before. Yet, +it allows us to defer _needing_ to understand _how_ the recipient of the +greeting is determined. + +If we can assume that `whom()` just works, we don't have to +downshift in our head to those details. Instead, we can remain at the same +level of thinking: what's the greeting? + +_(Yes, this is considerable more lines of code; again, not a move we'd likely +make typically. The takeaway is this: when you are "done" with an exercise +ask yourself, "can I adjust the shape of this code to better tell the +story of what's going on through its shape?")_ + +We made a bunch of changes, let's make sure we didn't break the program! + +``` +$ gradle test +:compileKotlin +:compileJava UP-TO-DATE +:copyMainKotlinClasses +:processResources UP-TO-DATE +:classes UP-TO-DATE +:compileTestKotlin +:compileTestJava UP-TO-DATE +:copyTestKotlinClasses UP-TO-DATE +:processTestResources UP-TO-DATE +:testClasses UP-TO-DATE +:test + +HelloWorldTest > helloSampleName PASSED + +HelloWorldTest > helloBlankName PASSED + +HelloWorldTest > helloNoName PASSED + +HelloWorldTest > helloAnotherSampleName PASSED + +BUILD SUCCESSFUL +``` + +This illustrates another benefit of writing tests: you can make significant +changes to the structure of the program and very quickly restore your +confidence that the program still works. These tests are a far cry from a +"proof" of correctness, but well-written tests do a much better job of +(very quickly) giving us evidence that it is. Without them, we manually +run the program with different inputs and/or inspecting the code +line-by-line — time-consuming and error prone. + + + +# Submitting your first iteration + +With a working solution that we've reviewed, we're ready to submit it to +exercism.io. + +``` +$ exercism submit src/main/kotlin/HelloWorld.kt +``` + + + +# Next Steps + +From here, there are a number of paths you can take. + + +## Move on to the next exercise + +There are many more exercises you can practice with. Grab the next one! + +``` +$ exercism fetch kotlin +``` + + +## Review (and comment on) others' submissions to this exercise + +The heart of Exercism is the conversations about coding +practices. It's definitely fun to practice, but engaging with others +both in their attempts and your own is how you get feedback. That feedback +can help point out what you're doing well and where you might need to +improve. + +Some submissions will be nearly identical to yours; others will be +completely different. Seeing both kinds can be instructive and interesting. + +Note that you can only view submissions of others for exercises you have +completed yourself. This enriches the experience of reading others' code +because you'll have your own experience of trying to solve the problem. + +Here's an up-to-date list of submissions on the Kotlin track: + +http://exercism.io/tracks/kotlin/exercises + + + +## Submit another iteration + +You are also encouraged to consider additional "requirements" on a given +exercise. + +For example, you could add a test or two that requires that the greeting +use the capitalized form on the person's name, regardless of the case they +used. + +In that situation, you'd: + +1. add a new test setting up that new expectation, +2. implement that in the code (the same process we just went through + together, above). +3. review your code for readability and refactor as you see fit. + +Exercism practitioners who "play" with each exercise — over trying to go as +fast as they can through the stream of exercises — report deep rewards. + + +## Contribute to Exercism + +The entire of Exercism is Open Source and is the labor of love for more +than 100 maintainers and many more contributors. + +A starting point to jumping in can be found here: + +https://github.com/exercism/docs/blob/master/contributing-to-language-tracks/README.md + +---- + +Regardless of what you decide to do next, we sincerely hope you learn +and enjoy being part of this community. If at any time you need assistance +do not hesitate to ask for help: + +http://exercism.io/languages/kotlin/help + +Cheers! diff --git a/lfe/leap/.gitignore b/lfe/leap/.gitignore new file mode 100644 index 0000000..6dd20ff --- /dev/null +++ b/lfe/leap/.gitignore @@ -0,0 +1,11 @@ +## -*- conf -*- +.rebar3 +_build/ +ebin/ +erl_crash.dump +rebar3.crashdump + +tmp +bin/configlet +bin/configlet.exe +CHECKLIST diff --git a/lfe/leap/rebar.lock b/lfe/leap/rebar.lock new file mode 100644 index 0000000..e858eb1 --- /dev/null +++ b/lfe/leap/rebar.lock @@ -0,0 +1,6 @@ +{"1.1.0", +[{<<"lfe">>,{pkg,<<"lfe">>,<<"1.1.1">>},0}]}. +[ +{pkg_hash,[ + {<<"lfe">>, <<"F57D2D705AB239CE171318DD31F4E374558266A88E1435F91045C1E8A2965D9C">>}]} +]. diff --git a/lua/hello-world/hello-world.lua b/lua/hello-world/hello-world.lua new file mode 100644 index 0000000..47479c8 --- /dev/null +++ b/lua/hello-world/hello-world.lua @@ -0,0 +1,18 @@ +-- This is a "stub" file. It's a little start on your solution. +-- It's not a complete solution though; you have to write some code. + +-- Table to be returned by the hello-world module. +local hello_world = {} + +-- Add the hello() function to the table returned by this module. +function hello_world.hello() + -- Write some code here to pass the test suite. + + -- When you have a working solution, REMOVE ALL THE STOCK COMMENTS. + -- They're here to help you get started but they only clutter a finished solution. + -- If you leave them in, reviewers will protest! + return '' +end + +-- Return the hello_world table to make it accessible as a module. +return hello_world diff --git a/ocaml/hello-world/.merlin b/ocaml/hello-world/.merlin new file mode 100644 index 0000000..d9fadbc --- /dev/null +++ b/ocaml/hello-world/.merlin @@ -0,0 +1,5 @@ +PKG findlib +PKG core +PKG ounit +S * +B * diff --git a/ocaml/hello-world/Makefile b/ocaml/hello-world/Makefile new file mode 100644 index 0000000..292b3a5 --- /dev/null +++ b/ocaml/hello-world/Makefile @@ -0,0 +1,11 @@ +test: test.native + @./test.native + +test.native: *.ml *.ml + @corebuild -r -quiet -pkg oUnit test.native + +clean: + rm -rf _build + rm -f test.native + +.PHONY: clean diff --git a/ocaml/hello-world/README.md b/ocaml/hello-world/README.md new file mode 100644 index 0000000..b53e7e6 --- /dev/null +++ b/ocaml/hello-world/README.md @@ -0,0 +1,61 @@ +# Hello World + +The classical introductory exercise. Just say "Hello, World!". + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is +the traditional first program for beginning programming in a new language +or environment. + +The objectives are simple: + +- Write a function that returns 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. + + +## Getting Started +For installation and learning resources, refer to the +[exercism help page](http://exercism.io/languages/ocaml). + +## Installation +To work on the exercises, you will need `Opam` and `Core`. Consult [opam](https://opam.ocaml.org) website for instructions on how to install `opam` for your OS. Once `opam` is installed open a terminal window and run the following command to install core: + +```bash +opam install core +``` + +To run the tests you will need `OUnit`. Install it using `opam`: + +```bash +opam install ounit +``` + +## Running Tests +A Makefile is provided with a default target to compile your solution and run the tests. At the command line, type: + +```bash +make +``` + +## Interactive Shell +`utop` is a command line program which allows you to run Ocaml code interactively. The easiest way to install it is via opam: +```bash +opam install utop +``` +Consult [utop](https://github.com/diml/utop/blob/master/README.md) for more detail. + +## Feedback, Issues, Pull Requests +The [exercism/ocaml](https://github.com/exercism/ocaml) repository on +GitHub is the home for all of the Ocaml exercises. + +If you have feedback about an exercise, or want to help implementing a new +one, head over there and create an issue. We'll do our best to help you! + +## Source + +This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/ocaml/hello-world/hello_world.ml b/ocaml/hello-world/hello_world.ml new file mode 100644 index 0000000..111d2b3 --- /dev/null +++ b/ocaml/hello-world/hello_world.ml @@ -0,0 +1 @@ +let hello = "Change me" diff --git a/ocaml/hello-world/hello_world.mli b/ocaml/hello-world/hello_world.mli new file mode 100644 index 0000000..15597a4 --- /dev/null +++ b/ocaml/hello-world/hello_world.mli @@ -0,0 +1,4 @@ +(* + Returns "Hello, World!" +*) +val hello: string diff --git a/ocaml/hello-world/test.ml b/ocaml/hello-world/test.ml new file mode 100644 index 0000000..5b82a00 --- /dev/null +++ b/ocaml/hello-world/test.ml @@ -0,0 +1,14 @@ +(* Test/exercise version: "1.0.0" *) + +open Core +open OUnit2 +open Hello_world + +let ae exp got _test_ctxt = assert_equal ~printer:String.to_string exp got + +let tests = [ + "Say Hi!" >:: ae "Hello, World!" hello; +] + +let () = + run_test_tt_main ("Hello World tests" >::: tests) \ No newline at end of file diff --git a/perl5/hello-world/HelloWorld.pm b/perl5/hello-world/HelloWorld.pm new file mode 100644 index 0000000..4f1edbe --- /dev/null +++ b/perl5/hello-world/HelloWorld.pm @@ -0,0 +1,10 @@ +# Declare package 'HelloWorld' with version +package HelloWorld 1; +use strict; +use warnings; + +sub hello { + # Remove the comments and write some code here to pass the test suite. +} + +1; diff --git a/perl5/hello-world/README.md b/perl5/hello-world/README.md new file mode 100644 index 0000000..f2bc3ce --- /dev/null +++ b/perl5/hello-world/README.md @@ -0,0 +1,21 @@ +# Hello World + +The classical introductory exercise. Just say "Hello, World!". + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is +the traditional first program for beginning programming in a new language +or environment. + +The objectives are simple: + +- Write a function that returns 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. +## Source + +This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/perl5/hello-world/hello-world.t b/perl5/hello-world/hello-world.t new file mode 100644 index 0000000..bf8a486 --- /dev/null +++ b/perl5/hello-world/hello-world.t @@ -0,0 +1,64 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use FindBin; +my $dir; +use lib $dir = $FindBin::Bin; # Look for the module inside the same directory as this test file. +use JSON::PP; + +my $exercise = 'HelloWorld'; # The name of this exercise. +my $test_version = 1; # The version we will be matching against the exercise. +my $module = $ENV{EXERCISM} ? 'Example' : $exercise; # $ENV{EXERCISM} is for tests not directly for the exercise, don't worry about these :) +use Test::More tests => 4; # This is how many tests we expect to run. + +use_ok $module or BAIL_OUT; # Check that the module can be use-d. + +# If the exercise is updated, we want to make sure other people testing +# your code don't think you've made a mistake if things have changed! +my $exercise_version = $exercise->VERSION // 0; +if ($exercise_version != $test_version) { + warn "\nExercise version mismatch. Further tests may fail!" + . "\n$exercise is v$exercise_version. " + . "Test is v$test_version.\n"; + BAIL_OUT if $ENV{EXERCISM}; +} + +my %subs; +foreach ( qw(hello) ) { + can_ok $exercise, $_; + $subs{$_} = $exercise->can($_); +} + +my $C_DATA; +is $subs{hello}->($_->{input}), $_->{expected}, $_->{description} foreach @{$C_DATA->{cases}}; + +# Ignore this for your exercise! Tells Exercism folks when exercise cases become out of date. +SKIP: { + skip '', 1 unless $ENV{EXERCISM}; + is_deeply eval q{ + use Path::Tiny; + decode_json path("$dir/../../problem-specifications/exercises/".path($dir)->basename.'/canonical-data.json')->realpath->slurp; + }, $C_DATA, 'canonical-data'; +} + +done_testing; # There are no more tests after this :) + +# 'INIT' is a phaser, it makes sure that the test data is available before everything else +# starts running (otherwise we'd have to shove the test data into the middle of the file!) +INIT { +$C_DATA = decode_json <<'EOF'; + +{ + "exercise": "hello-world", + "version": "1.0.0", + "cases": [ + { + "description": "Say Hi!", + "property": "hello", + "expected": "Hello, World!" + } + ] +} + +EOF +} diff --git a/python/isogram/README.md b/python/isogram/README.md new file mode 100644 index 0000000..6412b8d --- /dev/null +++ b/python/isogram/README.md @@ -0,0 +1,30 @@ +# Isogram + +Determine if a word or phrase is an isogram. + +An isogram (also known as a "nonpattern word") is a word or phrase without a repeating letter. + +Examples of isograms: + +- lumberjacks +- background +- downstream + +The word *isograms*, however, is not an isogram, because the s repeats. + +### Submitting Exercises + +Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/` directory. + +For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit /python/bob/bob.py`. + + +For more detailed information about running tests, code style and linting, +please see the [help page](http://exercism.io/languages/python). + +## Source + +Wikipedia [https://en.wikipedia.org/wiki/Isogram](https://en.wikipedia.org/wiki/Isogram) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/python/isogram/isogram.py b/python/isogram/isogram.py new file mode 100644 index 0000000..7b0ccf9 --- /dev/null +++ b/python/isogram/isogram.py @@ -0,0 +1,2 @@ +def is_isogram(): + pass diff --git a/python/isogram/isogram_test.py b/python/isogram/isogram_test.py new file mode 100644 index 0000000..2459ae0 --- /dev/null +++ b/python/isogram/isogram_test.py @@ -0,0 +1,39 @@ +import unittest + +from isogram import is_isogram + + +# test cases adapted from `x-common//canonical-data.json` @ version: 1.1.0 + +class TestIsogram(unittest.TestCase): + + def test_empty_string(self): + self.assertTrue(is_isogram("")) + + def test_isogram_with_only_lower_case_characters(self): + self.assertTrue(is_isogram("isogram")) + + def test_word_with_one_duplicated_character(self): + self.assertFalse(is_isogram("eleven")) + + def test_longest_reported_english_isogram(self): + self.assertTrue(is_isogram("subdermatoglyphic")) + + def test_word_with_duplicated_character_in_mixed_case(self): + self.assertFalse(is_isogram("Alphabet")) + + def test_hypothetical_isogrammic_word_with_hyphen(self): + self.assertTrue(is_isogram("thumbscrew-japingly")) + + def test_isogram_with_duplicated_non_letter_character(self): + self.assertTrue(is_isogram("Hjelmqvist-Gryb-Zock-Pfund-Wax")) + + def test_made_up_name_that_is_an_isogram(self): + self.assertTrue(is_isogram("Emily Jung Schwartzkopf")) + + def test_duplicated_character_in_the_middle(self): + self.assertFalse(is_isogram("accentor")) + + +if __name__ == '__main__': + unittest.main() diff --git a/rust/hello-world/.gitignore b/rust/hello-world/.gitignore new file mode 100644 index 0000000..cb14a42 --- /dev/null +++ b/rust/hello-world/.gitignore @@ -0,0 +1,7 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock +Cargo.lock diff --git a/rust/hello-world/src/lib.rs b/rust/hello-world/src/lib.rs new file mode 100644 index 0000000..f147ab7 --- /dev/null +++ b/rust/hello-world/src/lib.rs @@ -0,0 +1,5 @@ +// The &'static here means the return type has a static lifetime. +// This is a Rust feature that you don't need to worry about now. +pub fn hello() -> &'static str { + "Goodbye, World!" +} diff --git a/scala/hello-world/src/main/scala/HelloWorld.scala b/scala/hello-world/src/main/scala/HelloWorld.scala new file mode 100644 index 0000000..2947179 --- /dev/null +++ b/scala/hello-world/src/main/scala/HelloWorld.scala @@ -0,0 +1,4 @@ +object HelloWorld { + def hello() = ??? +} + diff --git a/swift/hello-world/.gitignore b/swift/hello-world/.gitignore new file mode 100644 index 0000000..02c0875 --- /dev/null +++ b/swift/hello-world/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj diff --git a/swift/hello-world/Package.swift b/swift/hello-world/Package.swift new file mode 100644 index 0000000..12d5586 --- /dev/null +++ b/swift/hello-world/Package.swift @@ -0,0 +1,5 @@ +import PackageDescription + +let package = Package( + name: "HelloWorld" +) diff --git a/swift/hello-world/Sources/HelloWorld.swift b/swift/hello-world/Sources/HelloWorld.swift new file mode 100644 index 0000000..cbe2927 --- /dev/null +++ b/swift/hello-world/Sources/HelloWorld.swift @@ -0,0 +1 @@ +//Solution goes in Sources diff --git a/swift/hello-world/Tests/HelloWorldTests/HelloWorldTests.swift b/swift/hello-world/Tests/HelloWorldTests/HelloWorldTests.swift new file mode 100644 index 0000000..7c49d43 --- /dev/null +++ b/swift/hello-world/Tests/HelloWorldTests/HelloWorldTests.swift @@ -0,0 +1,34 @@ +import XCTest +@testable import HelloWorld + +class HelloWorldTests: XCTestCase { + + func testNoName() { + let expected = "Hello, World!" + XCTAssertEqual(HelloWorld.hello(), expected, "When given no name, we should greet the world!") + } + + func testSampleName() { + let expected = "Hello, Alice!" + XCTAssertEqual(HelloWorld.hello("Alice"), expected, "When given 'Alice' we should greet Alice!") + } + + func testOtherSampleName() { + let expected = "Hello, Bob!" + XCTAssertEqual(HelloWorld.hello("Bob"), expected, "When given 'Bob' we should greet Bob!") + } + + func testNoStrangeName() { + let expected = "Hello, !" + XCTAssertEqual(HelloWorld.hello(""), expected, "When given an empty string, it is strange, but should have a space and punctuation") + } + + static var allTests: [(String, (HelloWorldTests) -> () throws -> Void)] { + return [ + ("testNoName", testNoName), + ("testSampleName", testSampleName), + ("testOtherSampleName", testOtherSampleName), + ("testNoStrangeName", testNoStrangeName), + ] + } +} diff --git a/swift/hello-world/Tests/LinuxMain.swift b/swift/hello-world/Tests/LinuxMain.swift new file mode 100644 index 0000000..e1fb7cd --- /dev/null +++ b/swift/hello-world/Tests/LinuxMain.swift @@ -0,0 +1,6 @@ +import XCTest +@testable import HelloWorldTests + +XCTMain([ + testCase(HelloWorldTests.allTests), + ])