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
@@ -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
-