t-ruby 0.0.34 → 0.0.36
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 +71 -9
- data/lib/t_ruby/benchmark.rb +16 -16
- data/lib/t_ruby/bundler_integration.rb +33 -35
- data/lib/t_ruby/cache.rb +46 -43
- data/lib/t_ruby/cli.rb +3 -3
- data/lib/t_ruby/compiler.rb +25 -27
- data/lib/t_ruby/config.rb +15 -11
- data/lib/t_ruby/constraint_checker.rb +14 -8
- data/lib/t_ruby/declaration_generator.rb +8 -8
- data/lib/t_ruby/doc_generator.rb +33 -33
- data/lib/t_ruby/docs_badge_generator.rb +8 -8
- data/lib/t_ruby/docs_example_verifier.rb +5 -6
- data/lib/t_ruby/error_handler.rb +21 -22
- data/lib/t_ruby/generic_type_parser.rb +3 -3
- data/lib/t_ruby/intersection_type_parser.rb +2 -2
- data/lib/t_ruby/ir.rb +21 -24
- data/lib/t_ruby/lsp_server.rb +128 -138
- data/lib/t_ruby/package_manager.rb +16 -18
- data/lib/t_ruby/parser.rb +7 -7
- data/lib/t_ruby/parser_combinator.rb +22 -22
- data/lib/t_ruby/rbs_generator.rb +2 -4
- data/lib/t_ruby/runtime_validator.rb +41 -37
- data/lib/t_ruby/smt_solver.rb +31 -29
- data/lib/t_ruby/type_alias_registry.rb +1 -0
- data/lib/t_ruby/type_checker.rb +64 -63
- data/lib/t_ruby/type_erasure.rb +2 -4
- data/lib/t_ruby/type_inferencer.rb +22 -26
- data/lib/t_ruby/union_type_parser.rb +3 -3
- data/lib/t_ruby/version.rb +1 -1
- data/lib/t_ruby/watcher.rb +18 -14
- metadata +4 -3
|
@@ -12,7 +12,7 @@ module TRuby
|
|
|
12
12
|
|
|
13
13
|
attr_reader :major, :minor, :patch, :prerelease
|
|
14
14
|
|
|
15
|
-
VERSION_REGEX = /^(\d+)\.(\d+)\.(\d+)(?:-(.+))
|
|
15
|
+
VERSION_REGEX = /^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/
|
|
16
16
|
|
|
17
17
|
def initialize(version_string)
|
|
18
18
|
match = VERSION_REGEX.match(version_string.to_s)
|
|
@@ -115,9 +115,8 @@ module TRuby
|
|
|
115
115
|
class PackageManifest
|
|
116
116
|
MANIFEST_FILE = ".trb-manifest.json"
|
|
117
117
|
|
|
118
|
-
attr_accessor :name, :version, :description, :author, :license
|
|
119
|
-
|
|
120
|
-
attr_accessor :repository, :keywords, :main
|
|
118
|
+
attr_accessor :name, :version, :description, :author, :license, :types, :dependencies, :dev_dependencies,
|
|
119
|
+
:repository, :keywords, :main
|
|
121
120
|
|
|
122
121
|
def initialize(data = {})
|
|
123
122
|
@name = data[:name] || data["name"]
|
|
@@ -145,11 +144,11 @@ module TRuby
|
|
|
145
144
|
devDependencies: @dev_dependencies,
|
|
146
145
|
repository: @repository,
|
|
147
146
|
keywords: @keywords,
|
|
148
|
-
main: @main
|
|
147
|
+
main: @main,
|
|
149
148
|
}.compact
|
|
150
149
|
end
|
|
151
150
|
|
|
152
|
-
def to_json(*
|
|
151
|
+
def to_json(*_args)
|
|
153
152
|
JSON.pretty_generate(to_h)
|
|
154
153
|
end
|
|
155
154
|
|
|
@@ -310,7 +309,7 @@ module TRuby
|
|
|
310
309
|
name: pkg["name"],
|
|
311
310
|
version: pkg["version"],
|
|
312
311
|
downloads: pkg["downloads"],
|
|
313
|
-
summary: pkg["info"] || pkg["summary"]
|
|
312
|
+
summary: pkg["info"] || pkg["summary"],
|
|
314
313
|
}
|
|
315
314
|
end
|
|
316
315
|
rescue StandardError => e
|
|
@@ -333,7 +332,7 @@ module TRuby
|
|
|
333
332
|
source_code: response["source_code_uri"],
|
|
334
333
|
documentation: response["documentation_uri"],
|
|
335
334
|
licenses: response["licenses"],
|
|
336
|
-
dependencies: parse_dependencies(response["dependencies"])
|
|
335
|
+
dependencies: parse_dependencies(response["dependencies"]),
|
|
337
336
|
}
|
|
338
337
|
rescue StandardError => e
|
|
339
338
|
warn "Failed to fetch package info: #{e.message}"
|
|
@@ -351,7 +350,7 @@ module TRuby
|
|
|
351
350
|
number: v["number"],
|
|
352
351
|
created_at: v["created_at"],
|
|
353
352
|
prerelease: v["prerelease"],
|
|
354
|
-
sha: v["sha"]
|
|
353
|
+
sha: v["sha"],
|
|
355
354
|
}
|
|
356
355
|
end
|
|
357
356
|
rescue StandardError => e
|
|
@@ -432,8 +431,6 @@ module TRuby
|
|
|
432
431
|
case response
|
|
433
432
|
when Net::HTTPSuccess
|
|
434
433
|
JSON.parse(response.body)
|
|
435
|
-
else
|
|
436
|
-
nil
|
|
437
434
|
end
|
|
438
435
|
rescue StandardError
|
|
439
436
|
nil
|
|
@@ -484,7 +481,7 @@ module TRuby
|
|
|
484
481
|
result
|
|
485
482
|
end
|
|
486
483
|
|
|
487
|
-
def extract_types(
|
|
484
|
+
def extract_types(_gem_path, target_dir)
|
|
488
485
|
# In a real implementation, would extract .d.trb files from gem
|
|
489
486
|
# For now, just create marker
|
|
490
487
|
File.write(File.join(target_dir, ".extracted"), Time.now.iso8601)
|
|
@@ -508,7 +505,7 @@ module TRuby
|
|
|
508
505
|
@packages[manifest.name] ||= {}
|
|
509
506
|
@packages[manifest.name][manifest.version] = {
|
|
510
507
|
dependencies: manifest.dependencies,
|
|
511
|
-
types: manifest.types
|
|
508
|
+
types: manifest.types,
|
|
512
509
|
}
|
|
513
510
|
end
|
|
514
511
|
|
|
@@ -524,6 +521,7 @@ module TRuby
|
|
|
524
521
|
if version == "*"
|
|
525
522
|
latest = get_versions(name).map { |v| SemanticVersion.parse(v) }.compact.max
|
|
526
523
|
return nil unless latest
|
|
524
|
+
|
|
527
525
|
version = latest.to_s
|
|
528
526
|
end
|
|
529
527
|
|
|
@@ -549,7 +547,7 @@ module TRuby
|
|
|
549
547
|
return nil unless pkg
|
|
550
548
|
|
|
551
549
|
# Copy type definitions
|
|
552
|
-
|
|
550
|
+
pkg[:types] || "**/*.d.trb"
|
|
553
551
|
# In real implementation, would download from registry
|
|
554
552
|
|
|
555
553
|
{ name: name, version: version, path: target }
|
|
@@ -616,7 +614,7 @@ module TRuby
|
|
|
616
614
|
result = @resolver.resolve(@manifest)
|
|
617
615
|
|
|
618
616
|
if result[:conflicts].any?
|
|
619
|
-
raise "Dependency conflicts: #{result[:conflicts].join(
|
|
617
|
+
raise "Dependency conflicts: #{result[:conflicts].join(", ")}"
|
|
620
618
|
end
|
|
621
619
|
|
|
622
620
|
installed = []
|
|
@@ -681,7 +679,7 @@ module TRuby
|
|
|
681
679
|
{
|
|
682
680
|
name: @manifest.name,
|
|
683
681
|
version: @manifest.version,
|
|
684
|
-
status: :published
|
|
682
|
+
status: :published,
|
|
685
683
|
}
|
|
686
684
|
end
|
|
687
685
|
|
|
@@ -693,7 +691,7 @@ module TRuby
|
|
|
693
691
|
package: @manifest.name,
|
|
694
692
|
version: version,
|
|
695
693
|
deprecated: true,
|
|
696
|
-
message: message
|
|
694
|
+
message: message,
|
|
697
695
|
}
|
|
698
696
|
end
|
|
699
697
|
|
|
@@ -709,7 +707,7 @@ module TRuby
|
|
|
709
707
|
lockfile = {
|
|
710
708
|
lockfileVersion: 1,
|
|
711
709
|
packages: resolved,
|
|
712
|
-
generatedAt: Time.now.iso8601
|
|
710
|
+
generatedAt: Time.now.iso8601,
|
|
713
711
|
}
|
|
714
712
|
|
|
715
713
|
File.write(
|
data/lib/t_ruby/parser.rb
CHANGED
|
@@ -55,7 +55,7 @@ module TRuby
|
|
|
55
55
|
type: :success,
|
|
56
56
|
functions: functions,
|
|
57
57
|
type_aliases: type_aliases,
|
|
58
|
-
interfaces: interfaces
|
|
58
|
+
interfaces: interfaces,
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
# Build IR if combinator is enabled
|
|
@@ -97,14 +97,14 @@ module TRuby
|
|
|
97
97
|
return {
|
|
98
98
|
name: alias_name,
|
|
99
99
|
definition: definition,
|
|
100
|
-
ir_type: type_result[:type]
|
|
100
|
+
ir_type: type_result[:type],
|
|
101
101
|
}
|
|
102
102
|
end
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
{
|
|
106
106
|
name: alias_name,
|
|
107
|
-
definition: definition
|
|
107
|
+
definition: definition,
|
|
108
108
|
}
|
|
109
109
|
end
|
|
110
110
|
|
|
@@ -126,7 +126,7 @@ module TRuby
|
|
|
126
126
|
result = {
|
|
127
127
|
name: function_name,
|
|
128
128
|
params: params,
|
|
129
|
-
return_type: return_type_str
|
|
129
|
+
return_type: return_type_str,
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
# Parse return type with combinator if available
|
|
@@ -195,7 +195,7 @@ module TRuby
|
|
|
195
195
|
depth -= 1
|
|
196
196
|
current += char
|
|
197
197
|
when ","
|
|
198
|
-
if depth
|
|
198
|
+
if depth.zero?
|
|
199
199
|
result << current.strip
|
|
200
200
|
current = ""
|
|
201
201
|
else
|
|
@@ -219,7 +219,7 @@ module TRuby
|
|
|
219
219
|
|
|
220
220
|
result = {
|
|
221
221
|
name: param_name,
|
|
222
|
-
type: type_str
|
|
222
|
+
type: type_str,
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
# Parse type with combinator if available
|
|
@@ -249,7 +249,7 @@ module TRuby
|
|
|
249
249
|
if member_match
|
|
250
250
|
member = {
|
|
251
251
|
name: member_match[1],
|
|
252
|
-
type: member_match[2].strip
|
|
252
|
+
type: member_match[2].strip,
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
# Parse member type with combinator
|
|
@@ -32,11 +32,13 @@ module TRuby
|
|
|
32
32
|
|
|
33
33
|
def map
|
|
34
34
|
return self if failure?
|
|
35
|
+
|
|
35
36
|
ParseResult.success(yield(value), remaining, position)
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
def flat_map
|
|
39
40
|
return self if failure?
|
|
41
|
+
|
|
40
42
|
yield(value, remaining, position)
|
|
41
43
|
end
|
|
42
44
|
end
|
|
@@ -167,7 +169,7 @@ module TRuby
|
|
|
167
169
|
remaining = input[position..]
|
|
168
170
|
match = @pattern.match(remaining)
|
|
169
171
|
|
|
170
|
-
if match
|
|
172
|
+
if match&.begin(0)&.zero?
|
|
171
173
|
matched = match[0]
|
|
172
174
|
ParseResult.success(matched, input, position + matched.length)
|
|
173
175
|
else
|
|
@@ -303,6 +305,7 @@ module TRuby
|
|
|
303
305
|
|
|
304
306
|
results << result.value
|
|
305
307
|
break if result.position == current_pos # Prevent infinite loop
|
|
308
|
+
|
|
306
309
|
current_pos = result.position
|
|
307
310
|
end
|
|
308
311
|
|
|
@@ -329,6 +332,7 @@ module TRuby
|
|
|
329
332
|
|
|
330
333
|
results << result.value
|
|
331
334
|
break if result.position == current_pos
|
|
335
|
+
|
|
332
336
|
current_pos = result.position
|
|
333
337
|
end
|
|
334
338
|
|
|
@@ -567,8 +571,8 @@ module TRuby
|
|
|
567
571
|
Fail.new(message)
|
|
568
572
|
end
|
|
569
573
|
|
|
570
|
-
def lazy(&
|
|
571
|
-
Lazy.new(&
|
|
574
|
+
def lazy(&)
|
|
575
|
+
Lazy.new(&)
|
|
572
576
|
end
|
|
573
577
|
|
|
574
578
|
def choice(*parsers)
|
|
@@ -597,11 +601,11 @@ module TRuby
|
|
|
597
601
|
end
|
|
598
602
|
|
|
599
603
|
def spaces
|
|
600
|
-
whitespace.many.map
|
|
604
|
+
whitespace.many.map(&:join)
|
|
601
605
|
end
|
|
602
606
|
|
|
603
607
|
def spaces1
|
|
604
|
-
whitespace.many1.map
|
|
608
|
+
whitespace.many1.map(&:join)
|
|
605
609
|
end
|
|
606
610
|
|
|
607
611
|
def newline
|
|
@@ -622,7 +626,7 @@ module TRuby
|
|
|
622
626
|
end
|
|
623
627
|
|
|
624
628
|
def float
|
|
625
|
-
regex(
|
|
629
|
+
regex(/-?\d+\.\d+/, "float").map(&:to_f)
|
|
626
630
|
end
|
|
627
631
|
|
|
628
632
|
def quoted_string(quote = '"')
|
|
@@ -670,7 +674,7 @@ module TRuby
|
|
|
670
674
|
type_name = identifier.label("type name")
|
|
671
675
|
|
|
672
676
|
# Simple type
|
|
673
|
-
|
|
677
|
+
type_name.map { |name| IR::SimpleType.new(name: name) }
|
|
674
678
|
|
|
675
679
|
# Lazy reference for recursive types
|
|
676
680
|
type_expr = lazy { @type_expr }
|
|
@@ -778,15 +782,15 @@ module TRuby
|
|
|
778
782
|
|
|
779
783
|
def build_parsers
|
|
780
784
|
# Type expression (delegate to TypeParser)
|
|
781
|
-
|
|
785
|
+
lazy { parse_type_inline }
|
|
782
786
|
|
|
783
787
|
# Keywords
|
|
784
788
|
kw_type = lexeme(string("type"))
|
|
785
789
|
kw_interface = lexeme(string("interface"))
|
|
786
790
|
kw_def = lexeme(string("def"))
|
|
787
791
|
kw_end = lexeme(string("end"))
|
|
788
|
-
|
|
789
|
-
|
|
792
|
+
lexeme(string("class"))
|
|
793
|
+
lexeme(string("module"))
|
|
790
794
|
|
|
791
795
|
# Type alias: type Name = Definition
|
|
792
796
|
type_alias = (
|
|
@@ -798,8 +802,6 @@ module TRuby
|
|
|
798
802
|
type_result = @type_parser.parse(definition)
|
|
799
803
|
if type_result[:success]
|
|
800
804
|
IR::TypeAlias.new(name: name, definition: type_result[:type])
|
|
801
|
-
else
|
|
802
|
-
nil
|
|
803
805
|
end
|
|
804
806
|
end
|
|
805
807
|
|
|
@@ -812,8 +814,6 @@ module TRuby
|
|
|
812
814
|
type_result = @type_parser.parse(type_str)
|
|
813
815
|
if type_result[:success]
|
|
814
816
|
IR::InterfaceMember.new(name: name, type_signature: type_result[:type])
|
|
815
|
-
else
|
|
816
|
-
nil
|
|
817
817
|
end
|
|
818
818
|
end
|
|
819
819
|
|
|
@@ -836,10 +836,10 @@ module TRuby
|
|
|
836
836
|
(lexeme(char(":")) >> regex(/[^,)]+/).map(&:strip)).optional
|
|
837
837
|
).map do |(name, type_str)|
|
|
838
838
|
type_node = if type_str
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
839
|
+
type_str_val = type_str.is_a?(Array) ? type_str.last : type_str
|
|
840
|
+
result = @type_parser.parse(type_str_val)
|
|
841
|
+
result[:success] ? result[:type] : nil
|
|
842
|
+
end
|
|
843
843
|
IR::Parameter.new(name: name, type_annotation: type_node)
|
|
844
844
|
end
|
|
845
845
|
|
|
@@ -864,9 +864,9 @@ module TRuby
|
|
|
864
864
|
return_type
|
|
865
865
|
).map do |(((_, name), params), ret_str)|
|
|
866
866
|
ret_type = if ret_str
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
867
|
+
result = @type_parser.parse(ret_str)
|
|
868
|
+
result[:success] ? result[:type] : nil
|
|
869
|
+
end
|
|
870
870
|
IR::MethodDef.new(
|
|
871
871
|
name: name,
|
|
872
872
|
params: params || [],
|
|
@@ -922,7 +922,7 @@ module TRuby
|
|
|
922
922
|
result << "#{prefix}#{i + 1}: #{input_lines[i]}"
|
|
923
923
|
|
|
924
924
|
if i == @line - 1
|
|
925
|
-
result << " "
|
|
925
|
+
result << " #{" " * (@column + @line.to_s.length + 1)}^"
|
|
926
926
|
end
|
|
927
927
|
end
|
|
928
928
|
|
data/lib/t_ruby/rbs_generator.rb
CHANGED
|
@@ -7,11 +7,9 @@ module TRuby
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def generate(functions, type_aliases)
|
|
10
|
-
lines = []
|
|
11
|
-
|
|
12
10
|
# Add type aliases
|
|
13
|
-
type_aliases.
|
|
14
|
-
|
|
11
|
+
lines = type_aliases.map do |type_alias|
|
|
12
|
+
generate_type_alias(type_alias)
|
|
15
13
|
end
|
|
16
14
|
|
|
17
15
|
lines << "" if type_aliases.any? && functions.any?
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
module TRuby
|
|
4
4
|
# Configuration for runtime validation
|
|
5
5
|
class ValidationConfig
|
|
6
|
-
attr_accessor :validate_all, :validate_public_only, :raise_on_error
|
|
7
|
-
attr_accessor :log_violations, :strict_mode
|
|
6
|
+
attr_accessor :validate_all, :validate_public_only, :raise_on_error, :log_violations, :strict_mode
|
|
8
7
|
|
|
9
8
|
def initialize
|
|
10
9
|
@validate_all = true
|
|
@@ -39,7 +38,7 @@ module TRuby
|
|
|
39
38
|
"Time" => ".is_a?(Time)",
|
|
40
39
|
"Date" => ".is_a?(Date)",
|
|
41
40
|
"IO" => ".is_a?(IO)",
|
|
42
|
-
"File" => ".is_a?(File)"
|
|
41
|
+
"File" => ".is_a?(File)",
|
|
43
42
|
}.freeze
|
|
44
43
|
|
|
45
44
|
def initialize(config = nil)
|
|
@@ -128,7 +127,7 @@ module TRuby
|
|
|
128
127
|
def generate_union_check(var_name, union_type)
|
|
129
128
|
types = union_type.split("|").map(&:strip)
|
|
130
129
|
checks = types.map { |t| generate_type_check(var_name, t) }
|
|
131
|
-
"(#{checks.join(
|
|
130
|
+
"(#{checks.join(" || ")})"
|
|
132
131
|
end
|
|
133
132
|
|
|
134
133
|
# Generate generic type check
|
|
@@ -141,16 +140,19 @@ module TRuby
|
|
|
141
140
|
|
|
142
141
|
case container_type
|
|
143
142
|
when "Array"
|
|
144
|
-
"#{var_name}.is_a?(Array) && #{var_name}.all? { |_e| #{generate_type_check(
|
|
143
|
+
"#{var_name}.is_a?(Array) && #{var_name}.all? { |_e| #{generate_type_check("_e", element_type)} }"
|
|
145
144
|
when "Hash"
|
|
146
145
|
if element_type.include?(",")
|
|
147
146
|
key_type, value_type = element_type.split(",").map(&:strip)
|
|
148
|
-
"#{var_name}.is_a?(Hash) && #{var_name}.all? { |_k, _v| #{generate_type_check(
|
|
147
|
+
"#{var_name}.is_a?(Hash) && #{var_name}.all? { |_k, _v| #{generate_type_check("_k",
|
|
148
|
+
key_type)} && #{generate_type_check(
|
|
149
|
+
"_v", value_type
|
|
150
|
+
)} }"
|
|
149
151
|
else
|
|
150
152
|
"#{var_name}.is_a?(Hash)"
|
|
151
153
|
end
|
|
152
154
|
when "Set"
|
|
153
|
-
"#{var_name}.is_a?(Set) && #{var_name}.all? { |_e| #{generate_type_check(
|
|
155
|
+
"#{var_name}.is_a?(Set) && #{var_name}.all? { |_e| #{generate_type_check("_e", element_type)} }"
|
|
154
156
|
else
|
|
155
157
|
# Generic with unknown container - just check container type
|
|
156
158
|
"#{var_name}.is_a?(#{container_type})"
|
|
@@ -161,7 +163,7 @@ module TRuby
|
|
|
161
163
|
def generate_intersection_check(var_name, intersection_type)
|
|
162
164
|
types = intersection_type.split("&").map(&:strip)
|
|
163
165
|
checks = types.map { |t| generate_type_check(var_name, t) }
|
|
164
|
-
"(#{checks.join(
|
|
166
|
+
"(#{checks.join(" && ")})"
|
|
165
167
|
end
|
|
166
168
|
|
|
167
169
|
# Generate return value validation wrapper
|
|
@@ -169,7 +171,7 @@ module TRuby
|
|
|
169
171
|
{
|
|
170
172
|
type: :return,
|
|
171
173
|
check: generate_type_check("_result", return_type),
|
|
172
|
-
return_type: return_type
|
|
174
|
+
return_type: return_type,
|
|
173
175
|
}
|
|
174
176
|
end
|
|
175
177
|
|
|
@@ -186,7 +188,7 @@ module TRuby
|
|
|
186
188
|
@function_validations[func[:name]] = generate_function_validation(func)
|
|
187
189
|
end
|
|
188
190
|
|
|
189
|
-
lines.each_with_index do |line,
|
|
191
|
+
lines.each_with_index do |line, _idx|
|
|
190
192
|
# Check for function definition
|
|
191
193
|
if line.match?(/^\s*def\s+(\w+)/)
|
|
192
194
|
match = line.match(/^(\s*)def\s+(\w+)/)
|
|
@@ -201,7 +203,7 @@ module TRuby
|
|
|
201
203
|
param_validations = validations.select { |v| v.is_a?(String) }
|
|
202
204
|
|
|
203
205
|
param_validations.each do |validation|
|
|
204
|
-
output_lines << "#{
|
|
206
|
+
output_lines << "#{" " * (function_indent + 2)}#{validation}"
|
|
205
207
|
end
|
|
206
208
|
end
|
|
207
209
|
|
|
@@ -233,34 +235,34 @@ module TRuby
|
|
|
233
235
|
RUBY
|
|
234
236
|
|
|
235
237
|
module_code += <<~RUBY
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
end
|
|
238
|
+
case expected_type
|
|
239
|
+
when "String"
|
|
240
|
+
raise TypeError, "\#{param_name} must be String, got \#{value.class}" unless value.is_a?(String)
|
|
241
|
+
when "Integer"
|
|
242
|
+
raise TypeError, "\#{param_name} must be Integer, got \#{value.class}" unless value.is_a?(Integer)
|
|
243
|
+
when "Float"
|
|
244
|
+
raise TypeError, "\#{param_name} must be Float, got \#{value.class}" unless value.is_a?(Float)
|
|
245
|
+
when "Boolean"
|
|
246
|
+
raise TypeError, "\#{param_name} must be Boolean, got \#{value.class}" unless value == true || value == false
|
|
247
|
+
when "Symbol"
|
|
248
|
+
raise TypeError, "\#{param_name} must be Symbol, got \#{value.class}" unless value.is_a?(Symbol)
|
|
249
|
+
when "Array"
|
|
250
|
+
raise TypeError, "\#{param_name} must be Array, got \#{value.class}" unless value.is_a?(Array)
|
|
251
|
+
when "Hash"
|
|
252
|
+
raise TypeError, "\#{param_name} must be Hash, got \#{value.class}" unless value.is_a?(Hash)
|
|
253
|
+
when "nil"
|
|
254
|
+
raise TypeError, "\#{param_name} must be nil, got \#{value.class}" unless value.nil?
|
|
255
|
+
else
|
|
256
|
+
# Custom type check
|
|
257
|
+
begin
|
|
258
|
+
type_class = Object.const_get(expected_type)
|
|
259
|
+
raise TypeError, "\#{param_name} must be \#{expected_type}, got \#{value.class}" unless value.is_a?(type_class)
|
|
260
|
+
rescue NameError
|
|
261
|
+
# Unknown type, skip validation
|
|
261
262
|
end
|
|
262
|
-
true
|
|
263
263
|
end
|
|
264
|
+
true
|
|
265
|
+
end
|
|
264
266
|
RUBY
|
|
265
267
|
|
|
266
268
|
# Generate validation methods for each function
|
|
@@ -274,6 +276,7 @@ module TRuby
|
|
|
274
276
|
|
|
275
277
|
func[:params].each do |param|
|
|
276
278
|
next unless param[:type]
|
|
279
|
+
|
|
277
280
|
module_code += " validate_type(#{param[:name]}, #{param[:type].inspect}, #{param[:name].inspect})\n"
|
|
278
281
|
end
|
|
279
282
|
|
|
@@ -288,6 +291,7 @@ module TRuby
|
|
|
288
291
|
def should_validate?(visibility)
|
|
289
292
|
return true if @config.validate_all
|
|
290
293
|
return visibility == :public if @config.validate_public_only
|
|
294
|
+
|
|
291
295
|
false
|
|
292
296
|
end
|
|
293
297
|
end
|