t-ruby 0.0.7 → 0.0.34
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 +6 -2
- data/lib/t_ruby/cli.rb +131 -6
- data/lib/t_ruby/compiler.rb +97 -9
- data/lib/t_ruby/config.rb +366 -24
- data/lib/t_ruby/docs_badge_generator.rb +192 -0
- data/lib/t_ruby/docs_example_extractor.rb +156 -0
- data/lib/t_ruby/docs_example_verifier.rb +222 -0
- data/lib/t_ruby/error_handler.rb +191 -13
- data/lib/t_ruby/parser.rb +33 -0
- data/lib/t_ruby/version.rb +1 -1
- data/lib/t_ruby/watcher.rb +42 -12
- data/lib/t_ruby.rb +5 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aaa0445c84cb0a6685e788645a19fee5d30d2f1e6f79052122fb16e8a3f08e91
|
|
4
|
+
data.tar.gz: 446845b5b1e470964f664d590197262f0e3555b82dd59f7b75a484324b99ec63
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e422c5535edcb5085efd7018825c1675b06b3c2bb3657da1c6d9f6b07202233b53c03c145888fbdc221fc78df4873d18c2d0f4326d19ede16134eda409fb7418
|
|
7
|
+
data.tar.gz: 0d988eaa6c08a586af4c965447087467e500cc75de4d7bc879c239c3f6924caf504123fc3117ed9be4e676b0ae2715bdadf888218e8072702c1a66bbb329a288
|
data/README.md
CHANGED
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
<img src="https://img.shields.io/badge/coverage-90%25-brightgreen" alt="Coverage: 90%" />
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="https://type-ruby.github.io"><strong>🌐 Official Website</strong></a>
|
|
21
|
+
</p>
|
|
22
|
+
|
|
19
23
|
<p align="center">
|
|
20
24
|
<a href="#install">Install</a>
|
|
21
25
|
•
|
|
@@ -106,7 +110,7 @@ end
|
|
|
106
110
|
- Like TypeScript, types live inside your code.
|
|
107
111
|
- Write `.trb`, and `trc` generates both `.rb` and `.rbs`.
|
|
108
112
|
|
|
109
|
-
```
|
|
113
|
+
```trb
|
|
110
114
|
# greet.trb
|
|
111
115
|
def greet(name: String): String
|
|
112
116
|
"Hello, #{name}!"
|
|
@@ -150,7 +154,7 @@ trc --version
|
|
|
150
154
|
|
|
151
155
|
### 1. Write `.trb`
|
|
152
156
|
|
|
153
|
-
```
|
|
157
|
+
```trb
|
|
154
158
|
# hello.trb
|
|
155
159
|
def greet(name: String): String
|
|
156
160
|
"Hello, #{name}!"
|
data/lib/t_ruby/cli.rb
CHANGED
|
@@ -7,6 +7,9 @@ module TRuby
|
|
|
7
7
|
|
|
8
8
|
Usage:
|
|
9
9
|
trc <file.trb> Compile a .trb file to .rb
|
|
10
|
+
trc <file.rb> Copy .rb file to build/ and generate .rbs
|
|
11
|
+
trc --init Initialize a new t-ruby project
|
|
12
|
+
trc --config, -c <path> Use custom config file
|
|
10
13
|
trc --watch, -w Watch input files and recompile on change
|
|
11
14
|
trc --decl <file.trb> Generate .d.trb declaration file
|
|
12
15
|
trc --lsp Start LSP server (for IDE integration)
|
|
@@ -15,8 +18,11 @@ module TRuby
|
|
|
15
18
|
|
|
16
19
|
Examples:
|
|
17
20
|
trc hello.trb Compile hello.trb to build/hello.rb
|
|
18
|
-
trc
|
|
19
|
-
trc
|
|
21
|
+
trc utils.rb Copy utils.rb to build/ and generate utils.rbs
|
|
22
|
+
trc --init Create trbconfig.yml and src/, build/ directories
|
|
23
|
+
trc -c custom.yml file.trb Compile with custom config file
|
|
24
|
+
trc -w Watch all .trb and .rb files in current directory
|
|
25
|
+
trc -w src/ Watch all .trb and .rb files in src/ directory
|
|
20
26
|
trc --watch hello.trb Watch specific file for changes
|
|
21
27
|
trc --decl hello.trb Generate hello.d.trb declaration file
|
|
22
28
|
trc --lsp Start language server for VS Code
|
|
@@ -41,6 +47,11 @@ module TRuby
|
|
|
41
47
|
return
|
|
42
48
|
end
|
|
43
49
|
|
|
50
|
+
if @args.include?("--init")
|
|
51
|
+
init_project
|
|
52
|
+
return
|
|
53
|
+
end
|
|
54
|
+
|
|
44
55
|
if @args.include?("--lsp")
|
|
45
56
|
start_lsp_server
|
|
46
57
|
return
|
|
@@ -57,12 +68,95 @@ module TRuby
|
|
|
57
68
|
return
|
|
58
69
|
end
|
|
59
70
|
|
|
60
|
-
|
|
61
|
-
|
|
71
|
+
# Extract config path if --config or -c flag is present
|
|
72
|
+
config_path = extract_config_path
|
|
73
|
+
|
|
74
|
+
# Get input file (first non-flag argument)
|
|
75
|
+
input_file = find_input_file
|
|
76
|
+
compile(input_file, config_path: config_path)
|
|
62
77
|
end
|
|
63
78
|
|
|
64
79
|
private
|
|
65
80
|
|
|
81
|
+
def init_project
|
|
82
|
+
config_file = "trbconfig.yml"
|
|
83
|
+
src_dir = "src"
|
|
84
|
+
build_dir = "build"
|
|
85
|
+
|
|
86
|
+
created = []
|
|
87
|
+
skipped = []
|
|
88
|
+
|
|
89
|
+
# Create trbconfig.yml with new schema
|
|
90
|
+
if File.exist?(config_file)
|
|
91
|
+
skipped << config_file
|
|
92
|
+
else
|
|
93
|
+
File.write(config_file, <<~YAML)
|
|
94
|
+
# T-Ruby configuration file
|
|
95
|
+
# See: https://type-ruby.github.io/docs/getting-started/project-configuration
|
|
96
|
+
|
|
97
|
+
source:
|
|
98
|
+
include:
|
|
99
|
+
- #{src_dir}
|
|
100
|
+
exclude: []
|
|
101
|
+
extensions:
|
|
102
|
+
- ".trb"
|
|
103
|
+
- ".rb"
|
|
104
|
+
|
|
105
|
+
output:
|
|
106
|
+
ruby_dir: #{build_dir}
|
|
107
|
+
# rbs_dir: sig # Optional: separate directory for .rbs files
|
|
108
|
+
preserve_structure: true
|
|
109
|
+
# clean_before_build: false
|
|
110
|
+
|
|
111
|
+
compiler:
|
|
112
|
+
strictness: standard # strict | standard | permissive
|
|
113
|
+
generate_rbs: true
|
|
114
|
+
target_ruby: "3.0"
|
|
115
|
+
# experimental: []
|
|
116
|
+
# checks:
|
|
117
|
+
# no_implicit_any: false
|
|
118
|
+
# no_unused_vars: false
|
|
119
|
+
# strict_nil: false
|
|
120
|
+
|
|
121
|
+
watch:
|
|
122
|
+
# paths: [] # Additional paths to watch
|
|
123
|
+
debounce: 100
|
|
124
|
+
# clear_screen: false
|
|
125
|
+
# on_success: "bundle exec rspec"
|
|
126
|
+
YAML
|
|
127
|
+
created << config_file
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Create src/ directory
|
|
131
|
+
if Dir.exist?(src_dir)
|
|
132
|
+
skipped << "#{src_dir}/"
|
|
133
|
+
else
|
|
134
|
+
Dir.mkdir(src_dir)
|
|
135
|
+
created << "#{src_dir}/"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Create build/ directory
|
|
139
|
+
if Dir.exist?(build_dir)
|
|
140
|
+
skipped << "#{build_dir}/"
|
|
141
|
+
else
|
|
142
|
+
Dir.mkdir(build_dir)
|
|
143
|
+
created << "#{build_dir}/"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Output results
|
|
147
|
+
if created.any?
|
|
148
|
+
puts "Created: #{created.join(', ')}"
|
|
149
|
+
end
|
|
150
|
+
if skipped.any?
|
|
151
|
+
puts "Skipped (already exists): #{skipped.join(', ')}"
|
|
152
|
+
end
|
|
153
|
+
if created.empty? && skipped.any?
|
|
154
|
+
puts "Project already initialized."
|
|
155
|
+
else
|
|
156
|
+
puts "t-ruby project initialized successfully!"
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
66
160
|
def start_lsp_server
|
|
67
161
|
server = LSPServer.new
|
|
68
162
|
server.run
|
|
@@ -92,8 +186,8 @@ module TRuby
|
|
|
92
186
|
exit 1
|
|
93
187
|
end
|
|
94
188
|
|
|
95
|
-
def compile(input_file)
|
|
96
|
-
config = Config.new
|
|
189
|
+
def compile(input_file, config_path: nil)
|
|
190
|
+
config = Config.new(config_path)
|
|
97
191
|
compiler = Compiler.new(config)
|
|
98
192
|
|
|
99
193
|
output_path = compiler.compile(input_file)
|
|
@@ -102,5 +196,36 @@ module TRuby
|
|
|
102
196
|
puts "Error: #{e.message}"
|
|
103
197
|
exit 1
|
|
104
198
|
end
|
|
199
|
+
|
|
200
|
+
# Extract config path from --config or -c flag
|
|
201
|
+
def extract_config_path
|
|
202
|
+
config_index = @args.index("--config") || @args.index("-c")
|
|
203
|
+
return nil unless config_index
|
|
204
|
+
|
|
205
|
+
@args[config_index + 1]
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Find the input file (first non-flag argument)
|
|
209
|
+
def find_input_file
|
|
210
|
+
skip_next = false
|
|
211
|
+
@args.each do |arg|
|
|
212
|
+
if skip_next
|
|
213
|
+
skip_next = false
|
|
214
|
+
next
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Skip known flags with arguments
|
|
218
|
+
if %w[--config -c --decl].include?(arg)
|
|
219
|
+
skip_next = true
|
|
220
|
+
next
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Skip flags without arguments
|
|
224
|
+
next if arg.start_with?("-")
|
|
225
|
+
|
|
226
|
+
return arg
|
|
227
|
+
end
|
|
228
|
+
nil
|
|
229
|
+
end
|
|
105
230
|
end
|
|
106
231
|
end
|
data/lib/t_ruby/compiler.rb
CHANGED
|
@@ -6,13 +6,13 @@ module TRuby
|
|
|
6
6
|
class Compiler
|
|
7
7
|
attr_reader :declaration_loader, :use_ir, :optimizer
|
|
8
8
|
|
|
9
|
-
def initialize(config, use_ir: true, optimize: true)
|
|
10
|
-
@config = config
|
|
9
|
+
def initialize(config = nil, use_ir: true, optimize: true)
|
|
10
|
+
@config = config || Config.new
|
|
11
11
|
@use_ir = use_ir
|
|
12
12
|
@optimize = optimize
|
|
13
13
|
@declaration_loader = DeclarationLoader.new
|
|
14
14
|
@optimizer = IR::Optimizer.new if use_ir && optimize
|
|
15
|
-
setup_declaration_paths
|
|
15
|
+
setup_declaration_paths if @config
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def compile(input_path)
|
|
@@ -20,8 +20,13 @@ module TRuby
|
|
|
20
20
|
raise ArgumentError, "File not found: #{input_path}"
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
# Handle .rb files separately
|
|
24
|
+
if input_path.end_with?(".rb")
|
|
25
|
+
return copy_ruby_file(input_path)
|
|
26
|
+
end
|
|
27
|
+
|
|
23
28
|
unless input_path.end_with?(".trb")
|
|
24
|
-
raise ArgumentError, "Expected .trb file, got: #{input_path}"
|
|
29
|
+
raise ArgumentError, "Expected .trb or .rb file, got: #{input_path}"
|
|
25
30
|
end
|
|
26
31
|
|
|
27
32
|
source = File.read(input_path)
|
|
@@ -42,22 +47,73 @@ module TRuby
|
|
|
42
47
|
File.write(output_path, output)
|
|
43
48
|
|
|
44
49
|
# Generate .rbs file if enabled in config
|
|
45
|
-
if @config.
|
|
50
|
+
if @config.compiler["generate_rbs"]
|
|
51
|
+
rbs_dir = @config.rbs_dir
|
|
52
|
+
FileUtils.mkdir_p(rbs_dir)
|
|
46
53
|
if @use_ir && parser.ir_program
|
|
47
|
-
generate_rbs_from_ir(base_filename,
|
|
54
|
+
generate_rbs_from_ir(base_filename, rbs_dir, parser.ir_program)
|
|
48
55
|
else
|
|
49
|
-
generate_rbs_file(base_filename,
|
|
56
|
+
generate_rbs_file(base_filename, rbs_dir, parse_result)
|
|
50
57
|
end
|
|
51
58
|
end
|
|
52
59
|
|
|
53
|
-
# Generate .d.trb file if enabled in config
|
|
54
|
-
|
|
60
|
+
# Generate .d.trb file if enabled in config (legacy support)
|
|
61
|
+
# TODO: Add compiler.generate_dtrb option in future
|
|
62
|
+
if @config.compiler.key?("generate_dtrb") && @config.compiler["generate_dtrb"]
|
|
55
63
|
generate_dtrb_file(input_path, out_dir)
|
|
56
64
|
end
|
|
57
65
|
|
|
58
66
|
output_path
|
|
59
67
|
end
|
|
60
68
|
|
|
69
|
+
# Compile T-Ruby source code from a string (useful for WASM/playground)
|
|
70
|
+
# @param source [String] T-Ruby source code
|
|
71
|
+
# @param options [Hash] Options for compilation
|
|
72
|
+
# @option options [Boolean] :rbs Whether to generate RBS output (default: true)
|
|
73
|
+
# @return [Hash] Result with :ruby, :rbs, :errors keys
|
|
74
|
+
def compile_string(source, options = {})
|
|
75
|
+
generate_rbs = options.fetch(:rbs, true)
|
|
76
|
+
|
|
77
|
+
parser = Parser.new(source, use_combinator: @use_ir)
|
|
78
|
+
parse_result = parser.parse
|
|
79
|
+
|
|
80
|
+
# Transform source to Ruby code
|
|
81
|
+
ruby_output = @use_ir ? transform_with_ir(source, parser) : transform_legacy(source, parse_result)
|
|
82
|
+
|
|
83
|
+
# Generate RBS if requested
|
|
84
|
+
rbs_output = ""
|
|
85
|
+
if generate_rbs
|
|
86
|
+
if @use_ir && parser.ir_program
|
|
87
|
+
generator = IR::RBSGenerator.new
|
|
88
|
+
rbs_output = generator.generate(parser.ir_program)
|
|
89
|
+
else
|
|
90
|
+
generator = RBSGenerator.new
|
|
91
|
+
rbs_output = generator.generate(
|
|
92
|
+
parse_result[:functions] || [],
|
|
93
|
+
parse_result[:type_aliases] || []
|
|
94
|
+
)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
{
|
|
99
|
+
ruby: ruby_output,
|
|
100
|
+
rbs: rbs_output,
|
|
101
|
+
errors: []
|
|
102
|
+
}
|
|
103
|
+
rescue ParseError => e
|
|
104
|
+
{
|
|
105
|
+
ruby: "",
|
|
106
|
+
rbs: "",
|
|
107
|
+
errors: [e.message]
|
|
108
|
+
}
|
|
109
|
+
rescue StandardError => e
|
|
110
|
+
{
|
|
111
|
+
ruby: "",
|
|
112
|
+
rbs: "",
|
|
113
|
+
errors: ["Compilation error: #{e.message}"]
|
|
114
|
+
}
|
|
115
|
+
end
|
|
116
|
+
|
|
61
117
|
# Compile to IR without generating output files
|
|
62
118
|
def compile_to_ir(input_path)
|
|
63
119
|
unless File.exist?(input_path)
|
|
@@ -166,6 +222,38 @@ module TRuby
|
|
|
166
222
|
generator = DeclarationGenerator.new
|
|
167
223
|
generator.generate_file(input_path, out_dir)
|
|
168
224
|
end
|
|
225
|
+
|
|
226
|
+
# Copy .rb file to output directory and generate .rbs signature
|
|
227
|
+
def copy_ruby_file(input_path)
|
|
228
|
+
unless File.exist?(input_path)
|
|
229
|
+
raise ArgumentError, "File not found: #{input_path}"
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
out_dir = @config.out_dir
|
|
233
|
+
FileUtils.mkdir_p(out_dir)
|
|
234
|
+
|
|
235
|
+
base_filename = File.basename(input_path, ".rb")
|
|
236
|
+
output_path = File.join(out_dir, base_filename + ".rb")
|
|
237
|
+
|
|
238
|
+
# Copy the .rb file to output directory
|
|
239
|
+
FileUtils.cp(input_path, output_path)
|
|
240
|
+
|
|
241
|
+
# Generate .rbs file if enabled in config
|
|
242
|
+
if @config.compiler["generate_rbs"]
|
|
243
|
+
rbs_dir = @config.rbs_dir
|
|
244
|
+
FileUtils.mkdir_p(rbs_dir)
|
|
245
|
+
generate_rbs_from_ruby(base_filename, rbs_dir, input_path)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
output_path
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Generate RBS from Ruby file using rbs prototype
|
|
252
|
+
def generate_rbs_from_ruby(base_filename, out_dir, input_path)
|
|
253
|
+
rbs_path = File.join(out_dir, base_filename + ".rbs")
|
|
254
|
+
result = `rbs prototype rb #{input_path} 2>/dev/null`
|
|
255
|
+
File.write(rbs_path, result) unless result.strip.empty?
|
|
256
|
+
end
|
|
169
257
|
end
|
|
170
258
|
|
|
171
259
|
# IR-aware code generator for source-preserving transformation
|