cuca 0.01

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/application_skeleton/README +21 -0
  2. data/application_skeleton/app/_controllers/application.rb +7 -0
  3. data/application_skeleton/app/_layouts/simple.rb +19 -0
  4. data/application_skeleton/app/_widgets/sourcecode.rb +21 -0
  5. data/application_skeleton/app/_widgets/test.rb +23 -0
  6. data/application_skeleton/app/demo.rb +64 -0
  7. data/application_skeleton/app/index.rb +39 -0
  8. data/application_skeleton/app/user/__default_username/index.rb +7 -0
  9. data/application_skeleton/conf/environment.rb +16 -0
  10. data/application_skeleton/log/access.log +1 -0
  11. data/application_skeleton/log/error.log +1 -0
  12. data/application_skeleton/log/messages +1 -0
  13. data/application_skeleton/public/css/style.css +27 -0
  14. data/application_skeleton/public/dispatch.cgi +31 -0
  15. data/application_skeleton/public/dispatch.fcgi +36 -0
  16. data/application_skeleton/public/img/cuca-seagull.png +0 -0
  17. data/application_skeleton/scripts/console +5 -0
  18. data/application_skeleton/scripts/console.rb +5 -0
  19. data/application_skeleton/scripts/server-lighttpd-fcgi.rb +116 -0
  20. data/application_skeleton/scripts/server-lighttpd.rb +109 -0
  21. data/application_skeleton/scripts/server-webrick.rb +26 -0
  22. data/application_skeleton/scripts/test.rb +8 -0
  23. data/application_skeleton/tests/widgets/link.rb +22 -0
  24. data/bin/cuca +43 -0
  25. data/lib/cuca/app.rb +317 -0
  26. data/lib/cuca/cgi_emu.rb +67 -0
  27. data/lib/cuca/cgi_fix.rb +58 -0
  28. data/lib/cuca/const.rb +3 -0
  29. data/lib/cuca/controller.rb +240 -0
  30. data/lib/cuca/generator/markaby.rb +80 -0
  31. data/lib/cuca/generator/view.rb +121 -0
  32. data/lib/cuca/layout.rb +62 -0
  33. data/lib/cuca/mimetypes.rb +89 -0
  34. data/lib/cuca/session.rb +143 -0
  35. data/lib/cuca/sessionflash.rb +56 -0
  36. data/lib/cuca/sessionpage.rb +41 -0
  37. data/lib/cuca/stdlib/arform.rb +208 -0
  38. data/lib/cuca/stdlib/arview.rb +16 -0
  39. data/lib/cuca/stdlib/form.rb +137 -0
  40. data/lib/cuca/stdlib/formerrors.rb +20 -0
  41. data/lib/cuca/stdlib/link.rb +37 -0
  42. data/lib/cuca/stdlib/list.rb +3 -0
  43. data/lib/cuca/stdlib/listwidget/dblist.rb +122 -0
  44. data/lib/cuca/stdlib/listwidget/list.rb +189 -0
  45. data/lib/cuca/stdlib/listwidget/querydef.rb +167 -0
  46. data/lib/cuca/stdlib/listwidget/staticdatalist.rb +79 -0
  47. data/lib/cuca/stdlib/slink.rb +30 -0
  48. data/lib/cuca/test/helpers.rb +42 -0
  49. data/lib/cuca/urlmap.rb +267 -0
  50. data/lib/cuca/widget.rb +212 -0
  51. data/lib/cuca.rb +68 -0
  52. metadata +141 -0
