diff --git a/.vscode/settings.json b/.vscode/settings.json
index 1f0bba0..e787e70 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -19,6 +19,7 @@
"nativeint",
"ncave",
"pathlib",
+ "pyfile",
"pyname",
"Pyxpecto",
"stroustrup",
diff --git a/CLAUDE.md b/CLAUDE.md
index d991bc6..200b003 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -58,16 +58,19 @@ Use `` F`#` `` (backticks around `#`) in markdown headings to prevent markdownli
```text
chapters/
-├── introduction.fs # What is Fable.Python, why use it
-├── python.fs # F# concepts for Python developers
-├── getting-started.fs # Setup, first project, hello world
-├── interop.fs # Using existing Python libraries
-├── bindings.fs # Creating Python bindings
-├── compatibility.fs # F# features supported, limitations
-├── async-programming.fs # async vs task, Python asyncio mapping
-├── fable-v5.fs # Fable v5 features, Rust core, PyPI
-├── pydantic.fs # Pydantic models, DTOs, validation
-└── units-of-measure.fs # Compile-time dimensional analysis
+├── Introduction.fs # What is Fable.Python, why use it
+├── Python.fs # F# concepts for Python developers
+├── GettingStarted.fs # Setup, first project, hello world
+├── Interop.fs # Using existing Python libraries
+├── Bindings.fs # Creating Python bindings
+├── Compatibility.fs # F# features supported, limitations
+├── AsyncProgramming.fs # async vs task, Python asyncio mapping
+├── Testing.fs # Testing F# code with Python test runners
+├── FableV5.fs # Fable v5 features, Rust core, PyPI
+├── Pydantic.fs # Pydantic models, DTOs, validation
+├── UnitsOfMeasure.fs # Compile-time dimensional analysis
+├── FableLiterate.fs # Symlink → ../Fable.Literate/App.fs
+└── Summary.fs # Wrap-up, resources, repo link
Fable.Literate/
├── App.fs # Fable.Literate converter source (F#)
└── Fable.Literate.fsproj
diff --git a/Fable.Literate/App.fs b/Fable.Literate/App.fs
index d65b882..62c74e3 100644
--- a/Fable.Literate/App.fs
+++ b/Fable.Literate/App.fs
@@ -464,15 +464,6 @@ dotnet fable Fable.Literate/ --lang python -o output/Fable.Literate/
python output/Fable.Literate/app.py chapters/introduction.fs > docs/introduction.md
```
-That's it! A complete literate programming converter in under 200 lines of F#.
-
-## The Punchline
-
-If you're reading this, the code worked.
-
-This entire blog post - every chapter, every code example, every explanation -
-was processed by the F# code you just read, compiled to Python, and output
-as Markdown. The proof is in the reading.
-
-Welcome to Fable.Python. Now go build something.
+That's it! A complete literate programming converter in under 200 lines of F`#`,
+compiled to Python, processing this very blog post.
*)
diff --git a/README.md b/README.md
index c2b3850..445a20d 100644
--- a/README.md
+++ b/README.md
@@ -16,8 +16,9 @@ This is a comprehensive guide to [Fable.Python](https://github.com/fable-compile
8. **Libraries** - Existing ecosystem (Thoth.Json, AsyncRx, Siren, etc.) *(coming soon)*
9. **Pydantic** - Pydantic interop with Decorate and ClassAttributes
10. **Units of Measure** - Compile-time dimensional analysis
-11. **Testing** - XUnit and Fable.Pyxpecto *(coming soon)*
-12. **Fabletext: The Strange Loop** - The self-documenting finale
+11. **Testing** - Testing F# code with Python test runners
+12. **Fable.Literate** - The self-documenting converter
+13. **Summary** - Wrap-up, resources, and contributing
## The Strange Loop
@@ -74,7 +75,9 @@ chapters/
├── Testing.fs # Testing with Python
├── FableV5.fs # What's new in Fable v5
├── Pydantic.fs # Pydantic interop
-└── UnitsOfMeasure.fs # Dimensional analysis
+├── UnitsOfMeasure.fs # Dimensional analysis
+├── FableLiterate.fs # Symlink → ../Fable.Literate/App.fs
+└── Summary.fs # Wrap-up and resources
Fable.Literate/
├── App.fs # Fable.Literate converter (F#)
└── Fable.Literate.fsproj
@@ -94,7 +97,7 @@ docs/
Defined in `justfile`:
```just
-chapters := "Introduction Python GettingStarted Interop Bindings Compatibility AsyncProgramming Testing FableV5 Pydantic UnitsOfMeasure"
+chapters := "Introduction Python GettingStarted Interop Bindings Compatibility AsyncProgramming Testing FableV5 Pydantic UnitsOfMeasure FableLiterate Summary"
```
To add a new chapter, just add the file and update this list.
diff --git a/chapters/FableLiterate.fs b/chapters/FableLiterate.fs
new file mode 120000
index 0000000..461e4c6
--- /dev/null
+++ b/chapters/FableLiterate.fs
@@ -0,0 +1 @@
+../Fable.Literate/App.fs
\ No newline at end of file
diff --git a/chapters/Summary.fs b/chapters/Summary.fs
new file mode 100644
index 0000000..9e1f9b8
--- /dev/null
+++ b/chapters/Summary.fs
@@ -0,0 +1,54 @@
+(*** hide ***)
+module Summary
+
+(**
+# Summary
+
+We've covered a lot of ground in this guide:
+
+- **Introduction**: What Fable.Python is and why it matters
+- **F`#` for Python Developers**: Bridging the conceptual gap between languages
+- **Getting Started**: Setting up your first Fable.Python project
+- **Interop**: Seamlessly calling Python libraries from F`#`
+- **Bindings**: Creating type-safe wrappers for Python code
+- **Compatibility**: Understanding what F`#` features work (and which don't)
+- **Async Programming**: Mapping F`#` async to Python's asyncio
+- **Testing**: Running F`#` code with pytest and other Python test runners
+- **Fable v5**: The latest features including the Rust core and PyPI packages
+- **Pydantic**: Building validated data models with Python's favorite library
+- **Units of Measure**: Compile-time dimensional analysis that vanishes at runtime
+- **Fable.Literate**: A self-documenting literate programming converter
+
+## The Punchline
+
+If you're reading this, the code worked.
+
+This entire blog post - every chapter, every code example, every explanation -
+was processed by F`#` code compiled to Python, and output as Markdown.
+The proof is in the reading.
+
+## Get Involved
+
+The source code for this entire project is available on GitHub:
+
+**[github.com/cardamomcode/fable-python](https://github.com/cardamomcode/fable-python)**
+
+The repository contains:
+- All the chapter source files (literate F`#`)
+- The Fable.Literate converter
+- Build scripts and configuration
+- The generated blog post
+
+Found a typo? Want to improve an explanation? Have a better example?
+Pull requests are welcome! This is a living document, and contributions
+from the community make it better for everyone.
+
+## Resources
+
+- [Fable Documentation](https://fable.io/docs/)
+- [Fable.Python on GitHub](https://github.com/fable-compiler/Fable.Python/)
+- [F`#` Software Foundation](https://fsharp.org/)
+- [Fable Discord](https://discord.gg/8c3Ng9N) - The Fable community is friendly and helpful
+
+Welcome to Fable.Python. Now go build something.
+*)
diff --git a/fable-python.fsproj b/fable-python.fsproj
index 8a2fe4a..eeab6c0 100644
--- a/fable-python.fsproj
+++ b/fable-python.fsproj
@@ -22,6 +22,7 @@
+
diff --git a/justfile b/justfile
index e3c9852..e5334a8 100644
--- a/justfile
+++ b/justfile
@@ -3,7 +3,7 @@
# Chapter order for documentation generation
# Edit this list to reorder or add chapters
-chapters := "Introduction Python GettingStarted Interop Bindings Compatibility AsyncProgramming Testing FableV5 Pydantic UnitsOfMeasure"
+chapters := "Introduction Python GettingStarted Interop Bindings Compatibility AsyncProgramming Testing FableV5 Pydantic UnitsOfMeasure FableLiterate Summary"
# Default: show help
default:
@@ -38,16 +38,17 @@ generate: build format-python
for name in {{chapters}}; do
# Convert PascalCase to snake_case for Python file naming
pyname=$(echo "$name" | sed 's/\([A-Z]\)/_\1/g' | sed 's/^_//' | tr '[:upper:]' '[:lower:]')
+ # FableLiterate uses different python output path (symlink to Fable.Literate/App.fs)
+ if [ "$name" = "FableLiterate" ]; then
+ pyfile="output/Fable.Literate/python.py"
+ else
+ pyfile="output/chapters/chapters/${pyname}.py"
+ fi
uv run python output/Fable.Literate/app.py \
- --python-file "output/chapters/chapters/${pyname}.py" \
+ --python-file "$pyfile" \
"chapters/${name}.fs" > "docs/${name}.md"
echo "Generated docs/${name}.md"
done
- # Also generate Fable.Literate documentation
- uv run python output/Fable.Literate/app.py \
- --python-file "output/Fable.Literate/python.py" \
- Fable.Literate/App.fs > docs/fable-literate.md
- echo "Generated docs/fable-literate.md"
# Fix markdown lint issues
just lint-markdown
@@ -59,25 +60,26 @@ blogpost: build format-python
for name in {{chapters}}; do
# Convert PascalCase to snake_case for Python file naming
pyname=$(echo "$name" | sed 's/\([A-Z]\)/_\1/g' | sed 's/^_//' | tr '[:upper:]' '[:lower:]')
+ # FableLiterate uses different python output path (symlink to Fable.Literate/App.fs)
+ if [ "$name" = "FableLiterate" ]; then
+ pyfile="output/Fable.Literate/python.py"
+ else
+ pyfile="output/chapters/chapters/${pyname}.py"
+ fi
if $first; then
# First chapter keeps original header levels (has the title)
uv run python output/Fable.Literate/app.py \
- --python-file "output/chapters/chapters/${pyname}.py" \
+ --python-file "$pyfile" \
"chapters/${name}.fs" > docs/blogpost.md
first=false
else
# Remaining chapters get headers increased by one level
echo "" >> docs/blogpost.md
uv run python output/Fable.Literate/app.py \
- --python-file "output/chapters/chapters/${pyname}.py" \
+ --python-file "$pyfile" \
--increase-headers "chapters/${name}.fs" >> docs/blogpost.md
fi
done
- # Include Fable.Literate documenting itself (the meta twist!)
- echo "" >> docs/blogpost.md
- uv run python output/Fable.Literate/app.py \
- --python-file "output/Fable.Literate/python.py" \
- --increase-headers Fable.Literate/App.fs >> docs/blogpost.md
echo "Generated docs/blogpost.md"
# Fix markdown lint issues
just lint-markdown