forthic 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +314 -14
- data/Rakefile +37 -8
- data/lib/forthic/decorators/docs.rb +69 -0
- data/lib/forthic/decorators/word.rb +331 -0
- data/lib/forthic/errors.rb +270 -0
- data/lib/forthic/grpc/client.rb +223 -0
- data/lib/forthic/grpc/errors.rb +149 -0
- data/lib/forthic/grpc/forthic_runtime_pb.rb +32 -0
- data/lib/forthic/grpc/forthic_runtime_services_pb.rb +31 -0
- data/lib/forthic/grpc/remote_module.rb +120 -0
- data/lib/forthic/grpc/remote_runtime_module.rb +148 -0
- data/lib/forthic/grpc/remote_word.rb +91 -0
- data/lib/forthic/grpc/runtime_manager.rb +60 -0
- data/lib/forthic/grpc/serializer.rb +184 -0
- data/lib/forthic/grpc/server.rb +361 -0
- data/lib/forthic/interpreter.rb +682 -133
- data/lib/forthic/literals.rb +170 -0
- data/lib/forthic/module.rb +383 -0
- data/lib/forthic/modules/standard/array_module.rb +940 -0
- data/lib/forthic/modules/standard/boolean_module.rb +176 -0
- data/lib/forthic/modules/standard/core_module.rb +362 -0
- data/lib/forthic/modules/standard/datetime_module.rb +349 -0
- data/lib/forthic/modules/standard/json_module.rb +55 -0
- data/lib/forthic/modules/standard/math_module.rb +365 -0
- data/lib/forthic/modules/standard/record_module.rb +203 -0
- data/lib/forthic/modules/standard/string_module.rb +170 -0
- data/lib/forthic/tokenizer.rb +225 -78
- data/lib/forthic/utils.rb +35 -0
- data/lib/forthic/websocket/handler.rb +548 -0
- data/lib/forthic/websocket/serializer.rb +160 -0
- data/lib/forthic/word_options.rb +141 -0
- data/lib/forthic.rb +30 -20
- data/protos/README.md +43 -0
- data/protos/v1/forthic_runtime.proto +200 -0
- metadata +76 -39
- data/.standard.yml +0 -3
- data/CHANGELOG.md +0 -5
- data/Guardfile +0 -42
- data/lib/forthic/code_location.rb +0 -20
- data/lib/forthic/forthic_error.rb +0 -51
- data/lib/forthic/forthic_module.rb +0 -145
- data/lib/forthic/global_module.rb +0 -2341
- data/lib/forthic/positioned_string.rb +0 -19
- data/lib/forthic/token.rb +0 -38
- data/lib/forthic/variable.rb +0 -34
- data/lib/forthic/version.rb +0 -5
- data/lib/forthic/words/definition_word.rb +0 -40
- data/lib/forthic/words/end_array_word.rb +0 -28
- data/lib/forthic/words/end_module_word.rb +0 -16
- data/lib/forthic/words/imported_word.rb +0 -27
- data/lib/forthic/words/map_word.rb +0 -169
- data/lib/forthic/words/module_memo_bang_at_word.rb +0 -22
- data/lib/forthic/words/module_memo_bang_word.rb +0 -21
- data/lib/forthic/words/module_memo_word.rb +0 -35
- data/lib/forthic/words/module_word.rb +0 -21
- data/lib/forthic/words/push_value_word.rb +0 -21
- data/lib/forthic/words/start_module_word.rb +0 -31
- data/lib/forthic/words/word.rb +0 -30
- data/sig/forthic.rbs +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: edd1101930e744ff0289d9a71f7449645852a558c7f12b4f4b0fe8bb211278cd
|
|
4
|
+
data.tar.gz: ea53ba5d3f04fca67b2088debe870eba40e9c2b1bca04061095420d0b92de8cd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8f193bcb169fe8b7a7f59c27978b3c296b61e791199b6e4c9797eb10d671ff091416ac5e7fc6ecd42f7bf70955dbbbf237fa7c97e8434ea3abd41e13a4c861e9
|
|
7
|
+
data.tar.gz: 9bea9f3a03156019a3e3e23bf634c8988bd13180ec28faa4cb91d4256851c3cefbcd9928341e494e8f281a3f331bd4262d358c7fd1bb61db99c50e0983dcc13c
|
data/README.md
CHANGED
|
@@ -1,37 +1,337 @@
|
|
|
1
|
-
# Forthic
|
|
1
|
+
# Forthic Ruby Runtime
|
|
2
2
|
|
|
3
|
-
A Forthic
|
|
3
|
+
**A Ruby runtime for [Forthic](https://github.com/forthix/forthic)** - *the* stack-based, concatenative language for composable transformations.
|
|
4
|
+
|
|
5
|
+
Use Forthic to wrap your Ruby code within composable words, leveraging categorical principles for clean, powerful abstractions.
|
|
6
|
+
|
|
7
|
+
**[Forthic Parent Documentation](https://github.com/forthix/forthic)** | **[Getting Started](#getting-started)** | **[Examples](examples/)** | **[API Docs](docs/)**
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## What is Forthic?
|
|
12
|
+
|
|
13
|
+
Forthic enables **categorical coding** - a way to solve problems by viewing them in terms of transformation rather than computation. This Ruby runtime lets you:
|
|
14
|
+
|
|
15
|
+
1. **Wrap existing code** with simple decorators
|
|
16
|
+
2. **Compose transformations** cleanly using stack-based operations
|
|
17
|
+
3. **Build powerful abstractions** from simple primitives
|
|
18
|
+
|
|
19
|
+
See the [Forthic repository](https://github.com/forthix/forthic) for philosophy, core concepts, and why categorical coding matters.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Quick Example
|
|
24
|
+
|
|
25
|
+
### Create a Module
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
require 'forthic'
|
|
29
|
+
|
|
30
|
+
class AnalyticsModule < Forthic::Decorators::DecoratedModule
|
|
31
|
+
def initialize
|
|
32
|
+
super("analytics")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
word :AVERAGE, "( numbers -- avg )", "Calculate average"
|
|
36
|
+
def AVERAGE(numbers)
|
|
37
|
+
numbers.sum.to_f / numbers.length
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
word :FILTER_OUTLIERS, "( numbers stdDevs -- filtered )", "Filter outliers beyond N std devs"
|
|
41
|
+
def FILTER_OUTLIERS(numbers, std_devs)
|
|
42
|
+
mean = AVERAGE(numbers)
|
|
43
|
+
std_dev = Math.sqrt(numbers.map { |n| (n - mean) ** 2 }.sum / numbers.length)
|
|
44
|
+
threshold = std_dev * std_devs
|
|
45
|
+
numbers.select { |n| (n - mean).abs <= threshold }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Use It
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
require 'forthic'
|
|
54
|
+
|
|
55
|
+
interp = Forthic::Interpreter.new
|
|
56
|
+
interp.register_module(AnalyticsModule.new)
|
|
57
|
+
|
|
58
|
+
interp.run(%{
|
|
59
|
+
["analytics"] USE-MODULES
|
|
60
|
+
|
|
61
|
+
[1 2 3 100 4 5] 2 FILTER-OUTLIERS AVERAGE
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
result = interp.stack_pop # Clean average without outliers
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
4
68
|
|
|
5
69
|
## Installation
|
|
6
70
|
|
|
7
|
-
|
|
71
|
+
Add to your Gemfile:
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
gem 'forthic'
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Then install:
|
|
8
78
|
|
|
9
79
|
```bash
|
|
10
|
-
bundle
|
|
80
|
+
bundle install
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Getting Started
|
|
86
|
+
|
|
87
|
+
### Basic Usage
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
require 'forthic'
|
|
91
|
+
|
|
92
|
+
interp = Forthic::Interpreter.new
|
|
93
|
+
|
|
94
|
+
# Execute Forthic code
|
|
95
|
+
interp.run(%{
|
|
96
|
+
[1 2 3 4 5] "2 *" MAP # Double each element
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
result = interp.stack_pop # [2, 4, 6, 8, 10]
|
|
11
100
|
```
|
|
12
101
|
|
|
13
|
-
|
|
102
|
+
### Creating Your First Module
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
require 'forthic'
|
|
106
|
+
|
|
107
|
+
class MyModule < Forthic::Decorators::DecoratedModule
|
|
108
|
+
def initialize
|
|
109
|
+
super("mymodule")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
word :PROCESS, "( data -- result )", "Process data your way"
|
|
113
|
+
def PROCESS(data)
|
|
114
|
+
# Wrap your existing Ruby code
|
|
115
|
+
my_existing_function(data)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Register and use
|
|
120
|
+
interp = Forthic::Interpreter.new
|
|
121
|
+
interp.register_module(MyModule.new)
|
|
122
|
+
|
|
123
|
+
interp.run(%{
|
|
124
|
+
["mymodule"] USE-MODULES
|
|
125
|
+
SOME-DATA PROCESS
|
|
126
|
+
})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
See [examples/README.md](examples/README.md) for detailed tutorials and examples.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Features
|
|
134
|
+
|
|
135
|
+
### Standard Library
|
|
136
|
+
|
|
137
|
+
The Ruby runtime includes comprehensive standard modules:
|
|
138
|
+
|
|
139
|
+
- **array** - MAP, SELECT, SORT, GROUP-BY, ZIP, REDUCE, FLATTEN (30+ operations)
|
|
140
|
+
- **record** - REC@, <REC, MERGE, KEYS, VALUES, INVERT-KEYS
|
|
141
|
+
- **string** - SPLIT, JOIN, UPPERCASE, LOWERCASE, TRIM, REPLACE
|
|
142
|
+
- **math** - +, -, *, /, ROUND, ABS, MIN, MAX, AVERAGE
|
|
143
|
+
- **datetime** - >DATE, >DATETIME, ADD-DAYS, FORMAT, DIFF-DAYS
|
|
144
|
+
- **json** - >JSON, JSON>, JSON-PRETTIFY
|
|
145
|
+
- **boolean** - ==, <, >, AND, OR, NOT, IN
|
|
146
|
+
|
|
147
|
+
See [docs/modules/](docs/modules/) for complete reference.
|
|
148
|
+
|
|
149
|
+
### Easy Module Creation
|
|
150
|
+
|
|
151
|
+
The decorator system makes wrapping code trivial:
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
word :MY_WORD, "( input -- output )", "Description"
|
|
155
|
+
def MY_WORD(input)
|
|
156
|
+
your_logic(input)
|
|
157
|
+
end
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Ruby Integration
|
|
161
|
+
|
|
162
|
+
- Full Ruby compatibility (Ruby 2.7+)
|
|
163
|
+
- Works with Rails applications
|
|
164
|
+
- Synchronous execution model
|
|
165
|
+
- Native Ruby error handling
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Documentation
|
|
170
|
+
|
|
171
|
+
### This Runtime
|
|
172
|
+
- **[Module API Reference](docs/modules/)** - Standard library documentation
|
|
173
|
+
- **[Examples](examples/)** - Working code samples
|
|
174
|
+
|
|
175
|
+
### Core Forthic Concepts
|
|
176
|
+
- **[Main Forthic Docs](https://github.com/forthix/forthic)** - Philosophy, language guide
|
|
177
|
+
- **[Why Forthic?](https://github.com/forthix/forthic/blob/main/docs/why-forthic.md)** - Motivation and core principles
|
|
178
|
+
- **[Category Theory](https://github.com/forthix/forthic/blob/main/docs/language/category-theory.md)** - Mathematical foundations
|
|
179
|
+
- **[Building Modules](https://github.com/forthix/forthic/blob/main/docs/tutorials/building-modules.md)** - Module creation patterns
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Examples
|
|
184
|
+
|
|
185
|
+
See the [examples/](examples/) directory for working code samples including:
|
|
186
|
+
- Basic usage patterns
|
|
187
|
+
- Custom module creation
|
|
188
|
+
- Multi-runtime execution
|
|
189
|
+
- Rails integration
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Building
|
|
14
194
|
|
|
15
195
|
```bash
|
|
16
|
-
|
|
196
|
+
# Install dependencies
|
|
197
|
+
bundle install
|
|
198
|
+
|
|
199
|
+
# Run all tests
|
|
200
|
+
bundle exec rspec
|
|
201
|
+
|
|
202
|
+
# Run only unit tests
|
|
203
|
+
bundle exec rspec spec/unit/
|
|
204
|
+
|
|
205
|
+
# Run only integration tests
|
|
206
|
+
bundle exec rspec spec/integration/
|
|
207
|
+
|
|
208
|
+
# Generate documentation
|
|
209
|
+
bundle exec rake docs
|
|
17
210
|
```
|
|
18
211
|
|
|
19
|
-
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Multi-Runtime Execution
|
|
20
215
|
|
|
21
|
-
|
|
216
|
+
Call code from other language runtimes seamlessly - use Python's pandas from Ruby, or TypeScript's JavaScript libraries from Ruby.
|
|
217
|
+
|
|
218
|
+
### Quick Example
|
|
22
219
|
|
|
23
220
|
```ruby
|
|
24
221
|
require 'forthic'
|
|
222
|
+
require 'forthic/grpc/client'
|
|
223
|
+
require 'forthic/grpc/remote_runtime_module'
|
|
25
224
|
|
|
26
225
|
interp = Forthic::Interpreter.new
|
|
27
|
-
interp.run("[1 2 3] '8 *' MAP")
|
|
28
|
-
puts interp.stack_pop
|
|
29
226
|
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
|
|
227
|
+
# Register the remote runtime module
|
|
228
|
+
remote_runtime = Forthic::Grpc::RemoteRuntimeModule.new
|
|
229
|
+
interp.register_module(remote_runtime)
|
|
230
|
+
|
|
231
|
+
interp.run(%{
|
|
232
|
+
# Connect to Python runtime
|
|
233
|
+
"localhost:50051" CONNECT-RUNTIME
|
|
234
|
+
|
|
235
|
+
# Load Python pandas module
|
|
236
|
+
["pandas"] USE-PY-MODULES
|
|
237
|
+
|
|
238
|
+
# Now use Python pandas from Ruby!
|
|
239
|
+
[
|
|
240
|
+
[ [.name "Alice"] [.age 30] ] REC
|
|
241
|
+
[ [.name "Bob"] [.age 25] ] REC
|
|
242
|
+
] DF-FROM-RECORDS
|
|
243
|
+
})
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Approaches
|
|
247
|
+
|
|
248
|
+
- **gRPC** - Ruby ↔ Python ↔ TypeScript (fast, server-to-server)
|
|
249
|
+
- **WebSocket** - Browser ↔ Rails (ActionCable, client-server)
|
|
250
|
+
|
|
251
|
+
### Learn More
|
|
252
|
+
|
|
253
|
+
📖 **[Complete Multi-Runtime Documentation](docs/multi-runtime/)**
|
|
254
|
+
|
|
255
|
+
- **[Overview](docs/multi-runtime/)** - When and how to use multi-runtime
|
|
256
|
+
- **[gRPC Setup](docs/multi-runtime/grpc.md)** - Server and client configuration
|
|
257
|
+
- **[WebSocket Setup](docs/multi-runtime/websocket.md)** - Browser-compatible communication
|
|
258
|
+
- **[Configuration](docs/multi-runtime/configuration.md)** - YAML config and connection management
|
|
259
|
+
- **[Examples](examples/)** - Working code samples
|
|
260
|
+
|
|
261
|
+
**Runtime Status:** ✅ TypeScript, Python, Ruby | 🚧 Rust | 📋 Java, .NET
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Project Structure
|
|
266
|
+
|
|
33
267
|
```
|
|
268
|
+
forthic-rb/
|
|
269
|
+
├── lib/forthic/ # Core library code
|
|
270
|
+
│ ├── decorators/ # Decorator system for modules and words
|
|
271
|
+
│ ├── modules/ # Standard library modules
|
|
272
|
+
│ │ └── standard/ # Standard modules (array, string, math, etc.)
|
|
273
|
+
│ ├── grpc/ # gRPC client/server for multi-runtime
|
|
274
|
+
│ ├── websocket/ # WebSocket/ActionCable support
|
|
275
|
+
│ ├── interpreter.rb # Main interpreter implementation
|
|
276
|
+
│ ├── module.rb # Module and word classes
|
|
277
|
+
│ ├── tokenizer.rb # Lexical analysis
|
|
278
|
+
│ └── errors.rb # Error classes
|
|
279
|
+
├── spec/ # Test suite
|
|
280
|
+
│ ├── unit/ # Unit tests
|
|
281
|
+
│ └── integration/ # Integration tests
|
|
282
|
+
├── scripts/ # Utility scripts
|
|
283
|
+
│ └── generate_docs.rb # Documentation generator
|
|
284
|
+
├── protos/ # Protocol buffer definitions
|
|
285
|
+
│ └── v1/ # Version 1 of gRPC protocol
|
|
286
|
+
└── docs/ # Generated documentation (created by rake docs)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Cross-Runtime Compatibility
|
|
292
|
+
|
|
293
|
+
This Ruby implementation maintains compatibility with:
|
|
294
|
+
- **forthic-ts** (TypeScript/JavaScript)
|
|
295
|
+
- **forthic-py** (Python)
|
|
296
|
+
- **forthic-rs** (Rust, in progress)
|
|
297
|
+
|
|
298
|
+
All runtimes share the same test suite and language semantics to ensure consistent behavior across platforms.
|
|
299
|
+
|
|
300
|
+
---
|
|
34
301
|
|
|
35
302
|
## Contributing
|
|
36
303
|
|
|
37
|
-
|
|
304
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development guidelines, or refer to the main [Forthic contributing guide](https://github.com/forthix/forthic/blob/main/CONTRIBUTING.md).
|
|
305
|
+
|
|
306
|
+
When adding new words or modules:
|
|
307
|
+
|
|
308
|
+
1. Use the decorator system (`word` or `direct_word`)
|
|
309
|
+
2. Include stack effect notation: `( input -- output )`
|
|
310
|
+
3. Provide clear descriptions
|
|
311
|
+
4. Add corresponding tests in `spec/`
|
|
312
|
+
5. Regenerate documentation: `bundle exec rake docs`
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Community
|
|
317
|
+
|
|
318
|
+
- **Main Repository:** [forthix/forthic](https://github.com/forthix/forthic)
|
|
319
|
+
- **Issues:** [Report issues](https://github.com/forthix/forthic-rb/issues)
|
|
320
|
+
- **Discussions:** [GitHub Discussions](https://github.com/forthix/forthic/discussions)
|
|
321
|
+
- **Examples:** [Real-world applications](examples/)
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
[BSD-2-Clause License](LICENSE) - Copyright 2024 LinkedIn Corporation. Copyright 2025 Forthix LLC.
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Related
|
|
332
|
+
|
|
333
|
+
- **[Forthic (main repo)](https://github.com/forthix/forthic)** - Core documentation and concepts
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
**Forthic**: Wrap. Compose. Abstract.
|
data/Rakefile
CHANGED
|
@@ -1,14 +1,43 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require "minitest/test_task"
|
|
3
|
+
require 'rspec/core/rake_task'
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
task default: :spec
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
desc 'Generate documentation from module decorators'
|
|
10
|
+
task :docs do
|
|
11
|
+
ruby 'scripts/generate_docs.rb'
|
|
12
|
+
end
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
desc 'Run all tests'
|
|
15
|
+
task test: :spec
|
|
16
|
+
|
|
17
|
+
desc 'Run unit tests only'
|
|
18
|
+
task :test_unit do
|
|
19
|
+
sh 'bundle exec rspec spec/unit'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
desc 'Run integration tests only'
|
|
23
|
+
task :test_integration do
|
|
24
|
+
sh 'bundle exec rspec spec/integration'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc 'Generate gRPC protobuf code from .proto file'
|
|
28
|
+
task :generate_grpc do
|
|
29
|
+
proto_file = 'protos/v1/forthic_runtime.proto'
|
|
30
|
+
proto_dir = 'protos/v1'
|
|
31
|
+
output_dir = 'lib/forthic/grpc'
|
|
32
|
+
|
|
33
|
+
# Create output directory if it doesn't exist
|
|
34
|
+
FileUtils.mkdir_p(output_dir)
|
|
35
|
+
|
|
36
|
+
# Generate Ruby protobuf code from v1 proto
|
|
37
|
+
sh "grpc_tools_ruby_protoc -I #{proto_dir} " \
|
|
38
|
+
"--ruby_out=#{output_dir} " \
|
|
39
|
+
"--grpc_out=#{output_dir} " \
|
|
40
|
+
"#{proto_file}"
|
|
41
|
+
|
|
42
|
+
puts "✓ Generated protobuf code from #{proto_file}"
|
|
43
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'word'
|
|
4
|
+
require 'json'
|
|
5
|
+
|
|
6
|
+
module Forthic
|
|
7
|
+
module Decorators
|
|
8
|
+
# Generate markdown documentation for a module
|
|
9
|
+
#
|
|
10
|
+
# @param mod [DecoratedModule] The module to document
|
|
11
|
+
# @return [String] Markdown-formatted documentation
|
|
12
|
+
def self.generate_module_docs(mod)
|
|
13
|
+
docs = mod.get_word_docs
|
|
14
|
+
md = "# #{mod.get_name} Module\n\n"
|
|
15
|
+
|
|
16
|
+
if docs.empty?
|
|
17
|
+
md += "*No documented words*\n"
|
|
18
|
+
return md
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Sort alphabetically by name
|
|
22
|
+
docs.sort_by! { |doc| doc[:name] }
|
|
23
|
+
|
|
24
|
+
docs.each do |doc|
|
|
25
|
+
md += "## #{doc[:name]}\n\n"
|
|
26
|
+
md += "**Stack Effect**: `#{doc[:stack_effect]}`\n\n"
|
|
27
|
+
md += "#{doc[:description]}\n\n" if doc[:description] && !doc[:description].empty?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
md
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Generate JSON documentation for multiple modules
|
|
34
|
+
#
|
|
35
|
+
# @param modules [Array<DecoratedModule>] The modules to document
|
|
36
|
+
# @return [Array<Hash>] Array of module documentation hashes
|
|
37
|
+
def self.generate_docs_json(modules)
|
|
38
|
+
modules.map do |mod|
|
|
39
|
+
{
|
|
40
|
+
name: mod.get_name,
|
|
41
|
+
words: mod.get_word_docs
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Generate full stdlib documentation
|
|
47
|
+
#
|
|
48
|
+
# @param interp [StandardInterpreter] The interpreter with stdlib loaded
|
|
49
|
+
# @return [String] Markdown-formatted stdlib documentation
|
|
50
|
+
def self.generate_stdlib_docs(interp)
|
|
51
|
+
module_names = [
|
|
52
|
+
"core", "array", "record", "string", "datetime",
|
|
53
|
+
"math", "boolean", "json", "utility"
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
md = "# Forthic Standard Library\n\n"
|
|
57
|
+
|
|
58
|
+
module_names.each do |module_name|
|
|
59
|
+
mod = interp.get_app_module.find_module(module_name)
|
|
60
|
+
if mod && mod.is_a?(DecoratedModule)
|
|
61
|
+
md += generate_module_docs(mod)
|
|
62
|
+
md += "\n---\n\n"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
md
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|