|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r58489 - sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/utility
From: lists.drrngrvy_at_[hidden]
Date: 2009-12-22 10:06:43
Author: drrngrvy
Date: 2009-12-22 10:06:42 EST (Tue, 22 Dec 2009)
New Revision: 58489
URL: http://svn.boost.org/trac/boost/changeset/58489
Log:
Added utility class for using Google's cTemplate (for HTML, JSON, etc. templates).
Added:
sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/utility/stencil.hpp (contents, props changed)
Added: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/utility/stencil.hpp
==============================================================================
--- (empty file)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/utility/stencil.hpp 2009-12-22 10:06:42 EST (Tue, 22 Dec 2009)
@@ -0,0 +1,345 @@
+// -- stencil.hpp --
+//
+// Copyright (c) Darren Garvey 2009.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+//
+////////////////////////////////////////////////////////////////
+//
+// A utility class for using Google's cTemplate.
+//
+// Note: requires ctemplate: http://code.google.com/p/google-ctemplate/
+//
+
+#ifndef BOOST_CGI_UTILITY_STENCIL_HPP_INCLUDED_20091222_
+#define BOOST_CGI_UTILITY_STENCIL_HPP_INCLUDED_20091222_
+
+#include <boost/cgi/common/response.hpp>
+#include <ctemplate/template.h>
+
+namespace stencils {
+
+class include_error
+ : public std::logic_error
+{
+public:
+ template<typename Str>
+ include_error(Str const& section_name, Str const& filename)
+ : std::logic_error(
+ "Section or file name empty in stencil::include,"
+ " with section_name = " + section_name + " and"
+ " filename = " + filename)
+ {}
+};
+
+
+/// A class used to represent a section in the stencil.
+class section
+{
+public:
+ typedef std::string string_type;
+
+ section() {}
+ section(
+ string_type const& name,
+ string_type const& filename = ""
+ )
+ : name(name)
+ , filename(filename)
+ {
+ }
+
+ string_type name;
+ string_type filename;
+};
+
+/// A lightweight wrapper around a ctemplate::TemplateDictionary.
+class dictionary
+{
+public:
+ typedef ctemplate::TemplateDictionary impl_type;
+ typedef std::string string_type;
+ typedef dictionary self_type;
+
+ dictionary() {}
+ dictionary(impl_type* impl)
+ : impl(impl)
+ {
+ }
+
+ /// Set the varible `name` to `value` in the stencil.
+ /**
+ * @param name The name of the variable. Use {{name}} in the stencil.
+ * @param value The value, can be any type that is supported by
+ * boost::lexical_cast. See the docs for lexical_cast:
+ * http://www.boost.org/libs/lexical_cast
+ */
+ template<typename T>
+ self_type& set(string_type const& name, T value)
+ {
+ impl->SetValue(name, boost::lexical_cast<string_type>(value));
+ return *this;
+ }
+
+ /// Set the varible `name` to `value` in the stencil.
+ template<>
+ self_type& set(string_type const& name, string_type const& value)
+ {
+ impl->SetValue(name, value);
+ return *this;
+ }
+
+ /// Set a variable and show a section in one go.
+ template<typename T>
+ self_type& set(string_type const& name, T value, section const& sec)
+ {
+ impl->SetValueAndShowSection(
+ name,
+ boost::lexical_cast<string_type>(value),
+ sec.name
+ );
+ return *this;
+ }
+
+ /// Set a variable and show a section in one go.
+ template<>
+ self_type& set(
+ string_type const& name,
+ string_type const& value,
+ section const& sec
+ )
+ {
+ impl->SetValueAndShowSection(name, value, sec.name);
+ return *this;
+ }
+
+ /// Show a section.
+ self_type& show(string_type const& section_name)
+ {
+ impl->ShowSection(section_name);
+ return *this;
+ }
+
+ /// Include a file into the stencil.
+ /**
+ * @return dictionary The returned sub-dictionary is used to set fields in
+ * an included stencil.
+ *
+ * @param section_name The name of the section, and of the marker in
+ * the stencil. Add {{>section_name}} into the
+ * stencil to include a file's contents.
+ * @param filename The name of the file to include. This must be set.
+ */
+ dictionary include(
+ string_type const& section_name,
+ string_type const& filename
+ )
+ {
+ if (section_name.empty() || filename.empty())
+ throw stencils::include_error(section_name, filename);
+ dictionary d;
+ d.impl = impl->AddIncludeDictionary(section_name);
+ d.impl->SetFilename(filename);
+ return d;
+ }
+
+ /// Include a file into the stencil.
+ /**
+ * @return dictionary The returned sub-dictionary is used to set fields in
+ * an included stencil.
+ *
+ * @param section The section to include. Be sure to set *both* the
+ * section name and filename first.
+ */
+ dictionary include(section const& sec)
+ {
+ if (sec.name.empty() || sec.filename.empty())
+ throw stencils::include_error(sec.name, sec.filename);
+ dictionary d;
+ d.impl = impl->AddIncludeDictionary(sec.name);
+ d.impl->SetFilename(sec.filename);
+ return d;
+ }
+
+ /// Add a section into the stencil.
+ dictionary add(section const& sec)
+ {
+ dictionary d;
+ d.impl = impl->AddSectionDictionary(sec.name);
+ return d;
+ }
+
+ /// Add a section into the stencil.
+ dictionary add(string_type const& section_name)
+ {
+ dictionary d;
+ d.impl = impl->AddSectionDictionary(section_name);
+ return d;
+ }
+
+ impl_type* impl;
+};
+
+}
+
+namespace boost { namespace cgi { namespace common {
+
+class stencil
+ : public boost::cgi::common::response
+{
+public:
+ typedef stencil self_type;
+ typedef boost::cgi::common::response base_type;
+ typedef ctemplate::Template stencil_type;
+ typedef ctemplate::TemplateDictionary impl_type;
+ typedef stencils::section section;
+ typedef stencils::dictionary dictionary;
+
+ enum strip
+ {
+ do_not_strip = ctemplate::DO_NOT_STRIP,
+ strip_blank_lines = ctemplate::STRIP_BLANK_LINES,
+ strip_whitespace = ctemplate::STRIP_WHITESPACE
+ };
+
+ stencil(impl_type* parent_dict)
+ : dict(parent_dict->MakeCopy("response"))
+ {
+ }
+
+ stencil(string_type const& root_dir = "")
+ : dict(new impl_type("response"))
+ {
+ if (!root_dir.empty())
+ ctemplate::Template::SetTemplateRootDirectory(root_dir);
+ }
+
+ /// Get the implementation type of the template.
+ impl_type& impl() { return *dict; }
+
+ bool expand(
+ string_type const& template_name,
+ enum strip strip_option = strip_blank_lines
+ )
+ {
+ // Save the data already stored in the response.
+ string_type content(str());
+ // Clear the response body (but not headers).
+ clear(false);
+
+ // Get hold of the template to output.
+ tmpl = ctemplate::Template::GetTemplate(
+ template_name,
+ (ctemplate::Strip)strip_option
+ );
+
+ if (!tmpl)
+ return false;
+
+ // Add the response content back into the template.
+ set("content", content);
+
+ // Expand the template and write it to the response.
+ string_type body;
+ tmpl->Expand(&body, dict.get());
+ write(body);
+
+ // All ok.
+ return true;
+ }
+
+ dictionary include(
+ string_type const& section_name,
+ string_type const& filename
+ )
+ {
+ dictionary d;
+ d.impl = dict->AddIncludeDictionary(section_name);
+ d.impl->SetFilename(filename);
+ return d;
+ }
+
+ dictionary include(section const& sec)
+ {
+ dictionary d;
+ d.impl = dict->AddIncludeDictionary(sec.name);
+ d.impl->SetFilename(sec.filename);
+ return d;
+ }
+
+ dictionary add(section const& sec)
+ {
+ dictionary d;
+ d.impl = dict->AddSectionDictionary(sec.name);
+ return d;
+ }
+
+ dictionary add(string_type const& section_name)
+ {
+ dictionary d;
+ d.impl = dict->AddSectionDictionary(section_name);
+ return d;
+ }
+
+ /// Set the varible `name` to `value` in the stencil.
+ /**
+ * @param name The name of the variable. Use {{name}} in the stencil.
+ * @param value The value, can be any type that is supported by
+ * boost::lexical_cast. See the docs for lexical_cast:
+ * http://www.boost.org/libs/lexical_cast
+ */
+ template<typename T>
+ self_type& set(string_type const& name, T value)
+ {
+ dict->SetValue(name, boost::lexical_cast<string_type>(value));
+ return *this;
+ }
+
+ /// Set the varible `name` to `value` in the stencil.
+ template<>
+ self_type& set(string_type const& name, string_type const& value)
+ {
+ dict->SetValue(name, value);
+ return *this;
+ }
+
+ /// Set a variable and show a section in one go.
+ template<typename T>
+ self_type& set(string_type const& name, T value, section const& sec)
+ {
+ dict->SetValueAndShowSection(
+ name,
+ boost::lexical_cast<string_type>(value),
+ sec.name
+ );
+ return *this;
+ }
+
+ /// Set a variable and show a section in one go.
+ template<>
+ self_type& set(
+ string_type const& name,
+ string_type const& value,
+ section const& sec
+ )
+ {
+ dict->SetValueAndShowSection(name, value, sec.name);
+ return *this;
+ }
+
+ /// Show a section.
+ self_type& show(string_type const& section_name)
+ {
+ dict->ShowSection(section_name);
+ return *this;
+ }
+
+ stencil_type* tmpl;
+ boost::scoped_ptr<impl_type> dict;
+ bool expanded;
+};
+
+} } } // namespace boost::cgi::common
+
+#endif // BOOST_CGI_UTILITY_STENCIL_HPP_INCLUDED_20091222_
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk