nitro 0.25.0 → 0.26.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.
Files changed (76) hide show
  1. data/CHANGELOG +531 -1
  2. data/ProjectInfo +29 -5
  3. data/README +1 -1
  4. data/doc/AUTHORS +12 -6
  5. data/doc/RELEASES +114 -0
  6. data/lib/glue/sweeper.rb +71 -0
  7. data/lib/nitro.rb +19 -12
  8. data/lib/nitro/adapter/cgi.rb +4 -0
  9. data/lib/nitro/adapter/webrick.rb +4 -2
  10. data/lib/nitro/caching.rb +1 -0
  11. data/lib/nitro/caching/fragments.rb +7 -1
  12. data/lib/nitro/caching/output.rb +6 -1
  13. data/lib/nitro/caching/stores.rb +13 -1
  14. data/lib/nitro/cgi.rb +9 -1
  15. data/lib/nitro/cgi/request.rb +11 -3
  16. data/lib/nitro/cgi/utils.rb +24 -2
  17. data/lib/nitro/compiler.rb +89 -63
  18. data/lib/nitro/compiler/cleanup.rb +16 -0
  19. data/lib/nitro/compiler/elements.rb +117 -0
  20. data/lib/nitro/compiler/markup.rb +3 -1
  21. data/lib/nitro/compiler/morphing.rb +203 -73
  22. data/lib/nitro/compiler/script_generator.rb +14 -0
  23. data/lib/nitro/compiler/shaders.rb +1 -1
  24. data/lib/nitro/context.rb +5 -6
  25. data/lib/nitro/controller.rb +43 -21
  26. data/lib/nitro/dispatcher.rb +86 -37
  27. data/lib/nitro/element.rb +3 -105
  28. data/lib/nitro/helper/benchmark.rb +3 -0
  29. data/lib/nitro/helper/dojo.rb +0 -0
  30. data/lib/nitro/helper/form.rb +85 -255
  31. data/lib/nitro/helper/form/controls.rb +274 -0
  32. data/lib/nitro/helper/javascript.rb +86 -6
  33. data/lib/nitro/helper/pager.rb +5 -0
  34. data/lib/nitro/helper/prototype.rb +49 -0
  35. data/lib/nitro/helper/scriptaculous.rb +0 -0
  36. data/lib/nitro/helper/xhtml.rb +11 -8
  37. data/lib/nitro/helper/xml.rb +1 -1
  38. data/lib/nitro/routing.rb +8 -1
  39. data/lib/nitro/scaffolding.rb +344 -0
  40. data/lib/nitro/server.rb +5 -1
  41. data/lib/nitro/server/runner.rb +19 -15
  42. data/lib/nitro/session.rb +32 -56
  43. data/lib/nitro/session/drbserver.rb +1 -1
  44. data/lib/nitro/session/file.rb +34 -15
  45. data/lib/nitro/session/memory.rb +13 -4
  46. data/lib/nitro/session/og.rb +56 -0
  47. data/proto/public/js/controls.js +30 -1
  48. data/proto/public/js/dragdrop.js +211 -146
  49. data/proto/public/js/effects.js +261 -399
  50. data/proto/public/js/prototype.js +131 -72
  51. data/proto/public/scaffold/edit.xhtml +10 -3
  52. data/proto/public/scaffold/form.xhtml +1 -7
  53. data/proto/public/scaffold/index.xhtml +20 -0
  54. data/proto/public/scaffold/list.xhtml +15 -8
  55. data/proto/public/scaffold/new.xhtml +10 -3
  56. data/proto/public/scaffold/search.xhtml +28 -0
  57. data/proto/public/scaffold/view.xhtml +8 -0
  58. data/proto/run.rb +93 -1
  59. data/src/part/admin.rb +4 -2
  60. data/src/part/admin/controller.rb +62 -28
  61. data/src/part/admin/skin.rb +8 -8
  62. data/src/part/admin/system.css +135 -0
  63. data/src/part/admin/template/index.xhtml +8 -12
  64. data/test/nitro/caching/tc_stores.rb +17 -0
  65. data/test/nitro/tc_caching.rb +1 -4
  66. data/test/nitro/tc_dispatcher.rb +22 -10
  67. data/test/nitro/tc_element.rb +1 -1
  68. data/test/nitro/tc_session.rb +23 -11
  69. data/test/public/blog/another/very_litle/index.xhtml +1 -0
  70. metadata +29 -15
  71. data/lib/nitro/dispatcher/general.rb +0 -62
  72. data/lib/nitro/dispatcher/nice.rb +0 -57
  73. data/lib/nitro/scaffold.rb +0 -171
  74. data/proto/public/index.xhtml +0 -83
  75. data/proto/public/js/scaffold.js +0 -74
  76. data/proto/public/settings.xhtml +0 -66
