Browse Source

Added support of using call with a class form a different view as plugin

master
Artyom Beilis 8 years ago
parent
commit
4afb2bdb02
8 changed files with 233 additions and 36 deletions
  1. +15
    -2
      CMakeLists.txt
  2. +43
    -26
      bin/cppcms_tmpl_cc
  3. +43
    -0
      cppcms/views_pool.h
  4. +45
    -6
      src/views_pool.cpp
  5. +10
    -0
      tests/tc_plugin.tmpl
  6. +41
    -2
      tests/tc_skin.tmpl
  7. +35
    -0
      tests/tc_test.cpp
  8. +1
    -0
      tests/tc_test_content.h

+ 15
- 2
CMakeLists.txt View File

@@ -616,6 +616,18 @@ add_custom_command(
${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc
${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin.tmpl)

add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tc_plugin.cpp
COMMAND ${PYTHON} ${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc
-o ${CMAKE_CURRENT_BINARY_DIR}/tc_plugin.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_plugin.tmpl
DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/tc_sep_skin.h
${CMAKE_CURRENT_SOURCE_DIR}/bin/cppcms_tmpl_cc
${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_skin.tmpl
${CMAKE_CURRENT_SOURCE_DIR}/tests/tc_plugin.tmpl
)




@@ -638,14 +650,15 @@ if(NOT DISABLE_SHARED)
COMPILE_DEFINITIONS "${SKIN3_DEFS}")
target_link_libraries(skin3 ${CPPCMS_LIB})

foreach(SKIN tc_skin_a tc_skin_b tc_skin tc_sep_skin_a tc_sep_skin_b tc_sep_skin)
foreach(SKIN tc_skin_a tc_skin_b tc_skin tc_sep_skin_a tc_sep_skin_b tc_sep_skin tc_plugin)
add_library(${SKIN} SHARED ${CMAKE_CURRENT_BINARY_DIR}/${SKIN}.cpp)
target_link_libraries(${SKIN} ${CPPCMS_LIB})
if(IS_WINDOWS)
set_target_properties(${SKIN} PROPERTIES COMPILE_DEFINITIONS DLL_EXPORT)
endif()
endforeach()
target_link_libraries(tc_plugin tc_sep_skin)

add_library(plugin SHARED tests/test_plugin_so.cpp)
target_link_libraries(plugin ${CPPCMS_LIB})
if(IS_WINDOWS)


+ 43
- 26
bin/cppcms_tmpl_cc View File

@@ -288,7 +288,7 @@ def make_ident(val):
else:
return "content." + val

def print_using_block_start(class_name,variable_name,content_name):
def print_using_block_start(class_name,variable_name,content_name,temp_and_view=None):
global output_template
if content_name:
content=make_ident(content_name)
@@ -299,19 +299,31 @@ def print_using_block_start(class_name,variable_name,content_name):
output_template(r'{')
if guard:
output_template(r' cppcms::base_content::app_guard _g(%s,content);' % content);
output_template(r' %s %s(out(),%s);' % ( class_name, variable_name, content));
if temp_and_view:
output_template(r' cppcms::views::view_lock _vl(%s,out(),%s); %s &%s = _vl.use_view<%s>();' % ( temp_and_view, content, class_name, variable_name, class_name));
else:
output_template(r' %s %s(out(),%s);' % ( class_name, variable_name, content));
def print_using_block_end():
global output_template
output_template('}')

class using_block:
pattern=r'^<%\s*using\s+(?P<class>(?:\w+::)*\w+)(?:\s+with\s+(?P<content>' + variable_match + r'))?\s+as\s+(?P<name>[a-zA-Z_]\w*)\s*%>$'
pattern=r'^<%\s*using\s+(?P<class>(?:\w+::)*\w+)(?:\s+with\s+(?P<content>' + variable_match + r'))?\s+as\s+(?P<name>[a-zA-Z_]\w*)' \
+ r'(?P<from>\s+from' \
+ r'(\s*(?P<fst_str>'+ str_match +r')|(?:\s+(?P<fst_var>' + variable_match + r')))' \
+ r'(\s*,\s*((?P<snd_str>'+ str_match +r')|(?P<snd_var>' + variable_match + r')))?' \
+ r')?' \
+ '\s*%>$'
basic_pattern = 'using'
basic_name = 'using'
type='using'
def use(self,m):
print_using_block_start(m.group('class'),m.group('name'),m.group('content'))
if m.group('from'):
temp_and_view = get_render_names(m);
else:
temp_and_view = None
print_using_block_start(m.group('class'),m.group('name'),m.group('content'),temp_and_view)
global stack
stack.append(self)
def on_end(self):
@@ -669,6 +681,31 @@ class form_block:
def on_end(self):
self.format_input(self.command_type,self.ident)

def get_render_names(m):
first_str = m.group('fst_str')
first_var = m.group('fst_var')
if first_var:
first = make_ident(first_var)
else:
first = first_str
second_str = m.group('snd_str')
second_var = m.group('snd_var')
if second_var:
second = make_ident(second_var)
else:
second = second_str

if first and second:
template_name = first
view_name = second
else:
global namespace_name
template_name = '"' + namespace_name + '"'
view_name = first;
return template_name + ', ' + view_name

class render_block:
pattern=r'^<%\s*render\s+' \
+ r'((?P<fst_str>'+ str_match +r')|(?P<fst_var>' + variable_match + r'))' \
@@ -685,34 +722,14 @@ class render_block:
content = 'content';
guard=False
first_str = m.group('fst_str')
first_var = m.group('fst_var')
if first_var:
first = make_ident(first_var)
else:
first = first_str
second_str = m.group('snd_str')
second_var = m.group('snd_var')
if second_var:
second = make_ident(second_var)
else:
second = second_str

if first and second:
template_name = first
view_name = second
else:
global namespace_name
template_name = '"' + namespace_name + '"'
view_name = first;
temp_and_view = get_render_names(m);
output_template('{')

if guard:
output_template(r'cppcms::base_content::app_guard _g(%s,content);' % content)

output_template(r'cppcms::views::pool::instance().render(%s,%s,out(),%s);' % (template_name,view_name,content))
output_template(r'cppcms::views::pool::instance().render(%s,out(),%s);' % (temp_and_view,content))

output_template('}')



+ 43
- 0
cppcms/views_pool.h View File

@@ -113,6 +113,43 @@ namespace cppcms {
std::string name_;
booster::hold_ptr<data> d;
};
///
/// \brief A class that allows to use the view withing the internal lock used inside pool class
///
/// It is similar in its operation in creating the view class similarly to pool::render() but
/// not calling base_view::render member function.
///
/// It is used with `<% using ... from ... %>` CppCMS template
///
/// \ver{v1_2}
class CPPCMS_API view_lock : public booster::noncopyable {
public:
///
/// Create a view and lock pool's internal lock
///
view_lock(std::string const &skin,std::string const &template_name,std::ostream &out,base_content &content);
///
/// Delete the view and unlock the pool's lock
///
~view_lock();
///
/// Shortcut to dynamic_cast<View &>(view())
///
template<typename View>
View &use_view()
{
return dynamic_cast<View &>(view());
}
///
/// Get the underlying view object
///
base_view &view();
private:
struct _data;
booster::hold_ptr<base_view> view_;
booster::hold_ptr<_data> d;
};

///
/// \brief This is a singleton object that holds all views in the process. Any view
@@ -164,6 +201,12 @@ namespace cppcms {
static pool &instance();
private:
friend class view_lock;
void lock();
void unlock();

// called on locked object
base_view *create_view(std::string const &skin,std::string const &template_name,std::ostream &out,base_content &content);
pool();
~pool();



+ 45
- 6
src/views_pool.cpp View File

@@ -130,9 +130,8 @@ void pool::remove(generator const &g)
d->generators.erase(name);
}

void pool::render(std::string const &skin,std::string const &template_name,std::ostream &out,base_content &content)
base_view *pool::create_view(std::string const &skin,std::string const &template_name,std::ostream &out,base_content &content)
{
booster::shared_lock<booster::recursive_shared_mutex> guard(d->lock);
data::generators_type::iterator s=d->generators.find(skin);
if(s==d->generators.end())
throw cppcms_error("cppcms::views::pool: no such skin:" + skin);
@@ -143,11 +142,51 @@ void pool::render(std::string const &skin,std::string const &template_name,std::
if(t==reg_skin.end())
throw cppcms_error("cppcms::view::pool: no suck view:" + template_name + " is registered for skin: " + skin);

std::auto_ptr<base_view> v;
v = t->second->create(template_name,out,&content);
if(!v.get())
throw cppcms_error("cppcms::views::pool: no such view " + template_name + " in the skin " + skin);
return v.release();
}

void pool::lock()
{
d->lock.shared_lock();
}
void pool::unlock()
{
d->lock.unlock();
}

struct view_lock::_data {};
view_lock::view_lock(std::string const &skin,std::string const &template_name,std::ostream &out,base_content &content)
{
pool &p = pool::instance();
p.lock();
try {
view_.reset(p.create_view(skin,template_name,out,content));
}
catch(...) {
p.unlock();
throw;
}
}
view_lock::~view_lock()
{
view_.reset();
pool::instance().unlock();
}

base_view &view_lock::view()
{
return *view_;
}

void pool::render(std::string const &skin,std::string const &template_name,std::ostream &out,base_content &content)
{
booster::shared_lock<booster::recursive_shared_mutex> guard(d->lock);
{
std::auto_ptr<base_view> v;
v = t->second->create(template_name,out,&content);
if(!v.get())
throw cppcms_error("cppcms::views::pool: no such view " + template_name + " in the skin " + skin);
booster::hold_ptr<base_view> v(create_view(skin,template_name,out,content));
v->render();
}
}


+ 10
- 0
tests/tc_plugin.tmpl View File

@@ -0,0 +1,10 @@
<% c++ #include "tc_sep_skin.h" %>
<% skin plugin %>
<% view master_plugin uses data::master extends tc_skin::master_api %>
<% template m1() %>plugin::master_plugin::m1 <%= text %><% end %>
<% end view %>

<% view helper_plugin uses data::helper extends tc_skin::helper_api %>
<% template h1() %>plugin::helper_plugin::h1 <%= x %><% end %>
<% end view %>
<% end skin %>

+ 41
- 2
tests/tc_skin.tmpl View File

@@ -216,8 +216,47 @@ TBD
<% include show_x(h.y) using helper_helper with h %>
<% include show_y(h.x) using helper_helper with h %>
<% include show_integer() using helper_master %>
<% end %>
<% end %>
<% end template %>
<% end view %>

<% view master_api uses data::master %>
<% template m1() %><% end %>
<% end view %>

<% view helper_api uses data::helper %>
<% template h1() %><% end %>
<% end view %>

<% view master_plugin uses data::master extends master_api %>
<% template m1() %>skin::master_plugin::m1 <%= text %><% end %>
<% end view %>

<% view helper_plugin uses data::helper extends helper_api %>
<% template h1() %>skin::helper_plugin::h1 <%= x %><% end %>
<% end view %>

<% view test_master_plugin uses data::master %>
<% template render() %>
<% using master_api as m from "master_plugin" %><% include m1() from m %><% end using %>
<% using master_api as m from name1 %><% include m1() from m %><% end using %>
<% using master_api as m from "plugin","master_plugin" %><% include m1() from m %><% end using %>
<% using master_api as m from "plugin",name1 %><% include m1() from m %><% end using %>
<% using master_api as m from skin1,"master_plugin" %><% include m1() from m %><% end using %>
<% using master_api as m from skin1,name1 %><% include m1() from m %><% end using %>
<% end template %>
<% end view %>

<% view test_helper_plugin uses data::master %>
<% template render() %>
<% using helper_api with h as m from "helper_plugin" %><% include h1() from m %><% end using %>
<% using helper_api with h as m from name1 %><% include h1() from m %><% end using %>
<% using helper_api with h as m from "plugin","helper_plugin" %><% include h1() from m %><% end using %>
<% using helper_api with h as m from "plugin",name1 %><% include h1() from m %><% end using %>
<% using helper_api with h as m from skin1,"helper_plugin" %><% include h1() from m %><% end using %>
<% using helper_api with h as m from skin1,name1 %><% include h1() from m %><% end using %>
<% end template %>
<% end view %>



<% end skin %>

+ 35
- 0
tests/tc_test.cpp View File

@@ -480,6 +480,38 @@ public:
);
}

void test_using_from()
{
std::cout << "- Testing using from" << std::endl;
data::master c;
c.text = "Text";
c.h.x=13;

c.skin1="plugin";
c.name1="master_plugin";
render("test_master_plugin", c );
compare_strings(str(),"\n"
"skin::master_plugin::m1 Text\n" //from "master_plugin" include m1()
"skin::master_plugin::m1 Text\n" //from name1 include m1()
"plugin::master_plugin::m1 Text\n" //from "tc_plugin","master_plugin" include m1()
"plugin::master_plugin::m1 Text\n" //from "tc_plugin",name1 include m1()
"plugin::master_plugin::m1 Text\n" //from skin1,"master_plugin" include m1()
"plugin::master_plugin::m1 Text\n" //from skin1,name1 include m1()
"");

c.skin1="plugin";
c.name1="helper_plugin";
render("test_helper_plugin", c );
compare_strings(str(),"\n"
"skin::helper_plugin::h1 13\n" //from "helper_plugin" include h1()
"skin::helper_plugin::h1 13\n" //from name1 include h1()
"plugin::helper_plugin::h1 13\n" //from "tc_plugin","helper_plugin" include h1()
"plugin::helper_plugin::h1 13\n" //from "tc_plugin",name1 include h1()
"plugin::helper_plugin::h1 13\n" //from skin1,"helper_plugin" include h1()
"plugin::helper_plugin::h1 13\n" //from skin1,name1 include h1()
"");
}


private:
std::string output_;
@@ -503,6 +535,7 @@ int main(int argc,char **argv)
cfg["views"]["skins"][0]="tc_sep_skin_a";
cfg["views"]["skins"][1]="tc_sep_skin_b";
cfg["views"]["skins"][2]="tc_sep_skin";
cfg["views"]["skins"][2]="tc_plugin";
}
else {
std::cout << "Using shared header/body" << std::endl;
@@ -532,6 +565,8 @@ int main(int argc,char **argv)
app.test_cache();
app.test_using_render();
app.test_gettext();
if(separate)
app.test_using_from();
}
catch(std::exception const &e)
{


+ 1
- 0
tests/tc_test_content.h View File

@@ -17,6 +17,7 @@ namespace data {
struct master : public cppcms::base_content {
int integer;
std::string text;
std::string skin1,skin2,name1;
helper h;
typedef std::vector<int> integers_type;
integers_type integers;


Loading…
Cancel
Save