Port of Menu & Menu editor to ElementTree #4
Conversation
I'll need to take a while to go through all that. I'm glad we opted to do it as a second pull request. No, I don't have any code that uses MenuEditor, and I'm not aware of any. That's pretty much why it has no tests, and why it still uses |
I'm on the process of porting the gtk menu editor found in the gnome-menus package to pyxdg for my project uxdgmenu, so I might be able to write tests along the way, and maybe add a few features when I need them. |
There's another important thing I want to fix: the parsing methods are incoherent since some of them return an object created from the parsed node, whereas some of them have side-effects (like creating an object and adding it to it's parent). We would then have a clean public API: # parses a menu file
# returns xdg.Menu.Menu
Parser.parse(filename)
# parses a <Menu> element
# returns xdg.Menu.Menu
Parser.parse_menu(node)
# parses a <Layout> element
# returns xdg.Menu.Layout
Parser.parse_layout(node)
# parses a <Move> element
# returns xdg.Menu.Move
Parser.parse_move(node)
# parses a <Rule> element
# returns xdg.Menu.Rule
Parser.parse_rule(node)
# parses a <Separator> element
# returns xdg.Menu.Separator
Parser.parse_separator(node) , the rest being internal only. |
I'm not entirely comfortable with creating I think I'd be inclined to have parsing code as straightforward functions, which extract the relevant details and return Python objects, without side effects, so they're easy to test. I haven't examined the menu system in detail, though, so I'm ready to hear counterproposals. |
Yes it is. Look at the # parse menufile
self.root = None
self._merged_files = set()
self._directory_dirs = set()
self.cache = MenuEntryCache() these are instance variables that store parsing state. This state was previously stored in a module global dict called Furthermore, using a class allows to easily switch parsing mode, for example a strict mode in which every parsing error raises an Exception and a normal mode in which the parser tries to recover as much data as it can, etc...
Well technically, the real parser here is the ElementTree parser. Our So the discussion is really about the few methods that deal with sorting, handling moves, not_only_allocated, etc... This will become clearer to me when I've worked more with the MenuEditor... Btw, thanks for taking time to review all of this! ;-) |
Isn't e.g. (Aside: the XML structure and our Menu instance aren't ASTs. An Abstract Syntax Tree represents the structure of a computer program. We build up an AST specifically for the rule, which can be treated as a computable expression. The menu structure is just a tree.) What's the concern with adding logic to classes that are instantiated a lot of times? As far as I know, it should have a speed or memory cost - the method is only bound when you access it ( |
OK, having had another look at this, I'm coming round to the idea of a class, but there are still some changes I think it needs:
|
And now, for instance, |
Thanks. I'm just testing this, but I see a test failure, both on Python 2.7 and 3.2:
It looks like it might work with Also, any thoughts on renaming the Parser class to something like XMLMenuBuilder? |
I tried that fix, it did work, so I've made a pull request against your pull request ;-) |
Minor fixes to xdg.Menu
Any thoughts on the class name? I'm leaning towards |
Alright, I'm going to merge this and rename the class to XMLMenuBuilder. Thanks @ju1ius. |
Port of Menu & Menu editor to ElementTree
And also some refactoring of the Menu parsing methods: parsing is now done by the xdg.Menu.Parser.parse() method. The xdg.Menu.parse() function is left as a shortcut.
All Menu classes are freed from the parsing job.
There are no unit tests for the MenuEditor class... Do you have some code I could use to test against (and turn to proper unit test while I'm at it) ?