@@ -2,6 +2,8 @@ require 'fileutils'
2
2
 
3
3
  require 'mega/synchash'
4
4
 
5
+ require 'glue/attribute'
6
+
5
7
  module Nitro
6
8
 
7
9
  # Adds support for caching.
@@ -20,8 +22,10 @@ module Caching
20
22
  self[name] = content
21
23
  end
22
24
 
25
+ alias_method :old_delete, :delete
26
+
23
27
  def delete(name, options = {})
24
- self.delete(name)
28
+ old_delete(name)
25
29
  end
26
30
 
27
31
  end
@@ -69,8 +73,16 @@ module Caching
69
73
 
70
74
  end
71
75
 
76
+ #--
77
+ # TODO: implement me
78
+ #++
79
+
72
80
  class DrbStrore
73
81
  end
82
+
83
+ #--
84
+ # TODO: implement me
85
+ #++
74
86
 
75
87
  class MemcacheStore
76
88
  end
@@ -1,3 +1,5 @@
1
+ require 'cgi'
2
+
1
3
  require 'glue/configuration'
2
4
  require 'nitro/cgi/http'
3
5
 
@@ -23,6 +25,12 @@ class Cgi
23
25
  context.in = inp
24
26
  context.headers = cgi.env
25
27
 
28
+ # gmosx: QUERY_STRING is sometimes not populated.
29
+
30
+ if context.query_string.empty? and context.uri =~ /\?/
31
+ context.headers['QUERY_STRING'] = context.uri.split('?').last
32
+ end
33
+
26
34
  Cgi.parse_params(context)
27
35
  Cgi.parse_cookies(context)
28
36
  context.render(context.path)
@@ -293,4 +301,4 @@ end
293
301
  end
294
302
 
295
303
  # * George Moschovitis <gm@navel.gr>
296
- # * Guillaume Pierronnet <guillaume.pierronnet@gmail.com>
304
+ # * Guillaume Pierronnet <guillaume.pierronnet@gmail.com>
@@ -39,7 +39,7 @@ module Request
39
39
  # 443 == port
40
40
  @headers['HTTPS'] == 'on'
41
41
  end
42
-
42
+
43
43
  # The request uri.
44
44
 
45
45
  def uri
@@ -84,7 +84,14 @@ module Request
84
84
  #++
85
85
 
86
86
  def query_string
87
- @headers['QUERY_STRING']
87
+ =begin
88
+ qs = headers['QUERY_STRING']
89
+ if qs.empty? and uri =~ /\?/
90
+ qs = headers['QUERY_STRING'] = uri.split('?').last
91
+ end
92
+ return qs
93
+ =end
94
+ headers['QUERY_STRING']
88
95
  end
89
96
 
90
97
  # The request method. Alternatively you could use the
@@ -160,6 +167,7 @@ module Request
160
167
  not /XMLHttpRequest/i.match(@headers['HTTP_X_REQUESTED_WITH']).nil?
161
168
  end
162
169
  alias xhr? :xml_http_request?
170
+ alias ajax? :xml_http_request?
163
171
 
164
172
  # Return the referer. For the initial page in the
165
173
  # clickstream there is no referer, set "/" by default.
@@ -187,7 +195,7 @@ module Request
187
195
 
