--- a/compare_locales/parser.py
+++ b/compare_locales/parser.py
@@ -453,29 +453,78 @@ class DefinesParser(Parser):
self.reKey = re.compile('^(\s*)'
'(#define[ \t]+(\w+)[ \t]+(.*?))([ \t]*$\n?)',
re.M)
self.reHeader = re.compile('^\s*(#(?!define\s).*\s*)*')
self.reFooter = re.compile('\s*(#(?!define\s).*\s*)*$', re.M)
Parser.__init__(self)
+class IniSection(Entity):
+ '''Entity-like object representing sections in ini files
+ '''
+ def __init__(self, ctx, span, pre_ws_span, def_span, val_span, post_span):
+ self.ctx = ctx
+ self.span = span
+ self.pre_ws_span = pre_ws_span
+ self.def_span = def_span
+ self.key_span = self.val_span = val_span
+ self.post_span = post_span
+ self.pp = lambda v: v
+
+ def __repr__(self):
+ return self.raw_val
+
+
class IniParser(Parser):
'''
Parse files of the form:
# initial comment
[cat]
whitespace*
#comment
string=value
...
'''
def __init__(self):
- self.reHeader = re.compile('^((?:\s*|[;#].*)\n)*\[.+?\]\n', re.M)
- self.reKey = re.compile('(\s*)((?:[;#].*\n\s*)*)((.+?)=(.*))(\n?)')
+ self.reComment = re.compile(
+ '((?:[ \t]*\n)*)'
+ '((?:^[;#].*?(?:\n|\Z))+)'
+ '((?:[ \t]*(?:\n|\Z))*)', re.M)
+ self.reSection = re.compile(
+ '((?:[ \t]*\n)*)'
+ '(\[(.*?)\])'
+ '((?:[ \t]*(?:\n|\Z))*)', re.M)
+ self.reKey = re.compile(
+ '((?:[ \t]*\n)*)'
+ '((.+?)=(.*))'
+ '((?:[ \t]*(?:\n|\Z))*)', re.M)
self.reFooter = re.compile('\s*([;#].*\s*)*$')
Parser.__init__(self)
+ def getEntity(self, ctx, offset):
+ contents = ctx.contents
+ m = self.reComment.match(contents, offset)
+ if m:
+ offset = m.end()
+ return (Comment(ctx, *[m.span(i) for i in xrange(4)]), offset)
+ m = self.reSection.match(contents, offset)
+ if m:
+ offset = m.end()
+ return (IniSection(ctx, *[m.span(i) for i in xrange(5)]), offset)
+ m = self.reKey.match(contents, offset)
+ if m:
+ offset = m.end()
+ return (self.createEntity(ctx, m), offset)
+ junkend = None
+ for exp in (self.reComment, self.reSection, self.reKey):
+ m = exp.search(contents, offset)
+ if m:
+ junkend = min(junkend, m.start(1)) if junkend else m.start()
+ if junkend is not None:
+ return (Junk(ctx, (offset, junkend)), junkend)
+ return (None, offset)
+
__constructors = [('\\.dtd$', DTDParser()),
('\\.properties$', PropertiesParser()),
('\\.ini$', IniParser()),
('\\.inc$', DefinesParser())]
--- a/compare_locales/tests/test_ini.py
+++ b/compare_locales/tests/test_ini.py
@@ -18,98 +18,116 @@ mpl2 = '''\
class TestIniParser(ParserTestMixin, unittest.TestCase):
filename = 'foo.ini'
def testSimpleHeader(self):
self._test('''; This file is in the UTF-8 encoding
[Strings]
TitleText=Some Title
-''', (('TitleText', 'Some Title'),))
- self.assert_('UTF-8' in self.parser.header)
+''', (
+ ('Comment', 'UTF-8 encoding'),
+ ('IniSection', 'Strings'),
+ ('TitleText', 'Some Title'),))
def testMPL2_Space_UTF(self):
self._test(mpl2 + '''
; This file is in the UTF-8 encoding
[Strings]
TitleText=Some Title
-''', (('TitleText', 'Some Title'),))
- self.assert_('MPL' in self.parser.header)
+''', (
+ ('Comment', mpl2),
+ ('Comment', 'UTF-8'),
+ ('IniSection', 'Strings'),
+ ('TitleText', 'Some Title'),))
def testMPL2_Space(self):
self._test(mpl2 + '''
[Strings]
TitleText=Some Title
-''', (('TitleText', 'Some Title'),))
- self.assert_('MPL' in self.parser.header)
+''', (
+ ('Comment', mpl2),
+ ('IniSection', 'Strings'),
+ ('TitleText', 'Some Title'),))
def testMPL2_MultiSpace(self):
self._test(mpl2 + '''\
; more comments
[Strings]
TitleText=Some Title
-''', (('TitleText', 'Some Title'),))
- self.assert_('MPL' in self.parser.header)
+''', (
+ ('Comment', mpl2),
+ ('Comment', 'more comments'),
+ ('IniSection', 'Strings'),
+ ('TitleText', 'Some Title'),))
def testMPL2_JunkBeforeCategory(self):
self._test(mpl2 + '''\
Junk
[Strings]
TitleText=Some Title
-''', (('Junk', mpl2 + '''\
-Junk
-[Strings]'''), ('TitleText', 'Some Title')))
- self.assert_('MPL' not in self.parser.header)
+''', (
+ ('Comment', mpl2),
+ ('Junk', 'Junk'),
+ ('IniSection', 'Strings'),
+ ('TitleText', 'Some Title')))
def test_TrailingComment(self):
self._test(mpl2 + '''
[Strings]
TitleText=Some Title
;Stray trailing comment
-''', (('TitleText', 'Some Title'),))
- self.assert_('MPL' in self.parser.header)
+''', (
+ ('Comment', mpl2),
+ ('IniSection', 'Strings'),
+ ('TitleText', 'Some Title'),
+ ('Comment', 'Stray trailing')))
def test_SpacedTrailingComments(self):
self._test(mpl2 + '''
[Strings]
TitleText=Some Title
;Stray trailing comment
;Second stray comment
-''', (('TitleText', 'Some Title'),))
- self.assert_('MPL' in self.parser.header)
+''', (
+ ('Comment', mpl2),
+ ('IniSection', 'Strings'),
+ ('TitleText', 'Some Title'),
+ ('Comment', 'Second stray comment')))
def test_TrailingCommentsAndJunk(self):
self._test(mpl2 + '''
[Strings]
TitleText=Some Title
;Stray trailing comment
Junk
;Second stray comment
-''', (('TitleText', 'Some Title'), ('Junk', '''\
-
-;Stray trailing comment
-Junk
-;Second stray comment
-
-''')))
- self.assert_('MPL' in self.parser.header)
+''', (
+ ('Comment', mpl2),
+ ('IniSection', 'Strings'),
+ ('TitleText', 'Some Title'),
+ ('Comment', 'Stray trailing'),
+ ('Junk', 'Junk'),
+ ('Comment', 'Second stray comment')))
def test_JunkInbetweenEntries(self):
self._test(mpl2 + '''
[Strings]
TitleText=Some Title
Junk
Good=other string
-''', (('TitleText', 'Some Title'), ('Junk', '''\
-
-Junk'''), ('Good', 'other string')))
- self.assert_('MPL' in self.parser.header)
+''', (
+ ('Comment', mpl2),
+ ('IniSection', 'Strings'),
+ ('TitleText', 'Some Title'),
+ ('Junk', 'Junk'),
+ ('Good', 'other string')))
if __name__ == '__main__':
unittest.main()