options->addOption(FileNameOption("o")
.filetype(eftPlot).outputFile()
- .store(&fnDist_).defaultValueIfSet("avedist")
+ .store(&fnDist_).defaultBasename("avedist")
.description("Average distances from reference group"));
options->addOption(SelectionOption("reference")
options.addOption(FileNameOption("f")
.description("Input file description")
.filetype(eftTrajectory).inputFile().required()
- .defaultValue("traj"));
+ .defaultBasename("traj"));
options.addOption(FileNameOption("lib")
.description("Library file description")
.filetype(eftGenericData).inputFile().libraryFile()
- .defaultValueIfSet("libdata"));
+ .defaultBasename("libdata"));
options.addOption(FileNameOption("io")
.store(&filename)
.description("Input/Output file description")
.filetype(eftGenericData).inputOutputFile()
- .defaultValueIfSet("inout"));
+ .defaultBasename("inout"));
options.addOption(FileNameOption("o")
.description("Output file description")
.filetype(eftPlot).outputFile());
options.addOption(FileNameOption("f")
.description("File name option with a long value")
.filetype(eftTrajectory).inputFile().required()
- .defaultValue("path/to/long/trajectory/name"));
+ .defaultBasename("path/to/long/trajectory/name"));
options.addOption(FileNameOption("f2")
.description("File name option with a long value")
.filetype(eftTrajectory).inputFile().required()
- .defaultValue("path/to/long/trajectory"));
+ .defaultBasename("path/to/long/trajectory"));
options.addOption(FileNameOption("lib")
.description("File name option with a long value and type")
.filetype(eftTrajectory).inputFile().libraryFile()
- .defaultValue("path/to/long/trajectory/name"));
+ .defaultBasename("path/to/long/trajectory/name"));
options.addOption(FileNameOption("longfileopt")
.description("File name option with a long name")
.filetype(eftGenericData).inputFile()
- .defaultValue("deffile"));
+ .defaultBasename("deffile"));
options.addOption(FileNameOption("longfileopt2")
.description("File name option with multiple long fields")
.filetype(eftGenericData).inputFile().libraryFile()
- .defaultValue("path/to/long/file/name"));
+ .defaultBasename("path/to/long/file/name"));
gmx::CommandLineHelpWriter writer(options);
checkHelp(&writer);
{
GMX_RELEASE_ASSERT(!bInSet_, "finishSet() not called");
processAll();
- if (isRequired() && !isSet())
+ if (isRequired() && !(isSet() || hasFlag(efOption_ExplicitDefaultValue)))
{
GMX_THROW(InvalidInputError("Option is required, but not set"));
}
//! Hides the option from normal help output.
MyClass &hidden(bool bHidden = true)
{ setFlag(efOption_Hidden, bHidden); return me(); }
- //! Requires the option to be specified explicitly.
+ /*! \brief
+ * Requires the option to be specified explicitly.
+ *
+ * Note that if you specify defaultValue() together with required(),
+ * the user is not required to explicitly provide the option.
+ * In this case, required() only affects possible help output.
+ */
MyClass &required(bool bRequired = true)
{ setFlag(efOption_Required, bRequired); return me(); }
//! Allows the option to be specified multiple times.
* is no default value, the storage is not altered, which can also be
* used to provide a default value. The latter method has to be used
* if the option can take multiple values.
- * If required() is specified, only affects the default value shown in
- * help output.
*
* \p defaultValue is copied when the option is created.
*/
bRead_(settings.bRead_), bWrite_(settings.bWrite_),
bLibrary_(settings.bLibrary_)
{
- if (settings.defaultValue())
+ if (settings.defaultBasename_ != NULL)
{
- setDefaultValue(completeFileName(*settings.defaultValue(),
- filetype_, false));
- }
- if (settings.defaultValueIfSet())
- {
- setDefaultValueIfSet(completeFileName(*settings.defaultValueIfSet(),
- filetype_, false));
+ if (isRequired())
+ {
+ setDefaultValue(completeFileName(settings.defaultBasename_,
+ filetype_, false));
+ }
+ else
+ {
+ setDefaultValueIfSet(completeFileName(settings.defaultBasename_,
+ filetype_, false));
+ }
}
}
*
* Public methods in this class do not throw.
*
- * This class is currently a stub implementation.
- *
* \inpublicapi
* \ingroup module_options
*/
//! Initializes an option with the given name.
explicit FileNameOption(const char *name)
- : MyBase(name), filetype_(eftUnknown),
+ : MyBase(name), filetype_(eftUnknown), defaultBasename_(NULL),
bRead_(false), bWrite_(false), bLibrary_(false)
{
}
/*! \brief
* Tells that the file will be looked up in library directories in
* addition to working directory.
+ *
+ * \todo
+ * Currently, this flag only affects the help output. Callers must
+ * take care themselves to actually search the file in the library
+ * directories. It would be nicer to do this searching within the
+ * file name option implementation.
*/
MyClass &libraryFile() { bLibrary_ = true; return me(); }
+ /*! \brief
+ * Sets a default basename for the file option.
+ *
+ * Use this method instead of defaultValue() or defaultValueIfSet() to
+ * set a default value for a file name option. No extension needs to
+ * be provided; it is automatically added based on filetype().
+ * The behavior is also adjusted based on required(): if the option is
+ * required, the value given to defaultBasename() is treated as for
+ * defaultValue(), otherwise it is treated as for defaultValueIfSet().
+ */
+ MyClass &defaultBasename(const char *basename)
+ { defaultBasename_ = basename; return me(); }
private:
+ // Use defaultBasename() instead.
+ using MyBase::defaultValue;
+ using MyBase::defaultValueIfSet;
+
//! Creates a FileNameOptionStorage object.
virtual AbstractOptionStoragePointer createStorage() const;
OptionFileType filetype_;
+ const char *defaultBasename_;
bool bRead_;
bool bWrite_;
bool bLibrary_;
*
* These flags are not part of the public interface, even though they are in an
* installed header. They are needed in a few template class implementations.
+ *
+ * \todo
+ * The flags related to default values are confusing, consider reorganizing
+ * them.
*/
enum OptionFlag
{
efOption_Set = 1<<0,
//! The current value of the option is a programmatic default value.
efOption_HasDefaultValue = 1<<1,
+ //! An explicit default value has been provided for the option.
+ efOption_ExplicitDefaultValue = 1<<2,
/*! \brief
* Next assignment to the option clears old values.
*
* This flag is set when a new option source starts, such that values
* from the new source will overwrite old ones.
*/
- efOption_ClearOnNextSet = 1<<2,
+ efOption_ClearOnNextSet = 1<<3,
//! %Option is required to be set.
efOption_Required = 1<<4,
//! %Option can be specified multiple times.
}
if (hasFlag(efOption_HasDefaultValue))
{
+ setFlag(efOption_ExplicitDefaultValue);
clear();
clearSet();
addValue(value);
EXPECT_EQ("testfile.xtc", value);
}
-TEST(FileNameOptionTest, HandlesDefaultValueWithoutExtension)
+TEST(FileNameOptionTest, HandlesRequiredDefaultValueWithoutExtension)
{
gmx::Options options(NULL, NULL);
std::string value;
ASSERT_NO_THROW(options.addOption(
- FileNameOption("f").store(&value)
+ FileNameOption("f").store(&value).required()
.filetype(gmx::eftGenericData).outputFile()
- .defaultValue("testfile")));
+ .defaultBasename("testfile")));
EXPECT_EQ("testfile.dat", value);
gmx::OptionsAssigner assigner(&options);
EXPECT_EQ("testfile.dat", value);
}
-TEST(FileNameOptionTest, HandlesDefaultValueIfSetWithoutExtension)
+TEST(FileNameOptionTest, HandlesOptionalDefaultValueWithoutExtension)
{
gmx::Options options(NULL, NULL);
std::string value;
ASSERT_NO_THROW(options.addOption(
FileNameOption("f").store(&value)
.filetype(gmx::eftIndex).outputFile()
- .defaultValueIfSet("testfile")));
+ .defaultBasename("testfile")));
EXPECT_TRUE(value.empty());
gmx::OptionsAssigner assigner(&options);
EXPECT_THROW(options.finish(), gmx::InvalidInputError);
}
+TEST(OptionsAssignerTest, HandlesRequiredParameterWithDefaultValue)
+{
+ gmx::Options options(NULL, NULL);
+ int value = 0;
+ using gmx::IntegerOption;
+ ASSERT_NO_THROW(options.addOption(
+ IntegerOption("p").store(&value).required()
+ .defaultValue(1)));
+
+ EXPECT_NO_THROW(options.finish());
+ EXPECT_EQ(1, value);
+}
+
TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
{
gmx::Options options(NULL, NULL);
options->setDescription(concatenateStrings(desc));
options->addOption(FileNameOption("o").filetype(eftPlot).outputFile()
- .store(&fnAngle_).defaultValueIfSet("angle")
+ .store(&fnAngle_).defaultBasename("angle")
.description("Computed angles"));
options->addOption(FileNameOption("od").filetype(eftPlot).outputFile()
- .store(&fnDump_).defaultValueIfSet("angdump")
+ .store(&fnDump_).defaultBasename("angdump")
.description("Individual angles on separate lines"));
options->addOption(StringOption("g1").enumValue(cGroup1TypeEnum)
options->setDescription(concatenateStrings(desc));
options->addOption(FileNameOption("o").filetype(eftPlot).outputFile()
- .store(&fnDist_).defaultValueIfSet("dist")
+ .store(&fnDist_).defaultBasename("dist")
.description("Computed distances"));
options->addOption(SelectionOption("select").required().valueCount(2)
.store(sel_));
options->setDescription(concatenateStrings(desc));
options->addOption(FileNameOption("os").filetype(eftPlot).outputFile()
- .store(&fnSize_).defaultValueIfSet("size")
+ .store(&fnSize_).defaultBasename("size")
.description("Number of positions in each selection"));
options->addOption(FileNameOption("oc").filetype(eftPlot).outputFile()
- .store(&fnFrac_).defaultValueIfSet("frac")
+ .store(&fnFrac_).defaultBasename("frac")
.description("Covered fraction for each selection"));
options->addOption(FileNameOption("oi").filetype(eftGenericData).outputFile()
- .store(&fnIndex_).defaultValueIfSet("index")
+ .store(&fnIndex_).defaultBasename("index")
.description("Indices selected by each selection"));
options->addOption(FileNameOption("on").filetype(eftIndex).outputFile()
- .store(&fnNdx_).defaultValueIfSet("index")
+ .store(&fnNdx_).defaultBasename("index")
.description("Index file from the selection"));
options->addOption(FileNameOption("om").filetype(eftPlot).outputFile()
- .store(&fnMask_).defaultValueIfSet("mask")
+ .store(&fnMask_).defaultBasename("mask")
.description("Mask for selected positions"));
options->addOption(SelectionOption("select").storeVector(&sel_)
options->addOption(FileNameOption("f")
.filetype(eftTrajectory).inputFile()
.store(&impl_->trjfile_)
- .defaultValueIfSet("traj")
+ .defaultBasename("traj")
.description("Input trajectory or single configuration"));
options->addOption(FileNameOption("s")
.filetype(eftTopology).inputFile()
.store(&impl_->topfile_)
- .defaultValueIfSet("topol")
+ .defaultBasename("topol")
.description("Input structure"));
options->addOption(FileNameOption("n")
.filetype(eftIndex).inputFile()
.store(&impl_->ndxfile_)
- .defaultValueIfSet("index")
+ .defaultBasename("index")
.description("Extra index groups"));
options->addOption(SelectionFileOption("sf"));