nitro 0.19.0 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/CHANGELOG +187 -0
  2. data/INSTALL +5 -0
  3. data/README +11 -5
  4. data/doc/AUTHORS +11 -1
  5. data/doc/RELEASES +217 -0
  6. data/doc/tutorial.txt +1 -2
  7. data/lib/nitro.rb +9 -6
  8. data/lib/nitro/adapter/webrick.rb +13 -2
  9. data/lib/nitro/builder/form.rb +11 -9
  10. data/lib/nitro/builder/rss.rb +2 -2
  11. data/lib/nitro/builder/xhtml.rb +15 -0
  12. data/lib/nitro/caching.rb +15 -10
  13. data/lib/nitro/conf.rb +0 -5
  14. data/lib/nitro/controller.rb +118 -81
  15. data/lib/nitro/cookie.rb +6 -6
  16. data/lib/nitro/dispatcher.rb +62 -18
  17. data/lib/nitro/element.rb +4 -1
  18. data/lib/nitro/element/java_script.rb +15 -0
  19. data/lib/nitro/localization.rb +3 -4
  20. data/lib/nitro/markup.rb +4 -4
  21. data/lib/nitro/mixin/debug.rb +30 -0
  22. data/lib/nitro/mixin/helper.rb +14 -0
  23. data/lib/nitro/mixin/javascript.rb +137 -0
  24. data/lib/nitro/{ui → mixin}/pager.rb +110 -82
  25. data/lib/nitro/render.rb +20 -8
  26. data/lib/nitro/request.rb +6 -0
  27. data/lib/nitro/routing.rb +6 -5
  28. data/lib/nitro/runner.rb +21 -9
  29. data/lib/nitro/server.rb +95 -0
  30. data/lib/nitro/service.rb +0 -1
  31. data/lib/nitro/session.rb +4 -5
  32. data/lib/nitro/shaders.rb +2 -2
  33. data/lib/nitro/template.rb +1 -1
  34. data/lib/nitro/testing/assertions.rb +2 -4
  35. data/lib/nitro/testing/context.rb +4 -6
  36. data/proto/public/js/behaviour.js +254 -0
  37. data/proto/public/js/controls.js +446 -0
  38. data/proto/public/js/dragdrop.js +537 -0
  39. data/proto/public/js/effects.js +612 -0
  40. data/proto/public/js/prototype.js +644 -370
  41. data/proto/public/settings.xhtml +64 -0
  42. data/test/nitro/adapter/tc_cgi.rb +2 -2
  43. data/test/nitro/builder/tc_rss.rb +1 -1
  44. data/test/nitro/mixin/tc_pager.rb +35 -0
  45. data/test/nitro/tc_controller.rb +1 -1
  46. data/test/nitro/tc_cookie.rb +14 -0
  47. data/test/nitro/tc_dispatcher.rb +11 -6
  48. data/test/nitro/tc_server.rb +35 -0
  49. metadata +20 -15
  50. data/lib/nitro/builder/atom.rb +0 -74
  51. data/lib/nitro/part.rb +0 -22
  52. data/lib/nitro/simple.rb +0 -11
  53. data/lib/nitro/ui/popup.rb +0 -41
  54. data/lib/nitro/ui/tabs.rb +0 -25
  55. data/lib/nitro/uri.rb +0 -193
  56. data/test/nitro/builder/tc_atom.rb +0 -24
  57. data/test/nitro/tc_uri.rb +0 -97
  58. data/test/nitro/ui/tc_pager.rb +0 -49
@@ -1,78 +1,58 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: pager.rb 1 2005-04-11 11:04:30Z gmosx $
1
+ require 'glue/uri'
2
+ require 'glue/configuration'
4
3
 
5
- require 'nitro/uri'
6
-
7
- module Nitro; module UI
4
+ module Nitro
8
5
 
9
6
  # Displays a collection of entitities in multiple pages.
10
7
  #
11
8
  # === Design
12
9
  #
