typeprof 0.10.0 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -27,7 +27,7 @@ module TypeProf
27
27
  self
28
28
  end
29
29
 
30
- def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, &ctn)
30
+ def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, replace_cref:, &ctn)
31
31
  blk_env = scratch.return_envs[@outer_ep]
32
32
  if replace_recv_ty
33
33
  replace_recv_ty = scratch.globalize_type(replace_recv_ty, caller_env, caller_ep)
@@ -46,7 +46,8 @@ module TypeProf
46
46
  return
47
47
  end
48
48
 
49
- nctx = Context.new(@iseq, @outer_ep.ctx.cref, nil)
49
+ cref = replace_cref || @outer_ep.ctx.cref
50
+ nctx = Context.new(@iseq, cref, nil)
50
51
  callee_ep = ExecutionPoint.new(nctx, 0, @outer_ep)
51
52
  nenv = Env.new(blk_env.static_env, locals, [], nil)
52
53
  alloc_site = AllocationSite.new(callee_ep)
@@ -87,7 +88,7 @@ module TypeProf
87
88
  TypedBlock.new(msig, ret_ty)
88
89
  end
89
90
 
90
- def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, &ctn)
91
+ def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, replace_cref:, &ctn)
91
92
  aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
92
93
  subst = aargs.consistent_with_method_signature?(@msig)
93
94
  unless subst
@@ -119,7 +120,7 @@ module TypeProf
119
120
  self
120
121
  end
121
122
 
122
- def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, &ctn)
123
+ def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, replace_cref:, &ctn)
123
124
  if aargs.lead_tys.size >= 1
124
125
  recv = aargs.lead_tys[0]
125
126
  recv = Type.any if recv == Type.bot
@@ -157,7 +158,7 @@ module TypeProf
157
158
  self
158
159
  end
159
160
 
160
- def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, &ctn)
161
+ def do_call(aargs, caller_ep, caller_env, scratch, replace_recv_ty:, replace_cref:, &ctn)
161
162
  aargs = scratch.globalize_type(aargs, caller_env, caller_ep)
162
163
 
163
164
  dummy_ctx = TypedContext.new(@caller_ep, @mid)
@@ -165,7 +166,7 @@ module TypeProf
165
166
  scratch.add_block_signature!(self, aargs.to_block_signature)
166
167
  scratch.add_block_to_ctx!(self, dummy_ctx)
167
168
 
168
- @blk.call(aargs, caller_ep, caller_env, scratch, replace_recv_ty: replace_recv_ty) do |ret_ty, ep, env|
169
+ @blk.call(aargs, caller_ep, caller_env, scratch, replace_recv_ty: replace_recv_ty, replace_cref: replace_cref) do |ret_ty, ep, env|
169
170
  scratch.add_return_value!(dummy_ctx, ret_ty)
170
171
  ctn[ret_ty, ep, env]
171
172
  end
@@ -158,7 +158,43 @@ module TypeProf
158
158
  naargs = ActualArguments.new([recv], nil, {}, Type.nil)
159
159
  nrecv = recv
160
160
  nrecv = nrecv.base_type if nrecv.is_a?(Type::ContainerType)
161
- scratch.do_invoke_block(aargs.blk_ty, naargs, ep, env, replace_recv_ty: nrecv) do |_ret_ty, ep|
161
+ scratch.do_invoke_block(aargs.blk_ty, naargs, ep, env, replace_recv_ty: nrecv) do |ret_ty, ep|
162
+ ctn[ret_ty, ep, env]
163
+ end
164
+ end
165
+
166
+ def module_eqq(recv, mid, aargs, ep, env, scratch, &ctn)
167
+ if aargs.lead_tys.size == 1
168
+ aargs.lead_tys[0].each_child do |aarg|
169
+ aarg = aarg.base_type if aarg.is_a?(Type::Symbol) # XXX
170
+ if aarg.is_a?(Type::Instance)
171
+ if aarg.klass == recv # XXX: inheritance
172
+ true_val = Type::Instance.new(Type::Builtin[:true])
173
+ ctn[true_val, ep, env]
174
+ else
175
+ false_val = Type::Instance.new(Type::Builtin[:false])
176
+ ctn[false_val, ep, env]
177
+ end
178
+ else
179
+ ctn[Type.bool, ep, env]
180
+ end
181
+ end
182
+ else
183
+ ctn[Type.bool, ep, env]
184
+ end
185
+ end
186
+
187
+ def object_module_eval(recv, mid, aargs, ep, env, scratch, &ctn)
188
+ if aargs.lead_tys.size >= 1
189
+ scratch.warn(ep, "class_eval with arguments is ignored")
190
+ ctn[Type.any, ep, env]
191
+ return
192
+ end
193
+ naargs = ActualArguments.new([recv], nil, {}, Type.nil)
194
+ nrecv = recv
195
+ nrecv = nrecv.base_type if nrecv.is_a?(Type::ContainerType)
196
+ ncref = ep.ctx.cref.extend(nrecv, true)
197
+ scratch.do_invoke_block(aargs.blk_ty, naargs, ep, env, replace_recv_ty: nrecv, replace_cref: ncref) do |_ret_ty, ep|
162
198
  ctn[recv, ep, env]
