steep 0.40.0 → 0.44.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.
Files changed (169) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/Gemfile +1 -0
  4. data/bin/output_rebaseline.rb +15 -30
  5. data/bin/output_test.rb +23 -57
  6. data/lib/steep.rb +89 -15
  7. data/lib/steep/annotation_parser.rb +10 -2
  8. data/lib/steep/ast/types/class.rb +4 -0
  9. data/lib/steep/cli.rb +31 -6
  10. data/lib/steep/diagnostic/ruby.rb +13 -8
  11. data/lib/steep/diagnostic/signature.rb +152 -2
  12. data/lib/steep/drivers/annotations.rb +18 -36
  13. data/lib/steep/drivers/check.rb +140 -31
  14. data/lib/steep/drivers/diagnostic_printer.rb +20 -11
  15. data/lib/steep/drivers/langserver.rb +4 -8
  16. data/lib/steep/drivers/print_project.rb +10 -9
  17. data/lib/steep/drivers/stats.rb +135 -119
  18. data/lib/steep/drivers/utils/driver_helper.rb +35 -0
  19. data/lib/steep/drivers/utils/jobs_count.rb +9 -0
  20. data/lib/steep/drivers/validate.rb +29 -18
  21. data/lib/steep/drivers/watch.rb +55 -49
  22. data/lib/steep/drivers/worker.rb +11 -8
  23. data/lib/steep/expectations.rb +159 -0
  24. data/lib/steep/index/signature_symbol_provider.rb +23 -1
  25. data/lib/steep/index/source_index.rb +55 -5
  26. data/lib/steep/interface/block.rb +4 -0
  27. data/lib/steep/project.rb +0 -30
  28. data/lib/steep/project/dsl.rb +5 -3
  29. data/lib/steep/project/pattern.rb +56 -0
  30. data/lib/steep/project/target.rb +11 -227
  31. data/lib/steep/server/base_worker.rb +1 -3
  32. data/lib/steep/server/change_buffer.rb +63 -0
  33. data/lib/steep/server/interaction_worker.rb +72 -57
  34. data/lib/steep/server/master.rb +652 -234
  35. data/lib/steep/server/type_check_worker.rb +304 -0
  36. data/lib/steep/server/worker_process.rb +16 -11
  37. data/lib/steep/{project → services}/completion_provider.rb +5 -5
  38. data/lib/steep/services/content_change.rb +61 -0
  39. data/lib/steep/services/file_loader.rb +48 -0
  40. data/lib/steep/services/goto_service.rb +321 -0
  41. data/lib/steep/{project → services}/hover_content.rb +19 -20
  42. data/lib/steep/services/path_assignment.rb +27 -0
  43. data/lib/steep/services/signature_service.rb +403 -0
  44. data/lib/steep/services/stats_calculator.rb +69 -0
  45. data/lib/steep/services/type_check_service.rb +413 -0
  46. data/lib/steep/signature/validator.rb +187 -85
  47. data/lib/steep/source.rb +21 -18
  48. data/lib/steep/subtyping/check.rb +246 -45
  49. data/lib/steep/subtyping/constraints.rb +4 -4
  50. data/lib/steep/type_construction.rb +428 -193
  51. data/lib/steep/type_inference/block_params.rb +1 -1
  52. data/lib/steep/type_inference/context.rb +22 -0
  53. data/lib/steep/type_inference/local_variable_type_env.rb +26 -12
  54. data/lib/steep/type_inference/logic.rb +1 -1
  55. data/lib/steep/type_inference/logic_type_interpreter.rb +4 -4
  56. data/lib/steep/type_inference/type_env.rb +43 -17
  57. data/lib/steep/version.rb +1 -1
  58. data/smoke/alias/test_expectations.yml +96 -0
  59. data/smoke/and/test_expectations.yml +31 -0
  60. data/smoke/array/test_expectations.yml +103 -0
  61. data/smoke/block/test_expectations.yml +125 -0
  62. data/smoke/case/test_expectations.yml +47 -0
  63. data/smoke/class/test_expectations.yml +120 -0
  64. data/smoke/const/test_expectations.yml +129 -0
  65. data/smoke/diagnostics-rbs-duplicated/test_expectations.yml +13 -0
  66. data/smoke/diagnostics-rbs/Steepfile +7 -4
  67. data/smoke/diagnostics-rbs/test_expectations.yml +231 -0
  68. data/smoke/diagnostics-rbs/unknown-type-name-2.rbs +5 -0
  69. data/smoke/{broken → diagnostics-ruby-unsat}/Steepfile +0 -0
  70. data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
  71. data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
  72. data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
  73. data/smoke/diagnostics/a.rbs +0 -4
  74. data/smoke/diagnostics/test_expectations.yml +451 -0
  75. data/smoke/dstr/test_expectations.yml +13 -0
  76. data/smoke/ensure/test_expectations.yml +62 -0
  77. data/smoke/enumerator/test_expectations.yml +135 -0
  78. data/smoke/extension/f.rb +2 -0
  79. data/smoke/extension/f.rbs +3 -0
  80. data/smoke/extension/test_expectations.yml +73 -0
  81. data/smoke/hash/test_expectations.yml +81 -0
  82. data/smoke/hello/test_expectations.yml +25 -0
  83. data/smoke/if/test_expectations.yml +34 -0
  84. data/smoke/implements/b.rb +13 -0
  85. data/smoke/implements/b.rbs +12 -0
  86. data/smoke/implements/test_expectations.yml +23 -0
  87. data/smoke/initialize/test_expectations.yml +1 -0
  88. data/smoke/integer/test_expectations.yml +101 -0
  89. data/smoke/interface/test_expectations.yml +23 -0
  90. data/smoke/kwbegin/test_expectations.yml +17 -0
  91. data/smoke/lambda/test_expectations.yml +39 -0
  92. data/smoke/literal/test_expectations.yml +106 -0
  93. data/smoke/map/test_expectations.yml +1 -0
  94. data/smoke/method/test_expectations.yml +90 -0
  95. data/smoke/module/test_expectations.yml +75 -0
  96. data/smoke/regexp/test_expectations.yml +615 -0
  97. data/smoke/regression/issue_328.rb +1 -0
  98. data/smoke/regression/issue_328.rbs +0 -0
  99. data/smoke/regression/issue_332.rb +11 -0
  100. data/smoke/regression/issue_332.rbs +19 -0
  101. data/smoke/regression/issue_372.rb +8 -0
  102. data/smoke/regression/issue_372.rbs +4 -0
  103. data/smoke/regression/masgn.rb +4 -0
  104. data/smoke/regression/test_expectations.yml +60 -0
  105. data/smoke/regression/thread.rb +7 -0
  106. data/smoke/rescue/test_expectations.yml +79 -0
  107. data/smoke/self/test_expectations.yml +23 -0
  108. data/smoke/skip/test_expectations.yml +23 -0
  109. data/smoke/stdout/test_expectations.yml +1 -0
  110. data/smoke/super/test_expectations.yml +69 -0
  111. data/smoke/toplevel/test_expectations.yml +15 -0
  112. data/smoke/tsort/Steepfile +2 -0
  113. data/smoke/tsort/test_expectations.yml +63 -0
  114. data/smoke/type_case/test_expectations.yml +48 -0
  115. data/smoke/unexpected/Steepfile +5 -0
  116. data/smoke/unexpected/test_expectations.yml +25 -0
  117. data/smoke/unexpected/unexpected.rb +1 -0
  118. data/smoke/unexpected/unexpected.rbs +3 -0
  119. data/smoke/yield/test_expectations.yml +68 -0
  120. data/steep.gemspec +4 -3
  121. metadata +127 -80
  122. data/lib/steep/project/file_loader.rb +0 -68
  123. data/lib/steep/project/signature_file.rb +0 -39
  124. data/lib/steep/project/source_file.rb +0 -129
  125. data/lib/steep/project/stats_calculator.rb +0 -80
  126. data/lib/steep/server/code_worker.rb +0 -150
  127. data/lib/steep/server/signature_worker.rb +0 -157
  128. data/lib/steep/server/utils.rb +0 -69
  129. data/smoke/alias/test.yaml +0 -73
  130. data/smoke/and/test.yaml +0 -24
  131. data/smoke/array/test.yaml +0 -80
  132. data/smoke/block/test.yaml +0 -96
  133. data/smoke/broken/broken.rb +0 -0
  134. data/smoke/broken/broken.rbs +0 -0
  135. data/smoke/broken/test.yaml +0 -6
  136. data/smoke/case/test.yaml +0 -36
  137. data/smoke/class/test.yaml +0 -89
  138. data/smoke/const/test.yaml +0 -96
  139. data/smoke/diagnostics-rbs-duplicated/test.yaml +0 -10
  140. data/smoke/diagnostics-rbs/test.yaml +0 -142
  141. data/smoke/diagnostics/test.yaml +0 -333
  142. data/smoke/dstr/test.yaml +0 -10
  143. data/smoke/ensure/test.yaml +0 -47
  144. data/smoke/enumerator/test.yaml +0 -100
  145. data/smoke/extension/test.yaml +0 -50
  146. data/smoke/hash/test.yaml +0 -62
  147. data/smoke/hello/test.yaml +0 -18
  148. data/smoke/if/test.yaml +0 -27
  149. data/smoke/implements/test.yaml +0 -16
  150. data/smoke/initialize/test.yaml +0 -4
  151. data/smoke/integer/test.yaml +0 -66
  152. data/smoke/interface/test.yaml +0 -16
  153. data/smoke/kwbegin/test.yaml +0 -14
  154. data/smoke/lambda/test.yaml +0 -28
  155. data/smoke/literal/test.yaml +0 -79
  156. data/smoke/map/test.yaml +0 -4
  157. data/smoke/method/test.yaml +0 -71
  158. data/smoke/module/test.yaml +0 -51
  159. data/smoke/regexp/test.yaml +0 -372
  160. data/smoke/regression/test.yaml +0 -38
  161. data/smoke/rescue/test.yaml +0 -60
  162. data/smoke/self/test.yaml +0 -16
  163. data/smoke/skip/test.yaml +0 -16
  164. data/smoke/stdout/test.yaml +0 -4
  165. data/smoke/super/test.yaml +0 -52
  166. data/smoke/toplevel/test.yaml +0 -12
  167. data/smoke/tsort/test.yaml +0 -32
  168. data/smoke/type_case/test.yaml +0 -33
  169. data/smoke/yield/test.yaml +0 -49
