diff --git a/lib/yard/autoload.rb b/lib/yard/autoload.rb index d00371c64..9c3caf164 100644 --- a/lib/yard/autoload.rb +++ b/lib/yard/autoload.rb @@ -78,6 +78,7 @@ module C autoload :AttributeHandler, __p('handlers/c/attribute_handler') autoload :ClassHandler, __p('handlers/c/class_handler') autoload :ConstantHandler, __p('handlers/c/constant_handler') + autoload :DirectiveParserHandler, __p('handlers/c/directive_parser_handler') autoload :HandlerMethods, __p('handlers/c/handler_methods') autoload :InitHandler, __p('handlers/c/init_handler') autoload :MethodHandler, __p('handlers/c/method_handler') diff --git a/lib/yard/handlers/c/directive_parser_handler.rb b/lib/yard/handlers/c/directive_parser_handler.rb new file mode 100644 index 000000000..535c4b82e --- /dev/null +++ b/lib/yard/handlers/c/directive_parser_handler.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true +class YARD::Handlers::C::DirectiveParserHandler < YARD::Handlers::C::Base + handles(/./) + statement_class Comment + + process do + Docstring.parser.parse(statement.source, namespace, self) + end +end diff --git a/lib/yard/parser/c/c_parser.rb b/lib/yard/parser/c/c_parser.rb index 8518d811e..c8f09799c 100644 --- a/lib/yard/parser/c/c_parser.rb +++ b/lib/yard/parser/c/c_parser.rb @@ -97,7 +97,14 @@ def consume_body_statements stmts = [] brace_level = 1 loop do - strip_non_statement_data + # Need to include the @! directive tags for them to be processed + # along with the body statement content. + # (At least the @!group directive.) + directive_tags = capture_directive_tags_hack do + strip_non_statement_data + end + stmts.concat(directive_tags) + start = @index line = @line consume_until(/[{};]/) @@ -115,6 +122,15 @@ def consume_body_statements stmts end + def capture_directive_tags_hack + temp = @statements.dup + yield if block_given? + stmts = (@statements - temp) + stmts.select do |stmt| + stmt.is_a?(Comment) && stmt.source.start_with?('@!') + end + end + def strip_non_statement_data start = @index loop do diff --git a/spec/parser/c_parser_spec.rb b/spec/parser/c_parser_spec.rb index bf11e7382..7c423c3d9 100755 --- a/spec/parser/c_parser_spec.rb +++ b/spec/parser/c_parser_spec.rb @@ -125,6 +125,44 @@ def parse(contents) end end + describe "Group directives" do + it "groups constants" do + parse <<-eof + void Init_Mask(void) + { + rb_cExample = rb_define_class("Example", rb_cObject); + + // @!group Foos + + /* 1: Foobar description. */ + rb_define_const(rb_cExample, "FOOBAR", INT2NUM(1)); + + /* 2: Foobiz description. */ + rb_define_const(rb_cExample, "FOOBIZ", INT2NUM(2)); + + // @!endgroup + + /* 3: Hello description. */ + rb_define_const(rb_cExample, "HELLO", INT2NUM(3)); + } + eof + constant = Registry.at('Example::FOOBAR') + expect(constant.value).to eq '1' + expect(constant.docstring).to eq "Foobar description." + expect(constant.group).to eq "Foos" + + constant = Registry.at('Example::FOOBIZ') + expect(constant.value).to eq '2' + expect(constant.docstring).to eq "Foobiz description." + expect(constant.group).to eq "Foos" + + constant = Registry.at('Example::HELLO') + expect(constant.value).to eq '3' + expect(constant.docstring).to eq "Hello description." + expect(constant.group).to eq nil + end + end + describe "Macros" do it "handles param## inside of macros" do thr = Thread.new do diff --git a/spec/parser/ruby/ruby_parser_spec.rb b/spec/parser/ruby/ruby_parser_spec.rb index 2ba9006f8..646597726 100644 --- a/spec/parser/ruby/ruby_parser_spec.rb +++ b/spec/parser/ruby/ruby_parser_spec.rb @@ -504,5 +504,38 @@ def bar; end if true it "handles compile errors" do expect { stmt(":~$ Do not clobber") }.to raise_error(Parser::ParserSyntaxError) end + + it "groups constants" do + YARD.parse_string <<-eof + class Example + # @!group Foos + + # Foobar description. + FOOBAR = 1 + + # Foobiz description. + FOOBIZ = 2 + + # @!endgroup + + # Hello description. + HELLO = 3 + end + eof + constant = Registry.at('Example::FOOBAR') + expect(constant.value).to eq '1' + expect(constant.docstring).to eq "Foobar description." + expect(constant.group).to eq "Foos" + + constant = Registry.at('Example::FOOBIZ') + expect(constant.value).to eq '2' + expect(constant.docstring).to eq "Foobiz description." + expect(constant.group).to eq "Foos" + + constant = Registry.at('Example::HELLO') + expect(constant.value).to eq '3' + expect(constant.docstring).to eq "Hello description." + expect(constant.group).to eq nil + end end end if HAVE_RIPPER