From 6a8191cc348d6e5b8f77c20ca8250e1afc8afba3 Mon Sep 17 00:00:00 2001 From: Matei Adriel Date: Wed, 25 Dec 2019 15:51:56 +0200 Subject: [PATCH] typescript(option): feat: added the 'orLazy' helper Signed-off-by: prescientmoon --- typescript/option/package.json | 2 + typescript/option/pnpm-lock.yaml | 94 ++++++++++++++++++++ typescript/option/src/helpers/external.ts | 1 + typescript/option/src/helpers/orLazy.test.ts | 48 ++++++++++ typescript/option/src/helpers/orLazy.ts | 17 ++++ 5 files changed, 162 insertions(+) create mode 100644 typescript/option/src/helpers/orLazy.test.ts create mode 100644 typescript/option/src/helpers/orLazy.ts diff --git a/typescript/option/package.json b/typescript/option/package.json index af5d47f..156a506 100644 --- a/typescript/option/package.json +++ b/typescript/option/package.json @@ -30,6 +30,7 @@ "@types/chai": "^4.2.7", "@types/mocha": "^5.2.7", "@types/node": "^12.12.21", + "@types/sinon": "^7.5.1", "@wessberg/rollup-plugin-ts": "^1.1.83", "chai": "^4.2.0", "mocha": "^6.2.2", @@ -37,6 +38,7 @@ "rollup": "^1.27.14", "rollup-plugin-terser": "^5.1.3", "semantic-release": "^15.14.0", + "sinon": "^8.0.1", "ts-node": "^8.5.4", "typescript": "^3.7.4", "utility-types": "^3.10.0" diff --git a/typescript/option/pnpm-lock.yaml b/typescript/option/pnpm-lock.yaml index 0fbc0cd..e5d1f82 100644 --- a/typescript/option/pnpm-lock.yaml +++ b/typescript/option/pnpm-lock.yaml @@ -7,6 +7,7 @@ devDependencies: '@types/chai': 4.2.7 '@types/mocha': 5.2.7 '@types/node': 12.12.21 + '@types/sinon': 7.5.1 '@wessberg/rollup-plugin-ts': 1.1.83_rollup@1.27.14+typescript@3.7.4 chai: 4.2.0 mocha: 6.2.2 @@ -14,6 +15,7 @@ devDependencies: rollup: 1.27.14 rollup-plugin-terser: 5.1.3_rollup@1.27.14 semantic-release: 15.14.0_semantic-release@15.14.0 + sinon: 8.0.1 ts-node: 8.5.4_typescript@3.7.4 typescript: 3.7.4 utility-types: 3.10.0 @@ -959,6 +961,31 @@ packages: semantic-release: '>=15.8.0 <16.0.0 || >=16.0.0-beta <17.0.0' resolution: integrity: sha512-LGjgPBGjjmjap/76O0Md3wc04Y7IlLnzZceLsAkcYRwGQdRPTTFUJKqDQTuieWTs7zfHzQoZqsqPfFxEN+g2+Q== + /@sinonjs/commons/1.7.0: + dependencies: + type-detect: 4.0.8 + dev: true + resolution: + integrity: sha512-qbk9AP+cZUsKdW1GJsBpxPKFmCJ0T8swwzVje3qFd+AkQb74Q/tiuzrdfFg8AD2g5HH/XbE/I8Uc1KYHVYWfhg== + /@sinonjs/formatio/4.0.1: + dependencies: + '@sinonjs/commons': 1.7.0 + '@sinonjs/samsam': 4.2.0 + dev: true + resolution: + integrity: sha512-asIdlLFrla/WZybhm0C8eEzaDNNrzymiTqHMeJl6zPW2881l3uuVRpm0QlRQEjqYWv6CcKMGYME3LbrLJsORBw== + /@sinonjs/samsam/4.2.0: + dependencies: + '@sinonjs/commons': 1.7.0 + array-from: 2.1.1 + lodash.get: 4.4.2 + dev: true + resolution: + integrity: sha512-yG7QbUz38ZPIegfuSMEcbOo0kkLGmPa8a0Qlz4dk7+cXYALDScWjIZzAm/u2+Frh+bcdZF6wZJZwwuJjY0WAjA== + /@sinonjs/text-encoding/0.7.1: + dev: true + resolution: + integrity: sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== /@thi.ng/api/6.6.0: dev: false resolution: @@ -1046,6 +1073,10 @@ packages: dev: true resolution: integrity: sha512-1OzrNb4RuAzIT7wHSsgZRlMBlNsJl+do6UblR7JMW4oB7bbR+uBEYtUh7gEc/jM84GGilh68lSOokyM/zNUlBA== + /@types/sinon/7.5.1: + dev: true + resolution: + integrity: sha512-EZQUP3hSZQyTQRfiLqelC9NMWd1kqLcmQE0dMiklxBkgi84T+cHOhnKpgk4NnOWpGX863yE6+IaGnOXUNFqDnQ== /@types/ua-parser-js/0.7.33: dev: true resolution: @@ -1214,6 +1245,10 @@ packages: node: '>=0.10.0' resolution: integrity: sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= + /array-from/2.1.1: + dev: true + resolution: + integrity: sha1-z+nYwmYoudxa7MYqn12PHzUsEZU= /array-ify/1.0.0: dev: true resolution: @@ -2019,6 +2054,12 @@ packages: node: '>=4' resolution: integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + /has-flag/4.0.0: + dev: true + engines: + node: '>=8' + resolution: + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== /has-symbols/1.0.1: dev: true engines: @@ -2263,6 +2304,10 @@ packages: node: '>=0.10.0' resolution: integrity: sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= + /isarray/0.0.1: + dev: true + resolution: + integrity: sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= /isarray/1.0.0: dev: true resolution: @@ -2363,6 +2408,10 @@ packages: '0': node >= 0.2.0 resolution: integrity: sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + /just-extend/4.0.2: + dev: true + resolution: + integrity: sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw== /lines-and-columns/1.1.6: dev: true resolution: @@ -2456,6 +2505,12 @@ packages: node: '>=4' resolution: integrity: sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== + /lolex/5.1.2: + dependencies: + '@sinonjs/commons': 1.7.0 + dev: true + resolution: + integrity: sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== /loose-envify/1.4.0: dependencies: js-tokens: 4.0.0 @@ -2678,6 +2733,17 @@ packages: dev: true resolution: integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + /nise/3.0.0: + dependencies: + '@sinonjs/commons': 1.7.0 + '@sinonjs/formatio': 4.0.1 + '@sinonjs/text-encoding': 0.7.1 + just-extend: 4.0.2 + lolex: 5.1.2 + path-to-regexp: 1.8.0 + dev: true + resolution: + integrity: sha512-EObFx5tioBMePHpU/gGczaY2YDqL255iwjmZwswu2CiwEW8xIGrr3E2xij+efIppS1nLQo9NyXSIUySGHUOhHQ== /node-emoji/1.10.0: dependencies: lodash.toarray: 4.4.0 @@ -3094,6 +3160,12 @@ packages: dev: true resolution: integrity: sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + /path-to-regexp/1.8.0: + dependencies: + isarray: 0.0.1 + dev: true + resolution: + integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== /path-type/3.0.0: dependencies: pify: 3.0.0 @@ -3500,6 +3572,18 @@ packages: node: '>=6' resolution: integrity: sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w== + /sinon/8.0.1: + dependencies: + '@sinonjs/commons': 1.7.0 + '@sinonjs/formatio': 4.0.1 + '@sinonjs/samsam': 4.2.0 + diff: 4.0.1 + lolex: 5.1.2 + nise: 3.0.0 + supports-color: 7.1.0 + dev: true + resolution: + integrity: sha512-vbXMHBszVioyPsuRDLEiPEgvkZnbjfdCFvLYV4jONNJqZNLWTwZ/gYSNh3SuiT1w9MRXUz+S7aX0B4Ar2XI8iw== /slash/3.0.0: dev: true engines: @@ -3721,6 +3805,14 @@ packages: node: '>=6' resolution: integrity: sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + /supports-color/7.1.0: + dependencies: + has-flag: 4.0.0 + dev: true + engines: + node: '>=8' + resolution: + integrity: sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== /supports-hyperlinks/1.0.1: dependencies: has-flag: 2.0.0 @@ -4103,6 +4195,7 @@ specifiers: '@types/chai': ^4.2.7 '@types/mocha': ^5.2.7 '@types/node': ^12.12.21 + '@types/sinon': ^7.5.1 '@wessberg/rollup-plugin-ts': ^1.1.83 chai: ^4.2.0 mocha: ^6.2.2 @@ -4110,6 +4203,7 @@ specifiers: rollup: ^1.27.14 rollup-plugin-terser: ^5.1.3 semantic-release: ^15.14.0 + sinon: ^8.0.1 ts-node: ^8.5.4 tslib: ^1.10.0 typescript: ^3.7.4 diff --git a/typescript/option/src/helpers/external.ts b/typescript/option/src/helpers/external.ts index a08193e..9b60b88 100644 --- a/typescript/option/src/helpers/external.ts +++ b/typescript/option/src/helpers/external.ts @@ -18,6 +18,7 @@ export * from './map' export * from './mapAsync' export * from './optionify' export * from './or' +export * from './orLazy' export * from './toArray' export * from './toNullable' export * from './withDefault' diff --git a/typescript/option/src/helpers/orLazy.test.ts b/typescript/option/src/helpers/orLazy.test.ts new file mode 100644 index 0000000..3cdb4c8 --- /dev/null +++ b/typescript/option/src/helpers/orLazy.test.ts @@ -0,0 +1,48 @@ +import { expect } from 'chai' +import { constantly } from '@thi.ng/compose' +import { orLazy } from './orLazy' +import { someX } from '../../test/constants' +import { None } from '../types' +import { spy } from 'sinon' + +describe('The orLazy helper', () => { + it("should return the first argument if it's Some", () => { + // act + const result = orLazy(someX, constantly(None)) + + // asser + expect(result).to.equal(someX) + }) + + it('should return the return of the second argument if the first is None', () => { + // act + const orSome = orLazy(None, constantly(someX)) + const orNone = orLazy(None, constantly(None)) + + // assert + expect(orSome).to.equal(someX) + expect(orNone).to.equal(None) + }) + + it('should not evaluate the second argument if the first one is Some', () => { + // arrange + const func = spy(constantly(someX)) + + // act + orLazy(someX, func) + + // assert + expect(func.called).to.be.false + }) + + it('should evaluate the second argument if the first one is None', () => { + // arrange + const func = spy(constantly(someX)) + + // act + orLazy(None, func) + + // assert + expect(func.called).to.be.true + }) +}) diff --git a/typescript/option/src/helpers/orLazy.ts b/typescript/option/src/helpers/orLazy.ts new file mode 100644 index 0000000..a4d83e9 --- /dev/null +++ b/typescript/option/src/helpers/orLazy.ts @@ -0,0 +1,17 @@ +import { isSome } from './isSome' +import { Option } from '../types' + +/** + * Lazy version of or. + * The second argument will only be evaluated if the first argument is Nothing. + * + * @param a The first argument. + * @param b The second argument. + */ +export const orLazy = (a: Option, b: () => Option) => { + if (isSome(a)) { + return a + } + + return b() +}