163
199
  end
164
200
  end
@@ -176,7 +212,7 @@ module TypeProf
176
212
  end
177
213
 
178
214
  elem_ty = Type.bot
179
- enum_for_blk = CustomBlock.new(ep, mid) do |aargs, caller_ep, caller_env, scratch, replace_recv_ty:, &blk_ctn|
215
+ enum_for_blk = CustomBlock.new(ep, mid) do |aargs, caller_ep, caller_env, scratch, replace_recv_ty:, replace_cref:, &blk_ctn|
180
216
  if aargs.lead_tys.size >= 1
181
217
  elem_ty = elem_ty.union(aargs.lead_tys[0])
182
218
  else
@@ -235,9 +271,12 @@ module TypeProf
235
271
  return ctn[Type.any, ep, env]
236
272
  end
237
273
 
274
+ # support multiple arguments: include M1, M2
238
275
  arg = aargs.lead_tys[0]
239
276
  arg.each_child do |arg|
240
277
  if arg.is_a?(Type::Class)
278
+ aargs = ActualArguments.new([recv], nil, {}, Type.nil)
279
+ scratch.do_send(arg, :included, aargs, ep, env) {|_ret_ty, _ep| }
241
280
  scratch.mix_module(:after, recv, arg, nil, ep.ctx.cref.singleton, ep)
242
281
  end
243
282
  end
@@ -259,6 +298,8 @@ module TypeProf
259
298
  arg = aargs.lead_tys[0]
260
299
  arg.each_child do |arg|
261
300
  if arg.is_a?(Type::Class)
301
+ aargs = ActualArguments.new([recv], nil, {}, Type.nil)
302
+ scratch.do_send(arg, :extended, aargs, ep, env) {|_ret_ty, _ep| }
262
303
  # if ep.ctx.cref.singleton is true, the meta-meta level is ignored. Should we warn?
263
304
  scratch.mix_module(:after, recv, arg, nil, true, ep)
264
305
  end
@@ -557,8 +598,6 @@ module TypeProf
557
598
  end
558
599
 
559
600
  def struct_s_new(recv, mid, aargs, ep, env, scratch, &ctn)
560
- # TODO: keyword_init
561
-
562
601
  keyword_init = false
563
602
  if aargs.kw_tys && aargs.kw_tys[:keyword_init] # XXX: more canonical way to extract keyword...
564
603
  if aargs.kw_tys[:keyword_init] == Type::Instance.new(Type::Builtin[:true])
@@ -806,9 +845,12 @@ module TypeProf
806
845
  scratch.set_custom_method(klass_module, :public, Builtin.method(:module_public), false)
807
846
  scratch.set_custom_method(klass_module, :private, Builtin.method(:module_private), false)
808
847
  scratch.set_custom_method(klass_module, :define_method, Builtin.method(:module_define_method))
809
- scratch.set_custom_method(klass_module, :"attr_accessor", Builtin.method(:module_attr_accessor))
810
- scratch.set_custom_method(klass_module, :"attr_reader", Builtin.method(:module_attr_reader))
811
- scratch.set_custom_method(klass_module, :"attr_writer", Builtin.method(:module_attr_writer))
848
+ scratch.set_custom_method(klass_module, :attr_accessor, Builtin.method(:module_attr_accessor))
849
+ scratch.set_custom_method(klass_module, :attr_reader, Builtin.method(:module_attr_reader))
850
+ scratch.set_custom_method(klass_module, :attr_writer, Builtin.method(:module_attr_writer))
851
+ scratch.set_custom_method(klass_module, :class_eval, Builtin.method(:object_module_eval))
852
+ scratch.set_custom_method(klass_module, :module_eval, Builtin.method(:object_module_eval))
853
+ scratch.set_custom_method(klass_module, :===, Builtin.method(:module_eqq))
812
854
 
