nitro 0.26.0 → 0.27.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/CHANGELOG +312 -0
  2. data/INSTALL +3 -1
  3. data/ProjectInfo +6 -9
  4. data/README +32 -5
  5. data/Rakefile +5 -1
  6. data/bin/nitrogen +3 -60
  7. data/doc/MIGRATION +24 -0
  8. data/doc/RELEASES +141 -0
  9. data/doc/lhttpd.txt +3 -0
  10. data/lib/glue/magick.rb +38 -0
  11. data/lib/glue/thumbnails.rb +3 -0
  12. data/lib/glue/webfile.rb +137 -0
  13. data/lib/nitro.rb +1 -1
  14. data/lib/nitro/adapter/acgi.rb +235 -0
  15. data/lib/nitro/adapter/cgi.rb +16 -17
  16. data/lib/nitro/adapter/scgi.rb +4 -4
  17. data/lib/nitro/adapter/webrick.rb +9 -2
  18. data/lib/nitro/cgi.rb +49 -49
  19. data/lib/nitro/cgi/response.rb +4 -0
  20. data/lib/nitro/cgi/stream.rb +7 -7
  21. data/lib/nitro/cgi/utils.rb +2 -1
  22. data/lib/nitro/compiler.rb +47 -4
  23. data/lib/nitro/compiler/elements.rb +40 -20
  24. data/lib/nitro/compiler/layout.rb +21 -0
  25. data/lib/nitro/compiler/localization.rb +3 -1
  26. data/lib/nitro/compiler/markup.rb +2 -0
  27. data/lib/nitro/compiler/morphing.rb +16 -4
  28. data/lib/nitro/compiler/script.rb +109 -0
  29. data/lib/nitro/context.rb +10 -10
  30. data/lib/nitro/dispatcher.rb +4 -2
  31. data/lib/nitro/element.rb +107 -26
  32. data/lib/nitro/element/{java_script.rb → javascript.rb} +7 -1
  33. data/lib/nitro/flash.rb +4 -1
  34. data/lib/nitro/helper.rb +15 -0
  35. data/lib/nitro/helper/benchmark.rb +8 -2
  36. data/lib/nitro/helper/form.rb +3 -3
  37. data/lib/nitro/helper/form/controls.rb +131 -29
  38. data/lib/nitro/helper/{dojo.rb → form/test.xhtml} +0 -0
  39. data/lib/nitro/helper/javascript.rb +69 -59
  40. data/lib/nitro/helper/{scriptaculous.rb → javascript/dojo.rb} +0 -0
  41. data/lib/nitro/helper/javascript/morphing.rb +163 -0
  42. data/lib/nitro/helper/javascript/prototype.rb +96 -0
  43. data/lib/nitro/helper/javascript/scriptaculous.rb +18 -0
  44. data/lib/nitro/helper/layout.rb +42 -0
  45. data/lib/nitro/helper/table.rb +190 -27
  46. data/lib/nitro/{adapter → helper}/wee.rb +9 -3
  47. data/lib/nitro/render.rb +23 -17
  48. data/lib/nitro/scaffolding.rb +19 -2
  49. data/lib/nitro/server.rb +4 -8
  50. data/lib/nitro/server/runner.rb +28 -6
  51. data/lib/nitro/session.rb +7 -7
  52. data/lib/nitro_and_og.rb +2 -0
  53. data/proto/public/Makefile.acgi +40 -0
  54. data/proto/public/acgi.c +138 -0
  55. data/proto/public/js/builder.js +7 -3
  56. data/proto/public/js/controls.js +32 -12
  57. data/proto/public/js/dragdrop.js +4 -3
  58. data/proto/public/js/effects.js +111 -62
  59. data/proto/public/js/scriptaculous.js +10 -13
  60. data/proto/public/js/slider.js +88 -31
  61. data/proto/public/scaffold/new.xhtml +2 -2
  62. data/setup.rb +1585 -0
  63. data/src/part/admin.rb +6 -0
  64. data/src/part/admin/controller.rb +3 -3
  65. data/src/part/admin/skin.rb +1 -8
  66. data/test/nitro/adapter/tc_webrick.rb +2 -0
  67. data/test/nitro/tc_controller_aspect.rb +1 -1
  68. data/test/nitro/tc_element.rb +5 -6
  69. data/test/nitro/tc_table.rb +66 -0
  70. metadata +277 -271
  71. data/doc/architecture.txt +0 -2
  72. data/doc/bugs.txt +0 -15
  73. data/doc/tutorial.txt +0 -26
  74. data/install.rb +0 -37
  75. data/lib/nitro/compiler/script_generator.rb +0 -14
  76. data/lib/nitro/compiler/shaders.rb +0 -206
  77. data/lib/nitro/helper/prototype.rb +0 -49
  78. data/lib/nitro/scaffold/relations.rb +0 -54
