katakata_irb 0.1.5 → 0.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 882c0834b6d52916911b26b82083e1100491dd24cafdb1c948c4c1795fe03d7e
4
- data.tar.gz: 2250eaec5d0b1cabc236f238249e132206b62e70ada1c16429567b680ace2093
3
+ metadata.gz: df817c7e7806e6ea21aa82e14a694130b0db5dd68c74ea84790b90ad3b895fb7
4
+ data.tar.gz: 9faa1d72b27f35bccc5b4d2dcc5c9f50b4dd9946ba5d63374d3083e933e62c38
5
5
  SHA512:
6
- metadata.gz: 60f3c4de13636f2948e740b3a57b6091c1f193ae7fa259d665c69a404833ef413b90aca3da7360f97be2d7a669e9a0d5fc101ff172890c4f0714c9eb63db8dd4
7
- data.tar.gz: eb496c54819de4f1e035e261a6afffcc13d2809b316428602567614dbc5671df5ead97fb4a0696afbb34a7ade9ce8a2b3e9579ebad4ddd006d9a32b120b3e05d
6
+ metadata.gz: 9bec77d0fd1f9484278541e48a964c683ef2546b8a5b107e731d7979b634c4c8fb9ce2b68261603fc5f4ad8eb83cfb3018e11881a2ecd4096d268e7be0e97405
7
+ data.tar.gz: b6520a88ad8644423f24e7c02e783bf1cb388b3a00d2c16151b97e08598f1fd80f55f8346562d00c9d2ec0e2b619d4f4db23eeba5834c39b9ebfc72ce765cbdb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- katakata_irb (0.1.5)
4
+ katakata_irb (0.1.6)
5
5
  irb (>= 1.4.0)
6
6
  rbs
7
7
 
@@ -87,7 +87,7 @@ module KatakataIrb
87
87
  end
88
88
 
89
89
  class Scope < BaseScope
90
- attr_reader :parent, :jump_branches, :mergeable_changes, :level
90
+ attr_reader :parent, :jump_branches, :mergeable_changes, :level, :lvars
91
91
 
92
92
  def self.from_binding(binding) = new(BaseScope.new(binding, binding.eval('self')))
93
93
 
@@ -101,6 +101,7 @@ module KatakataIrb
101
101
  @passthrough = passthrough
102
102
  @terminated = false
103
103
  @jump_branches = []
104
+ @lvars = Set.new
104
105
  @mergeable_changes = @changes = table.transform_values { [level, _1] }
105
106
  end
106
107
 
@@ -156,6 +157,7 @@ module KatakataIrb
156
157
 
157
158
  def []=(name, value)
158
159
  variable_level = level_of(name) || level
160
+ @lvars << name if level == variable_level && BaseScope.type_by_name(name) == :lvar
159
161
  @changes[name] = [variable_level, value]
160
162
  end
161
163
 
@@ -197,12 +199,17 @@ module KatakataIrb
197
199
  update scope
198
200
  end
199
201
 
202
+ def touch_lvars(lvars)
203
+ lvars.each { self[_1] = self[_1] || KatakataIrb::Types::NIL }
204
+ end
205
+
200
206
  def run_branches(*blocks)
201
207
  results = []
202
208
  branches = []
203
209
  blocks.each do |block|
204
210
  scope = Scope.new self, passthrough: true
205
211
  result = block.call scope
212
+ touch_lvars scope.lvars if scope.level == level
206
213
  next if scope.terminated?
207
214
  results << result
208
215
  branches << scope.mergeable_changes
@@ -222,6 +229,7 @@ module KatakataIrb
222
229
 
223
230
  def update(child_scope)
224
231
  current_level = level
232
+ touch_lvars child_scope.lvars if child_scope.level == current_level
225
233
  child_scope.mergeable_changes.each do |name, (level, value)|
226
234
  self[name] = value if level <= current_level
227
235
  end
