cuca 0.03 → 0.04

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,10 @@
1
1
  # little fake cgi class that allows automated testing of cgi application
2
2
 
3
3
  class CGIEmu < CGI
4
+
5
+ attr_reader :out_params
6
+ attr_reader :out_content
7
+
4
8
  class EnvTable
5
9
  def initialize(options)
6
10
  @test_path_info = options['PATH_INFO'] || '/'
@@ -63,5 +67,10 @@ class CGIEmu < CGI
63
67
  super()
64
68
  end
65
69
 
70
+ def out(params, &block)
71
+ @out_params = params
72
+ @out_content = block.call
73
+ end
74
+
66
75
  end
67
76
 
@@ -55,4 +55,14 @@ class CGI # :nodoc:
55
55
  end
56
56
  end
57
57
 
58
+ # cgi implementation test
59
+ def cgidump
60
+ s = ""
61
+ s << "-----ENV------<br>"
62
+ self.env_table.each_pair { |k,v| s << "#{k} => #{v}<br>" }
63
+ s << "--------------<br>"
64
+ s << "Server Software: #{self.server_software}<br>"
65
+ s << "PATH INFO: #{self.path_info}<br>"
66
+ end
67
+
58
68
  end
@@ -0,0 +1,67 @@
1
+ module Cuca
2
+
3
+ # == Configure the application
4
+ # App::Config is normally called from conf/environment.rb . The attributes below the framework
5
+ # will make use of, but you can always define own ones.
6
+ #
7
+ # == Example
8
+ #
9
+ # Cuca::App.configure do |conf|
10
+ # conf.include_directories = %{_widgets _special_widgets}
11
+ # conf.database = 'mydb' # application specific
12
+ # end
13
+ # === Attributes:
14
+ #
15
+ # * include_directories
16
+ # An array of directories that will be automatically included if you call an action.
17
+ # If one of the directories is found in the path where the action file is located it will require
18
+ # all files found. (default: %w{_controllers _widgets _layouts} )
19
+ # Optionally it's possible to autoload these support files. To do this you must pass an
20
+ # array of hashes to the method with the following keys:
21
+ # - :dir The name of the directory (e.g. _controllers)
22
+ # - :class_naming A proc that will take one parameter and returns the name of the class
23
+ # found within the file. It will get the filename as parameter.
24
+ # example :class_naming => Proc.new { |file_name| file_name.capitalize+'Controller' }
25
+ # * log_level - default 3 (future?)
26
+ # * magic_prefix - default: '__default_' (see Cuca::Controller)
27
+ # * display_errors - default: true , display errors in browser (swith off within production systems)
28
+ class Config < Hash
29
+ def method_missing(m, *params)
30
+ met = m.id2name
31
+
32
+ # raise NoMethodError
33
+ if met[met.size-1].chr == '=' then
34
+ self[met[0..met.size-2]] = params[0]
35
+ return
36
+ end
37
+
38
+ if met[-2..-1] == '<<' then
39
+ self[met[0..met.size-3]] ||= []
40
+ self[met[0..met.size-3]] << params[0]
41
+ return
42
+ end
43
+
44
+ return self[met] unless self[met].nil?
45
+
46
+ raise NoMethodError
47
+ end
48
+
49
+ # some default stuff
50
+ def initialize
51
+ self['include_directories'] = %w{_controllers _widgets _layouts}
52
+ self['log_level'] = 3
53
+ self['magic_prefix'] = '__default_'
54
+ self['session_key'] = 'cuca_session'
55
+ self['session_prefix'] = 'cuca.'
56
+ self['session_valid'] = 3600*24
57
+ self['view_directory'] = 'app/_views' # where to find views for the view/erb generator
58
+ self['http_404'] = '404.html'
59
+ self['http_500'] = '500.html'
60
+ self['default_mime_type'] = 'text/html'
61
+ self['display_errors'] = true
62
+ self['http_static_content_expires'] = 300 # expires http header for static content (only if served by the dispatcher)
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -1,3 +1,3 @@
1
1
  module Cuca
2
- VERSION = '0.03'
2
+ VERSION = '0.04'
3
3
  end
@@ -22,7 +22,7 @@ end
22
22
  # the output method you must implement run or post or get or any combination.
23
23
  #
24
24
  # Additionally you can also define a wrapping layout (using the layout function) and you can
25
- # run code before a certain action is called using before_filter's.
25
+ # run code before and after a certain action is called using before/after_filter's.
26
26
  #