data/lib/nitro.rb CHANGED
@@ -16,7 +16,7 @@ module Nitro
16
16
 
17
17
  # The version.
18
18
 
19
- Version = '0.26.0'
19
+ Version = '0.27.0'
20
20
 
21
21
  # Library path.
22
22
 
@@ -0,0 +1,235 @@
1
+ require 'cgi'
2
+ require 'posixlock'
3
+
4
+ STDOUT.sync = STDERR.sync = true
5
+ $VERBOSE = nil
6
+
7
+ require 'nitro/context'
8
+ require 'nitro/dispatcher'
9
+ require 'nitro/cgi'
10
+
11
+ require 'glue/flexob'
12
+
13
+ # Speeds things up, more comaptible with OSX.
14
+
15
+ Socket.do_not_reverse_lookup = true
16
+
17
+ module Nitro
18
+
19
+ # ACGI Adaptor. ACGI is a language independent,
20
+ # scalable, open extension to CGI that provides high
21
+ # performance without the limitations of server
22
+ # specific APIs.
23
+ #
24
+ # This code is directly from the author. Please go to
25
+ # http://codeforpeople.com/lib/ruby/acgi/ for more
26
+ # information about ACGI.
27
+ # or email: ara [dot] t [dot] howard [at] noaa [dot] gov
28
+ #
29
+ # It uses a compiled C cgi program to handle
30
+ # connections compile the acgi.c by executing
31
+ # "make -f Makefile.acgi" in your public/ folder.
32
+ # then make your .htaccess redirect all calls to acgi.cgi
33
+ # instead of fcgi.rb / cgi.rb
34
+ #
35
+ #--
36
+ # gmosx: not tested
37
+ #++
38
+
39
+ class ACGI < ::CGI
40
+ THIS = File::expand_path $0
41
+ COMMAND_LINE = [THIS, ARGV].join ' '
42
+ LOADED = Time::now
43
+ IPC_DIR = "/tmp/acgi_ipc"
44
+ CLIENT_LOCK_PATH = File::join IPC_DIR, "client.lock"
45
+ SERVER_LOCK_PATH = File::join IPC_DIR, "server.lock"
46
+ SERVER_ENVIRONMENT_PATH = File::join IPC_DIR, "server.environment"
47
+ SERVER_STDIN_PATH = File::join IPC_DIR, "server.stdin"
48
+ SERVER_STDOUT_PATH = File::join IPC_DIR, "server.stdout"
49
+ SERVER_STDERR_PATH = File::join IPC_DIR, "server.stderr"
50
+ SERVER_PID_PATH = File::join IPC_DIR, "server.pid"
51
+
52
+ RE_ENV = %r/^ ([^=]+) = (.*) $/ox
53
+ RE_NUL = %r/#{ Regexp::escape "\0" }/ox
54
+
55
+ SERVER = ENV['ACGI_SERVER'] || ARGV.delete('--server') || ARGV.delete('-s')
56
+
57
+ if SERVER
58
+ trap('HUP'){ exec ::ACGI::COMMAND_LINE }
59
+ %w( INT KILL TERM ).each{|s| trap(s){ exit }}
60
+ end
61
+
62
+ class << self
63
+ def each_cgi(*a, &b)
64
+ if SERVER
65
+ start_server(*a, &b)
66
+ else
67
+ munge_environment
68
+ @cgi = new(*a)
69
+ catching_errors{ b[ @cgi ] }
70
+ end
71
+ end
72
+
73
+ def start_server(*a, &b)
74
+ daemon do
75
+ ENV.clear # __very__ important for speed!
76
+ aquire_server_lock
77
+ record_pid
78
+ loop do
79
+ load_environment
80
+ munge_environment
81
+ @cgi = redirecting_stdin{ new(*a) }
82
+ redirecting_stdout_and_stderr{ catching_errors{ b[ @cgi ] }}
83
+ restart_if_updated
84
+ end
85
+ end
86
+ end
87
+
88
+ def restart_if_updated
89
+ # put the full path to your run.rb here if it doesn't work
90
+ #th = "/path/to/app/run.rb"
91
+ if File::stat(THIS).mtime > LOADED
92
+ #if File::stat(th).mtime > LOADED
93
+ exec COMMAND_LINE
94
+ end
95
+ end
96
+
97
+ def aquire_server_lock
98
+ lockfile = File.open(SERVER_LOCK_PATH)
99
+ lockfile.reopen(SERVER_LOCK_PATH, 'w')
100
+ at_exit{ lockfile.close }
101
+ ret = lockfile.posixlock(File::LOCK_EX|File::LOCK_NB)
102
+
103
+ raise("#{ File::basename $0 } already running..") if(!ret or !ret.zero?)
104
+ end
105
+
106
+ def record_pid
107
+ begin
108
+ f = File::open(SERVER_PID_PATH)
109
+ f.reopen(SERVER_PID_PATH, 'w')
110
+ f.print Process::pid
111
+ f.chmod 0777 rescue nil
112
+ ensure
113
+ f.close
114
+ end
115
+ end
116
+
117
+ def env_table
118
+ SERVER ? (@environment ||= {}) : ENV
119
+ end
120
+
121
+ def env
122
+ env_table
123
+ end
124
+
125
+ def load_environment
126
+ begin
127
+ f = File::open(SERVER_ENVIRONMENT_PATH)
128
+ f.reopen(SERVER_ENVIRONMENT_PATH, "r")
129
+ env_table.clear
130
+ kvs = f.read.chop.split RE_NUL
131
+ kvs.each do |kv|
132
+ m = RE_ENV.match(kv)
133
+ k, v = m[1], m[2]
134
+ env_table[k] = v
135
+ end
136
+ ensure
137
+ f.close
138
+ end
139
+ end
140
+
141
+ def munge_environment # because CGI::Cookie::parse is broken!
142
+ env_table['HTTP_COOKIE'] =
143
+ munge_http_cookie env_table['HTTP_COOKIE']
144
+ end
145
+
146
+ def munge_http_cookie http_cookie
147
+ return unless http_cookie
148
+ kvs = http_cookie.split %r/[;,]\s+/o
149
+ h = Hash::new{|h,k| h[k] = []}
150
+ kvs.each do |kv|
151
+ k, v = kv.split %r/=/o, 2
152
+ next unless k
153
+ k = CGI::unescape k
154
+ vs = v.to_s.split(%r/&/).map{|v| CGI::unescape v}
155
+ h[k].push(*vs)
156
+ end
157
+ h.sort.map{|k,vs| [k, vs.join('&')].join('=')}.join('; ')
158
+ end
159
+
160
+ def redirecting_stdin
161
+ stdin = $stdin
162
+ begin
163
+ @stdin = File::open(SERVER_STDIN_PATH)
164
+ @stdin.reopen(SERVER_STDIN_PATH, "r")
165
+ $stdin = @stdin
166
+ yield
167
+ ensure
168
+ @stdin.close if @stdin
169
+ $stdin = stdin
170
+ end
171
+ end
172
+
173
+ def redirecting_stdout_and_stderr
174
+ stdout, stderr = $stdout, $stderr
175
+ begin
176
+ @stdout = File::open(SERVER_STDOUT_PATH)
177
+ @stdout.reopen(SERVER_STDOUT_PATH, "w")
178
+ @stderr = File::open(SERVER_STDERR_PATH)
179
+ @stderr.reopen(SERVER_STDERR_PATH, "w")
180
+ $stdout, $stderr = @stdout, @stderr
181
+ yield
182
+ ensure
183
+ @stdout.close if @stdout
184
+ @stderr.close if @stderr
185
+ $stdout, $stderr = stdout, stderr
186
+ end
187
+ end
188
+
189
+ def catching_errors
190
+ @cgi ||= CGI::new
191
+ begin
192
+ yield
193
+ rescue Exception => e
194
+ m, c, b = e.message, e.class, e.backtrace.join("<br>\n")
195
+ @cgi.out{ "<hr><b><i>#{ m } (#{ c })</b></i><hr><hr>#{ b }" }
196
+ end
197
+ end
198
+
199
+ def daemon
200
+ exit!(0) if fork
201
+ Process::setsid
202
+ exit!(0) if fork
203
+ # Dir::chdir("/")
204
+ # File::umask(0)
205
+
206
+ # uncomment these if you don't want logs
207
+ #STDIN.reopen("/dev/null")
208
+ #STDOUT.reopen("/dev/null", "w")
209
+ #STDERR.reopen("/dev/null", "w")
210
+ yield if block_given?
211
+ end
212
+ end
213
+
214
+ def env_table
215
+ self::class.env_table
216
+ end
217
+ def env
218
+ self::class.env
219
+ end
220
+
221
+ # use this to start the ACGI server.
222
+
223
+ def self.start(server)
224
+ ACGI.each_cgi do |cgi|
225
+ begin
226
+ Cgi.process(server, cgi, $stdin, $stdout)
227
+ end
228
+ end
229
+ end
230
+
231
+ end
232
+
233
+ end
234
+
235
+ # * Ara Howard <ara.t.howard@noaa.gov>
@@ -2,12 +2,27 @@ require 'cgi'
2
2
  require 'stringio'
