rbs 1.0.0.pre → 1.0.3

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +10 -4
  3. data/CHANGELOG.md +41 -6
  4. data/Gemfile +7 -2
  5. data/README.md +1 -1
  6. data/Rakefile +11 -4
  7. data/Steepfile +2 -1
  8. data/bin/annotate-with-rdoc +0 -4
  9. data/bin/test_runner.rb +4 -5
  10. data/core/encoding.rbs +1 -1
  11. data/core/file.rbs +4 -0
  12. data/core/io.rbs +81 -5
  13. data/core/kernel.rbs +56 -56
  14. data/core/module.rbs +43 -2
  15. data/core/unbound_method.rbs +16 -0
  16. data/docs/CONTRIBUTING.md +2 -2
  17. data/docs/stdlib.md +50 -12
  18. data/docs/syntax.md +0 -17
  19. data/goodcheck.yml +3 -3
  20. data/lib/rbs/ast/declarations.rb +0 -47
  21. data/lib/rbs/definition_builder.rb +102 -64
  22. data/lib/rbs/definition_builder/ancestor_builder.rb +52 -3
  23. data/lib/rbs/environment.rb +1 -7
  24. data/lib/rbs/environment_loader.rb +7 -3
  25. data/lib/rbs/errors.rb +22 -57
  26. data/lib/rbs/parser.rb +1003 -1027
  27. data/lib/rbs/parser.y +12 -21
  28. data/lib/rbs/prototype/rb.rb +18 -4
  29. data/lib/rbs/prototype/runtime.rb +30 -14
  30. data/lib/rbs/test/hook.rb +7 -6
  31. data/lib/rbs/test/setup_helper.rb +0 -1
  32. data/lib/rbs/types.rb +6 -2
  33. data/lib/rbs/version.rb +1 -1
  34. data/lib/rbs/writer.rb +4 -3
  35. data/rbs.gemspec +1 -0
  36. data/sig/ancestor_builder.rbs +98 -0
  37. data/sig/declarations.rbs +4 -16
  38. data/sig/definition_builder.rbs +17 -71
  39. data/sig/errors.rbs +141 -2
  40. data/sig/method_builder.rbs +71 -0
  41. data/sig/substitution.rbs +3 -0
  42. data/sig/types.rbs +1 -15
  43. data/stdlib/csv/0/csv.rbs +3 -0
  44. data/stdlib/fileutils/0/fileutils.rbs +585 -0
  45. data/stdlib/pathname/0/pathname.rbs +2 -2
  46. data/stdlib/prettyprint/0/prettyprint.rbs +366 -0
  47. data/stdlib/prime/0/prime.rbs +6 -0
  48. data/stdlib/securerandom/0/securerandom.rbs +2 -0
  49. data/stdlib/uri/0/common.rbs +1 -1
  50. metadata +10 -7
  51. data/core/data.rbs +0 -5
@@ -50,7 +50,6 @@ rule
50
50
  | interface_decl
51
51
  | module_decl
52
52
  | class_decl
53
- | extension_decl
54
53
 
55
54
  start_new_scope: { start_new_variables_scope }
56
55
  start_merged_scope: { start_merged_variables_scope }
@@ -61,24 +60,6 @@ rule
61
60
  result = val[1].unshift(Annotation.new(string: val[0].value, location: val[0].location))
62
61
  }
63
62
 
64
- extension_decl:
65
- annotations kEXTENSION start_new_scope class_name type_params kLPAREN extension_name kRPAREN class_members kEND {
66
- reset_variable_scope
67
-
68
- location = val[1].location + val[9].location
69
- result = Declarations::Extension.new(
70
- name: val[3].value,
71
- type_params: val[4]&.value || [],
72
- extension_name: val[6].value.to_sym,
73
- members: val[8],
74
- annotations: val[0],
75
- location: location,
76
- comment: leading_comment(val[0].first&.location || location)
77
- )
78
- }
79
-
80
- extension_name: tUIDENT | tLIDENT
81
-
82
63
  class_decl:
83
64
  annotations kCLASS start_new_scope class_name module_type_params super_class class_members kEND {
84
65
  reset_variable_scope
@@ -630,7 +611,7 @@ rule
630
611
  }
631
612
 
632
613
  type_decl:
