Class: N::App::CodeHandler

Inherits:
ScriptHandler show all
Defined in:
lib/n/app/handlers/code-handler.rb

Overview

CodeHandler

web server handler that executes ruby code (logic) Caching is NOT SUPPORTED (and not needed anyway)

TODO:

probably extend PageHandler from CodeHandler and not vice versa.

Instance Attribute Summary

Attributes inherited from ServerFilter

#next_filter

Instance Method Summary collapse

Methods inherited from ScriptHandler

#compile_script, #compiled_script_cache, #log_error, #overload_path

Methods inherited from ServerFilter

#<<, #initialize, #process_next

Constructor Details

This class inherits a constructor from N::ServerFilter

Instance Method Details

#calc_script_key(path, hash) ⇒ Object



163
164
165
# File 'lib/n/app/handlers/code-handler.rb', line 163

def calc_script_key(path, hash)
	return "#{path}#{hash}".gsub(/[^\w]/, "")
end

#eval_script(script, request) ⇒ Object

evaluate the request script in the context of the current request. returns the output of the script, ie the fragment body.

Design:

I think that the script caching logic should be here, because it nicelly encapsulates transform and compile.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/n/app/handlers/code-handler.rb', line 62

def eval_script(script, request)

	$log.debug "Evaluating, #{request.path}" if $DBG

	fragment = Fragment.new(:key)
	
	# try to render the script, report errors.
	begin
		fragment.body = script.__render(request)
	rescue N::ScriptExitException => see
		# the script raised a ScripteExitException to force a premature
		# end. Surpress this error!
	rescue => ex
		log_error(request, ex)
	end

	return fragment
end

#get_compiled_script(path, hash = nil) ⇒ Object

try to get the script from the cache. invalidates the compiled version and return nil if the script is modified since compile time. Also takes active shader and localization into account. If script is not compiled, transform and compile it.

Output: the compiled script. Throws exception if the script does not exist.



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/n/app/handlers/code-handler.rb', line 132

def get_compiled_script(path, hash = nil)
	compiled_script = nil
	key = calc_script_key(path, hash)

	# gmosx: $reload_scripts is typically set to true when debugging
	# statically included files (.ss)
	unless $reload_scripts
	
		compiled_script = @@compiled_script_cache[key]

		# gmosx: monitor scripts should be explicit!
		if $srv_monitor_scripts and compiled_script and (File.mtime(compiled_script.path) > compiled_script.__create_time)
			$log.debug "Script '#{path}' externaly modified, recompiling" if $DBG
			compiled_script = nil
		end
		
	end

	unless compiled_script
		# the script is not cached, so load, transform and compile it!
		$log.debug "Compiling script '#{key}'" if $DBG

		script = transform_script(path, key)
		compiled_script = compile_script(script)
		
		@@compiled_script_cache[key] = compiled_script
	end
	
	return compiled_script
end

#process(request) ⇒ Object

process is called ONLY for top level scripts.

no need for synchronization, the page-script is thread safe. if you use thread-unsafe code in your script you are responsible for synchronization.

TODO: add timing code here



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/n/app/handlers/code-handler.rb', line 41

def process(request)	
	# gmosx, FIXME: temporarily here, move somewhere ELSE!

	request.locale = $lc_map[request.user.locale] || $lc_en
	script = get_compiled_script(request.path)		
	fragment = eval_script(script, request)
	
	# walk the filter pipeline
	super

	return fragment, script
end

#transform_script(path, hash, shader = nil) ⇒ Object

Output:

defcode: the code that customizes the base script class. pagecode: the code that renders the fragment.

REMARKS:

  • this method is evaluated in compile time, so we cannot pass or use the request/request pair. gmosx: NO, we do pass request, some data can and SHOULD be used to prepare the transform.



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/n/app/handlers/code-handler.rb', line 90

def transform_script(path, hash, shader = nil)

	path = overload_path(path)

	# load the page text from the script
	pagecode = ""

	pagecode = File.read("#$root_dir/#{path}")

	# convert to ruby code
	pagecode.gsub!(/<<</, "__out << %{")
	pagecode.gsub!(/>>>/, "}")

	script = %{
		class CodeScript_#{hash} < CodeScript
			def initialize(path)
				super
@pagecode = <<-'PAGECODE'
#{pagecode}
PAGECODE
@defcode = nil
			end
			def __render(request)
				__out = ""
				lc = request.locale
				#{pagecode}
				return __out
			end
		end
		return CodeScript_#{hash}.new("#{path}")
	}

	return script
end