27
27
  # == Naming
28
28
  #
@@ -95,8 +95,10 @@ end
95
95
  #
96
96
  # def get
97
97
  # mab do
98
- # h1 "Welcome to the Fancy Page called #{@page_title}"
99
- # p { text "Welcome to my"; b { paragraph } }
98
+ # h1 { "Welcome to the Fancy Page called #{@page_title}" }
99
+ # p { text "Welcome to my"
100
+ # b { "paragraph" }
101
+ # }
100
102
  # end
101
103
  # end
102
104
  # end
@@ -142,50 +144,72 @@ class Controller < Widget
142
144
 
143
145
 
144
146
  private
145
- def self.define_filter_method(chain_name, method_name)
147
+ def self.define_filter_method(chain_name, method_name, priority=50)
146
148
  begin
147
149
  filters = self.send(chain_name)
148
- filters = "#{filters};#{method_name}"
150
+ filters = "#{filters};#{method_name}|#{priority.to_s}"
149
151
  define_attr_method(chain_name, filters)
150
152
  rescue NoMethodError => e
151
- define_attr_method(chain_name, method_name)
153
+ define_attr_method(chain_name, "#{method_name}|#{priority.to_s}")
152
154
  end
153
155
  end
154
156
 
155
157
  # One or more before filter can set by an application Controller
156
158
  # The instance methods will be run before the action get ran (get/post/run)
159
+ # If you have many filters and need order you can set the priority option.
160
+ # Lower priorities will be ran first.
157
161
  public
158
- def self.before_filter(method)
159
- define_filter_method(:def_before_filter, method)
162
+ def self.before_filter(method, priority = 50)
163
+ define_filter_method(:def_before_filter, method, priority)
160
164
  end
161
165
 
162
166
  # Priority before filters will be ran before any before filters
163
- # this should be only used internally
167
+ # this should be only used internally or for core extension
164
168
  public
165
169
  def self.priority_before_filter(method)
166
170
  define_filter_method(:def_priority_before_filter, method)
167
171
  end
168
172
 
173
+ # Priority after filters will be ran after any after filters
174
+ # this should be only used internally or for core extension
175
+ # also this gets called no matter if anyone raises :stop method
176
+ public
177
+ def self.priority_after_filter(method)
178
+ define_filter_method(:def_priority_after_filter, method)
179
+ end
180
+
169
181
  # after_filter - get run after the controller action has be executed
182
+ # If you have many filters and need order you can set the priority option.
183
+ # Lower priorities will be ran first.
170
184
  public
171
- def self.after_filter(method)
172
- define_filter_method(:def_after_filter, method)
185
+ def self.after_filter(method, priority = 50)
186
+ define_filter_method(:def_after_filter, method, priority)
173
187
  end
174
188
 
175
189
  private
176
190
  def run_filters(chain_name, debug_filter_names)
177
- filters = self.class.run_attr_method(chain_name.to_s)
178
- return if filters.nil?
179
- filters.split(';').each do |filter|
180
- next if filter.strip == ''
181
-
182
- begin
183
- if (!self.methods.include?(filter)) then
184
- raise ApplicationException.new("Filter not found in chain #{debug_filter_names}: #{filter}")
185
- end
186
- # $stderr.puts "Running Filter (#{debug_filter_names}): #{filter}"
187
- ret = self.send(filter.intern)
188
- @cancel_execution = true if ret == false
191
+ filter_str = self.class.run_attr_method(chain_name.to_s)
192
+ return if filter_str.nil?
193
+
194
+ filters = []
195
+ filter_str.split(';').each do |f|
196
+ next if f.strip == ''
197
+ mp = f.split('|')
198
+ filters << [mp[0], mp[1]]
199
+ end
200
+
201
+ sorted_filters = filters.sort { |a,b| a[1] <=> b[1] }
202
+
203
+ sorted_filters.each do |f|
204
+ break if @cancel_execution
205
+ filter = f[0]
206
+ begin
207
+ if (!self.methods.include?(filter)) then
208
+ http_status "SERVER_ERROR"
209
+ raise ApplicationException.new("Filter not found in chain #{debug_filter_names}: #{filter}")
210
+ end
211
+ ret = self.send(filter.intern)
212
+ @cancel_execution = true if ret == false
189
213
  rescue BreakControllerException => bc
190
214
  handle_exception(bc)
191
215
  end
@@ -204,6 +228,10 @@ class Controller < Widget
204
228
  public
205
229
  def run_after_filters