@@ -0,0 +1,189 @@
1
+
2
+ require 'cuca/generator/view'
3
+ require 'cuca/generator/markaby'
4
+ require 'cuca/stdlib/listwidget/querydef'
5
+ require 'cuca/stdlib/slink'
6
+
7
+ # this is the parent class for dblist and staticdatalist
8
+ class BaseList < Cuca::Widget
9
+ include Cuca::Generator::View
10
+ include Cuca::Generator::Markaby
11
+
12
+ attr_reader :data
13
+ attr_reader :rewrite_hooks
14
+
15
+
16
+ # Add a proc to rewrite content of a field
17
+ # proc must take two arguments, |row_content, field_content|
18
+ def add_rewrite_hook(field_id, &proc)
19
+ @rewrite_hooks||= {}
20
+ @rewrite_hooks[field_id] = proc
21
+ end
22
+
23
+ def rewrite_field(row, field_id, content)
24
+ # $stderr.puts "REwrite field(#{row.inspect}, #{field_id.inspect}, #{content.inspect} - hooks #{@rewrite_hooks.inspect}"
25
+ return content unless @rewrite_hooks[field_id]
26
+ return @rewrite_hooks[field_id].call(row, content)
27
+ end
28
+
29
+
30
+ # Use to initialize
31
+ #
32
+ def setup
33
+ end
34
+
35
+ # OVERWRITE
36
+ # return a list of columns
37
+ def columns
38
+ return [{:id=>"one", :display =>'One', :searchable=>false}, {:id=>'two', :display => 'three'}]
39
+ end
40
+
41
+ #OVERWRITE:
42
+ # fetch data and write:
43
+ # @data = [['a','b', 12], ...]
44
+ # @total_rows = 123
45
+ def query(query_definition)
46
+ return
47
+ end
48
+
49
+ # TODO: Load from Session
50
+ def load_query_definition
51
+ qd = QueryDef.new(@list_name)
52
+ qd.from_params(params)
53
+ end
54
+
55
+ def output(list_name)
56
+ @list_name = list_name
57
+
58
+ @columns = columns
59
+ @query_def = load_query_definition
60
+ query(@query_def)
61
+ @paginate = paginate_links()
62
+ @params = params
63
+ @rewrite_hooks ||= {}
64
+
65
+ callback_method = "#{@list_name}_data"
66
+
67
+ # $stderr.puts "Callback check: #{controller.nil?.inspect} \n\n -- #{controller.methods.sort.inspect} --\n\n NAME #{controller.class.inspect}"
68
+ if !controller.nil? && controller.methods.include?(callback_method)
69
+ controller.send(callback_method, @data)
70
+ end
71
+
72
+ view_p(erb_template)
73
+ end # def
74
+
75
+ private
76
+ def paginate_links()
77
+ @rows_per_page = (@query_def.range.last - @query_def.range.first) + 1
78
+ @total_pages = (@total_rows / @rows_per_page).to_i
79
+ @total_pages = @total_pages + 1 unless ((@total_rows % @rows_per_page) == 0)
80
+
81
+ pl = '' ; i = 0
82
+ (0..(@total_pages-1)).each do |p|
83
+ range = i..(i+@rows_per_page-1)
84
+ if range.include?(@query_def.range.first+1) then
85
+ pl<< "#{(p+1).to_s} "
86
+ else
87
+ pl << "#{SLinkWidget.new(:args=>['',(p+1).to_s,@query_def.to_h('range', range)]).to_s} "
88
+ end
89
+ i+=@rows_per_page
90
+ end
91
+
92
+ return pl
93
+
94
+ #### The above should be a bit faster that this mab version:
95
+ # return mabtext do
96
+ # i = 0
97
+ # (0..(@total_pages-1)).each do |p|
98
+ # range = i..(i+@rows_per_page-1)
99
+ # $stderr.puts "#{range.inspect} include? #{@query_def.range.first+1}"
100
+ # if range.include?(@query_def.range.first+1) then
101
+ # text((p+1).to_s + " ")
102
+ # else
103
+ # Link('', @query_def.to_h('range', range)) { ((p+1).to_s) }
104
+ # SLink('',(p+1).to_s, @query_def.to_h('range', range))
105
+ # text " "
106
+ # end
107
+ # i+=@rows_per_page
108
+ # end
109
+ # end
110
+ end
111
+
112
+ private
113
+ def erb_template
114
+ <<'ENDTEMPLATE'
115
+ <div class='list'>
116
+ <%= @paginate %>
117
+ <table width>
118
+ <tr>
119
+
120
+ <% @columns.each do |c| %>
121
+ <td class='hl'>
122
+ <%= (@query_def.order_by == c[:id] || (c[:sortable] == false)) ?
123
+ c[:display] : SLink('',c[:display],@query_def.to_h('order_by', c[:id]))
124
+ %>
125
+ </td>
126
+ <% end %>
127
+
128
+ <form name="<%=@list_name%>_form" method="POST">
129
+ <tr>
130
+ <% @columns.each do |c|
131
+ ftag = "#{@list_name}_filter_#{c[:id]}" %>
132
+ <td>
133
+ <% if c[:searchable] != false then %>
134
+ <input style='float:left;' type="text" name="<%=ftag%>" value="<%=@query_def.filters[c[:id]]%>" >
135
+ <% end %>
136
+ <% if (@columns.last[:id] == c[:id]) then %>
137
+ <input style='float:right;' type="submit" value="ok">
138
+ <% end %>
139
+ </td>
140
+ <% end %>
141
+ </tr>
142
+ </form>
143
+
144
+ <% @data.each do |row| %>
145
+ <tr>
146
+ <% row.each_index do |field_idx| %>
147
+ <td> <%= rewrite_field(row, @columns[field_idx][:id], row[field_idx]) %> </td>
148
+ <% end %>
149
+ </tr>
150
+ <% end %>
151
+ </table>
152
+ </div>
153
+ ENDTEMPLATE
154
+ end
155
+
156
+ end
157
+
158
+
159
+ # This would be a markaby template for the listwidget. I find it less readable so will not
160
+ # continue working on it.
161
+ #
162
+ #
163
+ # mab {
164
+ # div.list do
165
+ # text @paginate
166
+ # table do
167
+ # tr do
168
+ # @columns.each { |c| td { @query_def.order_by == c[:id] ? text(c[:display]) : Link('', @query_def.to_h('order_by',
169
+ # end
170
+ # form(:name=>"#{@list_name}_form", :method=>'POST') do
171
+ # tr do
172
+ # @columns.each { |c|
173
+ # td { @ftag = "#{@list_name}_filter_#{c[:id]}"
174
+ # input(:type => 'text', :name => @ftag, :value => @query_def.filters[c[:id]])
175
+ # input(:type=>'submit',:value=>'ok') if (@columns.last[:id] == c[:id])
176
+ # }
177
+ # }
178
+ # end
179
+ # end
180
+ # @data.each do |row|
181
+ # tr do
182
+ # row.each_index do |field_idx|
183
+ # td { text rewrite_field(row, @columns[field_idx][:id], row[field_idx]) }
184
+ # end
185
+ # end
186
+ # end # data.each
187
+ # end # table.do
188
+ # end # div.list
189
+ # } #mab
@@ -0,0 +1,167 @@
1
+
2
+ # QueryDef is a settings class that hold the settings for the query for listwidget
3
+ #
4
+ # FIXME: Change name or put into namespace
5
+ class QueryDef
6
+ ATTRIBS = ['order_by','range', 'filters']
7
+ ATTRIBS_ENCODE =
8
+ {
9
+ 'range' =>
10
+ Proc.new do |e|
11
+ "#{e.first}-#{e.last}"
12
+ end,
13
+ 'filters' =>
14
+ Proc.new do |e|
15
+ s = '';
16
+ e.each_pair { |k,v| s << "#{k}:#{v};" };
17
+ s
18
+ end
19
+ }
20
+ ATTRIBS_DECODE =
21
+ {
22
+ 'range' =>
23
+ Proc.new do |e|
24
+ Range.new(e.split('-')[0].to_i,e.split('-')[1].to_i)
25
+ end,
26
+ 'filters' =>
27
+ Proc.new do |e|
28
+ h = {}
29
+ e.split(';').each do |p|
30
+ vals = p.split(':')
31
+ h[vals[0]] = vals[1] if (vals.size == 2)
32
+ end
33
+ h
34
+ end
35
+ }
36
+ ATTRIBS_DEFAULTS = { 'range' => 0..9,
37
+ 'order_by' => '',
38
+ 'filters' => {} }
39
+
40
+ # take from CGI class
41
+ def escape(string)
42
+ string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
43
+ '%' + $1.unpack('H2' * $1.size).join('%').upcase
44
+ end.tr(' ', '+')
45
+ end
46
+ def unescape(string)
47
+ string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do
48
+ [$1.delete('%')].pack('H*')
49
+ end
50
+ end
51
+
52
+ def method_missing(m, *params)
53
+ met = m.id2name
54
+
55
+ #getter
56
+ if (ATTRIBS.include?(met)) then
57
+ return @data[met] || ATTRIBS_DEFAULT[met].dup
58
+ end
59
+
60
+ #setter
61
+ raise NoMethodError if met[met.size-1].chr != '='
62
+ raise NoMethodError if params.size != 1
63
+ met = met[0..met.size-2] # cut '='
64
+ if ATTRIBS.include?(met) then
65
+ @data[met] = params[0]
66
+ else
67
+ raise NoMethodError
68
+ end
69
+ end
70
+
71
+ # value enc/dec
72
+ def ev_enc(name)
73
+ # $stderr.puts "env_enc(#{name}) #{@data.inspect}"
74
+ if ATTRIBS_ENCODE.has_key?(name) then
75
+ ATTRIBS_ENCODE[name].call(@data[name] || '')
76
+ else
77
+ @data[name]
78
+ end
79
+ end
80
+
81
+ def ev_dec(name, value)
82
+ if ATTRIBS_DECODE.has_key?(name) then
83
+ # $stderr.puts "ev_dec #{name} #{value}"
84
+ begin
85
+ return ATTRIBS_DECODE[name].call(value)
86
+ rescue
87
+ # $stderr.puts "Decoding failed: #{name} - #{value}: #{$!}"
88
+ return ATTRIBS_DEFAULTS[name].dup
89
+ end
90
+ else
91
+ return value
92
+ end
93
+ end
94
+
95
+ # attribute-name enc/dec
96
+ def at_enc(name)
97
+ "#{@list_name}_#{name}"
98
+ end
99
+
100
+ def at_dec(name)
101
+ name[@list_name.size..@name.size-1]
102
+ end
103
+
104
+ # returns an hash with the values and escaped names and attributes
105
+ # attr and newval with swap a value for this return without changing the actual data
106
+ def to_h(attr=nil, newval=nil)
107
+ if attr then
108
+ @backup = @data.dup
109
+ @data[attr] = newval
110
+ end
111
+
112
+ u = {}
113
+ ATTRIBS.each do |a|
114
+ # $stderr.puts "Encoding: #{a} - #{@data[a]}"
115
+ u[at_enc(a)] = escape(ev_enc(a) || '')
116
+ end
117
+
118
+ if attr then @data = @backup end
119
+
120
+ return u
121
+ end
122
+
123
+ def from_params(params)
124
+ # $stderr.puts "CGI PARAMS: #{$cgi.params.inspect}"
125
+ # $stderr.puts "*** From Params\n #{params.inspect}\n"
126
+ # $stderr.puts "*** DEFAULT ATTR: #{ATTRIBS_DEFAULTS.inspect}\n"
127
+ ATTRIBS.each do |a|
128
+ # $stderr.puts "Checking: #{at_enc(a)} = #{params[at_enc(a)][0]}"
129
+ v = params[at_enc(a)]
130
+ if v then
131
+ @data[a] = ev_dec(a,v)
132
+ else
133
+ @data[a] = ATTRIBS_DEFAULTS[a].dup
134
+ end
135
+ # $stderr.puts "\n*** ENDFROM_PARAMS: #{@data.inspect}"
136
+ end
137
+
138
+ # checking on filters that come by post
139
+ # $stderr.puts "PARAMS: #{params.inspect}"
140
+ params.each_pair do |p,v|
141
+ if p.include?("#{@list_name}_filter_") then
142
+ @data['filters'] ||= {}
143
+ fname = p.scan(/\_filter\_(.*)/)[0][0]
144
+ fdata = v
145
+ @data['filters'][fname] = fdata
146
+ # $stderr.puts "Filter update: #{@data['filters'].inspect}"
147
+ end
148
+ end
149
+
150
+
151
+ # $stderr.puts @data.to_yaml
152
+ return self
153
+ end
154
+
155
+ def initialize(list_name)
156
+ @list_name = list_name
157
+ @data = {}
158
+ end
159
+ end
160
+
161
+ # qr = QueryDef.new("my_list")
162
+ # qr.order_by = 'firstname'
163
+ # qr.range = 100..200
164
+ #
165
+ # qr.filters = {'firstname' => 'martin', 'lastname' => 'boese' }
166
+ # puts qr.to_url
167
+
@@ -0,0 +1,79 @@
1
+ require 'cuca/stdlib/listwidget/list'
2
+
3
+
4
+ # Displays data from memory
5
+ #
6
+ # Example:
7
+ #
8
+ # StaticDataList('list_name',
9
+ # :columns => [ { :id => 'id', :display=>'ID' },
10
+ # { :id => 'name', :display=>'Name' } ],
11
+ # :data => [[ 1, 'Jack'],
12
+ # [ 2, 'Elvis'],
13
+ # [ 3, 'Alice']])
14
+ class StaticDataListWidget < BaseList
15
+ def setup
16
+ super
17
+ end
18
+
19
+ def output(list_name = "noname", data_setup = {})
20
+ @sd_columns = data_setup[:columns] || []
21
+ @sd_data = data_setup[:data] || []
22
+ @list_name = list_name
23
+ setup
24
+ @sd_columns.freeze
25
+ @sd_data.freeze
26
+ super(@list_name)
27
+ end
28
+
29
+ def columns
30
+ return @sd_columns
31
+ end
32
+
33
+ def filter(data, column_name, value)
34
+ cidx = col_idx_by_id(column_name)
35
+ return data if cidx.nil?
36
+ return data if value.strip.empty?
37
+
38
+ new_data = []
39
+ data.each_index do |didx|
40
+ if data[didx][cidx].instance_of?(String) then
41
+ # $stderr.puts "Filter: #{@data[didx][cidx]} on #{value}"
42
+ new_data << data[didx] if data[didx][cidx].include?(value)
43
+ # $stderr.puts @new_data.inspect
44
+ end
45
+ end
46
+ # $stderr.puts "Filter done(#{column_name}, #{value}): #{new_data.inspect}"
47
+ return new_data
48
+ end
49
+
50
+ def apply_filters(query_def)
51
+ query_def.filters.each_pair do |k,v|
52
+ @data = filter(@data, k,v)
53
+ end
54
+ # $stderr.puts "Done filtering: #{@data.inspect}"
55
+ end
56
+
57
+
58
+
59
+ def query(query_def)
60
+ cidx = col_idx_by_id(query_def.order_by) || 0
61
+
62
+ @data = @sd_data.sort { |a,b| a[cidx] <=> b[cidx] }
63
+ apply_filters(query_def)
64
+ @total_rows = @data.size
65
+ @data = @data[query_def.range]
66
+
67
+ end
68
+
69
+ def col_idx_by_id(col)
70
+ @sd_columns.each_index do |idx|
71
+ if @sd_columns[idx][:id] == col then
72
+ return idx
73
+ end
74
+ end
75
+ return nil
76
+ end
77
+
78
+ end
79
+
@@ -0,0 +1,30 @@
1
+ # Simple, fast link - no markaby as block
2
+
3
+ class SLinkWidget < Cuca::Widget
4
+ private
5
+ def build_href(target, params)
6
+ r = target
7
+
8
+ r=r+"?" unless params.empty?
9
+
10
+ params.each_key do |key|
11
+ r = r + '&' unless r[r.size-1].chr == '?'
12
+ r = "#{r}#{key}=#{params[key]}"
13
+ end
14
+ return r
15
+ end
16
+
17
+
18
+ public
19
+ def output(target, text = nil, params = {}, tag_attrib = {})
20
+ @attribs = tag_attrib
21
+ @attribs[:href] = build_href(target, params)
22
+
23
+ @_content = "<a "
24
+ @attribs.each_pair do |k,v|
25
+ @_content << "#{k}='#{v}'"
26
+ end
27
+ @_content << ">#{text || target}</a>"
28
+
29
+ end
30
+ end
@@ -0,0 +1,42 @@
1
+
2
+ require 'test/unit'
3
+
4
+ module Cuca
5
+ module Test
6
+
7
+ # Some function that should help you testing your widgets and controllers
8
+ module Helpers
9
+
10
+
11
+ # init the application. call this from the setup method.
12
+ def init(app_path = '/', params = {})
13
+ require 'cuca/cgi_emu'
14
+ @app = Cuca::App.new(CGIEmu.new({'PATH_INFO' => app_path, 'QUERY_PARAMS' => params}))
15
+ @app.load_support_files
16
+ end
17
+
18
+ # this will create a widget instance with params and block
19
+ # as passed to this function. Also it will pass current instance
20
+ # variables to the assigns.
21
+ def widget(widget_class, *args, &block)
22
+ a = {}
23
+ instance_variables.each do |v|
24
+ a[v.gsub(/\@/,'')] = self.instance_variable_get(v)
25
+ end
26
+ return widget_class.new({:assigns => a, :args => args}, &block)
27
+ end
28
+
29
+ # same as above but enable the profiler to stdout
30
+ def widget_p(widget_class, *args, &block)
31
+ a = {}
32
+ instance_variables.each do |v|
33
+ a[v.gsub(/\@/,'')] = self.instance_variable_get(v)
34
+ end
35
+ return widget_class.new({:assigns => a, :args => args, :profiler => $stdout}, &block)
36
+ end
37
+
38
+
39
+ end
40
+ end
41
+ end
42
+