summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2016-06-25 15:50:08 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2016-06-25 15:50:08 +0100
commit8b921a1c5ad31fdc6c88b2a5e1f3b34782aa0142 (patch)
treef6caabff944eb0ba083c725882d4e7c0e5c68fdc
parentAdd missing CR (diff)
downloadicespider-8b921a1c5ad31fdc6c88b2a5e1f3b34782aa0142.tar.bz2
icespider-8b921a1c5ad31fdc6c88b2a5e1f3b34782aa0142.tar.xz
icespider-8b921a1c5ad31fdc6c88b2a5e1f3b34782aa0142.zip
Default parameter expressions
-rw-r--r--icespider/common/Jamfile.jam4
-rw-r--r--icespider/common/pathparts.cpp (renamed from icespider/core/paths.cpp)10
-rw-r--r--icespider/common/pathparts.h (renamed from icespider/core/paths.h)16
-rw-r--r--icespider/common/routes.ice9
-rw-r--r--icespider/compile/routeCompiler.cpp72
-rw-r--r--icespider/core/core.cpp2
-rw-r--r--icespider/core/irouteHandler.h2
-rw-r--r--icespider/unittests/testApp.cpp25
-rw-r--r--icespider/unittests/testCompile.cpp4
-rw-r--r--icespider/unittests/testRoutes.json24
10 files changed, 136 insertions, 32 deletions
diff --git a/icespider/common/Jamfile.jam b/icespider/common/Jamfile.jam
index 081ebd1..c06ff0c 100644
--- a/icespider/common/Jamfile.jam
+++ b/icespider/common/Jamfile.jam
@@ -1,6 +1,9 @@
+lib adhocutil : : : : <include>/usr/include/adhocutil ;
+
lib icespider-common :
[ glob-tree *.ice *.cpp : bin ]
:
+ <library>adhocutil
<library>..//pthread
<library>..//Ice
<library>..//IceUtil
@@ -8,5 +11,6 @@ lib icespider-common :
<library>..//pthread
<library>..//Ice
<library>..//IceUtil
+ <include>.
;
diff --git a/icespider/core/paths.cpp b/icespider/common/pathparts.cpp
index f4bad0e..d7581b3 100644
--- a/icespider/core/paths.cpp
+++ b/icespider/common/pathparts.cpp
@@ -1,5 +1,6 @@
-#include "paths.h"
+#include "pathparts.h"
#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/trim.hpp>
namespace ba = boost::algorithm;
@@ -12,7 +13,7 @@ namespace IceSpider {
for (auto pi = ba::make_split_iterator(relp, ba::first_finder("/", ba::is_equal())); pi != decltype(pi)(); ++pi) {
std::string pp(pi->begin(), pi->end());
if (pp.front() == '{' && pp.back() == '}') {
- parts.push_back(PathPartPtr(new PathParameter()));
+ parts.push_back(PathPartPtr(new PathParameter(pp)));
}
else {
parts.push_back(PathPartPtr(new PathLiteral(pp)));
@@ -38,6 +39,11 @@ namespace IceSpider {
return value == v;
}
+ PathParameter::PathParameter(const std::string & s) :
+ name(boost::algorithm::trim_copy_if(s, ispunct))
+ {
+ }
+
bool
PathParameter::matches(const std::string &) const
{
diff --git a/icespider/core/paths.h b/icespider/common/pathparts.h
index 0999593..0720af0 100644
--- a/icespider/core/paths.h
+++ b/icespider/common/pathparts.h
@@ -4,30 +4,34 @@
#include <vector>
#include <string>
#include <memory>
+#include <visibility.h>
namespace IceSpider {
-
- class PathPart {
+ class DLL_PUBLIC PathPart {
public:
virtual bool matches(const std::string &) const = 0;
};
typedef std::shared_ptr<PathPart> PathPartPtr;
- class PathLiteral : public PathPart {
+ class DLL_PUBLIC PathLiteral : public PathPart {
public:
PathLiteral(const std::string & v);
bool matches(const std::string &) const;
- private:
const std::string value;
};
- class PathParameter : public PathPart {
+ class DLL_PUBLIC PathParameter : public PathPart {
public:
+ PathParameter(const std::string &);
+
bool matches(const std::string &) const;
+
+ const std::string name;
};
- class Path {
+
+ class DLL_PUBLIC Path {
public:
typedef std::vector<PathPartPtr> PathParts;
diff --git a/icespider/common/routes.ice b/icespider/common/routes.ice
index 01bed51..0e64692 100644
--- a/icespider/common/routes.ice
+++ b/icespider/common/routes.ice
@@ -7,15 +7,20 @@ module UserIceSpider {
};
class Parameter {
string name;
- ParameterSource source;
+ ParameterSource source = URL;
optional(0) string key;
bool isOptional = false;
+ ["slicer:name:default"]
+ optional(1) string defaultExpr;
+
+ ["slicer:ignore"]
+ bool hasUserSource;
};
sequence<Parameter> Parameters;
class Route {
string name;
string path;
- HttpMethod method;
+ HttpMethod method = GET;
string operation;
Parameters params;
};
diff --git a/icespider/compile/routeCompiler.cpp b/icespider/compile/routeCompiler.cpp
index 9c6c59d..b28231e 100644
--- a/icespider/compile/routeCompiler.cpp
+++ b/icespider/compile/routeCompiler.cpp
@@ -1,4 +1,5 @@
#include "routeCompiler.h"
+#include <pathparts.h>
#include <slicer/slicer.h>
#include <slicer/modelPartsTypes.h>
#include <Slice/Preprocessor.h>
@@ -84,9 +85,21 @@ namespace IceSpider {
if (defined != r->params.end()) {
auto d = *defined;
if (!d->key) d->key = d->name;
- continue;
}
- r->params.push_back(new UserIceSpider::Parameter(p->name(), UserIceSpider::ParameterSource::URL, p->name(), false));
+ else {
+ r->params.push_back(new UserIceSpider::Parameter(p->name(), UserIceSpider::ParameterSource::URL, p->name(), false, IceUtil::Optional<std::string>(), false));
+ defined = --r->params.end();
+ }
+ auto d = *defined;
+ if (d->source == UserIceSpider::ParameterSource::URL) {
+ IceSpider::Path path(r->path);
+ d->hasUserSource = std::find_if(path.parts.begin(), path.parts.end(), [d](const auto & pp) {
+ if (auto par = dynamic_cast<PathParameter *>(pp.get())) {
+ return par->name == d->key;
+ }
+ return false;
+ }) != path.parts.end();
+ }
}
}
}
@@ -211,8 +224,15 @@ namespace IceSpider {
fprintbf(3, output, "%s() :\n", r->name);
fprintbf(4, output, "IceSpider::IRouteHandler(UserIceSpider::HttpMethod::%s, \"%s\")", methodName, r->path);
for (const auto & p : r->params) {
- fprintf(output, ",\n");
- fprintbf(4, output, "_pn_%s(\"%s\")", p->name, *p->key);
+ if (p->hasUserSource) {
+ fprintf(output, ",\n");
+ fprintbf(4, output, "_pn_%s(\"%s\")", p->name, *p->key);
+ }
+ if (p->defaultExpr) {
+ fprintf(output, ",\n");
+ fprintbf(4, output, "_pd_%s(%s)",
+ p->name, p->defaultExpr.get());
+ }
}
fprintf(output, "\n");
fprintbf(3, output, "{\n");
@@ -221,15 +241,23 @@ namespace IceSpider {
fprintbf(3, output, "{\n");
auto o = findOperation(r, units);
for (const auto & p : r->params) {
- auto ip = *std::find_if(o->parameters().begin(), o->parameters().end(), [p](const auto & ip) { return ip->name() == p->name; });
- fprintbf(4, output, "auto _p_%s(request->get%sParam<%s>(_pn_%s)",
- p->name, getEnumString(p->source), Slice::typeToString(ip->type()), p->name);
- if (!p->isOptional) {
- fprintbf(0, output, " /\n");
- fprintbf(5, output, " [this]() { return requiredParameterNotFound<%s>(\"%s\", _pn_%s); }",
- Slice::typeToString(ip->type()), getEnumString(p->source), p->name);
+ if (p->hasUserSource) {
+ auto ip = *std::find_if(o->parameters().begin(), o->parameters().end(), [p](const auto & ip) { return ip->name() == p->name; });
+ fprintbf(4, output, "auto _p_%s(request->get%sParam<%s>(_pn_%s)",
+ p->name, getEnumString(p->source), Slice::typeToString(ip->type()), p->name);
+ if (!p->isOptional) {
+ fprintbf(0, output, " /\n");
+ if (p->defaultExpr) {
+ fprintbf(5, output, " [this]() { return _pd_%s; }",
+ p->name);
+ }
+ else {
+ fprintbf(5, output, " [this]() { return requiredParameterNotFound<%s>(\"%s\", _pn_%s); }",
+ Slice::typeToString(ip->type()), getEnumString(p->source), p->name);
+ }
+ }
+ fprintbf(0, output, ");\n");
}
- fprintbf(0, output, ");\n");
}
fprintbf(4, output, "auto prx = getProxy<%s>(request);\n", proxyName);
if (o->returnsData()) {
@@ -239,7 +267,15 @@ namespace IceSpider {
fprintbf(4, output, "prx->%s(", operation);
}
for (const auto & p : o->parameters()) {
- fprintbf(output, "_p_%s, ", p->name());
+ auto rp = *std::find_if(r->params.begin(), r->params.end(), [p](const auto & rp) {
+ return rp->name == p->name();
+ });
+ if (rp->hasUserSource) {
+ fprintbf(output, "_p_%s, ", p->name());
+ }
+ else {
+ fprintbf(output, "_pd_%s, ", p->name());
+ }
}
fprintbf(output, "request->getContext())");
if (o->returnsData()) {
@@ -252,7 +288,15 @@ namespace IceSpider {
fprintbf(3, output, "}\n\n");
fprintbf(2, output, "private:\n");
for (const auto & p : r->params) {
- fprintbf(3, output, "const std::string _pn_%s;\n", p->name);
+ if (p->hasUserSource) {
+ fprintbf(3, output, "const std::string _pn_%s;\n", p->name);
+ }
+ if (p->defaultExpr) {
+ auto ip = *std::find_if(o->parameters().begin(), o->parameters().end(), [p](const auto & ip) { return ip->name() == p->name; });
+ fprintbf(3, output, "const %s _pd_%s;\n",
+ Slice::typeToString(ip->type()), p->name);
+
+ }
}
fprintbf(1, output, "};\n\n");
}
diff --git a/icespider/core/core.cpp b/icespider/core/core.cpp
index 9f87bda..5509580 100644
--- a/icespider/core/core.cpp
+++ b/icespider/core/core.cpp
@@ -51,7 +51,7 @@ namespace IceSpider {
if (!path.empty()) {
ba::split(pathparts, path, ba::is_any_of("/"), ba::token_compress_off);
}
- if (pathparts.size() > mroutes.size()) {
+ if (pathparts.size() >= mroutes.size()) {
// Not found error
return NULL;
}
diff --git a/icespider/core/irouteHandler.h b/icespider/core/irouteHandler.h
index 911c1b4..32513ae 100644
--- a/icespider/core/irouteHandler.h
+++ b/icespider/core/irouteHandler.h
@@ -3,7 +3,7 @@
#include "ihttpRequest.h"
#include "util.h"
-#include "paths.h"
+#include <pathparts.h>
#include <routes.h>
#include <plugins.h>
#include <visibility.h>
diff --git a/icespider/unittests/testApp.cpp b/icespider/unittests/testApp.cpp
index 1e9562b..b5af516 100644
--- a/icespider/unittests/testApp.cpp
+++ b/icespider/unittests/testApp.cpp
@@ -12,7 +12,7 @@ using namespace UserIceSpider;
BOOST_AUTO_TEST_CASE( testLoadConfiguration )
{
- BOOST_REQUIRE_EQUAL(4, AdHoc::PluginManager::getDefault()->getAll<IceSpider::IRouteHandler>().size());
+ BOOST_REQUIRE_EQUAL(6, AdHoc::PluginManager::getDefault()->getAll<IceSpider::IRouteHandler>().size());
}
BOOST_FIXTURE_TEST_SUITE(c, IceSpider::Core);
@@ -23,8 +23,8 @@ BOOST_AUTO_TEST_CASE( testCoreSettings )
BOOST_REQUIRE_EQUAL(4, routes[HttpMethod::GET].size());
BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::GET][0].size());
BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::GET][1].size());
- BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::GET][2].size());
- BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::GET][3].size());
+ BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::GET][2].size());
+ BOOST_REQUIRE_EQUAL(2, routes[HttpMethod::GET][3].size());
BOOST_REQUIRE_EQUAL(1, routes[HttpMethod::HEAD].size());
BOOST_REQUIRE_EQUAL(2, routes[HttpMethod::POST].size());
BOOST_REQUIRE_EQUAL(0, routes[HttpMethod::POST][0].size());
@@ -44,7 +44,7 @@ class TestRequest : public IceSpider::IHttpRequest {
path(p)
{
}
-
+
std::string getRequestPath() const override
{
return path;
@@ -108,6 +108,12 @@ BOOST_AUTO_TEST_CASE( testFindRoutes )
TestRequest requestGetItem(this, HttpMethod::GET, "/view/something/something");
BOOST_REQUIRE(findRoute(&requestGetItem));
+ TestRequest requestGetItemParam(this, HttpMethod::GET, "/item/something/1234");
+ BOOST_REQUIRE(findRoute(&requestGetItemParam));
+
+ TestRequest requestGetItemDefault(this, HttpMethod::GET, "/item/something");
+ BOOST_REQUIRE(findRoute(&requestGetItemDefault));
+
TestRequest requestGetItemLong(this, HttpMethod::GET, "/view/something/something/extra");
BOOST_REQUIRE(!findRoute(&requestGetItemLong));
@@ -167,6 +173,17 @@ BOOST_AUTO_TEST_CASE( testCallMethods )
process(&requestGetItem);
BOOST_REQUIRE_EQUAL(requestGetItem.output.str(), "200 OK\r\n\r\n{\"value\":\"withParams\"}");
+ TestRequest requestGetItemGiven(this, HttpMethod::GET, "/item/something/1234");
+ requestGetItemGiven.url["s"] = "something";
+ requestGetItemGiven.url["i"] = "1234";
+ process(&requestGetItemGiven);
+ BOOST_REQUIRE_EQUAL(requestGetItemGiven.output.str(), "200 OK\r\n\r\n{\"value\":\"withParams\"}");
+
+ TestRequest requestGetItemDefault(this, HttpMethod::GET, "/item/something");
+ requestGetItemDefault.url["s"] = "something";
+ process(&requestGetItemDefault);
+ BOOST_REQUIRE_EQUAL(requestGetItemDefault.output.str(), "200 OK\r\n\r\n{\"value\":\"withParams\"}");
+
TestRequest requestDeleteItem(this, HttpMethod::DELETE, "/some value");
requestDeleteItem.url["s"] = "some value";
process(&requestDeleteItem);
diff --git a/icespider/unittests/testCompile.cpp b/icespider/unittests/testCompile.cpp
index 4325c16..26fc458 100644
--- a/icespider/unittests/testCompile.cpp
+++ b/icespider/unittests/testCompile.cpp
@@ -28,7 +28,7 @@ BOOST_AUTO_TEST_CASE( testLoadConfiguration )
rc.applyDefaults(cfg, u);
BOOST_REQUIRE_EQUAL("common", cfg->name);
- BOOST_REQUIRE_EQUAL(4, cfg->routes.size());
+ BOOST_REQUIRE_EQUAL(6, cfg->routes.size());
BOOST_REQUIRE_EQUAL("index", cfg->routes[0]->name);
BOOST_REQUIRE_EQUAL("/", cfg->routes[0]->path);
@@ -85,7 +85,7 @@ BOOST_AUTO_TEST_CASE( testLoad )
BOOST_TEST_INFO(dlerror());
BOOST_REQUIRE(lib);
- BOOST_REQUIRE_EQUAL(4, AdHoc::PluginManager::getDefault()->getAll<IceSpider::IRouteHandler>().size());
+ BOOST_REQUIRE_EQUAL(6, AdHoc::PluginManager::getDefault()->getAll<IceSpider::IRouteHandler>().size());
// smoke test (block ensure dlclose dones't cause segfault)
{
auto route = AdHoc::PluginManager::getDefault()->get<IceSpider::IRouteHandler>("common::index");
diff --git a/icespider/unittests/testRoutes.json b/icespider/unittests/testRoutes.json
index b766f31..4ad8cc3 100644
--- a/icespider/unittests/testRoutes.json
+++ b/icespider/unittests/testRoutes.json
@@ -36,6 +36,30 @@
"source": "Body"
}
]
+ },
+ {
+ "name": "defaultItem",
+ "path": "/item/{s}",
+ "method": "GET",
+ "operation": "TestIceSpider.TestApi.withParams",
+ "params": [
+ {
+ "name": "i",
+ "default": "1234"
+ }
+ ]
+ },
+ {
+ "name": "itemWithDefault",
+ "path": "/item/{s}/{i}",
+ "method": "GET",
+ "operation": "TestIceSpider.TestApi.withParams",
+ "params": [
+ {
+ "name": "i",
+ "default": "1234"
+ }
+ ]
}
],
"slices": [