206
230
  run_filters(:def_after_filter, 'After Filters')
231
+ ce = @cancel_execution
232
+ @cancel_execution = false
233
+ run_filters(:def_priority_after_filter, 'Priority After Filters')
234
+ @cancel_execution = ce
207
235
  end
208
236
 
209
237
 
@@ -235,13 +263,24 @@ class Controller < Widget
235
263
 
236
264
  if e.flags.has_key?(:error) then
237
265
  @_layout = false
266
+ http_status "SERVER_ERROR"
238
267
  clear
239
268
  @error_message = e.flags[:error]
240
269
  @cancel_execution = true
241
- mab { html { body { h2 "Error"; text @error_message }}}
270
+ trace = ''
271
+ if Cuca::App.config['display_errors'] then
272
+ e.backtrace.each do |b|
273
+ trace<< "<br/>#{b}"
274
+ end
275
+ end
276
+ mab { html { body { h2 "Error"; text @error_message; br; text trace }}}
242
277
  end
243
278
  end
244
279
 
280
+ def action_name
281
+ $app.urlmap.action
282
+ end
283
+
245
284
  private
246
285
  # Overwrite this method to handle get and post events
247
286
  def run
@@ -261,7 +300,7 @@ class Controller < Widget
261
300
  # exceptions. what within [post,get,run]
262
301
  # TOTHINKABOUT: run before filter from this method?
263
302
  public
264
- def _do(what, subcall)
303
+ def _do(what, subcall = nil)
265
304
  return if @cancel_execution
266
305
 
267
306
  method_name = what
@@ -270,6 +309,8 @@ class Controller < Widget
270
309
  self.send(method_name) if self.methods.include?(method_name)
271
310
  rescue BreakControllerException => e
272
311
  handle_exception(e)
312
+ rescue ApplicationException => e
313
+ http_status "SERVER_ERROR"
273
314
  end
274
315
  end
275
316
 
@@ -301,6 +342,7 @@ class Controller < Widget
301
342
  layout_class = Object::const_get(lname)
302
343
  rescue => e
303
344
  # fixme - if layout loading fails we should display some error
345
+ raise ApplicationException.new("Could not load layout: #{lname}: #{e}")
304
346
  return nil
305
347
  end
306
348
  end
@@ -318,4 +360,3 @@ end
318
360
 
319
361
 
320
362
  end # Module
321
-
@@ -47,6 +47,7 @@ class Layout < Widget
47
47
  # the controller will create the layout. The controller will also set the content_for_layout
48
48
  # assign besides other assigns from the controller.
49
49
  def initialize(params = {}, &block)
50
+ raise ArgumentError.new("Layout requires :assigns for layout content") if params[:assigns].nil?
50
51
  params[:assigns].each_pair do |k,v|
51
52
  instance_variable_set("@#{k.to_s}", v)
52
53
  end
@@ -71,6 +71,7 @@ module Cuca
71
71
  class Session
72
72
  attr_reader :flash
73
73
  attr_reader :page
74
+ attr_reader :cgi
74
75
 
75
76
  private
76
77
  def make_session
@@ -90,7 +91,7 @@ class Session
90
91
  # returns true/false if a session exists
91
92
  def exists?
92
93
  begin
93
- p = @parameters.clone
94
+ p = @session_parameters.clone
94
95
  p['new_session'] = false
95
96
  session = CGI::Session.new(cgi, p)
96
97
  rescue ArgumentError
@@ -106,11 +107,13 @@ class Session
106
107
  'database_manager' => CGI::Session::PStore,
107
108
  'session_key' => App::config["session_key"],
108
109
  'session_path' => '/',
110
+ # 'new_session' => false,
109
111
  'session_expires' => Time.now + App::config["session_valid"].to_i,
110
112
  'prefix' => App::config["session_prefix"] }
111
113
 
112
114
  make_session
113
115
 
116
+
114
117
  @flash = SessionFlash.new(self)
115
118
  @page = SessionPage.new(self)
116
119
  end
@@ -143,14 +146,15 @@ class Controller
143
146
  # close it afterwards.
144
147
  def self.use_session
145
148
  priority_before_filter('ses_initialize_session')
146
- after_filter('ses_close_session')
149
+ priority_after_filter('ses_close_session')
147
150
  end
148
151
 
149
152
  def ses_initialize_session
150
- $session = Session.new($cgi)
153
+ $session = Session.new($app.cgi)
151
154
  end
152
155
  def ses_close_session
153
156
  $session.close
157
+ # $session = nil
154
158
  end
155
159
  end
156
160
 
@@ -18,6 +18,7 @@ class SessionPage
18
18
  @ses = session
19
19
  @ses[:SessionPage] ||= {}
20
20
  pagemem[pagekey] ||= {}
21
+ session.cgi.parameters.each_pair { |k,v| self[k] = v }
21
22
  expire
22
23
  end
23
24
 
@@ -1,4 +1,5 @@
1
1
  require 'cuca/stdlib/form'
2
+ require 'cuca/stdlib/formerrors'
2
3
  require 'cuca/generator/markaby'
3
4
 
4
5
  # == Form's for ActiveRecord
@@ -42,13 +43,22 @@ class ARFormWidget < FormWidget
42
43
  @form_erros = {}
43
44
  p = request_parameters.dup
44
45
  p.delete(@submit_name)
46
+
47
+ if @model.new_record? then
48
+ @disabled_on_create.each { |d| p.delete(d) }
49
+ @hidden_on_create.each { |d| p.delete(d) }
50
+ else
51
+ @disabled_on_update.each { |d| p.delete(d) }
52
+ @hidden_on_update.each { |d| p.delete(d) }
53
+ end
54
+
45
55
 
46
56
  # don't save empty passwords!!
47
57
  @password_fields ||= []
48
58
  @password_fields.each do |pwf|
49
59
  p.delete(pwf) if p[pwf].chomp.empty?
50
60
  end
51
-
61
+ $stderr.puts p.inspect
52
62
  @model.attributes = p
53
63
 
54
64
  return true if @model.valid?
@@ -187,6 +197,7 @@ end
187
197
  r << "<form action='#{@post_to}' method='POST'>\n"
188
198
  r << "<table>"
189
199
  @model.class.columns.each do |col|
200
+ next if field_hidden?(col.name)
190
201
  k = col.name
191
202
  v = @model.send(k.intern) # this allows us to overwrite accessors
192
203
  r << "<tr><td>#{k}</td><td>#{fe(col.type,k,v)}</td></tr>"
@@ -78,9 +78,10 @@ class DBListWidget < BaseList
78
78
  ret
79
79
  end
80
80
  findstuff[:select] = sel.compact.join(',')
81
- # $stderr.puts "Find-Stuff: #{findstuff.inspect}"
81
+ $stderr.puts "Find-Stuff: #{findstuff.inspect}"
82
82
  @data = @model_class.find(:all, findstuff)
83
83
  @data = normalize_result(@data)
84
+
84
85
  @total_rows= @model_class.count(:conditions => where_clause(query_def), :joins => @joins)
85
86
 
86
87
  # $stderr.puts "Query: #{@data.inspect} - #{query_def.order_by.inspect}"
@@ -154,6 +154,7 @@ end
154
154
  %>
155
155
  </td>
156
156
  <% end %>
157
+ <td></td>
157
158
 
158
159
  <form name="<%=@list_name%>_form" method="POST">
159
160
  <tr>
@@ -163,11 +164,11 @@ end
163
164
  <% if c[:searchable] != false then %>
164
165
  <input style='float:left;' type="text" name="<%=ftag%>" value="<%=@query_def.filters[c[:id]]%>" >
165
166
  <% end %>
166
- <% if (@columns.last[:id] == c[:id]) then %>
167
- <input style='float:right;' type="submit" value="ok">
168
- <% end %>
169
167
  </td>
170
- <% end %>
168
+ <% end %>
169
+
170
+ <td><input style='float:right;' type="submit" value="filter"></td>
171
+
171
172
  </tr>
172
173
  </form>
173
174
 
@@ -11,10 +11,12 @@ module Helpers
11
11
  # init the application. call this from the setup method.
12
12
  def init(app_path = '/', params = {})
13
13
  require 'cuca/cgi_emu'
14
- @app = Cuca::App.new(CGIEmu.new({'PATH_INFO' => app_path, 'QUERY_PARAMS' => params}))
14
+ @cgi = CGIEmu.new({'PATH_INFO' => app_path, 'QUERY_PARAMS' => params})
15
+ @app = Cuca::App.new(@cgi)
15
16
  @app.load_support_files
16
17
  end
17
18
 
19
+
18
20
  # this will create a widget instance with params and block
19
21
  # as passed to this function. Also it will pass current instance
20
22
  # variables to the assigns.
@@ -0,0 +1,324 @@
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
+