188
196
  if @headers.include?('HTTP_X_FORWARDED_FOR') then
189
197
  remote_ips = @headers['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip|
190
- ip =~ /^unknown$|^(10|172\.16|192\.168)\./i
198
+ ip =~ /^unknown$|^(127|10|172\.16|192\.168)\./i
191
199
  end
192
200
 
193
201
  return remote_ips.first.strip unless remote_ips.empty?
@@ -10,7 +10,9 @@ module Request
10
10
  # Different servers hold user agent in differnet
11
11
  # strings (unify this).
12
12
 
13
- def user_agent
14
13
  headers['HTTP_USER_AGENT'] || headers['USER-AGENT']
15
14
  end
15
+ def user_agent
16
+ headers['HTTP_USER_AGENT'] || headers['USER-AGENT']
17
+ end
16
18
 
17
19
  def from_gecko?
18
20
  user_agent =~ /Gecko/
@@ -34,9 +36,29 @@ module Request
34
36
  def from_w3c?
35
37
  from_gecko? or from_khtml? or from_opera?
36
38
  end
39
+
40
+ def from_osx?
41
+ user_agent =~ /Mac OS X/ or user_agent =~ /Mac_PowerPC/
42
+ end
43
+
44
+ def from_os9?
45
+ end
46
+
47
+ def from_mac?
48
+ from_osx? or from_os9?
49
+ end
50
+
51
+ def from_unix?
52
+ user_agent =~ /linux/ or user_agent =~ /FreeBSD/
53
+ end
54
+ alias_method :from_linux?, :from_unix?
55
+
56
+ def from_windows?
57
+ user_agent =~ /Windows/
58
+ end
37
59
 
38
60
  end
39
61
 
40
62
  end
41
63
 
42
- # * Chris Farmiloe <chris.farmiloe@farmiloe.com>
64
+ # * Chris Farmiloe <chris.farmiloe@farmiloe.com>
@@ -1,7 +1,13 @@
1
1
  require 'nano/kernel/singleton'
2
2
 
3
3
  require 'glue/template'
4
+
5
+ require 'nitro/compiler/elements'
4
6
  require 'nitro/compiler/errors'
7
+ require 'nitro/compiler/markup'
8
+ require 'nitro/compiler/morphing'
9
+ require 'nitro/compiler/include'
10
+ require 'nitro/compiler/cleanup'
5
11
 
6
12
  module Nitro
7
13
 
@@ -13,6 +19,10 @@ class Compiler
13
19
  unless const_defined? :PROTO_TEMPLATE_ROOT
14
20
  PROTO_TEMPLATE_ROOT = "#{Nitro.proto_path}/public"
15
21
  end
22
+
23
+ # The controller for this compiler.
24
+
25
+ attr_accessor :controller
16
26
 
17
27
  # Set to true to force reloading of code and templates for
18
28
  # each request. Extremely useful during development. Must be
@@ -20,50 +30,81 @@ class Compiler
20
30
  # performance penalty.
21
31
 
22
32
  setting :reload, :default => true, :doc => 'If true all code and templates are reloaded in each request'
23
-
33
+
34
+ def initialize(controller = nil)
35
+ @controller = controller
36
+ end
37
+
24
38
  # Action names with double underscores (__) are converted
25
39
  # to subdirectories. Here are some example mappings:
26
40
  #
27
41
  # hello_world -> template_root/hello_world.xhtml
28
42
  # this__is__my__hello_world -> template_root/this/is/my/hello_world
29
43
 
30
- def template_for_action(action, template_root = Template.root, ext = Template.extension)
31
- # attempt to find a template of the form
32
- # template_root/action.xhtml
44
+ def template_for_action(action, ext = Template.extension)
45
+ cklass = @controller
46
+ template_root = nil
47
+ checked_proto = nil
48
+
49
+ # search for template in controller and its ancestors's template_root
50
+ # if there is not an action defined in controller then also check in
51
+ # PROTO_TEMPLATE_ROOT
33
52
 
34
- path = "#{template_root}/#{action.gsub(/__/, '/')}.#{ext}".squeeze('/')
53
+ loop do
54
+ if cklass.respond_to?(:template_root) && template_root = cklass.template_root
55
+ cklass = cklass.superclass
56
+ elsif !@controller.respond_to?(:action) && !checked_proto
57
+ template_root = PROTO_TEMPLATE_ROOT
58
+ checked_proto = true
59
+ else
60
+ return nil # no template found
61
+ end
62
+
63
+ # attempt to find a template of the form
64
+ # template_root/action.xhtml
35
65
 
36
- unless File.exist?(path)
66
+ path = "#{template_root}/#{action.gsub(/__/, '/')}.#{ext}".squeeze('/')
67
+ return path if File.exist?(path)
68
+
37
69
  # attempt to find a template of the form
38
70
  # template_root/action/index.xhtml
39
71
 
40
72
  path = "#{template_root}/#{action.gsub(/__/, '/')}/#{Template.default}.#{ext}".squeeze('/')
41
-
42
- unless File.exist?(path)
43
- # No template found!
44
- return nil
45
- end
73
+ return path if File.exist?(path)
46
74
  end
75
+ end
76
+ alias_method :template?, :template_for_action
77
+
78
+ # Helper.
47
79
 
48
- return path
80
+ def action?(sym)
81
+ return @controller.action_methods.include?(sym.to_s)
49
82
  end
50
83
 
51
- # This is methods transforms the template. Typically
84
+ # This method transforms the template. Typically
52
85
  # template processors are added as aspects to this method
53
86
  # to allow for customized template transformation prior
54
87
  # to compilation.
55
88
  #
56
89
  # The default transformation extracts the Ruby code from
57
- # processing instructions.
90
+ # processing instructions, and uses the StaticInclude,
91
+ # Morphing, Elements and Markup compiler modules.
58
92
 
59
93
  def transform_template(template)
60
- Template.transform(template)
94
+ template = StaticInclude.transform(template)
95
+ template = Morphing.transform(template)
96
+ template = Elements.transform(template)
97
+ template = Markup.transform(template)
98
+ template = Cleanup.transform(template)
99
+ template = Template.transform(template)
61
100
  end
62
101
 
63
102
  # Compile the template into a render method.
103
+ # Don't compile the template if the controller
104
+ # responds_to? #{action}_template.
64
105
 
65
- def compile_template(klass, action, path)
66
- Logger.debug "Compiling template '#{klass}: #{path}'" if $DBG
106
+ def compile_template(action, path)
107
+ Logger.debug "Compiling template '#{@controller}: #{path}'" if $DBG
67
108
 
68
109
  template = File.read(path)
69
110
 
@@ -74,7 +115,7 @@ class Compiler
74
115
  }