813
855
  scratch.set_custom_method(klass_proc, :[], Builtin.method(:proc_call))
814
856
  scratch.set_custom_method(klass_proc, :call, Builtin.method(:proc_call))
data/lib/typeprof/cli.rb CHANGED
@@ -20,6 +20,7 @@ module TypeProf
20
20
  options = {}
21
21
  dir_filter = nil
22
22
  gem_rbs_features = []
23
+ gem_repo_dirs = []
23
24
  show_version = false
24
25
  max_sec = max_iter = nil
25
26
 
@@ -31,6 +32,7 @@ module TypeProf
31
32
  opt.on("--version", "Display typeprof version") { show_version = true }
32
33
  opt.on("-I DIR", "Add DIR to the load/require path") {|v| $LOAD_PATH << v }
33
34
  opt.on("-r FEATURE", "Require RBS of the FEATURE gem") {|v| gem_rbs_features << v }
35
+ opt.on("--repo DIR", "Add DIR to the RBS repository") {|v| gem_repo_dirs << v }
34
36
 
35
37
  opt.separator ""
36
38
  opt.separator "Analysis output options:"
@@ -46,6 +48,8 @@ module TypeProf
46
48
  dir_filter ||= ConfigData::DEFAULT_DIR_FILTER
47
49
  dir_filter << [:exclude, File.expand_path(dir)]
48
50
  end
51
+ opt.on("--exclude-untyped", "Exclude (comment out) all entries including untyped") {|v| options[:exclude_untyped] = v }
52
+ opt.on("--[no-]show-typeprof-version", "Display TypeProf version in a header") {|v| options[:show_typeprof_version] = v }
49
53
  opt.on("--[no-]show-errors", "Display possible errors found during the analysis") {|v| options[:show_errors] = v }
50
54
  opt.on("--[no-]show-untyped", "Display \"Foo | untyped\" instead of \"Foo\"") {|v| options[:show_untyped] = v }
51
55
  opt.on("--[no-]show-parameter-names", "Display parameter names for methods") {|v| options[:show_parameter_names] = v }
@@ -87,6 +91,7 @@ module TypeProf
87
91
  rbs_files: rbs_files,
88
92
  output: output,
89
93
  gem_rbs_features: gem_rbs_features,
94
+ gem_repo_dirs: gem_repo_dirs,
90
95
  verbose: verbose,
91
96
  dir_filter: dir_filter,
92
97
  max_sec: max_sec,
@@ -6,6 +6,7 @@ module TypeProf
6
6
  :rbs_files,
7
7
  :output,
8
8
  :gem_rbs_features,
9
+ :gem_repo_dirs,
9
10
  :verbose,
10
11
  :dir_filter,
11
12
  :max_iter,
@@ -25,10 +26,13 @@ module TypeProf
25
26
  def initialize(**opt)
26
27
  opt[:output] ||= $stdout
27
28
  opt[:gem_rbs_features] ||= []
29
+ opt[:gem_repo_dirs] ||= []
28
30
  opt[:dir_filter] ||= DEFAULT_DIR_FILTER
29
31
  opt[:verbose] ||= 0
30
32
  opt[:options] ||= {}
