-
-
Notifications
You must be signed in to change notification settings - Fork 627
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Adding auto-generated files * Adding intro.md * Adding support classes * Adding stub * Adding tests * Adding `proof.ci.js` * Lint and format * Fixing a merge conflict * Automatic imports ordering * Update package.json
- Loading branch information
Showing
18 changed files
with
396 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Instructions | ||
|
||
Use lenses to update nested records (specific to languages with immutable data). | ||
|
||
Updating fields of nested, immutable records is kind of annoying. | ||
The code for such cases is as cumbersome as the structure is deep. | ||
If you have, say, a Person, that contains an Address, which has a Street, that has a Number, updating the Number requires creating a new Street with the new Number, then a new Address with the new Street and, finally, a new Person with the new Address. | ||
Confused already? | ||
|
||
One solution to this problem is to use [lenses][lenses]. | ||
|
||
Implement several record accessing functions using lenses. | ||
The test suite also allows you to avoid lenses altogether so you can experiment with different approaches. | ||
|
||
[lenses]: https://en.wikibooks.org/wiki/Haskell/Lenses_and_functional_references |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
In JavaScript, lenses are a functional programming concept that allows you to access and modify data in a modular and immutable way. They are essentially composable pairs of pure getter and setter functions that focus on a particular field inside an object. | ||
|
||
Lenses can be used to simplify code, make it more reusable, and avoid common programming errors. For example, lenses can be used to: | ||
|
||
- Access and modify nested data structures without having to worry about the specific structure of the data. | ||
- Update data in a pure way, without mutating the original object. | ||
- Compose multiple lenses together to create more complex lenses that can access and modify data in a variety of ways. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"root": true, | ||
"extends": "@exercism/eslint-config-javascript", | ||
"env": { | ||
"jest": true | ||
}, | ||
"overrides": [ | ||
{ | ||
"files": [".meta/proof.ci.js", ".meta/exemplar.js", "*.spec.js"], | ||
"excludedFiles": ["custom.spec.js"], | ||
"extends": "@exercism/eslint-config-javascript/maintainers" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/node_modules | ||
/bin/configlet | ||
/bin/configlet.exe | ||
/pnpm-lock.yaml | ||
/yarn.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"authors": [ | ||
"sarava338", | ||
"Cool-Katt" | ||
], | ||
"files": { | ||
"solution": [ | ||
"lens-person.js" | ||
], | ||
"test": [ | ||
"lens-person.spec.js" | ||
], | ||
"example": [ | ||
".meta/proof.ci.js" | ||
], | ||
"editor": [ | ||
"address.js", | ||
"born.js", | ||
"lens.js", | ||
"name.js", | ||
"person.js" | ||
] | ||
}, | ||
"blurb": "Use lenses to update nested records (specific to languages with immutable data)." | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* eslint-disable no-unused-vars */ | ||
import { Address } from '../address'; | ||
import { Born } from '../born'; | ||
import { Lens } from '../lens'; | ||
import { Name } from '../name'; | ||
import { Person } from '../person'; | ||
|
||
// Implement the nameLens with the getter and setter | ||
export const nameLens = new Lens( | ||
(person) => person.name, | ||
(person, name) => new Person(name, person.born, person.address), | ||
); | ||
|
||
// Implement the bornAtLens with the getter and setter | ||
export const bornAtLens = new Lens( | ||
(person) => person.born.bornAt, | ||
(person, bornAt) => | ||
new Person( | ||
person.name, | ||
new Born(bornAt, person.born.bornOn), | ||
person.address, | ||
), | ||
); | ||
|
||
// Implement the streetLens with the getter and setter | ||
export const streetLens = new Lens( | ||
(person) => person.address.street, | ||
(person, street) => | ||
new Person( | ||
person.name, | ||
person.born, | ||
new Address( | ||
person.address.houseNumber, | ||
street, | ||
person.address.place, | ||
person.address.country, | ||
), | ||
), | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
audit=false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2021 Exercism | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export class Address { | ||
/** | ||
* | ||
* @param {number} houseNumber | ||
* @param {string} street | ||
* @param {string} place | ||
* @param {string} country | ||
*/ | ||
constructor(houseNumber, street, place, country) { | ||
this.houseNumber = houseNumber; | ||
this.street = street; | ||
this.place = place; | ||
this.country = country; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
module.exports = { | ||
presets: ['@exercism/babel-preset-javascript'], | ||
plugins: [], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export class Born { | ||
/** | ||
* | ||
* @param {Address} bornAt | ||
* @param {Date} bornOn | ||
*/ | ||
constructor(bornAt, bornOn) { | ||
this.bornAt = bornAt; | ||
this.bornOn = bornOn; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// | ||
// This is only a SKELETON file for the 'Lense Person' exercise. It's been provided as a | ||
// convenience to get you started writing code faster. | ||
// | ||
|
||
/* eslint-disable no-unused-vars */ | ||
import { Person } from './person'; | ||
import { Name } from './name'; | ||
import { Born } from './born'; | ||
import { Address } from './address'; | ||
import { Lens } from './lens'; | ||
|
||
// Implement the nameLens with the getter and setter | ||
export const nameLens = new Lens( | ||
() => { | ||
throw new Error('Remove this statement and implement this function'); | ||
}, | ||
() => { | ||
throw new Error('Remove this statement and implement this function'); | ||
}, | ||
); | ||
|
||
// Implement the bornAtLens with the getter and setter | ||
export const bornAtLens = new Lens( | ||
() => { | ||
throw new Error('Remove this statement and implement this function'); | ||
}, | ||
() => { | ||
throw new Error('Remove this statement and implement this function'); | ||
}, | ||
); | ||
|
||
// Implement the streetLens with the getter and setter | ||
export const streetLens = new Lens( | ||
() => { | ||
throw new Error('Remove this statement and implement this function'); | ||
}, | ||
() => { | ||
throw new Error('Remove this statement and implement this function'); | ||
}, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { Address } from './address'; | ||
import { Born } from './born'; | ||
import { Name } from './name'; | ||
import { Person } from './person'; | ||
|
||
import { bornAtLens, nameLens, streetLens } from './lens-person'; | ||
|
||
// test data | ||
const person = new Person( | ||
new Name('Saravanan', 'Lakshamanan'), | ||
new Born( | ||
new Address(100, 'Hospital street', 'Tamil Nadu', 'India'), | ||
new Date(), | ||
), | ||
new Address(1, 'Coder street', 'Tamil Nadu', 'India'), | ||
); | ||
|
||
// test suite for nameLens | ||
describe('nameLens', () => { | ||
test('should get the name of the person', () => { | ||
expect(nameLens.get(person)).toEqual(person.name); | ||
}); | ||
|
||
xtest('should set a new forename for the person', () => { | ||
const updatedPerson = nameLens.set(person, new Name('Sara', 'Lakshmanan')); | ||
expect(nameLens.get(updatedPerson)).toEqual(updatedPerson.name); | ||
}); | ||
|
||
xtest('should set a new surname for the person', () => { | ||
const updatedPerson = nameLens.set(person, new Name('Saravanan', 'Laksh')); | ||
expect(nameLens.get(updatedPerson)).toEqual(updatedPerson.name); | ||
}); | ||
|
||
xtest('should ensure immutability by checking the original person object', () => { | ||
expect(person).not.toStrictEqual( | ||
new Person(new Name('Sara', 'Lakshamanan'), person.born, person.address), | ||
); | ||
}); | ||
}); | ||
|
||
// Test suite for bornAtLens | ||
describe('bornAtLens', () => { | ||
xtest('should get the address where the person was born', () => { | ||
expect(bornAtLens.get(person)).toEqual(person.born.bornAt); | ||
}); | ||
|
||
xtest('should set a new street for the place where the person was born', () => { | ||
const updatedPerson = bornAtLens.set( | ||
person, | ||
new Address(2, 'Exercism street', 'Tamil Nadu', 'India'), | ||
); | ||
expect(bornAtLens.get(updatedPerson)).toEqual(updatedPerson.born.bornAt); | ||
}); | ||
|
||
xtest('should ensure immutability by checking the original person object', () => { | ||
expect(person).not.toEqual( | ||
new Person( | ||
person.name, | ||
new Born( | ||
new Address(2, 'Exercism street', 'Tamil Nadu', 'India'), | ||
person.born.bornOn, | ||
), | ||
person.address, | ||
), | ||
); | ||
}); | ||
}); | ||
|
||
// Test suite for streetLens | ||
describe('streetLens', () => { | ||
xtest('should get the current street of the person', () => { | ||
expect(streetLens.get(person)).toEqual(person.address.street); | ||
}); | ||
|
||
xtest('should set a new street for the current address of the person', () => { | ||
const updatedPerson = streetLens.set(person, 'Exercism street'); | ||
expect(streetLens.get(updatedPerson)).toEqual(updatedPerson.address.street); | ||
}); | ||
|
||
xtest('should ensure immutability by checking the original person object', () => { | ||
expect(person).not.toEqual( | ||
new Person( | ||
person.name, | ||
person.born, | ||
new Address( | ||
person.address.houseNumber, | ||
'Exercism Street', | ||
person.address.place, | ||
person.address.country, | ||
), | ||
), | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
export class Lens { | ||
/** | ||
* | ||
* @param {Function} getter | ||
* @param {Function} setter | ||
*/ | ||
constructor(getter, setter) { | ||
this.get = getter; | ||
this.set = setter; | ||
} | ||
|
||
/** | ||
* Function to get the value from a lens | ||
* @param {Person} person | ||
* @returns {Person} | ||
*/ | ||
get(person) { | ||
return this.get(person); | ||
} | ||
|
||
/** | ||
* Function to set the value using a lens | ||
* @param {Person} person | ||
* @param {any} value | ||
* @returns {Person} | ||
*/ | ||
set(person, value) { | ||
return this.set(value, person); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
export class Name { | ||
/** | ||
* | ||
* @param {string} forename | ||
* @param {string} surname | ||
*/ | ||
constructor(forename, surname) { | ||
this.forename = forename; | ||
this.surname = surname; | ||
} | ||
} |
Oops, something went wrong.