@@ -50,28 +50,33 @@ module Steep
50
50
  Rainbow("#{path}:#{start[:line]+1}:#{start[:character]}").magenta
51
51
  end
52
52
 
53
- def print(diagnostic)
53
+ def print(diagnostic, prefix: "", source: true)
54
54
  header, *rest = diagnostic[:message].split(/\n/)
55
55
 
56
- stdout.puts "#{location(diagnostic)}: [#{severity_message(diagnostic[:severity])}] #{Rainbow(header).underline}"
56
+ stdout.puts "#{prefix}#{location(diagnostic)}: [#{severity_message(diagnostic[:severity])}] #{Rainbow(header).underline}"
57
57
 
58
58
  unless rest.empty?
59
59
  rest.each do |message|
60
- stdout.puts "│ #{message}"
60
+ stdout.puts "#{prefix}│ #{message}"
61
61
  end
62
62
  end
63
63
 
64
64
  if diagnostic[:code]
65
- stdout.puts "│" unless rest.empty?
66
- stdout.puts "│ Diagnostic ID: #{diagnostic[:code]}"
65
+ stdout.puts "#{prefix}│" unless rest.empty?
66
+ stdout.puts "#{prefix}│ Diagnostic ID: #{diagnostic[:code]}"
67
67
  end
