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
File without changes
@@ -37,21 +37,24 @@ private
37
37
  if labels = options[:labels] || options[:labels_values]
38
38
  str = ''
39
39
 
40
- unless values = options[:values]
41
- if values = options[:labels_values]
42
- else
43
- values = (0...labels.size).to_a
44
- end
45
- end
40
+ values = options[:values] || options[:labels_values] || (0...labels.size).to_a
46
41
 
47
42
  selected = (options[:selected] || -1).to_i
48
43
 
49
44
  labels.each_with_index do |label, idx|
50
45
  value = values[idx]
46
+ if options[:style]
47
+ style = if options[:style].is_a?(Array)
48
+ options[:style][idx]
49
+ else
50
+ options[:style]
51
+ end
52
+ style = %{ style="#{style}"}
53
+ end
51
54
  if value == selected
52
- str << %|<option value="#{value}" selected="1">#{label}</option>|
55
+ str << %|<option value="#{value}" selected="selected"#{style}>#{label}</option>|
53
56
  else
54
- str << %|<option value="#{value}">#{label}</option>|
57
+ str << %|<option value="#{value}"#{style}>#{label}</option>|
55
58
  end
56
59
  end
57
60
 
@@ -99,7 +99,7 @@ end
99
99
  # output to a target buffer.
100
100
 
101
101
  class XmlBuilder
102
- include XmlMixin
102
+ include XmlHelper
103
103
 
104
104
  # The target receives the generated xml,
105
105
  # should respond_to :<<
@@ -3,6 +3,9 @@ module Nitro
3
3
  # Router mixin. Typically used to generate 'nice' urls.
4
4
  # Nice urls are considered (?) more Search Engine
5
5
  # friendly.
6
+ #
7
+ # However, due to the power of Nitro'w intelligent dispatching
8
+ # mechanism, routing is almost never used!
6
9
 
7
10
  module Router
8
11
 
@@ -10,6 +13,10 @@ module Router
10
13
  # can be handled by the Dispatcher.
11
14
 
12
15
  attr_accessor :routes
16
+
17
+ # Strip the beginning of the path, used by cgi adapter.
18
+
19
+ setting :strip_path, :default => nil, :doc => 'Strip the beginning of the path, used by cgi adapter'
13
20
 
14
21
  # Apply routing rules to the path.
15
22
 
@@ -23,6 +30,7 @@ module Router
23
30
  end
24
31
  end
25
32
 
33
+ path.sub!(Router.strip_path, '') if Router.strip_path
26
34
  return path
27
35
  end
28
36
 
@@ -31,4 +39,3 @@ end
31
39
  end
32
40
 
33
41
  # * George Moschovitis <gm@navel.gr>
34
-
@@ -0,0 +1,344 @@
1
+ require 'nitro/helper/form'
2
+ require 'nitro/helper/pager'
3
+
4
+
5
+ module Nitro
6
+
7
+ # This module is applied to controllers to provide
8
+ # automatically generated CRUD methods.
9
+ #--
10
+ # TODO: add search, add base, add to_title, validate/error
11
+ # handling.
12
+ #++
13
+
14
+ module Scaffolding
15
+
16
+ # The directory where the default scaffold templates reside.
17
+
18
+ setting :template_root, :default => File.join(Nitro.proto_path, 'public', 'scaffold'), :doc => 'The directory where the default scaffold templates reside'
19
+
20
+ # The items to show per page in the scaffolder lists.
21
+
22
+ setting :per_page, :default => 20, :doc => 'The items to show per page in the scaffolder lists'
23
+
24
+ def self.included(base)
25
+ super
26
+ base.helper(:form)
27
+ base.helper(:pager)
28
+ base.extend(ClassMethods)
29
+ end
30
+
31
+ def self.class_to_name(klass)
32
+ klass.to_s.demodulize.underscore.downcase
33
+ end
34
+
35
+ def self.class_to_list(klass)
36
+ klass.to_s.demodulize.underscore.downcase.plural
37
+ end
38
+
39
+ #--
40
+ # Compiles the scaffolding code.
41
+ #++
42
+
43
+ class ScaffoldCompiler
44
+
45
+ def initialize(controller, klass, options)
46
+ @controller = controller
47
+ @klass = klass
48
+ @options = options
49
+ @oid = options[:oid] || options[:pk]
50
+ @name = options[:name]
51
+ @plural = options[:plural_name]
52
+ @suffix = options[:suffix]
53
+ @compiler = Compiler.new(@controller)
54
+ @base = options[:base] || options[:mount] || options[:at]
55
+ @base = @plural.dup if @base == true
56
+ @base__ = "#{@base}__" if @base
57
+ end
58
+
59
+ def class_to_name(klass)
60
+ klass.to_s.demodulize.underscore.downcase
61
+ end
62
+
63
+ def define_class_method(meth, code)
64
+ unless @klass.instance_methods.include?(meth.to_s)
65
+ @klass.module_eval %{
66
+ def #{meth}
67
+ #{code}
68
+ end
69
+ }
70
+ end
71
+ end
72
+
73
+ def define_controller_action(definition, code, template = nil)
74
+ sym, args = definition.to_s.split(/\(|\)/)
75
+
76
+ if sym == 'index'
77
+ action = "#{@base__}index"
78
+ else
79
+ action = "#@base__#{sym}#@suffix"
80
+ end
81
+
82
+ unless @controller.action?(action)
83
+ @controller.module_eval %{
84
+ def #{action}(#{args})
85
+ @klass = #{@klass}
86
+ #{code}
87
+ end
88
+ }
89
+ end
90
+
91
+ unless @compiler.template?(action)
92
+
93
+ # Use the standard scaffold template.
94
+ path = File.join(Scaffolding.template_root, "#{template || sym}.xhtml")
95
+
96
+ if File.exist?(path) and source = File.read(path)
97
+ # Interpolate the source.
98
+ source.gsub!(/%base%/, @base.to_s)
99
+ source.gsub!(/%name%/, @name)
100
+ source.gsub!(/%plural%/, @plural)
101
+
102
+ # Transform the source.
103
+ source = @compiler.transform_template(source)
104
+
105
+ @controller.module_eval %{
106
+ def #{action}_template
107
+ #{source}
108
+ end
109
+ }
110
+ end
111
+ end
112
+ end
113
+
114
+ # Scaffold the class and the controller.
115
+
116
+ def scaffold
117
+ scaffold_class
118
+ scaffold_controller
119
+ end
120
+
121
+ # Scaffold the class.
122
+
123
+ def scaffold_class
124
+ define_class_method :scaffold_base, %{
125
+ "#{@controller.ann.self.mount_point}/#@base"
126
+ }
127
+
128
+ define_class_method :to_href, %{
129
+ "#{@controller.ann.self.mount_point}/#@base/view/\#@#{@oid}"
130
+ }
131
+
132
+ define_class_method :to_edit_href, %{
133
+ "#{@controller.ann.self.mount_point}/#@base/edit/\#@#{@oid}"
134
+ }
135
+ end
136
+
137
+ # Scaffold the controller.
138
+
139
+ def scaffold_controller
140
+ define_controller_action 'index', %{
141
+ #{Aspects.gen_advice_code(:scaffold_index, @controller.advices, :pre)}
142
+ @list, @pager = paginate(@klass, :per_page => Scaffolding.per_page)
143
+ }
144
+
145
+ define_controller_action 'list', %{
146
+ #{Aspects.gen_advice_code(:scaffold_list, @controller.advices, :pre)}
147
+ @list, @pager = paginate(@klass, :per_page => Scaffolding.per_page)
148
+ }
149
+
150
+ define_controller_action 'view(oid)', %{
151
+ #{Aspects.gen_advice_code(:scaffold_view, @controller.advices, :pre)}
152
+ @obj = @klass[oid]
153
+ }
154
+
155
+ define_controller_action 'new(all = false)', %{
156
+ #{Aspects.gen_advice_code(:scaffold_new, @controller.advices, :pre)}
157
+ @obj = @klass.new
158
+ @all = all
159
+ }
160
+
161
+ define_controller_action 'edit(oid = nil, all = false)', %{
162
+ #{Aspects.gen_advice_code(:scaffold_edit, @controller.advices, :pre)}
163
+ @obj = @klass[oid]
164
+ @all = all
165
+ }
166
+
167
+ # FIXME: investigate save, improve.
168
+
169
+ define_controller_action 'save', %{
170
+ if oid = request['#@oid']
171
+ oid = oid.to_s # fix StringIO (post).
172
+ obj = request.fill(@klass[oid], :assign_relations => true, :force_boolean => true, :preprocess => true)
173
+ else
174
+ obj = request.fill(@klass.create, :assign_relations => true, :preprocess => true)
175
+ end
176
+ #{Aspects.gen_advice_code(:scaffold_save, @controller.advices, :pre)}
177
+ unless obj.valid?
178
+ flash[:ERRORS] = obj.errors
179
+ redirect_to_referer
180
+ end
181
+ obj.save
182
+ #{Aspects.gen_advice_code(:scaffold_save, @controller.advices, :post)}
183
+ redirect '#{action_path(:list)}'
184
+ }
185
+
186
+ define_controller_action 'search(query)', %{
187
+ #{Aspects.gen_advice_code(:scaffold_search, @controller.advices, :pre)}
188
+ @query = query
189
+ if @klass.respond_to? :search
190
+ @list = #@klass.search(query)
191
+ end
192
+ }
193
+
194
+ define_controller_action 'delete(oid)', %{
195
+ #{Aspects.gen_advice_code(:scaffold_delete, @controller.advices, :pre)}
196
+ @klass.delete(oid)
197
+ #{Aspects.gen_advice_code(:scaffold_delete, @controller.advices, :post)}
198
+ redirect_to_referer
199
+ }
200
+
201
+ # Actions for the relations
202
+
203
+ for rel in @klass.relations
204
+ define_controller_action "remove_#{rel.target_singular_name}(oid, rid)", %{
205
+ obj = @klass[oid]
206
+ #{Aspects.gen_advice_code(:scaffold_remove_relation, @controller.advices, :pre)}
207
+ rob = #{rel.target_class}[rid]
208
+ obj.#{rel.name}.remove(rob)
209
+ #{Aspects.gen_advice_code(:scaffold_remove_relation, @controller.advices, :post)}
210
+ redirect_to_referer
211
+ }
212
+ define_controller_action "delete_#{rel.target_singular_name}(oid, rid)", %{
213
+ #{Aspects.gen_advice_code(:scaffold_delete_relation, @controller.advices, :pre)}
214
+ obj = @klass[oid]
215
+ rob = #{rel.target_class}[rid]
216
+ obj.#{rel.name}.delete(rob)
217
+ #{Aspects.gen_advice_code(:scaffold_delete_relation, @controller.advices, :post)}
218
+ redirect_to_referer
219
+ }
220
+ end
221
+ end
222
+
223
+ private
224
+
225
+ def action_method(sym)
226
+ action = "#{@base__}#{sym}"
227
+ action << @suffix unless @suffix.nil? or sym == :index
228
+ return action
229
+ end
230
+
231
+ def action_path(sym)
232
+ action = "#{@base}/#{sym}"
233
+ action << @suffix unless @suffix.nil? or sym == :index
234
+ return action
235
+ end
236
+ end
237
+
238
+ module ClassMethods
239
+
240
+ # This method modifies both the controller and the
241
+ # scaffolded Class.
242
+ #
243
+ # === Example
244
+ #
245
+ # scaffold Article
246
+ #
247
+ # ==== Actions/Methods added to the Controller
248
+ #
249
+ # * articles
250
+ # * edit_article
251
+ # * view_article
252
+ # * delete_article
253
+ # * search_artile
254
+ # * query_article
255
+ #
256
+ # ==== Methods added to the Class (ex: Article)
257
+ #
258
+ # * to_href
259
+ # * to_edit_href
260
+ #
261
+ #--
262
+ # This is the first phase of the scaffolding proccess,
263
+ # scaffold targets are marked, and default options set.
264
+ #++
265
+
266
+ def scaffold(klass, options = {})
267
+ o = {
268
+ :pk => 'oid',
269
+ :name => Scaffolding.class_to_name(klass),
270
+ :plural_name => Scaffolding.class_to_list(klass),
271
+ :mount => true
272
+ }
273
+ o.merge!(options)
274
+ if scaffolding_classes.has_key? klass
275
+ scaffolding_classes[klass].merge!(o)
276
+ else
277
+ scaffolding_classes[klass] = o
278
+ end
279
+ end
280
+
281
+ #--
282
+ # This is the second phase of the scaffolding process
283
+ #++
284
+
285
+ def compile_scaffolding_code
286
+ # load scaffolding for all og classes if specified
287
+
288
+ if scaffold_all?
289
+ options = scaffold_all_options
290
+ Og.manager.manageable_classes.each do |klass|
291
+ unless klass.ancestors.include?(Og::Unmanageable) or options[:except] && options[:except].include?(klass)
292
+ scaffold(klass, options)
293
+ end
294
+ end
295
+ scaffold_all false
296
+ end
297
+
298
+ # compile the scaffold methods
299
+
300
+ scaffolding_classes.each do |klass, options|
301
+ Scaffolding::ScaffoldCompiler.new(self, klass, options).scaffold
302
+ end
303
+ end
304
+
305
+ #--
306
+ # set the options flag to trigger scaffolding of all classes in second phase
307
+ # use exclude to ignore classes.... scaffold_all :exclude => [Product, Category]
308
+ #++
309
+
310
+ def scaffold_all(options = {})
311
+ if options
312
+ o = if options.kind_of? Hash then options else Hash.new end
313
+ else
314
+ o = nil
315
+ end
316
+ @scaffold_all_options = o
317
+ end
318
+
319
+ #--
320
+ # Keep track of scaffolded classes on this controller
321
+ #++
322
+
323
+ def scaffolding_classes
324
+ # TODO: maybe make this with a inhertitor?
325
+ # although inhertited scaffolding might be pointless
326
+ @scaffolding_classes ||= {}
327
+ end
328
+
329
+ #--
330
+ # Scaffold all classes flag
331
+ #++
332
+
333
+ def scaffold_all_options
334
+ @scaffold_all_options
335
+ end
336
+ alias_method :scaffold_all?, :scaffold_all_options
337
+
338
+ end
339
+
340
+ end
341
+
342
+ end
343
+
344
+ # * George Moschovitis <gm@navel.gr>
@@ -120,7 +120,11 @@ class Server
120
120
  server = Server.new
