Class: N::App::PageScript

Inherits:
Script
  • Object
show all
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

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