@@ -70,7 +70,7 @@ class KatakataIrb::TypeSimulator
70
70
  else
71
71
  current_self_types = scope.self_type.types
72
72
  self_types = current_self_types.map do |type|
73
- if (type in KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
73
+ if type.is_a?(KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
74
74
  KatakataIrb::Types::InstanceType.new type.module_or_class
75
75
  else
76
76
  type
@@ -129,10 +129,10 @@ class KatakataIrb::TypeSimulator
129
129
  in [:array, [:args_add_star,] => star]
130
130
  args, kwargs = retrieve_method_args star
131
131
  types = args.flat_map do |elem|
132
- if elem in KatakataIrb::Types::Splat
132
+ if elem.is_a? KatakataIrb::Types::Splat
133
133
  splat = simulate_evaluate elem.item, scope
134
- array_value = to_array splat, :to_a
135
- array_value ? (array_value.params[:Elem] || []) : splat
134
+ array_elem, non_array = partition_to_array splat.nonnillable, :to_a
135
+ KatakataIrb::Types::UnionType[*array_elem, *non_array]
136
136
  else
137
137
  simulate_evaluate elem, scope
138
138
  end
@@ -173,10 +173,10 @@ class KatakataIrb::TypeSimulator
173
173
  values << simulate_evaluate(value, scope)
174
174
  in [:assoc_splat, value]
175
175
  hash = simulate_evaluate value, scope
176
- unless (hash in KatakataIrb::Types::InstanceType) && hash.klass == Hash
176
+ unless hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
177
177
  hash = simulate_call hash, :to_hash, [], nil, nil
178
178
  end
179
- if (hash in KatakataIrb::Types::InstanceType) && hash.klass == Hash
179
+ if hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
180
180
  keys << hash.params[:K] if hash.params[:K]
181
181
  values << hash.params[:V] if hash.params[:V]
182
182
  end
@@ -192,7 +192,7 @@ class KatakataIrb::TypeSimulator
192
192
  statements.map { simulate_evaluate _1, scope }.last
193
193
  in [:const_path_ref, receiver, [:@const, name,]]
194
194
  r = simulate_evaluate receiver, scope
195
- (r in KatakataIrb::Types::SingletonType) ? KatakataIrb::BaseScope.type_of { r.module_or_class.const_get name } : KatakataIrb::Types::NIL
195
+ r.is_a?(KatakataIrb::Types::SingletonType) ? KatakataIrb::BaseScope.type_of { r.module_or_class.const_get name } : KatakataIrb::Types::NIL
196
196
  in [:__var_ref_or_call, [type, name, pos]]
197
197
  sexp = scope.has?(name) ? [:var_ref, [type, name, pos]] : [:vcall, [:@ident, name, pos]]
198
198
  simulate_evaluate sexp, scope
@@ -221,7 +221,7 @@ class KatakataIrb::TypeSimulator
221
221
  receiver_type = simulate_evaluate receiver, scope if receiver
222
222
  args, kwargs, _block = retrieve_method_args args
223
223
  args_type = args.map do |arg|
224
- if arg in KatakataIrb::Types::Splat
224
+ if arg.is_a? KatakataIrb::Types::Splat
225
225
  simulate_evaluate arg.item, scope
226
226
  nil # TODO: splat
227
227
  else
@@ -242,7 +242,7 @@ class KatakataIrb::TypeSimulator
242
242
  receiver_type = receiver ? simulate_evaluate(receiver, scope) : scope.self_type
243
243
  evaluate_method = lambda do |scope|
244
244
  args_type = args.map do |arg|
245
- if arg in KatakataIrb::Types::Splat
245
+ if arg.is_a? KatakataIrb::Types::Splat
246
246
  simulate_evaluate arg.item, scope
247
247
  nil # TODO: splat
248
248
  else
@@ -342,7 +342,7 @@ class KatakataIrb::TypeSimulator
342
342
  simulate_evaluate receiver, scope
343
343
  args, kwargs, _block = retrieve_method_args key
344
344
  args.each do |arg|
345
- item = ((arg in KatakataIrb::Types::Splat) ? arg.item : arg)
345
+ item = arg.is_a?(KatakataIrb::Types::Splat) ? arg.item : arg
346
346
  simulate_evaluate item, scope
347
347
  end
348
348
  kwargs_type kwargs, scope
@@ -435,7 +435,7 @@ class KatakataIrb::TypeSimulator
435
435
  in [:super, args]
436
436
  args, kwargs, _block = retrieve_method_args args
437
437
  args.each do |arg|
438
- item = ((arg in KatakataIrb::Types::Splat) ? arg.item : arg)
438
+ item = arg.is_a?(KatakataIrb::Types::Splat) ? arg.item : arg
439
439
  simulate_evaluate item, scope
440
440
  end
441
441
  kwargs_type kwargs, scope
@@ -460,7 +460,7 @@ class KatakataIrb::TypeSimulator
460
460
  error_class_stmts = [*stmts, stmt]
461
461
  end
462
462
  error_classes = (error_class_stmts || []).flat_map { simulate_evaluate _1, s }.uniq
463
- error_types = error_classes.filter_map { KatakataIrb::Types::InstanceType.new _1.module_or_class if _1 in KatakataIrb::Types::SingletonType }
463
+ error_types = error_classes.filter_map { KatakataIrb::Types::InstanceType.new _1.module_or_class if _1.is_a?(KatakataIrb::Types::SingletonType) }
464
464
  error_types << KatakataIrb::Types::InstanceType.new(StandardError) if error_types.empty?
465
465
  s[error_var] = KatakataIrb::Types::UnionType[*error_types]
466
466
  end
@@ -486,7 +486,7 @@ class KatakataIrb::TypeSimulator
486
486
  result
487
487
  in [:sclass, klass_stmt, body_stmt]
488
488
  klass_types = simulate_evaluate(klass_stmt, scope).types.filter_map do |type|
489
- KatakataIrb::Types::SingletonType.new type.klass if type in KatakataIrb::Types::InstanceType
489
+ KatakataIrb::Types::SingletonType.new type.klass if type.is_a? KatakataIrb::Types::InstanceType
490
490
  end
491
491
  klass_types = [KatakataIrb::Types::CLASS] if klass_types.empty?
492
492
  sclass_scope = KatakataIrb::Scope.new(scope, { KatakataIrb::Scope::SELF => KatakataIrb::Types::UnionType[*klass_types], KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil }, trace_cvar: false, trace_ivar: false, trace_lvar: false)
@@ -497,7 +497,7 @@ class KatakataIrb::TypeSimulator
497
497
  klass_types = simulate_evaluate(klass_stmt, scope).types
498
498
  klass_types += simulate_evaluate(superclass_stmt, scope).types if superclass_stmt
499
499
  klass_types = klass_types.select do |type|
500
- (type in KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
500
+ type.is_a?(KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
501
501
  end
502
502
  klass_types << KatakataIrb::Types::CLASS if klass_types.empty?
503
503
  klass_scope = KatakataIrb::Scope.new(scope, { KatakataIrb::Scope::SELF => KatakataIrb::Types::UnionType[*klass_types], KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil }, trace_cvar: false, trace_ivar: false, trace_lvar: false)
@@ -571,6 +571,9 @@ class KatakataIrb::TypeSimulator
571
571
  simulate_evaluate a, scope
572
572
  simulate_evaluate b, scope
573
573
  KatakataIrb::Types::STRING
574
+ in [:defined, expression]
575
+ scope.conditional { simulate_evaluate expression, _1 }
576
+ KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
574
577
  else
575
578
  KatakataIrb.log_puts
576
579
  KatakataIrb.log_puts :NOMATCH
@@ -597,7 +600,7 @@ class KatakataIrb::TypeSimulator
597
600
  in [:binary, lpattern, :'=>', [:var_field, [:@ident, name,]] => rpattern]
598
601
  if lpattern in [:var_ref, [:@const, _const_name,]]
599
602
  const_value = simulate_evaluate lpattern, scope
600
- if (const_value in KatakataIrb::Types::SingletonType) && const_value.module_or_class.is_a?(Class)
603
+ if const_value.is_a?(KatakataIrb::Types::SingletonType) && const_value.module_or_class.is_a?(Class)
601
604
  scope[name] = KatakataIrb::Types::InstanceType.new const_value.module_or_class
602
605
  else
603
606
  scope[name] = KatakataIrb::Types::OBJECT
@@ -609,7 +612,7 @@ class KatakataIrb::TypeSimulator
609
612
  end
610
613
  in [:aryptn, _unknown, items, splat, post_items]
611
614
  # TODO: deconstruct keys
612
- array_types = types.select { (_1 in KatakataIrb::Types::InstanceType) && _1.klass == Array }
615
+ array_types = types.select { _1.is_a?(KatakataIrb::Types::InstanceType) && _1.klass == Array }
613
616
  elem = KatakataIrb::Types::UnionType[*array_types.filter_map { _1.params[:Elem] }]
614
617
  items&.each do |item|
615
618
  match_pattern elem, item, scope
@@ -623,7 +626,7 @@ class KatakataIrb::TypeSimulator
623
626
  end
624
627
  in [:hshptn, _unknown, items, splat]
625
628
  # TODO: deconstruct keys
626
- hash_types = types.select { (_1 in KatakataIrb::Types::InstanceType) && _1.klass == Hash }
629
+ hash_types = types.select { _1.is_a?(KatakataIrb::Types::InstanceType) && _1.klass == Hash }
627
630
  key_type = KatakataIrb::Types::UnionType[*hash_types.filter_map { _1.params[:K] }]
628
631
  value_type = KatakataIrb::Types::UnionType[*hash_types.filter_map { _1.params[:V] }]
629
632
  items&.each do |key_pattern, value_pattern|
@@ -652,7 +655,7 @@ class KatakataIrb::TypeSimulator
652
655
  def evaluate_mrhs(sexp, scope)
653
656
  args, kwargs, = retrieve_method_args sexp
654
657
  values = args.filter_map do |t|
655
- if t in KatakataIrb::Types::Splat
658
+ if t.is_a? KatakataIrb::Types::Splat
656
659
  simulate_evaluate t.item, scope
657
660
  # TODO
658
661
  nil
@@ -679,17 +682,31 @@ class KatakataIrb::TypeSimulator
679
682
  [values, kw]
680
683
  end
681
684
 
682
- def to_array(value, method)
683
- return value if (value in KatakataIrb::Types::InstanceType) && value.klass == Array
684
- to_array_result = simulate_call value, method, [], nil, nil, name_match: false
685
- return to_array_result if (to_array_result in KatakataIrb::Types::InstanceType) && to_array_result.klass == Array
685
+ def sized_splat(value, method, size)
686
+ array_elem, non_array = partition_to_array value, method
687
+ values = [KatakataIrb::Types::UnionType[*array_elem, *non_array]]
688
+ values += [array_elem] * (size - 1) if array_elem && size >= 1
689
+ values
686
690
  end
687
691
 
688
- def evaluate_massign(sexp, values, scope)
689
- unless values in Array
690
- array_value = to_array values, :to_ary
691
- values = array_value ? [array_value.params[:Elem] || KatakataIrb::Types::OBJECT] * sexp.size : [values]
692
+ def partition_to_array(value, method)
693
+ arrays, non_arrays = value.types.partition { _1.is_a?(KatakataIrb::Types::InstanceType) && _1.klass == Array }
694
+ non_arrays.select! do |type|
695
+ to_array_result = simulate_call type, method, [], nil, nil, name_match: false
696
+ if to_array_result.is_a?(KatakataIrb::Types::InstanceType) && to_array_result.klass == Array
697
+ arrays << to_array_result
698
+ false
699
+ else
700
+ true
701
+ end
692
702
  end
703
+ array_elem = arrays.empty? ? nil : KatakataIrb::Types::UnionType[*arrays.map { _1.params[:Elem] || KatakataIrb::Types::OBJECT }]
704
+ non_array = non_arrays.empty? ? nil : KatakataIrb::Types::UnionType[*non_arrays]
705
+ [array_elem, non_array]
706
+ end
707
+
708
+ def evaluate_massign(sexp, values, scope)
709
+ values = sized_splat values, :to_ary, sexp.size unless values.is_a? Array
693
710
 
694
711
  rest_index = sexp.find_index { _1 in [:rest_param, ]}
695
712
  if rest_index
@@ -729,12 +746,12 @@ class KatakataIrb::TypeSimulator
729
746
  keys = []
730
747
  values = []
731
748
  kwargs.each do |kv|
732
- if kv in KatakataIrb::Types::Splat
749
+ if kv.is_a? KatakataIrb::Types::Splat
733
750
  hash = simulate_evaluate kv.item, scope
734
- unless (hash in KatakataIrb::Types::InstanceType) && hash.klass == Hash
751
+ unless hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
735
752
  hash = simulate_call hash, :to_hash, [], nil, nil
736
753
  end
737
- if (hash in KatakataIrb::Types::InstanceType) && hash.klass == Hash
754
+ if hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
738
755
  keys << hash.params[:K] if hash.params[:K]
739
756
  values << hash.params[:V] if hash.params[:V]
740
757
  end
@@ -822,6 +839,8 @@ class KatakataIrb::TypeSimulator
822
839
  [args, [], nil]
823
840
  in [:arg_paren, args]
824
841
  args ? retrieve_method_args(args) : [[], [], nil]
842
+ in [[:command | :command_call, ] => command_arg] # method(a b, c), method(a.b c, d)
843
+ [[command_arg], [], nil]
825
844
  else
826
845
  [[], [], nil]
827
846
  end
@@ -901,11 +920,7 @@ class KatakataIrb::TypeSimulator
901
920
  values = values.dup
902
921
  params => [:params, pre_required, optional, rest, post_required, _keywords, keyrest, block]
903
922
  size = (pre_required&.size || 0) + (optional&.size || 0) + (post_required&.size || 0) + (rest ? 1 : 0)
904
- if values.size == 1 && size >= 2
905
- value = values.first
906
- array_value = to_array value, :to_ary if value
907
- values = [array_value.params[:Elem] || KatakataIrb::Types::OBJECT] * size if array_value
908
- end
923
+ values = sized_splat values.first, :to_ary, size if values.size == 1 && size >= 2
909
924
  pre_values = values.shift pre_required.size if pre_required
910
925
  post_values = values.pop post_required.size if post_required
911
926
  opt_values = values.shift optional.size if optional
@@ -955,7 +970,7 @@ class KatakataIrb::TypeSimulator
955
970
  name.match?(/\A_[1-9]\z/) ? name[1..].to_i : 0
956
971
  else
957
972
  sexp.filter_map do |s|
958
- max_numbered_params s if s in Array
973
+ max_numbered_params s if s.is_a? Array
959
974
  end.max || 0
960
975
  end
961
976
  end
@@ -4,9 +4,16 @@ require 'rbs/cli'
4
4
  module KatakataIrb; end
5
5
  module KatakataIrb::Types
6
6
  def self.rbs_builder
7
- @rbs_builder ||= RBS::DefinitionBuilder.new(
8
- env: RBS::Environment.from_loader(RBS::CLI::LibraryOptions.new.loader).resolve_type_names
9
- )
7
+ @rbs_builder ||= load_rbs_builder
8
+ end
9
+
10
+ def self.load_rbs_builder
11
+ loader = RBS::CLI::LibraryOptions.new.loader
12
+ loader.add path: Pathname('sig')
13
+ RBS::DefinitionBuilder.new env: RBS::Environment.from_loader(loader).resolve_type_names
14
+ rescue => e
15
+ puts "\nKatakataIRB failed to initialize RBS::DefinitionBuild\n#{e}"
16
+ Object.new
10
17
  end
11
18
 
12
19
  Splat = Struct.new :item
@@ -24,7 +31,7 @@ module KatakataIrb::Types
24
31
  next unless name
25
32
  type_name = RBS::TypeName(name).absolute!
26
33
  definition = (singleton ? rbs_builder.build_singleton(type_name) : rbs_builder.build_instance(type_name)) rescue nil
27
- method = definition&.methods&.[](method_name)
34
+ method = definition.methods[method_name] if definition
28
35
  return method if method
29
36
  end
30
37
  nil
@@ -170,6 +177,9 @@ module KatakataIrb::Types
170
177
  def types() = [self]
171
178
  def nillable?() = false
172
179
  def nonnillable() = self
180
+ def inspect
181
+ "#{module_or_class}.itself"
182
+ end
173
183
  end
174
184
 
175
185
  class InstanceType
@@ -185,6 +195,19 @@ module KatakataIrb::Types
185
195
  def types() = [self]
186
196
  def nillable?() = (@klass == NilClass)
187
197
  def nonnillable() = self
198
+ def inspect
199
+ case klass
200
+ when NilClass
201
+ 'nil'
202
+ when TrueClass
203
+ 'true'
204
+ when FalseClass
205
+ 'false'
206
+ else
207
+ params_string = "[#{params.map { "#{_1}: #{_2.inspect}" }.join(', ')}]" unless params.empty?
208
+ "#{klass.name}#{params_string}"
209
+ end
210
+ end
188
211
  end
189
212
 
190
213
  class ProcType
@@ -201,6 +224,7 @@ module KatakataIrb::Types
201
224
  def types() = [self]
202
225
  def nillable?() = (@klass == NilClass)
203
226
  def nonnillable() = self
227
+ def inspect() = 'Proc'
204
228
  end
205
229
 
206
230
  NIL = InstanceType.new NilClass
@@ -276,6 +300,7 @@ module KatakataIrb::Types
276
300
  def methods() = @types.flat_map(&:methods).uniq
277
301
  def all_methods() = @types.flat_map(&:all_methods).uniq
278
302
  def constants() = @types.flat_map(&:constants).uniq
303
+ def inspect() = @types.map(&:inspect).join(' | ')
279
304
  end
280
305
 
281
306
  BOOLEAN = UnionType[TRUE, FALSE]
@@ -284,9 +309,9 @@ module KatakataIrb::Types
284
309
  case return_type
285
310
  when RBS::Types::Bases::Self
286
311
  self_type
287
- when RBS::Types::Bases::Void, RBS::Types::Bases::Bottom, RBS::Types::Bases::Nil
312
+ when RBS::Types::Bases::Bottom, RBS::Types::Bases::Nil
288
313
  NIL
289
- when RBS::Types::Bases::Any
314
+ when RBS::Types::Bases::Any, RBS::Types::Bases::Void
290
315
  OBJECT
291
316
  when RBS::Types::Bases::Class
292
317
  self_type.transform do |type|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KatakataIrb
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.6"
5
5
  end
data/sig/katakata_irb.rbs CHANGED
@@ -1,4 +1,7 @@
1
1
  module KatakataIrb
2
2
  VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
3
+ module Completor
4
+ def self.analyze: (code: String, binding?: Binding) -> Array[Symbol | Object | String | true | false]?
5
+ def self.setup: () -> void
6
+ end
4
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: katakata_irb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - tompng
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-14 00:00:00.000000000 Z
11
+ date: 2023-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: irb