121
121
  server.start(options)
122
122
 
123
- runner.invoke(server) unless $NITRO_NO_INVOKE
123
+ unless $NITRO_NO_INVOKE
124
+ runner.invoke(server)
125
+ else
126
+ Logger.info 'Running in console mode.'
127
+ end
124
128
 
125
129
  return server
126
130
  end
@@ -1,6 +1,7 @@
1
1
  require 'optparse'
2
2
 
3
3
  require 'glue/configuration'
4
+ require 'nitro/compiler'
4
5
 
5
6
  module Nitro
6
7
 
@@ -151,6 +152,8 @@ class Runner
151
152
  irb_name = 'irb'
152
153
  end
153
154
  ENV['NITRO_INVOKE'] = 'irb'
155
+ $NITRO_NO_INVOKE = true
156
+ @server = :console
154
157
  conf_file = File.basename(caller.last.split(':').first)
155
158
  exec "#{irb_name} -r #{conf_file} -r irb/completion --noinspect"
156
159
  exit
@@ -284,31 +287,35 @@ class Runner
284
287
 
285
288
  @server ||= Runner.adapter
286
289
 
287
- puts "\n",
288
- "==> Listening at #{server.address}:#{server.port}. (#{self.class.mode} mode)",
289
- "==> Press Ctrl-C to shutdown; Run with --help for options.\n\n"
290
+ puts "\n==> Setup for #{self.class.mode} mode"
290
291
 
