- <%= klass.type %> <%= klass.full_name %> + <%= klass.type %> <%= klass.full_name + (klass.type_parameters_to_s ? " #{klass.type_parameters_to_s}" : "") %>

diff --git a/lib/rdoc/parser/ruby.rb b/lib/rdoc/parser/ruby.rb index 85f1cd0391..97dea96f85 100644 --- a/lib/rdoc/parser/ruby.rb +++ b/lib/rdoc/parser/ruby.rb @@ -901,6 +901,33 @@ def parse_class_regular container, declaration_context, single, # :nodoc: read_documentation_modifiers cls, RDoc::CLASS_MODIFIERS record_location cls + if comment.text =~ /^#(\W)*:type-params:$/ + all_lines = comment.text.lines + non_param_lines = all_lines.take_while { |line| line !~ /^#(\W)*:type-params:$/ } + param_lines = all_lines.drop(non_param_lines.size).drop(1).take_while { |line| line !~ /^#\W*$/ } + comment.text = non_param_lines.join("\n") + cls.type_parameters = param_lines.map do |type_param_line| + type_params = type_param_line.gsub(/^#/, '').gsub(/\n$/, '').lstrip.split(" ") + type_param_hash = { name: nil, variance: :invariant, unchecked: false, upper_bound: nil } + type_params.each_with_index do |type_param, i| + case type_param + when "unchecked" + type_param_hash[:unchecked] = true + when "in" + type_param_hash[:variance] = :contravariant + when "out" + type_param_hash[:variance] = :covariant + when "<" + type_param_hash[:upper_bound] = type_params[i + 1] + break + else + type_param_hash[:name] = type_param + end + end + RDoc::TypeParameter.new(*type_param_hash.values) + end + end + cls.add_comment comment, @top_level @top_level.add_to_classes_or_modules cls @@ -1713,6 +1740,34 @@ def parse_module container, single, tk, comment record_location mod read_documentation_modifiers mod, RDoc::CLASS_MODIFIERS + + if comment.text =~ /^#(\W)*:type-params:$/ + all_lines = comment.text.lines + non_param_lines = all_lines.take_while { |line| line !~ /^#(\W)*:type-params:$/ } + param_lines = all_lines.drop(non_param_lines.size).drop(1).take_while { |line| line !~ /^#\W*$/ } + comment.text = non_param_lines.join("\n") + mod.type_parameters = param_lines.map do |type_param_line| + type_params = type_param_line.gsub(/^#/, '').gsub(/\n$/, '').lstrip.split(" ") + type_param_hash = { name: nil, variance: :invariant, unchecked: false, upper_bound: nil } + type_params.each_with_index do |type_param, i| + case type_param + when "unchecked" + type_param_hash[:unchecked] = true + when "in" + type_param_hash[:variance] = :contravariant + when "out" + type_param_hash[:variance] = :covariant + when "<" + type_param_hash[:upper_bound] = type_params[i + 1] + break + else + type_param_hash[:name] = type_param + end + end + RDoc::TypeParameter.new(*type_param_hash.values) + end + end + mod.add_comment comment, @top_level parse_statements mod diff --git a/lib/rdoc/type_parameter.rb b/lib/rdoc/type_parameter.rb new file mode 100644 index 0000000000..c0e05b81cf --- /dev/null +++ b/lib/rdoc/type_parameter.rb @@ -0,0 +1,51 @@ +module RDoc + class TypeParameter < CodeObject + attr_reader :name, :variance, :unchecked, :upper_bound + + def initialize(name, variance, unchecked = false, upper_bound = nil) + @name = name + @variance = variance + @unchecked = unchecked + @upper_bound = upper_bound + end + + def ==(other) + other.is_a?(TypeParameter) && + self.name == other.name && + self.variance == other.variance && + self.unchecked == other.unchecked && + self.upper_bound == other.upper_bound + end + + alias eql? == + + def unchecked? + unchecked + end + + def to_s + s = "" + + if unchecked? + s << "unchecked " + end + + case variance + when :invariant + # nop + when :covariant + s << "out " + when :contravariant + s << "in " + end + + s << name.to_s + + if type = upper_bound + s << " < #{type}" + end + + s + end + end +end diff --git a/test/rdoc/test_rdoc_generator_darkfish.rb b/test/rdoc/test_rdoc_generator_darkfish.rb index 96319bb4f7..8bb64a59a8 100644 --- a/test/rdoc/test_rdoc_generator_darkfish.rb +++ b/test/rdoc/test_rdoc_generator_darkfish.rb @@ -322,6 +322,36 @@ def test_title_escape assert_main_title(File.binread('index.html'), title) end + def test_generate_type_param + top_level = @store.add_file 'file.rb' + type_parameters = [ + RDoc::TypeParameter.new("Elem", :invariant, true, "Integer") + ] + top_level.add_class @klass.class, @klass.name, nil, type_parameters + + @g.generate + + assert_file @klass.name + ".html" + + assert_include File.read(@klass.name + ".html"), %Q[\[unchecked Elem < Integer\]] + end + + def test_generate_type_params + top_level = @store.add_file 'file.rb' + type_parameters = [ + RDoc::TypeParameter.new("Elem", :invariant, true, "Integer"), + RDoc::TypeParameter.new("T", :covariant, false, "String"), + RDoc::TypeParameter.new("A", :contravariant, true, "Object") + ] + top_level.add_class @klass.class, @klass.name, nil, type_parameters + + @g.generate + + assert_file @klass.name + ".html" + + assert_include File.read(@klass.name + ".html"), %Q[\[unchecked Elem < Integer, out T < String, unchecked in A < Object\]] + end + ## # Asserts that +filename+ has a link count greater than 1 if hard links to # @tmpdir are supported. diff --git a/test/rdoc/test_rdoc_parser_ruby.rb b/test/rdoc/test_rdoc_parser_ruby.rb index 3e2a85ffba..19ee4a37d9 100644 --- a/test/rdoc/test_rdoc_parser_ruby.rb +++ b/test/rdoc/test_rdoc_parser_ruby.rb @@ -739,6 +739,34 @@ def test_parse_class assert_equal 1, foo.line end + def test_parse_class_generic + comment = RDoc::Comment.new <<-COMMENT, @top_level, :ruby +## +# my class +# :type-params: +# out KEY < Integer +# unchecked in VALUE < String +# X +# + COMMENT + + util_parser "class Foo\nend" + + tk = @parser.get_tk + + @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + type_parameters = [ + RDoc::TypeParameter.new("KEY", :covariant, false, "Integer"), + RDoc::TypeParameter.new("VALUE", :contravariant, true, "String"), + RDoc::TypeParameter.new("X", :invariant, false) + ] + foo = @top_level.classes.first + assert_equal 'Foo', foo.full_name + assert_equal 'my class', foo.comment.text + assert_equal type_parameters, foo.type_parameters + end + def test_parse_class_singleton comment = RDoc::Comment.new "##\n# my class\n", @top_level @@ -1027,6 +1055,34 @@ def test_parse_module assert_equal 'my module', foo.comment.text end + def test_parse_module_generic + comment = RDoc::Comment.new <<-COMMENT, @top_level, :ruby +## +# my module +# :type-params: +# out KEY < Integer +# unchecked in VALUE < String +# X +# + COMMENT + + util_parser "module Foo\nend" + + tk = @parser.get_tk + + @parser.parse_module @top_level, RDoc::Parser::Ruby::NORMAL, tk, comment + + type_parameters = [ + RDoc::TypeParameter.new("KEY", :covariant, false, "Integer"), + RDoc::TypeParameter.new("VALUE", :contravariant, true, "String"), + RDoc::TypeParameter.new("X", :invariant, false) + ] + foo = @top_level.modules.first + assert_equal 'Foo', foo.full_name + assert_equal 'my module', foo.comment.text + assert_equal type_parameters, foo.type_parameters + end + def test_parse_module_nodoc @top_level.stop_doc From 4bf209ee8556f9729a477e49a1ad23da5726e37f Mon Sep 17 00:00:00 2001 From: Sushanth Sathesh Rao <57192414+raosush@users.noreply.github.com> Date: Sun, 11 Sep 2022 21:51:15 +0530 Subject: [PATCH 2/4] Marshal: Load, dump for TypeParameter --- lib/rdoc/type_parameter.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/rdoc/type_parameter.rb b/lib/rdoc/type_parameter.rb index c0e05b81cf..692b33b5cc 100644 --- a/lib/rdoc/type_parameter.rb +++ b/lib/rdoc/type_parameter.rb @@ -2,6 +2,8 @@ module RDoc class TypeParameter < CodeObject attr_reader :name, :variance, :unchecked, :upper_bound + MARSHAL_VERSION = 3 # :nodoc: + def initialize(name, variance, unchecked = false, upper_bound = nil) @name = name @variance = variance @@ -9,6 +11,23 @@ def initialize(name, variance, unchecked = false, upper_bound = nil) @upper_bound = upper_bound end + def marshal_load(array) + @name = array[1] + @variance = array[2] + @unchecked = array[3] + @upper_bound = array[4] + end + + def marshal_dump + [ + MARSHAL_VERSION, + @name, + @variance, + @unchecked, + @upper_bound + ] + end + def ==(other) other.is_a?(TypeParameter) && self.name == other.name && From a727f09473472d303445a85897f8fe621ea39e5e Mon Sep 17 00:00:00 2001 From: Sushanth Sathesh Rao <57192414+raosush@users.noreply.github.com> Date: Tue, 13 Sep 2022 19:27:36 +0530 Subject: [PATCH 3/4] Marshal: Support type parameters for classes_modules --- lib/rdoc/class_module.rb | 5 +++-- lib/rdoc/type_parameter.rb | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/rdoc/class_module.rb b/lib/rdoc/class_module.rb index 58d19ccefb..fde4c92250 100644 --- a/lib/rdoc/class_module.rb +++ b/lib/rdoc/class_module.rb @@ -342,8 +342,8 @@ def marshal_dump # :nodoc: tl.relative_name end, parent.full_name, - parent.class, - ] + parent.class + ].concat(type_parameters) end def marshal_load array # :nodoc: @@ -428,6 +428,7 @@ def marshal_load array # :nodoc: @parent_name = array[12] @parent_class = array[13] + @type_parameters = array[14] if array[14] end ## diff --git a/lib/rdoc/type_parameter.rb b/lib/rdoc/type_parameter.rb index 692b33b5cc..d0583e5c92 100644 --- a/lib/rdoc/type_parameter.rb +++ b/lib/rdoc/type_parameter.rb @@ -2,7 +2,7 @@ module RDoc class TypeParameter < CodeObject attr_reader :name, :variance, :unchecked, :upper_bound - MARSHAL_VERSION = 3 # :nodoc: + MARSHAL_VERSION = 0 # :nodoc: def initialize(name, variance, unchecked = false, upper_bound = nil) @name = name From a45de1808d366fea58b47c65385d96f64e53c4fd Mon Sep 17 00:00:00 2001 From: Sushanth Sathesh Rao <57192414+raosush@users.noreply.github.com> Date: Thu, 13 Jul 2023 08:30:34 +0530 Subject: [PATCH 4/4] Remove ruby-version --- .ruby-version | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .ruby-version diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index fd2a01863f..0000000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -3.1.0