Merge remote-tracking branch 'upstream/master' into primer_md_table_update

This commit is contained in:
Chris Baish 2019-07-19 07:12:46 +01:00
commit d64e4cf14e
10 changed files with 217 additions and 177 deletions

View File

@ -1,6 +1,6 @@
## gMock Cheat Sheet ## gMock Cheat Sheet
<!-- GOOGLETEST_CM0018 DO NOT DELETE --> <!-- GOOGLETEST_CM0019 DO NOT DELETE -->
### Defining a Mock Class ### Defining a Mock Class
@ -215,7 +215,7 @@ and the default action will be taken each time.
### Matchers {#MatcherList} ### Matchers {#MatcherList}
<!-- GOOGLETEST_CM0019 DO NOT DELETE --> <!-- GOOGLETEST_CM0020 DO NOT DELETE -->
A **matcher** matches a *single* argument. You can use it inside `ON_CALL()` or A **matcher** matches a *single* argument. You can use it inside `ON_CALL()` or
`EXPECT_CALL()`, or use it to validate a value directly: `EXPECT_CALL()`, or use it to validate a value directly:
@ -341,65 +341,97 @@ write the elements in-line, match them more flexibly, or get more informative
messages, you can use: messages, you can use:
| Matcher | Description | | Matcher | Description |
| :----------------------------------- | :----------------------------------- | | :---------------------------------------- | :------------------------------- |
| `ContainerEq(container)` | The same as `Eq(container)` except | | `BeginEndDistanceIs(m)` | `argument` is a container whose |
: : that the failure message also : : : `begin()` and `end()` iterators :
: : includes which elements are in one : : : are separated by a number of :
: : container but not the other. : : : increments matching `m`. E.g. :
| `Contains(e)` | `argument` contains an element that | : : `BeginEndDistanceIs(2)` or :
: : matches `e`, which can be either a : : : `BeginEndDistanceIs(Lt(2))`. For :
: : value or a matcher. : : : containers that define a :
: : `size()` method, `SizeIs(m)` may :
: : be more efficient. :
| `ContainerEq(container)` | The same as `Eq(container)` |
: : except that the failure message :
: : also includes which elements are :
: : in one container but not the :
: : other. :
| `Contains(e)` | `argument` contains an element |
: : that matches `e`, which can be :
: : either a value or a matcher. :
| `Each(e)` | `argument` is a container where | | `Each(e)` | `argument` is a container where |
: : _every_ element matches `e`, which : : : *every* element matches `e`, :
: : can be either a value or a matcher. : : : which can be either a value or a :
: : matcher. :
| `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, | | `ElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, |
: : where the i-th element matches `ei`, : : : where the *i*-th element matches :
: : which can be a value or a matcher. 0 : : : `ei`, which can be a value or a :
: : to 10 arguments are allowed. : : : matcher. :
| `ElementsAreArray({ e0, e1, ..., en | The same as `ElementsAre()` except | | `ElementsAreArray({e0, e1, ..., en})`, | The same as `ElementsAre()` |
: })`, `ElementsAreArray(array)`, or : that the expected element : : `ElementsAreArray(a_container)`, : except that the expected element :
: `ElementsAreArray(array, count)` : values/matchers come from an : : `ElementsAreArray(begin, end)`, : values/matchers come from an :
: : initializer list, STL-style : : `ElementsAreArray(array)`, or : initializer list, STL-style :
: : container, or C-style array. : : `ElementsAreArray(array, count)` : container, iterator range, or :
: : C-style array. :
| `IsEmpty()` | `argument` is an empty container | | `IsEmpty()` | `argument` is an empty container |
: : (`container.empty()`). : : : (`container.empty()`). :
| `Pointwise(m, container)` | `argument` contains the same number | | `IsFalse()` | `argument` evaluates to `false` |
: : of elements as in `container`, and : : : in a Boolean context. :
: : for all i, (the i-th element in : | `IsSubsetOf({e0, e1, ..., en})`, | `argument` matches |
: : `argument`, the i-th element in : : `IsSubsetOf(a_container)`, : `UnorderedElementsAre(x0, x1, :
: : `container`) match `m`, which is a : : `IsSubsetOf(begin, end)`, : ..., xk)` for some subset `{x0, :
: : matcher on 2-tuples. E.g. : : `IsSubsetOf(array)`, or : x1, ..., xk}` of the expected :
: : `Pointwise(Le(), upper_bounds)` : : `IsSubsetOf(array, count)` : matchers. :
: : verifies that each element in : | `IsSupersetOf({e0, e1, ..., en})`, | Some subset of `argument` |
: : `argument` doesn't exceed the : : `IsSupersetOf(a_container)`, : matches :
: : corresponding element in : : `IsSupersetOf(begin, end)`, : `UnorderedElementsAre(`expected :
: : `upper_bounds`. See more detail : : `IsSupersetOf(array)`, or : matchers`)`. :
: : below. : : `IsSupersetOf(array, count)` : :
| `SizeIs(m)` | `argument` is a container whose size | | `IsTrue()` | `argument` evaluates to `true` |
: : matches `m`. E.g. `SizeIs(2)` or : : : in a Boolean context. :
: : `SizeIs(Lt(2))`. : | `Pointwise(m, container)`, `Pointwise(m, | `argument` contains the same |
| `UnorderedElementsAre(e0, e1, ..., | `argument` has `n + 1` elements, and | : {e0, e1, ..., en})` : number of elements as in :
: en)` : under some permutation each element : : : `container`, and for all i, (the :
: : i-th element in `argument`, the :
: : i-th element in `container`) :
: : match `m`, which is a matcher on :
: : 2-tuples. E.g. `Pointwise(Le(), :
: : upper_bounds)` verifies that :
: : each element in `argument` :
: : doesn't exceed the corresponding :
: : element in `upper_bounds`. See :
: : more detail below. :
| `SizeIs(m)` | `argument` is a container whose |
: : size matches `m`. E.g. :
: : `SizeIs(2)` or `SizeIs(Lt(2))`. :
| `UnorderedElementsAre(e0, e1, ..., en)` | `argument` has `n + 1` elements, |
: : and under *some* permutation of :
: : the elements, each element :
: : matches an `ei` (for a different : : : matches an `ei` (for a different :
: : `i`), which can be a value or a : : : `i`), which can be a value or a :
: : matcher. 0 to 10 arguments are : : : matcher. :
: : allowed. : | `UnorderedElementsAreArray({e0, e1, ..., | The same as |
| `UnorderedElementsAreArray({ e0, e1, | The same as `UnorderedElementsAre()` | : en})`, : `UnorderedElementsAre()` except :
: ..., en })`, : except that the expected element : : `UnorderedElementsAreArray(a_container)`, : that the expected element :
: `UnorderedElementsAreArray(array)`, : values/matchers come from an : : `UnorderedElementsAreArray(begin, end)`, : values/matchers come from an :
: or `UnorderedElementsAreArray(array, : initializer list, STL-style : : `UnorderedElementsAreArray(array)`, or : initializer list, STL-style :
: count)` : container, or C-style array. : : `UnorderedElementsAreArray(array, count)` : container, iterator range, or :
| `WhenSorted(m)` | When `argument` is sorted using the | : : C-style array. :
: : `<` operator, it matches container : | `UnorderedPointwise(m, container)`, | Like `Pointwise(m, container)`, |
: : matcher `m`. E.g. : : `UnorderedPointwise(m, {e0, e1, ..., : but ignores the order of :
: : `WhenSorted(ElementsAre(1, 2, 3))` : : en})` : elements. :
: : verifies that `argument` contains : | `WhenSorted(m)` | When `argument` is sorted using |
: : elements `1`, `2`, and `3`, ignoring : : : the `<` operator, it matches :
: : order. : : : container matcher `m`. E.g. :
| `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, except | : : `WhenSorted(ElementsAre(1, 2, :
: : that the given comparator instead of : : : 3))` verifies that `argument` :
: : `<` is used to sort `argument`. E.g. : : : contains elements 1, 2, and 3, :
: : `WhenSortedBy(std\:\:greater<int>(), : : : ignoring order. :
| `WhenSortedBy(comparator, m)` | The same as `WhenSorted(m)`, |
: : except that the given comparator :
: : instead of `<` is used to sort :
: : `argument`. E.g. :
: : `WhenSortedBy(std\:\:greater(), :
: : ElementsAre(3, 2, 1))`. : : : ElementsAre(3, 2, 1))`. :
**Notes:** **Notes:**

View File

@ -1,6 +1,6 @@
## Googletest Mocking (gMock) Cookbook ## Googletest Mocking (gMock) Cookbook
<!-- GOOGLETEST_CM0011 DO NOT DELETE --> <!-- GOOGLETEST_CM0012 DO NOT DELETE -->
You can find recipes for using gMock here. If you haven't yet, please read You can find recipes for using gMock here. If you haven't yet, please read
[this](for_dummies.md) first to make sure you understand the basics. [this](for_dummies.md) first to make sure you understand the basics.
@ -154,7 +154,7 @@ class MockStack : public StackInterface<Elem> {
#### Mocking Non-virtual Methods {#MockingNonVirtualMethods} #### Mocking Non-virtual Methods {#MockingNonVirtualMethods}
gMock can mock non-virtual functions to be used in Hi-perf dependency gMock can mock non-virtual functions to be used in Hi-perf dependency
injection.<!-- GOOGLETEST_CM0016 DO NOT DELETE -->. injection.<!-- GOOGLETEST_CM0017 DO NOT DELETE -->.
In this case, instead of sharing a common base class with the real class, your In this case, instead of sharing a common base class with the real class, your
mock class will be *unrelated* to the real class, but contain methods with the mock class will be *unrelated* to the real class, but contain methods with the
@ -1455,7 +1455,7 @@ mock object and gMock.
#### Knowing When to Expect {#UseOnCall} #### Knowing When to Expect {#UseOnCall}
<!-- GOOGLETEST_CM0017 DO NOT DELETE --> <!-- GOOGLETEST_CM0018 DO NOT DELETE -->
**`ON_CALL`** is likely the *single most under-utilized construct* in gMock. **`ON_CALL`** is likely the *single most under-utilized construct* in gMock.

View File

@ -1,6 +1,6 @@
## Googletest Mocking (gMock) for Dummies {#GMockForDummies} ## Googletest Mocking (gMock) for Dummies {#GMockForDummies}
<!-- GOOGLETEST_CM0012 DO NOT DELETE --> <!-- GOOGLETEST_CM0013 DO NOT DELETE -->
### What Is gMock? ### What Is gMock?
@ -499,7 +499,7 @@ always return 100 as `n++` is only evaluated once. Similarly, `Return(new Foo)`
will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will will create a new `Foo` object when the `EXPECT_CALL()` is executed, and will
return the same pointer every time. If you want the side effect to happen every return the same pointer every time. If you want the side effect to happen every
time, you need to define a custom action, which we'll teach in the time, you need to define a custom action, which we'll teach in the
[cook book](http://<!-- GOOGLETEST_CM0011 DO NOT DELETE -->). [cook book](http://<!-- GOOGLETEST_CM0012 DO NOT DELETE -->).
Time for another quiz! What do you think the following means? Time for another quiz! What do you think the following means?

View File

@ -1,6 +1,6 @@
## Legacy gMock FAQ {#GMockFaq} ## Legacy gMock FAQ {#GMockFaq}
<!-- GOOGLETEST_CM0020 DO NOT DELETE --> <!-- GOOGLETEST_CM0021 DO NOT DELETE -->
### When I call a method on my mock object, the method for the real object is invoked instead. What's the problem? ### When I call a method on my mock object, the method for the real object is invoked instead. What's the problem?

View File

@ -174,9 +174,9 @@ We list the most frequently used macros below. For a complete list, see file
### Multi-threaded Tests ### Multi-threaded Tests
Google Test is thread-safe where the pthread library is available. After Google Test is thread-safe where the pthread library is available. After
`#include "gtest/gtest.h"`, you can check the `GTEST_IS_THREADSAFE` macro to see `#include "gtest/gtest.h"`, you can check the
whether this is the case (yes if the macro is `#defined` to 1, no if it's `GTEST_IS_THREADSAFE` macro to see whether this is the case (yes if the macro is
undefined.). `#defined` to 1, no if it's undefined.).
If Google Test doesn't correctly detect whether pthread is available in your If Google Test doesn't correctly detect whether pthread is available in your
environment, you can force it with environment, you can force it with

View File

@ -1,6 +1,6 @@
# Advanced googletest Topics # Advanced googletest Topics
<!-- GOOGLETEST_CM0015 DO NOT DELETE --> <!-- GOOGLETEST_CM0016 DO NOT DELETE -->
## Introduction ## Introduction
@ -385,7 +385,7 @@ using ::testing::StartsWith;
``` ```
Read this Read this
[recipe](https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#using-matchers-in-googletest-assertions) [recipe](../../googlemock/docs/cook_book.md#using-matchers-in-googletest-assertions)
in the gMock Cookbook for more details. in the gMock Cookbook for more details.
gMock has a rich set of matchers. You can do many things googletest cannot do gMock has a rich set of matchers. You can do many things googletest cannot do

View File

@ -1,6 +1,6 @@
# Googletest FAQ # Googletest FAQ
<!-- GOOGLETEST_CM0013 DO NOT DELETE --> <!-- GOOGLETEST_CM0014 DO NOT DELETE -->
## Why should test suite names and test names not contain underscore? ## Why should test suite names and test names not contain underscore?
@ -332,7 +332,7 @@ You may still want to use `SetUp()/TearDown()` in the following cases:
* In the body of a constructor (or destructor), it's not possible to use the * In the body of a constructor (or destructor), it's not possible to use the
`ASSERT_xx` macros. Therefore, if the set-up operation could cause a fatal `ASSERT_xx` macros. Therefore, if the set-up operation could cause a fatal
test failure that should prevent the test from running, it's necessary to test failure that should prevent the test from running, it's necessary to
use `abort` <!-- GOOGLETEST_CM0014 DO NOT DELETE --> and abort the whole test executable, use `abort` <!-- GOOGLETEST_CM0015 DO NOT DELETE --> and abort the whole test executable,
or to use `SetUp()` instead of a constructor. or to use `SetUp()` instead of a constructor.
* If the tear-down operation could throw an exception, you must use * If the tear-down operation could throw an exception, you must use
`TearDown()` as opposed to the destructor, as throwing in a destructor leads `TearDown()` as opposed to the destructor, as throwing in a destructor leads

View File

@ -1,25 +1,24 @@
## Using GoogleTest from various build systems ## ## Using GoogleTest from various build systems
GoogleTest comes with pkg-config files that can be used to determine all GoogleTest comes with pkg-config files that can be used to determine all
necessary flags for compiling and linking to GoogleTest (and GoogleMock). necessary flags for compiling and linking to GoogleTest (and GoogleMock).
Pkg-config is a standardised plain-text format containing Pkg-config is a standardised plain-text format containing
* the includedir (-I) path * the includedir (-I) path
* necessary macro (-D) definitions * necessary macro (-D) definitions
* further required flags (-pthread) * further required flags (-pthread)
* the library (-L) path * the library (-L) path
* the library (-l) to link to * the library (-l) to link to
All current build systems support pkg-config in one way or another. For All current build systems support pkg-config in one way or another. For all
all examples here we assume you want to compile the sample examples here we assume you want to compile the sample
`samples/sample3_unittest.cc`. `samples/sample3_unittest.cc`.
### CMake
### CMake ###
Using `pkg-config` in CMake is fairly easy: Using `pkg-config` in CMake is fairly easy:
``` cmake ```cmake
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
cmake_policy(SET CMP0048 NEW) cmake_policy(SET CMP0048 NEW)
@ -43,11 +42,10 @@ that all libraries have been compiled with threading enabled. In addition,
GoogleTest might also require `-pthread` in the compiling step, and as such GoogleTest might also require `-pthread` in the compiling step, and as such
splitting the pkg-config `Cflags` variable into include dirs and macros for splitting the pkg-config `Cflags` variable into include dirs and macros for
`target_compile_definitions()` might still miss this). The same recommendation `target_compile_definitions()` might still miss this). The same recommendation
goes for using `_LDFLAGS` over the more commonplace `_LIBRARIES`, which goes for using `_LDFLAGS` over the more commonplace `_LIBRARIES`, which happens
happens to discard `-L` flags and `-pthread`. to discard `-L` flags and `-pthread`.
### Autotools
### Autotools ###
Finding GoogleTest in Autoconf and using it from Automake is also fairly easy: Finding GoogleTest in Autoconf and using it from Automake is also fairly easy:
@ -77,8 +75,7 @@ testapp_CXXFLAGS = $(GTEST_CFLAGS)
testapp_LDADD = $(GTEST_LIBS) testapp_LDADD = $(GTEST_LIBS)
``` ```
### Meson
### Meson ###
Meson natively uses pkgconfig to query dependencies: Meson natively uses pkgconfig to query dependencies:
@ -96,13 +93,12 @@ testapp = executable(
test('first_and_only_test', testapp) test('first_and_only_test', testapp)
``` ```
### Plain Makefiles
### Plain Makefiles ### Since `pkg-config` is a small Unix command-line utility, it can be used in
handwritten `Makefile`s too:
Since `pkg-config` is a small Unix command-line utility, it can be used ```Makefile
in handwritten `Makefile`s too:
``` Makefile
GTEST_CFLAGS = `pkg-config --cflags gtest_main` GTEST_CFLAGS = `pkg-config --cflags gtest_main`
GTEST_LIBS = `pkg-config --libs gtest_main` GTEST_LIBS = `pkg-config --libs gtest_main`
@ -120,12 +116,11 @@ testapp.o: samples/sample3_unittest.cc
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $< -c -o $@ $(GTEST_CFLAGS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $< -c -o $@ $(GTEST_CFLAGS)
``` ```
### Help! pkg-config can't find GoogleTest!
### Help! pkg-config can't find GoogleTest! ###
Let's say you have a `CMakeLists.txt` along the lines of the one in this Let's say you have a `CMakeLists.txt` along the lines of the one in this
tutorial and you try to run `cmake`. It is very possible that you get a tutorial and you try to run `cmake`. It is very possible that you get a failure
failure along the lines of: along the lines of:
``` ```
-- Checking for one of the modules 'gtest_main' -- Checking for one of the modules 'gtest_main'
@ -135,9 +130,9 @@ CMake Error at /usr/share/cmake/Modules/FindPkgConfig.cmake:640 (message):
These failures are common if you installed GoogleTest yourself and have not These failures are common if you installed GoogleTest yourself and have not
sourced it from a distro or other package manager. If so, you need to tell sourced it from a distro or other package manager. If so, you need to tell
pkg-config where it can find the `.pc` files containing the information. pkg-config where it can find the `.pc` files containing the information. Say you
Say you installed GoogleTest to `/usr/local`, then it might be that the installed GoogleTest to `/usr/local`, then it might be that the `.pc` files are
`.pc` files are installed under `/usr/local/lib64/pkgconfig`. If you set installed under `/usr/local/lib64/pkgconfig`. If you set
``` ```
export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig

View File

@ -164,7 +164,7 @@ you'll get a compiler error. We used to require the arguments to support the
`<<` is supported, it will be called to print the arguments when the assertion `<<` is supported, it will be called to print the arguments when the assertion
fails; otherwise googletest will attempt to print them in the best way it can. fails; otherwise googletest will attempt to print them in the best way it can.
For more details and how to customize the printing of the arguments, see For more details and how to customize the printing of the arguments, see
[documentation](https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#teaching-gmock-how-to-print-your-values) [documentation](../../googlemock/docs/cook_book.md#teaching-gmock-how-to-print-your-values)
These assertions can work with a user-defined type, but only if you define the These assertions can work with a user-defined type, but only if you define the
corresponding comparison operator (e.g. `==`, `<`, etc). Since this is corresponding comparison operator (e.g. `==`, `<`, etc). Since this is

View File

@ -1,52 +1,51 @@
<b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming. <b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming.
# The Problem # # The Problem
Template and macro libraries often need to define many classes, Template and macro libraries often need to define many classes, functions, or
functions, or macros that vary only (or almost only) in the number of macros that vary only (or almost only) in the number of arguments they take.
arguments they take. It's a lot of repetitive, mechanical, and It's a lot of repetitive, mechanical, and error-prone work.
error-prone work.
Variadic templates and variadic macros can alleviate the problem. Variadic templates and variadic macros can alleviate the problem. However, while
However, while both are being considered by the C++ committee, neither both are being considered by the C++ committee, neither is in the standard yet
is in the standard yet or widely supported by compilers. Thus they or widely supported by compilers. Thus they are often not a good choice,
are often not a good choice, especially when your code needs to be especially when your code needs to be portable. And their capabilities are still
portable. And their capabilities are still limited. limited.
As a result, authors of such libraries often have to write scripts to As a result, authors of such libraries often have to write scripts to generate
generate their implementation. However, our experience is that it's their implementation. However, our experience is that it's tedious to write such
tedious to write such scripts, which tend to reflect the structure of scripts, which tend to reflect the structure of the generated code poorly and
the generated code poorly and are often hard to read and edit. For are often hard to read and edit. For example, a small change needed in the
example, a small change needed in the generated code may require some generated code may require some non-intuitive, non-trivial changes in the
non-intuitive, non-trivial changes in the script. This is especially script. This is especially painful when experimenting with the code.
painful when experimenting with the code.
# Our Solution # # Our Solution
Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta
Programming, or Practical Utility for Meta Programming, whichever you Programming, or Practical Utility for Meta Programming, whichever you prefer) is
prefer) is a simple meta-programming tool for C++. The idea is that a a simple meta-programming tool for C++. The idea is that a programmer writes a
programmer writes a `foo.pump` file which contains C++ code plus meta `foo.pump` file which contains C++ code plus meta code that manipulates the C++
code that manipulates the C++ code. The meta code can handle code. The meta code can handle iterations over a range, nested iterations, local
iterations over a range, nested iterations, local meta variable meta variable definitions, simple arithmetic, and conditional expressions. You
definitions, simple arithmetic, and conditional expressions. You can can view it as a small Domain-Specific Language. The meta language is designed
view it as a small Domain-Specific Language. The meta language is to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, for example) and
designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, concise, making Pump code intuitive and easy to maintain.
for example) and concise, making Pump code intuitive and easy to
maintain.
## Highlights ## ## Highlights
* The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms. * The implementation is in a single Python script and thus ultra portable: no
* Pump tries to be smart with respect to [Google's style guide](https://github.com/google/styleguide): it breaks long lines (easy to have when they are generated) at acceptable places to fit within 80 columns and indent the continuation lines correctly. build or installation is needed and it works cross platforms.
* The format is human-readable and more concise than XML. * Pump tries to be smart with respect to
* The format works relatively well with Emacs' C++ mode. [Google's style guide](https://github.com/google/styleguide): it breaks long
lines (easy to have when they are generated) at acceptable places to fit
within 80 columns and indent the continuation lines correctly.
* The format is human-readable and more concise than XML.
* The format works relatively well with Emacs' C++ mode.
## Examples ## ## Examples
The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line): The following Pump code (where meta keywords start with `$`, `[[` and `]]` are
meta brackets, and `$$` starts a meta comment that ends with the line):
``` ```
$var n = 3 $$ Defines a meta variable n. $var n = 3 $$ Defines a meta variable n.
@ -71,7 +70,7 @@ $if i == 0 [[
will be translated by the Pump compiler to: will be translated by the Pump compiler to:
``` cpp ```cpp
// Foo0 does blah for 0-ary predicates. // Foo0 does blah for 0-ary predicates.
template <size_t N> template <size_t N>
class Foo0 { class Foo0 {
@ -105,9 +104,10 @@ Func($for i + [[a$i]]);
$$ The text between i and [[ is the separator between iterations. $$ The text between i and [[ is the separator between iterations.
``` ```
will generate one of the following lines (without the comments), depending on the value of `n`: will generate one of the following lines (without the comments), depending on
the value of `n`:
``` cpp ```cpp
Func(); // If n is 0. Func(); // If n is 0.
Func(a1); // If n is 1. Func(a1); // If n is 1.
Func(a1 + a2); // If n is 2. Func(a1 + a2); // If n is 2.
@ -115,32 +115,38 @@ Func(a1 + a2 + a3); // If n is 3.
// And so on... // And so on...
``` ```
## Constructs ## ## Constructs
We support the following meta programming constructs: We support the following meta programming constructs:
| `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. | | `$var id = exp` | Defines a named constant value. `$id` is |
|:----------------|:-----------------------------------------------------------------------------------------------| : : valid util the end of the current meta :
| `$range id exp..exp` | Sets the range of an iteration variable, which can be reused in multiple loops later. | : : lexical block. :
| `$for id sep [[ code ]]` | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. | | :------------------------------- | :--------------------------------------- |
| `$range id exp..exp` | Sets the range of an iteration variable, |
: : which can be reused in multiple loops :
: : later. :
| `$for id sep [[ code ]]` | Iteration. The range of `id` must have |
: : been defined earlier. `$id` is valid in :
: : `code`. :
| `$($)` | Generates a single `$` character. | | `$($)` | Generates a single `$` character. |
| `$id` | Value of the named constant or iteration variable. | | `$id` | Value of the named constant or iteration |
: : variable. :
| `$(exp)` | Value of the expression. | | `$(exp)` | Value of the expression. |
| `$if exp [[ code ]] else_branch` | Conditional. | | `$if exp [[ code ]] else_branch` | Conditional. |
| `[[ code ]]` | Meta lexical block. | | `[[ code ]]` | Meta lexical block. |
| `cpp_code` | Raw C++ code. | | `cpp_code` | Raw C++ code. |
| `$$ comment` | Meta comment. | | `$$ comment` | Meta comment. |
**Note:** To give the user some freedom in formatting the Pump source **Note:** To give the user some freedom in formatting the Pump source code, Pump
code, Pump ignores a new-line character if it's right after `$for foo` ignores a new-line character if it's right after `$for foo` or next to `[[` or
or next to `[[` or `]]`. Without this rule you'll often be forced to write `]]`. Without this rule you'll often be forced to write very long lines to get
very long lines to get the desired output. Therefore sometimes you may the desired output. Therefore sometimes you may need to insert an extra new-line
need to insert an extra new-line in such places for a new-line to show in such places for a new-line to show up in your output.
up in your output.
## Grammar ## ## Grammar
``` ebnf ```ebnf
code ::= atomic_code* code ::= atomic_code*
atomic_code ::= $var id = exp atomic_code ::= $var id = exp
| $var id = [[ code ]] | $var id = [[ code ]]
@ -159,19 +165,26 @@ else_branch ::= $else [[ code ]]
exp ::= simple_expression_in_Python_syntax exp ::= simple_expression_in_Python_syntax
``` ```
## Code ## ## Code
You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py).
very unpolished and lacks automated tests, although it has been It is still very unpolished and lacks automated tests, although it has been
successfully used many times. If you find a chance to use it in your successfully used many times. If you find a chance to use it in your project,
project, please let us know what you think! We also welcome help on please let us know what you think! We also welcome help on improving Pump.
improving Pump.
## Real Examples ## ## Real Examples
You can find real-world applications of Pump in [Google Test](https://github.com/google/googletest/tree/master/googletest) and [Google Mock](https://github.com/google/googletest/tree/master/googlemock). The source file `foo.h.pump` generates `foo.h`. You can find real-world applications of Pump in
[Google Test](https://github.com/google/googletest/tree/master/googletest) and
[Google Mock](https://github.com/google/googletest/tree/master/googlemock). The
source file `foo.h.pump` generates `foo.h`.
## Tips ## ## Tips
* If a meta variable is followed by a letter or digit, you can separate them using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` generate `Foo1Helper` when `j` is 1. * If a meta variable is followed by a letter or digit, you can separate them
* To avoid extra-long Pump source lines, you can break a line anywhere you want by inserting `[[]]` followed by a new line. Since any new-line character next to `[[` or `]]` is ignored, the generated code won't contain this new line. using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper`
generate `Foo1Helper` when `j` is 1.
* To avoid extra-long Pump source lines, you can break a line anywhere you
want by inserting `[[]]` followed by a new line. Since any new-line
character next to `[[` or `]]` is ignored, the generated code won't contain
this new line.