68
68
 
69
- stdout.puts "│"
69
+ stdout.puts "#{prefix}│"
70
70
 
71
- print_source_line(diagnostic)
71
+ if source
72
+ print_source_line(diagnostic, prefix: prefix)
73
+ else
74
+ stdout.puts "#{prefix}└ (no source code available)"
75
+ stdout.puts "#{prefix}"
76
+ end
72
77
  end
73
78
 
74
- def print_source_line(diagnostic)
79
+ def print_source_line(diagnostic, prefix: "")
75
80
  start_pos = diagnostic[:range][:start]
76
81
  end_pos = diagnostic[:range][:end]
77
82
 
@@ -80,14 +85,18 @@ module Steep
80
85
  leading = line[0...start_pos[:character]]
81
86
  if start_pos[:line] == end_pos[:line]
82
87
  subject = line[start_pos[:character]...end_pos[:character]]
83
- trailing = line[end_pos[:character]...].chomp
88
+ trailing = (line[end_pos[:character]...] || "").chomp
84
89
  else
85
90
  subject = line[start_pos[:character]...].chomp
86
91
  trailing = ""
87
92
  end
88
93
 
89
- stdout.puts "└ #{leading}#{color_severity(subject, severity: diagnostic[:severity])}#{trailing}"
90
- stdout.puts " #{" " * leading.size}#{"~" * subject.size}"
94
+ unless subject.valid_encoding?
95
+ subject.scrub!
96
+ end
97
+
98
+ stdout.puts "#{prefix}└ #{leading}#{color_severity(subject, severity: diagnostic[:severity])}#{trailing}"
99
+ stdout.puts "#{prefix} #{" " * leading.size}#{"~" * subject.size}"
91
100
  end
