diff --git a/src/exo4/exo4.test.ts b/src/exo4/exo4.test.ts new file mode 100644 index 0000000..1a609c1 --- /dev/null +++ b/src/exo4/exo4.test.ts @@ -0,0 +1,63 @@ +import { Country, exclamation, greet, excitedlyGreet } from './exo4'; + +describe('exo4', () => { + describe('greet', () => { + it('should greet Alice in french', () => { + const result = greet('Alice')(Country.France); + + expect(result).toStrictEqual('Bonjour, Alice'); + }); + + it('should greet Bernardo in spanish', () => { + const result = greet('Bernardo')(Country.Spain); + + expect(result).toStrictEqual('Buenos dìas, Bernardo'); + }); + + it('should greet Crystal in english', () => { + const result = greet('Crystal')(Country.USA); + + expect(result).toStrictEqual('Hello, Crystal'); + }); + }); + + describe('exclamation', () => { + it('should add exclamation in french style (with a space before "!")', () => { + const result = exclamation('Youpi')(Country.France); + + expect(result).toStrictEqual('Youpi !'); + }); + + it('should add exclamation in spanish style (between "¡" and "!")', () => { + const result = exclamation('Olé')(Country.Spain); + + expect(result).toStrictEqual('¡Olé!'); + }); + + it('should add exclamation in english style (with no space before "!")', () => { + const result = exclamation('Yeah')(Country.USA); + + expect(result).toStrictEqual('Yeah!'); + }); + }); + + describe('excitedlyGreet', () => { + it('should excitedly greet Alice in french', () => { + const result = excitedlyGreet('Alice')(Country.France); + + expect(result).toStrictEqual('Bonjour, Alice !'); + }); + + it('should excitedly greet Bernardo in spanish', () => { + const result = excitedlyGreet('Bernardo')(Country.Spain); + + expect(result).toStrictEqual('¡Buenos dìas, Bernardo!'); + }); + + it('should excitedly greet Crystal in english', () => { + const result = excitedlyGreet('Crystal')(Country.USA); + + expect(result).toStrictEqual('Hello, Crystal!'); + }); + }); +}); diff --git a/src/exo4/exo4.ts b/src/exo4/exo4.ts new file mode 100644 index 0000000..7b1512f --- /dev/null +++ b/src/exo4/exo4.ts @@ -0,0 +1,88 @@ +// `fp-ts` training Exercice 4 +// Dependency injection with `Reader` + +import { Reader } from 'fp-ts/Reader'; + +import { unimplemented } from '../utils'; + +// Sometimes, a function can have a huge amount of dependencies (services, +// repositories, ...) and it is often impractical (not to say truly annoying) +// to thread those values through multiple levels of the call stack. +// +// That's precisely what dependency injection is meant to solve, and it's not a +// concept exclusive to OOP! +// In the world of FP, the so-called `Reader` construct (just a fancy word for +// a partially applied function) offers precisely those capabilities. + +/////////////////////////////////////////////////////////////////////////////// +// SETUP // +/////////////////////////////////////////////////////////////////////////////// + +// Let's consider a small range of countries (here, France, Spain and the USA): + +export enum Country { + France = 'France', + Spain = 'Spain', + USA = 'USA', +} + +/////////////////////////////////////////////////////////////////////////////// +// ASK // +/////////////////////////////////////////////////////////////////////////////// + +// These countries have different rules on how to add exclamation to a sentence: +// - french speakers will add an exclamation point at the end preceded by a +// space: "Youpi !" +// - spanish speakers begin the sentence with an inverted exclamation point and +// finish it by a regular one: `¡Olé!` +// - english speakers will have no space before the exclamation point at the end +// of the sentence: `Yeah!` +// +// The following function should take a sentence as input and return a `Reader` +// that will at some point expect a `Country` and return the sentence with the +// proper exclamation style. +// +// HINT: Take a look at `reader.ask` to access the environment value + +export const exclamation: (sentence: string) => Reader = + unimplemented(); + +// Obviously, different countries often mean different languages and so +// different words for saying "Hello": + +export const sayHello = (country: Country): string => { + switch (country) { + case Country.France: + return 'Bonjour'; + case Country.Spain: + return 'Buenos dìas'; + case Country.USA: + return 'Hello'; + } +}; + +// Using the `sayHello` function above, write the `greet` function that +// delivers a personalized greeting to a person based on their name. +// The output should look something like `${hello}, ${name}`. +// +// HINT: Remember that a `Reader` is just an alias for `(r: R) => T` +// +// HINT: You can look into `reader.map` to modify the output of a `Reader` +// action. + +export const greet: (name: string) => Reader = unimplemented(); + +// Finally, we are going to compose multiple `Reader`s together. +// +// Sometimes, a simple greeting is not enough, we want to communicate our +// excitement to see the person. +// Luckily, we already know how to greet them normally (`greet`) and how to +// add excitement to a sentence (`exclamation`). +// +// Compose those two to complete the `excitedlyGreet` function below: +// +// HINT: As with other wrapper types in `fp-ts`, `reader` offers a way of +// composing effects with `reader.chain`. + +export const excitedlyGreet: (name: string) => Reader = + unimplemented(); diff --git a/src/exo4/index.ts b/src/exo4/index.ts new file mode 100644 index 0000000..52d8c4e --- /dev/null +++ b/src/exo4/index.ts @@ -0,0 +1 @@ +export * from './exo4';