3
3
  require 'tempfile'
4
4
 
5
+ #--
6
+ # Adapt the default CGI object to suit Nitro.
7
+ #++
8
+
9
+ class CGI # :nodoc: all
10
+ def env
11
+ ENV
12
+ end
13
+ end
14
+
5
15
  # Speeds things up, more comaptible with OSX.
6
16
 
7
17
  Socket.do_not_reverse_lookup = true
8
18
 
9
19
  module Nitro
10
20
 
21
+ # A plain CGI adapter. To be used only in development
22
+ # environments, this adapter is *extremely* slow for
23
+ # live/production environments. This adapter is provided for
24
+ # the sake of completeness.
25
+
11
26
  class CgiAdapter
12
27
  #--
13
28
  # No need for connection pooling, CGI uses process.
@@ -15,23 +30,8 @@ class CgiAdapter
15
30
 
16
31
  def self.start(server)
17
32
  cgi = CGI.new
18
- def cgi.env
19
- env_table
20
- end
21
33
  Router.strip_path = cgi.env["SCRIPT_NAME"]
22
- Cgi.process(server, cgi, cgi, cgi)
23
- =begin
24
- context = Context.new(server)
25
- context.headers = ENV
26
-
27
- CgiUtils.parse_params(context)
28
- CgiUtils.parse_cookies(context)
29
-
30
- context.render(context.path)
31
-
32
- cgi.print(CgiUtils.response_headers(context))
33
- cgi.print(context.out)
34
- =end
34
+ Cgi.process(server, cgi, $stdin, $stdout)
35
35
  end