13
- # The new version is carefully designed for scaleability. It stores
10
+ # This pager is carefully designed for scaleability. It stores
14
11
  # only the items for one page. The name parameter is needed, multiple
15
12
  # pagers can coexist in a single page. Unlike older pagers this
16
- # pager leverages the SQL LIMIT option to optimize database interaction.
17
- #
18
- # === Example
19
- #
20
- # @pager = UI::Pager.new('entries', @request, 5)
21
- # @entries = BlogEntry.all("ORDER BY oid #{@pager.sql_limit}")
22
- # @pager.set(BlogEntry.count)
23
- #
24
- # default navigation (customize with css):
25
- # <div class="pager">#{@pager.navigation}</div>
26
- #
27
- # custom navigation:
28
- #
29
- # <table cellspacing="0" width="100%" border="1">
30
- # <tr>
31
- # <td width="64"><x:pager-prev>Previous</x:pager-prev></td>
32
- # <td width="100%"></td>
33
- # <td width="64"><x:pager-next>Next</x:pager-next></td>
34
- # </tr>
35
- # </table>
36
- #--
37
- # INVESTIGATE:
38
- # mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
39
- # -> WHERE id > 100 LIMIT 10;
40
- # mysql> SELECT FOUND_ROWS();
41
- #++
42
-
43
- class Pager < Array
44
-
45
- attr_accessor :name, :idx, :page, :page_count
46
-
47
- # Total count of items
48
- attr_accessor :total_count
13
+ # pager leverages the SQL LIMIT option to optimize database
14
+ # interaction.
15
+
16
+ class Pager
17
+ # Items per page.
49
18
 
50
- # Page items
51
- attr_accessor :page_items
19
+ setting :per_page, :default => 10, :doc => 'Items per page'
52
20
 
53
- # Read needed variables from the request.
54
- attr_accessor :request
21
+ # The request key.
55
22
 
56
- def initialize(name, request, items_per_page = 10, items = nil)
57
- raise "items_per_page should be > 0" unless items_per_page > 0
23
+ setting :key, :default => '_page', :doc => 'The request key'
24
+
25
+ # The current page.
26
+
27
+ attr_accessor :page
28
+
29
+ # Items per page.
30
+
31
+ attr_accessor :per_page
58
32
 
59
- @request, @name = request, name
60
- @page = request.query.fetch("__pg#{@name}", 1).to_i
61
- @items_per_page = items_per_page
62
- @start_idx = (@page - 1) * items_per_page
33
+ # The total number of pages.
34
+
35
+ attr_accessor :page_count
36
+
37
+ # Total count of items.
38
+
39
+ attr_accessor :total_count
63
40
 
64
- if items
65
- set(items.size())
66
- # gmosx, FIXME: not exactly what i want!
67
- items.slice!(@start_idx, @items_per_page)
68
- end
69
- end
41
+ def initialize(request, per_page, total_count, key = Pager.key)
42
+ raise 'per_page should be > 0' unless per_page > 0
70
43
 
71
- def set(total_count)
44
+ @request, @key = request, key
45
+ @page = request.query.fetch(key, 1).to_i
46
+ @per_page = per_page
47
+ set_count(total_count)
48
+ @start_idx = (@page - 1) * per_page
49
+ end
50
+
51
+ def set_count(total_count)
72
52
  @total_count = total_count
73
- @page_count = (@total_count.to_f() / @items_per_page).ceil()
53
+ @page_count = (@total_count.to_f / @per_page).ceil
74
54
  end
75
-
55
+
76
56
  def first_page
77
57
  return 1
78
58
  end
@@ -135,10 +115,33 @@ class Pager < Array
135
115
 
136
116
  return (s..e)
137
117
  end
118
+
119
+ # To be used with Og queries.
120
+
121
+ def limit
122
+ { :limit => @per_page, :offset => @start_idx }
123
+ end
124
+
125
+ def offset
126
+ @start_idx
127
+ end
128
+
129
+ # Create an appropriate SQL limit clause.
130
+ # Returns postgres/mysql compatible limit.
138
131
 
