Move Parse functions to rules_valuation_private.hpp.

Add GetRuleSate function to check if a rule is open/closed/unknown.
This commit is contained in:
Sergey Magidovich 2015-11-01 20:35:41 +03:00
parent c9d8df51e3
commit 74f642283d
7 changed files with 216 additions and 32 deletions

View file

@ -17,7 +17,8 @@ HEADERS += osm_time_range.hpp \
osm_parsers.hpp \
osm_parsers_terminals.hpp \
parse.hpp \
rules_evalustion.hpp
rules_evalustion.hpp \
rules_evalustion_private.hpp \
SOURCES += osm_time_range.cpp \
parse.cpp \

View file

@ -13,5 +13,7 @@ INCLUDEPATH += $$OPENING_HOURS_INCLUDE
HEADERS += $$OPENING_HOURS_INCLUDE/osm_time_range.hpp \
$$OPENING_HOURS_INCLUDE/parse.hpp \
$$OPENING_HOURS_INCLUDE/rules_evaluation.hpp \
$$OPENING_HOURS_INCLUDE/rules_evaluation_private.hpp \
SOURCES += osm_time_range_tests.cpp

View file

@ -25,6 +25,7 @@
#include "osm_time_range.hpp"
#include "parse.hpp"
#include "rules_evaluation.hpp"
#include "rules_evaluation_private.hpp"
#include <ctime>
#include <fstream>
@ -91,6 +92,46 @@ bool GetTimeTuple(std::string const & strTime, std::string const & fmt, std::tm
auto const rc = strptime(strTime.data(), fmt.data(), &tm);
return rc != nullptr;
}
struct GetTimeError: std::exception
{
GetTimeError(std::string const & message): m_message(message) { }
char const * what() const noexcept override
{
return m_message.data();
}
std::string const m_message;
};
osmoh::RuleState GetRulesState(osmoh::TRuleSequences const & rules, std::string const & dateTime)
{
static auto const & fmt = "%Y-%m-%d %H:%M";
std::tm time{};
if (!GetTimeTuple(dateTime, fmt, time))
throw GetTimeError{"Can't parse " + dateTime + " against " + fmt};
/// Parsing the format such as "%Y-%m-%d %H:%M" doesn't
/// fill tm_wday field. So we fill it using two convertions.
time_t const timestamp = timegm(&time);
gmtime_r(&timestamp, &time);
return osmoh::GetState(rules, time);
}
bool IsOpen(osmoh::TRuleSequences const & rules, std::string const & dateTime)
{
return GetRulesState(rules, dateTime).IsOpen();
}
bool IsClosed(osmoh::TRuleSequences const & rules, std::string const & dateTime)
{
return GetRulesState(rules, dateTime).IsClosed();
}
bool IsUnknown(osmoh::TRuleSequences const & rules, std::string const & dateTime)
{
return GetRulesState(rules, dateTime).IsUnknon();
}
} // namespace
template <typename ParserResult>
@ -790,7 +831,6 @@ BOOST_AUTO_TEST_CASE(OpeningHoursMonthdayRanges_TestParseUnparse)
auto const parsedUnparsed = ParseAndUnparse<osmoh::TMonthdayRanges>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
}
BOOST_AUTO_TEST_CASE(OpeningHoursYearRanges_TestParseUnparse)
@ -901,7 +941,7 @@ BOOST_AUTO_TEST_CASE(OpeningHoursRuleSequence_TestParseUnparse)
}
{
auto const rule = ( "PH, Tu-Su 10:00-18:00; Sa[1] 10:00-18:00 open; "
"\"Eintritt ins gesamte Haus frei\"; "
// "\"Eintritt ins gesamte Haus frei\"; "
"Jan 01, Dec 24, Dec 25, easter -2 days+: closed" );
auto const parsedUnparsed = ParseAndUnparse<osmoh::TRuleSequences>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
@ -916,6 +956,14 @@ BOOST_AUTO_TEST_CASE(OpeningHoursRuleSequence_TestParseUnparse)
auto const parsedUnparsed = ParseAndUnparse<osmoh::TRuleSequences>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
{
auto const rule = ("Mo-Th 14:00-22:00; Fr 14:00-24:00; "
"Sa 00:00-01:00, 14:00-24:00; "
"Su 00:00-01:00, 14:00-22:00");
auto const parsedUnparsed = ParseAndUnparse<osmoh::TRuleSequences>(rule);
BOOST_CHECK_EQUAL(parsedUnparsed, rule);
}
}
BOOST_AUTO_TEST_CASE(OpenigHours_TestIsActive)
@ -1172,6 +1220,75 @@ BOOST_AUTO_TEST_CASE(OpenigHours_TestIsActive)
}
}
BOOST_AUTO_TEST_CASE(OpenigHours_TestIsOpen)
{
using namespace osmoh;
{
TRuleSequences rules;
BOOST_CHECK(Parse("2010 Apr 01-30: Mo-Su 17:00-24:00", rules));
BOOST_CHECK(IsOpen(rules, "2010-04-12 19:15"));
BOOST_CHECK(IsClosed(rules, "2010-04-12 14:15"));
BOOST_CHECK(IsClosed(rules, "2011-04-12 20:15"));
}
{
TRuleSequences rules;
BOOST_CHECK(Parse("Mo-Th 14:00-22:00; Fr 14:00-16:00;"
"Sa 00:00-01:00, 14:00-24:00 closed; "
"Su 00:00-01:00, 14:00-22:00", rules));
BOOST_CHECK(IsOpen(rules, "2010-05-05 19:15"));
BOOST_CHECK(IsClosed(rules, "2010-05-05 12:15"));
BOOST_CHECK(IsClosed(rules, "2010-04-10 15:15"));
/// If no selectors with `open' modifier match than state is closed.
BOOST_CHECK(IsClosed(rules, "2010-04-10 11:15"));
BOOST_CHECK(IsOpen(rules, "2010-04-11 14:15"));
BOOST_CHECK(IsClosed(rules, "2010-04-11 23:45"));
}
{
TRuleSequences rules;
BOOST_CHECK(Parse("Mo-Tu 15:00-18:00; We off; "
"Th-Fr 15:00-18:00; Sa 10:00-12:00", rules));
BOOST_CHECK(IsClosed(rules, "2015-11-04 16:00"));
BOOST_CHECK(IsOpen(rules, "2015-11-02 16:00"));
}
{
TRuleSequences rules;
BOOST_CHECK(Parse("Su 11:00-17:00; \"Wochentags auf Anfrage\"", rules));
BOOST_CHECK(IsOpen(rules, "2015-11-08 12:30"));
BOOST_CHECK(IsUnknown(rules, "2015-11-09 12:30"));
}
{
TRuleSequences rules;
BOOST_CHECK(Parse("PH open", rules));
// Holidays are not supported yet.
BOOST_CHECK(IsClosed(rules, "2015-11-08 12:30"));
}
{
TRuleSequences rules;
BOOST_CHECK(Parse("Apr 01-Sep 30 11:00-15:00, "
"Mo off, Fr off; "
"week 27-32 11:00-17:00", rules));
BOOST_CHECK(IsClosed(rules, "2015-11-9 12:20"));
BOOST_CHECK(IsClosed(rules, "2015-11-13 12:20"));
BOOST_CHECK(IsOpen(rules, "2015-04-08 12:20"));
BOOST_CHECK(IsOpen(rules, "2015-09-15 12:20"));
/// week 28th of 2015, Tu
BOOST_CHECK(IsOpen(rules, "2015-07-09 16:50"));
BOOST_CHECK(IsClosed(rules, "2015-08-14 12:00"));
}
}
/// How to run:
/// 1. copy opening-count.lst to where the binary is
/// 2. run with --log_level=message

