nitro 0.25.0 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
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>