rbcurse 0.1.0

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 (55) hide show
  1. data/CHANGELOG +1570 -0
  2. data/History.txt +6 -0
  3. data/Manifest.txt +54 -0
  4. data/README.txt +304 -0
  5. data/Rakefile +28 -0
  6. data/examples/qdfilechooser.rb +68 -0
  7. data/examples/rfe.rb +853 -0
  8. data/examples/rfe_renderer.rb +69 -0
  9. data/examples/test1.rb +242 -0
  10. data/examples/test2.rb +498 -0
  11. data/examples/testcombo.rb +95 -0
  12. data/examples/testkeypress.rb +61 -0
  13. data/examples/testmenu.rb +105 -0
  14. data/examples/testtable.rb +266 -0
  15. data/examples/testtabp.rb +106 -0
  16. data/examples/testtodo.rb +532 -0
  17. data/examples/viewtodo.rb +512 -0
  18. data/lib/rbcurse/action.rb +31 -0
  19. data/lib/rbcurse/applicationheader.rb +57 -0
  20. data/lib/rbcurse/celleditor.rb +120 -0
  21. data/lib/rbcurse/checkboxcellrenderer.rb +69 -0
  22. data/lib/rbcurse/colormap.rb +133 -0
  23. data/lib/rbcurse/comboboxcellrenderer.rb +45 -0
  24. data/lib/rbcurse/defaultlistselectionmodel.rb +49 -0
  25. data/lib/rbcurse/keylabelprinter.rb +143 -0
  26. data/lib/rbcurse/listcellrenderer.rb +99 -0
  27. data/lib/rbcurse/listkeys.rb +33 -0
  28. data/lib/rbcurse/listscrollable.rb +216 -0
  29. data/lib/rbcurse/listselectable.rb +67 -0
  30. data/lib/rbcurse/mapper.rb +108 -0
  31. data/lib/rbcurse/orderedhash.rb +77 -0
  32. data/lib/rbcurse/rcombo.rb +243 -0
  33. data/lib/rbcurse/rdialogs.rb +183 -0
  34. data/lib/rbcurse/rform.rb +845 -0
  35. data/lib/rbcurse/rinputdataevent.rb +36 -0
  36. data/lib/rbcurse/rlistbox.rb +804 -0
  37. data/lib/rbcurse/rmenu.rb +666 -0
  38. data/lib/rbcurse/rmessagebox.rb +325 -0
  39. data/lib/rbcurse/rpopupmenu.rb +754 -0
  40. data/lib/rbcurse/rtabbedpane.rb +259 -0
  41. data/lib/rbcurse/rtable.rb +1296 -0
  42. data/lib/rbcurse/rtextarea.rb +673 -0
  43. data/lib/rbcurse/rtextview.rb +335 -0
  44. data/lib/rbcurse/rwidget.rb +1731 -0
  45. data/lib/rbcurse/scrollable.rb +301 -0
  46. data/lib/rbcurse/selectable.rb +94 -0
  47. data/lib/rbcurse/table/tablecellrenderer.rb +85 -0
  48. data/lib/rbcurse/table/tabledatecellrenderer.rb +102 -0
  49. data/lib/rbcurse.rb +7 -0
  50. data/lib/ver/keyboard.rb +150 -0
  51. data/lib/ver/keyboard2.rb +170 -0
  52. data/lib/ver/ncurses.rb +102 -0
  53. data/lib/ver/window.rb +369 -0
  54. data/test/test_rbcurse.rb +0 -0
  55. metadata +118 -0