36
36
 
37
37
  end
@@ -40,4 +40,3 @@ end
40
40
 
41
41
  # * James Britt <james_b@neurogami.com>
42
42
  # * George Moschovitis <gm@navel.gr>
43
-
@@ -8,7 +8,7 @@ require 'cgi'
8
8
  require 'monitor'
9
9
  require 'singleton'
10
10
 
11
- module SCGI
11
+ module SCGI # :nodoc: all
12
12
 
13
13
  class LogFactory < Monitor
14
14
  include Singleton
@@ -62,7 +62,7 @@ module SCGI
62
62
  end
63
63
 
64
64
  # Modifies CGI so that we can use it.
65
- class SCGIFixed < ::CGI
65
+ class SCGIFixed < ::CGI # :nodoc: all
66
66
  public :env_table
67
67
 
68
68
  def initialize(params, data, out, *args)
@@ -87,7 +87,7 @@ module SCGI
87
87
  end
88
88
 
89
89
 
90
- class SCGIProcessor < Monitor
90
+ class SCGIProcessor < Monitor # :nodoc: all
91
91
  attr_reader :settings
92
92
 
93
93
  def initialize(settings = {})
@@ -243,4 +243,4 @@ module SCGI
243
243
  end
244
244
 
245
245
  # * Zed A Shaw <zedshaw@zedshaw.com>
246
- # * George Moschovitis <gm@navel.gr>
246
+ # * George Moschovitis <gm@navel.gr>
@@ -80,7 +80,13 @@ class XhtmlFileHandler < WEBrick::HTTPServlet::DefaultFileHandler
80
80
  end
81
81
  end
82
82
 
83
- # A Webrick Adapter for Nitro.
83
+ # A Webrick Adapter for Nitro. Webrick is a pure Ruby web server
84
+ # included in the default Ruby distribution. The Webrick Adapter
85
+ # is the prefered adapter in development/debug environments. It
86
+ # is also extremely easy to setup.
87
+ #
88
+ # However, for live/production environments, you should prefer
89
+ # a more performant adapter like FCGI or SCGI.
84
90
 
85
91
  class WebrickAdapter < WEBrick::HTTPServlet::AbstractServlet
86
92
  include WEBrick
@@ -152,6 +158,7 @@ class WebrickAdapter < WEBrick::HTTPServlet::AbstractServlet
152
158
 
153
159
  context.close
154
160
  ensure
161
+ $autoreload_dirty = false
155
162
  Og.manager.put_store if defined?(Og) and Og.respond_to?(:manager)
156
163
  end
157
164
  end
@@ -186,4 +193,4 @@ end
186
193
 
187
194
  # * George Moschovitis <gm@navel.gr>
188
195
  # * Guillaume Pierronnet <guillaume.pierronnet@laposte.net>
189
- # * Bryan Soto <bryan.a.soto@gmail.com>
196
+ # * Bryan Soto <bryan.a.soto@gmail.com>
data/lib/nitro/cgi.rb CHANGED
@@ -5,6 +5,9 @@ require 'nitro/cgi/http'
5
5
 
6
6
  module Nitro
7
7
 
8
+ # Nitro CGI (Common Gateway Interface) methods. Typically
9
+ # handles HTTP Request parsing and HTTP Response generation.
10
+
8
11
  class Cgi
9
12
  include Http
10
13
 
@@ -25,39 +28,55 @@ class Cgi
25
28
  context.in = inp
26
29
  context.headers = cgi.env
27
30
 
28
- # gmosx: QUERY_STRING is sometimes not populated.
31
+ #--
32
+ # gmosx: only handle nitro requests.
33
+ #++
34
+ if context.path !~ /\./
35
+ # gmosx: QUERY_STRING is sometimes not populated.
29
36
 
30
- if context.query_string.empty? and context.uri =~ /\?/
31
- context.headers['QUERY_STRING'] = context.uri.split('?').last
32
- end
37
+ if context.query_string.empty? and context.uri =~ /\?/
38
+ context.headers['QUERY_STRING'] = context.uri.split('?').last
39
+ end
33
40
 
34
- Cgi.parse_params(context)
35
- Cgi.parse_cookies(context)
36
- context.render(context.path)
41
+ Cgi.parse_params(context)
42
+ Cgi.parse_cookies(context)
43
+ context.render(context.path)
37
44
 
38
- out.print(Cgi.response_headers(context))
39
-
40
- if context.out.is_a?(IO)
41
- while buf = context.out.read(4096)
42
- out.write(buf)
45
+ out.print(Cgi.response_headers(context))
46
+
47
+ if context.out.is_a?(IO)
48
+ while buf = context.out.read(4096)
49
+ out.write(buf)
50
+ end
51
+ else
52
+ out.print(context.out)
43
53
  end
44
- else
45
- out.print(context.out)
46
54
  end
47
55
 
56
+ $autoreload_dirty = false
57
+
48
58
  context.close
49
59
  end
50
60
 
61
+ # push a parameter into the params hash
62
+
63
+ def self.structure_param(params, key, val)
64
+ if key =~ /(.+)\[(.+)\]$/ or key =~ /([^\.]+)\.(.+)$/
65
+ params[$1] ||= Hash.new
66
+ params[$1] = structure_param(params[$1], $2, val)
67
+ elsif key =~ /(.+)\[\]$/
68
+ params[$1] ||= Array.new
69
+ params[$1] << val
70
+ else
71
+ params[key] = val.nil? ? nil : val
72
+ end
73
+ return params
74
+ end
75
+
51
76
  # Returns a hash with the pairs from the query
52
77
  # string. The implicit hash construction that is done
53
78
  # in parse_request_params is not done here.
54
- #
55
- # Parameters in the form xxx[] are converted
56
- # to arrays.
57
- #
58
- # Use the field.attr or field[attr] notation to pass
59
- # compound objects.
60
-
79
+
61
80
  def self.parse_query_string(query_string)
62
81
  params = {}
63
82
 
@@ -69,24 +88,8 @@ class Cgi
69
88
 
70
89
  key = CGI.unescape(key) unless key.nil?
71
90
  val = CGI.unescape(val) unless val.nil?
72
-
73
- if key =~ /(.*)\[\]$/
74
- # Multiple values, for example a checkbox collection.
75
- # Stored as an array.
76
- if params.has_key?($1)
77
- params[$1] << val
78
- else
79
- params[$1] = [val]
80
- end
81
- elsif key =~ /(.*)\[(.*)\]$/ or key =~ /(.*)\.(.*)$/
82
- # A compound object with attributes.
83
- # Stored as a Hash.
84
- params[$1] ||= {}
85
- params[$1][$2] = val
86
- else
87
- # Standard single valued parameter.
88
- params[key] = val.nil? ? nil : val
89
- end
91
+
92
+ params = self.structure_param(params, key, val)
90
93
  end
91
94
 
92
95
  return params
@@ -105,7 +108,8 @@ class Cgi
105
108
  # FIXME: dont precreate?
106
109
  context.cookies = {}
107
110
 
108
- if env.has_key?('HTTP_COOKIE') or env.has_key?('COOKIE')
111
+ #if env.has_key?('HTTP_COOKIE') or env.has_key?('COOKIE')
112
+ if env['HTTP_COOKIE'] or env['COOKIE']
109
113
  (env['HTTP_COOKIE'] or env['COOKIE']).split(/; /).each do |c|
110
114
  key, val = c.split(/=/, 2)
111
115
 
@@ -175,7 +179,7 @@ class Cgi
175
179
  when :get, :head
176
180
  context.params = Cgi.parse_query_string(context.query_string)
177
181
  when :post
178
- context.in.binmode # if defined?(context.in.binmode)
182
+ context.in.binmode if defined?(context.in.binmode)
179
183
  context.params = Cgi.parse_query_string(context.in.read(context.content_length) || '')
180
184
  end
181
185
  end
@@ -192,7 +196,7 @@ class Cgi
192
196
  content_length = context.content_length
193
197
  env_table = context.env
194
198
 
195
- params = Hash.new([])
199
+ params = Hash.new()
196
200
  boundary = "--" + boundary
197
201
  buf = ""
198
202
 
@@ -277,17 +281,13 @@ class Cgi
277
281
  define_method(:content_type) { content_type.dup.taint }
278
282
 
279
283
  # gmosx: this hides the performance hit!!
280
- define_method(:to_s) { read }
284
+ define_method(:to_s) { str = read; rewind; return str}
281
285
  end
282
286
 
283
287
  /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
284
288
  name = $1.dup
285
-
286
- if params.has_key?(name)
287
- params[name] = [params[name]] << body
288
- else
289
- params[name] = body
290
- end
289
+
290
+ params = self.structure_param(params, name, body)
291
291
 
292
292
  break if buf.size == 0
293
293
  break if content_length === -1