92
101
  end
93
102
  end
@@ -10,6 +10,7 @@ module Steep
10
10
  attr_reader :type_check_thread
11
11
 
12
12
  include Utils::DriverHelper
13
+ include Utils::JobsCount
13
14
 
14
15
  TypeCheckRequest = Struct.new(:version, keyword_init: true)
15
16
 
@@ -36,22 +37,17 @@ module Steep
36
37
  def run
37
38
  @project = load_config()
38
39
 
39
- loader = Project::FileLoader.new(project: project)
40
- loader.load_sources([])
41
- loader.load_signatures()
42
-
43
40
  interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: project.steepfile_path)
44
- signature_worker = Server::WorkerProcess.spawn_worker(:signature, name: "signature", steepfile: project.steepfile_path)
45
- code_workers = Server::WorkerProcess.spawn_code_workers(steepfile: project.steepfile_path)
41
+ typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: [], count: jobs_count)
46
42
 
47
43
  master = Server::Master.new(
48
44
  project: project,
49
45
  reader: reader,
50
46
  writer: writer,
51
47
  interaction_worker: interaction_worker,
52
- signature_worker: signature_worker,
53
- code_workers: code_workers
48
+ typecheck_workers: typecheck_workers
54
49
  )
50
+ master.typecheck_automatically = true
55
51
 
56
52
  master.start()
57
53
 
@@ -14,33 +14,34 @@ module Steep
14
14
  def run
15
15
  project = load_config()
16
16
 
17
- loader = Project::FileLoader.new(project: project)
18
- loader.load_sources([])
19
- loader.load_signatures()
17
+ loader = Services::FileLoader.new(base_dir: project.base_dir)
20
18
 
21
19
  project.targets.each do |target|
