Skip to content

Commit ff5388c

Browse files
Merge pull request #2414 from redis/DOC-5963-landing-notebooks
DOC-5963 landing notebooks
2 parents d60de77 + ec830ea commit ff5388c

File tree

14 files changed

+353
-121
lines changed

14 files changed

+353
-121
lines changed

build/components/example.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
'java-async': '//',
2929
'java-reactive': '//',
3030
'go': '//',
31+
'c': '//',
3132
'c#': '//',
3233
'c#-sync': '//',
3334
'c#-async': '//',

build/local_examples.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
'.py': 'python',
2424
'.js': 'node.js',
2525
'.go': 'go',
26+
'.c': 'c',
27+
'.h': 'c',
2628
'.cs': 'c#',
2729
'.java': 'java',
2830
'.php': 'php',
@@ -34,6 +36,7 @@
3436
'python': 'Python',
3537
'node.js': 'Node.js',
3638
'go': 'Go',
39+
'c': 'C',
3740
'c#': 'C#-Sync',
3841
'java': 'Java-Sync', # Default to sync, could be overridden
3942
'php': 'PHP',
@@ -57,12 +60,15 @@ def get_client_name_from_language_and_path(language: str, path: str) -> str:
5760
"""Get client name from language with path-based overrides.
5861
5962
For Java (.java) files, override based on path substrings:
63+
- If 'lettuce-sync' in path -> Lettuce-Sync
6064
- If 'lettuce-async' in path -> Java-Async
6165
- If 'lettuce-reactive' in path -> Java-Reactive
6266
6367
Substring checks are case-sensitive and can appear anywhere in the path.
6468
"""
6569
if language == 'java':
70+
if 'lettuce-sync' in path:
71+
return 'Lettuce-Sync'
6672
if 'lettuce-async' in path:
6773
return 'Java-Async'
6874
if 'lettuce-reactive' in path:

build/tcedocs/README.md

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ There are two sections that need to updated when new languages are added.
88
1. In the `[params]` section:
99

1010
```toml
11-
clientsExamples = ["Python", "Node.js", "Java-Sync", "Java-Async", "Java-Reactive", "Go", "C#", "RedisVL", "PHP"]
11+
clientsExamples = ["Python", "Node.js", "Java-Sync", "Lettuce-Sync", "Java-Async", "Java-Reactive", "Go", "C", "C#-Sync", "C#-Async", "RedisVL", "PHP", "Rust-Sync", "Rust-Async"]
1212
```
1313

