Skip to content

Commit

Permalink
Fix spelling mistakes
Browse files Browse the repository at this point in the history
  • Loading branch information
bas080 committed Oct 3, 2021
1 parent 0da801e commit 1bd9975
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 13 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Let's see what valid and less valid uses of patroon are.

### Arrays

A less intuitive case (atleast initially) is the matching with an empty array.
A less intuitive case (at least initially) is the matching with an empty array.

```js ./tape-test
patroon(
Expand All @@ -29,7 +29,7 @@ patroon(
)([1])
```

Notice that the empty array watches with `[1]`. This is because the empty array
Notice that the empty array matches with `[1]`. This is because the empty array
is a subset of `[1]`.

In this case you might as well write the following for readability sake:
Expand Down Expand Up @@ -80,7 +80,7 @@ t.end()
The array pattern assumes that the array has rest elements. It's a design
choice which avoids adding additional helpers with little to no downsides.

In case the seamingly unexpected case seems truely unexpected; I suggest you
In case the seemingly unexpected case seems truly unexpected; I suggest you
think of patterns as a subset of the value you are trying to match. In the case
of arrays. `[1,2]` is a subset of `[1,2,3]`. `[2,3]` is not a subset of
`[1,2,3]` because arrays also care about the order of elements.
Expand Down Expand Up @@ -149,7 +149,7 @@ patroon(
)({a: 1})
```

Next we match on the existance of object keys. We use the `_` to
Next we match on the existence of object keys. We use the `_` to
achieve this.

```js ./tape-test
Expand Down Expand Up @@ -261,7 +261,7 @@ npm test
```
```
> patroon@0.0.1 test
> patroon@0.0.2 test
> tape ./src/index.test.js
TAP version 13
Expand Down
8 changes: 4 additions & 4 deletions README.mz
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Let's see what valid and less valid uses of patroon are.

### Arrays

A less intuitive case (atleast initially) is the matching with an empty array.
A less intuitive case (at least initially) is the matching with an empty array.

```js ./tape-test
patroon(
Expand All @@ -29,7 +29,7 @@ patroon(
)([1])
```

Notice that the empty array watches with `[1]`. This is because the empty array
Notice that the empty array matches with `[1]`. This is because the empty array
is a subset of `[1]`.

In this case you might as well write the following for readability sake:
Expand Down Expand Up @@ -80,7 +80,7 @@ t.end()
The array pattern assumes that the array has rest elements. It's a design
choice which avoids adding additional helpers with little to no downsides.

In case the seamingly unexpected case seems truely unexpected; I suggest you
In case the seemingly unexpected case seems truly unexpected; I suggest you
think of patterns as a subset of the value you are trying to match. In the case
of arrays. `[1,2]` is a subset of `[1,2,3]`. `[2,3]` is not a subset of
`[1,2,3]` because arrays also care about the order of elements.
Expand Down Expand Up @@ -149,7 +149,7 @@ patroon(
)({a: 1})
```

Next we match on the existance of object keys. We use the `_` to
Next we match on the existence of object keys. We use the `_` to
achieve this.

```js ./tape-test
Expand Down
284 changes: 284 additions & 0 deletions README.mz.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
# Patroon

Patroon as an attempt to add pattern matching-ish functionality without
introducing new syntax.

## Implementation

1. [./src/walkable.js][2] - Patroon allows one to define deeply nested
patterns. To implement these features succinctly we use an abstraction
which allows the traversing of a tree. This is an area of computer science
named [tree traversal][1].
2. [./src/index.js][3] - We now take the walkable utility and implement
patroon's functionality.
3. [./src/helpers.js][4] - You might have noticed that both the patroon and
walkable modules have common helper functions.

## Specifications

Let's see what valid and less valid uses of patroon are.

### Arrays

A less intuitive case (atleast initially) is the matching with an empty array.

```js ./tape-test
patroon(
[], end,
[1], fail
)([1])
```

Notice that the empty array matches with `[1]`. This is because the empty array
is a subset of `[1]`.

In this case you might as well write the following for readability sake:

```js ./tape-test
patroon(
typed(Array), end,
)([1])
```

Patroon even tries to determine if something is a constructor. No need to use
typed in that case.

```js ./tape-test
patroon(
Number, fail,
Array, end,
)([1])
```

If you wish to match on the reference of a constructor you can use the `ref` helper.

```js ./tape-test
patroon(
1, fail,
Number, fail,
ref(Number), end,
)(Number)
```

Some more array examples to wrap your brain around.

```js ./tape-test
const arrayMatch = patroon(
[1,2], () => 2,
[1,2,3], () => 3,
[2], () => 1,
[], () => null
)

t.equal(arrayMatch([1,2]), 2)
t.equal(arrayMatch([1,2,3]), 2)
t.equal(arrayMatch([]), null)
t.equal(arrayMatch([2, 3]), 1)
t.end()
```

