cuca 0.07 → 0.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +10 -0
- data/README.md +51 -0
- data/application_skeleton/app/test.rb +16 -0
- data/application_skeleton/conf/config.rb +8 -1
- data/application_skeleton/public/dispatch-fwdev.cgi +3 -1
- data/application_skeleton/public/dispatch.cgi +1 -1
- data/application_skeleton/public/dispatch.fcgi +1 -1
- data/application_skeleton/scripts/server-lighttpd-fcgi.rb +43 -4
- data/application_skeleton/scripts/server-lighttpd.rb +58 -5
- data/application_skeleton/scripts/server-webrick.rb +1 -1
- data/application_skeleton/tests/functional/basic.rb +32 -0
- data/bin/cuca +7 -3
- data/lib/cuca.rb +1 -1
- data/lib/cuca/app.rb +44 -31
- data/lib/cuca/cgi_emu.rb +17 -6
- data/lib/cuca/const.rb +1 -1
- data/lib/cuca/controller.rb +0 -2
- data/lib/cuca/generator/view.rb +7 -5
- data/lib/cuca/mimetypes.rb +2 -0
- data/lib/cuca/sessionpage.rb +18 -4
- data/lib/cuca/stdlib/README +2 -0
- data/lib/cuca/stdlib/form.rb +1 -1
- data/lib/cuca/stdlib/listwidget/dblist.rb +13 -2
- data/lib/cuca/stdlib/listwidget/querydef.rb +11 -17
- data/lib/cuca/test/helpers.rb +55 -2
- data/lib/cuca/urlmap.rb +18 -9
- data/tests/all.rb +4 -1
- data/tests/controller.rb +26 -9
- data/tests/test_app/app/test.rb +0 -0
- data/tests/urlmap.rb +7 -0
- data/tests/widget.rb +2 -2
- metadata +106 -128
- data/README +0 -43
- data/application_skeleton/public/dispatch.cgi-old +0 -18
- data/application_skeleton/public/dispatch.fcgi-old +0 -25
- data/application_skeleton/scripts/rack-test.rb +0 -52
- data/application_skeleton/scripts/server-rack-thin.rb +0 -40
- data/application_skeleton/scripts/server-rack-webrick.rb +0 -22
- data/lib/cuca/stdlib/old_arform.rb +0 -254
data/lib/cuca/cgi_emu.rb
CHANGED
@@ -1,16 +1,23 @@
|
|
1
1
|
# little fake cgi class that allows automated testing of cgi application
|
2
2
|
|
3
|
+
require 'stringio'
|
4
|
+
|
3
5
|
class CGIEmu < CGI
|
4
6
|
|
5
7
|
attr_reader :out_params
|
6
8
|
attr_reader :out_content
|
9
|
+
|
10
|
+
attr_reader :output_cookies # made by CGI::Session
|
7
11
|
|
8
12
|
class EnvTable
|
9
13
|
def initialize(options)
|
10
14
|
@test_path_info = options['PATH_INFO'] || '/'
|
11
15
|
@test_query_params = options['QUERY_PARAMS'] || {}
|
16
|
+
@request_method = options['REQUEST_METHOD'] || 'GET'
|
17
|
+
@content_length = options['CONTENT_LENGTH'] || 0
|
18
|
+
@http_cookie = options['HTTP_COOKIE']
|
12
19
|
|
13
|
-
the_env_table.each_pair { |k,v| ENV[k] = v }
|
20
|
+
the_env_table.each_pair { |k,v| ENV[k] = v.to_s }
|
14
21
|
|
15
22
|
# ENV.merge(the_env_table)
|
16
23
|
end
|
@@ -35,7 +42,6 @@ class CGIEmu < CGI
|
|
35
42
|
"REMOTE_ADDR"=>"127.0.0.1",
|
36
43
|
"SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.6/2007-06-07)",
|
37
44
|
"HTTP_REFERER"=>"http://localhost:2000/",
|
38
|
-
"HTTP_COOKIE"=>"cuca_session=285715682bf030a19cb24b2560aabc36",
|
39
45
|
"HTTP_ACCEPT_CHARSET"=>"utf-8, utf-8;q=0.5, *;q=0.5",
|
40
46
|
"REQUEST_URI"=>"http://localhost:2000" + @test_path_info,
|
41
47
|
"SERVER_PORT"=>"2000",
|
@@ -43,8 +49,12 @@ class CGIEmu < CGI
|
|
43
49
|
"QUERY_STRING"=>query_string,
|
44
50
|
"HTTP_ACCEPT"=>"text/html, image/jpeg, image/png, text/*, image/*, */*",
|
45
51
|
"SCRIPT_FILENAME"=>"/home/bones/workspace/cuca/scripts/../public/dispatch.cgi",
|
46
|
-
"REQUEST_METHOD"
|
47
|
-
"HTTP_CONNECTION"=>"Keep-Alive"
|
52
|
+
"REQUEST_METHOD"=>@request_method,
|
53
|
+
"HTTP_CONNECTION"=>"Keep-Alive",
|
54
|
+
"CONTENT_LENGTH" => @content_length,
|
55
|
+
"HTTP_COOKIE" => @http_cookie,
|
56
|
+
# 'CONTENT_TYPE' => "application/x-www-form-urlencoded"
|
57
|
+
}
|
48
58
|
end
|
49
59
|
|
50
60
|
def [](key)
|
@@ -58,11 +68,12 @@ class CGIEmu < CGI
|
|
58
68
|
end
|
59
69
|
|
60
70
|
def stdinput
|
61
|
-
|
62
|
-
StringIO.new("")
|
71
|
+
StringIO.new(@content)
|
63
72
|
end
|
64
73
|
|
65
74
|
def initialize(options)
|
75
|
+
@content = options['CONTENT'] || ''
|
76
|
+
options.delete('CONTENT')
|
66
77
|
@test_options = options
|
67
78
|
super()
|
68
79
|
end
|
data/lib/cuca/const.rb
CHANGED
data/lib/cuca/controller.rb
CHANGED
data/lib/cuca/generator/view.rb
CHANGED
@@ -44,15 +44,17 @@ module View
|
|
44
44
|
# This will return the generated markup as a string
|
45
45
|
def viewtext(filename=nil)
|
46
46
|
view_dir = $cuca_path + '/' + App::config['view_directory']
|
47
|
+
|
47
48
|
begin
|
48
|
-
|
49
|
+
template = File.read(view_dir + "/#{filename}")
|
49
50
|
rescue => e
|
50
|
-
return "Error
|
51
|
+
return "Error reading template: #{e}"
|
51
52
|
end
|
52
|
-
|
53
|
-
template = f.read
|
54
|
-
f.close
|
55
53
|
|
54
|
+
if RUBY_VERSION > '1.8' && Cuca::App.config['view_encoding'] then
|
55
|
+
template.force_encoding(Cuca::App.config['view_encoding'])
|
56
|
+
end
|
57
|
+
|
56
58
|
viewtext_p(template)
|
57
59
|
end
|
58
60
|
|
data/lib/cuca/mimetypes.rb
CHANGED
data/lib/cuca/sessionpage.rb
CHANGED
@@ -1,10 +1,19 @@
|
|
1
1
|
module Cuca
|
2
2
|
|
3
3
|
# A session page (access via session.page) is memory that is only valid
|
4
|
-
# for the current action.
|
5
|
-
#
|
4
|
+
# for the current action.
|
5
|
+
# Query and Request paramenters are automatically available in this container and
|
6
|
+
# remain available if removed due to a page refresh or similar.
|
7
|
+
#
|
8
|
+
# If you leave the page, they are NOT erased anymore (this used to be cuca behavior
|
9
|
+
# <= 0.7). They stay valid until EXPIRE_TIME_HOURS (default 4 hours).
|
10
|
+
#
|
11
|
+
# see Cuca::Session
|
6
12
|
class SessionPage
|
7
13
|
|
14
|
+
LAKEY = :session_page_last_access
|
15
|
+
EXPIRE_TIME_HOURS = 4
|
16
|
+
|
8
17
|
private
|
9
18
|
def pagekey
|
10
19
|
"Pk_#{$app.urlmap.script.gsub(/[\/\\]/, '_')}".intern
|
@@ -19,7 +28,8 @@ class SessionPage
|
|
19
28
|
@ses = session
|
20
29
|
@ses[:SessionPage] ||= {}
|
21
30
|
pagemem[pagekey] ||= {}
|
22
|
-
|
31
|
+
pagemem[pagekey][LAKEY] = Time.now
|
32
|
+
session.cgi.parameters.each_pair { |k,v| self[k] = v.dup if v.kind_of?(String) }
|
23
33
|
expire
|
24
34
|
end
|
25
35
|
|
@@ -49,9 +59,13 @@ class SessionPage
|
|
49
59
|
private
|
50
60
|
def expire
|
51
61
|
pagemem.each_pair do |k,v|
|
52
|
-
|
62
|
+
next if k == pagekey
|
63
|
+
next unless pagemem[k][LAKEY]
|
64
|
+
next if pagemem[k][LAKEY] > (Time.now - (3600 * EXPIRE_TIME_HOURS))
|
65
|
+
pagemem.delete(k)
|
53
66
|
end
|
54
67
|
end
|
68
|
+
|
55
69
|
end
|
56
70
|
|
57
71
|
end
|
data/lib/cuca/stdlib/form.rb
CHANGED
@@ -88,7 +88,7 @@ class FormWidget < Cuca::Widget
|
|
88
88
|
# it will get the variables from the options[:default_values]
|
89
89
|
def get_form_variables
|
90
90
|
var = @options[:default_values] || {}
|
91
|
-
params.each_pair { |k,v| var[k] = v } if posted? # request_method == 'POST'
|
91
|
+
params.each_pair { |k,v| var[k.to_s] = v } if posted? # request_method == 'POST'
|
92
92
|
@variables = {}
|
93
93
|
var.each_pair { |k,v| @variables[k.to_s] = v } # this allows is to pass symbols to default_values
|
94
94
|
@variables
|
@@ -80,6 +80,7 @@ class DBListWidget < BaseList
|
|
80
80
|
findstuff[:offset] = query_def.range.first
|
81
81
|
findstuff[:limit] = query_def.range.last-query_def.range.first+1
|
82
82
|
findstuff[:joins] = @joins || nil
|
83
|
+
findstuff[:group] = @group_by if @group_by.to_s != ''
|
83
84
|
sel = @query_columns.collect do |c|
|
84
85
|
ret = c.has_key?(:query) ? "#{c[:query]} as #{c[:id]}" : c[:id]
|
85
86
|
ret = nil if c[:query] == false
|
@@ -88,9 +89,18 @@ class DBListWidget < BaseList
|
|
88
89
|
findstuff[:select] = sel.compact.join(',')
|
89
90
|
@data = @model_class.find(:all, findstuff)
|
90
91
|
@additional_data = @data.dup
|
91
|
-
|
92
|
+
|
93
|
+
rowcount_findstuff = findstuff.dup
|
94
|
+
rowcount_findstuff.delete(:limit)
|
95
|
+
rowcount_findstuff.delete(:offset)
|
96
|
+
rowcount_findstuff.delete(:order)
|
97
|
+
|
92
98
|
@data = normalize_result(@data)
|
93
|
-
|
99
|
+
|
100
|
+
@total_rows= @model_class.count(rowcount_findstuff)
|
101
|
+
if @total_rows.kind_of?(Hash) then # if group_by is defined we'll get this
|
102
|
+
@total_rows = @total_rows.size
|
103
|
+
end
|
94
104
|
end
|
95
105
|
|
96
106
|
def setup
|
@@ -118,6 +128,7 @@ class DBListWidget < BaseList
|
|
118
128
|
@columns = data_setup[:columns] || []
|
119
129
|
@extra_conditions = data_setup[:conditons] || ""
|
120
130
|
@joins = data_setup[:joins] || ""
|
131
|
+
@group_by = data_setup[:group_by] || ""
|
121
132
|
@options ||= data_setup[:options] # can be used by 'setup'
|
122
133
|
@model_class = model_class || nil
|
123
134
|
setup
|
@@ -67,8 +67,8 @@ class QueryDef
|
|
67
67
|
end
|
68
68
|
|
69
69
|
#setter
|
70
|
-
raise NoMethodError if met[met.size-1].chr != '='
|
71
|
-
raise NoMethodError if params.size != 1
|
70
|
+
raise NoMethodError, met if met[met.size-1].chr != '='
|
71
|
+
raise NoMethodError, met if params.size != 1
|
72
72
|
met = met[0..met.size-2] # cut '='
|
73
73
|
if ATTRIBS.include?(met) then
|
74
74
|
@data[met] = params[0]
|
@@ -79,9 +79,9 @@ class QueryDef
|
|
79
79
|
|
80
80
|
# value enc/dec
|
81
81
|
def ev_enc(name)
|
82
|
-
|
82
|
+
|
83
83
|
if ATTRIBS_ENCODE.has_key?(name) then
|
84
|
-
ATTRIBS_ENCODE[name].call(@data[name]
|
84
|
+
ATTRIBS_ENCODE[name].call(@data[name])
|
85
85
|
else
|
86
86
|
@data[name]
|
87
87
|
end
|
@@ -89,7 +89,7 @@ class QueryDef
|
|
89
89
|
|
90
90
|
def ev_dec(name, value)
|
91
91
|
if ATTRIBS_DECODE.has_key?(name) then
|
92
|
-
|
92
|
+
$stderr.puts "ev_dec #{name} #{value}"
|
93
93
|
begin
|
94
94
|
return ATTRIBS_DECODE[name].call(value)
|
95
95
|
rescue
|
@@ -112,20 +112,20 @@ class QueryDef
|
|
112
112
|
|
113
113
|
# returns an hash with the values and escaped names and attributes
|
114
114
|
# attr and newval with swap a value for this return without changing the actual data
|
115
|
-
def to_h(
|
116
|
-
if
|
115
|
+
def to_h(attr1=nil, newval1=nil, attr2=nil, newval2=nil)
|
116
|
+
if attr1 then
|
117
117
|
@backup = @data.dup
|
118
|
-
@data[
|
118
|
+
@data[attr1] = newval1
|
119
119
|
@data[attr2] = newval2 unless attr2.nil?
|
120
120
|
end
|
121
121
|
|
122
122
|
u = {}
|
123
123
|
ATTRIBS.each do |a|
|
124
|
-
#
|
124
|
+
# $stderr.puts "Encoding: #{a} - #{@data[a]}"
|
125
125
|
u[at_enc(a)] = escape(ev_enc(a) || '')
|
126
126
|
end
|
127
127
|
|
128
|
-
if
|
128
|
+
if attr1 then @data = @backup end
|
129
129
|
|
130
130
|
return u
|
131
131
|
end
|
@@ -153,7 +153,7 @@ class QueryDef
|
|
153
153
|
fname = p.scan(/\_filter\_(.*)/)[0][0]
|
154
154
|
fdata = v
|
155
155
|
@data['filters'][fname] = fdata
|
156
|
-
|
156
|
+
$stderr.puts "Filter update: #{@data['filters'].inspect}"
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
@@ -169,10 +169,4 @@ class QueryDef
|
|
169
169
|
end
|
170
170
|
end
|
171
171
|
|
172
|
-
# qr = QueryDef.new("my_list")
|
173
|
-
# qr.order_by = 'firstname'
|
174
|
-
# qr.range = 100..200
|
175
|
-
#
|
176
|
-
# qr.filters = {'firstname' => 'martin', 'lastname' => 'boese' }
|
177
|
-
# puts qr.to_url
|
178
172
|
|
data/lib/cuca/test/helpers.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
|
2
2
|
require 'test/unit'
|
3
|
+
require 'cuca/cgi_emu'
|
4
|
+
require 'cuca/urlmap'
|
5
|
+
|
6
|
+
require 'ostruct'
|
3
7
|
|
4
8
|
module Cuca
|
5
9
|
module Test
|
@@ -10,8 +14,6 @@ module Helpers
|
|
10
14
|
|
11
15
|
# init the application. call this from the setup method.
|
12
16
|
def init(app_path = '/', params = {})
|
13
|
-
require 'cuca/cgi_emu'
|
14
|
-
require 'cuca/urlmap'
|
15
17
|
@cgi = CGIEmu.new({'PATH_INFO' => app_path, 'QUERY_PARAMS' => params})
|
16
18
|
@app = Cuca::App.new
|
17
19
|
@app.load_support_files(Cuca::URLMap.new($cuca_path+'/app', app_path))
|
@@ -39,6 +41,57 @@ def widget_p(widget_class, *args, &block)
|
|
39
41
|
end
|
40
42
|
|
41
43
|
|
44
|
+
#
|
45
|
+
# Functional Tests
|
46
|
+
#
|
47
|
+
def cgi_status_to_text(status)
|
48
|
+
require 'cgi'
|
49
|
+
CGI::HTTP_STATUS[status] || status
|
50
|
+
end
|
51
|
+
|
52
|
+
def cgi_to_result(cgi, other = {})
|
53
|
+
op = cgi.out_params
|
54
|
+
|
55
|
+
result = OpenStruct.new
|
56
|
+
result.status = cgi_status_to_text(op['status'])
|
57
|
+
result.status_cgi = op['status']
|
58
|
+
result.type = op['type']
|
59
|
+
result.content = cgi.out_content
|
60
|
+
result.cookies = cgi.output_cookies
|
61
|
+
other.each { |k,v| result.send("#{k}=".intern, v) }
|
62
|
+
result
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def measure_time
|
67
|
+
t = Time.now.to_f
|
68
|
+
yield
|
69
|
+
Time.now.to_f - t
|
70
|
+
end
|
71
|
+
|
72
|
+
def get(target, query_parameters= {})
|
73
|
+
@cgi = CGIEmu.new({'PATH_INFO' => target,
|
74
|
+
'QUERY_PARAMS' => query_parameters,
|
75
|
+
'HTTP_COOKIE' => @test_http_cookie})
|
76
|
+
@app = Cuca::App.new
|
77
|
+
t = measure_time { @app.cgicall(@cgi) }
|
78
|
+
cgi_to_result(@app.cgi, :time => t)
|
79
|
+
end
|
80
|
+
|
81
|
+
def post(target, request_parameters = {})
|
82
|
+
require 'uri'
|
83
|
+
body = URI.encode_www_form(request_parameters)
|
84
|
+
@cgi = CGIEmu.new({'PATH_INFO' => target,
|
85
|
+
'REQUEST_METHOD' => 'POST',
|
86
|
+
'CONTENT_LENGTH' => body.size,
|
87
|
+
'CONTENT' => body,
|
88
|
+
'HTTP_COOKIE' => @test_http_cookie})
|
89
|
+
@app = Cuca::App.new
|
90
|
+
t = measure_time { @app.cgicall(@cgi) }
|
91
|
+
cgi_to_result(@app.cgi, :time => t)
|
92
|
+
end
|
93
|
+
|
94
|
+
|
42
95
|
end
|
43
96
|
end
|
44
97
|
end
|
data/lib/cuca/urlmap.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
|
2
2
|
if __FILE__ == $0 then
|
3
3
|
require 'rubygems'
|
4
|
-
|
4
|
+
begin
|
5
|
+
require 'cuca'
|
6
|
+
rescue LoadError
|
7
|
+
end
|
5
8
|
end
|
6
9
|
|
7
10
|
module Cuca
|
@@ -115,7 +118,6 @@ class URLMap
|
|
115
118
|
# it's real path
|
116
119
|
private
|
117
120
|
def scan_dir(base, file)
|
118
|
-
|
119
121
|
striped = "#{base}/#{file}"[@base_path.length..-1]
|
120
122
|
mount = Cuca::App.config['mount'] || {}
|
121
123
|
# $stderr.puts "SCAN DIR: #{striped}"
|
@@ -133,7 +135,7 @@ class URLMap
|
|
133
135
|
return file.empty? ? base : "#{base}/#{file}" # avoid returning double //
|
134
136
|
end
|
135
137
|
|
136
|
-
d = Dir["#{base}/#{DEF_ACT}*"].
|
138
|
+
d = Dir["#{base}/#{DEF_ACT}*"].map { |f| f.split('/').last }
|
137
139
|
|
138
140
|
# puts "Directory not found, checking for default in #{base} - #{file}"
|
139
141
|
|
@@ -163,19 +165,26 @@ class URLMap
|
|
163
165
|
end
|
164
166
|
|
165
167
|
|
168
|
+
# removes double slashes from a path-string
|
169
|
+
def clean_path(directory)
|
170
|
+
directory.gsub(/\/\//, '/')
|
171
|
+
end
|
172
|
+
|
166
173
|
# scan will match an URI to a script and set assigns. (called from initialize)
|
167
174
|
private
|
168
175
|
def scan
|
169
176
|
files = @path_info.split('/')
|
170
|
-
|
177
|
+
|
171
178
|
files << '' if @path_info[@path_info.size-1].chr == '/' # add empty element if we point to a directory
|
172
179
|
|
173
180
|
# files now contains something like:
|
174
|
-
# [users, show, martin, contacts]
|
181
|
+
# ['', 'users', 'show', 'martin', 'contacts']
|
175
182
|
|
176
183
|
# puts files.inspect
|
177
184
|
real_path = @base_path.dup
|
178
185
|
|
186
|
+
@path_tree = [] if files.size > 1
|
187
|
+
|
179
188
|
# scan directory
|
180
189
|
files.each_index do |idx|
|
181
190
|
next if idx >= (files.size-1) # skip last element
|
@@ -196,7 +205,7 @@ class URLMap
|
|
196
205
|
|
197
206
|
raise RoutingError.new("Routing Error - script not found at #{real_path} - #{files.last}") if !r
|
198
207
|
|
199
|
-
real_path = "#{real_path}/#{r}"
|
208
|
+
real_path = clean_path("#{real_path}/#{r}")
|
200
209
|
|
201
210
|
@script = File.expand_path(real_path)
|
202
211
|
# @path_tree = _tree(@base_path, @script)
|
@@ -251,14 +260,14 @@ class URLMap
|
|
251
260
|
|
252
261
|
def initialize(base_path, path_info, default_actions = ['index'])
|
253
262
|
@path_info = path_info
|
254
|
-
@base_path = File.expand_path(base_path)
|
263
|
+
@base_path = clean_path(File.expand_path(base_path))
|
255
264
|
@script = ''
|
256
265
|
@subcall = nil
|
257
266
|
@default_actions = default_actions
|
258
267
|
@assigns = {}
|
259
268
|
@action = ''
|
260
269
|
@action_path = ''
|
261
|
-
@path_tree = [base_path]
|
270
|
+
@path_tree = [@base_path]
|
262
271
|
scan
|
263
272
|
self
|
264
273
|
end
|
@@ -273,7 +282,7 @@ end
|
|
273
282
|
#
|
274
283
|
|
275
284
|
if __FILE__ == $0 then
|
276
|
-
require 'app'
|
285
|
+
require 'cuca/app'
|
277
286
|
|
278
287
|
BASE = '/home/bones/src/cuca/app'
|
279
288
|
URL = 'user/martin/somewhere/notexist/'
|