139
- # Override this method in your application
140
- # if needed.
132
+ def to_sql
133
+ if @start_idx > 0
134
+ return "LIMIT #{@per_page} OFFSET #{@start_idx}"
135
+ else
136
+ # gmosx: perhaps this is optimized ? naaaaaah...
137
+ return "LIMIT #{@per_page}"
138
+ end
139
+ end
140
+
141
+ # Override this method in your application if needed.
142
+ #--
141
143
  # TODO: better markup.
144
+ #++
142
145
 
143
146
  def navigation
144
147
  nav = ""
@@ -175,32 +178,57 @@ class Pager < Array
175
178
 
176
179
  return nav
177
180
  end
181
+ alias_method :links, :navigation
182
+
183
+ private
178
184
 
179
- # Create an appropriate SQL limit clause.
180
- # Returns postgres/mysql compatible limit.
181
-
182
- def sql_limit
183
- if @start_idx > 0
184
- return "LIMIT #{@items_per_page} OFFSET #{@start_idx}"
185
- else
186
- # gmosx: perhaps this is optimized ? naaaaaah...
187
- return "LIMIT #{@items_per_page}"
188
- end
189
- end
190
-
191
- # Returns the current offset. The offset is zero-based.
192
-
193
- def offset
194
- (@page-1) * @items_per_page
195
- end
196
-
197
185
  # Generate the target URI.
198
- #
186
+
199
187
  def target_uri(page)
200
- params = {"__pg#{@name}" => page}
188
+ params = { @key => page }
201
189
  return UriUtils.update_query_string(@request.uri.to_s, params)
202
190
  end
203
191
 
204
192
  end
205
193
 
206
- end; end
194
+ # Pager related helper methods.
195
+
196
+ module PagerMixin
197
+
198
+ private
199
+
200
+ # Helper method that generates a collection of items and the
201
+ # asorted pager object.
202
+ #
203
+ # === Example
204
+ #
205
+ # entries, pager = paginate(Article, :condition => 'title LIKE %Ab%', :per_page => 10)
206
+ #
207
+ # <ul>
208
+ # <?r for entry in entries ?>
209
+ # <li>#{entry.to_link}</li>
210
+ # <?r end ?>
211
+ # </ul>
212
+ # #{pager.links}
213
+
214
+ def paginate(klass_or_array, options = {})
215
+ per_page = options.delete(:per_page) || Pager.per_page
216
+
217
+ if klass_or_array.is_a? Array
218
+ items = klass_or_array.dup
219
+ pager = Pager.new(request, per_page, items.size, key = Pager.key)
220
+ items = items.slice(pager.offset, pager.per_page)
221
+ return items, pager
222
+ else
223
+ pager = Pager.new(request, per_page, klass_or_array.count(options), key = Pager.key)
224
+ options.update(pager.limit)
225
+ items = klass_or_array.all(options)
226
+ return items, pager
227
+ end
228
+ end
229
+
230
+ end
231
+
232
+ end
233
+
234
+ # * George Moschovitis <gm@navel.gr>
data/lib/nitro/render.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  require 'sync'
2
2
 
3
+ require 'facet/string/blank%3F'
4
+
3
5
  require 'glue/attribute'
4
6
  require 'glue/misc'
5
7
  require 'glue/object'
8
+ require 'glue/settings'
6
9
 
7
10
  require 'nitro/shaders'
8
11
  require 'nitro/buffering'
@@ -27,12 +30,12 @@ module Rendering
27
30
  @@sync = Sync.new
28
31
 
29
32
  # The default template root
30
-
31
- mattr_accessor :default_template_root, 'public'
32
-
33
+
34
+ setting :default_template_root, :default => 'public', :doc => 'The default template root'
35
+
33
36
  # The default template name (no extension).
34
37
 
35
- mattr_accessor :default_template, 'index'
38
+ setting :default_template, :default => 'index', :doc => 'The default template name (no extension).'
36
39
 
37
40
  # The shader used for transforming templates.
38
41
  # The default shader is very simple, here is a
