nitro 0.26.0 → 0.27.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 (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