Skip to content

Commit

Permalink
test: verify examples with doctest rather than custom script
Browse files Browse the repository at this point in the history
  • Loading branch information
davidchambers committed Mar 21, 2019
1 parent 0f0fd04 commit 3ad5b88
Show file tree
Hide file tree
Showing 6 changed files with 333 additions and 153 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"rules": {
"comma-dangle": ["error", "always-multiline"],
"max-len": ["off"],
"no-unused-vars": ["error", {"varsIgnorePattern": "^format$"}],
"no-unused-vars": ["error", {"varsIgnorePattern": "^(format|user)$"}],
"semi": ["off"]
}
}
Expand Down
3 changes: 3 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Contributing

Note: __README.md__ is generated from comments in __index.js__. Do not modify
__README.md__ directly.

1. Update local master branch:

$ git checkout master
Expand Down
173 changes: 93 additions & 80 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
# string-format

string-format is a small JavaScript library for formatting strings, based on
Python's [`str.format()`][1]. For example:
string-format is a small JavaScript library for formatting strings,
based on Python's [`str.format()`][1]. For example:

```javascript
'"{firstName} {lastName}" <{email}>'.format (user)
// => '"Jane Smith" <[email protected]>'
> const user = {
. firstName: 'Jane',
. lastName: 'Smith',
. email: '[email protected]',
. }
```

```javascript
> '"{firstName} {lastName}" <{email}>'.format (user)
'"Jane Smith" <[email protected]>'
```

The equivalent concatenation:

```javascript
'"' + user.firstName + ' ' + user.lastName + '" <' + user.email + '>'
// => '"Jane Smith" <[email protected]>'
> '"' + user.firstName + ' ' + user.lastName + '" <' + user.email + '>'
'"Jane Smith" <[email protected]>'
```

### Installation
Expand Down Expand Up @@ -41,14 +49,14 @@ The equivalent concatenation:

### Modes

