1########################################################################
2##
3## Copyright (C) 2012-2021 The Octave Project Developers
4##
5## See the file COPYRIGHT.md in the top-level directory of this
6## distribution or <https://octave.org/copyright/>.
7##
8## This file is part of Octave.
9##
10## Octave is free software: you can redistribute it and/or modify it
11## under the terms of the GNU General Public License as published by
12## the Free Software Foundation, either version 3 of the License, or
13## (at your option) any later version.
14##
15## Octave is distributed in the hope that it will be useful, but
16## WITHOUT ANY WARRANTY; without even the implied warranty of
17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18## GNU General Public License for more details.
19##
20## You should have received a copy of the GNU General Public License
21## along with Octave; see the file COPYING.  If not, see
22## <https://www.gnu.org/licenses/>.
23##
24########################################################################
25
26## -*- texinfo -*-
27## @deftypefn  {} {} methods (@var{obj})
28## @deftypefnx {} {} methods ("@var{classname}")
29## @deftypefnx {} {} methods (@dots{}, "-full")
30## @deftypefnx {} {@var{mtds} =} methods (@dots{})
31## List the names of the public methods for the object @var{obj} or the
32## named class @var{classname}.
33##
34## @var{obj} may be an Octave class object or a Java object.
35## @var{classname} may be the name of an Octave class or a Java class.
36##
37## If the optional argument @qcode{"-full"} is given then Octave returns
38## full method signatures which include output type, name of method,
39## and the number and type of inputs.
40##
41## When called with no output arguments, @code{methods} prints the list of
42## method names to the screen.  Otherwise, the output argument @var{mtds}
43## contains the list in a cell array of strings.
44## @seealso{ismethod, properties, fieldnames}
45## @end deftypefn
46
47function mtds = methods (obj, opt)
48
49  if (nargin < 1 || nargin > 2)
50    print_usage ();
51  endif
52
53  havesigs = false;
54  showsigs = false;
55  if (nargin == 2)
56    if (! strcmp (opt, "-full"))
57      error ("methods: invalid option");
58    endif
59    showsigs = true;
60  endif
61
62  if (isobject (obj))
63    ## Call internal C++ function for Octave objects
64    mtds_list = __methods__ (obj);
65  elseif (ischar (obj))
66    ## Could be a classname for an Octave class or Java class.
67    ## Try Octave class first.
68    mtds_list = __methods__ (obj);
69    if (isempty (mtds_list))
70      mtds_str = javaMethod ("getMethods", "org.octave.ClassHelper", obj);
71      mtds_list = ostrsplit (mtds_str, ';');
72      mtds_list = mtds_list(:);  # return a column vector for compatibility
73      havesigs = true;
74    endif
75  elseif (isjava (obj))
76    ## If obj is a String or a subclass of String, then get the methods of its
77    ## class name, not the methods of the class that may be named by the
78    ## content of the string.
79    if (isa (obj, "java.lang.String"))
80      klass = class (obj);
81      mtds_str = javaMethod ("getMethods", "org.octave.ClassHelper", klass);
82    else
83      mtds_str = javaMethod ("getMethods", "org.octave.ClassHelper", obj);
84    endif
85    mtds_list = strsplit (mtds_str, ';');
86    mtds_list = mtds_list(:);  # return a column vector for compatibility
87    havesigs = true;
88  else
89    error ("methods: invalid input argument");
90  endif
91
92  if (havesigs && ! showsigs)
93    ## Extract only the method name for ordinary class methods, delete the
94    ## return type and the argument list.
95    mtds_list = regexprep (mtds_list, '^(?:[^(]+) (\w+) ?\(.*$', '$1');
96
97    ## Extract only the class name for class constructors, delete the optional
98    ## "org.example." package prefix and the argument list.
99    mtds_list = regexprep (mtds_list, '^(?:[\.\w]+\.)?(\w+) ?\(.*$', '$1');
100
101    mtds_list = unique (mtds_list);
102  else
103    ## Delete the "org.example." package prefix if present.
104    mtds_list = regexprep (mtds_list, '^(?:[\.\w]+\.)(\w+ ?\(.*)$', '$1');
105  endif
106
107  if (nargout == 0)
108    classname = ifelse (ischar (obj), obj, class (obj));
109    printf ("Methods for class %s:\n", classname);
110    disp (list_in_columns (mtds_list));
111  else
112    mtds = mtds_list;
113  endif
114
115endfunction
116
117
118## test old-style @classname
119%!test
120%! mtds = methods ("ftp");
121%! assert (mtds{1}, "ascii");
122
123## test Java classname
124%!testif HAVE_JAVA; usejava ("jvm")
125%! mtds = methods ("java.lang.Double");
126%! search = strfind (mtds, "valueOf");
127%! assert (! isempty ([search{:}]));
128
129## test Java classname with -full prototypes
130%!testif HAVE_JAVA; usejava ("jvm")
131%! mtds = methods ("java.lang.Double", "-full");
132%! search = strfind (mtds, "java.lang.Double valueOf");
133%! assert (! isempty ([search{:}]));
134
135## test that methods does the right thing when passed a String object
136%!testif HAVE_JAVA; usejava ("jvm") <*48758>
137%! object = javaObject ("java.lang.String", "java.lang.Integer");
138%! assert (methods (object), methods ("java.lang.String"));
139
140## test classdef classname
141%!assert (methods ("inputParser"),
142%!        {"addOptional"; "addParamValue"; "addParameter";
143%!         "addRequired"; "addSwitch"; "add_missing"; "delete";
144%!         "disp"; "error"; "is_argname"; "parse"; "validate_arg";
145%!         "validate_name"});
146
147## Test input validation
148%!error methods ()
149%!error methods ("a", "b", "c")
150%!error <invalid option> methods ("ftp", "option1")
151%!error <invalid input argument> methods (1)
152