Enhancements - modifiers

- Now only allows one modifier.
- Removed "not", "synth", "next", "first", "last" modifiers.
- Modified match logic.
This commit is contained in:
Paul Beckingham 2009-06-12 21:11:33 -04:00
parent 5a0535c9b5
commit bd0309b4ff
6 changed files with 160 additions and 153 deletions

View file

@ -35,8 +35,28 @@
Att::Att () Att::Att ()
: mName ("") : mName ("")
, mValue ("") , mValue ("")
, mMod ("")
{ {
mMods.clear (); }
////////////////////////////////////////////////////////////////////////////////
Att::Att (const std::string& name, const std::string& mod, const std::string& value)
{
mName = name;
mValue = value;
mMod = mod;
}
////////////////////////////////////////////////////////////////////////////////
Att::Att (const std::string& name, const std::string& mod, int value)
{
mName = name;
std::stringstream s;
s << value;
mValue = s.str ();
mMod = mod;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -44,8 +64,7 @@ Att::Att (const std::string& name, const std::string& value)
{ {
mName = name; mName = name;
mValue = value; mValue = value;
mMod = "";
mMods.clear ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -57,7 +76,7 @@ Att::Att (const std::string& name, int value)
s << value; s << value;
mValue = s.str (); mValue = s.str ();
mMods.clear (); mMod = "";
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -65,7 +84,7 @@ Att::Att (const Att& other)
{ {
mName = other.mName; mName = other.mName;
mValue = other.mValue; mValue = other.mValue;
mMods = other.mMods; mMod = other.mMod;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -75,7 +94,7 @@ Att& Att::operator= (const Att& other)
{ {
mName = other.mName; mName = other.mName;
mValue = other.mValue; mValue = other.mValue;
mMods = other.mMods; mMod = other.mMod;
} }
return *this; return *this;
@ -116,8 +135,8 @@ bool Att::valid (const std::string& input) const
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// start --> name --> . --> mod --> : --> " --> value --> " --> end // start --> name --> . --> mod --> : --> " --> value --> " --> end
// ^ | // | ^
// |__________| // |_____________________|
// //
void Att::parse (const std::string& input) void Att::parse (const std::string& input)
{ {
@ -130,20 +149,20 @@ void Att::parse (Nibbler& n)
// Ensure a clean object first. // Ensure a clean object first.
mName = ""; mName = "";
mValue = ""; mValue = "";
mMods.clear (); mMod = "";
if (n.getUntilOneOf (".:", mName)) if (n.getUntilOneOf (".:", mName))
{ {
if (mName.length () == 0) if (mName.length () == 0)
throw std::string ("Missing attribute name"); // TODO i18n throw std::string ("Missing attribute name"); // TODO i18n
while (n.skip ('.')) if (n.skip ('.'))
{ {
std::string mod; std::string mod;
if (n.getUntilOneOf (".:", mod)) if (n.getUntil (":", mod))
{ {
if (validMod (mod)) if (validMod (mod))
mMods.push_back (mod); mMod = mod;
else else
throw std::string ("The name '") + mod + "' is not a valid modifier"; // TODO i18n throw std::string ("The name '") + mod + "' is not a valid modifier"; // TODO i18n
} }
@ -174,15 +193,12 @@ void Att::parse (Nibbler& n)
bool Att::validMod (const std::string& mod) const bool Att::validMod (const std::string& mod) const
{ {
if (mod == "before" || mod == "after" || // i18n: TODO if (mod == "before" || mod == "after" || // i18n: TODO
mod == "not" || // i18n: TODO
mod == "none" || mod == "any" || // i18n: TODO mod == "none" || mod == "any" || // i18n: TODO
mod == "synth" || // i18n: TODO
mod == "under" || mod == "over" || // i18n: TODO mod == "under" || mod == "over" || // i18n: TODO
mod == "first" || mod == "last" || // i18n: TODO mod == "first" || mod == "last" || // i18n: TODO
mod == "this" || // i18n: TODO
mod == "next" || // i18n: TODO
mod == "is" || mod == "isnt" || // i18n: TODO mod == "is" || mod == "isnt" || // i18n: TODO
mod == "has" || mod == "hasnt" || // i18n: TODO mod == "has" || mod == "hasnt" || // i18n: TODO
mod == "contains" || // i18n: TODO
mod == "startswith" || mod == "endswith") // i18n: TODO mod == "startswith" || mod == "endswith") // i18n: TODO
return true; return true;
@ -194,36 +210,34 @@ bool Att::validMod (const std::string& mod) const
// Record that does not have modifiers, but may have a value. // Record that does not have modifiers, but may have a value.
bool Att::match (const Att& other) const bool Att::match (const Att& other) const
{ {
// If there are no mods, just perform a straight compares on value. // If there are no mods, just perform a straight compare on value.
if (mMods.size () == 0) if (mMod == "" && mValue != other.mValue)
if (mName != other.mName || mValue != other.mValue)
return false; return false;
// Assume a match, and short-circuit on mismatch. // Assume a match, and short-circuit on mismatch.
foreach (mod, mMods)
{ // is = equal. Nop.
// is = equal. else if (mMod == "is") // TODO i18n
if (*mod == "is") // TODO i18n
if (mValue != other.mValue) if (mValue != other.mValue)
return false; return false;
// isnt = not equal. // isnt = not equal.
if (*mod == "isnt") // TODO i18n else if (mMod == "isnt") // TODO i18n
if (mValue == other.mValue) if (mValue == other.mValue)
return false; return false;
// any = any value, but not empty value. // any = any value, but not empty value.
if (*mod == "any") // TODO i18n else if (mMod == "any") // TODO i18n
if (other.mValue == "") if (other.mValue == "")
return false; return false;
// none = must have empty value. // none = must have empty value.
if (*mod == "none") // TODO i18n else if (mMod == "none") // TODO i18n
if (other.mValue != "") if (other.mValue != "")
return false; return false;
// startswith = first characters must match. // startswith = first characters must match.
if (*mod == "startswith") // TODO i18n else if (mMod == "startswith") // TODO i18n
{ {
if (other.mValue.length () < mValue.length ()) if (other.mValue.length () < mValue.length ())
return false; return false;
@ -233,7 +247,7 @@ bool Att::match (const Att& other) const
} }
// endswith = last characters must match. // endswith = last characters must match.
if (*mod == "endswith") // TODO i18n else if (mMod == "endswith") // TODO i18n
{ {
if (other.mValue.length () < mValue.length ()) if (other.mValue.length () < mValue.length ())
return false; return false;
@ -245,26 +259,26 @@ bool Att::match (const Att& other) const
} }
// has = contains as a substring. // has = contains as a substring.
if (*mod == "has") // TODO i18n else if (mMod == "has" || mMod == "contains") // TODO i18n
if (other.mValue.find (mValue) == std::string::npos) if (other.mValue.find (mValue) == std::string::npos)
return false; return false;
// hasnt = does not contain as a substring. // hasnt = does not contain as a substring.
if (*mod == "hasnt") // TODO i18n else if (mMod == "hasnt") // TODO i18n
if (other.mValue.find (mValue) != std::string::npos) if (other.mValue.find (mValue) != std::string::npos)
return false; return false;
// TODO before // Harder:
// TODO after // TODO before/after
// TODO not <-- could be a problem
// TODO synth
// TODO under/below // TODO under/below
// TODO over/above // TODO over/above
// TODO first
// TODO last // Impossible?
// TODO synth
// TODO this // TODO this
// TODO next // TODO next
} // TODO first
// TODO last
return true; return true;
} }
@ -288,18 +302,18 @@ std::string Att::composeF4 () const
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Att::addMod (const std::string& mod) void Att::mod (const std::string& input)
{ {
if (validMod (mod)) if (!validMod (input))
mMods.push_back (mod); throw std::string ("The name '") + input + "' is not a valid modifier"; // TODO i18n
else
throw std::string ("The name '") + mod + "' is not a valid modifier"; // TODO i18n mMod = input;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Att::mods (std::vector <std::string>& all) const std::string Att::mod () const
{ {
all = mMods; return mMod;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -419,4 +433,5 @@ void Att::decode (std::string& value) const
while ((i = value.find ("&colon;")) != std::string::npos) // no i18n while ((i = value.find ("&colon;")) != std::string::npos) // no i18n
value.replace (i, 7, ":"); value.replace (i, 7, ":");
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -34,12 +34,14 @@
class Att class Att
{ {
public: public:
Att (); // Default constructor Att ();
Att (const std::string&, const std::string&); // Simple constructor Att (const std::string&, const std::string&, const std::string&);
Att (const std::string&, int); // Simple constructor Att (const std::string&, const std::string&, int);
Att (const Att&); // Copy constructor Att (const std::string&, const std::string&);
Att& operator= (const Att&); // Assignment operator Att (const std::string&, int);
~Att (); // Destructor Att (const Att&);
Att& operator= (const Att&);
~Att ();
bool valid (const std::string&) const; bool valid (const std::string&) const;
void parse (const std::string&); void parse (const std::string&);
@ -49,8 +51,8 @@ public:
std::string composeF4 () const; std::string composeF4 () const;
void addMod (const std::string&); void mod (const std::string&);
void mods (std::vector <std::string>&) const; std::string mod () const;
std::string name () const; std::string name () const;
void name (const std::string&); void name (const std::string&);
@ -70,7 +72,7 @@ private:
private: private:
std::string mName; std::string mName;
std::string mValue; std::string mValue;
std::vector <std::string> mMods; std::string mMod;
}; };
#endif #endif

View file

@ -479,6 +479,15 @@ void Context::constructFilter ()
foreach (att, task) foreach (att, task)
if (att->first != "uuid") if (att->first != "uuid")
filter.push_back (att->second); filter.push_back (att->second);
// TODO this doesn't work.
if (task.has ("description"))
{
std::vector <std::string> words;
split (words, task.get ("description"), ' ');
foreach (word, words)
filter.push_back (Att ("description", "contains", *word));
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -159,8 +159,6 @@ int TDB2::loadPending (std::vector <Task>& tasks, Filter& filter)
char line[T_LINE_MAX]; char line[T_LINE_MAX];
foreach (location, mLocations) foreach (location, mLocations)
{ {
std::cout << "# location.path: " << location->path << "" << std::endl;
line_number = 1; line_number = 1;
file = location->path + "/pending.data"; file = location->path + "/pending.data";
@ -208,8 +206,6 @@ int TDB2::loadCompleted (std::vector <Task>& tasks, Filter& filter)
char line[T_LINE_MAX]; char line[T_LINE_MAX];
foreach (location, mLocations) foreach (location, mLocations)
{ {
std::cout << "# location.path: " << location->path << "" << std::endl;
// TODO If the filter contains Status:x where x is not deleted or // TODO If the filter contains Status:x where x is not deleted or
// completed, then this can be skipped. // completed, then this can be skipped.

View file

@ -430,6 +430,15 @@ void Task::removeTag (const std::string& tag)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Task::validate () const void Task::validate () const
{ {
// Every task needs an ID.
/*
if (sequence[0] == 0)
throw std::string ("Every task needs an ID.");
*/
// TODO Every task needs an ID, entry and description attribute.
// TODO Verify until > due // TODO Verify until > due
// TODO Verify entry < until, due, start, end // TODO Verify entry < until, due, start, end
// TODO If name == "recur", then Duration::valid (value). // TODO If name == "recur", then Duration::valid (value).

View file

@ -33,7 +33,7 @@ Context context;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv) int main (int argc, char** argv)
{ {
UnitTest t (74); UnitTest t (67);
Att a; Att a;
t.notok (a.valid ("name"), "Att::valid name -> fail"); t.notok (a.valid ("name"), "Att::valid name -> fail");
@ -85,88 +85,70 @@ int main (int argc, char** argv)
t.is (a6.value_int (), 7, "Att::value_int set/get"); t.is (a6.value_int (), 7, "Att::value_int set/get");
t.is (a6.value (), "7", "Att::value 7"); t.is (a6.value (), "7", "Att::value 7");
// Att::addMod // Att::mod
bool good = true; bool good = true;
try {a6.addMod ("is");} catch (...) {good = false;} try {a6.mod ("is");} catch (...) {good = false;}
t.ok (good, "Att::addMod (is)"); t.ok (good, "Att::mod (is)");
good = true; good = true;
try {a6.addMod ("before");} catch (...) {good = false;} try {a6.mod ("before");} catch (...) {good = false;}
t.ok (good, "Att::addMod (before)"); t.ok (good, "Att::mod (before)");
good = true; good = true;
try {a6.addMod ("after");} catch (...) {good = false;} try {a6.mod ("after");} catch (...) {good = false;}
t.ok (good, "Att::addMod (after)"); t.ok (good, "Att::mod (after)");
good = true; good = true;
try {a6.addMod ("not");} catch (...) {good = false;} try {a6.mod ("none");} catch (...) {good = false;}
t.ok (good, "Att::addMod (not)"); t.ok (good, "Att::mod (none)");
good = true; good = true;
try {a6.addMod ("none");} catch (...) {good = false;} try {a6.mod ("any");} catch (...) {good = false;}
t.ok (good, "Att::addMod (none)"); t.ok (good, "Att::mod (any)");
good = true; good = true;
try {a6.addMod ("any");} catch (...) {good = false;} try {a6.mod ("over");} catch (...) {good = false;}
t.ok (good, "Att::addMod (any)"); t.ok (good, "Att::mod (over)");
good = true; good = true;
try {a6.addMod ("over");} catch (...) {good = false;} try {a6.mod ("under");} catch (...) {good = false;}
t.ok (good, "Att::addMod (over)"); t.ok (good, "Att::mod (under)");
good = true; good = true;
try {a6.addMod ("under");} catch (...) {good = false;} try {a6.mod ("first");} catch (...) {good = false;}
t.ok (good, "Att::addMod (under)"); t.ok (good, "Att::mod (first)");
good = true; good = true;
try {a6.addMod ("synth");} catch (...) {good = false;} try {a6.mod ("last");} catch (...) {good = false;}
t.ok (good, "Att::addMod (synth)"); t.ok (good, "Att::mod (last)");
good = true; good = true;
try {a6.addMod ("first");} catch (...) {good = false;} try {a6.mod ("isnt");} catch (...) {good = false;}
t.ok (good, "Att::addMod (first)"); t.ok (good, "Att::mod (isnt)");
good = true; good = true;
try {a6.addMod ("last");} catch (...) {good = false;} try {a6.mod ("has");} catch (...) {good = false;}
t.ok (good, "Att::addMod (last)"); t.ok (good, "Att::mod (has)");
good = true; good = true;
try {a6.addMod ("this");} catch (...) {good = false;} try {a6.mod ("contains");} catch (...) {good = false;}
t.ok (good, "Att::addMod (this)"); t.ok (good, "Att::mod (contains)");
good = true; good = true;
try {a6.addMod ("next");} catch (...) {good = false;} try {a6.mod ("hasnt");} catch (...) {good = false;}
t.ok (good, "Att::addMod (next)"); t.ok (good, "Att::mod (hasnt)");
good = true; good = true;
try {a6.addMod ("isnt");} catch (...) {good = false;} try {a6.mod ("startswith");} catch (...) {good = false;}
t.ok (good, "Att::addMod (isnt)"); t.ok (good, "Att::mod (startswith)");
good = true; good = true;
try {a6.addMod ("has");} catch (...) {good = false;} try {a6.mod ("endswith");} catch (...) {good = false;}
t.ok (good, "Att::addMod (has)"); t.ok (good, "Att::mod (endswith)");
good = true; good = true;
try {a6.addMod ("hasnt");} catch (...) {good = false;} try {a6.mod ("fartwizzle");} catch (...) {good = false;}
t.ok (good, "Att::addMod (hasnt)"); t.notok (good, "Att::mod (fartwizzle)");
good = true;
try {a6.addMod ("startswith");} catch (...) {good = false;}
t.ok (good, "Att::addMod (startswith)");
good = true;
try {a6.addMod ("endswith");} catch (...) {good = false;}
t.ok (good, "Att::addMod (endswith)");
good = true;
try {a6.addMod ("fartwizzle");} catch (...) {good = false;}
t.notok (good, "Att::addMod (fartwizzle)");
// Att::mods
std::vector <std::string> mods;
a6.mods (mods);
t.is (mods.size (), (size_t)18, "Att::mods () size == 18");
t.is (mods[0], "is", "Att::mods [0] == 'is'");
// Att::parse // Att::parse
Nibbler n (""); Nibbler n ("");
@ -260,12 +242,6 @@ int main (int argc, char** argv)
t.ok (good, "Att::parse (name.any:\"value\")"); t.ok (good, "Att::parse (name.any:\"value\")");
t.is (a7.composeF4 (), "name:\"value\"", "Att::composeF4 -> name:\"value\""); t.is (a7.composeF4 (), "name:\"value\"", "Att::composeF4 -> name:\"value\"");
n = Nibbler ("name.any.none:\"value\"");
good = true;
try {a7.parse (n);} catch (...) {good = false;}
t.ok (good, "Att::parse (name.any.none:\"value\")");
t.is (a7.composeF4 (), "name:\"value\"", "Att::composeF4 -> name:\"value\"");
n = Nibbler ("name.bogus:\"value\""); n = Nibbler ("name.bogus:\"value\"");
good = true; good = true;
try {a7.parse (n);} catch (...) {good = false;} try {a7.parse (n);} catch (...) {good = false;}