Class: N::App::PageScript
- Defined in:
- lib/n/app/handlers/page-handler.rb
Overview
Pagescript
encapsulates the script defining a specific xml page. effectively acts as a Generator.
Requirements:
-
the generated class should be a singleton, no need to stress
the garbage collector.
-
the render method should be thread safe.
Design:
-
only pass request and request for simplicity __session can be deducted from request, and __user/__errors from
__session.
Injection:
Injection is the inclusion of subscripts in a super (parent) script. There are two types of inclusion, dynamic and static. In contrary to what you may believe, dynamix inclusion IS needed in cases where you decide what tou include at runtime. A synthesized “my” page is a good example. However, n1 overused dynamic inclusion. In most cases static inclusion works just fine. Another interesting optimization is when you dynamically include but not recursivelly. The full, recursive and dynamic include is really seldomly needed. However in our implementation there is no difference between inject_once / inject_recursive.
Class generation example:
WARNING: the example may be deprecated!
source script:
<?xml version=‘1.0’?> <?ruby a = 5 b = request ?> <html> <body> this is it a = #a, b = #b and c = #"cval"<br/> cool huh? </body> </html>
generated class:
class PageScript__index def render(request) out = “” a = 5 b = request __out << %{ <html> <body> this is it a = #a, b = #b and c = #"cval"<br/> cool huh? </body> </html> } return __out end end
Future:
-
use catbuffer for optimized appends.
Instance Attribute Summary
Attributes inherited from Script
#cacheability, #key, #path, #sub_scripts
Instance Method Summary collapse
-
#__include(uri, request, parent = false) ⇒ Object
<x:include xl:href=‘…’/> implementation Dynamically include (“inject”) a subpage (fragment) in this page.
Methods inherited from Script
#__action, #__authorize?, #__cache?, #__cache_clear, #__cache_get, #__cache_put, #__calc_lm, #__calc_tag, #__create_time, #__etag, #__file_mtime, #__force_login, #__init, #__init_render, #__inject, #__lm, #__path, #__post_evaluate, #__post_render, #__pre_evaluate, #__pre_render, #__render, #__shader, #__tag, #admin?, admin_role, #cache?, #cache_flag, #cache_valid?, enable_cache!, #initialize
Constructor Details
This class inherits a constructor from N::App::Script
Instance Method Details
#__include(uri, request, parent = false) ⇒ Object
<x:include xl:href=‘…’/> implementation Dynamically include (“inject”) a subpage (fragment) in this page.
gmosx, SOS: This is a new version for dynamic inclusion that doesnt generate subrequest objects. For use with new (v3) code.
Design:
To keep this method simple (and as a small optimization) we used to not allow a query string when including. Pass the parameters as request arguments or parameters. Here is an example:
<?r request_set_arg(“max_message”, 5); request = true ?> <x:include xl:href=‘*parts/messages/view-messages.xi’/>
However to support legacy code, to follow the REST design guidelines, and because it turned out to be easy thanks to the refactoring, the query string is supported. Passing params through the request object is suggested though (and essential to pass ruby objects). The query string of the included string is converted to arguments to avoid poluting the parent request query string.
Still, the preferred way is to use the args hash to pass special arguments to included scripts. <?r request.set_arg(“maxitems”, 5) ?> <x:include xl:href=“p/list.si” />
If you want to include the parents query string for caching purposes call with parent = true!
TODO: add unit test for this.
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 |
# File 'lib/n/app/handlers/page-handler.rb', line 531 def __include(uri, request, parent = false) begin $log.devel "Including #{uri}" # get script real path and type script_path, type, args, qs = N::UriUtils.decode(uri) # update the dependencies set, we only need the key as flag, # so just insert true. Calculating the dependencies this # way is simple and not too inefficient. # # @dependencies[script_path] = true request.level += 1 request.path = script_path # Build the cache key for this request. # attach the query string of the parent. Needed for # example in fragments with pagers. Do NOT do this # by default, or excessive numbers of fragments will # be generated. if parent request.fragment_hash = "#{qs}#{request.query_string}" else request.fragment_hash = qs end # add arguments passes through the query string. request.parameters.update(args) # TODO: select by regexp # FIXME: hacky implementation, NO Need for this test, always # PageHandler. if handler = $srv_extension_map[type] handler = handler[1] else $log.error "No handler for extension '#{type}'" unless N::StringUtils.valid?(type) $log.error "Perhaps you have a syntax error in your include statement or you didnt pass the uri" end end fragment, script = handler.sub_process(request) # restore parent request request.level -= 1 # gmosx: one idea was to clear the args here to avoid a class of bugs. # But i think it is better to trust the developer to do this, thus # giving him greater flexibility. # gmosx: NO !!! practice shows that it is NOT GOOD to trust the # developer :) # Hmm clearing the args also poses problems though :( # # request.args.clear() return fragment.body rescue ScriptHandlerError => e # allready handled! rescue Exception, StandardError => e # gmosx: this block is used to catch possible errors in the inject # implementation if we do not catch these errors here, they # propagate to the caller that prints a NON usefull message, that # can waste a developers time. # $log.error "error in INCLUDE IMPLEMENTATION while including: #{uri}" # gmosx: too noisy, only uncomment if you get the above error!! $log.error pp_exception(e) # Following our design goal of chaos reduction (ie small changes # should result in small results) we drink the exception and # output an error flag. So the rest of the page is rendered and # the server error handler is NOT triggered. end return "(error)" end |