nitro 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +382 -0
- data/ProjectInfo +4 -4
- data/README +1 -1
- data/doc/AUTHORS +15 -15
- data/doc/MIGRATION +13 -0
- data/doc/RELEASES +102 -0
- data/lib/glue/sweeper.rb +1 -1
- data/lib/nitro.rb +38 -9
- data/lib/nitro/adapter/acgi.rb +1 -3
- data/lib/nitro/adapter/cgi.rb +1 -1
- data/lib/nitro/adapter/fastcgi.rb +1 -3
- data/lib/nitro/adapter/mongrel.rb +8 -6
- data/lib/nitro/adapter/webrick.rb +1 -2
- data/lib/nitro/cgi.rb +1 -1
- data/lib/nitro/compiler.rb +21 -40
- data/lib/nitro/compiler/elements.rb +72 -32
- data/lib/nitro/compiler/errors.rb +92 -42
- data/lib/nitro/compiler/include.rb +47 -17
- data/lib/nitro/compiler/morphing.rb +1 -3
- data/lib/nitro/compiler/script.rb +2 -2
- data/lib/nitro/context.rb +36 -0
- data/lib/nitro/controller.rb +140 -31
- data/lib/nitro/dispatcher.rb +27 -28
- data/lib/nitro/element.rb +52 -15
- data/lib/nitro/flash.rb +44 -0
- data/lib/nitro/helper/buffer.rb +0 -2
- data/lib/nitro/helper/form.rb +2 -2
- data/lib/nitro/helper/form/controls.rb +14 -3
- data/lib/nitro/helper/pager.rb +1 -1
- data/lib/nitro/helper/table.rb +4 -3
- data/lib/nitro/helper/xml.rb +1 -1
- data/lib/nitro/part.rb +20 -0
- data/lib/nitro/render.rb +44 -5
- data/lib/nitro/router.rb +81 -0
- data/lib/nitro/scaffolding.rb +24 -23
- data/lib/nitro/server.rb +12 -1
- data/lib/nitro/server/runner.rb +12 -0
- data/lib/nitro/session.rb +3 -12
- data/lib/nitro/session/drb.rb +2 -5
- data/lib/nitro/session/file.rb +2 -2
- data/lib/nitro/session/memcached.rb +14 -0
- data/lib/nitro/session/memory.rb +3 -26
- data/lib/nitro/session/og.rb +1 -1
- data/lib/nitro/test/assertions.rb +1 -1
- data/lib/nitro/test/context.rb +8 -2
- data/lib/nitro/test/testcase.rb +16 -7
- data/proto/public/error.xhtml +58 -21
- data/proto/public/js/controls.js +60 -15
- data/proto/public/js/dragdrop.js +105 -16
- data/proto/public/js/effects.js +19 -12
- data/proto/public/js/scriptaculous.js +1 -1
- data/proto/public/js/slider.js +2 -2
- data/proto/public/js/unittest.js +29 -20
- data/proto/public/scaffold/edit.xhtml +1 -1
- data/proto/public/scaffold/index.xhtml +2 -2
- data/proto/public/scaffold/list.xhtml +2 -2
- data/proto/public/scaffold/new.xhtml +1 -1
- data/proto/public/scaffold/search.xhtml +1 -1
- data/src/part/admin/controller.rb +5 -5
- data/src/part/admin/template/index.xhtml +2 -2
- data/test/nitro/compiler/tc_compiler.rb +23 -0
- data/test/nitro/helper/tc_table.rb +35 -0
- data/test/nitro/tc_cgi.rb +1 -1
- data/test/nitro/tc_controller.rb +3 -3
- data/test/nitro/tc_controller_aspect.rb +2 -0
- data/test/nitro/tc_dispatcher.rb +10 -1
- data/test/nitro/tc_flash.rb +14 -0
- data/test/nitro/tc_router.rb +58 -0
- data/test/nitro/tc_session.rb +26 -9
- metadata +13 -12
- data/lib/nitro/routing.rb +0 -41
- data/test/nitro/caching/tc_stores.rb +0 -17
- data/test/nitro/tc_table.rb +0 -66
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'rexml/document'
|
2
2
|
require 'rexml/streamlistener'
|
3
|
+
require 'facet/class/by_name'
|
3
4
|
|
4
5
|
require 'nitro/element'
|
5
6
|
require "glue/html"
|
6
7
|
|
8
|
+
|
7
9
|
module Nitro
|
8
10
|
|
9
11
|
# A compiler that handles the processing of Elements
|
@@ -16,8 +18,9 @@ class Elements # :nodoc: all
|
|
16
18
|
attr_accessor :buffer
|
17
19
|
attr_accessor :stack
|
18
20
|
|
19
|
-
def initialize
|
20
|
-
super
|
21
|
+
def initialize(compiler)
|
22
|
+
super()
|
23
|
+
@compiler = compiler
|
21
24
|
@buffer = ''
|
22
25
|
@stack = []
|
23
26
|
end
|
@@ -29,35 +32,20 @@ class Elements # :nodoc: all
|
|
29
32
|
# check if the name starts with the element prefix, or
|
30
33
|
# is capitalized.
|
31
34
|
|
32
|
-
if
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
unless klass.ancestors.include? Nitro::Element
|
39
|
-
if Element.auto_extend
|
40
|
-
klass.send(:include, Nitro::ElementMixin)
|
41
|
-
else
|
42
|
-
Logger.error "Invalid element class '#{name}', does not extend Nitro::Element"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
else
|
46
|
-
Logger.error "The class of this element tag '#{name}' does not exist"
|
47
|
-
end
|
48
|
-
|
49
|
-
if klass and obj = klass.new
|
50
|
-
attributes.each do | k, v |
|
51
|
-
obj.instance_variable_set("@#{k}", v)
|
52
|
-
end
|
35
|
+
if klass = is_element?(name)
|
36
|
+
|
37
|
+
obj = klass.new
|
38
|
+
attributes.each do | k, v |
|
39
|
+
obj.instance_variable_set("@#{k}", v)
|
40
|
+
end
|
53
41
|
|
54
|
-
|
42
|
+
@stack.push [obj, @buffer, @parent]
|
55
43
|
|
56
|
-
|
57
|
-
|
44
|
+
@buffer = obj._text
|
45
|
+
@parent.add_child(obj) if @parent
|
58
46
|
|
59
|
-
|
60
|
-
|
47
|
+
@parent = obj
|
48
|
+
|
61
49
|
else # This is a static element.
|
62
50
|
attrs = []
|
63
51
|
|
@@ -74,14 +62,66 @@ class Elements # :nodoc: all
|
|
74
62
|
def tag_end(name)
|
75
63
|
# check if the name starts with the element prefix, or
|
76
64
|
# is capitalized.
|
77
|
-
if
|
78
|
-
name = name.split(':')[1].camelize if name =~ PREFIX_RE
|
65
|
+
if is_element? name
|
79
66
|
obj, @buffer, @parent = @stack.pop
|
80
67
|
@buffer << obj.render
|
81
68
|
else
|
82
69
|
@buffer << "</#{name}>"
|
83
70
|
end
|
84
71
|
end
|
72
|
+
|
73
|
+
|
74
|
+
# Check if a tag is a Nitro::Element. If found, it also tries to
|
75
|
+
# auto-extend the klass.
|
76
|
+
#
|
77
|
+
# returns the Element class if found
|
78
|
+
def is_element?(name)
|
79
|
+
# Doesn't support modulized classes
|
80
|
+
# name = name.demodulize
|
81
|
+
return false unless name =~ PREFIX_RE or name =~ CAPITALIZED_RE
|
82
|
+
|
83
|
+
name = name.gsub(/#{PREFIX_RE}:/,'').camelize if name =~ PREFIX_RE
|
84
|
+
|
85
|
+
# First try to use Nitro::Element::xxx then ::xxx
|
86
|
+
|
87
|
+
begin
|
88
|
+
klass = Class.by_name("Nitro::Element::#{name}")
|
89
|
+
rescue
|
90
|
+
end
|
91
|
+
|
92
|
+
# Look into the module the controller's module if any
|
93
|
+
|
94
|
+
begin
|
95
|
+
namespace = @compiler.controller.name
|
96
|
+
if /::/ =~ namespace
|
97
|
+
namespace = namespace.gsub( /::[a-zA-Z]+$/, "::#{name}" )
|
98
|
+
pp namespace
|
99
|
+
klass = Class.by_name(namespace)
|
100
|
+
end
|
101
|
+
rescue
|
102
|
+
end unless klass
|
103
|
+
|
104
|
+
# Look in the root module
|
105
|
+
|
106
|
+
begin
|
107
|
+
klass = Class.by_name(name)
|
108
|
+
rescue
|
109
|
+
end unless klass
|
110
|
+
|
111
|
+
return false unless klass.kind_of?( Class )
|
112
|
+
|
113
|
+
# Try to auto-extend
|
114
|
+
|
115
|
+
unless klass.ancestors.include? Nitro::Element
|
116
|
+
if Element.auto_extend
|
117
|
+
klass.send(:include, Nitro::ElementMixin)
|
118
|
+
else
|
119
|
+
return false
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
return klass
|
124
|
+
end
|
85
125
|
|
86
126
|
def text(str)
|
87
127
|
@buffer << str
|
@@ -92,7 +132,7 @@ class Elements # :nodoc: all
|
|
92
132
|
end
|
93
133
|
|
94
134
|
def comment(c)
|
95
|
-
unless Template.strip_xml_comments
|
135
|
+
unless Glue::Template.strip_xml_comments
|
96
136
|
@buffer << "<!--#{c}-->"
|
97
137
|
end
|
98
138
|
end
|
@@ -116,7 +156,7 @@ class Elements # :nodoc: all
|
|
116
156
|
#++
|
117
157
|
|
118
158
|
def transform(source, compiler)
|
119
|
-
listener = Listener.new
|
159
|
+
listener = Listener.new(compiler)
|
120
160
|
|
121
161
|
REXML::Document.parse_stream(source, listener)
|
122
162
|
|
@@ -1,65 +1,115 @@
|
|
1
1
|
require 'facet/ormsupport'
|
2
2
|
|
3
|
-
|
3
|
+
# This supports source code extraction from a full
|
4
|
+
# backtrace from any exception and also exposes class
|
5
|
+
# methods incase you wish to harness them from elsewhere.
|
6
|
+
#--
|
7
|
+
# TODO: Cache source code? Memory vs Speed - Is it worth
|
8
|
+
# it?
|
9
|
+
# FIXME: Don't change the Exception class, use NitroException
|
10
|
+
# or something.
|
11
|
+
#++
|
4
12
|
|
5
|
-
class
|
6
|
-
SOURCE_CODE_RADIUS = 5
|
13
|
+
class Exception
|
7
14
|
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(source_code, filename, original_exception)
|
11
|
-
@source_code = source_code.split("\n")
|
12
|
-
@filename = filename
|
13
|
-
@original_exception = original_exception
|
14
|
-
end
|
15
|
+
# Radius of the source code to display arround the error line.
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
SOURCE_RADIUS = 5
|
18
|
+
|
19
|
+
class << self
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
# Extracts the filename and line from the given line (step)
|
22
|
+
# of the backtrace.
|
23
|
+
|
24
|
+
def file_and_line_no(step)
|
25
|
+
file = no = nil
|
26
|
+
if res = step.match(/^(.+):(\d+)$/)
|
27
|
+
file = res[1]
|
28
|
+
no = res[2]
|
29
|
+
elsif res = step.match(/^(.+):(\d+):in `.+'$/)
|
30
|
+
file = res[1]
|
31
|
+
no = res[2]
|
32
|
+
end
|
33
|
+
if file and no
|
34
|
+
[file,no.to_i]
|
35
|
+
else
|
36
|
+
nil
|
37
|
+
end
|
23
38
|
end
|
24
|
-
|
39
|
+
|
40
|
+
# Extract the source arround the error line.
|
41
|
+
|
42
|
+
def source_extract(step, indent = 0)
|
43
|
+
begin
|
44
|
+
file, no = file_and_line_no(step)
|
45
|
+
source = File.read(file)
|
46
|
+
|
47
|
+
if file =~ /\.xhtml$/
|
48
|
+
source = Compiler.new.transform_template(source)
|
49
|
+
no -= 2
|
50
|
+
end
|
51
|
+
|
52
|
+
source = source.split("\n")
|
53
|
+
start = (no-1) - SOURCE_RADIUS
|
54
|
+
finish = (no-1) + SOURCE_RADIUS
|
55
|
+
start = 0 if start < 0
|
56
|
+
finish = source.size if finish > source.size
|
25
57
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
58
|
+
number = start
|
59
|
+
extract = source[start..finish].collect do |line|
|
60
|
+
number += 1
|
61
|
+
line = line.gsub(/; @out << %\^/, ' ?>').gsub(/\^;/, '<?r ')
|
62
|
+
"#{' ' * indent}#{number}: #{line}"
|
63
|
+
end
|
30
64
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
line = line.gsub(/; @out << %\^/, ' ?>').gsub(/\^;/, '<?r ')
|
35
|
-
if number == line_number
|
36
|
-
"#{' ' * indent}#{number}: #{line}"
|
37
|
-
else
|
38
|
-
"#{' ' * indent}#{number}: #{line}"
|
65
|
+
return extract.join("\n")
|
66
|
+
rescue => ex
|
67
|
+
''
|
39
68
|
end
|
40
69
|
end
|
70
|
+
|
71
|
+
end
|
41
72
|
|
42
|
-
|
73
|
+
# Identifies the 'hot' index in the backtrace, where the error
|
74
|
+
# actually happened.
|
75
|
+
|
76
|
+
def hot_trace_index
|
77
|
+
index = 0
|
78
|
+
while backtrace[index] =~ /controller\.rb(.*)method_missing/
|
79
|
+
index += 1
|
80
|
+
end
|
81
|
+
return index
|
43
82
|
end
|
44
83
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
84
|
+
# Returns the 'hot' backtrace line.
|
85
|
+
|
86
|
+
def hot_trace_step
|
87
|
+
backtrace[hot_trace_index]
|
49
88
|
end
|
50
89
|
|
51
|
-
|
52
|
-
|
90
|
+
# Returns the 'hot' backtrace file.
|
91
|
+
|
92
|
+
def hot_file
|
93
|
+
file_and_line_no(hot_trace_step).first
|
53
94
|
end
|
54
95
|
|
55
|
-
def
|
56
|
-
|
96
|
+
def file_and_line_no(step)
|
97
|
+
self.class.file_and_line_no(step)
|
98
|
+
end
|
99
|
+
|
100
|
+
def source_extract(step = hot_trace_step, indent = 0)
|
101
|
+
self.class.source_extract(step,indent)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Extract source for backtrace.
|
105
|
+
|
106
|
+
def source_for_backtrace(indent = 0)
|
107
|
+
backtrace.inject([]) do |sources, step|
|
108
|
+
sources << source_extract(indent,step)
|
109
|
+
end
|
57
110
|
end
|
58
|
-
end
|
59
111
|
|
60
|
-
class TemplateCompileError < ActionCompileError
|
61
|
-
end
|
62
|
-
|
63
112
|
end
|
64
113
|
|
65
114
|
# * George Moschovitis <gm@navel.gr>
|
115
|
+
# * Rob Pitt <rob@motionpath.co.uk>
|
@@ -7,27 +7,57 @@ module Nitro
|
|
7
7
|
# to use static includes in many many cases.
|
8
8
|
|
9
9
|
class StaticInclude
|
10
|
-
|
11
|
-
#
|
12
|
-
|
10
|
+
# Statically include sub-template files.
|
11
|
+
# The target file is included at compile time.
|
12
|
+
# If the given path is relative, the template_root stack of
|
13
|
+
# the controller is traversed. If an absolute path is provided,
|
14
|
+
# templates are searched only in Template.root
|
15
|
+
#
|
16
|
+
# gmosx: must be xformed before the <?r pi.
|
17
|
+
#
|
18
|
+
# === Example
|
19
|
+
# <?include href="root/myfile.sx" ?>
|
13
20
|
|
14
|
-
def self.transform(text)
|
15
|
-
|
16
|
-
|
17
|
-
#
|
18
|
-
# gmosx: must be xformed before the <?r pi.
|
19
|
-
#
|
20
|
-
# Example:
|
21
|
-
# <?include href="root/myfile.sx" ?>
|
22
|
-
|
21
|
+
def self.transform(text, compiler)
|
22
|
+
controller = compiler.controller
|
23
|
+
|
23
24
|
return text.gsub(/<\?include href=["|'](.*?)["|'](.*)\?>/) do |match|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
found = false
|
26
|
+
|
27
|
+
if $1[0] == ?/
|
28
|
+
# Absolute path, search only in the application template
|
29
|
+
# root.
|
30
|
+
|
31
|
+
href = $1[1, 999999] # hack!!
|
32
|
+
template_stack = [ Glue::Template.root ]
|
33
|
+
else
|
34
|
+
# Relative path, traverse the template_root stack.
|
35
|
+
|
36
|
+
href = $1
|
37
|
+
template_stack = controller.instance_variable_get(:@template_root)
|
38
|
+
end
|
39
|
+
|
40
|
+
for template_root in template_stack
|
41
|
+
if File.exist?(filename = "#{template_root}/#{href}")
|
42
|
+
found = true
|
43
|
+
break
|
44
|
+
end
|
45
|
+
|
46
|
+
if File.exist?(filename = "#{template_root}/#{href}.xinc")
|
47
|
+
found = true
|
48
|
+
break
|
49
|
+
end
|
50
|
+
|
51
|
+
if File.exist?(filename = "#{template_root}/#{href}.xhtml")
|
52
|
+
found = true
|
53
|
+
break
|
29
54
|
end
|
30
55
|
end
|
56
|
+
|
57
|
+
unless found
|
58
|
+
raise "Cannot statically include '#{href}'"
|
59
|
+
end
|
60
|
+
|
31
61
|
itext = File.read(filename)
|
32
62
|
itext.gsub!(/<\?xml.*\?>/, '')
|
33
63
|
itext.gsub!(/<\/?root(.*?)>/m, ' ');
|
@@ -4,8 +4,6 @@ require 'rexml/streamlistener'
|
|
4
4
|
require 'facet/dictionary'
|
5
5
|
require 'facet/string/blank'
|
6
6
|
|
7
|
-
require 'glue/html'
|
8
|
-
|
9
7
|
module Nitro
|
10
8
|
|
11
9
|
# :section: A collection of standard morphers.
|
@@ -205,7 +203,7 @@ class Morphing
|
|
205
203
|
end
|
206
204
|
|
207
205
|
def comment(c)
|
208
|
-
unless Template.strip_xml_comments
|
206
|
+
unless Glue::Template.strip_xml_comments
|
209
207
|
@buffer << "<!--#{c}-->"
|
210
208
|
end
|
211
209
|
end
|
@@ -87,13 +87,13 @@ module ScriptCompiler
|
|
87
87
|
js_buffer = compiler.shared[:js_buffer]
|
88
88
|
|
89
89
|
if script or js_buffer
|
90
|
-
text.sub!(/<\/
|
90
|
+
text.sub!(/<\/body>/) do |match|
|
91
91
|
%{
|
92
92
|
<script type="text/javascript">
|
93
93
|
#{script}
|
94
94
|
#{js_buffer}
|
95
95
|
</script>
|
96
|
-
</
|
96
|
+
</body>
|
97
97
|
}
|
98
98
|
end
|
99
99
|
end
|
data/lib/nitro/context.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
1
3
|
require 'facet/kernel/assign_with'
|
2
4
|
|
3
5
|
require 'nitro/cgi'
|
@@ -21,6 +23,10 @@ class Context
|
|
21
23
|
include Response
|
22
24
|
include Render
|
23
25
|
|
26
|
+
# The cache/store used to back global variables.
|
27
|
+
|
28
|
+
setting :global_cache_class, :default => ($NITRO_GLOBAL_CACHE_CLASS || MemoryCache), :doc => 'The store used to back global variables'
|
29
|
+
|
24
30
|
# The configuration parameters.
|
25
31
|
|
26
32
|
attr_accessor :conf
|
@@ -60,6 +66,8 @@ class Context
|
|
60
66
|
if @session.has_key?(:FLASH)
|
61
67
|
@session[:FLASH].clean
|
62
68
|
end
|
69
|
+
|
70
|
+
# INVESTIGATE: is this needed?
|
63
71
|
@session.sync
|
64
72
|
end
|
65
73
|
end
|
@@ -85,6 +93,14 @@ class Context
|
|
85
93
|
@session || @session = Session.lookup(self)
|
86
94
|
end
|
87
95
|
|
96
|
+
# Access global variables. In a distributed server scenario,
|
97
|
+
# these variables can reside outside of the process.
|
98
|
+
|
99
|
+
def global
|
100
|
+
return $global
|
101
|
+
end
|
102
|
+
alias_method :application, :global
|
103
|
+
|
88
104
|
# Lookup the controller for this request.
|
89
105
|
#--
|
90
106
|
# FIXME: improve this! BUGGY
|
@@ -101,6 +117,14 @@ class Context
|
|
101
117
|
#
|
102
118
|
# * name
|
103
119
|
# * force_boolean
|
120
|
+
#
|
121
|
+
# === Example
|
122
|
+
#
|
123
|
+
# request.fill(User.new)
|
124
|
+
#
|
125
|
+
# Prefer to use the following form:
|
126
|
+
#
|
127
|
+
# User.new.assign_with(request)
|
104
128
|
|
105
129
|
def fill(obj, options = {})
|
106
130
|
Property.populate_object(obj, @params, options)
|
@@ -110,6 +134,18 @@ class Context
|
|
110
134
|
|
111
135
|
end
|
112
136
|
|
137
|
+
# Forwards to the context
|
138
|
+
#
|
139
|
+
# use in Nitro::Action
|
140
|
+
|
141
|
+
module ContextHelper
|
142
|
+
extend Forwardable
|
143
|
+
|
144
|
+
attr_accessor :context
|
145
|
+
|
146
|
+
def_delegators :@context, :controller, :request, :response, :session, :out
|
147
|
+
end
|
148
|
+
|
113
149
|
end
|
114
150
|
|
115
151
|
# * George Moschovitis <gm@navel.gr>
|