string-format can be used in two modes: [function mode](#function-mode) and
[method mode](#method-mode).
string-format can be used in two modes: [function mode](#function-mode)
and [method mode](#method-mode).

#### Function mode

```javascript
format ('Hello, {}!', 'Alice')
// => 'Hello, Alice!'
> format ('Hello, {}!', 'Alice')
'Hello, Alice!'
```

In this mode the first argument is a template string and the remaining
Expand All @@ -57,153 +65,159 @@ arguments are values to be interpolated.
#### Method mode

```javascript
'Hello, {}!'.format ('Alice')
// => 'Hello, Alice!'
> 'Hello, {}!'.format ('Alice')
'Hello, Alice!'
```

In this mode values to be interpolated are supplied to the `format` method
of a template string. This mode is not enabled by default. The method must
first be defined via [`format.extend`](#format.extend):
In this mode values to be interpolated are supplied to the `format`
method of a template string. This mode is not enabled by default.
The method must first be defined via [`format.extend`](#format.extend):

```javascript
format.extend (String.prototype, {})
> format.extend (String.prototype, {})
```

`format (template, $0, $1, …, $N)` and `template.format ($0, $1, …, $N)` can
then be used interchangeably.
`format (template, $0, $1, …, $N)` and `template.format ($0, $1, …, $N)`
can then be used interchangeably.

<a name="format"></a>

### `format (template, $0, $1, …, $N)`

Returns the result of replacing each `{…}` placeholder in the template string
with its corresponding replacement.
Returns the result of replacing each `{…}` placeholder in the template
string with its corresponding replacement.

Placeholders may contain numbers which refer to positional arguments:

```javascript
'{0}, you have {1} unread message{2}'.format ('Holly', 2, 's')
// => 'Holly, you have 2 unread messages'
> '{0}, you have {1} unread message{2}'.format ('Holly', 2, 's')
'Holly, you have 2 unread messages'
```

Unmatched placeholders produce no output:

```javascript
'{0}, you have {1} unread message{2}'.format ('Steve', 1)
// => 'Steve, you have 1 unread message'
> '{0}, you have {1} unread message{2}'.format ('Steve', 1)
'Steve, you have 1 unread message'
```

A format string may reference a positional argument multiple times:

```javascript
"The name's {1}. {0} {1}.".format ('James', 'Bond')
// => "The name's Bond. James Bond."
> "The name's {1}. {0} {1}.".format ('James', 'Bond')
"The name's Bond. James Bond."
```

Positional arguments may be referenced implicitly:

```javascript
'{}, you have {} unread message{}'.format ('Steve', 1)
// => 'Steve, you have 1 unread message'
> '{}, you have {} unread message{}'.format ('Steve', 1)
'Steve, you have 1 unread message'
```

A format string must not contain both implicit and explicit references:

```javascript
'My name is {} {}. Do you like the name {0}?'.format ('Lemony', 'Snicket')
// => ValueError: cannot switch from implicit to explicit numbering
> 'My name is {} {}. Do you like the name {0}?'.format ('Lemony', 'Snicket')
! ValueError: cannot switch from implicit to explicit numbering
```

`{{` and `}}` in format strings produce `{` and `}`:
```javascript
'{{}} creates an empty {} in {}'.format ('dictionary', 'Python')
// => '{} creates an empty dictionary in Python'
> '{{}} creates an empty {} in {}'.format ('dictionary', 'Python')
'{} creates an empty dictionary in Python'
```

Dot notation may be used to reference object properties:

```javascript
const bobby = {firstName: 'Bobby', lastName: 'Fischer'}
const garry = {firstName: 'Garry', lastName: 'Kasparov'}
> const bobby = {firstName: 'Bobby', lastName: 'Fischer'}
> const garry = {firstName: 'Garry', lastName: 'Kasparov'}

'{0.firstName} {0.lastName} vs. {1.firstName} {1.lastName}'.format (bobby, garry)
// => 'Bobby Fischer vs. Garry Kasparov'
> '{0.firstName} {0.lastName} vs. {1.firstName} {1.lastName}'.format (bobby, garry)
'Bobby Fischer vs. Garry Kasparov'
```

`0.` may be omitted when referencing a property of `{0}`:

```javascript
const repo = {owner: 'davidchambers', slug: 'string-format'}
> const repo = {owner: 'davidchambers', slug: 'string-format'}

'https://github.com/{owner}/{slug}'.format (repo)
// => 'https://github.com/davidchambers/string-format'
> 'https://github.com/{owner}/{slug}'.format (repo)
'https://github.com/davidchambers/string-format'
```

If the referenced property is a method, it is invoked with no arguments to
determine the replacement:
If the referenced property is a method, it is invoked with no arguments
to determine the replacement:

```javascript
const sheldon = {
firstName: 'Sheldon',
lastName: 'Cooper',
dob: new Date ('1970-01-01'),
fullName: function() { return this.firstName + ' ' + this.lastName },
quip: function() { return 'Bazinga!' },
}
> const sheldon = {
. firstName: 'Sheldon',
. lastName: 'Cooper',
. dob: new Date ('1970-01-01'),
. fullName: function() { return this.firstName + ' ' + this.lastName },
. quip: function() { return 'Bazinga!' },
. }

'{fullName} was born at precisely {dob.toISOString}'.format (sheldon)
// => 'Sheldon Cooper was born at precisely 1970-01-01T00:00:00.000Z'
> '{fullName} was born at precisely {dob.toISOString}'.format (sheldon)
'Sheldon Cooper was born at precisely 1970-01-01T00:00:00.000Z'

"I've always wanted to go to a goth club. {quip.toUpperCase}".format (sheldon)
// => "I've always wanted to go to a goth club. BAZINGA!"
> "I've always wanted to go to a goth club. {quip.toUpperCase}".format (sheldon)
"I've always wanted to go to a goth club. BAZINGA!"
```

<a name="format.create"></a>

### `format.create (transformers)`

This function takes an object mapping names to transformers and returns a
formatting function. A transformer is applied if its name appears, prefixed
with `!`, after a field name in a template string.
This function takes an object mapping names to transformers and returns
a formatting function. A transformer is applied if its name appears,
prefixed with `!`, after a field name in a template string.

```javascript
const fmt = format.create ({
escape: s => s.replace (/[&<>"'`]/g, c => '&#' + c.charCodeAt (0) + ';'),
upper: s => s.toUpperCase (),
})
> const fmt = format.create ({
. escape: s =>
. s.replace (/[&<>"'`]/g, c => '&#' + c.charCodeAt (0) + ';'),
. upper: s =>
. s.toUpperCase (),
. })

fmt ('Hello, {!upper}!', 'Alice')
// => 'Hello, ALICE!'
> fmt ('Hello, {!upper}!', 'Alice')
'Hello, ALICE!'

const restaurant = {name: 'Anchor & Hope', url: 'http://anchorandhopesf.com/'}

fmt ('<a href="{url!escape}">{name!escape}</a>', restaurant)
// => '<a href="http://anchorandhopesf.com/">Anchor &#38; Hope</a>'
> fmt ('<a href="{url!escape}">{name!escape}</a>', {
. name: 'Anchor & Hope',
. url: 'http://anchorandhopesf.com/',
. })
'<a href="http://anchorandhopesf.com/">Anchor &#38; Hope</a>'
```

<a name="format.extend"></a>

### `format.extend (prototype, transformers)`

This function takes a prototype (presumably `String.prototype`) and an object
mapping names to transformers, and defines a `format` method on the prototype.
A transformer is applied if its name appears, prefixed with `!`, after a field
name in a template string.
This function takes a prototype (presumably `String.prototype`) and an
object mapping names to transformers, and defines a `format` method on
the prototype. A transformer is applied if its name appears, prefixed
with `!`, after a field name in a template string.

```javascript
format.extend (String.prototype, {
escape: s => s.replace (/[&<>"'`]/g, c => '&#' + c.charCodeAt (0) + ';'),
upper: s => s.toUpperCase (),
})
> format.extend (String.prototype, {
. escape: s =>
. s.replace (/[&<>"'`]/g, c => '&#' + c.charCodeAt (0) + ';'),
. upper: s =>
. s.toUpperCase (),
. })

'Hello, {!upper}!'.format ('Alice')
// => 'Hello, ALICE!'
> 'Hello, {!upper}!'.format ('Alice')
'Hello, ALICE!'

const restaurant = {name: 'Anchor & Hope', url: 'http://anchorandhopesf.com/'}

'<a href="{url!escape}">{name!escape}</a>'.format (restaurant)
// => '<a href="http://anchorandhopesf.com/">Anchor &#38; Hope</a>'
> '<a href="{url!escape}">{name!escape}</a>'.format ({
. name: 'Anchor & Hope',
. url: 'http://anchorandhopesf.com/',
. })
'<a href="http://anchorandhopesf.com/">Anchor &#38; Hope</a>'
```

### Running the test suite
Expand All @@ -213,5 +227,4 @@ $ npm install
$ npm test
```


[1]: http://docs.python.org/library/stdtypes.html#str.format
Loading

0 comments on commit 3ad5b88

Please sign in to comment.