@@ -48,11 +51,12 @@ module Rendering
48
51
  # </tt>
49
52
 
50
53
  mattr_accessor :shader; @@shader = RubyShader.new
54
+ # setting :shader, :default => RubyShader.new, :doc => 'The shader used for transforming templates'
51
55
 
52
56
  # If set to :full, reloads all controllers. Useful in
53
57
  # development.
54
58
 
55
- mattr_accessor :reload, false
59
+ setting :reload, :default => false, :doc => 'If set to :full reloads everything, useful in development'
56
60
 
57
61
  # Given the action try find the matching template.
58
62
  # Can search for xhtml or xml templates.
@@ -133,15 +137,17 @@ module Rendering
133
137
 
134
138
  param_count = klass.instance_method(action.intern).arity
135
139
 
140
+ # gmosx, FIXME: REIMPLEMENT THIS!!!!
141
+
136
142
  if param_count > 0
137
143
  code << %{
144
+ params = []
138
145
  qs = context.query_string.split(/[&;]/)
139
146
 
140
- params = []
141
147
  #{param_count}.times do |i|
142
148
  params << qs.shift.split(/=/).last
143
149
  end
144
-
150
+
145
151
  unless :stop == #{action}(*params)
146
152
  }
147
153
  else
@@ -272,7 +278,11 @@ module Render
272
278
  # The name of the currently executing action.
273
279
 
274
280
  attr_accessor :action_name
275
-
281
+
282
+ # The name of the current controller.
283
+
284
+ attr_accessor :controller_name
285
+
276
286
  # Initialize the render.
277
287
  #
278
288
  # [+context+]
@@ -280,6 +290,7 @@ module Render
280
290
 
281
291
  def initialize(context, base = nil)
282
292
  @request = @response = @context = context
293
+ @controller_name = base
283
294
  @out = context.out
284
295
  end
285
296
 
@@ -324,6 +335,7 @@ private
324
335
  def redirect(url, status = 303)
325
336
  url = url.to_s
326
337
  url = "#{@context.host_url}/#{url.gsub(/^\//, '')}" unless url =~ /http/
338
+
327
339
  @context.status = status
328
340
  @context.out = "<html><a href=\"#{url}\">#{url}</a>.</html>\n"
329
341
  @context.response_headers['location'] = url
data/lib/nitro/request.rb CHANGED
@@ -152,6 +152,12 @@ module Request
152
152
  def []=(param, value)
153
153
  @params[param] = value
154
154
  end
155
+
156
+ # Fetch a parameter with default value.
157
+
158
+ def fetch(param, default = nil)
159
+ @params.fetch(param, default)
160
+ end
155
161
  end
156
162
 
157
163
  end
data/lib/nitro/routing.rb CHANGED
@@ -1,10 +1,8 @@
1
- # * George Moschovitis <gm@navel.gr>
2
- # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: routing.rb 1 2005-04-11 11:04:30Z gmosx $
4
-
5
1
  module Nitro
6
2
 
7
- # Router mixin.
3
+ # Router mixin. Typically used to generate 'nice' urls.
4
+ # Nice urls are considered (?) more Search Engine
5
+ # friendly.
8
6
 
9
7
  module Router
10
8
 
@@ -31,3 +29,6 @@ module Router
31
29
  end
32
30
 
33
31
  end
32
+
33
+ # * George Moschovitis <gm@navel.gr>
34
+
data/lib/nitro/runner.rb CHANGED
@@ -3,6 +3,8 @@
3
3
  require 'optparse'
4
4
 
5
5
  require 'glue/misc'
6
+ require 'glue/configuration'
7
+
6
8
  require 'nitro/conf'
7
9
 
8
10
  module Nitro
@@ -135,7 +137,8 @@ class Runner
135
137
  end
136
138
  ENV['NITRO_INVOKE'] = 'irb'
137
139
  conf_file = File.basename(caller.last.split(':').first)