20
+ source_changes = loader.load_changes(target.source_pattern, changes: {})
21
+ signature_changes = loader.load_changes(target.signature_pattern, changes: {})
22
+
22
23
  stdout.puts "Target:"
23
24
  stdout.puts " #{target.name}:"
24
25
  stdout.puts " sources:"
25
26
  stdout.puts " patterns:"
26
- target.source_patterns.each do |pattern|
27
+ target.source_pattern.patterns.each do |pattern|
27
28
  stdout.puts " - #{pattern}"
28
29
  end
29
30
  stdout.puts " ignores:"
30
- target.ignore_patterns.each do |pattern|
31
+ target.source_pattern.ignores.each do |pattern|
31
32
  stdout.puts " - #{pattern}"
32
33
  end
33
34
  stdout.puts " files:"
34
- target.source_files.each_key do |path|
35
+ source_changes.each_key do |path|
35
36
  stdout.puts " - #{path}"
36
37
  end
37
38
  stdout.puts " signatures:"
38
39
  stdout.puts " patterns:"
39
- target.signature_patterns.each do |pattern|
40
+ target.signature_pattern.patterns.each do |pattern|
40
41
  stdout.puts " - #{pattern}"
41
42
  end
42
43
  stdout.puts " files:"
43
- target.signature_files.each_key do |path|
44
+ signature_changes.each_key do |path|
44
45
  stdout.puts " - #{path}"
45
46
  end
46
47
  stdout.puts " libraries:"
@@ -48,7 +49,7 @@ module Steep
48
49
  stdout.puts " - #{lib}"
49
50
  end
50
51
  stdout.puts " library dirs:"
51
- Project::Target.construct_env_loader(options: target.options).tap do |loader|
52
+ target.new_env_loader(project: project).tap do |loader|
52
53
  loader.each_dir do |lib, path|
53
54
  case lib
54
55
  when :core
@@ -3,11 +3,106 @@ require "csv"
3
3
  module Steep
4
4
  module Drivers
5
5
  class Stats
6
+ class CSVPrinter
7
+ attr_reader :io
8
+
9
+ def initialize(io:)
10
+ @io = io
11
+ end
12
+
13
+ def print(stats_result)
14
+ io.puts(
15
+ CSV.generate do |csv|
16
+ csv << ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"]
17
+ stats_result.each do |row|
18
+ if row[:type] == "success"
19
+ csv << [
20
+ row[:target],
21
+ row[:path],
22
+ row[:type],
23
+ row[:typed_calls],
24
+ row[:untyped_calls],
25
+ row[:total_calls],
26
+ if row[:total_calls].nonzero?
27
+ (row[:typed_calls].to_f / row[:total_calls] * 100).to_i
28
+ else
29
+ 100
30
+ end
31
+ ]
32
+ else
33
+ csv << [
34
+ row[:target],
35
+ row[:path],
36
+ row[:type],
37
+ 0,
38
+ 0,
39
+ 0,
40
+ 0
41
+ ]
42
+ end
43
+ end
44
+ end
45
+ )
46
+ end
47
+ end
48
+
49
+ class TablePrinter
50
+ attr_reader :io
51
+
52
+ def initialize(io:)
53
+ @io = io
54
+ end
55
+
56
+ def print(stats_result)
57
+ rows = []
58
+ stats_result.sort_by {|row| row[:path] }.each do |row|
59
+ if row[:type] == "success"
60
+ rows << [
61
+ row[:target],
62
+ row[:path] + " ",
63
+ row[:type],
64
+ row[:typed_calls],
65
+ row[:untyped_calls],
66
+ row[:total_calls],
67
+ if row[:total_calls].nonzero?
68
+ "#{(row[:typed_calls].to_f / row[:total_calls] * 100).to_i}%"
69
+ else
70
+ "100%"
71
+ end
72
+ ]
73
+ else
74
+ rows << [
75
+ row[:target],
76
+ row[:path],
77
+ row[:type],
78
+ 0,
79
+ 0,
80
+ 0,
81
+ "N/A"
82
+ ]
83
+ end
84
+ end
85
+
86
+ table = Terminal::Table.new(
87
+ headings: ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"],
88
+ rows: rows
89
+ )
90
+ table.align_column(3, :right)
91
+ table.align_column(4, :right)
92
+ table.align_column(5, :right)
93
+ table.align_column(6, :right)
94
+ table.style = { border_top: false, border_bottom: false, border_y: "", border_i: "" }
95
+ io.puts(table)
96
+ end
97
+ end
98
+
6
99
  attr_reader :stdout