75
116
 
76
117
  begin
77
- klass.class_eval(code, path)
118
+ @controller.class_eval(code, path)
78
119
  rescue SyntaxError => e
79
120
  raise TemplateCompileError.new(code, template, e)
80
121
  end
@@ -88,18 +129,12 @@ class Compiler
88
129
  # TODO: cleanup this method.
89
130
  #++
90
131
 
91
- def compile_action(klass, action)
92
- #--
93
- # gmosx: Move elsewhere.
94
- #++
95
-
96
- Aspects.include_advice_modules(klass)
97
-
132
+ def compile_action(action)
98
133
  action = action.to_s.gsub(/_action$/, '')
99
-
134
+
100
135
  return false unless action
101
136
 
102
- Logger.debug "Compiling action '#{klass}##{action}'" if $DBG
137
+ Logger.debug "Compiling action '#@controller##{action}'" if $DBG
103
138
 
104
139
  valid = false
105
140
 
@@ -111,16 +146,16 @@ class Compiler
111
146
 
112
147
  # Inject the pre advices.
113
148
 
114
- code << Aspects.gen_advice_code(action, klass.advices, :pre)
149
+ code << Aspects.gen_advice_code(action, @controller.advices, :pre)
115
150
 
116
151
  # Call the action
117
152
 
