diff --git a/Gemfile.lock b/Gemfile.lock index e6417fd..bcc6cda 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - yard-markdown (0.3.6) + yard-markdown (0.4) csv yard diff --git a/README.md b/README.md index 344a5aa..f7bb130 100644 --- a/README.md +++ b/README.md @@ -31,4 +31,8 @@ This is a successor to [rdoc-mardown gem](https://github.com/skatkov/rdoc-markdo ## Testing Unit tests can't really test this gem properly. So it's semi-manual process of making changes and reviewing output. - `yardoc example.rb` -> outputs everything into example/ folder. +Testing Rdoc conversion to markdown: + `yardoc example_rdoc.rb` -> outputs everything into example/ folder. + +Testing Yard conversion to markdown: + `yardoc example_yard.rb` -> outputs everything into example/ folder. diff --git a/example/Aquatic.md b/example/Aquatic.md new file mode 100644 index 0000000..cfc76e0 --- /dev/null +++ b/example/Aquatic.md @@ -0,0 +1,20 @@ +# Module: Aquatic + +**Defined in:** example_yard.rb + +A mixin for aquatic creatures. + +# Public Instance Methods +## swim() [](#method-i-swim) +Swim in the water. + +**return** [void] + + +# Constants +## DEFAULT_SALMON_SPEED [](#constant-DEFAULT_SALMON_SPEED) + + +## MAX_DEPTH [](#constant-MAX_DEPTH) + + diff --git a/example/Bird.md b/example/Bird.md deleted file mode 100644 index 8ec39ef..0000000 --- a/example/Bird.md +++ /dev/null @@ -1,38 +0,0 @@ -# Class: Bird -**Inherits:** Object - -**Defined in:** example.rb - -The base class for all birds. - -# Public Instance Methods -## _fly_impl(_direction, _velocity) [](#method-i-_fly_impl) -:nodoc: - -## fly(direction, velocity) [](#method-i-fly) -Fly somewhere. - -Flying is the most critical feature of birds. - -:args: direction, velocity - -:call-seq: - Bird.fly(symbol, number) -> bool - Bird.fly(string, number) -> bool - -# Example - - fly(:south, 70) - -## speak() [](#method-i-speak) -Produce some noise. -- FIXME: maybe extract this to a base class `Animal`? ++ - - - -# Constants -## DEFAULT_DUCK_VELOCITY [](#constant-DEFAULT_DUCK_VELOCITY) -Default velocity for a flying duck. - -## DEFAULT_SPEED [](#constant-DEFAULT_SPEED) -Maximum speed for a swimming duck. - diff --git a/example/Duck.md b/example/Duck.md deleted file mode 100644 index 271861e..0000000 --- a/example/Duck.md +++ /dev/null @@ -1,57 +0,0 @@ -# Class: Duck -**Inherits:** Object - -**Extended by:** Animal - -**Includes:** Waterfowl - -**Defined in:** example.rb - -A duck is a Waterfowl Bird. - -Features: - - bird:: - - * speak - * fly - - waterfowl:: - - * swim - -# Public Instance Methods -## initialize(domestic, rubber) [](#method-i-initialize) -Creates a new duck. - -## speak() [](#method-i-speak) -Duck overrides generic implementation. - -## swim() [](#method-i-swim) -Swimming helper. - -## useful?() [](#method-i-useful?) -Checks if this duck is a useful one. - -:call-seq: - Bird.useful? -> bool - - -# Public Class Methods -## rubber_ducks() [](#method-c-rubber_ducks) - -# Attributes -## domestic[RW] [](#attribute-i-domestic) -True for domestic ducks. - -## rubber[RW] [](#attribute-i-rubber) -True for rubber ducks. - - -# Constants -## DEFAULT_DUCK_VELOCITY [](#constant-DEFAULT_DUCK_VELOCITY) -Default velocity for a flying duck. - -## DEFAULT_SPEED [](#constant-DEFAULT_SPEED) -Maximum speed for a swimming duck. - diff --git a/example/Fish.md b/example/Fish.md new file mode 100644 index 0000000..50111fd --- /dev/null +++ b/example/Fish.md @@ -0,0 +1,35 @@ +# Class: Fish +**Inherits:** Object + +**Defined in:** example_yard.rb + +The base class for all fish. + +# Public Instance Methods +## make_sound() [](#method-i-make_sound) +Make a sound. + +**return** [void] +**yield** [sound] The sound produced by the fish +**yieldparam** [String] The actual sound +## swim(direction, speed) [](#method-i-swim) +Swim in a specific direction. + +Swimming is the most critical feature of fish. + +**param** [Symbol, String] The direction to swim +**param** [Integer] The speed at which to swim +**return** [Boolean] Whether the swim was successful + +**example** +```ruby +swim(:north, 30) +``` + +# Constants +## DEFAULT_SALMON_SPEED [](#constant-DEFAULT_SALMON_SPEED) + + +## MAX_DEPTH [](#constant-MAX_DEPTH) + + diff --git a/example/Salmon.md b/example/Salmon.md new file mode 100644 index 0000000..f15b6e9 --- /dev/null +++ b/example/Salmon.md @@ -0,0 +1,58 @@ +# Class: Salmon +**Inherits:** Fish + +**Includes:** Aquatic + +**Defined in:** example_yard.rb + +A salmon is an Aquatic Fish. + +## Features + +* **Fish** + * make_sound + * swim +* **Aquatic** + * swim (overridden) + +# Public Instance Methods +## initialize(farmed, wild) [](#method-i-initialize) +Creates a new salmon. + +**param** [Boolean] Whether the salmon is farmed +**param** [Boolean] Whether the salmon is wild +**return** [Salmon] a new instance of Salmon +## make_sound() [](#method-i-make_sound) +Salmon overrides generic implementation. + +**return** [void] +**yield** [sound] The sound produced by the salmon +**yieldparam** [String] The actual sound +## sustainable?() [](#method-i-sustainable?) +Checks if this salmon is sustainable. + +**return** [Boolean] Whether the salmon is sustainable +## swim() [](#method-i-swim) +Swim in the water. + +**return** [void] + +# Public Class Methods +## wild_salmon() [](#method-c-wild_salmon) +**return** [Array] List of all wild salmon + +# Attributes +## farmed[RW] [](#attribute-i-farmed) + +**return** [Boolean] True for farmed salmon +## wild[RW] [](#attribute-i-wild) + +**return** [Boolean] True for wild salmon + +# Constants +## DEFAULT_SALMON_SPEED [](#constant-DEFAULT_SALMON_SPEED) + + +## MAX_DEPTH [](#constant-MAX_DEPTH) + + diff --git a/example/Waterfowl.md b/example/Waterfowl.md deleted file mode 100644 index 49b4761..0000000 --- a/example/Waterfowl.md +++ /dev/null @@ -1,19 +0,0 @@ -# Module: Waterfowl - -**Defined in:** example.rb - -A mixin for waterfowl creatures. - -# Public Instance Methods -## swim() [](#method-i-swim) -Swimming helper. - - - -# Constants -## DEFAULT_DUCK_VELOCITY [](#constant-DEFAULT_DUCK_VELOCITY) -Default velocity for a flying duck. - -## DEFAULT_SPEED [](#constant-DEFAULT_SPEED) -Maximum speed for a swimming duck. - diff --git a/example/index.csv b/example/index.csv index f94dedd..eb14883 100644 --- a/example/index.csv +++ b/example/index.csv @@ -1,21 +1,20 @@ name,type,path -Waterfowl,Module,Waterfowl.md -Waterfowl#DEFAULT_DUCK_VELOCITY,Constant,Waterfowl.md#constant-DEFAULT_DUCK_VELOCITY -Waterfowl#DEFAULT_SPEED,Constant,Waterfowl.md#constant-DEFAULT_SPEED -Waterfowl.swim,Method,Waterfowl.md#method-i-swim -Bird,Class,Bird.md -Bird#DEFAULT_DUCK_VELOCITY,Constant,Bird.md#constant-DEFAULT_DUCK_VELOCITY -Bird#DEFAULT_SPEED,Constant,Bird.md#constant-DEFAULT_SPEED -Bird._fly_impl,Method,Bird.md#method-i-_fly_impl -Bird.fly,Method,Bird.md#method-i-fly -Bird.speak,Method,Bird.md#method-i-speak -Duck,Class,Duck.md -Duck#DEFAULT_DUCK_VELOCITY,Constant,Duck.md#constant-DEFAULT_DUCK_VELOCITY -Duck#DEFAULT_SPEED,Constant,Duck.md#constant-DEFAULT_SPEED -Duck.initialize,Method,Duck.md#method-i-initialize -Duck.speak,Method,Duck.md#method-i-speak -Duck.swim,Method,Duck.md#method-i-swim -Duck.useful?,Method,Duck.md#method-i-useful? -Duck.rubber_ducks,Method,Duck.md#method-c-rubber_ducks -domestic,Attribute,Duck.md#attribute-i-domestic -rubber,Attribute,Duck.md#attribute-i-rubber +Aquatic,Module,Aquatic.md +Aquatic.DEFAULT_SALMON_SPEED,Constant,Aquatic.md#constant-DEFAULT_SALMON_SPEED +Aquatic.MAX_DEPTH,Constant,Aquatic.md#constant-MAX_DEPTH +Aquatic.swim,Method,Aquatic.md#method-i-swim +Fish,Class,Fish.md +Fish.DEFAULT_SALMON_SPEED,Constant,Fish.md#constant-DEFAULT_SALMON_SPEED +Fish.MAX_DEPTH,Constant,Fish.md#constant-MAX_DEPTH +Fish.make_sound,Method,Fish.md#method-i-make_sound +Fish.swim,Method,Fish.md#method-i-swim +Salmon,Class,Salmon.md +Salmon.DEFAULT_SALMON_SPEED,Constant,Salmon.md#constant-DEFAULT_SALMON_SPEED +Salmon.MAX_DEPTH,Constant,Salmon.md#constant-MAX_DEPTH +Salmon.initialize,Method,Salmon.md#method-i-initialize +Salmon.make_sound,Method,Salmon.md#method-i-make_sound +Salmon.sustainable?,Method,Salmon.md#method-i-sustainable? +Salmon.swim,Method,Salmon.md#method-i-swim +Salmon.wild_salmon,Method,Salmon.md#method-c-wild_salmon +farmed,Attribute,Salmon.md#attribute-i-farmed +wild,Attribute,Salmon.md#attribute-i-wild diff --git a/example.rb b/example_rdoc.rb similarity index 100% rename from example.rb rename to example_rdoc.rb diff --git a/example_yard.rb b/example_yard.rb new file mode 100644 index 0000000..8913a74 --- /dev/null +++ b/example_yard.rb @@ -0,0 +1,154 @@ +# @title YARD Markdown Example +# @description This example demonstrates various YARD features using markdown formatting. +# +# ## Links +# +# 1. [YARD Documentation](https://yardoc.org/) +# 2. [Markdown Syntax](https://daringfireball.net/projects/markdown/syntax) + +# A mixin for aquatic creatures. +module Aquatic + # Swim in the water. + # + # @return [void] + def swim + puts "swimming in the water" + end +end + +# The base class for all fish. +class Fish + # Make a sound. + # + # @yield [sound] The sound produced by the fish + # @yieldparam sound [String] The actual sound + # @return [void] + def make_sound + puts "generic bubbling" + yield "blub" + yield "blub" + end + + # Swim in a specific direction. + # + # Swimming is the most critical feature of fish. + # + # @param direction [Symbol, String] The direction to swim + # @param speed [Integer] The speed at which to swim + # @return [Boolean] Whether the swim was successful + # + # @example + # swim(:north, 30) + def swim(direction, speed) + _swim_impl(direction, speed) + end + + private + + # @!visibility private + def _swim_impl(direction, speed) + puts "swimming away: direction=#{direction}, speed=#{speed}" + end +end + +# A salmon is an Aquatic Fish. +# +# ## Features +# +# - **Fish** +# - make_sound +# - swim +# - **Aquatic** +# - swim (overridden) +class Salmon < Fish + include Aquatic + + # @!group Fish overrides + + # Salmon overrides generic implementation. + # + # @yield [sound] The sound produced by the salmon + # @yieldparam sound [String] The actual sound + # @return [void] + def make_sound + sound = splash + yield sound + end + + # Implements splashing + # + # @return [String] The splash sound + def splash + "splash" + end + + private :splash + + # @!endgroup + + # @!group Salmon specific attributes + + # @return [Boolean] True for farmed salmon + attr_accessor :farmed + + # @return [Boolean] True for wild salmon + attr_reader :wild + + # @return [Integer] Maximum speed for a swimming salmon + MAX_SPEED = 40 + + # @!endgroup + + # Global list of all wild salmon. + # + # Use for conservation efforts. + @@wild_salmon = [] + + # @return [Array] List of all wild salmon + def self.wild_salmon + @@wild_salmon + end + + # Creates a new salmon. + # + # @param farmed [Boolean] Whether the salmon is farmed + # @param wild [Boolean] Whether the salmon is wild + def initialize(farmed, wild) + @farmed = farmed + @wild = wild + @@wild_salmon << self if wild + end + + # Checks if this salmon is sustainable. + # + # @return [Boolean] Whether the salmon is sustainable + def sustainable? + @wild || (@farmed && environmentally_friendly?) + end + + private + + # @return [Boolean] Whether farming practices are environmentally friendly + def environmentally_friendly? + # Implementation details... + true + end +end + +# @!constant [Integer] DEFAULT_SALMON_SPEED +# Default speed for a swimming salmon +DEFAULT_SALMON_SPEED = 20 + +# @!constant [Integer] MAX_DEPTH +# Maximum depth for salmon habitat +MAX_DEPTH = 500 + +# Default wild salmon. +# +# @note Global variables should be used sparingly, but this is for demonstration. +$default_wild_salmon = Salmon.new(false, true) + +# Farmed sustainable salmon. +# +# @note This is just a local variable for demonstration purposes. +farmed_sustainable_salmon = Salmon.new(true, false) diff --git a/templates/default/fulldoc/markdown/setup.rb b/templates/default/fulldoc/markdown/setup.rb index 9f6b351..4a2399e 100644 --- a/templates/default/fulldoc/markdown/setup.rb +++ b/templates/default/fulldoc/markdown/setup.rb @@ -90,6 +90,10 @@ def serialize_index(objects) end end +# @param object [YARD::CodeObjects::Base] +# @return [String] markdown formatted string +# +# @todo Extract template out of setup.rb class. def serialize(object) template = ERB.new( @@ -106,12 +110,14 @@ def serialize(object) <%= rdoc_to_md object.docstring %> +<%= render_tags object %> <% if (insmeths = public_instance_methods(object)).size > 0 %> # Public Instance Methods <% insmeths.each do |item| %> ## <%= item.name(false) %>(<%= item.parameters.map {|p| p.join("") }.join(", ")%>) [](#<%=aref(item)%>) <%= rdoc_to_md item.docstring %> +<%= render_tags item %> <% end %><% end %> <% if (pubmeths = public_class_methods(object)).size > 0 %> @@ -119,6 +125,7 @@ def serialize(object) <% pubmeths.each do |item| %> ## <%= item.name(false) %>(<%= item.parameters.map {|p| p.join(" ") }.join(", ") %>) [](#<%=aref(item)%>) <%= rdoc_to_md item.docstring %> +<%= render_tags item %> <% end %> <% end %> @@ -128,6 +135,7 @@ def serialize(object) ## <%= item.name %><%= item.reader? ? "[RW]" : "[R]" %> [](#<%=aref(item)%>) <%= rdoc_to_md item.docstring %> +<%= render_tags item %> <% end %> <% end %> @@ -138,6 +146,8 @@ def serialize(object) ## <%= cnst.name %> [](#<%=aref(cnst)%>) <%= rdoc_to_md cnst.docstring %> +<%= render_tags cnst %> + <% end %><% end %><% end %>', trim_mode: "<>", ) @@ -147,10 +157,50 @@ def serialize(object) require "rdoc" +## +# Converts rdoc to markdown. +# +# I didn't found a way to detect yard/rdoc docstrings, so we're running docstrings through rdoc to markdown converter in all cases. If it's yard docstring, it doesn't seem to have any negative effect on end results. But absense of bugs, doesn't mean that there are no issues. +# +# @param docstring [String, YARD::Docstring] +# @return [String] markdown formatted string def rdoc_to_md(docstring) RDoc::Markup::ToMarkdown.new.convert(docstring) end +## +# Formats yard tags belonging to a object. +# +# This is mostly a feature of yard and rdoc doesn't have any of that. Rdoc supports ":nodoc:" and other tags. Yard claims to have full support for rdoc, doesn't really handle tags like ":nodoc:" or anything else from rdoc. +# +# There is an attempt to handle @example tag differently, we surround it with a code block. +# +# @see https://rubydoc.info/gems/yard/file/docs/TagsArch.md +# +# @param object [YARD::CodeObjects::Base] +# @return [String] markdown formatted string of Tags + +def render_tags(object) + result = String.new("") + object.tags.each do |tag| + result << if !(tag.tag_name == "example") + "**@#{tag.tag_name}** [#{tag.types&.join(', ')}] #{tag.text}\n" + else + "" + end + end + + object.tags.each do |tag| + result << if (tag.tag_name == "example") + "\n**@#{tag.tag_name}**\n```ruby\n#{tag.text}\n```" + else + "" + end + end + + result +end + def aref(object) if object.type == :constant "constant-#{object.name(false)}" diff --git a/yard-markdown.gemspec b/yard-markdown.gemspec index ba05b3f..1d081de 100644 --- a/yard-markdown.gemspec +++ b/yard-markdown.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |spec| spec.name = "yard-markdown" - spec.version = "0.3.6" + spec.version = "0.4" spec.authors = ["Stanislav (Stas) Katkov"] spec.email = ["yard-markdown@skatkov.com"]