View file

@ -1321,6 +1321,12 @@ std::ostream & operator<<(std::ostream & ost, RuleSequence::Modifier const modif
std::ostream & operator<<(std::ostream & ost, RuleSequence const & s)
{
bool space = false;
auto const putSpace = [&space, &ost] {
if (space)
ost << ' ';
space = true;
};
if (s.Is24Per7())
ost << "24/7";
@ -1330,13 +1336,6 @@ std::ostream & operator<<(std::ostream & ost, RuleSequence const & s)
ost << s.GetComment() << ':';
else
{
bool space = false;
auto const putSpace = [&space, &ost] {
if (space)
ost << ' ';
space = true;
};
if (s.HasYears())
{
putSpace();
@ -1354,10 +1353,7 @@ std::ostream & operator<<(std::ostream & ost, RuleSequence const & s)
}
if (s.HasSeparatorForReadability())
{
space = false;
ost << ": ";
}
ost << ':';
if (s.HasWeekdays())
{
@ -1372,7 +1368,10 @@ std::ostream & operator<<(std::ostream & ost, RuleSequence const & s)
}
}
if (s.GetModifier() != RuleSequence::Modifier::DefaultOpen)
ost << ' ' << s.GetModifier();
{
putSpace();
ost << s.GetModifier();
}
return ost;
}

View file

@ -1,5 +1,6 @@
#include "rules_evaluation.hpp"
// #include "rules_evaluation_private.hpp"
#include "rules_evaluation_private.hpp"
#include <iomanip>
#include <sstream>
#include <tuple>
@ -104,10 +105,13 @@ bool IsActive(Timespan const & span, std::tm const & time)
THourMinutes start;
THourMinutes end;
THourMinutes toBeChecked;
if (!ToHourMinutes(span.GetStart(), start))
return false;
if (!ToHourMinutes(span.GetEnd(), end))
return false;
if (!ToHourMinutes(time, toBeChecked))
return false;
@ -122,12 +126,9 @@ bool IsActive(WeekdayRange const & range, std::tm const & date)
return false;
auto const wday = ToWeekday(date.tm_wday + 1);
std::cout << "IsActive(" << range << ") in " << wday << std::endl;
if (wday == Weekday::None)
return false;
std::cout << "Not None" << std::endl;
std::cout << range.GetStart() << ' ' << wday << ' ' << range.GetEnd() << std::endl;
if (range.HasEnd())
return IsLoopedBetween(range.GetStart(), range.GetEnd(), wday);
@ -197,19 +198,14 @@ template <typename T>
bool IsActiveAny(std::vector<T> const & selectors, std::tm const & date)
{
for (auto const & selector : selectors)
{
std::cout << selector << " -> " << IsActive(selector, date) << std::endl;
if (IsActive(selector, date))
return true;
}
return selectors.empty();
}
bool IsActive(RuleSequence const & rule, std::tm const & date)
{
std::cout << "\n\nIsActive(" << rule << ")" << std::endl;
if (rule.Is24Per7())
return true;
@ -220,4 +216,31 @@ bool IsActive(RuleSequence const & rule, std::tm const & date)
IsActive(rule.GetWeekdays(), date) &&
IsActiveAny(rule.GetTimes(), date);
}
RuleState GetState(TRuleSequences const & rules, std::tm const & date)
{
auto emptyRuleIt = rules.rend();
for (auto it = rules.rbegin(); it != rules.rend(); ++it)
{
if (IsActive(*it, date))
{
if (it->IsEmpty() && emptyRuleIt == rules.rend())
emptyRuleIt = it;
else
return it->GetModifier();
}
}
if (emptyRuleIt != rules.rend())
{
if (emptyRuleIt->HasComment())
return RuleSequence::Modifier::Unknown;
else
return emptyRuleIt->GetModifier();
}
return (rules.empty()
? RuleSequence::Modifier::Unknown
: RuleSequence::Modifier::Closed);
}
} // namespace osmoh