1414
The order of the `clientsExamples` list matters: it's the order in which the language tabs are presented for each code example.
@@ -18,13 +18,18 @@ There are two sections that need to updated when new languages are added.
1818
[params.clientsConfig]
1919
"Python"={quickstartSlug="redis-py"}
2020
"Node.js"={quickstartSlug="nodejs"}
21-
"Java-sync"={quickstartSlug="jedis"}
22-
"Java-async"={quickstartSlug="lettuce"}
23-
"Java-reactive"={quickstartSlug="lettuce"}
21+
"Java-Sync"={quickstartSlug="jedis"}
22+
"Lettuce-Sync"={quickstartSlug="lettuce"}
23+
"Java-Async"={quickstartSlug="lettuce"}
24+
"Java-Reactive"={quickstartSlug="lettuce"}
2425
"Go"={quickstartSlug="go"}
25-
"C#"={quickstartSlug="dotnet"}
26+
"C"={quickstartSlug="hiredis"}
27+
"C#-Sync"={quickstartSlug="dotnet"}
28+
"C#-Async"={quickstartSlug="dotnet"}
2629
"RedisVL"={quickstartSlug="redis-vl"}
2730
"PHP"={quickstartSlug="php"}
31+
"Rust-Sync"={quickstartSlug="rust"}
32+
"Rust-Async"={quickstartSlug="rust"}
2833
```
2934

3035
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.
@@ -36,7 +41,7 @@ A shortcode is a simple snippet inside a content file that Hugo will render usin
3641

3742
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.
3843

39-
Here is the configuration file for Python, `redis_py.json`:
44+
Here is the configuration file for Python, `redis_py.json`:
4045

4146
```json
4247
{
@@ -65,15 +70,20 @@ Register your component file by adding it to the `clients` array in the `index.j
6570
Here is an example:
6671
```json
6772
"clients": [
68-
"nredisstack",
73+
"nredisstack_sync",
74+
"nredisstack_async",
6975
"go_redis",
7076
"node_redis",
7177
"php",
7278
"redis_py",
7379
"jedis",
80+
"lettuce_sync",
7481
"lettuce_async",
7582
"lettuce_reactive",
76-
"redis_vl"
83+
"redis_vl",
84+
"redis_rs_sync",
85+
"redis_rs_async",
86+
"hi_redis"
7787
]
7888
```
7989

@@ -99,14 +109,18 @@ PREFIXES = {
99109
'java-async': '//',
100110
'java-reactive': '//',
101111
'go': '//',
112+
'c': '//',
102113
'c#': '//',
103114
'redisvl': '#',
104-
'php': '//'
115+
'php': '//',
116+
'rust': '//'
105117
}
106118
```
107119

108120
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.
109121

122+
⚠️ **CRITICAL**: The `PREFIXES` dictionary is **essential** for the example parser to work. If you add a new language, you **must** add an entry to this dictionary, or examples will fail to process with an "Unknown language" error. This is the most commonly missed step when adding a new language.
123+
110124
## Understand special comments in the example source code files
111125

112126
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:
@@ -130,10 +144,12 @@ Add a source code file to an appropriate client repo. Consult the /data/componen
130144

131145
| Programming Language | GitHub Repo | Default directory |
132146
|----------------------|-----------------------------------------------------|---------------------------------------------------|
147+
| C | [hiredis](https://github.com/redis/hiredis) | `examples` |
133148
| C# | [NRedisStack](https://github.com/redis/NRedisStack) | `tests/Doc` |
134149
| Go | [go-redis](https://github.com/redis/go-redis) | `doctests` |
135150
| 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 |
151+
| | [Lettuce](https://github.com/redis/lettuce) | `src/test/java/io/redis/examples/sync`, |
152+
| | | `src/test/java/io/redis/examples/async`, or |
137153
| | | `src/test/java/io/redis/examples/reactive` |
138154
| Node.js | [node-redis](https://github.com/redis/node-redis) | `doctests` |
139155
| PHP | [Predis](https://github.com/predis/predis) | Examples, for now, are stored in `local_examples` |
@@ -148,9 +164,15 @@ At times, it can take quite a while to get new or updated examples through the r
148164
local_examples
149165
├── client-specific
150166
│   ├── go
167+
│ ├── c
168+
│ │ ...
169+
151170
│   │   ...
152171
│   ├── jedis
153172
│   │   ...
173+
│ ├── lettuce-sync
174+
│ │ ...
175+
154176
│   ├── lettuce-async
155177
│   │   ...
156178
│   ├── lettuce-reactive

build/tcedocs/SPECIFICATION.md

Lines changed: 133 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,15 +245,16 @@ The system operates in three distinct phases:
245245

246246
Some languages have multiple client implementations (sync/async, different libraries). The system uses directory path to determine which variant:
247247

248-
- Java files in `lettuce-async/``Java-Async` (Lettuce async client)
248+
- Java files in `lettuce-sync/``Lettuce-Sync` (Lettuce synchronous client)
249+
- Java files in `lettuce-async/``Java-Async` (Lettuce asynchronous client)
249250
- Java files in `lettuce-reactive/``Java-Reactive` (Lettuce reactive client)
250251
- Java files elsewhere → `Java-Sync` (Jedis synchronous client)
251252
- Rust files in `rust-async/``Rust-Async`
252253
- Rust files in `rust-sync/``Rust-Sync`
253254
- C# files in `async/``C#-Async`
254255
- C# files in `sync/``C#-Sync`
255256

256-
This allows the same language to appear multiple times in the tab interface with different implementations.
257+
This allows the same language to appear multiple times in the tab interface with different implementations. The order of checks matters: more specific paths (e.g., `lettuce-sync`) should be checked before generic ones (e.g., `Java-Sync`).
257258

258259
**Outputs**:
259260
- Copies files to `examples/{example_id}/local_{filename}`
@@ -1126,7 +1127,7 @@ def main():
11261127
**Client Examples Order**:
11271128
```toml
11281129
[params]
1129-
clientsExamples = ["Python", "Node.js", "Java-Sync", "Java-Async", "Java-Reactive", "Go", "C#-Sync", "C#-Async", "RedisVL", "PHP", "Rust-Sync", "Rust-Async"]
1130+
clientsExamples = ["Python", "Node.js", "Java-Sync", "Lettuce-Sync", "Java-Async", "Java-Reactive", "Go", "C", "C#-Sync", "C#-Async", "RedisVL", "PHP", "Rust-Sync", "Rust-Async"]
11301131
```
11311132

11321133
This controls:
@@ -1489,9 +1490,10 @@ See [Appendix: Adding a Language](#adding-a-language) for complete step-by-step
14891490
1. ✅ Update `config.toml` (clientsExamples, clientsConfig)
14901491
2. ✅ Create component config in `data/components/`
14911492
3. ✅ Register in `data/components/index.json`
1492-
4. ✅ Add language to `PREFIXES` in `build/components/example.py`
1493+
4. ✅ Add language to `PREFIXES` in `build/components/example.py` ⚠️ **CRITICAL - DO NOT SKIP**
14931494
5. ✅ Add extension mapping in `build/local_examples.py`
14941495
6. ✅ Add test markers if needed
1496+
7. ⚠️ Check if Jupyter notebook support is needed (update `build/jupyterize/` if applicable)
14951497

14961498
### Customizing the UI
14971499

@@ -2138,3 +2140,130 @@ OK
21382140
{{< /clients-example >}}
21392141
```
21402142

2143+
2144+
## Lessons Learned: Adding the C (hiredis) Client
2145+
2146+
### Critical Discovery: The PREFIXES Dictionary
2147+
2148+
When adding the C client, a critical step was initially missed: **adding the language to the `PREFIXES` dictionary in `build/components/example.py`**.
2149+
2150+
**Why this matters**: The `PREFIXES` dictionary maps each language to its comment prefix character(s). This is used by the example parser to:
2151+
- Identify special markers like `EXAMPLE:`, `STEP_START`, `HIDE_START`, etc.
2152+
- Parse metadata from source files
2153+
- Process example files correctly
2154+
2155+
**What happens if you skip this step**:
2156+
- The example parser will fail with an error: `Unknown language "c" for example {path}`
2157+
- Examples won't be processed
2158+
- The build system will silently skip C examples
2159+
- No error message will appear in the build output (just a debug log)
2160+
2161+
**The fix**:
2162+
```python
2163+
# In build/components/example.py, add to PREFIXES dictionary:
2164+
PREFIXES = {
2165+
...
2166+
'c': '//', # C uses // for comments
2167+
...
2168+
}
2169+
```
2170+
2171+
### Complete Checklist for Adding a New Language
2172+
2173+
The original checklist was incomplete. Here's the comprehensive version:
2174+
2175+
**Configuration Files**:
2176+
1. ✅ `config.toml` - Add to `clientsExamples` list and `clientsConfig` section
2177+
2. ✅ `data/components/{language}.json` - Create component configuration
2178+
3. ✅ `data/components/index.json` - Register the component
2179+
2180+
**Build System**:
2181+
4. ✅ `build/components/example.py` - **CRITICAL**: Add to `PREFIXES` dictionary
2182+
5. ✅ `build/components/example.py` - Add to `TEST_MARKER` dictionary (if language has test annotations)
2183+
6. ✅ `build/local_examples.py` - Add file extension mapping to `EXTENSION_TO_LANGUAGE`
2184+
7. ✅ `build/local_examples.py` - Add language to `LANGUAGE_TO_CLIENT` mapping
2185+
2186+
**Optional (if Jupyter notebook support is needed)**:
2187+
8. ⚠️ `build/jupyterize/jupyterize.py` - Add to `KERNEL_SPECS` dictionary
2188+
9. ⚠️ `build/jupyterize/jupyterize_config.json` - Add language-specific boilerplate and unwrap patterns
2189+
2190+
**Documentation**:
2191+
10. ✅ `build/tcedocs/SPECIFICATION.md` - Update examples and checklist
2192+
11. ✅ `build/tcedocs/README.md` - Update tables and examples
2193+
2194+
### Pre-existing Examples
2195+
2196+
**Important**: Before adding a new language, check if examples already exist in the repository:
2197+
- Look in `local_examples/client-specific/{language}/` for local examples
2198+
- Check the client repository for remote examples
2199+
- Verify the component configuration points to the correct example directory
2200+
2201+
For C (hiredis), there was already a `landing.c` example in `local_examples/client-specific/c/` that was ready to be processed once the language was properly configured.
2202+
2203+
### Language-Specific Comment Prefixes
2204+
2205+
Different languages use different comment styles. When adding a language, ensure the correct prefix is used:
2206+
2207+
| Language | Prefix | Example |
2208+
|----------|--------|---------|
2209+
| Python | `#` | `# EXAMPLE: my_example` |
2210+
| C | `//` | `// EXAMPLE: my_example` |
2211+
| Java | `//` | `// EXAMPLE: my_example` |
2212+
| Go | `//` | `// EXAMPLE: my_example` |
2213+
| C# | `//` | `// EXAMPLE: my_example` |
2214+
| PHP | `//` | `// EXAMPLE: my_example` |
2215+
| Rust | `//` | `// EXAMPLE: my_example` |
2216+
| Node.js | `//` | `// EXAMPLE: my_example` |
2217+
2218+
**Critical**: The `PREFIXES` dictionary uses **lowercase** language names as keys, but the `Example` class converts the language to lowercase before accessing it (line 57 in `example.py`).
2219+
2220+
### Verification Steps
2221+
2222+
After adding a new language, verify the integration:
2223+
2224+
```bash
2225+
# 1. Check that the language is recognized
2226+
grep -r "c" build/components/example.py # Should find 'c': '//' in PREFIXES
2227+
2228+
# 2. Process examples
2229+
python3 build/local_examples.py
2230+
2231+
# 3. Verify examples were processed
2232+
grep -i "landing" data/examples.json | grep -i "c"
2233+
2234+
# 4. Check for errors in the build output
2235+
python3 build/make.py 2>&1 | grep -i "error\|unknown language"
2236+
2237+
# 5. Build and serve
2238+
hugo serve
2239+
```
2240+
2241+
### Common Mistakes to Avoid
2242+
2243+
1. **Forgetting the PREFIXES entry**: This is the most common mistake. The build will appear to succeed but examples won't be processed.
2244+
2245+
2. **Case sensitivity**: Language names in `PREFIXES` must be lowercase, but `clientsExamples` in `config.toml` uses proper case (e.g., `"C"` not `"c"`).
2246+
2247+
3. **Inconsistent naming**: Ensure the language name is consistent across:
2248+
- `config.toml` clientsExamples (proper case, e.g., `"C"`)
2249+
- `config.toml` clientsConfig keys (proper case, e.g., `"C"`)
2250+
- `build/local_examples.py` LANGUAGE_TO_CLIENT values (proper case, e.g., `'C'`)
2251+
- `build/components/example.py` PREFIXES keys (lowercase, e.g., `'c'`)
2252+
2253+
4. **Missing component registration**: If the component isn't registered in `data/components/index.json`, remote examples won't be fetched.
2254+
2255+
5. **Wrong file extension mapping**: Ensure the file extension correctly maps to the language name in `EXTENSION_TO_LANGUAGE`.
2256+
2257+
### Single-Variant vs Multi-Variant Languages
2258+
2259+
**Single-variant languages** (Python, Go, PHP, C):
2260+
- One client implementation per language
2261+
- No path-based client name overrides needed
2262+
- File extension mapping is straightforward
2263+
2264+
**Multi-variant languages** (Java, Rust, C#):
2265+
- Multiple client implementations (e.g., Sync, Async, Reactive)
2266+
- Require path-based client name overrides in `get_client_name_from_language_and_path()`
2267+
- More complex configuration
2268+
2269+
C is a single-variant language, so it doesn't require path-based overrides.

config.toml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ tagManagerId = "GTM-TKZ6J9R"
4545
gitHubRepo = "https://github.com/redis/docs"
4646

4747
# Display and sort order for client examples
48-
clientsExamples = ["Python", "Node.js", "Java-Sync", "Java-Async", "Java-Reactive", "Go", "C#-Sync", "C#-Async", "RedisVL", "PHP", "Rust-Sync", "Rust-Async"]
48+
clientsExamples = ["Python", "Node.js", "Java-Sync", "Lettuce-Sync", "Java-Async", "Java-Reactive", "Go", "C", "C#-Sync", "C#-Async", "RedisVL", "PHP", "Rust-Sync", "Rust-Async"]
4949
searchService = "/convai/api/search-service"
5050
ratingsService = "/docusight/api/rate/docs"
5151

@@ -60,16 +60,18 @@ rdi_current_version = "1.15.0"
6060
[params.clientsConfig]
6161
"Python"={quickstartSlug="redis-py"}
6262
"Node.js"={quickstartSlug="nodejs"}
63-
"Java-sync"={quickstartSlug="jedis"}
64-
"Java-async"={quickstartSlug="lettuce"}
65-
"Java-reactive"={quickstartSlug="lettuce"}
63+
"Java-Sync"={quickstartSlug="jedis"}
64+
"Lettuce-Sync"={quickstartSlug="lettuce"}
65+
"Java-Async"={quickstartSlug="lettuce"}
66+
"Java-Reactive"={quickstartSlug="lettuce"}
6667
"Go"={quickstartSlug="go"}
68+
"C"={quickstartSlug="hiredis"}
6769
"C#-Sync"={quickstartSlug="dotnet"}
6870
"C#-Async"={quickstartSlug="dotnet"}
6971
"RedisVL"={quickstartSlug="redis-vl"}
7072
"PHP"={quickstartSlug="php"}
71-
"Rust-sync"={quickstartSlug="rust"}
72-
"Rust-async"={quickstartSlug="rust"}
73+
"Rust-Sync"={quickstartSlug="rust"}
74+
"Rust-Async"={quickstartSlug="rust"}
7375

7476
# Mount directories for duplicate content
7577
[module]

0 commit comments

Comments
 (0)