cuca 0.03 → 0.04

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.
@@ -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
+