cuca 0.07 → 0.12
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.
- 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/'
|