7
100
  attr_reader :stderr
8
101
  attr_reader :command_line_patterns
102
+ attr_accessor :format
9
103
 
10
104
  include Utils::DriverHelper
105
+ include Utils::JobsCount
11
106
 
12
107
  def initialize(stdout:, stderr:)
13
108
  @stdout = stdout
@@ -18,10 +113,6 @@ module Steep
18
113
  def run
19
114
  project = load_config()
20
115
 
21
- loader = Project::FileLoader.new(project: project)
22
- loader.load_sources(command_line_patterns)
23
- loader.load_signatures()
24
-
25
116
  stderr.puts Rainbow("# Calculating stats:").bold
26
117
  stderr.puts
27
118
 
@@ -34,147 +125,72 @@ module Steep
34
125
  server_reader = LanguageServer::Protocol::Transport::Io::Reader.new(server_read)
35
126
  server_writer = LanguageServer::Protocol::Transport::Io::Writer.new(server_write)
36
127
 
37
- interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: project.steepfile_path, delay_shutdown: true)
38
- signature_worker = Server::WorkerProcess.spawn_worker(:signature, name: "signature", steepfile: project.steepfile_path, delay_shutdown: true)
39
- code_workers = Server::WorkerProcess.spawn_code_workers(steepfile: project.steepfile_path, delay_shutdown: true)
128
+ typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(
129
+ steepfile: project.steepfile_path,
130
+ delay_shutdown: true,
131
+ args: command_line_patterns,
132
+ count: jobs_count
133
+ )
40
134
 
41
135
  master = Server::Master.new(
42
136
  project: project,
43
137
  reader: server_reader,
44
138
  writer: server_writer,
45
- interaction_worker: interaction_worker,
46
- signature_worker: signature_worker,
47
- code_workers: code_workers
139
+ interaction_worker: nil,
140
+ typecheck_workers: typecheck_workers
48
141
  )
142
+ master.typecheck_automatically = false
143
+ master.commandline_args.push(*command_line_patterns)
49
144
 
50
145
  main_thread = Thread.start do
51
146
  master.start()
52
147
  end
53
148
  main_thread.abort_on_exception = true
54
149
 
55
- client_writer.write({ method: :initialize, id: 0 })
150
+ initialize_id = request_id()
151
+ client_writer.write({ method: :initialize, id: initialize_id })
152
+ wait_for_response_id(reader: client_reader, id: initialize_id)
153
+
154
+ typecheck_guid = SecureRandom.uuid
155
+ client_writer.write({ method: "$/typecheck", params: { guid: typecheck_guid }})
156
+ wait_for_message(reader: client_reader) do |message|
157
+ message[:method] == "$/progress" &&
158
+ message[:params][:token] == typecheck_guid &&
159
+ message[:params][:value][:kind] == "end"
160
+ end
56
161
 
57
- stats_id = -1
162
+ stats_id = request_id()
58
163
  client_writer.write(
59
164
  {
60
165
  id: stats_id,
61
166
  method: "workspace/executeCommand",
62
- params: {
63
- command: "steep/stats",
64
- arguments: project.all_source_files.map {|path| project.absolute_path(path) }
65
- }
167
+ params: { command: "steep/stats", arguments: [] }
66
168
  })
67
169
 