291
292
  case @server
292
293
  when :webrick
293
294
  require 'nitro/adapter/webrick'
295
+ puts "==> Listening at #{server.address}:#{server.port}."
296
+ puts "==> Press Ctrl-C to shutdown; Run with --help for options.\n\n"
294
297
  Webrick.start(server)
295
298
 
296
299
  when :lhttpd
297
300
  require 'nitro/adapter/fastcgi'
301
+ puts "==> Launching lighttpd (FastCGI)."
298
302
  `lighttpd -f conf/lhttpd_fcgi.conf`
299
303
 
300
304
  when :lhttpd_scgi
301
305
  require 'nitro/adapter/scgi'
306
+ puts "==> Launching lighttpd (SCGI)."
302
307
  `lighttpd -f conf/lhttpd_scgi.conf`
303
308
 
304
309
  when :apache
305
310
  require 'nitro/adapter/fastcgi'
311
+ puts "==> Launching apache (FastCGI)."
306
312
  `apachectl -d #{Dir.pwd} -f conf/apache.conf -k start`
307
313
 
308
314
  when :cgi
309
315
  require 'nitro/adapter/cgi'
316
+ puts "==> Using standard CGI. Please look into using Fast/Scgi"
310
317
  end
311
-
318
+
312
319
  when :stop
313
320
 
314
321
  case @server
@@ -342,24 +349,21 @@ class Runner
342
349
  # Attempt to load external configuration in Ruby or
343
350
  # YAML format. The files:
344
351
  #
345
- # * conf/mode.rb
352
+ # * conf/mode.rb
346
353
  # * conf/mode.yaml
347
354
  #
348
355
  # are considered.
349
356
 
350
357
  def load_external_configuration(mode = :debug)
351
- begin
352
- # gmosx: Workaround for an RDoc bug.
353
- # require "conf/#{mode}.rb"
354
- eval %|require 'conf/#{mode}.rb'|
355
- rescue Object
356
- end
358
+
359
+ # require "conf/#{mode}.rb"
360
+ ruby_conf = "conf/#{mode}.rb"
361
+ load ruby_conf if File.exist?(ruby_conf)
357
362
 
358
363
  # Try to configure from a yaml file.
359
- begin
360
- Configuration.load "conf/#{mode}.yml"
361
- rescue Object => ex
362
- end
364
+ yml_conf = "conf/#{mode}.yml"
365
+ Configuration.load yml_conf if File.exist?(yml_conf)
366
+
363
367
  end
364
368
 
365
369
  end