138
- exec "#{irb_name} -r #{conf_file} -r irb/completion --noinspect"
140
+ # exec "#{irb_name} -r #{conf_file} -r irb/completion --noinspect"
141
+ exec "#{irb_name} -r #{conf_file} --noinspect"
139
142
  exit
140
143
  end
141
144
 
@@ -170,20 +173,19 @@ class Runner
170
173
  # using the passed configuration parameters.
171
174
 
172
175
  def run(conf)
173
-
174
176
  if conf.is_a?(Hash)
175
177
  conf = Conf.new(conf)
176
178
  end
177
179
 
178
180
  case @mode
179
- when :debug
180
- setup_debug(conf)
181
+ when :debug
182
+ setup_debug(conf)
181
183
 
182
- when :stage
183
- setup_stage(conf)
184
-
185
- when :live
186
- setup_live(conf)
184
+ when :stage
185
+ setup_stage(conf)
186
+
187
+ when :live
188
+ setup_live(conf)
187
189
  end
188
190
 
189
191
  if 'fcgi_proc' == ENV['NITRO_INVOKE']
@@ -330,6 +332,16 @@ def self.run(conf = nil)
330
332
  runner.run(conf)
331
333
  end
332
334
 
335
+ #--
336
+ # Experimental.
337
+ #++
338
+
339
+ def self.start(controller)
340
+ # require 'glue/autoreload'
341
+ # autoreload(3)
342
+ Server.run(controller)
343
+ end
344
+
333
345
  end
334
346
 
335
347
  # * George Moschovitis <gm@navel.gr>
@@ -0,0 +1,95 @@
1
+ require 'glue/autoreload'
2
+ require 'nitro/adapter/webrick'
3
+
4
+ module Nitro
5
+
6
+ class Server
7
+
8
+ # :nodoc: all
9
+ # A Helper class used for CherryPy-style publishing.
10
+
11
+ class Mounter
12
+ def initialize(parent, base = '')
13
+ @parent, @base = parent, base
14
+ end
15
+
16
+ def method_missing(sym, *args)
17
+ sym = sym.to_s
18
+ if sym =~ /=$/
19
+ @parent.map["#@base/#{sym.gsub(/=/, '')}"] = args.first
20
+ else
21
+ Mounter.new(@parent, "#@base/#{sym}")
22
+ end
23
+ end
24
+ end
25
+
26
+ # The server listening address.
27
+ #--
28
+ # 0.0.0.0 may be a better default?
29
+ #++
30
+
31
+ setting :address, :default => '127.0.0.1', :doc => 'The server listening address'
32
+
33
+ # The server listening port.
34
+
35
+ setting :port, :default => 9999, :doc => 'The server listening port'
36
+
37
+ # The map.
38
+
39
+ setting :map, :default => { '/' => SimpleController }, :doc => 'The server map'
40
+
41
+ # The name of the application.
42
+
43
+ attr_accessor :name
44
+
45
+ # The sitemap. Defines how controller objects are published.
46
+
47
+ attr_accessor :map
48
+
49
+ def initialize(name = 'Nitro')
50
+ @name = name
51
+ @map = self.class.map.dup
52
+ end
53
+
54
+ # Start the server.
55
+
56
+ def start(controller = nil)
57
+ self.map['/'] = controller if controller
58
+
59
+ $DBG = true
60
+ autoreload(3)
61
+ Rendering.reload = :full
62
+
63
+ dispatcher = Dispatcher.new
64
+ dispatcher.publish(self.map)
65
+ conf = {
66
+ :dispatcher => dispatcher
67
+ }
68
+
69
+ Webrick.start(Conf.new(conf))
70
+ end
71
+
72
+ def root=(controller)
73
+ @map['/'] = controller
74
+ end
75
+
76
+ def root
77
+ Mounter.new(self)
78
+ end
79
+
80
+ # Helper method.
81
+
82
+ def self.run(controller = nil)
83
+ server = Server.new
84
+ server.start(controller)
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ # Alias for the Server class.
92
+
93
+ App = Nitro::Server unless Object.const_defined?(:App)
94
+
95
+ # * George Moschovitis <gm@navel.gr>