The array pattern assumes that the array has rest elements. It's a design
choice which avoids adding additional helpers with little to no downsides.

In case the seamingly unexpected case seems truely unexpected; I suggest you
think of patterns as a subset of the value you are trying to match. In the case
of arrays. `[1,2]` is a subset of `[1,2,3]`. `[2,3]` is not a subset of
`[1,2,3]` because arrays also care about the order of elements.

Now is a good time to introduce the placeholder(`_`) concept.

### Placeholders

```js ./tape-test
const alwaysMatches = patroon(_, t.end())('any value really')
```

A function that looks for a certain pattern in an array.

```js ./tape-test
const containsPattern = patroon(
[0, 0], true,
[_, _], ([, ...rest]) => containsPattern(rest),
[], false
)

t.true(containsPattern([0,0]))
t.true(containsPattern([1,0,0]))
t.false(containsPattern([1,0,1]))
t.true(containsPattern([1,0,1,0,0]))
t.end()
```

A toPairs function:

```js ./tape-test
const toPairs = patroon(
[_, _], ([a, b, ...c], p = []) => toPairs(c, [...p, [a, b]]),
_, (_, p = []) => p
)

t.deepEquals(toPairs([1]), [])
t.deepEquals(toPairs([1, 2]), [[1, 2]])
t.deepEquals(toPairs([1, 2, 3]), [[1, 2]])
t.deepEquals(toPairs([1, 2, 3, 4]), [[1, 2], [3, 4]])
t.end()
```

> An exercise would be to change toPairs to throw when an uneven length array
> is passed. Multiple answers are possible and some are more optimized than
> others.

So that's arrays. What about objects.

### Objects

Just like an empty array; matching on an empty object can be written in two
ways.

```js ./tape-test
patroon(
{}, pass,
)({a: 1})

patroon(
typed(Object), pass,
)({a: 1})

patroon(
Object, end,
)({a: 1})
```

Next we match on the existance of object keys. We use the `_` to
achieve this.

```js ./tape-test
patroon(
{a: _}, end
)({a: 2})
```

Next we also match on the key's value.

```js ./tape-test
patroon(
{a: 1}, fail,
{a: 2}, end,
{a: 3}, fail
)({a: 2})
```

What about nested objects? No problem!

```js ./tape-test
patroon(
{a: {a: 1}}, fail,
{a: {a: 2}}, end,
{a: {a: 3}}, fail
)({a: {a: 2}})
```

### Types

We'll match on type using `typed` which internally uses `instanceof`.


```js ./tape-test
patroon(
typed(TypeError), fail,
typed(Error), pass
)(new Error())

patroon(
TypeError, end,
Error, fail
)(new TypeError())
```

An object of a certain type might also have values we would want to match on.

```js ./tape-test
patroon(
typed(TypeError, { value: 20 }), fail,
typed(Error, { value: 30 }), fail,
typed(Error, { value: 20 }), end
)(Object.assign(new Error(), { value: 20 }))
```

Simply pass a pattern as the second argument of typed.

Now we'll try predicates.

### Predicates

By default a function is assumed to be a predicate.

```js ./tape-test
const isTrue = v => v === true

patroon(
isTrue, end
)(true)
```

You might have a case where you want to match on the reference of a function.
Some people are weird like that. In that case one can use the ref helper.

```js ./tape-test
const fun = () => false

patroon(
fun, fail,
ref(fun), end
)(fun)
```

Could one combine predicates with arrays and objects? Sure one can!

```js ./tape-test
const is20 = v => v === 20

patroon(
[[is20]], end,
)([[20]])
```

```js ./tape-test
const is42 = v => v === 42

patroon(
[{a: is42}], end,
)([{a: 42}])
```

## Tests

Now for some additional edge cases and some generative testing.
[./src/index.test.js][5]

```bash bash
npm test
```

## Formatting

Standard is good enough.

```bash bash 2>&1
npx standard || npx standard --fix
```

## Documentation

The README.md is generated using [markatzea][6].

```bash bash
test "$RECUR" -eq 1 || RECUR=1 markatzea README.mz | tee README.md
```

[1]:https://en.wikipedia.org/wiki/Tree_traversal
[2]:https://github.com/bas080/patroon/blob/master/src/walkable.js
[3]:https://github.com/bas080/patroon/blob/master/src/index.js
[4]:https://github.com/bas080/patroon/blob/master/src/helpers.js
[5]:https://github.com/bas080/patroon/blob/master/src/index.test.js
[6]:https://github.com/bas080/markatzea
5 changes: 2 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "patroon",
"version": "0.0.1",
"version": "0.0.2",
"description": "Pattern matching library",
"main": "./src/index.js",
"scripts": {
Expand Down

0 comments on commit 1bd9975

Please sign in to comment.