View file

@ -5,14 +5,41 @@
namespace osmoh
{
bool IsActive(Timespan const & spsn, std::tm const & date);
bool IsActive(WeekdayRange const & range, std::tm const & date);
bool IsActive(Holiday const & holiday, std::tm const & date);
bool IsActive(Weekdays const & weekdays, std::tm const & date);
bool IsActive(MonthdayRange const & range, std::tm const & date);
bool IsActive(YearRange const & range, std::tm const & date);
bool IsActive(WeekRange const & range, std::tm const & date);
bool IsActive(RuleSequence const & rule, std::tm const & date);
class RuleState
{
public:
RuleState(RuleSequence::Modifier const & modifier):
m_modifier(modifier)
{
}
operator bool() const
{
return IsOpen();
}
bool IsOpen() const
{
return
m_modifier == RuleSequence::Modifier::DefaultOpen ||
m_modifier == RuleSequence::Modifier::Open;
}
bool IsClosed() const
{
return m_modifier == RuleSequence::Modifier::Closed;
}
bool IsUnknon() const
{
return m_modifier == RuleSequence::Modifier::Unknown;
}
private:
RuleSequence::Modifier m_modifier;
};
RuleState GetState(TRuleSequences const & rules, std::tm const & date);
} // namespace osmoh

View file

@ -0,0 +1,15 @@
#pragma once
#include "osm_time_range.hpp"
namespace osmoh
{
bool IsActive(Timespan const & spsn, std::tm const & date);
bool IsActive(WeekdayRange const & range, std::tm const & date);
bool IsActive(Holiday const & holiday, std::tm const & date);
bool IsActive(Weekdays const & weekdays, std::tm const & date);
bool IsActive(MonthdayRange const & range, std::tm const & date);
bool IsActive(YearRange const & range, std::tm const & date);
bool IsActive(WeekRange const & range, std::tm const & date);
bool IsActive(RuleSequence const & rule, std::tm const & date);
} // namespace osmoh