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
@@ -3,7 +3,9 @@ require 'glue/markup'
3
3
  module Nitro
4
4
 
5
5
  module Markup
6
-
6
+
7
+ include Glue::Markup
8
+
7
9
  # Transform the markup macros.
8
10
  # Maps #(..) to :sanitize.
9
11
  # Maps #|..| to :markup.
@@ -1,95 +1,190 @@
1
1
  require 'rexml/document'
2
2
  require 'rexml/streamlistener'
3
3
 
4
+ require 'mega/dictionary'
5
+ require 'nano/string/blank'
6
+
7
+ require 'glue/html'
8
+
4
9
  module Nitro
5
10
 
6
- # A compiler that handles these attribute's tags:
11
+ # :section: A collection of standard morphers.
12
+
13
+ # The base morpher class. Morphers are triggered
14
+ # by a special 'key' attribute in the xml stream and
15
+ # transform the owner element.
16
+
17
+ class Morpher
18
+ def initialize(key, name, attributes)
19
+ @key = key
20
+ @name = name
21
+ @attributes = attributes
22
+ @value = @attributes[@key]
23
+ end
24
+
25
+ def before_start(buffer); end
26
+ def after_start(buffer); end
27
+ def before_end(buffer); end
28
+ def after_end(buffer); end
29
+ end
30
+
31
+ # A useful super class for morphers.
32
+
33
+ class StandardMorpher < Morpher
34
+ def after_end(buffer)
35
+ # gmosx: leave the leading space.
36
+ buffer << " <?r end ?>"
37
+ end
38
+ end
39
+
40
+ # attribute: times
7
41
  #
8
- # <tag if="x">..</tag>
9
- # <tag unless="x">..</tag>
10
- # <tag each="x">..</tag>
11
- # <tag times="x">..</tag>
42
+ # <li times="3">...</li>
43
+ #
44
+ # becomes
12
45
  #
13
- # by transforming them like that
46
+ # <?r 3.times do ?>
47
+ # <li>...</li>
48
+ # <?r end ?>
49
+
50
+ class TimesMorpher < StandardMorpher
51
+ def before_start(buffer)
52
+ # gmosx: leave the trailing space.
53
+ buffer << "<?r #@value.times do ?> "
54
+ @attributes.delete(@key)
55
+ end
56
+ end
57
+
58
+ # attribute: each, for
14
59
  #
15
- # <div prop1="one" if="@mycond" prop2="two">@mycond is true</div>
60
+ # <li each="item in array">my item is #{item}</li>
16
61
  #
17
62
  # becomes
18
63
  #
19
- # <?r if @mycond ?>
20
- # <div prop1="one" prop2="two">@mycond is true</div>
64
+ # <?r for item in array ?>
65
+ # <li>my item is #{item}</li>
21
66
  # <?r end ?>
67
+
68
+ class EachMorpher < Morpher
69
+ def before_start(buffer)
70
+ if @value =~ / in /
71
+ buffer << "<?r for #@value ?> "
72
+ @attributes.delete(@key)
73
+ end
74
+ end
75
+
76
+ def after_end(buffer)
77
+ if @value =~ / in /
78
+ buffer << " <?r end ?>"
79
+ end
80
+ end
81
+ end
82
+
83
+ # attribute: if, unless
22
84
  #
85
+ # <div prop1="one" if="@mycond" prop2="two">@mycond is true</div>
23
86
  #
24
- # <li times="3">...</li>
25
- #
26
87
  # becomes
27
88
  #
28
- # <?r 3.times do ?>
29
- # <li>...</li>
89
+ # <?r if @mycond ?>
90
+ # <div prop1="one" prop2="two">@mycond is true</div>
30
91
  # <?r end ?>
92
+
93
+ class IfMorpher < StandardMorpher
94
+ def before_start(buffer)
95
+ buffer << "<?r #@key #@value ?> "
96
+ @attributes.delete(@key)
97
+ end
98
+ end
99
+
100
+ # attribute: selected_if, checked_if, selected_unless, checked_unless
31
101
  #
