-
-
Notifications
You must be signed in to change notification settings - Fork 199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make the code more understandable #236
Comments
For me the most difficult part was math_nodes = collections.namedtuple("MathNodes", ["displaymath"])
math_nodes.displaymath = sphinx.ext.mathbase.displaymath
node_factory = NodeFactory(docutils.nodes, sphinx.addnodes, math_nodes)
rst_content_creator = RstContentCreator(ViewList, textwrap.dedent)
renderer_factory_creator_constructor = DoxygenToRstRendererFactoryCreatorConstructor(
node_factory,
parser_factory,
DomainDirectiveFactory,
rst_content_creator
) |
Ha, ridiculous name eh? I am very happy to try to get rid of it. Though that class itself does very little so is it more than whole DoxygenToRstRenderer stack that you'd like to see improved or you just want to be free of that one class? |
Name kind of makes sense if you are familiar with musical terminology like hemidemisemiquavers =). I'd go with simplifying this chain of factories first if possible. Currently it looks like all the callers use the same pattern: renderer_factory_creator = self.renderer_factory_creator_constructor.create_factory_creator(
project_info,
self.state.document,
target_handler
)
try:
renderer_factory = renderer_factory_creator.create_factory(
node_stack,
self.state,
self.state.document,
filter_,
target_handler,
)
except ParserError as e:
return format_parser_error("doxygenclass", e.error, e.filename, self.state,
self.lineno, True)
except FileIOError as e:
return format_parser_error("doxygenclass", e.error, e.filename, self.state, self.lineno)
context = RenderContext(node_stack, mask_factory, directive_args)
object_renderer = renderer_factory.create_renderer(context) Since all three levels of creation happen together, perhaps this chain of factories can be collapsed. |
That's interesting. I'll give it some thought. I've made some progress getting rid of some stuff. I'll push in a bit I hope. |
Tried to refactor it. Turns out it wasn't being used. For #236
I really got lost along the way somewhere. For #236.
Import and use ViewList & textwrap directly instead of going through a layer of indirection. I initially did stuff like this out of a belief that it made it more testable as it was easy to mock out the stuff being passed in. However I haven't written any tests and even if I did, I wouldn't mock 'dedent'. For #236
Not sure why we have it. Doesn't appear to be used again. For #236.
Not at the top followed by passing it all the way down to where it is needed. For #236.
Instead of creating it at the top and passing it all the way down. This does mean that we have a lot of NodeFactory instances but they are light weight so nothing to be worried about. For #236.
Instead of passing it down from the top. Reduces the need for the intermediate factories which we'll hopefully eliminate at some point. For #236.
I assume it has been fixed on the Sphinx side a long time ago. It was reported a long time ago anyway. For #236.
Like the others. Might as well have it close to where it is used. Unlikely to want to replace it for testing purposes and it avoid all the intermediate passing around. For #236.
To clean them up as they don't seem to be being used. For #236.
It never did much and we've already removed most of the things it helped pass on. Here we remove it completely and inline the construction of the subfactory directly as we always have the parser_factory when we want to build it. For #236.
@michaeljones, great job with refactoring! I have another idea that I want to discuss with you before starting any development. The idea is to apply the visitor pattern to renderers. To be more specific, I suggest introducing a Doxygen node visitor class: class DoxygenVisitor:
def visit_function(self, node):
pass # called on memberdef node of function kind
def visit_typedef(self, node):
pass # called on memberdef node of typedef kind
... and using it to implement the Sphinx/RST renderer: class SphinxRenderer(DoxygenVisitor):
def visit_function(self, node):
# renders Doxygen function node using Sphinx function directive from the current domain
def visit_typedef(self, node):
... I think this will simplify the code because all the shared state that currently needs to be passed through
This could also improve performance because we won't be creating many What do you think? |
That sounds really promising. I'd be really interested to see that. I'm happy with the little progress I made trying to cull stuff and clean up a bit, but the code is so familiar and such a representation of how I've been thinking about Breathe throughout the project that I really struggle to imagine fundamentally different ways to approach it. We definitely need to shake it up a bit to have a better go at making it a more approachable code base. Please go for it and let me know if I can help. Though I suspect such things are tricky to share. Happy to help if I can though. |
Tried to refactor it. Turns out it wasn't being used. For #236
I really got lost along the way somewhere. For #236.
Import and use ViewList & textwrap directly instead of going through a layer of indirection. I initially did stuff like this out of a belief that it made it more testable as it was easy to mock out the stuff being passed in. However I haven't written any tests and even if I did, I wouldn't mock 'dedent'. For #236
Not sure why we have it. Doesn't appear to be used again. For #236.
Not at the top followed by passing it all the way down to where it is needed. For #236.
Instead of creating it at the top and passing it all the way down. This does mean that we have a lot of NodeFactory instances but they are light weight so nothing to be worried about. For #236.
Instead of passing it down from the top. Reduces the need for the intermediate factories which we'll hopefully eliminate at some point. For #236.
I assume it has been fixed on the Sphinx side a long time ago. It was reported a long time ago anyway. For #236.
Like the others. Might as well have it close to where it is used. Unlikely to want to replace it for testing purposes and it avoid all the intermediate passing around. For #236.
To clean them up as they don't seem to be being used. For #236.
It never did much and we've already removed most of the things it helped pass on. Here we remove it completely and inline the construction of the subfactory directly as we always have the parser_factory when we want to build it. For #236.
I have come to accept that the code is unnecessarily complex to understand. I now realise it could be much more readable and approachable. I have defended it in the past but it must be possible to make it better.
I hope that by improving it we might get more contributions from people who are interested but currently turned off by the state of the code. This would definitely help the project as I don't find much time to work on it and move it forward.
Broadly, I will try to reduce the number of factories being used and have less dependency injection. The dependency injection was mostly designed to make the code more testable but I have never written tests to take advantage of that so it is just a cost to readability at the moment.
I would love some input to help identify particularly difficult parts of the code or to propose improvements. I am keen to improve it now but not entirely sure how to start. But I will try :)
The text was updated successfully, but these errors were encountered: