cuca 0.04 → 0.05
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +11 -2
- data/application_skeleton/app/index.rb +1 -1
- data/application_skeleton/conf/config.rb +5 -5
- data/lib/cuca.rb +22 -14
- data/lib/cuca/app.rb +1 -1
- data/lib/cuca/const.rb +1 -1
- data/lib/cuca/controller.rb +3 -4
- data/lib/cuca/generator/markaby.rb +18 -8
- data/lib/cuca/generator/view.rb +19 -13
- data/lib/cuca/session.rb +2 -0
- data/lib/cuca/stdlib/arform.rb +65 -3
- data/lib/cuca/stdlib/form.rb +17 -4
- data/lib/cuca/stdlib/listwidget/list.rb +10 -1
- data/lib/cuca_console.rb +12 -0
- data/tests/test_app/README +1 -1
- metadata +3 -4
- data/lib/cuca/urlmap-original.rb +0 -324
- data/lib/cuca/urlmap2.rb +0 -22
data/CHANGELOG
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
|
2
|
-
*
|
2
|
+
* 2009/08/20 - 0.05
|
3
|
+
- Widget can be defined within the action controller file.
|
4
|
+
- Fixed minor typos in application skeleton conf/config.rb
|
5
|
+
- Fix to catch exceptions in conf/config and conf/environment
|
6
|
+
- Fixes & minor changes in stdlib/form
|
7
|
+
- Stdlib listwidget rewrite_hooks will pass named hash instead of plain array
|
8
|
+
as row data
|
9
|
+
- fixed script/console to load support files
|
10
|
+
- Fixed bad error rescueing in generators that displayed irritating errors
|
11
|
+
|
12
|
+
* 2008/06/17 - 0.04
|
3
13
|
- Fixed error-message displaying traceback but not the actual exception
|
4
14
|
- Display trace if enabled on 'stop :error' events
|
5
15
|
- Option for autoloading support files (instead of bulk 'require')
|
@@ -12,7 +22,6 @@
|
|
12
22
|
- Added some unit tests
|
13
23
|
- Minor fixes in stdlib
|
14
24
|
- Some fixes in dispatchers
|
15
|
-
-
|
16
25
|
|
17
26
|
|
18
27
|
* 2008/05/18 - 0.03
|
@@ -17,7 +17,7 @@ class IndexController < ApplicationController
|
|
17
17
|
h2 { "If you want to learn cuca" }
|
18
18
|
ul do
|
19
19
|
li { text "Have a look at the Demo Widgets: "; SLink('demo', 'Here') }
|
20
|
-
li { text "Checkout the cuca website: "; SLink("http://cuca.rubyforge.
|
20
|
+
li { text "Checkout the cuca website: "; SLink("http://cuca.rubyforge.org") }
|
21
21
|
li { text "Read the source code of these examples" }
|
22
22
|
end
|
23
23
|
|
@@ -26,14 +26,14 @@ Cuca::App.configure do |config|
|
|
26
26
|
|
27
27
|
### This would be an autoload configuration
|
28
28
|
# config.include_directories = [
|
29
|
-
# { :dir => '_controllers', :class_naming
|
30
|
-
# { :dir => '_widgets', :class_naming
|
31
|
-
# { :dir => '_layouts', :class_naming
|
32
|
-
# { :dir => '_models', :class_naming
|
29
|
+
# { :dir => '_controllers', :class_naming => lambda { |f| f.capitalize+'Controller' } },
|
30
|
+
# { :dir => '_widgets', :class_naming => lambda { |f| f.capitalize+'Widget' } },
|
31
|
+
# { :dir => '_layouts', :class_naming => lambda { |f| f.capitalize+'Layout' } },
|
32
|
+
# { :dir => '_models', :class_naming => lambda { |f| f.capitalize } }
|
33
33
|
# ]
|
34
34
|
|
35
35
|
### For pretty url mapping
|
36
|
-
# config.magic_action_prefix = '
|
36
|
+
# config.magic_action_prefix = '__'
|
37
37
|
|
38
38
|
### This defines the session cookie definitions
|
39
39
|
# config.session_key = 'cuca_session'
|
data/lib/cuca.rb
CHANGED
@@ -35,6 +35,7 @@ require 'rubygems'
|
|
35
35
|
# All Classes are defined under this namespace
|
36
36
|
module Cuca
|
37
37
|
|
38
|
+
|
38
39
|
class CucaException < Exception # :nodoc:
|
39
40
|
end
|
40
41
|
|
@@ -44,6 +45,24 @@ end
|
|
44
45
|
|
45
46
|
end
|
46
47
|
|
48
|
+
# To require config and environment
|
49
|
+
def init_save_require(filename)
|
50
|
+
begin
|
51
|
+
require filename
|
52
|
+
rescue => e
|
53
|
+
title = "INIT Error [#{filename}]: #{e}"
|
54
|
+
$stderr.puts title
|
55
|
+
err = ''
|
56
|
+
e.backtrace.each do |b|
|
57
|
+
err << " #{b}\n"
|
58
|
+
end
|
59
|
+
$stderr.puts err
|
60
|
+
c = CGI.new
|
61
|
+
c.out { "<b>#{title}<br><br>#{err.gsub(/\n/,'<br>')}" }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
47
66
|
|
48
67
|
if $cuca_path.nil? then
|
49
68
|
$stderr.puts "WARN: $cuca_path not found, assuming #{Dir.pwd}"
|
@@ -57,23 +76,12 @@ $cuca_path = File.expand_path($cuca_path) + '/'
|
|
57
76
|
require 'cuca/app'
|
58
77
|
|
59
78
|
$LOAD_PATH << $cuca_path+'/lib'
|
60
|
-
|
61
|
-
|
62
|
-
rescue LoadError => e
|
63
|
-
$stderr.puts "WARN: Error loading conf/config: #{e}"
|
64
|
-
end
|
79
|
+
|
80
|
+
init_save_require($cuca_path+'/conf/config')
|
65
81
|
|
66
82
|
require 'cuca/widget'
|
67
83
|
require 'cuca/controller'
|
68
84
|
require 'cuca/layout'
|
69
85
|
|
70
|
-
|
71
|
-
require $cuca_path+'/conf/environment'
|
72
|
-
rescue LoadError => e
|
73
|
-
$stderr.puts "WARN: Error loading conf/environment: #{e}"
|
74
|
-
rescue => e
|
75
|
-
e.backtrace.each do |b|
|
76
|
-
$stderr.puts" #{b}\n"
|
77
|
-
end
|
78
|
-
end
|
86
|
+
init_save_require($cuca_path+'/conf/environment')
|
79
87
|
|
data/lib/cuca/app.rb
CHANGED
data/lib/cuca/const.rb
CHANGED
data/lib/cuca/controller.rb
CHANGED
@@ -65,9 +65,8 @@ end
|
|
65
65
|
#
|
66
66
|
# == Interrupting the program
|
67
67
|
#
|
68
|
-
# If you want to stop your program you can call the 'stop' method. Stop
|
69
|
-
#
|
70
|
-
# raising an error message.
|
68
|
+
# If you want to stop your program you can call the 'stop' method. Stop take some arguments
|
69
|
+
# that allows you to redirect, display error or set a different layout.
|
71
70
|
#
|
72
71
|
#
|
73
72
|
# == Examples
|
@@ -157,7 +156,7 @@ class Controller < Widget
|
|
157
156
|
# One or more before filter can set by an application Controller
|
158
157
|
# The instance methods will be run before the action get ran (get/post/run)
|
159
158
|
# If you have many filters and need order you can set the priority option.
|
160
|
-
# Lower priorities will
|
159
|
+
# Lower priorities will run first.
|
161
160
|
public
|
162
161
|
def self.before_filter(method, priority = 50)
|
163
162
|
define_filter_method(:def_before_filter, method, priority)
|
@@ -7,13 +7,22 @@ class ::Markaby::Builder # :nodoc:
|
|
7
7
|
|
8
8
|
def method_missing(sym, *args, &block ) # :nodoc:
|
9
9
|
class_name = sym.id2name
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
|
11
|
+
# give up immediately if we don't have a Constant capable method
|
12
|
+
return old_method_missing(sym, *args, &block) if
|
13
|
+
class_name[0].chr.upcase != class_name[0].chr
|
14
|
+
|
15
|
+
|
16
|
+
widget_name = class_name+'Widget'
|
17
|
+
|
18
|
+
c=Object::const_get(widget_name) if Object::const_defined?(widget_name)
|
19
|
+
|
20
|
+
if (c.nil? && !$app.nil?) then
|
21
|
+
c = $app.urlmap.action_module.const_get(widget_name) if \
|
22
|
+
$app.urlmap.action_module.const_defined?(widget_name)
|
14
23
|
end
|
15
24
|
|
16
|
-
|
25
|
+
return old_method_missing(sym, *args, &block) if c.nil?
|
17
26
|
|
18
27
|
widget = c.new({:args => args,
|
19
28
|
:assigns => @assigns },
|
@@ -32,10 +41,11 @@ module Cuca
|
|
32
41
|
# A generator is a mixin to Cuca::Widget. It should provide functions that generate
|
33
42
|
# content.
|
34
43
|
# Visible within a generator function should be all instance variables, all instance
|
35
|
-
# methods and an easy accessor to widgets
|
36
|
-
#
|
44
|
+
# methods and an easy accessor to widgets defined on the root namespace and
|
45
|
+
# within the action namespace ($app.urlmap.action_namespace). For example the view and
|
46
|
+
# markaby generators that come with cuca you can call a widget like:
|
37
47
|
# Link(a,b,c..) { block}
|
38
|
-
# and it will initialize the LinkWidget
|
48
|
+
# and it will initialize the LinkWidget.
|
39
49
|
module Generator
|
40
50
|
|
41
51
|
# == Markaby Generator
|
data/lib/cuca/generator/view.rb
CHANGED
@@ -52,30 +52,36 @@ module View
|
|
52
52
|
@base = base_object
|
53
53
|
end
|
54
54
|
|
55
|
+
|
56
|
+
|
55
57
|
def method_missing(sym, *args, &block )
|
56
58
|
class_name = sym.id2name
|
59
|
+
|
60
|
+
# $stderr.puts "View: Method missing: #{class_name}: #{@base.class.name}"
|
61
|
+
|
62
|
+
# 1st try to find method in the base widget
|
63
|
+
if @base.methods.include?(class_name) then
|
64
|
+
return @base.send(class_name, *args, &block)
|
65
|
+
end
|
57
66
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
c=Object::const_get(class_name+"Widget")
|
65
|
-
rescue NameError => e
|
66
|
-
raise "Undefined method: #{sym.id2name}"
|
67
|
+
# 2nd try to find a widget in root namespace and the controllers
|
68
|
+
widget_name = class_name+'Widget'
|
69
|
+
c=Object::const_get(widget_name) if Object.const_defined?(widget_name)
|
70
|
+
if (c.nil? && !$app.nil?) then
|
71
|
+
c = $app.urlmap.action_module.const_get(widget_name) if \
|
72
|
+
$app.urlmap.action_module.const_defined?(widget_name)
|
67
73
|
end
|
68
74
|
|
75
|
+
raise "Undefined method: #{sym.id2name}" if c.nil?
|
76
|
+
|
69
77
|
widget = c.new({:args => args,
|
70
78
|
:assigns => @assigns },
|
71
79
|
&block)
|
72
80
|
|
73
|
-
# $stderr.puts "Widget:" + widget.inspect
|
74
|
-
return widget.to_s
|
75
81
|
|
76
|
-
|
82
|
+
return widget.to_s
|
77
83
|
end
|
78
|
-
|
84
|
+
end
|
79
85
|
|
80
86
|
|
81
87
|
# VIEW_DIR = $cuca_path+'app/_views'
|
data/lib/cuca/session.rb
CHANGED
@@ -57,6 +57,8 @@ module Cuca
|
|
57
57
|
#
|
58
58
|
# Page memory is a container to store data only valid for the current action.
|
59
59
|
# It will be erased once you leave to a different action.
|
60
|
+
# Current request and query parameters (get/post) are automatically available in this
|
61
|
+
# container.
|
60
62
|
#
|
61
63
|
#
|
62
64
|
#
|
data/lib/cuca/stdlib/arform.rb
CHANGED
@@ -31,11 +31,22 @@ class ARFormWidget < FormWidget
|
|
31
31
|
@disabled_on_create = options[:disabled_on_create] || []
|
32
32
|
@hidden_on_update = options[:hidden_on_update] || []
|
33
33
|
@hidden_on_create = options[:hidden_on_create] || []
|
34
|
-
super(form_name, options
|
34
|
+
super(form_name, options)
|
35
35
|
end
|
36
36
|
|
37
37
|
def on_submit
|
38
38
|
controller.send(@form_name+'_submit', @model) unless controller.nil?
|
39
|
+
|
40
|
+
# this is to reload the form with the new values in case the formname_submit did
|
41
|
+
# save something:
|
42
|
+
clear
|
43
|
+
form
|
44
|
+
end
|
45
|
+
|
46
|
+
# overwrite this method to perform modifications
|
47
|
+
# before validateing the data
|
48
|
+
def before_validate(variables)
|
49
|
+
variables
|
39
50
|
end
|
40
51
|
|
41
52
|
def validate
|
@@ -44,6 +55,10 @@ class ARFormWidget < FormWidget
|
|
44
55
|
p = request_parameters.dup
|
45
56
|
p.delete(@submit_name)
|
46
57
|
|
58
|
+
|
59
|
+
p = before_validate(p)
|
60
|
+
|
61
|
+
|
47
62
|
if @model.new_record? then
|
48
63
|
@disabled_on_create.each { |d| p.delete(d) }
|
49
64
|
@hidden_on_create.each { |d| p.delete(d) }
|
@@ -58,7 +73,7 @@ class ARFormWidget < FormWidget
|
|
58
73
|
@password_fields.each do |pwf|
|
59
74
|
p.delete(pwf) if p[pwf].chomp.empty?
|
60
75
|
end
|
61
|
-
$stderr.puts p.inspect
|
76
|
+
# $stderr.puts p.inspect
|
62
77
|
@model.attributes = p
|
63
78
|
|
64
79
|
return true if @model.valid?
|
@@ -95,6 +110,12 @@ class ARFormWidget < FormWidget
|
|
95
110
|
"<input type='text' name='#{name}' value='#{value}' #{'disabled' unless enabled}>"
|
96
111
|
end
|
97
112
|
|
113
|
+
private
|
114
|
+
def fe_textarea(name, value, enabled, rows=4, cols = 50)
|
115
|
+
"<textarea name='#{name}' rows='#{rows}' cols='#{cols}'>#{value}</textarea>"
|
116
|
+
end
|
117
|
+
|
118
|
+
|
98
119
|
# the fe-password is special: will never contain a value and will not save the
|
99
120
|
# password if nothing was typed into the field
|
100
121
|
private
|
@@ -130,8 +151,9 @@ end
|
|
130
151
|
|
131
152
|
def fe_datetime(name, v,enabled)
|
132
153
|
v = Time.now unless v
|
154
|
+
v = "#{v.year}/#{twodig(v.month)}/#{twodig(v.day)} #{v.hour}:#{v.min}" if v.instance_of?(Time)
|
133
155
|
r = <<-EOS
|
134
|
-
<input type='text' name='#{name}' id='i_#{name}' value='#{v
|
156
|
+
<input type='text' name='#{name}' id='i_#{name}' value='#{v}' #{'disabled' unless enabled}>
|
135
157
|
EOS
|
136
158
|
if enabled then
|
137
159
|
r << <<-EOS
|
@@ -152,6 +174,35 @@ end
|
|
152
174
|
return r
|
153
175
|
end
|
154
176
|
|
177
|
+
# select date.. no time
|
178
|
+
def fe_date(name, v,enabled)
|
179
|
+
v = Time.now unless v
|
180
|
+
r = <<-EOS
|
181
|
+
<input type='text' name='#{name}' id='i_#{name}' value='#{v.year}/#{twodig(v.month)}/#{twodig(v.day)}' #{'disabled' unless enabled}>
|
182
|
+
EOS
|
183
|
+
if enabled then
|
184
|
+
r << <<-EOS
|
185
|
+
<input type='submit' id='s_#{name}' value='...'>
|
186
|
+
<script type="text/javascript">
|
187
|
+
Calendar.setup({
|
188
|
+
inputField : "i_#{name}", // id of the input field
|
189
|
+
ifFormat : "%Y/%m/%d", // format of the input field
|
190
|
+
showsTime : false, // will display a time selector
|
191
|
+
button : "s_#{name}", // trigger for the calendar (button ID)
|
192
|
+
singleClick : true, // double-click mode
|
193
|
+
step : 1 // show all years in drop-down boxes (instead of every other year as default)
|
194
|
+
});
|
195
|
+
</script>
|
196
|
+
</input>
|
197
|
+
EOS
|
198
|
+
end
|
199
|
+
return r
|
200
|
+
end
|
201
|
+
|
202
|
+
def fe_time(name,v,enabled)
|
203
|
+
"<input name='#{name}' size=5 type='text' value='#{v || '0:00'}'#{' disabled' unless enabled}>"
|
204
|
+
end
|
205
|
+
|
155
206
|
def fe_bool(name,v,enabled)
|
156
207
|
r = ''
|
157
208
|
r << "<select name='#{name}' #{'disabled' unless enabled}>\n"
|
@@ -177,6 +228,10 @@ end
|
|
177
228
|
r << fe_int(name,value,enabled)
|
178
229
|
when :datetime
|
179
230
|
r << fe_datetime(name,value,enabled)
|
231
|
+
when :date
|
232
|
+
r << fe_date(name,value,enabled)
|
233
|
+
when :time
|
234
|
+
r << fe_time(name, value, enabled)
|
180
235
|
when :password
|
181
236
|
r << fe_password(name, enabled)
|
182
237
|
end
|
@@ -189,6 +244,13 @@ end
|
|
189
244
|
fe(col.type, col.name, @model.send(column_name.intern))
|
190
245
|
end
|
191
246
|
|
247
|
+
|
248
|
+
# Load column values into instance variables
|
249
|
+
def setup
|
250
|
+
@model.class.columns.each do |col|
|
251
|
+
self.instance_variable_set("@#{col.name}", @model.send(col.name.intern))
|
252
|
+
end
|
253
|
+
end
|
192
254
|
|
193
255
|
# you might want to replace this method
|
194
256
|
public
|
data/lib/cuca/stdlib/form.rb
CHANGED
@@ -53,25 +53,38 @@ class FormWidget < Cuca::Widget
|
|
53
53
|
# {form_name}_submit(result) on the CONTROLLER.
|
54
54
|
def on_submit
|
55
55
|
controller.send(@form_name+'_submit', get_variables) unless controller.nil?
|
56
|
+
clear
|
57
|
+
form
|
56
58
|
end
|
57
59
|
|
58
|
-
|
60
|
+
# options can be used for form specific stuff
|
61
|
+
# we only use :post_to to set @post_to atm
|
62
|
+
def output(form_name, options = {})
|
59
63
|
@form_name = form_name
|
60
|
-
|
64
|
+
|
61
65
|
@submit_name = 'submit_'+@form_name
|
62
66
|
@form_errors = {}
|
63
67
|
|
68
|
+
@options = options
|
69
|
+
|
70
|
+
setup
|
71
|
+
|
72
|
+
@post_to = @options[:post_to] || cgi.path_info
|
73
|
+
|
74
|
+
|
75
|
+
# form
|
76
|
+
|
64
77
|
if posted? then
|
65
78
|
load_variables
|
66
79
|
validate
|
67
80
|
if @form_errors.empty? then
|
68
|
-
|
81
|
+
# What was that thought about?
|
82
|
+
# clear # submitted forms should not have any content that might have been generated
|
69
83
|
return on_submit
|
70
84
|
else
|
71
85
|
form
|
72
86
|
end
|
73
87
|
else
|
74
|
-
setup
|
75
88
|
form
|
76
89
|
end
|
77
90
|
end
|
@@ -20,10 +20,19 @@ class BaseList < Cuca::Widget
|
|
20
20
|
@rewrite_hooks[field_id] = proc
|
21
21
|
end
|
22
22
|
|
23
|
+
def row2hash(row)
|
24
|
+
res = {}
|
25
|
+
c = columns
|
26
|
+
c.each_index do |idx|
|
27
|
+
res[c[idx][:id]] = row[idx]
|
28
|
+
end
|
29
|
+
res
|
30
|
+
end
|
31
|
+
|
23
32
|
def rewrite_field(row, field_id, content)
|
24
33
|
# $stderr.puts "REwrite field(#{row.inspect}, #{field_id.inspect}, #{content.inspect} - hooks #{@rewrite_hooks.inspect}"
|
25
34
|
return content unless @rewrite_hooks[field_id]
|
26
|
-
return @rewrite_hooks[field_id].call(row, content)
|
35
|
+
return @rewrite_hooks[field_id].call(row2hash(row), content)
|
27
36
|
end
|
28
37
|
|
29
38
|
|
data/lib/cuca_console.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# This file is -r required when runnung script/console to load
|
2
|
+
# support files automatically.
|
3
|
+
# Only for the CLI irb console
|
4
|
+
|
5
|
+
require 'cuca/urlmap'
|
6
|
+
|
7
|
+
puts "Cuca console: type: url [/some/path] to load support files of your app"
|
8
|
+
$app = Cuca::App.new
|
9
|
+
|
10
|
+
def url(some_path)
|
11
|
+
$app.load_support_files(Cuca::URLMap.new($cuca_path+'/app', some_path))
|
12
|
+
end
|
data/tests/test_app/README
CHANGED
@@ -1 +1 @@
|
|
1
|
-
This directory is for the unit tests, it doesn't make sense for anything else.
|
1
|
+
This directory is for the unit tests, it doesn't make sense for anything else.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cuca
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.05"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Boese
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-08-20 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -41,12 +41,11 @@ extra_rdoc_files:
|
|
41
41
|
files:
|
42
42
|
- bin/cuca
|
43
43
|
- lib/cuca.rb
|
44
|
+
- lib/cuca_console.rb
|
44
45
|
- lib/cuca
|
45
46
|
- lib/cuca/cgi_fix.rb
|
46
47
|
- lib/cuca/controller.rb
|
47
48
|
- lib/cuca/config.rb
|
48
|
-
- lib/cuca/urlmap2.rb
|
49
|
-
- lib/cuca/urlmap-original.rb
|
50
49
|
- lib/cuca/stdlib
|
51
50
|
- lib/cuca/stdlib/arview.rb
|
52
51
|
- lib/cuca/stdlib/form.rb
|
data/lib/cuca/urlmap-original.rb
DELETED
@@ -1,324 +0,0 @@
|
|
1
|
-
|
2
|
-
if __FILE__ == $0 then
|
3
|
-
require 'rubygems'
|
4
|
-
require 'cuca'
|
5
|
-
end
|
6
|
-
|
7
|
-
module Cuca
|
8
|
-
|
9
|
-
# URLMap will throw this in case we can't find a controller
|
10
|
-
# file for a URL.
|
11
|
-
class RoutingError < StandardError # :nodoc:
|
12
|
-
end
|
13
|
-
|
14
|
-
|
15
|
-
# == URLMap
|
16
|
-
#
|
17
|
-
# URLMap is used internally to match a URL to a controller file.
|
18
|
-
# Call with ds = URLMap.new('/path/to/app', 'path/from/url')
|
19
|
-
# URLMap.new(base_path, url)
|
20
|
-
#
|
21
|
-
# You can then fetch the following values:
|
22
|
-
#
|
23
|
-
# * script - path to the controller file
|
24
|
-
# * url - unmodified URL as passed to initializer
|
25
|
-
# * assigns - hash with variable assigns from the url (magick prefixes)
|
26
|
-
# * subcall - name of subcall or nil if a normal call was made
|
27
|
-
# * action - Action name (Note: action.capitalize+"Controller" is your controller class name)
|
28
|
-
# * base_url - Base URL to the action (e.g.: /user/someone/show is -> /user/someone/)
|
29
|
-
# * base_path - Unmodified base_path
|
30
|
-
# * action_path - Path to the action script
|
31
|
-
# * action_path_full - Full path to action script
|
32
|
-
# * path_tree - an array of each directory on the way from /path/to/app to the script
|
33
|
-
# (to look for include_directories in - see Cuca::Config)
|
34
|
-
# * action_module - The module the action should be loaded into (to avoid name conflicts, depends on action_path)
|
35
|
-
#
|
36
|
-
#
|
37
|
-
# == Match on other URL
|
38
|
-
#
|
39
|
-
# A widget/controller can make use of the URLMap object to scan on other directories (example to find out if a
|
40
|
-
# link url will be withing the same controller).
|
41
|
-
#
|
42
|
-
# See match? / submatch? and usubmatch?
|
43
|
-
#
|
44
|
-
#
|
45
|
-
# == Notes
|
46
|
-
#
|
47
|
-
# URL's ending with '/' will be scanned for default index files.
|
48
|
-
#
|
49
|
-
# URL's where last part (action) starts with '-' will be scanned for
|
50
|
-
# subcalls
|
51
|
-
#
|
52
|
-
# If no script is found or any other error it will raise a RoutingError exception
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# == Example
|
56
|
-
#
|
57
|
-
# u = URLMap.new('/home/bones/src/cuca_app/app', 'customer/southwind_lda/show'
|
58
|
-
#
|
59
|
-
# u.script => '/home/bones/src/cuca_app/app/customer/__customer/show.rb'
|
60
|
-
# u.action => 'show'
|
61
|
-
# u.base_url => '/customer/__customer/'
|
62
|
-
# u.assigns => { 'customer' => 'southwind_lda' }
|
63
|
-
# u.action_path => 'customer/southwind_lda/'
|
64
|
-
#
|
65
|
-
class URLMap
|
66
|
-
attr_reader :url # current url
|
67
|
-
attr_reader :assigns
|
68
|
-
attr_reader :script
|
69
|
-
attr_reader :subcall
|
70
|
-
attr_reader :base_url
|
71
|
-
attr_reader :base_path
|
72
|
-
attr_reader :action
|
73
|
-
attr_reader :action_path
|
74
|
-
attr_reader :action_path_full
|
75
|
-
attr_reader :action_module
|
76
|
-
attr_reader :path_tree
|
77
|
-
|
78
|
-
DEF_ACT = Cuca::App::config['magic_action_prefix'] || '__'
|
79
|
-
DEF_IDX = [ 'index', 'default' ]
|
80
|
-
|
81
|
-
private
|
82
|
-
def scan_file(base, file)
|
83
|
-
|
84
|
-
if (file == '') then # check for default index file
|
85
|
-
DEF_IDX.each do |idxfile|
|
86
|
-
if File.exist?("#{base}/#{idxfile}.rb")
|
87
|
-
@action = idxfile
|
88
|
-
return "#{idxfile}.rb"
|
89
|
-
end
|
90
|
-
end
|
91
|
-
raise RoutingError.new("No default index file found in #{base}")
|
92
|
-
end
|
93
|
-
|
94
|
-
@action = file
|
95
|
-
|
96
|
-
# check if a regular file exists:
|
97
|
-
# puts "Checking file on #{check}"
|
98
|
-
return (file+".rb") if File.exist?("#{base}/#{file}.rb")
|
99
|
-
|
100
|
-
# check if the subcall file exists:
|
101
|
-
if (file[0].chr == '-') then
|
102
|
-
(action,subcall) = file.scan(/^\-(.*)\-(.*)$/).flatten
|
103
|
-
if action.nil? || subcall.nil? || action.strip.empty? then
|
104
|
-
raise RoutingError.new("Bad format on subcall: #{file}")
|
105
|
-
end
|
106
|
-
raise RoutingError.new("Script not found for subcall: #{file}: #{action}.rb") if !File.exist?("#{base}/#{action}.rb")
|
107
|
-
@subcall = subcall
|
108
|
-
@action = action
|
109
|
-
return "#{action}.rb"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
|
114
|
-
# scan_dir will look within a realdirectory for an unparsed url 'file' and return
|
115
|
-
# it's real path
|
116
|
-
private
|
117
|
-
def scan_dir(base, file)
|
118
|
-
|
119
|
-
striped = "#{base}/#{file}"[@base_path.length..-1]
|
120
|
-
mount = Cuca::App.config['mount'] || {}
|
121
|
-
$stderr.puts "SCAN DIR: #{striped}"
|
122
|
-
$stderr.puts "MOUNTS: #{mount.inspect}"
|
123
|
-
|
124
|
-
|
125
|
-
if mount["#{striped}/"] then
|
126
|
-
$stderr.puts "Found mount point, returning: #{mount["#{striped}/"]}"
|
127
|
-
return mount["#{striped}/"]
|
128
|
-
end
|
129
|
-
|
130
|
-
if File.directory?("#{base}/#{file}") then
|
131
|
-
return file.empty? ? base : "#{base}/#{file}" # avoid returning double //
|
132
|
-
end
|
133
|
-
|
134
|
-
d = Dir["#{base}/#{DEF_ACT}*"].collect { |f| f.split('/').last }
|
135
|
-
|
136
|
-
# puts "Directory not found, checking for default in #{base} - #{file}"
|
137
|
-
|
138
|
-
# puts d.inspect
|
139
|
-
#
|
140
|
-
|
141
|
-
raise RoutingError.new("Multiple default actions defined in #{base}") if d.size > 1
|
142
|
-
raise RoutingError.new("Routing Error in #{base}") if d.empty?
|
143
|
-
|
144
|
-
|
145
|
-
@assigns[d[0][DEF_ACT.size..-1]] = file
|
146
|
-
"#{base}/#{d[0]}"
|
147
|
-
end
|
148
|
-
|
149
|
-
|
150
|
-
private
|
151
|
-
def make_module(path)
|
152
|
-
const_name = "Appmod_#{path.gsub(/[\/\\]/, '_')}"
|
153
|
-
|
154
|
-
if Cuca::Objects::const_defined?(const_name.intern) then
|
155
|
-
return Cuca::Objects::const_get(const_name.intern)
|
156
|
-
end
|
157
|
-
|
158
|
-
m = Module.new
|
159
|
-
Cuca::Objects::const_set(const_name.intern, m)
|
160
|
-
return m
|
161
|
-
end
|
162
|
-
|
163
|
-
|
164
|
-
# scan will match an URI to a script and set assigns. (called from initialize)
|
165
|
-
private
|
166
|
-
def scan
|
167
|
-
files = @path_info.split('/')
|
168
|
-
|
169
|
-
files << '' if @path_info[@path_info.size-1].chr == '/' # add empty element if we point to a directory
|
170
|
-
|
171
|
-
# files now contains something like:
|
172
|
-
# [users, show, martin, contacts]
|
173
|
-
|
174
|
-
# puts files.inspect
|
175
|
-
real_path = @base_path.dup
|
176
|
-
|
177
|
-
# scan directory
|
178
|
-
files.each_index do |idx|
|
179
|
-
next if idx >= (files.size-1) # skip last element
|
180
|
-
r = scan_dir(real_path, files[idx])
|
181
|
-
raise RoutingError.new("Routing Error at #{real_path} - #{files[idx]}") if !r
|
182
|
-
@path_tree << r
|
183
|
-
real_path = r
|
184
|
-
end
|
185
|
-
|
186
|
-
@url = @path_info
|
187
|
-
@base_url = "#{files[0..-2].join('/')}/"
|
188
|
-
@action_path = real_path[@base_path.length..-1]
|
189
|
-
@action_path_full = real_path
|
190
|
-
@action_module = make_module(@action_path)
|
191
|
-
|
192
|
-
# scan file (last element)
|
193
|
-
r = scan_file(real_path, files.last)
|
194
|
-
|
195
|
-
raise RoutingError.new("Routing Error - script not found at #{real_path} - #{files.last}") if !r
|
196
|
-
|
197
|
-
real_path = "#{real_path}/#{r}"
|
198
|
-
|
199
|
-
@script = File.expand_path(real_path)
|
200
|
-
# @path_tree = _tree(@base_path, @script)
|
201
|
-
self
|
202
|
-
end
|
203
|
-
|
204
|
-
|
205
|
-
# match will check if the supplied url maches with a script
|
206
|
-
# returns boolean
|
207
|
-
#
|
208
|
-
# Example:
|
209
|
-
# URLMap('/path/to/app', '/customer/southwind_lda/').match?('/path/to/app/customer/__custid/index.rb') => true
|
210
|
-
public
|
211
|
-
def match?(script)
|
212
|
-
m_script = @script
|
213
|
-
p_script = File.expand_path(script)
|
214
|
-
|
215
|
-
# $stderr.puts "URLMap::match - #{m_script} - #{p_script}"
|
216
|
-
return (m_script == p_script)
|
217
|
-
rescue RoutingError
|
218
|
-
false
|
219
|
-
end
|
220
|
-
|
221
|
-
|
222
|
-
# this will match if the current script can be found within a path
|
223
|
-
# from the parameters.
|
224
|
-
#
|
225
|
-
# Example:
|
226
|
-
# URLMap('/path/to/app', '/customer/southwind_lda/').submatch?('/customer/__custid/') => true
|
227
|
-
public
|
228
|
-
def submatch?(some_path)
|
229
|
-
# $stderr.puts "Submatch: #{some_path} with #{@script} - #{(@script.length < some_path.length).inspect} #{@script.include?(some_path)}"
|
230
|
-
return false if @script.length < some_path.length
|
231
|
-
return @script.include?(some_path)
|
232
|
-
end
|
233
|
-
|
234
|
-
# this will match the current script to a part of a url (link):
|
235
|
-
#
|
236
|
-
# Example:
|
237
|
-
# URLMap('/path/to/app', '/customer/southwind_lda/').submatch?('/customer/other_customer/') => true
|
238
|
-
public
|
239
|
-
def usubmatch?(some_path)
|
240
|
-
@path_info.include?(some_path)
|
241
|
-
end
|
242
|
-
|
243
|
-
# FIXME: needed?
|
244
|
-
public
|
245
|
-
def has_script?(script)
|
246
|
-
return !(@script == '')
|
247
|
-
end
|
248
|
-
|
249
|
-
|
250
|
-
def initialize(base_path, path_info, default_actions = ['index'])
|
251
|
-
@path_info = path_info
|
252
|
-
@base_path = File.expand_path(base_path)
|
253
|
-
@script = ''
|
254
|
-
@subcall = nil
|
255
|
-
@default_actions = default_actions
|
256
|
-
@assigns = {}
|
257
|
-
@action = ''
|
258
|
-
@action_path = ''
|
259
|
-
@path_tree = [base_path]
|
260
|
-
scan
|
261
|
-
self
|
262
|
-
end
|
263
|
-
|
264
|
-
end
|
265
|
-
|
266
|
-
end
|
267
|
-
|
268
|
-
|
269
|
-
#
|
270
|
-
# Testings:
|
271
|
-
#
|
272
|
-
|
273
|
-
if __FILE__ == $0 then
|
274
|
-
require 'app'
|
275
|
-
|
276
|
-
BASE = '/home/bones/src/cuca/app'
|
277
|
-
URL = 'user/martin/somewhere/notexist/'
|
278
|
-
|
279
|
-
puts "Testing on '#{BASE}' - '#{URL}'"
|
280
|
-
|
281
|
-
module Cuca
|
282
|
-
ds = URLMap.new(BASE, URL)
|
283
|
-
begin
|
284
|
-
rescue RoutingError => e
|
285
|
-
puts "E: Invalid request #{$!}"
|
286
|
-
end
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
puts "Match with: #{ds.match?('/home/bones/src/cuca/app/user/__default_username/index.rb')}"
|
291
|
-
puts "Submatch with /user/__username/ #{ds.submatch?('/user/__username/')}"
|
292
|
-
puts "Submatch with '/user/' #{ds.submatch?('/user/')}"
|
293
|
-
puts "USubmatch with '/user/' #{ds.usubmatch?('/user/martin')}"
|
294
|
-
puts
|
295
|
-
puts "Script is: #{ds.script}"
|
296
|
-
puts "Assigns are: #{ds.assigns.inspect}"
|
297
|
-
puts "Subcall: #{ds.subcall.inspect}"
|
298
|
-
puts "Action: #{ds.action}"
|
299
|
-
puts "Action Path: #{ds.action_path}"
|
300
|
-
puts "Action Path Full: #{ds.action_path_full}"
|
301
|
-
puts "Action Module: #{ds.action_module.inspect}"
|
302
|
-
puts "Path tree: #{ds.path_tree.inspect}"
|
303
|
-
end
|
304
|
-
|
305
|
-
end
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
# URL: "/user/martin/show"
|
314
|
-
# DIR: "/user/__userid/show'
|
315
|
-
# MOUNT: "/user/__userid/" =>>> "/plugin/user" contains 'show'
|
316
|
-
# MOUNT: "/user/__userid/" =>>> "/plugin/user2" contains 'see'
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
data/lib/cuca/urlmap2.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
class URLMap2
|
4
|
-
|
5
|
-
|
6
|
-
def path2array(p)
|
7
|
-
p.split('/')
|
8
|
-
end
|
9
|
-
def array2path(a)
|
10
|
-
a.join('/')
|
11
|
-
end
|
12
|
-
|
13
|
-
|
14
|
-
def initialize(directory, options)
|
15
|
-
@app_path = options[:app_path] || raise ArgumentError.new("app_path required")
|
16
|
-
@mounts = options[:mounts] || []
|
17
|
-
@url = options[:url] || raise ArgumentError.new("url required")
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|