32
- #
33
- # <li each="item in array">my item is #{item}</li>
102
+ # <option value="1" selected_if="@cond">opt1</option>
34
103
  #
35
104
  # becomes
36
105
  #
37
- # <?r for item in array ?>
38
- # <li>my item is #{item}</li>
106
+ # <?r if @cond ?>
107
+ # <option value="1" selected="selected">opt1</option>
108
+ # <?r else ?>
109
+ # <option value="1">opt1</option>
39
110
  # <?r end ?>
40
111
 
112
+ class SelectedIfMorpher < StandardMorpher
113
+ def before_start(buffer)
114
+ @attr, @cond = @key.split('_')
115
+ @attributes.delete(@key)
116
+ @attributes[@attr] = @attr
117
+ buffer << "<?r #@cond #@value ?> "
118
+ end
119
+
120
+ def after_start(buffer)
121
+ @start_index = buffer.length
122
+ end
123
+
124
+ def before_end(buffer)
125
+ @attributes.delete(@attr)
126
+ @end_index = buffer.length
127
+ buffer << Morphing.emit_end(@name)
128
+ buffer << "<?r else ?>"
129
+ buffer << Morphing.emit_start(@name, @attributes)
130
+ buffer << buffer[@start_index...@end_index]
131
+ end
132
+
133
+ end
134
+
135
+ # :section: The morphing system.
136
+
137
+ # A compiler module that translates xml stream. Multiple
138
+ # 'key' attributes are supported per element.
139
+
41
140
  class Morphing
42
141
 
142
+ #--
143
+ # The listener used to parse the xml stream.
144
+ #
145
+ # TODO: add support for morphing comments, text, etc.
146
+ #++
147
+
43
148
  class Listener # :nodoc: all
44
149
  include REXML::StreamListener
45
-
46
- attr_reader :buffer
150
+
151
+ attr_accessor :buffer
47
152
 
48
153
  def initialize
49
154
  super
50
155
  @buffer = ''
51
156
  @stack = []
52
- @depth = 0
53
157
  end
54
-
158
+
55
159
  def tag_start(name, attributes)
56
- if attr = attributes.detect { |k, v| %w{if unless for each times}.include?(k) }
57
- temp_buffer =
58
- if attr[0] == 'times'
59
- "<?r #{attr[1]}.times do ?>"
60
- elsif (attr[0] == 'for' or attr[0] == 'each') and attr[1] =~ / in /
61
- "<?r for #{attr[1]} ?>"
62
- elsif attr[0] == 'if' or attr[0] == 'unless'
63
- "<?r #{attr[0]} #{attr[1]} ?>"
64
- else
65
- Logger.info "Morphing: #{attr[0]} attribute found but was not suitable for morphing" if $DBG
66
- false
67
- end
68
- if temp_buffer
69
- @buffer << temp_buffer
70
- attributes.delete(attr[0])
71
- @stack.push(@depth)
72
- end
73
- end
160
+ morphers = []
161
+
162
+ #for key, val in attributes
163
+ # if morpher_class = Morphing.morphers[key]
164
+ # morphers << morpher_class.new(key, name, attributes)
165
+ # end
166
+ #end
74
167
 
75
- attrs = attributes.collect do | k, v |
76
- %|#{k}="#{v}"|
168
+ Morphing.morphers.each do |key, morpher_class|
169
+ if attributes.has_key? key
170
+ morphers << morpher_class.new(key, name, attributes)
171
+ end
77
172
  end
78
173
 
79
- attrs = attrs.empty? ? "" : " " + attrs.join(' ')
80
- @depth += 1
81
- @buffer << "<#{name}#{attrs}>"
174
+ morphers.each { |h| h.before_start(@buffer) }
175
+ @buffer << Morphing.emit_start(name, attributes)
176
+ morphers.each { |h| h.after_start(@buffer) }
177
+
178
+ @stack.push(morphers)
82
179
  end
83
180
 
84
181
  def tag_end(name)