68
- stats_result = []
69
- client_reader.read do |response|
70
- if response[:id] == stats_id
71
- stats_result.push(*response[:result])
72
- break
73
- end
74
- end
75
-
76
- shutdown_id = -2
77
- client_writer.write({ method: :shutdown, id: shutdown_id })
78
-
79
- client_reader.read do |response|
80
- if response[:id] == shutdown_id
81
- break
82
- end
83
- end
170
+ stats_response = wait_for_response_id(reader: client_reader, id: stats_id)
171
+ stats_result = stats_response[:result]
84
172
 
85
- client_writer.write({ method: "exit" })
173
+ shutdown_exit(reader: client_reader, writer: client_writer)
86
174
  main_thread.join()
87
175
 
88
- stdout.puts(
89
- CSV.generate do |csv|
90
- csv << ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"]
91
- stats_result.each do |row|
92
- if row[:type] == "success"
93
- csv << [
94
- row[:target],
95
- row[:path],
96
- row[:type],
97
- row[:typed_calls],
98
- row[:untyped_calls],
99
- row[:total_calls],
100
- if row[:total_calls].nonzero?
101
- (row[:typed_calls].to_f / row[:total_calls] * 100).to_i
176
+ printer = case format
177
+ when "csv"
178
+ CSVPrinter.new(io: stdout)
179
+ when "table"
180
+ TablePrinter.new(io: stdout)
181
+ when nil
182
+ if stdout.tty?
183
+ TablePrinter.new(io: stdout)
184
+ else
185
+ CSVPrinter.new(io: stdout)
186
+ end
102
187
  else
103
- 100
188
+ raise ArgumentError.new("Invalid format: #{format}")
104
189
  end
105
- ]
106
- else
107
- csv << [
108
- row[:target],
109
- row[:path],
110
- row[:type],
111
- 0,
112
- 0,
113
- 0,
114
- 0
115
- ]
116
- end
117
- end
118
- end
119
- )
120
- #
121
- # type_check(project)
122
- #
123
- # stdout.puts(
124
- # CSV.generate do |csv|
125
- # csv << ["Target", "File", "Status", "Typed calls", "Untyped calls", "All calls", "Typed %"]
126
- #
127
- # project.targets.each do |target|
128
- # case (status = target.status)
129
- # when Project::Target::TypeCheckStatus
130
- # status.type_check_sources.each do |source_file|
131
- # case source_file.status
132
- # when Project::SourceFile::TypeCheckStatus
133
- # typing = source_file.status.typing
134
- #
135
- # typed = 0
136
- # untyped = 0
137
- # total = 0
138
- # typing.method_calls.each_value do |call|
139
- # case call
140
- # when TypeInference::MethodCall::Typed
141
- # typed += 1
142
- # when TypeInference::MethodCall::Untyped
143
- # untyped += 1
144
- # end
145
- #
146
- # total += 1
147
- # end
148
- #
149
- # csv << format_stats(target, source_file.path, "success", typed, untyped, total)
150
- # when Project::SourceFile::TypeCheckErrorStatus
151
- # csv << format_stats(target, source_file.path, "error", 0, 0, 0)
152
- # else
153
- # csv << format_stats(target, source_file.path, "unknown (#{source_file.status.class.to_s.split(/::/).last})", 0, 0, 0)
154
- # end
155
- # end
156
- # end
157
- # end
158
- # end
159
- # )
160
190
 
161
- 0
162
- end
191
+ printer.print(stats_result)
163
192
 
164
- def format_stats(target, path, status, typed, untyped, total)
165
- [
166
- target.name,
167
- path.to_s,
168
- status,
169
- typed,
170
- untyped,
171
- total,
172
- if total.nonzero?
173
- format("%.2f", (typed.to_f/total)*100)
174
- else
175
- 0
176
- end
177
- ]
193
+ 0
178
194
  end
179
195
  end
180
196
  end