118
- if klass.action_methods.include?(action)
153
+ if @controller.action_methods.include?(action)
119
154
  valid = true
120
155
 
121
156
  # Annotated parameters.
122
157
 
123
- if params = klass.ann(action.to_sym).params and (!params.nil?)
158
+ if params = @controller.ann(action.to_sym).params and (!params.nil?)
124
159
  params = params.collect { |p| "@#{p} = @context['#{p}']" }
125
160
  code << "#{params.join(';')}"
126
161
  end
@@ -128,7 +163,7 @@ class Compiler
128
163
  # Try to resolve action parameters. Returns negative
129
164
  # numbers for arbitrary parameters.
130
165
 
131
- param_count = klass.instance_method(action.intern).arity
166
+ param_count = @controller.instance_method(action.intern).arity
132
167
 
133
168
  if param_count != 0
134
169
  if param_count > 0
@@ -172,38 +207,22 @@ class Compiler
172
207
 
173
208
  # Take :view annotation into account.
174
209
 
175
- view = klass.ann(action.to_sym).view # FIXME
210
+ view = @controller.ann(action.to_sym).view # FIXME
176
211
  view = action if view.nil?
177
212
 
178
- cklass = klass
179
- template_path = nil
180
-
181
- loop do
182
- template_root = nil
183
-
184
- if cklass.respond_to?(:template_root)
185
- template_root = cklass.template_root
186
- end
187
-
188
- # Don't use a proto template if there is an action
189
- # defined.
190
-
191
- template_root ||= PROTO_TEMPLATE_ROOT unless valid
192
-
193
- if template_root and template_path = template_for_action(view.to_s, template_root)
194
- valid = true
195
- code << %{
196
- #{action}_template;
197
- }
198
- break
199
- end
200
-
201
- break unless cklass = cklass.superclass
213
+ # Search the [controller] class and it's ancestors for the template
214
+
215
+ template_path = template_for_action(view.to_s)
216
+ if template_path or @controller.instance_methods.include?("#{action}_template")
217
+ valid = true
218
+ code << %{
219
+ #{action}_template
220
+ }
202
221
  end
203
222
 
204
223
  return false unless valid
205
224
 