85
- @depth -= 1
86
- @buffer << "</#{name}>"
87
- if @stack.last == @depth
88
- @buffer << "\n<?r end ?>"
89
- @stack.pop
90
- end
182
+ morphers = @stack.pop
183
+ morphers.reverse.each { |h| h.before_end(@buffer) }
184
+ @buffer << Morphing.emit_end(name)
185
+ morphers.reverse.each { |h| h.after_end(@buffer) }
91
186
  end
92
-
187
+
93
188
  def text(str)
94
189
  @buffer << str
95
190
  end
@@ -97,6 +192,26 @@ class Morphing
97
192
  def instruction(name, attributes)
98
193
  @buffer << "<?#{name}#{attributes}?>"
99
194
  end
195
+
196
+ def comment(c)
197
+ unless Template.strip_xml_comments
198
+ @buffer << "<!--#{c}-->"
199
+ end
200
+ end
201
+
202
+ def doctype(name, pub_sys, long_name, uri)
203
+ @buffer << "<!DOCTYPE #{name} #{pub_sys} #{long_name} #{uri}>"
204
+ end
205
+ end
206
+
207
+
208
+ def self.emit_start(name, attributes)
209
+ attrs = attributes.map{ |k, v| %|#{k}="#{v}"| }.join(' ')
210
+ attrs.blank? ? "<#{name}>" : "<#{name} #{attrs}>"
211
+ end
212
+
213
+ def self.emit_end(name)
214
+ "</#{name}>"
100
215
  end
101
216
 
102
217
  def self.transform(source)
@@ -105,32 +220,47 @@ class Morphing
105
220
  return listener.buffer
106
221
  end
107
222
 
108
- end
223
+ # The morphers map.
224
+
225
+ @morphers = Dictionary.new
226
+
227
+ class << self
228
+
229
+ def morphers
230
+ @morphers
231
+ end
232
+
233
+ def morphers=(hash)
234
+ @morphers = hash
235
+ end
236
+
237
+ def add_morpher(key, klass)
238
+ @morphers[key.to_s] = klass
239
+ end
240
+ alias_method :add, :add_morpher
241
+
242
+ def delete_morpher(key)
243
+ @morphers.delete(key)
244
+ end
245
+ alias_method :delete, :delete_morpher
246
+ end
109
247
 
248
+ # Install the default morphers.
249
+
250
+ add_morpher :times, TimesMorpher
251
+ add_morpher :if, IfMorpher
252
+ add_morpher :unless, IfMorpher
253
+ add_morpher :each, EachMorpher
254
+ add_morpher :for, EachMorpher
255
+ add_morpher :selected_if, SelectedIfMorpher
256
+ add_morpher :selected_unless, SelectedIfMorpher
257
+ add_morpher :checked_if, SelectedIfMorpher
258
+ add_morpher :checked_unless, SelectedIfMorpher
259
+
110
260
  end
111
261
 
112
- if __FILE__ == $0
113
- puts Nitro::Morphing.transform(<<EOF)
114
- <body>
115
- <child attr1="attr1" if="test" attr2="attr2">
116
- <mytag>
117
- this is texxt
118
- <one if="@qsdf">
119
- qqqqq
120
- </one>
121
- </mytag>
122
- </child>
123
- <child times="4">
124
- <mytag>
125
- qqqqq
126
- </mytag>
127
- <one if="@qsdf">
128
- text
129
- </one>
130
- </child>
131
- </body>
132
- EOF
133
262
  end
134
263
 
135
264
  # * George Moschovitis <gm@navel.gr>
136
265
  # * Guillaume Pierronnet <guillaume.pierronnet@gmail.com>
266
+ # * Chris Farmiloe <chris.farmiloe@farmiloe.com>
@@ -0,0 +1,14 @@
1
+ require 'glue/markup'
2
+
3
+ module Nitro
4
+
5
+ # Generates in-page javascript
6
+
7
+ module ScriptGenerator
8
+
9
+ def self.transform(text)
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -1,5 +1,5 @@
1
1
  require 'nitro/template'
2
- require 'nitro/element'
2
+ require 'nitro/compiler/elements'
3
3
 
4
4
  module Nitro
5
5
 
@@ -60,17 +60,16 @@ class Context
60
60
  alias_method :finish, :close
61
61
 
62
62
  #--
63
- # FIXME: something more elegant/efficient.
63
+ # FIXME: still something more elegant/efficient.
64
64
  #++
65
65
 
66
66
  def out
67
- if @out == '(error)'
68
- @out = ''
67
+ return @out if @out == ""
68
+ if @rendering_errors
69
+ @out = String.new
69
70
  render '/error'
70
- @out
71
- else
72
- @out
73
71
  end
72
+ @out
74
73
  end
75
74
 
76
75
  # Lazy lookup of the session to avoid costly cookie
@@ -5,35 +5,19 @@ require 'glue/markup'
5
5
 
6
6
  require 'nitro'
7
7
  require 'nitro/render'
8
- require 'nitro/scaffold'
8
+ require 'nitro/scaffolding'
9
9
  require 'nitro/caching'
10
10
  require 'nitro/flash'
11
11
  require 'nitro/helper'
12
12
 
13
13
  module Nitro
14
14
 
15
- # Encapsulates metadata that describe an action
16
- # parameter.
17
- #
18
- # [+default+]
19
- # The default value.
20
- #
21
- # [+format+]
22
- # The expected format.
23
- #
24
- # [+required+]
25
- # Is this parameter required?
26
-
27
- unless const_defined? :ActionParam
28
- ActionParam = Struct.new(:default, :format, :required)
29
- end
30
-
31
15
  # Include this Mixin to a class to make objects of this class
32
16
  # publishable, ie accessible through a standard web (REST)
33
17
  # interface.
34
18
 
35
19
  module Publishable
36
- def self.append_features(base)
20
+ def self.included(base)
37
21
  super
38
22
 
39
23
  base.module_eval do
@@ -55,7 +39,7 @@ module Publishable
55
39
  # Helper method.
56
40
 
57
41
  def template_root
58
- self.class.template_root || Template.root
42
+ self.class.template_root
59
43
  end
60
44
  end
61
45
 
@@ -100,7 +84,7 @@ module Publishable
100
84
 
101
85
  base.module_eval do
102
86
  def method_missing(action, *args)
103
- if Compiler.new.compile(self.class, action)
87
+ if Compiler.new(self.class).compile(action)
104
88
  send(action, *args)
105
89
  else
106
90
  super
@@ -108,6 +92,33 @@ module Publishable
108
92
  end
109
93
  end
110
94
 
95
+ # Does this publishable respond to the given action?
96
+
97
+ base.module_eval do
98
+ class << self
99
+ def respond_to_action?(action)
100
+ action_methods.include?(action.to_s)
101
+ end
102
+ alias_method :action?, :respond_to_action?
103
+ end
104
+ end
105
+
106
+ # Does this class respond to the given action?
107
+ # Also looks for templates in the template root.
108
+ #
109
+ # Prefer to use the compiler for this.
110
+ #--
111
+ # THINK: maybe move template? here
112
+ #++
113
+
114
+ base.module_eval do
115
+ class << self
116
+ def respond_to_action_or_template?(sym)
117
+ return self.respond_to_action?(sym.to_s) || Compiler.new(self).template?(sym)
118
+ end
119
+ end
120
+ end
121
+
111
122
  # Cookie helpers.
112
123
  #--
113
124
  # TODO: move elsewhere.
@@ -138,9 +149,20 @@ class Controller
138
149
  include Caching
139
150
  include Helpers
140
151
  helper Markup
152
+
153
+ # This callback is called after the Controller is mounted.
154
+
155
+ def self.mounted(path)
156
+ # Resolve aspects.
157
+ Aspects.include_advice_modules(self)
158
+
159
+ # The scaffolding code is compiled after the mount, so
160
+ # that template roots are finalized.
161
+ compile_scaffolding_code
162
+ end
163
+
141
164
  end
142
165
 
143
166
  end
144
167
 
145
168
  # * George Moschovitis <gm@navel.gr>
146
-