31
33
  opt[:options] = {
34
+ exclude_untyped: false,
35
+ show_typeprof_version: true,
32
36
  show_indicator: true,
33
37
  show_untyped: false,
34
38
  show_errors: false,
@@ -76,9 +80,19 @@ module TypeProf
76
80
  Import.import_library(scratch, feature)
77
81
  end
78
82
 
79
- prologue_ctx = Context.new(nil, nil, nil)
80
- prologue_ep = ExecutionPoint.new(prologue_ctx, -1, nil)
81
- prologue_env = Env.new(StaticEnv.new(Type.bot, Type.nil, false, true), [], [], Utils::HashWrapper.new({}))
83
+ rbs_files = []
84
+ rbs_codes = []
85
+ Config.rbs_files.each do |rbs|
86
+ if rbs.is_a?(Array) # [String name, String content]
87
+ rbs_codes << rbs
88
+ else
89
+ rbs_files << rbs
90
+ end
91
+ end
92
+ Import.import_rbs_files(scratch, rbs_files)
93
+ rbs_codes.each do |name, content|
94
+ Import.import_rbs_code(scratch, name, content)
95
+ end
82
96
 
83
97
  Config.rb_files.each do |rb|
84
98
  if rb.is_a?(Array) # [String name, String content]
@@ -86,17 +100,7 @@ module TypeProf
86
100
  else
87
101
  iseq = ISeq.compile(rb)
88
102
  end
89
- ep, env = TypeProf.starting_state(iseq)
90
- scratch.merge_env(ep, env)
91
- scratch.add_callsite!(ep.ctx, prologue_ep, prologue_env) {|ty, ep| }
92
- end
93
-
94
- Config.rbs_files.each do |rbs|
95
- if rbs.is_a?(Array) # [String name, String content]
96
- Import.import_rbs_code(scratch, *rbs)
97
- else
98
- Import.import_rbs_file(scratch, rbs)
99
- end
103
+ scratch.add_entrypoint(iseq)
100
104
  end
101
105
 
102
106
  result = scratch.type_profile
@@ -45,6 +45,12 @@ module TypeProf
45
45
  Type::Cell.new(Type::Cell::Elements.new([Type.bot] * klass.type_params.size), base_type)
46
46
  end
47
47
  end
48
+
49
+ def include_untyped?(scratch)
50
+ return true if @base_type.include_untyped?(scratch)
51
+ return true if @elems.include_untyped?(scratch)
52
+ false
53
+ end
48
54
  end
49
55
 
50
56
  # The most basic container type for default type parameter class
@@ -196,6 +202,10 @@ module TypeProf
196
202
  end
197
203
  Elements.new(elems)
198
204
  end
205
+
206
+ def include_untyped?(scratch)
207
+ return @elems.any? {|ty| ty.include_untyped?(scratch) }
208
+ end
199
209
  end
200
210
  end
201
211
 
@@ -531,6 +541,12 @@ module TypeProf
531
541
  return rest_ary_ty, following_tys
532
542
  end
533
543
  end
544
+
545
+ def include_untyped?(scratch)
546
+ return true if @lead_tys.any? {|ty| ty.include_untyped?(scratch) }
547
+ return true if @rest_ty.include_untyped?(scratch)
548
+ false
549
+ end
534
550
  end
535
551
  end
536
552
 
@@ -790,6 +806,14 @@ module TypeProf
790
806
  end
791
807
  kw_tys
792
808
  end
809
+
810
+ def include_untyped?(scratch)
811
+ @map_tys.each do |key, val|
812
+ return true if key.include_untyped?(scratch)
813
+ return true if val.include_untyped?(scratch)
814
+ end
815
+ false
816
+ end
793
817
  end
794
818
  end
795
819
 
@@ -26,6 +26,10 @@ module TypeProf
26
26
  end
27
27
 
28
28
  def show_message(terminated, output)
29
+ if Config.options[:show_typeprof_version]
30
+ output.puts "# TypeProf #{ VERSION }"
31
+ output.puts
32
+ end
29
33
  if terminated
30
34
  output.puts "# CAUTION: Type profiling was terminated prematurely because of the limitation"
31
35
  output.puts
@@ -94,6 +98,10 @@ module TypeProf
94
98
  if class_def.klass_obj.superclass != :__root__ && class_def.klass_obj.superclass
95
99
  omit = class_def.klass_obj.superclass == Type::Builtin[:obj] || class_def.klass_obj == Type::Builtin[:obj]
96
100
  superclass = omit ? nil : @scratch.get_class_name(class_def.klass_obj.superclass)
101
+ type_args = class_def.klass_obj.superclass_type_args
102
+ if type_args && !type_args.empty?
103
+ superclass += "[#{ type_args.map {|ty| ty.screen_name(@scratch) }.join(", ") }]"
104
+ end
97
105
  end
98
106
 
99
107
  @scratch.namespace = class_def.name
@@ -129,18 +137,17 @@ module TypeProf
129
137
  ctxs = @iseq_method_to_ctxs[mdef]
130
138
  next unless ctxs
131
139
 
132
- ctxs.each do |ctx|
133
- next if mid != ctx.mid
134
- next if Config.check_dir_filter(ctx.iseq.absolute_path) == :exclude
140
+ ctx = ctxs.find {|ctx| ctx.mid == mid } || ctxs.first
135
141
 
136
- method_name = ctx.mid
137
- method_name = "self.#{ method_name }" if singleton
142
+ next if Config.check_dir_filter(ctx.iseq.absolute_path) == :exclude
138
143
 
139
- key = [:iseq, method_name]
140
- visibilities[key] ||= mdef.pub_meth
141
- source_locations[key] ||= ctx.iseq.source_location(0)
142
- (methods[key] ||= []) << @scratch.show_method_signature(ctx)
143
- end
144
+ method_name = mid
145
+ method_name = "self.#{ method_name }" if singleton
146
+
147
+ key = [:iseq, method_name]
148
+ visibilities[key] ||= mdef.pub_meth
149
+ source_locations[key] ||= ctx.iseq.source_location(0)
150
+ (methods[key] ||= []) << @scratch.show_method_signature(ctx)
144
151
  when AliasMethodDef
145
152
  alias_name, orig_name = mid, mdef.orig_mid
146
153
  if singleton
@@ -169,7 +176,7 @@ module TypeProf
169
176
  else
170
177
  entry = ivars[[singleton, mdef.ivar]]
171
178
  ty = entry ? entry.type : Type.any
172
- methods[key] = [mdef.kind, ty.screen_name(@scratch)]
179
+ methods[key] = [mdef.kind, ty.screen_name(@scratch), ty.include_untyped?(@scratch)]
173
180
  end
174
181
  when TypedMethodDef
175
182
  if mdef.rbs_source
@@ -336,14 +343,22 @@ module TypeProf
336
343
  type, (method_name, hidden) = key
337
344
  case type
338
345
  when :attr
339
- kind, ty = *arg
340
- lines << (indent + " attr_#{ kind } #{ method_name }#{ hidden ? "()" : "" }: #{ ty }")
346
+ kind, ty, untyped = *arg
347
+ exclude = Config.options[:exclude_untyped] && untyped ? "#" : " " # XXX
348
+ lines << (indent + "#{ exclude } attr_#{ kind } #{ method_name }#{ hidden ? "()" : "" }: #{ ty }")
341
349
  when :rbs
342
350
  sigs = arg.sort.join("\n" + indent + "#" + " " * (method_name.size + 5) + "| ")
343
351
  lines << (indent + "# def #{ method_name }: #{ sigs }")
344
352
  when :iseq
345
- sigs = arg.sort.join("\n" + indent + " " * (method_name.size + 6) + "| ")
346
- lines << (indent + " def #{ method_name }: #{ sigs }")
353
+ sigs = []
354
+ untyped = false
355
+ arg.each do |sig, untyped0|
356
+ sigs << sig
357
+ untyped ||= untyped0
358
+ end
359
+ sigs = sigs.sort.join("\n" + indent + " " * (method_name.size + 6) + "| ")
360
+ exclude = Config.options[:exclude_untyped] && untyped ? "#" : " " # XXX
361
+ lines << (indent + "#{ exclude } def #{ method_name }: #{ sigs }")
347
362
  when :alias
348
363
  orig_name = arg
349
364
  lines << (indent + " alias #{ method_name } #{ orig_name }")
@@ -3,6 +3,10 @@ require "rbs"
3
3
  module TypeProf
4
4
  class RBSReader
5
5
  def initialize
6
+ @repo = RBS::Repository.new
7
+ Config.gem_repo_dirs.each do |dir|
8
+ @repo.add(Pathname(dir))
9
+ end
6
10
  @env, @builtin_env_json = RBSReader.get_builtin_env
7
11
  end
8
12
 
@@ -11,7 +15,7 @@ module TypeProf
11
15
  unless @builtin_env
12
16
  @builtin_env = RBS::Environment.new
13
17
 
14
- loader = RBS::EnvironmentLoader.new
18
+ loader = RBS::EnvironmentLoader.new(repository: @repo)
15
19
  new_decls = loader.load(env: @builtin_env).map {|decl,| decl }
16
20
  @builtin_env_json = load_rbs(@builtin_env, new_decls)
17
21
  end
@@ -24,22 +28,30 @@ module TypeProf
24
28
  end
25
29
 
26
30
  def load_library(lib)
27
- loader = RBS::EnvironmentLoader.new(core_root: nil)
31
+ loader = RBS::EnvironmentLoader.new(core_root: nil, repository: @repo)
28
32
  loader.add(library: lib)
29
33
 
30
34
  case lib
35
+ when 'bigdecimal-math'
36
+ loader.add(library: 'bigdecimal')
31
37
  when "yaml"
32
38
  loader.add(library: "pstore")
33
39
  loader.add(library: "dbm")
40
+ when "logger"
41
+ loader.add(library: "monitor")
42
+ when "csv"
43
+ loader.add(library: "forwardable")
44
+ when "prime"
45
+ loader.add(library: "singleton")
34
46
  end
35
47
 
36
48
  new_decls = loader.load(env: @env).map {|decl,| decl }
37
49
  RBSReader.load_rbs(@env, new_decls)
38
50
  end
39
51
 
40
- def load_path(path)
41
- loader = RBS::EnvironmentLoader.new(core_root: nil)
42
- loader.add(path: path)
52
+ def load_paths(paths)
53
+ loader = RBS::EnvironmentLoader.new(core_root: nil, repository: @repo)
54
+ paths.each {|path| loader.add(path: path) }
43
55
  new_decls = loader.load(env: @env).map {|decl,| decl }
44
56
  RBSReader.load_rbs(@env, new_decls)
45
57
  end
@@ -69,6 +81,7 @@ module TypeProf
69
81
  class RBS2JSON
70
82
  def initialize(all_env, cur_env)
71
83
  @all_env, @cur_env = all_env, cur_env
84
+ @alias_resolution_stack = {}
72
85
  end
73
86
 
74
87
  def dump_json
@@ -176,11 +189,15 @@ module TypeProf
176
189
  when RBS::AST::Members::Include
177
190
  name = member.name
178
191
  if name.kind == :class
192
+ # including a module
179
193
  mod = conv_type_name(name)
180
194
  type_args = member.args.map {|type| conv_type(type) }
181
195
  modules[:include] << [mod, type_args]
182
196
  else
183
- # including an interface is not supported yet
197
+ # including an interface
198
+ mod = conv_type_name(name)
199
+ type_args = member.args.map {|type| conv_type(type) }
200
+ modules[:include] << [mod, type_args]
184
201
  end
185
202
 
186
203
  when RBS::AST::Members::Extend
@@ -424,8 +441,17 @@ module TypeProf
424
441
  raise NotImplementedError
425
442
  end
426
443
  when RBS::Types::Alias
427
- alias_decl = @all_env.alias_decls[ty.name]
428
- alias_decl ? conv_type(alias_decl.decl.type) : [:any]
444
+ if @alias_resolution_stack[ty.name]
445
+ [:any]
446
+ else
447
+ begin
448
+ @alias_resolution_stack[ty.name] = true
449
+ alias_decl = @all_env.alias_decls[ty.name]
450
+ alias_decl ? conv_type(alias_decl.decl.type) : [:any]
451
+ ensure
452
+ @alias_resolution_stack.delete(ty.name)
453
+ end
454
+ end
429
455
  when RBS::Types::Union
430
456
  [:union, ty.types.map {|ty2| conv_type(ty2) }.compact]
431
457
  when RBS::Types::Optional
@@ -472,9 +498,9 @@ module TypeProf
472
498
  Import.new(scratch, json).import
473
499
  end
474
500
 
475
- def self.import_rbs_file(scratch, rbs_path)
476
- rbs_path = Pathname(rbs_path) unless rbs_path.is_a?(Pathname)
477
- Import.new(scratch, scratch.rbs_reader.load_path(rbs_path)).import(true)
501
+ def self.import_rbs_files(scratch, rbs_paths)
502
+ rbs_paths = rbs_paths.map {|rbs_path| Pathname(rbs_path) }
503
+ Import.new(scratch, scratch.rbs_reader.load_paths(rbs_paths)).import(true)
478
504
  end
479
505
 
480
506
  def self.import_rbs_code(scratch, rbs_name, rbs_code)