633
- annotations kTYPE qualified_name kEQ type {
614
+ annotations kTYPE type_alias_name kEQ type {
634
615
  location = val[1].location + val[4].location
635
616
  result = Declarations::Alias.new(name: val[2].value,
636
617
  type: val[4],
@@ -1056,6 +1037,16 @@ rule
1056
1037
  result = LocatedValue.new(value: type_name, location: location)
1057
1038
  }
1058
1039
 
1040
+ type_alias_name:
1041
+ namespace tLIDENT {
1042
+ namespace = val[0]&.value || Namespace.empty
1043
+ name = val[1].value.to_sym
1044
+ type_name = TypeName.new(namespace: namespace, name: name)
1045
+ location = (loc0 = val[0]&.location) ? loc0 + val[1].location : val[1].location
1046
+ result = LocatedValue.new(value: type_name, location: location)
1047
+ }
1048
+
1049
+
1059
1050
  namespace:
1060
1051
  {
1061
1052
  result = nil
@@ -1380,7 +1371,7 @@ def next_token
1380
1371
  new_token(:tWRITE_ATTR)
1381
1372
  when input.scan(KEYWORDS_RE)
1382
1373
  new_token(KEYWORDS[input.matched], input.matched.to_sym)
1383
- when input.scan(/:((@{,2}|\$)?\w+(\?|\!)?|\+|\-)\b?/)
1374
+ when input.scan(/:((@{,2}|\$)?\w+(\?|\!)?|[|&\/%~`^]|<=>|={2,3}|=~|[<>]{2}|[<>]=?|[-+]@?|\*{1,2}|\[\]=?|![=~]?)\b?/)
1384
1375
  s = input.matched.yield_self {|s| s[1, s.length] }.to_sym
1385
1376
  new_token(:tSYMBOL, s)
1386
1377
  when input.scan(/[+-]?\d[\d_]*/)
@@ -129,9 +129,13 @@ module RBS
129
129
  RBS.logger.warn "`class <<` syntax with not-self may be compiled to incorrect code: #{this}"
130
130
  end
131
131
 
132
+ accessibility = current_accessibility(decls)
133
+
132
134
  ctx = Context.initial.tap { |ctx| ctx.singleton = true }
133
135
  process_children(body, decls: decls, comments: comments, context: ctx)
134
136
 
137
+ decls << accessibility
138
+
135
139
  when :DEFN, :DEFS
136
140
  if node.type == :DEFN
137
141
  def_name, def_body = node.children
@@ -376,7 +380,7 @@ module RBS
376
380
  def function_type_from_body(node)
377
381
  table_node, args_node, *_ = node.children
378
382
 
379
- pre_num, _pre_init, opt, _first_post, post_num, _post_init, rest, kw, kwrest, _block = args_node.children
383
+ pre_num, _pre_init, opt, _first_post, post_num, _post_init, rest, kw, kwrest, _block = args_from_node(args_node)
380
384
 
381
385
  return_type = function_return_type_from_body(node)
382
386
 
@@ -396,7 +400,8 @@ module RBS
396
400
  end
397
401
 
398
402
  if rest
399
- fun = fun.update(rest_positionals: Types::Function::Param.new(name: rest, type: untyped))
403
+ rest_name = rest == :* ? nil : rest # # For `def f(...) end` syntax
404
+ fun = fun.update(rest_positionals: Types::Function::Param.new(name: rest_name, type: untyped))
400
405
  end
401
406
 
402
407
  table_node.drop(fun.required_positionals.size + fun.optional_positionals.size + (fun.rest_positionals ? 1 : 0)).take(post_num).each do |name|
@@ -555,13 +560,16 @@ module RBS
555
560
  def block_from_body(node)
556
561
  _, args_node, body_node = node.children
557
562
 
558
- _pre_num, _pre_init, _opt, _first_post, _post_num, _post_init, _rest, _kw, _kwrest, block = args_node.children
563
+ _pre_num, _pre_init, _opt, _first_post, _post_num, _post_init, _rest, _kw, _kwrest, block = args_from_node(args_node)
559
564
 
560
565
  method_block = nil
561
566
 
562
567
  if block
563
568
  method_block = Types::Block.new(
564
- required: true,
569
+ # HACK: The `block` is :& on `def m(...)` syntax.
570
+ # In this case the block looks optional in most cases, so it marks optional.
571
+ # In other cases, we can't determine which is required or optional, so it marks required.
572
+ required: block != :&,
565
573
  type: Types::Function.empty(untyped)
566
574
  )
567
575
  end
@@ -610,6 +618,12 @@ module RBS
610
618
  method_block
611
619
  end
612
620
 
621
+ # NOTE: args_node may be a nil by a bug
622
+ # https://bugs.ruby-lang.org/issues/17495
623
+ def args_from_node(args_node)
624
+ args_node&.children || [0, nil, nil, nil, 0, nil, nil, nil, nil, nil]
625
+ end
626
+
613
627
  def keyword_hash?(node)
614
628
  if node
615
629
  if node.type == :HASH
@@ -80,12 +80,12 @@ module RBS
80
80
  unless const_name(mix)
81
81
  RBS.logger.warn("Skipping anonymous module #{mix} included in #{mod}")
82
82
  else
83
- module_name = to_type_name(const_name(mix))
84
- if module_name.namespace == type_name.namespace
85
- module_name = TypeName.new(name: module_name.name, namespace: Namespace.empty)
83
+ module_name = module_full_name = to_type_name(const_name(mix))
84
+ if module_full_name.namespace == type_name.namespace
85
+ module_name = TypeName.new(name: module_full_name.name, namespace: Namespace.empty)
86
86
  end
87
87
 
88
- yield module_name, mix
88
+ yield module_name, module_full_name, mix
89
89
  end
90
90
  end
91
91
  end
@@ -319,7 +319,9 @@ module RBS
319
319
  location: nil
320
320
  )
321
321
  else
322
- Types::ClassInstance.new(name: to_type_name(const_name(value.class)), args: [], location: nil)
322
+ value_type_name = to_type_name(const_name(value.class))
323
+ args = type_args(value_type_name)
324
+ Types::ClassInstance.new(name: value_type_name, args: args, location: nil)
323
325
  end
324
326
 
325
327
  @decls << AST::Declarations::Constant.new(
@@ -339,7 +341,9 @@ module RBS
339
341
  RBS.logger.warn("Skipping anonymous superclass #{mod.superclass} of #{mod}")
340
342
  nil
341
343
  else
342
- AST::Declarations::Class::Super.new(name: to_type_name(const_name(mod.superclass)), args: [], location: nil)
344
+ super_name = to_type_name(const_name(mod.superclass))
345
+ super_args = type_args(super_name)
346
+ AST::Declarations::Class::Super.new(name: super_name, args: super_args, location: nil)
343
347
  end
344
348
 
345
349
  decl = AST::Declarations::Class.new(
@@ -352,20 +356,22 @@ module RBS
352
356
  comment: nil
353
357
  )
354
358
 
355
- each_included_module(type_name, mod) do |module_name, _|
359
+ each_included_module(type_name, mod) do |module_name, module_full_name, _|
360
+ args = type_args(module_full_name)
356
361
  decl.members << AST::Members::Include.new(
357
362
  name: module_name,
358
- args: [],
363
+ args: args,
359
364
  location: nil,
360
365
  comment: nil,
361
366
  annotations: []
362
367
  )
363
368
  end
364
369
 
365
- each_included_module(type_name, mod.singleton_class) do |module_name, _|
370
+ each_included_module(type_name, mod.singleton_class) do |module_name, module_full_name ,_|
371
+ args = type_args(module_full_name)
366
372
  decl.members << AST::Members::Extend.new(
367
373
  name: module_name,
368
- args: [],
374
+ args: args,
369
375
  location: nil,
370
376
  comment: nil,
371
377
  annotations: []
@@ -399,20 +405,22 @@ module RBS
399
405
  comment: nil
400
406
  )
401
407
 
402
- each_included_module(type_name, mod) do |module_name, _|
408
+ each_included_module(type_name, mod) do |module_name, module_full_name, _|
409
+ args = type_args(module_full_name)
403
410
  decl.members << AST::Members::Include.new(
404
411
  name: module_name,
405
- args: [],
412
+ args: args,
406
413
  location: nil,
407
414
  comment: nil,
408
415
  annotations: []
409
416
  )
410
417
  end
411
418
 
412
- each_included_module(type_name, mod.singleton_class) do |module_name, _|
419
+ each_included_module(type_name, mod.singleton_class) do |module_name, module_full_name, _|
420
+ args = type_args(module_full_name)
413
421
  decl.members << AST::Members::Extend.new(
414
422
  name: module_name,
415
- args: [],
423
+ args: args,
416
424
  location: nil,
417
425
  comment: nil,
418
426
  annotations: []
@@ -430,6 +438,14 @@ module RBS
430
438
  @module_name_method ||= Module.instance_method(:name)
431
439
  @module_name_method.bind(const).call
432
440
  end
441
+
442
+ def type_args(type_name)
443
+ if class_decl = env.class_decls[type_name.absolute!]
444
+ class_decl.type_params.size.times.map { :untyped }
445
+ else
446
+ []
447
+ end
448
+ end
433
449
  end
434
450
  end
435
451
  end
@@ -71,14 +71,15 @@ module RBS
71
71
  with_name, without_name = alias_names(method_name, random)
72
72
  full_method_name = "#{prefix}#{method_name}"
73
73
 
74
- param_source = params.take_while {|param| param[0] == :req }.map(&:last) + ["*rest_args_#{random}"]
74
+ param_source = params.take_while {|param| param[0] == :req }.map(&:last) + ["*rest_args__#{random}"]
75
+ block_param = "block__#{random}"
75
76
 
76
77
  RBS.logger.debug {
77
- "Generating method definition: def #{with_name}(#{param_source.join(", ")}, &block) ..."
78
+ "Generating method definition: def #{with_name}(#{param_source.join(", ")}, &#{block_param}) ..."
78
79
  }
79
80
 
80
81
  [__LINE__ + 1, <<RUBY]
81
- def #{with_name}(#{param_source.join(", ")}, &block)
82
+ def #{with_name}(#{param_source.join(", ")}, &#{block_param})
82
83
  args = [#{param_source.join(", ")}]
83
84
  ::RBS.logger.debug { "#{full_method_name} with arguments: [" + args.map(&:inspect).join(", ") + "]" }
84
85
 
@@ -88,7 +89,7 @@ def #{with_name}(#{param_source.join(", ")}, &block)
88
89
 
89
90
  if block_given?
90
91
  receiver = self
91
- block_receives_block = block.parameters.last&.yield_self {|type, _| type == :block }
92
+ block_receives_block = #{block_param}.parameters.last&.yield_self {|type, _| type == :block }
92
93
 
93
94
  wrapped_block = proc do |*block_args, &block2|
94
95
  return_from_block = false
@@ -96,12 +97,12 @@ def #{with_name}(#{param_source.join(", ")}, &block)
96
97
  begin
97
98
  block_result = if receiver.equal?(self)
98
99
  if block_receives_block
99
- block.call(*block_args, &block2)
100
+ #{block_param}.call(*block_args, &block2)
100
101
  else
101
102
  yield(*block_args)
102
103
  end
103
104
  else
104
- instance_exec(*block_args, &block)
105
+ instance_exec(*block_args, &#{block_param})
105
106
  end
106
107
 
107
108
  return_from_block = true
@@ -38,7 +38,6 @@ module RBS
38
38
  nil
39
39
  end
40
40
  end
41
-
42
41
  end
43
42
  end
44
43
  end
@@ -943,7 +943,11 @@ module RBS
943
943
  end
944
944
 
945
945
  def has_keyword?
946
- !required_keywords.empty? || !optional_keywords.empty? || rest_keywords
946
+ if !required_keywords.empty? || !optional_keywords.empty? || rest_keywords
947
+ true
948
+ else
949
+ false
950
+ end
947
951
  end
948
952
  end
949
953
 
@@ -953,7 +957,7 @@ module RBS
953
957
 
954
958
  def initialize(type:, required:)
955
959
  @type = type
956
- @required = required
960
+ @required = required ? true : false
957
961
  end
958
962
 
959
963
  def ==(other)
@@ -1,3 +1,3 @@
1
1
  module RBS
2
- VERSION = "1.0.0.pre"
2
+ VERSION = "1.0.3"
3
3
  end
@@ -232,10 +232,11 @@ module RBS
232
232
  def method_name(name)
233
233
  s = name.to_s
234
234
 
235
- if /\A#{Parser::KEYWORDS_RE}\z/.match?(s)
236
- "`#{s}`"
237
- else
235
+ if [:tOPERATOR, :kAMP, :kHAT, :kSTAR, :kLT, :kEXCLAMATION, :kSTAR2, :kBAR].include?(Parser::PUNCTS[s]) ||
236
+ (/\A[a-zA-Z_]\w*[?!=]?\z/.match?(s) && !/\Aself\??\z/.match?(s))
238
237
  s
238
+ else
239
+ "`#{s}`"
239
240
  end
240
241
  end
241
242
 
@@ -34,4 +34,5 @@ Gem::Specification.new do |spec|
34
34
  spec.bindir = "exe"
35
35
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
36
36
  spec.require_paths = ["lib"]
37
+ spec.required_ruby_version = ">= 2.6"
37
38
  end
@@ -0,0 +1,98 @@
1
+ module RBS
2
+ class DefinitionBuilder
3
+ class AncestorBuilder
4
+ class OneAncestors
5
+ attr_reader type_name: TypeName
6
+ attr_reader params: Array[Symbol]?
7
+ attr_reader super_class: Definition::Ancestor::t?
8
+ attr_reader self_types: Array[Definition::Ancestor::Instance]?
9
+ attr_reader included_modules: Array[Definition::Ancestor::Instance]?
10
+ attr_reader included_interfaces: Array[Definition::Ancestor::Instance]?
11
+ attr_reader prepended_modules: Array[Definition::Ancestor::Instance]?
12
+ attr_reader extended_modules: Array[Definition::Ancestor::Instance]?
13
+ attr_reader extended_interfaces: Array[Definition::Ancestor::Instance]?
14
+
15
+ def initialize: (type_name: TypeName,
16
+ params: Array[Symbol]?,
17
+ super_class: Definition::Ancestor::t?,
18
+ self_types: Array[Definition::Ancestor::Instance]?,
19
+ included_modules: Array[Definition::Ancestor::Instance]?,
20
+ included_interfaces: Array[Definition::Ancestor::Instance]?,
21
+ prepended_modules: Array[Definition::Ancestor::Instance]?,
22
+ extended_modules: Array[Definition::Ancestor::Instance]?,
23
+ extended_interfaces: Array[Definition::Ancestor::Instance]?) -> void
24
+
25
+ def each_ancestor: { (Definition::Ancestor::t) -> void } -> void
26
+ | -> Enumerator[Definition::Ancestor::t, void]
27
+
28
+ def self.class_instance: (type_name: TypeName, params: Array[Symbol], super_class: Definition::Ancestor::t?) -> instance
29
+
30
+ def self.singleton: (type_name: TypeName, super_class: Definition::Ancestor::t?) -> instance
31
+
32
+ def self.module_instance: (type_name: TypeName, params: Array[Symbol]) -> instance
33
+
34
+ def self.interface: (type_name: TypeName, params: Array[Symbol]) -> instance
35
+
36
+ def each_included_module: () { (Definition::Ancestor::Instance) -> void } -> void
37
+ | () -> Enumerator[Definition::Ancestor::Instance, void]
38
+
39
+ def each_included_interface: () { (Definition::Ancestor::Instance) -> void } -> void
40
+ | () -> Enumerator[Definition::Ancestor::Instance, void]
41
+
42
+ def each_prepended_module: () { (Definition::Ancestor::Instance) -> void } -> void
43
+ | () -> Enumerator[Definition::Ancestor::Instance, void]
44
+
45
+ def each_extended_module: () { (Definition::Ancestor::Instance) -> void } -> void
46
+ | () -> Enumerator[Definition::Ancestor::Instance, void]
47
+
48
+ def each_extended_interface: () { (Definition::Ancestor::Instance) -> void } -> void
49
+ | () -> Enumerator[Definition::Ancestor::Instance, void]
50
+
51
+ def each_self_type: () { (Definition::Ancestor::Instance) -> void } -> void
52
+ | () -> Enumerator[Definition::Ancestor::Instance, void]
53
+ end
54
+
55
+ attr_reader env: Environment
56
+
57
+ attr_reader one_instance_ancestors_cache: Hash[TypeName, OneAncestors]
58
+ attr_reader instance_ancestors_cache: Hash[TypeName, Definition::InstanceAncestors]
59
+
60
+ attr_reader one_singleton_ancestors_cache: Hash[TypeName, OneAncestors]
61
+ attr_reader singleton_ancestors_cache: Hash[TypeName, Definition::SingletonAncestors]
62
+
63
+ attr_reader one_interface_ancestors_cache: Hash[TypeName, OneAncestors]
64
+ attr_reader interface_ancestors_cache: Hash[TypeName, Definition::InstanceAncestors]
65
+
66
+ def initialize: (env: Environment) -> void
67
+
68
+ def validate_super_class!: (TypeName, Environment::ClassEntry) -> void
69
+
70
+ def one_instance_ancestors: (TypeName) -> OneAncestors
71
+
72
+ def one_singleton_ancestors: (TypeName) -> OneAncestors
73
+
74
+ def one_interface_ancestors: (TypeName) -> OneAncestors
75
+
76
+ def instance_ancestors: (TypeName, ?building_ancestors: Array[Definition::Ancestor::t]) -> Definition::InstanceAncestors
77
+
78
+ def singleton_ancestors: (TypeName, ?building_ancestors: Array[Definition::Ancestor::t]) -> Definition::SingletonAncestors
79
+
80
+ def interface_ancestors: (TypeName, ?building_ancestors: Array[Definition::Ancestor::t]) -> Definition::InstanceAncestors
81
+
82
+ def mixin_ancestors: (Environment::ClassEntry | Environment::ModuleEntry,
83
+ included_modules: Array[Definition::Ancestor::Instance]?,
84
+ included_interfaces:Array[Definition::Ancestor::Instance]?,
85
+ prepended_modules: Array[Definition::Ancestor::Instance]?,
86
+ extended_modules: Array[Definition::Ancestor::Instance]?,
87
+ extended_interfaces: Array[Definition::Ancestor::Instance]?) -> void
88
+
89
+ def mixin_ancestors0: (AST::Declarations::Class | AST::Declarations::Module | AST::Declarations::Interface,
90
+ align_params: Substitution?,
91
+ included_modules: Array[Definition::Ancestor::Instance]?,
92
+ included_interfaces:Array[Definition::Ancestor::Instance]?,
93
+ prepended_modules: Array[Definition::Ancestor::Instance]?,
94
+ extended_modules: Array[Definition::Ancestor::Instance]?,
95
+ extended_interfaces: Array[Definition::Ancestor::Instance]?) -> void
96
+ end
97
+ end
98
+ end
@@ -73,8 +73,9 @@ module RBS
73
73
  class Super
74
74
  attr_reader name: TypeName
75
75
  attr_reader args: Array[Types::t]
76
+ attr_reader location: Location?
76
77
 
77
- def initialize: (name: TypeName, args: Array[Types::t]) -> void
78
+ def initialize: (name: TypeName, args: Array[Types::t], location: Location?) -> void
78
79
 
79
80
  include _HashEqual
80
81
  include _ToJson
@@ -130,21 +131,6 @@ module RBS
130
131
  include _ToJson
131
132
  end
132
133
 
133
- class Extension < Base
134
- attr_reader name: TypeName
135
- attr_reader type_params: ModuleTypeParams
136
- attr_reader extension_name: Symbol
137
- attr_reader members: Array[Members::t]
138
- attr_reader annotations: Array[Annotation]
139
- attr_reader location: Location?
140
- attr_reader comment: Comment?
141
-
142
- def initialize: (name: TypeName, type_params: ModuleTypeParams, extension_name: Symbol, members: Array[Members::t], annotations: Array[Annotation], location: Location?, comment: Comment?) -> void
143
-
144
- include _HashEqual
145
- include _ToJson
146
- end
147
-
148
134
  class Interface
149
135
  type member = Members::t
150
136
 
@@ -157,6 +143,8 @@ module RBS
157
143
 
158
144
  def initialize: (name: TypeName, type_params: ModuleTypeParams, members: Array[member], annotations: Array[Annotation], location: Location?, comment: Comment?) -> void
159
145
 
146
+ include MixinHelper
147
+
160
148
  include _HashEqual
161
149
  include _ToJson
162
150
  end