cuca 0.01

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