diff options
author | Alexis Hildebrandt <afh@surryhill.net> | 2015-01-27 11:55:08 +0100 |
---|---|---|
committer | Alexis Hildebrandt <afh@surryhill.net> | 2015-01-27 22:02:59 +0100 |
commit | 11a01f1b5aeff063740edfbe99dba35003237551 (patch) | |
tree | c30df6911bd553f2229c1012214963a589d1c393 | |
parent | 19f4f587f0a527056707465bdd9b441a53236711 (diff) | |
download | fork-ledger-11a01f1b5aeff063740edfbe99dba35003237551.tar.gz fork-ledger-11a01f1b5aeff063740edfbe99dba35003237551.tar.bz2 fork-ledger-11a01f1b5aeff063740edfbe99dba35003237551.zip |
[doc] Report undocumented value expression functions
in the manpage and texinfo manual.
-rw-r--r-- | doc/ledger3.texi | 22 | ||||
-rwxr-xr-x | test/CheckManpage.py | 1 | ||||
-rwxr-xr-x | test/CheckOptions.py | 48 | ||||
-rwxr-xr-x | test/CheckTexinfo.py | 41 |
4 files changed, 89 insertions, 23 deletions
diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 080fc3eb..a2a93c98 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -8020,13 +8020,13 @@ functions and variables below: @defun abs value @defunx U value Return the absolute value of the given @var{value}, e.g. @var{amount}. -@end defun @smallexample @c command:3406FC1 $ ledger -f expr.dat --format "%(account) %(abs(amount))\n" reg assets @end smallexample @smallexample @c output:3406FC1 Assets:Cash ¤ 123,45 @end smallexample +@end defun @defun amount_expr @value{FIXME:UNDOCUMENTED} @@ -8038,7 +8038,6 @@ codes to display it in the given @var{color} if @var{bool} is true. It typically checks the value of the option @option{--color}. Since ANSI escape codes include non-printable character sequences, such as escape @kbd{^[} the following example may not appear as the final result on the commandline. -@end defun @smallexample @c command:4D836EE,with_input:3406FC1 $ ledger -f expr.dat --format "%(ansify_if(account, blue, options.color))\n" reg @end smallexample @@ -8046,10 +8045,10 @@ $ ledger -f expr.dat --format "%(ansify_if(account, blue, options.color))\n" reg [34mAssets:Cash[0m [34mExpenses:Office Supplies[0m @end smallexample +@end defun @defun ceiling value Return the next integer of @var{value} toward @math{+}infinity. -@end defun @smallexample @c command:FF9C18C,with_input:3406FC1 $ ledger -f expr.dat --format "%(account) %(ceiling(amount))\n" reg @end smallexample @@ -8057,6 +8056,7 @@ $ ledger -f expr.dat --format "%(account) %(ceiling(amount))\n" reg Assets:Cash ¤ -123,00 Expenses:Office Supplies ¤ 124,00 @end smallexample +@end defun @defvar code Return the transaction code, the string between the parenthesis after the date. @@ -8102,7 +8102,6 @@ $ ledger -f expr.dat --format "%(date) %(account)\n" reg assets @defun floor value Return the next integer of @var{value} toward @math{-}infinity. -@end defun @smallexample @c command:4FDC7C5,with_input:3406FC1 $ ledger -f expr.dat --format "%(account) %(floor(amount))\n" reg @end smallexample @@ -8110,6 +8109,7 @@ $ ledger -f expr.dat --format "%(account) %(floor(amount))\n" reg Assets:Cash ¤ -124,00 Expenses:Office Supplies ¤ 123,00 @end smallexample +@end defun @defun format @value{FIXME:UNDOCUMENTED} @@ -8118,13 +8118,13 @@ Expenses:Office Supplies ¤ 123,00 @defun format_date date format Return the @var{date} as a string using @var{format}. See strftime (3) for format string details. -@end defun @smallexample @c command:9605B13,with_input:3406FC1 $ ledger -f expr.dat --format "%(format_date(date, '%A, %B %d. %Y'))\n" reg assets @end smallexample @smallexample @c output:9605B13 Friday, January 16. 2015 @end smallexample +@end defun @defun format_datetime @value{FIXME:UNDOCUMENTED} @@ -8151,7 +8151,6 @@ If @var{right_justify=true} then the field is right justify within the width of the field. If it is @var{false}, then the field is left justified and padded to the full width of the field. If @var{colorize} is true, then ledger will honor color settings. -@end defun @smallexample @c command:082FB27,with_input:3406FC1 $ ledger -f expr.dat --format "»%(justify(account, 30, 30, true))«\n" reg @end smallexample @@ -8159,6 +8158,7 @@ $ ledger -f expr.dat --format "»%(justify(account, 30, 30, true))«\n" reg » Assets:Cash« » Expenses:Office Supplies« @end smallexample +@end defun @defun market @defunx P @@ -8189,7 +8189,6 @@ true $ @defun percent value_a value_b Return the percentage of @var{value_a} in relation to @var{value_b} (used as 100%) -@end defun @smallexample @c command:04959BF,with_input:3406FC1 $ ledger -f expr.dat --format "%(percent(amount, 200))\n" reg @end smallexample @@ -8197,6 +8196,7 @@ $ ledger -f expr.dat --format "%(percent(amount, 200))\n" reg -61.73% 61.73% @end smallexample +@end defun @defun print @value{FIXME:UNDOCUMENTED} @@ -8208,7 +8208,6 @@ $ ledger -f expr.dat --format "%(percent(amount, 200))\n" reg @defun quoted expression Surround @var{expression} with double-quotes. -@end defun @smallexample @c command:EAD8AA7,with_input:3406FC1 $ ledger -f expr.dat --format "%(quoted(account)) %(quoted(amount))\n" reg @end smallexample @@ -8216,6 +8215,7 @@ $ ledger -f expr.dat --format "%(quoted(account)) %(quoted(amount))\n" reg "Assets:Cash" "¤ -123,45" "Expenses:Office Supplies" "¤ 123,45" @end smallexample +@end defun @defun round @value{FIXME:UNDOCUMENTED} @@ -8227,7 +8227,6 @@ $ ledger -f expr.dat --format "%(quoted(account)) %(quoted(amount))\n" reg @defun roundto value n Return @var{value} rounded to @var{n} digits. Does not affect formatting. -@end defun @smallexample @c command:B4DFB9F,with_input:3406FC1 $ ledger -f expr.dat --format "%(account) %(roundto(amount, 1))\n" reg @end smallexample @@ -8235,6 +8234,7 @@ $ ledger -f expr.dat --format "%(account) %(roundto(amount, 1))\n" reg Assets:Cash ¤ -123,40 Expenses:Office Supplies ¤ 123,50 @end smallexample +@end defun @defun scrub @value{FIXME:UNDOCUMENTED} @@ -8272,7 +8272,6 @@ Expenses:Office Supplies ¤ 123,50 @defun to_int value @defunx int value Return the integer value for @var{value}. -@end defun @smallexample @c command:0B0CBA1,with_input:3406FC1 $ ledger -f expr.dat --format "%(1 + to_int('1'))\n%(2,5 + int(2,5))\n" reg assets @end smallexample @@ -8280,6 +8279,7 @@ $ ledger -f expr.dat --format "%(1 + to_int('1'))\n%(2,5 + int(2,5))\n" reg asse 2 4.5 @end smallexample +@end defun @defun to_mask @value{FIXME:UNDOCUMENTED} @@ -8314,13 +8314,13 @@ $ ledger -f expr.dat --now 2015/01/01 --format "%(today)\n" reg assets @defun trim value Trim leading and trailing whitespace from @var{value}. -@end defun @smallexample @c command:377BBAB,with_input:3406FC1 $ ledger -f expr.dat --format "»%(trim(' Trimmed '))«\n" reg assets @end smallexample @smallexample @c output:377BBAB »Trimmed« @end smallexample +@end defun @defun truncated @value{FIXME:UNDOCUMENTED} diff --git a/test/CheckManpage.py b/test/CheckManpage.py index 6b0f2476..944f4e07 100755 --- a/test/CheckManpage.py +++ b/test/CheckManpage.py @@ -17,6 +17,7 @@ class CheckManpage (CheckOptions): def __init__(self, args): CheckOptions.__init__(self, args) self.option_pattern = '\.It Fl \\\\-([-A-Za-z]+)' + self.function_pattern = '\.It Fn ([-A-Za-z_]+)' self.source_file = join(self.source, 'doc', 'ledger.1') self.source_type = 'manpage' diff --git a/test/CheckOptions.py b/test/CheckOptions.py index 124ce197..5059a289 100755 --- a/test/CheckOptions.py +++ b/test/CheckOptions.py @@ -22,16 +22,21 @@ class CheckOptions (object): self.ledger = os.path.abspath(args.ledger) self.source = os.path.abspath(args.source) - self.missing_baseline_tests = set() self.missing_options = set() self.unknown_options = set() + self.missing_functions = set() + self.unknown_functions = set() - def find_options(self, filename): - regex = re.compile(self.option_pattern) + def find_pattern(self, filename, pattern): + regex = re.compile(pattern) return {match.group(1) for match in {regex.match(line) for line in open(filename)} if match} + def find_options(self, filename): + return self.find_pattern(filename, self.option_pattern) + + def find_functions(self, filename): + return self.find_pattern(filename, self.function_pattern) def find_alternates(self): - regex = re.compile(r'OPT_ALT\([^,]*,\s*([^)]+?)_?\)'); command = shlex.split('grep --no-filename OPT_ALT') for source_file in ['session', 'report']: command.append(os.path.join(self.source, 'src', '%s.cc' % source_file)) @@ -39,6 +44,8 @@ class CheckOptions (object): output = subprocess.check_output(command).split('\n'); except subprocess.CalledProcessError: output = '' + + regex = re.compile(r'OPT_ALT\([^,]*,\s*([^)]+?)_?\)'); alternates = {match.group(1).replace('_', '-') for match in {regex.search(line) for line in output} if match} return alternates @@ -49,22 +56,43 @@ class CheckOptions (object): ledger_options = {match.group(1).replace('_', '-') for match in {regex.search(line.decode()) for line in pipe.stderr} if match} return ledger_options + def ledger_functions(self): + command = shlex.split('grep --no-filename fn_ %s' % (os.path.join(self.source, 'src', 'report.h'))) + try: + output = subprocess.check_output(command).split('\n'); + except subprocess.CalledProcessError: + output = '' + + regex = re.compile(r'fn_([^(]+)\('); + functions = {match.group(1) for match in {regex.search(line) for line in output} if match} + return functions + def main(self): options = self.find_options(self.source_file) - for option in self.ledger_options(): if option not in options: self.missing_options.add(option) else: options.remove(option) - known_alternates = self.find_alternates() self.unknown_options = {option for option in options if option not in known_alternates} + functions = self.find_functions(self.source_file) + for function in self.ledger_functions(): + if function not in functions: + self.missing_functions.add(function) + else: + functions.remove(function) + known_functions = ['tag', 'has_tag'] + self.unknown_functions = {function for function in functions if function not in known_functions} + if len(self.missing_options): - print("Missing %s entries for:%s%s\n" % (self.source_type, self.sep, self.sep.join(sorted(list(self.missing_options))))) + print("Missing %s option entries for:%s%s\n" % (self.source_type, self.sep, self.sep.join(sorted(list(self.missing_options))))) if len(self.unknown_options): - print("%s entry for unknown options:%s%s" % (self.source_type, self.sep, self.sep.join(sorted(list(self.unknown_options))))) - - errors = len(self.missing_options) + len(self.unknown_options) + print("%s entry for unknown options:%s%s\n" % (self.source_type, self.sep, self.sep.join(sorted(list(self.unknown_options))))) + if len(self.missing_functions): + print("Missing %s function entries for:%s%s\n" % (self.source_type, '\n ', '\n '.join(sorted(list(self.missing_functions))))) + if len(self.unknown_functions): + print("%s entry for unknown functions:%s%s\n" % (self.source_type, '\n ', '\n '.join(sorted(list(self.unknown_functions))))) + errors = len(self.missing_options) + len(self.unknown_options) + len(self.missing_functions) + len(self.unknown_functions) return errors diff --git a/test/CheckTexinfo.py b/test/CheckTexinfo.py index 34d0e153..cd167eba 100755 --- a/test/CheckTexinfo.py +++ b/test/CheckTexinfo.py @@ -16,10 +16,47 @@ from CheckOptions import CheckOptions class CheckTexinfo (CheckOptions): def __init__(self, args): CheckOptions.__init__(self, args) - self.option_pattern = '@item --([-A-Za-z]+).*@c option' + self.option_pattern = '^@item\s+--([-A-Za-z]+)' + self.function_pattern = '^@defun\s+([-A-Za-z_]+)' self.source_file = join(self.source, 'doc', 'ledger3.texi') self.source_type = 'texinfo' + + def find_functions(self, filename): + functions = set() + state_normal = 0 + state_function = 1 + state = state_normal + function = None + fun_doc = str() + fun_example = False + item_regex = re.compile(self.function_pattern) + itemx_regex = re.compile('^@defunx') + example_regex = re.compile('^@smallexample\s+@c\s+command:') + fix_regex = re.compile('FIX') + comment_regex = re.compile('^\s*@c') + for line in open(filename): + line = line.strip() + if state == state_normal: + match = item_regex.match(line) + if match: + state = state_function + function = match.group(1) + elif state == state_function: + if line == '@end defun': + if function and fun_example and len(fun_doc) and not fix_regex.search(fun_doc): + functions.add(function) + state = state_normal + fun_example = None + fun_doc = str() + elif itemx_regex.match(line): + continue + elif example_regex.match(line): + fun_example = True + elif not comment_regex.match(line): + fun_doc += line + return functions + def find_options(self, filename): options = set() state_normal = 0 @@ -27,7 +64,7 @@ class CheckTexinfo (CheckOptions): state = state_normal option = None opt_doc = str() - item_regex = re.compile('^@item --([-A-Za-z]+)') + item_regex = re.compile(self.option_pattern) itemx_regex = re.compile('^@itemx') fix_regex = re.compile('FIX') comment_regex = re.compile('^\s*@c') |