Remove arbitrary arguments in favor of parsing arguments from experiment files.

refs: #4611

Change-Id: Ic668b58766fef8a1e537ccaacf82230b3fb50923
diff --git a/AUTHORS.md b/AUTHORS.md
index 89309df..55d2f29 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -7,6 +7,7 @@
 
 * The University of Memphis
 
+    * Alexander Lane       <awlane@memphis.edu>
     * Ashlesh Gawande      <https://www.linkedin.com/in/agawande>
     * Vince Lehman         <http://vslehman.com>
     * Yucheng Zhang        <yzhang@memphis.edu>
diff --git a/bin/minindn b/bin/minindn
index 2061c73..626b551 100755
--- a/bin/minindn
+++ b/bin/minindn
@@ -103,13 +103,10 @@
 
     def __call__(self, parser, namespace, values, option_string=None):
         experimentNames = ExperimentManager.getExperimentNames()
-        experimentArgs = ExperimentManager.getExperimentArgs()
 
         print("Mini-NDN experiments:")
         for experiment in experimentNames:
             print("  {}".format(experiment))
-            if experiment in experimentArgs:
-                print("      ({})".format(experimentArgs[experiment]))
 
         sys.exit(0)
 
@@ -134,7 +131,7 @@
         self.placer = None
         self.tunnelType = None
         self.faceType = "udp"
-        self.arbArgs = {}
+        self.arguments = None
         self.csSize = 65536
 
 def createResultsDir(resultDir, faces, rType):
@@ -224,17 +221,11 @@
     parser.add_argument("--cs-size", dest='csSize', type=int, default=65536,
                         help="Set CS size in NFD's conf file")
 
+    ExperimentManager.addExperimentArgs(parser)
+
     if "argcomplete" in sys.modules:
         argcomplete.autocomplete(parser)
 
-    args, unknownArgs = parser.parse_known_args()
-
-    unknownArgsList = []
-    for arg in unknownArgs:
-        if arg.startswith(("--")):
-            parser.add_argument(arg)
-            unknownArgsList.append(arg.split("--")[1])
-
     args = parser.parse_args()
 
     options = ProgramOptions()
@@ -258,10 +249,7 @@
     options.placeList = args.placeList
     options.faceType = args.faceType
     options.csSize = args.csSize
-
-    for k in args.__dict__:
-        if k in unknownArgsList:
-            options.arbArgs[k] = args.__dict__[k]
+    options.arguments = args
 
     if options.experimentName is not None and options.experimentName not in ExperimentManager.getExperimentNames():
         print("No experiment named %s" % options.experimentName)
@@ -471,7 +459,7 @@
             "pctTraffic": options.pctTraffic,
             "nlsrSecurity": options.nlsrSecurity,
             "workDir": options.workDir,
-            "arbArgs" : options.arbArgs
+            "arguments" : options.arguments
         }
 
         experiment = ExperimentManager.create(experimentName, experimentArgs)
@@ -526,4 +514,4 @@
         print("Mininet Error: {}".format(e))
         call(["nfd-stop"])
         call(["sudo", "mn", "--clean"])
-        sys.exit(1)
\ No newline at end of file
+        sys.exit(1)
diff --git a/docs/EXPERIMENTS.md b/docs/EXPERIMENTS.md
index b72ba7c..24ed27b 100644
--- a/docs/EXPERIMENTS.md
+++ b/docs/EXPERIMENTS.md
@@ -180,22 +180,25 @@
 
     Experiment.register("example-name", ExampleExperiment)
 
-## Passing arbitrary arguments to experiments
+## Passing arguments to experiments
 
-One can pass any arbitrary argument to the Mini-NDN command line
-as long as the arguments don't clash with Mini-NDN's arguments.
-This feature allows users to pass any argument to Mini-NDN and process
-them in an experiment without modifying Mini-NDN's core.
+Mini-NDN has the capacity to pass arguments to experiments, insofar
+as they do not clash with those of Mini-NDN. This feature
+allows users to pass arguments to Mini-NDN and process them in an
+experiment without having to rewrite Mini-NDN's core.
 
-Please look at `ndn/experiments/arbitrary_arguments_experiment.py`
-to see how these arguments can be accessed. To have the experiment
-options printed in `sudo minindn --list-experiments` when using
-arbitrary arguments one can add the static `arguments` method as
-shown in the aforementioned experiment.
+An example of an experiment implementing this functionality is given in
+`ndn/experiments/arguments_experiment.py`, which demonstrates how to
+write code which handles arguments. Documentation for these arguments
+appears when called with `sudo minindn -h`, as does documentation for
+fixed arguments defined in core code, so it is strongly recommended to
+differentiate those you write yourself. Note that Bash and Zsh users
+can make use of autocomplete functionality when calling these arguments.
 
 To run the experiment:
 