@@ -0,0 +1,105 @@
1
+ #$LOAD_PATH << "/Users/rahul/work/projects/rbcurse/"
2
+ # this program tests out various widgets.
3
+ require 'rubygems'
4
+ require 'ncurses'
5
+ require 'logger'
6
+ require 'rbcurse'
7
+ #require 'lib/rbcurse/rform'
8
+ require 'rbcurse/rpopupmenu'
9
+ if $0 == __FILE__
10
+ include RubyCurses
11
+
12
+ begin
13
+ # Initialize curses
14
+ VER::start_ncurses # this is initializing colors via ColorMap.setup
15
+ $log = Logger.new("view.log")
16
+ $log.level = Logger::DEBUG
17
+
18
+ @window = VER::Window.root_window
19
+ # Initialize few color pairs
20
+ # Create the window to be associated with the form
21
+ # Un post form and free the memory
22
+
23
+ catch(:close) do
24
+ colors = Ncurses.COLORS
25
+ $log.debug "START #{colors} colors #{$datacolor} ---------"
26
+ @form = Form.new @window
27
+ @form.window.printstring 0, 25, "Demo of Ruby Curses PopupMenu", $normalcolor, 'reverse'
28
+ r = 1; fc = 12;
29
+ row = 10; col = 10
30
+ colorlabel = Label.new @form, {'text' => "A label:", "row" => row, "col" => col, "color"=>"cyan", "mnemonic" => 'A'}
31
+
32
+ #@mb = RubyCurses::MenuBar.new
33
+ #filemenu = RubyCurses::Menu.new "File"
34
+ filemenu = RubyCurses::PopupMenu.new "File"
35
+ filemenu.add(item = RubyCurses::MenuItem.new("Open",'O'))
36
+
37
+ filemenu.insert_separator 1
38
+ filemenu.add(RubyCurses::MenuItem.new "New",'N')
39
+ filemenu.add(item = RubyCurses::MenuItem.new("Save",'S'))
40
+ filemenu.add(item = RubyCurses::MenuItem.new("Test",'T'))
41
+ filemenu.add(item = RubyCurses::MenuItem.new("Wrap Text",'W'))
42
+ filemenu.add(item = RubyCurses::MenuItem.new("Exit",'X'))
43
+ item.command() {
44
+ #throw(:menubarclose);
45
+ throw(:close)
46
+ }
47
+ item = RubyCurses::CheckBoxMenuItem.new "Reverse"
48
+ #filemenu.create_window
49
+ # item.onvalue="On"
50
+ # item.offvalue="Off"
51
+ #item.checkbox.text "Labelcb"
52
+ #item.text="Labelcb"
53
+ # in next line, an explicit repaint is required since label is on another form.
54
+ #item.command(colorlabel){|it, label| att = it.getvalue ? 'reverse' : nil; label.attr(att); label.repaint}
55
+
56
+
57
+ filemenu.add(item)
58
+ #@mb.add(filemenu)
59
+ editmenu = RubyCurses::Menu.new "Edit"
60
+ item = RubyCurses::MenuItem.new "Cut"
61
+ editmenu.add(item)
62
+ item.accelerator = "Ctrl-X"
63
+ item=RubyCurses::MenuItem.new "Copy"
64
+ editmenu.add(item)
65
+ item.accelerator = "Ctrl-C"
66
+ item=RubyCurses::MenuItem.new "Paste"
67
+ editmenu.add(item)
68
+ item.accelerator = "Ctrl-V"
69
+ #@mb.add(editmenu)
70
+ #@mb.add(
71
+ menu=RubyCurses::Menu.new("Others")
72
+ filemenu.add(menu)
73
+ #item=RubyCurses::MenuItem.new "Save","S"
74
+ item = RubyCurses::MenuItem.new "Config"
75
+ menu.add(item)
76
+ item = RubyCurses::MenuItem.new "Tables"
77
+ menu.add(item)
78
+ savemenu = RubyCurses::Menu.new "EditM"
79
+ item = RubyCurses::MenuItem.new "CutM"
80
+ savemenu.add(item)
81
+ item = RubyCurses::MenuItem.new "DeleteM"
82
+ savemenu.add(item)
83
+ item = RubyCurses::MenuItem.new "PasteM"
84
+ savemenu.add(item)
85
+ menu.add(savemenu)
86
+ # 2008-12-20 13:06 no longer hardcoding toggle key of menu_bar.
87
+ #@mb.toggle_key = KEY_F2
88
+ #@form.set_menu_bar @mb
89
+ #@cell = CellRenderer.new "Hello", {"col" => 1, "row"=>29, "justify"=>:right, "display_length" => 30}
90
+ # END
91
+ @form.repaint
92
+ filemenu.show colorlabel, 0,1
93
+ @window.wrefresh
94
+ Ncurses::Panel.update_panels
95
+ end
96
+ rescue => ex
97
+ ensure
98
+ @window.destroy if !@window.nil?
99
+ VER::stop_ncurses
100
+ p ex if ex
101
+ p(ex.backtrace.join("\n")) if ex
102
+ $log.debug( ex) if ex
103
+ $log.debug(ex.backtrace.join("\n")) if ex
104
+ end
105
+ end
@@ -0,0 +1,266 @@
1
+ #$LOAD_PATH << "/Users/rahul/work/projects/rbcurse/"
2
+ require 'rubygems'
3
+ require 'ncurses'
4
+ require 'logger'
5
+ #require 'ver/keyboard'
6
+ require 'rbcurse'
7
+ require 'rbcurse/rcombo'
8
+ require 'rbcurse/rtable'
9
+ require 'rbcurse/celleditor'
10
+ #require 'rbcurse/table/tablecellrenderer'
11
+ require 'rbcurse/comboboxcellrenderer'
12
+ require 'rbcurse/action'
13
+
14
+ ##
15
+ # a renderer which paints alternate lines with
16
+ # another color, for people with poor taste.
17
+ class MyRenderer < TableCellRenderer
18
+ def initialize text="", config={}, &block
19
+ super
20
+ @orig_bgcolor = @bgcolor
21
+ @orig_color = @color
22
+ end
23
+ def repaint graphic, r=@row,c=@col, value=@text, focussed=false, selected=false
24
+ @bgcolor = @orig_bgcolor
25
+ @color = @orig_color
26
+ if !focussed and !selected
27
+ @bgcolor = r % 2 == 0 ? "green" : @orig_bgcolor
28
+ @color = r % 2 == 0 ? "black" : @orig_color
29
+ end
30
+ super
31
+ end
32
+ end
33
+ if $0 == __FILE__
34
+ include RubyCurses
35
+ include RubyCurses::Utils
36
+
37
+ begin
38
+ # Initialize curses
39
+ VER::start_ncurses # this is initializing colors via ColorMap.setup
40
+ $log = Logger.new("view.log")
41
+ $log.level = Logger::DEBUG
42
+
43
+ @window = VER::Window.root_window
44
+
45
+ catch(:close) do
46
+ colors = Ncurses.COLORS
47
+ $log.debug "START #{colors} colors ---------"
48
+ @form = Form.new @window
49
+ @window.printstring 0,30,"Demo of Ruby Curses Table: Edit, Resize, Insert, Move, Delete Row/Col", $datacolor
50
+ r = 1; c = 30;
51
+ data = [["You're beautiful",3,"James Blunt",3.21, true, "WIP"],
52
+ ["Where are you",3,"London Beat",3.47, true, "WIP"],
53
+ ["I'll always love my mama",92,"Intruders",412, true, "Fin"],
54
+ ["I believe in love",4,"Paula Cole",110.0, false, "Cancel"],
55
+ ["Red Sky at night",4,"Dave Gilmour",102.72, false, "Postp"],
56
+ ["Midnight and you",8,"Barry White",12.72, false, "Todo"],
57
+ ["Let the music play",9,"Barry White",12.2, false, "WIP"],
58
+ ["I swear",nil,"Boyz II Men",112.7, true, "Cancel"],
59
+ ["Believe",9,"Elton John",12.2, false, "Todo"],
60
+ ["Private Dancer",9,"Tina Turner",12.2, false, "Todo"],
61
+ ["Liberian Girl",9,"Michael Jackson",12.2, false, "Todo"],
62
+ ["Like a prayer",163,"Charlotte Perrelli",5.4, false, "WIP"]]
63
+
64
+ colnames = %w[ Song Cat Artist Ratio Flag Status]
65
+ statuses = ["Todo", "WIP", "Fin", "Cancel", "Postp"]
66
+
67
+ texta = Table.new @form do
68
+ name "mytext"
69
+ row r
70
+ col c
71
+ width 78
72
+ height 15
73
+ #title "A Table"
74
+ #title_attrib (Ncurses::A_REVERSE | Ncurses::A_BOLD)
75
+ cell_editing_allowed true
76
+ editing_policy :EDITING_AUTO
77
+ set_data data, colnames
78
+ end
79
+ sel_col = Variable.new 0
80
+ sel_col.value = 0
81
+ tcm = texta.get_table_column_model
82
+ selcolname = texta.get_column_name sel_col.value
83
+ #
84
+ ## key bindings fo texta
85
+ # column widths
86
+ $log.debug " tcm #{tcm.inspect}"
87
+ $log.debug " tcms #{tcm.columns}"
88
+ $log.debug " tcm0 #{tcm.column(0).identifier}"
89
+ $log.debug " tcm0 #{tcm.column(0).width}"
90
+ tcm.column(0).width 24
91
+ tcm.column(1).width 5
92
+ tcm.column(2).width 18
93
+ #tcm.column(2).editable false
94
+ tcm.column(3).width 7
95
+ tcm.column(4).width 5
96
+ tcm.column(5).width 8
97
+ texta.configure() do
98
+ bind_key(330) { texta.remove_column(tcm.column(texta.focussed_col)) rescue "" }
99
+ bind_key(?+) {
100
+ acolumn = texta.get_column selcolname
101
+ w = acolumn.width + 1
102
+ acolumn.width w
103
+ #texta.table_structure_changed
104
+ }
105
+ bind_key(?-) {
106
+ acolumn = texta.get_column selcolname
107
+ w = acolumn.width - 1
108
+ if w > 3
109
+ acolumn.width w
110
+ #texta.table_structure_changed
111
+ end
112
+ }
113
+ bind_key(?>) {
114
+ colcount = tcm.column_count-1
115
+ #texta.move_column sel_col.value, sel_col.value+1 unless sel_col.value == colcount
116
+ col = texta.focussed_col
117
+ texta.move_column col, col+1 unless col == colcount
118
+ }
119
+ bind_key(?<) {
120
+ col = texta.focussed_col
121
+ texta.move_column col, col-1 unless col == 0
122
+ #texta.move_column sel_col.value, sel_col.value-1 unless sel_col.value == 0
123
+ }
124
+ #bind_key(KEY_RIGHT) { sel_col.value = sel_col.value+1; current_column sel_col.value}
125
+ #bind_key(KEY_LEFT) { sel_col.value = sel_col.value-1;current_column sel_col.value}
126
+ end
127
+ keylabel = RubyCurses::Label.new @form, {'text' => "", "row" => r+16, "col" => c, "color" => "yellow", "bgcolor"=>"blue", "display_length"=>60, "height"=>2}
128
+ eventlabel = RubyCurses::Label.new @form, {'text' => "Events:", "row" => r+19, "col" => c, "color" => "white", "bgcolor"=>"blue", "display_length"=>60, "height"=>2}
129
+
130
+ # report some events
131
+ texta.table_model.bind(:TABLE_MODEL_EVENT){|e| eventlabel.text = "Event: #{e}"}
132
+ texta.get_table_column_model.bind(:TABLE_COLUMN_MODEL_EVENT){|e| eventlabel.text = "Event: #{e}"}
133
+ texta.bind(:TABLE_TRAVERSAL_EVENT){|e| eventlabel.text = "Event: #{e}"}
134
+
135
+ @help = "C-q to quit. M-Tab (next col) C-n (Pg Dn), C-p (Pg Up), M-0 Top, M-9 End, C-x (select). Columns:- Narrow, + expand, > < switch"
136
+ RubyCurses::Label.new @form, {'text' => @help, "row" => Ncurses.LINES-3, "col" => 2, "color" => "yellow", "height"=>2}
137
+
138
+ str_renderer = TableCellRenderer.new ""
139
+ num_renderer = TableCellRenderer.new "", { "justify" => :right }
140
+ bool_renderer = CheckBoxCellRenderer.new "", {"parent" => texta, "display_length"=>5}
141
+ combo_renderer = RubyCurses::ComboBoxCellRenderer.new nil, {"parent" => texta, "display_length"=> 8}
142
+ combo_editor = RubyCurses::CellEditor.new(RubyCurses::ComboBox.new nil, {"focusable"=>false, "visible"=>false, "list"=>statuses, "display_length"=>8})
143
+ texta.set_default_cell_renderer_for_class "String", str_renderer
144
+ texta.set_default_cell_renderer_for_class "Fixnum", num_renderer
145
+ texta.set_default_cell_renderer_for_class "Float", num_renderer
146
+ texta.set_default_cell_renderer_for_class "TrueClass", bool_renderer
147
+ texta.set_default_cell_renderer_for_class "FalseClass", bool_renderer
148
+ texta.get_table_column_model.column(5).cell_editor = combo_editor
149
+ =begin
150
+ field = Field.new @form do
151
+ name "value"
152
+ row r+18
153
+ col c
154
+ display_length 30
155
+ bgcolor "cyan"
156
+ set_label Label.new @form, {'text' => "Value", 'mnemonic'=> 'V'}
157
+ # bind :ENTER do $editing = true end
158
+ # bind :LEAVE do $editing = false end
159
+ end
160
+ =end
161
+ buttrow = r+21 #Ncurses.LINES-4
162
+ b_newrow = Button.new @form do
163
+ text "&New"
164
+ row buttrow
165
+ col c
166
+ bind(:ENTER) { eventlabel.text "New button adds a new row at the bottom " }
167
+ end
168
+ tm = texta.table_model
169
+ b_newrow.command {
170
+ cc = texta.get_table_column_model.column_count
171
+ # need to get datatypes etc, this is just a junk test
172
+ tmp=[]
173
+ #0.upto(cc-1) { tmp << "" }
174
+ 0.upto(cc-1) { tmp << nil }
175
+ tm << tmp
176
+ #texta.table_data_changed
177
+ keylabel.text = "Added a row"
178
+ alert("Added a row at bottom of table")
179
+
180
+ }
181
+
182
+ # using ampersand to set mnemonic
183
+ b_delrow = Button.new @form do
184
+ text "&Delete"
185
+ row buttrow
186
+ col c+10
187
+ bind(:ENTER) { eventlabel.text "Deletes focussed row" }
188
+ end
189
+ b_delrow.command { |form|
190
+ row = texta.focussed_row
191
+ if confirm("Do your really want to delete row #{row}?")== :YES
192
+ tm.delete_at row
193
+ #texta.table_data_changed
194
+ else
195
+ #$message.value = "Quit aborted"
196
+ end
197
+ }
198
+ b_change = Button.new @form do
199
+ text "&Lock"
200
+ row buttrow
201
+ col c+20
202
+ command {
203
+ r = texta.focussed_row
204
+ c = sel_col.value
205
+ #$log.debug " Update gets #{field.getvalue.class}"
206
+ #texta.set_value_at(r, c, field.getvalue)
207
+ toggle = texta.column(texta.focussed_col()).editable
208
+ if toggle.nil? or toggle==true
209
+ toggle = false
210
+ text "Un&lock"
211
+ else
212
+ toggle = true
213
+ text "&Lock "
214
+ end
215
+ eventlabel.text "Set column #{texta.focussed_col()} editable to #{toggle}"
216
+ texta.column(texta.focussed_col()).editable toggle
217
+ alert("Set column #{texta.focussed_col()} editable to #{toggle}")
218
+ }
219
+ bind(:ENTER) { eventlabel.text "Toggles editable state of current column " }
220
+ end
221
+ b_insert = Button.new @form do
222
+ text "&Insert"
223
+ row buttrow
224
+ col c+32
225
+ command {
226
+ # this does not trigger a data change since we are not updating model. so update
227
+ # on pressing up or down
228
+ #0.upto(100) { |i| data << ["test", rand(100), "abc:#{i}", rand(100)/2.0]}
229
+ #texta.table_data_changed
230
+ }
231
+ bind(:ENTER) { eventlabel.text "Does nothing " }
232
+ end
233
+
234
+
235
+ @form.repaint
236
+ @window.wrefresh
237
+ Ncurses::Panel.update_panels
238
+ while((ch = @window.getchar()) != ?\C-q )
239
+ colcount = tcm.column_count-1
240
+ s = keycode_tos ch
241
+ keylabel.text = "Pressed #{ch} , #{s}"
242
+ @form.handle_key(ch)
243
+
244
+ sel_col.value = tcm.column_count-1 if sel_col.value > tcm.column_count-1
245
+ sel_col.value = 0 if sel_col.value < 0
246
+ selcolname = texta.get_column_name sel_col.value
247
+ keylabel.text = "Pressed #{ch} , #{s}. Column selected #{texta.focussed_col}: Width:#{tcm.column(sel_col.value).width} #{selcolname}. Focussed Row: #{texta.focussed_row}, Rows: #{texta.table_model.row_count}, Cols: #{colcount}"
248
+ s = texta.get_value_at(texta.focussed_row, texta.focussed_col)
249
+ #s = s.to_s
250
+ ## $log.debug " updating Field #{s}, #{s.class}"
251
+ ## field.set_buffer s unless field.state == :HIGHLIGHTED # $editing
252
+
253
+ @form.repaint
254
+ @window.wrefresh
255
+ end
256
+ end
257
+ rescue => ex
258
+ ensure
259
+ @window.destroy if !@window.nil?
260
+ VER::stop_ncurses
261
+ p ex if ex
262
+ p(ex.backtrace.join("\n")) if ex
263
+ $log.debug( ex) if ex
264
+ $log.debug(ex.backtrace.join("\n")) if ex
265
+ end
266
+ end
@@ -0,0 +1,106 @@
1
+ # this is a test program, tests out tabbed panes. type F1 to exit
2
+ #
3
+ #$LOAD_PATH << "/Users/rahul/work/projects/rbcurse/"
4
+ require 'rubygems'
5
+ require 'ncurses'
6
+ require 'logger'
7
+ require 'rbcurse'
8
+ require 'rbcurse/rtabbedpane'
9
+
10
+ class TestTabbedPane
11
+ def initialize
12
+ acolor = $reversecolor
13
+ #$config_hash ||= {}
14
+ end
15
+ def run
16
+ $config_hash ||= Variable.new Hash.new
17
+ #configvar.update_command(){ |v| $config_hash[v.source()] = v.value }
18
+ @tp = RubyCurses::TabbedPane.new nil do
19
+ height 12
20
+ width 50
21
+ row 5
22
+ col 10
23
+ end
24
+ @tab1 = @tp.add_tab "&Language"
25
+ f1 = @tab1.form
26
+ #$radio = Variable.new
27
+ radio1 = RadioButton.new f1 do
28
+ #variable $radio
29
+ variable $config_hash
30
+ name "radio1"
31
+ text "ruby"
32
+ value "ruby"
33
+ color "red"
34
+ row 4
35
+ col 2
36
+ end
37
+ radio2 = RadioButton.new f1 do
38
+ #variable $radio
39
+ variable $config_hash
40
+ name "radio1"
41
+ text "jruby"
42
+ value "jruby"
43
+ color "green"
44
+ row 5
45
+ col 2
46
+ end
47
+ radio3 = RadioButton.new f1 do
48
+ #variable $radio
49
+ variable $config_hash
50
+ name "radio1"
51
+ text "macruby"
52
+ value "macruby"
53
+ color "cyan"
54
+ row 6
55
+ col 2
56
+ end
57
+ @tab2 = @tp.add_tab "&Settings"
58
+ f2 = @tab2.form
59
+ r = 3
60
+ butts = [ "Use &HTTP/1.0", "Use &frames", "&Use SSL" ]
61
+ bcodes = %w[ HTTP, FRAMES, SSL ]
62
+ butts.each_with_index do |t, i|
63
+ RubyCurses::CheckBox.new f2 do
64
+ text butts[i]
65
+ variable $config_hash
66
+ name bcodes[i]
67
+ row r+i
68
+ col 4
69
+ end
70
+ end
71
+ @tab3 = @tp.add_tab "&Editors"
72
+ f3 = @tab3.form
73
+ butts = %w[ &Vim E&macs &Jed &Other ]
74
+ bcodes = %w[ VIM EMACS JED OTHER]
75
+ row = 3
76
+ butts.each_with_index do |name, i|
77
+ RubyCurses::CheckBox.new f3 do
78
+ text name
79
+ variable $config_hash
80
+ name bcodes[i]
81
+ row row
82
+ col 4
83
+ end
84
+ row +=1
85
+ end
86
+ @tp.show
87
+ @tp.handle_keys
88
+ end
89
+ end
90
+ if $0 == __FILE__
91
+ # Initialize curses
92
+ begin
93
+ # XXX update with new color and kb
94
+ VER::start_ncurses # this is initializing colors via ColorMap.setup
95
+ $log = Logger.new("view.log")
96
+ $log.level = Logger::DEBUG
97
+ n = TestTabbedPane.new
98
+ rescue => ex
99
+ ensure
100
+ VER::stop_ncurses
101
+ p ex if ex
102
+ p(ex.backtrace.join("\n")) if ex
103
+ $log.debug( ex) if ex
104
+ $log.debug(ex.backtrace.join("\n")) if ex
105
+ end
106
+ end