Skip to content

Commit 68ea89f

Browse files
committed
Merge branch 'main' into feat-ros-8.4
2 parents 576726b + 0a9dede commit 68ea89f

File tree

234 files changed

+34004
-1557
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

234 files changed

+34004
-1557
lines changed

assets/css/index.css

Lines changed: 596 additions & 20 deletions
Large diffs are not rendered by default.

build/components/component.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,11 @@ def _copy_examples(self):
273273
example_metadata['sourceUrl'] = (
274274
f'{ex["git_uri"]}/tree/{default_branch}/{ex["path"]}/{os.path.basename(f)}'
275275
)
276+
277+
# Add binderId only if it exists
278+
if e.binder_id:
279+
example_metadata['binderId'] = e.binder_id
280+
276281
examples = self._root._examples
277282
if example_id not in examples:
278283
examples[example_id] = {}

build/components/example.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
STEP_START = 'STEP_START'
99
STEP_END = 'STEP_END'
1010
EXAMPLE = 'EXAMPLE:'
11+
BINDER_ID = 'BINDER_ID'
1112
GO_OUTPUT = 'Output:'
1213
TEST_MARKER = {
1314
'java': '@Test',
@@ -16,7 +17,8 @@
1617
'java-reactive': '@Test',
1718
'c#': r'\[Fact]|\[SkipIfRedis\(.*\)]',
1819
'c#-sync': r'\[Fact]|\[SkipIfRedis\(.*\)]',
19-
'c#-async': r'\[Fact]|\[SkipIfRedis\(.*\)]'
20+
'c#-async': r'\[Fact]|\[SkipIfRedis\(.*\)]',
21+
'rust': r'#\[test]|#\[cfg\(test\)]|#\[tokio::test]'
2022
}
2123
PREFIXES = {
2224
'python': '#',
@@ -44,6 +46,7 @@ class Example(object):
4446
hidden = None
4547
highlight = None
4648
named_steps = None
49+
binder_id = None
4750

4851
def __init__(self, language: str, path: str) -> None:
4952
logging.debug("ENTERING: ")
@@ -58,6 +61,7 @@ def __init__(self, language: str, path: str) -> None:
5861
self.hidden = []
5962
self.highlight = []
6063
self.named_steps = {}
64+
self.binder_id = None
6165
self.make_ranges()
6266
self.persist(self.path)
6367
logging.debug("EXITING: ")
@@ -87,6 +91,7 @@ def make_ranges(self) -> None:
8791
rstart = re.compile(f'{PREFIXES[self.language]}\\s?{REMOVE_START}')
8892
rend = re.compile(f'{PREFIXES[self.language]}\\s?{REMOVE_END}')
8993
exid = re.compile(f'{PREFIXES[self.language]}\\s?{EXAMPLE}')
94+
binder = re.compile(f'{PREFIXES[self.language]}\\s?{BINDER_ID}\\s+([a-zA-Z0-9_-]+)')
9095
go_output = re.compile(f'{PREFIXES[self.language]}\\s?{GO_OUTPUT}')
9196
go_comment = re.compile(f'{PREFIXES[self.language]}')
9297
test_marker = re.compile(f'{TEST_MARKER.get(self.language)}')
@@ -149,6 +154,13 @@ def make_ranges(self) -> None:
149154
elif re.search(exid, l):
150155
output = False
151156
pass
157+
elif re.search(binder, l):
158+
# Extract BINDER_ID hash value
159+
match = re.search(binder, l)
160+
if match:
161+
self.binder_id = match.group(1)
162+
logging.debug(f'Found BINDER_ID: {self.binder_id} in {self.path}:L{curr+1}')
163+
output = False
152164
elif self.language == "go" and re.search(go_output, l):
153165
if output:
154166
logging.error("Nested Go Output anchor in {self.path}:L{curr+1} - aborting.")

build/local_examples.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ def process_local_examples(local_examples_dir: str = 'local_examples',
180180
'sourceUrl': None # Local examples don't have source URLs
181181
}
182182

183+
# Add binderId only if it exists
184+
if example.binder_id:
185+
example_metadata['binderId'] = example.binder_id
186+
183187
examples_data[example_id][client_name] = example_metadata
184188
logging.info(f"Processed {client_name} example for {example_id}")
185189

build/tcedocs/README.md

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
# How to add a multi-language code examples to redis.io
2+
3+
## Configure Hugo
4+
5+
The website redis.io is built from Markdown files using [Hugo](https://gohugo.io). Multi-language code example support is configured in Hugo by adding information to its configuration file, `config.toml`.
6+
There are two sections that need to updated when new languages are added.
7+
8+
1. In the `[params]` section:
9+
10+
```toml
11+
clientsExamples = ["Python", "Node.js", "Java-Sync", "Java-Async", "Java-Reactive", "Go", "C#", "RedisVL", "PHP"]
12+
```
13+
14+
The order of the `clientsExamples` list matters: it's the order in which the language tabs are presented for each code example.
15+
1. In the `[params.clientsConfig]` section:
16+
17+
```toml
18+
[params.clientsConfig]
19+
"Python"={quickstartSlug="redis-py"}
20+
"Node.js"={quickstartSlug="nodejs"}
21+
"Java-sync"={quickstartSlug="jedis"}
22+
"Java-async"={quickstartSlug="lettuce"}
23+
"Java-reactive"={quickstartSlug="lettuce"}
24+
"Go"={quickstartSlug="go"}
25+
"C#"={quickstartSlug="dotnet"}
26+
"RedisVL"={quickstartSlug="redis-vl"}
27+
"PHP"={quickstartSlug="php"}
28+
```
29+
30+
This configuration, along with the configuration steps below, is used to control the behavior of the Hugo shortcode that was developed to show tabbed code examples.
31+
A shortcode is a simple snippet inside a content file that Hugo will render using a predefined template. This template can contain HTML and JavaScript.
32+
33+
### How to add a new programming language
34+
35+
#### Add the components file
36+
37+
The folder `data/components` contains one component configuration file for each supported language. These files contain information about the GitHub repos that house the code examples.
38+
39+
Here is the configuration file for Python, `redis_py.json`:
40+
41+
```json
42+
{
43+
"id": "redis_py",
44+
"type": "client",
45+
"name": "redis-py",
46+
"language": "Python",
47+
"label": "Python",
48+
"repository": {
49+
"git_uri": "https://github.com/redis/redis-py"
50+
},
51+
"examples": {
52+
"git_uri": "https://github.com/redis/redis-py",
53+
"path": "doctests",
54+
"pattern": "*.py"
55+
}
56+
}
57+
```
58+
59+
The `language` property needs to match the value that was added to the `config.toml` file in the previous step. The `label` property, while generally the same as `language`, may be set to a string that is different from `language`. For RedisVL, `language` is set to `Python` and `label` is set to `RedisVL`. The `examples` property points to a GitHub repository, a path under which examples should be searched, and a file name pattern. The current logic will scan for examples that fulfill the filename pattern within the given path.
60+
61+
#### Register the component file
62+
63+
Register your component file by adding it to the `clients` array in the `index.json` file, which resides in the the same folder as the per-language JSON files. The entry should match the file name prefix and ID of the component.
64+
65+
Here is an example:
66+
```json
67+
"clients": [
68+
"nredisstack",
69+
"go_redis",
70+
"node_redis",
71+
"php",
72+
"redis_py",
73+
"jedis",
74+
"lettuce_async",
75+
"lettuce_reactive",
76+
"redis_vl"
77+
]
78+
```
79+
80+
Code examples are pulled from the GitHub repo for each supported language at docs site build time.
81+
82+
### Verify that your language is supported by the source code file parser
83+
84+
Component handling is implemented in `build/components/component.py`. The example file parser that is used by it is implemented inside `build/components/example.py`. Add any language-specific information you need to have the build code support your language's examples.
85+
86+
```python
87+
TEST_MARKER = {
88+
'java': '@Test',
89+
'java-sync': '@Test',
90+
'java-async': '@Test',
91+
'java-reactive': '@Test',
92+
'c#': r'\[Fact]|\[SkipIfRedis\(.*\)]'
93+
}
94+
PREFIXES = {
95+
'python': '#',
96+
'node.js': '//',
97+
'java': '//',
98+
'java-sync': '//',
99+
'java-async': '//',
100+
'java-reactive': '//',
101+
'go': '//',
102+
'c#': '//',
103+
'redisvl': '#',
104+
'php': '//'
105+
}
106+
```
107+
108+
The `TEST_MARKER` dictionary maps programming languages to test framework annotations, which allows the parser to filter such source code lines out. The `PREFIXES` dictionary maps each language to its comment prefix. Python, for example, uses a hashtag (`#`) to start a comment.
109+
110+
## Understand special comments in the example source code files
111+
112+
Each code example uses special comments, such as `HIDE_START` and `REMOVE_START`, to control how the examples are displayed. The following list gives an explanation:
113+
114+
- `EXAMPLE: id`: Defines the identifier of the source code example file, where `id` is any common string (for example, `cmds_string`). IDs should only contain ASCII alphanumeric characters, underline characters (`_`), or hyphen characters (`-`). Do not use multibyte characters.
115+
- `BINDER_ID id`: Defines the [BinderHub](https://binderhub.readthedocs.io/en/latest/) commit hash for the example. This is used to generate a link to a BinderHub instance that will run the example.
116+
- `HIDE_START`: Starts a code block that should be *hidden* when showing the example. This code block will only become visible if **unhide** (the eye button) is clicked.
117+
- `HIDE_END`: Marks the end a hidden code block.
118+
- `REMOVE_START`: Starts a code block that should be entirely removed when the example is processed by the build code. This is useful for removing lines of code that do not contribute to the example but are needed to embed the code into a proper test case or framework. Good examples of such code blocks are imports of external libraries or test assertions.
119+
- `REMOVE_END`: Marks the end of a code block that should be removed from the example.
120+
- `STEP_START step-name`: Starts a code block that represents a specific step in a set of examples.
121+
- `STEP_END`: Marks the end of a code block that represents a specific step in a set of examples.
122+
123+
## Add examples to the client library or to the local_examples directory
124+
125+
Examples are added to either a client repo, or, temporarily, to the `local_examples` directory in the `redis.io/docs` repo.
126+
127+
### Add examples to the client libraries
128+
129+
Add a source code file to an appropriate client repo. Consult the /data/components/<client-component>.json file for the location.
130+
131+
| Programming Language | GitHub Repo | Default directory |
132+
|----------------------|-----------------------------------------------------|---------------------------------------------------|
133+
| C# | [NRedisStack](https://github.com/redis/NRedisStack) | `tests/Doc` |
134+
| Go | [go-redis](https://github.com/redis/go-redis) | `doctests` |
135+
| Java | [jedis](https://github.com/redis/jedis) | `src/test/java/io/redis/examples` |
136+
| | [Lettuce](https://github.com/redis/lettuce) | `src/test/java/io/redis/examples/async` or |
137+
| | | `src/test/java/io/redis/examples/reactive` |
138+
| Node.js | [node-redis](https://github.com/redis/node-redis) | `doctests` |
139+
| PHP | [Predis](https://github.com/predis/predis) | Examples, for now, are stored in `local_examples` |
140+
| Python | [redis-py](https://github.com/redis/redis-py) | `doctests` |
141+
| | [RedisVL](https://github.com/redis/redis-vl-python) | `doctests` |
142+
143+
### Add examples to the local_examples directory
144+
145+
At times, it can take quite a while to get new or updated examples through the review process. To make the examples available immediately on the docs site, you can place examples temporarily in the `local_examples/client-specific` directory. The manner in which files are added isn't terribly important, as the build code will recursively walk the entire directory, so it will find examples in any directory under `local_examples`.
146+
147+
```
148+
local_examples
149+
├── client-specific
150+
│   ├── go
151+
│   │   ...
152+
│   ├── jedis
153+
│   │   ...
154+
│   ├── lettuce-async
155+
│   │   ...
156+
│   ├── lettuce-reactive
157+
│   │   ...
158+
│   ├── nodejs
159+
│   │   ...
160+
│   └── redis-py
161+
│   ...
162+
```
163+
164+
## Add your example to the content page
165+
166+
In order to add a multi-language code example to a content page, use the `clients-example` shortcode:
167+
168+
```
169+
{{< clients-example id ... />}}
170+
```
171+
172+
The ID is the same one you used with `EXAMPLE: id` in the first line of your code example.
173+
174+
### Named versus positional parameters
175+
176+
The `clients-example` shortcode supports both positional and named parameters. The lion's share of current examples use positional parameters, but, going forward, names parameters should be used.
177+
178+
Named parameters:
179+
180+
- set: Name of the example set (required)
181+
- step: Example step name (required)
182+
- lang_filter: Language filter (optional, default: "")
183+
- max_lines: Maximum number of lines shown by default (optional, default: 100)
184+
- dft_tab_name: Custom first tab name (optional, default: ">_ Redis CLI")
185+
- dft_tab_link_title: Custom first tab footer link title (optional)
186+
- dft_tab_url: Custom first tab footer link URL (optional)
187+
- show_footer: Show footer (optional, default: true)
188+
189+
Positional parameters (for backward compatibility):
190+
191+
- 0: example set name
192+
- 1: step name
193+
- 2: language filter
194+
- 3: max lines
195+
- 4: custom first tab name
196+
- 5: custom first tab footer link title
197+
- 6: custom first tab footer link URL
198+
199+
### Examples
200+
201+
When converting existing content with redis-cli examples to the new format, you can wrap the existing redis-cli example:
202+
203+
```
204+
{{< clients-example set="set_and_get" step="" >}}
205+
> set mykey somevalue
206+
OK
207+
> get mykey
208+
"somevalue"
209+
{{< /clients-example >}}
210+
```
211+
212+
If the redis-cli example is too long you can hide some lines by specifying the limit as the fourth argument:
213+
214+
```
215+
{{< clients-example set="set_and_get" step="" lang_filter="" max_lines="2" >}}
216+
> set mykey somevalue
217+
OK
218+
> get mykey <-- this line will be hidden
219+
"somevalue" <-- this line will be hidden
220+
{{< /clients-example >}}
221+
```
222+
223+
To refer to a particular step placed in between `STEP_START stepname` and `STEP_END` comments in the code example, you should use the second argument to define the name of the step:
224+
225+
```
226+
{{< clients-example set="id" step="stepname" />}}
227+
```
228+
229+
If you need to embed an example for a specific programming language, the third argument should be defined:
230+
231+
```
232+
{{< clients-example set="id" step="stepname" lang_filter="lang" />}}
233+
```
234+
235+
The following example shows the `connect` step of a Python example:
236+
237+
```
238+
{{< clients-example set="set_and_get" step="connect" lang_filter="Python" />}}
239+
```
240+
The programming language name should match the value in the Hugo configuration file.

0 commit comments

Comments
 (0)