-    sudo minindn --experiment arbitrary-arguments --ds 400 --logging false
+    sudo minindn --experiment arg-exp --ds 226 --logging
 
-The experiment will print out the supplied arbitrary values which are --ds
-and --logging. --experiment is a fixed argument of Mini-NDN.
\ No newline at end of file
+The experiment will print out the supplied value for --ds and a boolean
+value for the presence of --logging. --experiment is a fixed argument of
+Mini-NDN.
\ No newline at end of file
diff --git a/ndn/experiment_manager.py b/ndn/experiment_manager.py
index 5f2a174..d8ec0eb 100644
--- a/ndn/experiment_manager.py
+++ b/ndn/experiment_manager.py
@@ -35,7 +35,6 @@
 
     def __init__(self):
         self.experiments = {}
-        self.expArgs = {}
 
     def loadModules(self):
         currentDir = os.path.dirname(__file__)
@@ -52,12 +51,6 @@
     def register(self, name, experimentClass):
         if name not in self.experiments:
             self.experiments[name] = experimentClass
-            try:
-                helpStr = experimentClass.arguments()
-                if type(helpStr) is str:
-                    self.expArgs[name] = experimentClass.arguments()
-            except:
-                pass
         else:
             raise _ExperimentManager.Error("Experiment '%s' has already been registered" % name)
 
@@ -92,7 +85,9 @@
 
     return experimentNames
 
-def getExperimentArgs():
+def addExperimentArgs(parser):
+    # Find all experiment command line arguments and parse them.
     manager = __getInstance()
-
-    return manager.expArgs
+    for name in manager.experiments:
+        if hasattr(manager.experiments[name], "parseArguments"):
+            manager.experiments[name].parseArguments(parser)
\ No newline at end of file
diff --git a/ndn/experiments/arbitrary_arguments_experiment.py b/ndn/experiments/arbitrary_arguments_experiment.py
deleted file mode 100644
index 159e2a7..0000000
--- a/ndn/experiments/arbitrary_arguments_experiment.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from ndn.experiments.experiment import Experiment
-
-class AbitraryArgumentsExperiment(Experiment):
-    def __init__(self, args):
-        Experiment.__init__(self, args)
-        if "ds" in self.arbArgs:
-            self.ds = int(self.arbArgs["ds"])
-        else:
-            self.ds = 1000
-
-        if "logging" in self.arbArgs:
-            self.logging = self.arbArgs["logging"]
-            if self.logging == "true":
-                self.logging = True
-            else:
-                self.logging = False
-        else:
-            self.logging = False
-
-    def setup(self):
-        pass
-
-    def run(self):
-        print("Argument ds: {}".format(self.ds))
-        print("Argument logging: {}".format(self.logging))
-
-    @staticmethod
-    def arguments():
-        ''' This will be printed in sudo minindn --list-experiments'''
-        return "--ds <num-data-streams> --logging <true/false>"
-
-Experiment.register("arbitrary-arguments", AbitraryArgumentsExperiment)
\ No newline at end of file
diff --git a/ndn/experiments/arguments_experiment.py b/ndn/experiments/arguments_experiment.py
new file mode 100644
index 0000000..e7ed6f9
--- /dev/null
+++ b/ndn/experiments/arguments_experiment.py
@@ -0,0 +1,23 @@
+from ndn.experiments.experiment import Experiment
+
+class ArgumentsExperiment(Experiment):
+    def __init__(self, args):
+        Experiment.__init__(self, args)
+        self.ds = self.arguments.ds
+        self.logging = self.arguments.logging
+
+    def setup(self):
+        pass
+
+    def run(self):
+        print("Argument ds: {}".format(self.ds))
+        print("Argument logging: {}".format(self.logging))
+
+    @staticmethod
+    def parseArguments(parser):
+        parser.add_argument("--ds", dest="ds", default="1000",
+                            help="[Arguments Experiment] Number of data streams")
+        parser.add_argument("--logging", dest="logging", action="store_true",
+                            help="[Arguments Experiment] Enable logging")
+
+Experiment.register("args-exp", ArgumentsExperiment)
\ No newline at end of file
diff --git a/ndn/experiments/experiment.py b/ndn/experiments/experiment.py
index 23efebd..5ada588 100644
--- a/ndn/experiments/experiment.py
+++ b/ndn/experiments/experiment.py
@@ -36,7 +36,7 @@
         self.strategy = args["strategy"]
         self.pctTraffic = args["pctTraffic"]
         self.nlsrSecurity = args["nlsrSecurity"]
-        self.arbArgs = args["arbArgs"]
+        self.arguments = args["arguments"]
 
         # Used to restart pings on the recovered node if any
         self.pingedDict = {}
@@ -148,4 +148,4 @@
 
     @staticmethod
     def register(name, experimentClass):
-        ExperimentManager.register(name, experimentClass)
+        ExperimentManager.register(name, experimentClass)
\ No newline at end of file