t-ruby 0.0.36 → 0.0.38
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 +2 -2
- data/lib/t_ruby/cli.rb +26 -2
- data/lib/t_ruby/compiler.rb +86 -30
- data/lib/t_ruby/config.rb +0 -7
- data/lib/t_ruby/declaration_generator.rb +17 -0
- data/lib/t_ruby/version.rb +1 -1
- data/lib/t_ruby/version_checker.rb +60 -0
- data/lib/t_ruby.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dc0d0297e719aa0061465983334438eeb0ce5d4230e5d1f363cbfe5d3def7b66
|
|
4
|
+
data.tar.gz: 898d406d4ce3b0a415312ee2473fff6e7983accd0227aed7030ba5eb396c868f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '00942ff35f9b6dc3824959cf42e72d35731e41f34156cb063eccc21c18686382fc1faf7b17e3e91caeb8910f2c5f6663fcae30877660e7c09e1e9d90f735ac97'
|
|
7
|
+
data.tar.gz: cd5893ac01d1c9e4e969e20739a1e21b2bcf174b5aac6ca54ab0cb52a0f41d411bff883b204b1669de513399e801533e83beba2f46b9e8cc4b1c6cb5aa17ba46
|
data/README.md
CHANGED
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<img src="https://img.shields.io/
|
|
12
|
+
<a href="https://github.com/type-ruby/t-ruby/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/type-ruby/t-ruby/ci.yml?label=CI" alt="CI" /></a>
|
|
13
13
|
<img src="https://img.shields.io/badge/ruby-3.0+-cc342d" alt="Ruby 3.0+" />
|
|
14
14
|
<a href="https://rubygems.org/gems/t-ruby"><img src="https://img.shields.io/gem/v/t-ruby" alt="Gem Version" /></a>
|
|
15
15
|
<img src="https://img.shields.io/gem/dt/t-ruby" alt="Downloads" />
|
|
16
|
-
<img src="https://
|
|
16
|
+
<a href="https://coveralls.io/github/type-ruby/t-ruby?branch=main"><img src="https://coveralls.io/repos/github/type-ruby/t-ruby/badge.svg?branch=main" alt="Coverage" /></a>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
19
|
<p align="center">
|
data/lib/t_ruby/cli.rb
CHANGED
|
@@ -13,7 +13,8 @@ module TRuby
|
|
|
13
13
|
trc --watch, -w Watch input files and recompile on change
|
|
14
14
|
trc --decl <file.trb> Generate .d.trb declaration file
|
|
15
15
|
trc --lsp Start LSP server (for IDE integration)
|
|
16
|
-
trc
|
|
16
|
+
trc update Update t-ruby to the latest version
|
|
17
|
+
trc --version, -v Show version (and check for updates)
|
|
17
18
|
trc --help, -h Show this help
|
|
18
19
|
|
|
19
20
|
Examples:
|
|
@@ -44,6 +45,12 @@ module TRuby
|
|
|
44
45
|
|
|
45
46
|
if @args.include?("--version") || @args.include?("-v")
|
|
46
47
|
puts "trc #{VERSION}"
|
|
48
|
+
check_for_updates
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if @args.include?("update")
|
|
53
|
+
update_gem
|
|
47
54
|
return
|
|
48
55
|
end
|
|
49
56
|
|
|
@@ -78,6 +85,24 @@ module TRuby
|
|
|
78
85
|
|
|
79
86
|
private
|
|
80
87
|
|
|
88
|
+
def check_for_updates
|
|
89
|
+
result = VersionChecker.check
|
|
90
|
+
return unless result
|
|
91
|
+
|
|
92
|
+
puts ""
|
|
93
|
+
puts "New version available: #{result[:latest]} (current: #{result[:current]})"
|
|
94
|
+
puts "Run 'trc update' to update"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def update_gem
|
|
98
|
+
puts "Updating t-ruby..."
|
|
99
|
+
if VersionChecker.update
|
|
100
|
+
puts "Successfully updated t-ruby!"
|
|
101
|
+
else
|
|
102
|
+
puts "Update failed. Try: gem install t-ruby"
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
81
106
|
def init_project
|
|
82
107
|
config_file = "trbconfig.yml"
|
|
83
108
|
src_dir = "src"
|
|
@@ -105,7 +130,6 @@ module TRuby
|
|
|
105
130
|
output:
|
|
106
131
|
ruby_dir: #{build_dir}
|
|
107
132
|
# rbs_dir: sig # Optional: separate directory for .rbs files
|
|
108
|
-
preserve_structure: true
|
|
109
133
|
# clean_before_build: false
|
|
110
134
|
|
|
111
135
|
compiler:
|
data/lib/t_ruby/compiler.rb
CHANGED
|
@@ -38,29 +38,27 @@ module TRuby
|
|
|
38
38
|
# Transform source to Ruby code
|
|
39
39
|
output = @use_ir ? transform_with_ir(source, parser) : transform_legacy(source, parse_result)
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
base_filename = File.basename(input_path, ".trb")
|
|
45
|
-
output_path = File.join(out_dir, "#{base_filename}.rb")
|
|
41
|
+
# Compute output path (respects preserve_structure setting)
|
|
42
|
+
output_path = compute_output_path(input_path, @config.ruby_dir, ".rb")
|
|
43
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
|
46
44
|
|
|
47
45
|
File.write(output_path, output)
|
|
48
46
|
|
|
49
47
|
# Generate .rbs file if enabled in config
|
|
50
48
|
if @config.compiler["generate_rbs"]
|
|
51
|
-
|
|
52
|
-
FileUtils.mkdir_p(
|
|
49
|
+
rbs_path = compute_output_path(input_path, @config.rbs_dir, ".rbs")
|
|
50
|
+
FileUtils.mkdir_p(File.dirname(rbs_path))
|
|
53
51
|
if @use_ir && parser.ir_program
|
|
54
|
-
|
|
52
|
+
generate_rbs_from_ir_to_path(rbs_path, parser.ir_program)
|
|
55
53
|
else
|
|
56
|
-
|
|
54
|
+
generate_rbs_file_to_path(rbs_path, parse_result)
|
|
57
55
|
end
|
|
58
56
|
end
|
|
59
57
|
|
|
60
58
|
# Generate .d.trb file if enabled in config (legacy support)
|
|
61
59
|
# TODO: Add compiler.generate_dtrb option in future
|
|
62
60
|
if @config.compiler.key?("generate_dtrb") && @config.compiler["generate_dtrb"]
|
|
63
|
-
generate_dtrb_file(input_path,
|
|
61
|
+
generate_dtrb_file(input_path, @config.ruby_dir)
|
|
64
62
|
end
|
|
65
63
|
|
|
66
64
|
output_path
|
|
@@ -161,8 +159,70 @@ module TRuby
|
|
|
161
159
|
@optimizer&.stats
|
|
162
160
|
end
|
|
163
161
|
|
|
162
|
+
# Compute output path for a source file
|
|
163
|
+
# @param input_path [String] path to source file
|
|
164
|
+
# @param output_dir [String] base output directory
|
|
165
|
+
# @param new_extension [String] new file extension (e.g., ".rb", ".rbs")
|
|
166
|
+
# @return [String] computed output path (always preserves directory structure)
|
|
167
|
+
def compute_output_path(input_path, output_dir, new_extension)
|
|
168
|
+
relative = compute_relative_path(input_path)
|
|
169
|
+
base = relative.sub(/\.[^.]+$/, new_extension)
|
|
170
|
+
File.join(output_dir, base)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Compute relative path from source directory
|
|
174
|
+
# @param input_path [String] path to source file
|
|
175
|
+
# @return [String] relative path preserving directory structure
|
|
176
|
+
def compute_relative_path(input_path)
|
|
177
|
+
# Use realpath to resolve symlinks (e.g., /var vs /private/var on macOS)
|
|
178
|
+
absolute_input = resolve_path(input_path)
|
|
179
|
+
source_dirs = @config.source_include
|
|
180
|
+
|
|
181
|
+
# Check if file is inside any source_include directory
|
|
182
|
+
if source_dirs.size > 1
|
|
183
|
+
# Multiple source directories: include the source dir name in output
|
|
184
|
+
# src/models/user.trb → src/models/user.trb
|
|
185
|
+
source_dirs.each do |src_dir|
|
|
186
|
+
absolute_src = resolve_path(src_dir)
|
|
187
|
+
next unless absolute_input.start_with?("#{absolute_src}/")
|
|
188
|
+
|
|
189
|
+
# Return path relative to parent of source dir (includes src dir name)
|
|
190
|
+
parent_of_src = File.dirname(absolute_src)
|
|
191
|
+
return absolute_input.sub("#{parent_of_src}/", "")
|
|
192
|
+
end
|
|
193
|
+
else
|
|
194
|
+
# Single source directory: exclude the source dir name from output
|
|
195
|
+
# src/models/user.trb → models/user.trb
|
|
196
|
+
src_dir = source_dirs.first
|
|
197
|
+
if src_dir
|
|
198
|
+
absolute_src = resolve_path(src_dir)
|
|
199
|
+
if absolute_input.start_with?("#{absolute_src}/")
|
|
200
|
+
return absolute_input.sub("#{absolute_src}/", "")
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# File outside source directories: use path relative to current working directory
|
|
206
|
+
# external/foo.trb → external/foo.trb
|
|
207
|
+
cwd = resolve_path(".")
|
|
208
|
+
if absolute_input.start_with?("#{cwd}/")
|
|
209
|
+
return absolute_input.sub("#{cwd}/", "")
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Absolute path from outside cwd: use basename only
|
|
213
|
+
File.basename(input_path)
|
|
214
|
+
end
|
|
215
|
+
|
|
164
216
|
private
|
|
165
217
|
|
|
218
|
+
# Resolve path to absolute path, following symlinks
|
|
219
|
+
# Falls back to expand_path if realpath fails (e.g., file doesn't exist yet)
|
|
220
|
+
def resolve_path(path)
|
|
221
|
+
File.realpath(path)
|
|
222
|
+
rescue Errno::ENOENT
|
|
223
|
+
File.expand_path(path)
|
|
224
|
+
end
|
|
225
|
+
|
|
166
226
|
def setup_declaration_paths
|
|
167
227
|
# Add default declaration paths
|
|
168
228
|
@declaration_loader.add_search_path(@config.out_dir)
|
|
@@ -197,30 +257,29 @@ module TRuby
|
|
|
197
257
|
end
|
|
198
258
|
end
|
|
199
259
|
|
|
200
|
-
# Generate RBS from IR
|
|
201
|
-
def
|
|
260
|
+
# Generate RBS from IR to a specific path
|
|
261
|
+
def generate_rbs_from_ir_to_path(rbs_path, ir_program)
|
|
202
262
|
generator = IR::RBSGenerator.new
|
|
203
263
|
rbs_content = generator.generate(ir_program)
|
|
204
|
-
|
|
205
|
-
rbs_path = File.join(out_dir, "#{base_filename}.rbs")
|
|
206
264
|
File.write(rbs_path, rbs_content) unless rbs_content.strip.empty?
|
|
207
265
|
end
|
|
208
266
|
|
|
209
|
-
# Legacy RBS generation
|
|
210
|
-
def
|
|
267
|
+
# Legacy RBS generation to a specific path
|
|
268
|
+
def generate_rbs_file_to_path(rbs_path, parse_result)
|
|
211
269
|
generator = RBSGenerator.new
|
|
212
270
|
rbs_content = generator.generate(
|
|
213
271
|
parse_result[:functions] || [],
|
|
214
272
|
parse_result[:type_aliases] || []
|
|
215
273
|
)
|
|
216
|
-
|
|
217
|
-
rbs_path = File.join(out_dir, "#{base_filename}.rbs")
|
|
218
274
|
File.write(rbs_path, rbs_content) unless rbs_content.empty?
|
|
219
275
|
end
|
|
220
276
|
|
|
221
277
|
def generate_dtrb_file(input_path, out_dir)
|
|
278
|
+
dtrb_path = compute_output_path(input_path, out_dir, DeclarationGenerator::DECLARATION_EXTENSION)
|
|
279
|
+
FileUtils.mkdir_p(File.dirname(dtrb_path))
|
|
280
|
+
|
|
222
281
|
generator = DeclarationGenerator.new
|
|
223
|
-
generator.
|
|
282
|
+
generator.generate_file_to_path(input_path, dtrb_path)
|
|
224
283
|
end
|
|
225
284
|
|
|
226
285
|
# Copy .rb file to output directory and generate .rbs signature
|
|
@@ -229,28 +288,25 @@ module TRuby
|
|
|
229
288
|
raise ArgumentError, "File not found: #{input_path}"
|
|
230
289
|
end
|
|
231
290
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
base_filename = File.basename(input_path, ".rb")
|
|
236
|
-
output_path = File.join(out_dir, "#{base_filename}.rb")
|
|
291
|
+
# Compute output path (respects preserve_structure setting)
|
|
292
|
+
output_path = compute_output_path(input_path, @config.ruby_dir, ".rb")
|
|
293
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
|
237
294
|
|
|
238
295
|
# Copy the .rb file to output directory
|
|
239
296
|
FileUtils.cp(input_path, output_path)
|
|
240
297
|
|
|
241
298
|
# Generate .rbs file if enabled in config
|
|
242
299
|
if @config.compiler["generate_rbs"]
|
|
243
|
-
|
|
244
|
-
FileUtils.mkdir_p(
|
|
245
|
-
|
|
300
|
+
rbs_path = compute_output_path(input_path, @config.rbs_dir, ".rbs")
|
|
301
|
+
FileUtils.mkdir_p(File.dirname(rbs_path))
|
|
302
|
+
generate_rbs_from_ruby_to_path(rbs_path, input_path)
|
|
246
303
|
end
|
|
247
304
|
|
|
248
305
|
output_path
|
|
249
306
|
end
|
|
250
307
|
|
|
251
|
-
# Generate RBS from Ruby file using rbs prototype
|
|
252
|
-
def
|
|
253
|
-
rbs_path = File.join(out_dir, "#{base_filename}.rbs")
|
|
308
|
+
# Generate RBS from Ruby file using rbs prototype to a specific path
|
|
309
|
+
def generate_rbs_from_ruby_to_path(rbs_path, input_path)
|
|
254
310
|
result = `rbs prototype rb #{input_path} 2>/dev/null`
|
|
255
311
|
File.write(rbs_path, result) unless result.strip.empty?
|
|
256
312
|
end
|
data/lib/t_ruby/config.rb
CHANGED
|
@@ -19,7 +19,6 @@ module TRuby
|
|
|
19
19
|
"output" => {
|
|
20
20
|
"ruby_dir" => "build",
|
|
21
21
|
"rbs_dir" => nil,
|
|
22
|
-
"preserve_structure" => true,
|
|
23
22
|
"clean_before_build" => false,
|
|
24
23
|
},
|
|
25
24
|
"compiler" => {
|
|
@@ -72,12 +71,6 @@ module TRuby
|
|
|
72
71
|
@output["rbs_dir"] || ruby_dir
|
|
73
72
|
end
|
|
74
73
|
|
|
75
|
-
# Check if source directory structure should be preserved in output
|
|
76
|
-
# @return [Boolean] true if structure should be preserved
|
|
77
|
-
def preserve_structure?
|
|
78
|
-
@output["preserve_structure"] != false
|
|
79
|
-
end
|
|
80
|
-
|
|
81
74
|
# Check if output directory should be cleaned before build
|
|
82
75
|
# @return [Boolean] true if should clean before build
|
|
83
76
|
def clean_before_build?
|
|
@@ -64,6 +64,23 @@ module TRuby
|
|
|
64
64
|
output_path
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
# Generate declaration file to a specific output path
|
|
68
|
+
def generate_file_to_path(input_path, output_path)
|
|
69
|
+
unless File.exist?(input_path)
|
|
70
|
+
raise ArgumentError, "File not found: #{input_path}"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
unless input_path.end_with?(".trb")
|
|
74
|
+
raise ArgumentError, "Expected .trb file, got: #{input_path}"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
source = File.read(input_path)
|
|
78
|
+
content = generate(source)
|
|
79
|
+
|
|
80
|
+
File.write(output_path, content)
|
|
81
|
+
output_path
|
|
82
|
+
end
|
|
83
|
+
|
|
67
84
|
private
|
|
68
85
|
|
|
69
86
|
def generate_type_alias(type_alias)
|
data/lib/t_ruby/version.rb
CHANGED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
require "uri"
|
|
6
|
+
require "openssl"
|
|
7
|
+
|
|
8
|
+
module TRuby
|
|
9
|
+
class VersionChecker
|
|
10
|
+
GEM_NAME = "t-ruby"
|
|
11
|
+
RUBYGEMS_API = "https://rubygems.org/api/v1/gems/#{GEM_NAME}.json".freeze
|
|
12
|
+
|
|
13
|
+
def self.check
|
|
14
|
+
new.check
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.update
|
|
18
|
+
new.update
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def check
|
|
22
|
+
latest = fetch_latest_version
|
|
23
|
+
return nil unless latest
|
|
24
|
+
|
|
25
|
+
current = Gem::Version.new(VERSION)
|
|
26
|
+
latest_version = Gem::Version.new(latest)
|
|
27
|
+
|
|
28
|
+
return nil if current >= latest_version
|
|
29
|
+
|
|
30
|
+
{ current: VERSION, latest: latest }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def update
|
|
34
|
+
system("gem install #{GEM_NAME}")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def fetch_latest_version
|
|
40
|
+
uri = URI(RUBYGEMS_API)
|
|
41
|
+
|
|
42
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
43
|
+
http.use_ssl = true
|
|
44
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
45
|
+
http.verify_callback = ->(_preverify_ok, _store_ctx) { true } # Skip CRL check
|
|
46
|
+
http.open_timeout = 3
|
|
47
|
+
http.read_timeout = 3
|
|
48
|
+
|
|
49
|
+
request = Net::HTTP::Get.new(uri)
|
|
50
|
+
response = http.request(request)
|
|
51
|
+
|
|
52
|
+
return nil unless response.is_a?(Net::HTTPSuccess)
|
|
53
|
+
|
|
54
|
+
data = JSON.parse(response.body)
|
|
55
|
+
data["version"]
|
|
56
|
+
rescue StandardError
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/t_ruby.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: t-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.38
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Y. Fred Kim
|
|
@@ -65,6 +65,7 @@ files:
|
|
|
65
65
|
- lib/t_ruby/type_inferencer.rb
|
|
66
66
|
- lib/t_ruby/union_type_parser.rb
|
|
67
67
|
- lib/t_ruby/version.rb
|
|
68
|
+
- lib/t_ruby/version_checker.rb
|
|
68
69
|
- lib/t_ruby/watcher.rb
|
|
69
70
|
homepage: https://type-ruby.github.io
|
|
70
71
|
licenses:
|