206
- if klass.action_methods.include?(action)
225
+ if @controller.action_methods.include?(action)
207
226
  code << %{
208
227
  if @out.empty? and action_return_value.is_a?(String)
209
228
  print(action_return_value)
@@ -220,7 +239,7 @@ class Compiler
220
239
 
221
240
  # Inject the post advices.
222
241
 
223
- code << Aspects.gen_advice_code(action, klass.advices, :post)
242
+ code << Aspects.gen_advice_code(action, @controller.advices, :post)
224
243
 
225
244
  code << %{
226
245
  @action_name = @parent_action_name
@@ -230,12 +249,16 @@ class Compiler
230
249
  # First compile the action method.
231
250
 
232
251
  # begin
233
- klass.class_eval(code)
252
+ @controller.class_eval(code)
234
253
  # rescue SyntaxError => e
235
254
  # raise ActionCompileError.new(code, action, e)
236
255
  # end
237
-
238
- compile_template(klass, action, template_path) if template_path
256
+
257
+ unless @controller.respond_to?("#{action}_template")
258
+ if template_path
259
+ compile_template(action, template_path)
260
+ end
261
+ end
239
262
 
240
263
  return true
241
264
  end
@@ -243,8 +266,8 @@ class Compiler
243
266
  # Compiles an action method in the given (controller) class.
244
267
  # A sync is used to make compilation thread safe.
245
268
 
246
- def compile(klass, action)
247
- compile_action(klass, action)
269
+ def compile(action)
270
+ compile_action(action)
248
271
  end
249
272
 
250
273
  # :section: Helper methods.
@@ -279,3 +302,6 @@ class Compiler
279
302
  end
280
303
 
281
304
  end
305
+
306
+ # * George Moschovitis <gm@navel.gr>
307
+ # * Chris Farmiloe <chris.farmiloe@farmiloe.com>
@@ -0,0 +1,16 @@
1
+ module Nitro
2
+
3
+ # Tidy up the html
4
+
5
+ module Cleanup
6
+
7
+ def self.transform(text)
8
+ Glue::Html.cleanup(text)
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+
15
+ # * George Moschovitis <gm@navel.gr>
16
+ # * Chris Farmiloe <chris.farmiloe@farmiloe.com>
@@ -0,0 +1,117 @@
1
+ require 'rexml/document'
2
+ require 'rexml/streamlistener'
3
+
4
+ require 'nitro/element'
5
+ require "glue/html"
6
+
7
+ module Nitro
8
+
9
+ # A compiler that handles the processing of Elements
10
+
11
+ class Elements # :nodoc: all
12
+
13
+ class Listener # :nodoc: all
14
+ include REXML::StreamListener
15
+
16
+ attr_accessor :buffer
17
+ attr_accessor :stack
18
+
19
+ def initialize
20
+ super
21
+ @buffer = ''
22
+ @stack = []
23
+ end
24
+
25
+ PREFIX_RE = /^#{Element.prefix}:/
26
+ CAPITALIZED_RE = /^[A-Z]/
27
+
28
+ def tag_start(name, attributes)
29
+ # check if the name starts with the element prefix, or
30
+ # is capitalized.
31
+ if name =~ PREFIX_RE or name =~ CAPITALIZED_RE
32
+ name = name.split(':')[1].camelize if name =~ PREFIX_RE
33
+
34
+ obj = Object.const_get(name).new
35
+
36
+ attributes.each do | k, v |
37
+ obj.instance_variable_set("@#{k}", v)
38
+ end
39
+
40
+ @stack.push [obj, @buffer, @parent]
41
+
42
+ @buffer = obj._text
43
+ @parent.add_child(obj) if @parent
44
+
45
+ @parent = obj
46
+ else # This is a static element.
47
+ attrs = []
48
+
49
+ attributes.each do | k, v |
50
+ attrs << %|#{k}="#{v}"|
51
+ end
52
+
53
+ attrs = attrs.empty? ? nil : " #{attrs.join(' ')}"
54
+
55
+ @buffer << "<#{name}#{attrs}>"
56
+ end
57
+ end
58
+
59
+ def tag_end(name)
60
+ # check if the name starts with the element prefix, or
61
+ # is capitalized.
62
+ if name =~ PREFIX_RE or name =~ CAPITALIZED_RE
63
+ name = name.split(':')[1].camelize if name =~ PREFIX_RE
64
+ obj, @buffer, @parent = @stack.pop
65
+ @buffer << obj.render
66
+ else
67
+ @buffer << "</#{name}>"
68
+ end
69
+ end
70
+
71
+ def text(str)
72
+ @buffer << str
73
+ end
74
+
75
+ def instruction(name, attributes)
76
+ @buffer << "<?#{name}#{attributes}?>"
77
+ end
78
+
79
+ def comment(c)
80
+ unless Template.strip_xml_comments
81
+ @buffer << "<!--#{c}-->"
82
+ end
83
+ end
84
+ end
85
+
86
+ class << self
87
+ def parse(source)
88
+ self.new.parse(source)
89
+ end
90
+
91
+ def transform(source)
92
+ self.new.transform(source)
93
+ end
94
+ end
95
+
96
+ # Expand the elemens found in source.
97
+
98
+ def transform(source)
99
+ listener = Listener.new
100
+ REXML::Document.parse_stream(source, listener)
101
+ # gmosx, FIXME: optimize this, how?
102
+ # gmosx, FIXME: this is a hack fix, improve.
103
+ # TODO:farms why is cleanup called this many times?!?!? ... waste of gsubs
104
+ return listener.buffer
105
+ end
106
+ end
107
+
108
+ # An (old) alias.
109
+
110
+ unless const_defined? :ElementProcessor
111
+ ElementProcessor = Elements
112
+ end
113
+
114
+ end
115
+
116
+ # * George Moschovitis <gm@navel.gr>
117
+ # * Chris Farmiloe <chris.farmiloe@farmiloe.com>