mono-docs: Allow derived classes to have external examples
authorXavi Artigas <xavierartigas@yahoo.es>
Thu, 11 Apr 2019 10:40:21 +0000 (12:40 +0200)
committerShinwoo Kim <cinoo.kim@samsung.com>
Wed, 17 Apr 2019 01:20:03 +0000 (10:20 +0900)
Summary:
You can now have external example files for derived classes (Efl.Ui.Button.SetText)
as well as for base classes (Efl.IText.SetText).
If both files are present, both examples are embedded in the docs. The more
examples the better!

Examples for classes in-between the hierarchy (Efl.Ui.Widget.SetText) are not
picked up. Might be worth examining in the future.

Test Plan:
Create example files for both `Efl.Ui.Button.AutorepeatEnabled.cs` and `Efl.Ui.IAutorepeat.AutorepeatEnabled.cs`.
You should see both examples appearing in the docs.

Reviewers: lauromoura, vitor.sousa

Reviewed By: vitor.sousa

Subscribers: cedric, #reviewers, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D8597

src/bin/eolian_mono/eolian/mono/documentation.hh
src/bin/eolian_mono/eolian/mono/generation_contexts.hh
src/bin/eolian_mono/eolian/mono/klass.hh

index d603e0b..1cea16e 100644 (file)
@@ -313,12 +313,12 @@ struct documentation_generator
    }
 
    template<typename OutputIterator, typename Context>
-   bool generate_tag_example(OutputIterator sink, std::string const& object_name, Context const& context) const
+   bool generate_tag_example(OutputIterator sink, std::string const& full_object_name, Context const& context) const
    {
       auto options = efl::eolian::grammar::context_find_tag<options_context>(context);
       // Example embedding not requested
       if (options.examples_dir.empty()) return true;
-      std::string file_name = options.examples_dir + object_name + ".cs";
+      std::string file_name = options.examples_dir + full_object_name + ".cs";
       std::ifstream exfile(file_name);
       // There is no example file for this class or method, just return
       if (!exfile.good()) return true;
@@ -335,6 +335,24 @@ struct documentation_generator
       return as_generator("\n").generate(sink, attributes::unused, context);
    }
 
+   template<typename OutputIterator, typename Context>
+   bool generate_all_tag_examples(OutputIterator sink, std::string const & full_class_name, std::string const& object_name, Context const& context) const
+   {
+      // Take example from derived class
+      auto derived_klass = efl::eolian::grammar::context_find_tag<class_context>(context);
+      std::string derived_full_name =
+        derived_klass.name.empty() ? object_name : derived_klass.name + "." + object_name;
+      std::string base_full_name =
+        full_class_name.empty() ? object_name : full_class_name + "." + object_name;
+      if (!derived_klass.name.empty())
+        {
+           if (!generate_tag_example(sink, derived_full_name, context)) return false;
+        }
+      if (derived_full_name.compare(base_full_name) == 0) return true;
+      // Take example from base class
+      return generate_tag_example(sink, base_full_name, context);
+   }
+
    // Actual exported generators
    template<typename OutputIterator, typename Attribute, typename Context>
    bool generate(OutputIterator sink, Attribute const& attr, Context const& context) const
@@ -366,9 +384,10 @@ struct documentation_generator
        if (!text.empty())
          if (!generate_tag_value(sink, text, context)) return false;
 
-       std::string managed_name = name_helpers::klass_full_concrete_or_interface_name(prop.klass);
-       managed_name += "." + name_helpers::property_managed_name(prop);
-       return generate_tag_example(sink, managed_name, context);
+       return generate_all_tag_examples(sink,
+                                        name_helpers::klass_full_concrete_or_interface_name(prop.klass),
+                                        name_helpers::property_managed_name(prop),
+                                        context);
    }
 
    template<typename OutputIterator, typename Context>
@@ -404,7 +423,10 @@ struct documentation_generator
        if (!generate_tag_return(sink, func.return_documentation.full_text, context))
          return false;
 
-       return generate_tag_example(sink, function_conversion(func), context);
+       return generate_all_tag_examples(sink,
+                                        name_helpers::klass_full_concrete_or_interface_name(func.klass),
+                                        name_helpers::managed_method_name(func.klass.eolian_name, func.name),
+                                        context);
    }
 
    template<typename OutputIterator, typename Context>
@@ -420,7 +442,10 @@ struct documentation_generator
        if (!generate_tag_return(sink, func.return_documentation.full_text, context))
          return false;
 
-       return generate_tag_example(sink, function_conversion(func), context);
+       return generate_all_tag_examples(sink,
+                                        name_helpers::klass_full_concrete_or_interface_name(func.klass),
+                                        name_helpers::managed_method_name(func.klass.eolian_name, func.name),
+                                        context);
    }
 
    template<typename OutputIterator, typename Context>
index ff6c039..dc72696 100644 (file)
@@ -20,6 +20,7 @@ struct class_context
         variables,
     };
     wrapper_kind current_wrapper_kind;
+    std::string name;
 };
 
 struct indentation_context
index 87ad1bd..4664446 100644 (file)
@@ -117,7 +117,9 @@ struct klass
      // Interface class
      if(class_type == "interface")
      {
-       auto iface_cxt = context_add_tag(class_context{class_context::interface}, context);
+       auto iface_cxt = context_add_tag(class_context{class_context::interface,
+                                        name_helpers::klass_full_concrete_or_interface_name(cls)},
+                                        context);
 
        if(!as_generator(documentation).generate(sink, cls, iface_cxt))
          return false;
@@ -195,7 +197,9 @@ struct klass
      // Concrete class for interfaces, mixins, etc.
      if(class_type != "class" && class_type != "abstract class")
        {
-         auto concrete_cxt = context_add_tag(class_context{class_context::concrete}, context);
+         auto concrete_cxt = context_add_tag(class_context{class_context::concrete,
+                                             name_helpers::klass_full_concrete_or_interface_name(cls)},
+                                             context);
          auto concrete_name = name_helpers::klass_concrete_name(cls);
          auto interface_name = name_helpers::klass_interface_name(cls);
 
@@ -277,7 +281,9 @@ struct klass
      // Inheritable class
      if(class_type == "class" || class_type == "abstract class")
        {
-        auto inherit_cxt = context_add_tag(class_context{class_context::inherit}, context);
+        auto inherit_cxt = context_add_tag(class_context{class_context::inherit,
+                                           name_helpers::klass_full_concrete_or_interface_name(cls)},
+                                           context);
 
         // Class header
         if(!as_generator
@@ -351,7 +357,9 @@ struct klass
      // Native Inherit class
      //if(class_type == "class")
        {
-         auto inative_cxt = context_add_tag(class_context{class_context::inherit_native}, context);
+         auto inative_cxt = context_add_tag(class_context{class_context::inherit_native,
+                                            name_helpers::klass_full_concrete_or_interface_name(cls)},
+                                            context);
          auto native_inherit_name = name_helpers::klass_native_inherit_name(cls);
          auto inherit_name = name_helpers::klass_inherit_name(cls);
          std::string base_name;