Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 1 | # API Example Code |
| 2 | |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 3 | This directory contains the API sample code that is referenced from the API |
| 4 | documentation in the framework. |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 5 | |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 6 | The examples can be run individually by just specifying the path to the example |
| 7 | on the command line (or in the run configuration of an IDE). |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 8 | |
Alberto | b44cbe1 | 2022-02-28 21:41:20 +0100 | [diff] [blame] | 9 | For example (no pun intended!), to run the first example from the `Curve2D` |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 10 | class in Chrome, you would run it like so from the [api](.) directory: |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 11 | |
| 12 | ``` |
| 13 | % flutter run -d chrome lib/animation/curves/curve2_d.0.dart |
| 14 | ``` |
| 15 | |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 16 | All of these same examples are available on the API docs site. For instance, the |
| 17 | example above is available on [this page]( |
| 18 | https://api.flutter.dev/flutter/animation/Curve2D-class.html#animation.Curve2D.1). |
| 19 | Most of the samples are available as interactive examples in |
| 20 | [Dartpad](https://dartpad.dev), but some (the ones marked with `{@tool sample}` |
| 21 | in the framework source code), just don't make sense on the web, and so are |
| 22 | available as standalone examples that can be run here. For instance, setting the |
| 23 | system overlay style doesn't make sense on the web (it only changes the |
| 24 | notification area background color on Android), so you can run the example for |
| 25 | that on an Android device like so: |
| 26 | |
| 27 | ``` |
| 28 | % flutter run -d MyAndroidDevice lib/services/system_chrome/system_chrome.set_system_u_i_overlay_style.1.dart |
| 29 | ``` |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 30 | |
| 31 | ## Naming |
| 32 | |
| 33 | The naming scheme for the files is similar to the hierarchy under |
| 34 | [packages/flutter/lib/src](../../packages/flutter/lib/src), except that the |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 35 | files are represented as directories (without the `.dart` suffix), and each |
| 36 | sample in the file is a separate file in that directory. So, for the example |
| 37 | above, where the examples are from the |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 38 | [packages/flutter/lib/src/animation/curves.dart](../../packages/flutter/lib/src/animation/curves.dart) |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 39 | file, the `Curve2D` class, the first sample (hence the index "0") for that |
| 40 | symbol resides in the file named |
| 41 | [lib/animation/curves/curve2_d.0.dart](lib/animation/curves/curve2_d.0.dart). |
| 42 | |
| 43 | Symbol names are converted from "CamelCase" to "snake_case". Dots are left |
| 44 | between symbol names, so the first example for symbol |
| 45 | `InputDecoration.prefixIconConstraints` would be converted to |
| 46 | `input_decoration.prefix_icon_constraints.0.dart`. |
| 47 | |
| 48 | If the same example is linked to from multiple symbols, the source will be in |
| 49 | the canonical location for one of the symbols, and the link in the API docs |
| 50 | block for the other symbols will point to the first symbol's example location. |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 51 | |
| 52 | ## Authoring |
| 53 | |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 54 | > For more detailed information about authoring examples, see |
| 55 | > [the snippets package](https://pub.dev/packages/snippets). |
| 56 | |
| 57 | When authoring examples, first place a block in the Dartdoc documentation for |
| 58 | the symbol you would like to attach it to. Here's what it might look like if you |
| 59 | wanted to add a new example to the `Curve2D` class: |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 60 | |
| 61 | ```dart |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 62 | /// {@tool dartpad} |
| 63 | /// Write a description of the example here. This description will appear in the |
| 64 | /// API web documentation to introduce the example. |
| 65 | /// |
| 66 | /// ** See code in examples/api/lib/animation/curves/curve2_d.0.dart ** |
| 67 | /// {@end-tool} |
| 68 | ``` |
| 69 | |
| 70 | The "See code in" line needs to be formatted exactly as above, with no wrapping |
| 71 | or newlines, one space after the "`**`" at the beginning, and one space before |
| 72 | the "`**`" at the end, and the words "See code in" at the beginning of the line. |
| 73 | This is what the snippets tool and the IDE use when finding the example source |
| 74 | code that you are creating. |
| 75 | |
| 76 | Use `{@tool dartpad}` for Dartpad examples, and use `{@tool sample}` for |
| 77 | examples that shouldn't be run/shown in Dartpad. |
| 78 | |
| 79 | Once that comment block is inserted in the source code, create a new file at the |
Youssef Attia | e9230ba | 2022-06-06 13:24:00 -0700 | [diff] [blame] | 80 | appropriate path under [`examples/api`](.) that matches the location of the |
| 81 | source file they are linked from, and are named for the symbol they are attached |
| 82 | to, in lower_snake_case, with an index relating to their order within the doc |
| 83 | comment. So, for the `Curve2D` case, since it's in the `animation` package, in |
| 84 | a file called `curves.dart`, and it's the first example, it goes in |
| 85 | `examples/api/lib/animation/curves/curve2_d.0.dart`. |
| 86 | |
| 87 | You should also add tests for your sample code under [`examples/api/test`](./test). |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 88 | |
| 89 | The entire example should be in a single file, so that Dartpad can load it. |
| 90 | |
| 91 | Only packages that can be loaded by Dartpad may be imported. If you use one that |
| 92 | hasn't been used in an example before, you may have to add it to the |
| 93 | [pubspec.yaml](pubspec.yaml) in the api directory. |
| 94 | |
| 95 | ## Snippets |
| 96 | |
| 97 | There is another type of example that can also be authored, using `{@tool |
| 98 | snippet}`. Snippet examples are just written inline in the source, like so: |
| 99 | |
| 100 | ```dart |
| 101 | /// {@tool dartpad} |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 102 | /// Write a description of the example here. This description will appear in the |
| 103 | /// API web documentation to introduce the example. |
| 104 | /// |
| 105 | /// ```dart |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 106 | /// // Sample code goes here, e.g.: |
| 107 | /// const Widget emptyBox = SizedBox(); |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 108 | /// ``` |
| 109 | /// {@end-tool} |
| 110 | ``` |
| 111 | |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 112 | The source for these snippets isn't stored under the [`examples/api`](.) |
| 113 | directory, or available in Dartpad in the API docs, since they're not intended |
| 114 | to be runnable, they just show some incomplete snippet of example code. It must |
| 115 | compile (in the context of the sample analyzer), but doesn't need to do |
| 116 | anything. See [the snippets documentation]( |
| 117 | https://pub.dev/packages/snippets#snippet-tool) for more information about the |
| 118 | context that the analyzer uses. |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 119 | |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 120 | ## Writing Tests |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 121 | |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 122 | Examples are required to have tests. There is already a "smoke test" that runs |
| 123 | all the API examples, just to make sure that they start up without crashing. In |
| 124 | addition, we also require writing tests of functionality in the examples, and |
| 125 | generally just do what we normally do for writing tests. The one thing that |
| 126 | makes it more challenging for the examples is that they can't really be written |
| 127 | for testability in any obvious way, since that would probably complicate the |
| 128 | example and make it harder to explain. |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 129 | |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 130 | As an example, in regular framework code, you might include a parameter for a |
| 131 | `Platform` object that can be overridden by a test to supply a dummy platform, |
| 132 | but in the example, this would be unnecessary complexity for the example. In all |
| 133 | other ways, these are just normal tests. |
Greg Spencer | 33403bd | 2021-08-25 09:45:12 -0700 | [diff] [blame] | 134 | |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 135 | Tests go into a directory under [test](./test) that matches their location under |
| 136 | [lib](./lib). They are named the same as the example they are testing, with |
| 137 | `_test.dart` at the end, like other tests. For instance, a `LayoutBuilder` |
| 138 | example that resides in [`lib/widgets/layout_builder/layout_builder.0.dart`]( |
| 139 | ./lib/widgets/layout_builder/layout_builder.0.dart) would have its tests in a |
Youssef Attia | e9230ba | 2022-06-06 13:24:00 -0700 | [diff] [blame] | 140 | file named [`test/widgets/layout_builder/layout_builder.0_test.dart`]( |
Greg Spencer | 983cbb2 | 2021-10-04 13:53:02 -0700 | [diff] [blame] | 141 | ./test/widgets/layout_builder/layout_builder.0_test.dart) |