treetop 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. data/README +3 -0
  2. data/Rakefile +35 -0
  3. data/bin/tt +25 -0
  4. data/lib/treetop.rb +10 -6
  5. data/lib/treetop/compiler.rb +7 -0
  6. data/lib/treetop/compiler/grammar_compiler.rb +21 -0
  7. data/lib/treetop/compiler/lexical_address_space.rb +17 -0
  8. data/lib/treetop/compiler/load_grammar.rb +7 -0
  9. data/lib/treetop/compiler/metagrammar.rb +2441 -0
  10. data/lib/treetop/compiler/metagrammar.treetop +384 -0
  11. data/lib/treetop/compiler/node_classes.rb +18 -0
  12. data/lib/treetop/compiler/node_classes/anything_symbol.rb +10 -0
  13. data/lib/treetop/compiler/node_classes/atomic_expression.rb +9 -0
  14. data/lib/treetop/compiler/node_classes/character_class.rb +10 -0
  15. data/lib/treetop/compiler/node_classes/choice.rb +31 -0
  16. data/lib/treetop/compiler/node_classes/declaration_sequence.rb +24 -0
  17. data/lib/treetop/compiler/node_classes/grammar.rb +28 -0
  18. data/lib/treetop/compiler/node_classes/inline_module.rb +27 -0
  19. data/lib/treetop/compiler/node_classes/nonterminal.rb +11 -0
  20. data/lib/treetop/compiler/node_classes/optional.rb +19 -0
  21. data/lib/treetop/compiler/node_classes/parenthesized_expression.rb +9 -0
  22. data/lib/treetop/compiler/node_classes/parsing_expression.rb +132 -0
  23. data/lib/treetop/compiler/node_classes/parsing_rule.rb +55 -0
  24. data/lib/treetop/compiler/node_classes/predicate.rb +45 -0
  25. data/lib/treetop/compiler/node_classes/repetition.rb +56 -0
  26. data/lib/treetop/compiler/node_classes/sequence.rb +64 -0
  27. data/lib/treetop/compiler/node_classes/terminal.rb +10 -0
  28. data/lib/treetop/compiler/node_classes/treetop_file.rb +9 -0
  29. data/lib/treetop/compiler/ruby_builder.rb +109 -0
  30. data/lib/treetop/ruby_extensions.rb +2 -0
  31. data/lib/treetop/ruby_extensions/string.rb +19 -0
  32. data/lib/treetop/runtime.rb +9 -0
  33. data/lib/treetop/runtime/compiled_parser.rb +66 -0
  34. data/lib/treetop/runtime/node_cache.rb +27 -0
  35. data/lib/treetop/runtime/parse_cache.rb +19 -0
  36. data/lib/treetop/runtime/parse_failure.rb +32 -0
  37. data/lib/treetop/runtime/parse_result.rb +30 -0
  38. data/lib/treetop/runtime/syntax_node.rb +53 -0
  39. data/lib/treetop/runtime/terminal_parse_failure.rb +33 -0
  40. data/lib/treetop/runtime/terminal_syntax_node.rb +12 -0
  41. data/test/compilation_target/target.rb +143 -0
  42. data/test/compilation_target/target.treetop +15 -0
  43. data/test/compilation_target/target_test.rb +56 -0
  44. data/test/compiler/and_predicate_test.rb +33 -0
  45. data/test/compiler/anything_symbol_test.rb +24 -0
  46. data/test/compiler/character_class_test.rb +45 -0
  47. data/test/compiler/choice_test.rb +49 -0
  48. data/test/compiler/circular_compilation_test.rb +20 -0
  49. data/test/compiler/failure_propagation_functional_test.rb +20 -0
  50. data/test/compiler/grammar_compiler_test.rb +58 -0
  51. data/test/compiler/grammar_test.rb +33 -0
  52. data/test/compiler/nonterminal_symbol_test.rb +15 -0
  53. data/test/compiler/not_predicate_test.rb +35 -0
  54. data/test/compiler/one_or_more_test.rb +30 -0
  55. data/test/compiler/optional_test.rb +32 -0
  56. data/test/compiler/parsing_rule_test.rb +30 -0
  57. data/test/compiler/sequence_test.rb +68 -0
  58. data/test/compiler/terminal_symbol_test.rb +35 -0
  59. data/test/compiler/test_grammar.treetop +7 -0
  60. data/test/compiler/zero_or_more_test.rb +51 -0
  61. data/test/composition/a.treetop +11 -0
  62. data/test/composition/b.treetop +11 -0
  63. data/test/composition/c.treetop +10 -0
  64. data/test/composition/d.treetop +10 -0
  65. data/test/composition/grammar_composition_test.rb +23 -0
  66. data/test/parser/syntax_node_test.rb +53 -0
  67. data/test/parser/terminal_parse_failure_test.rb +22 -0
  68. data/test/ruby_extensions/string_test.rb +33 -0
  69. data/test/screw/Rakefile +16 -0
  70. data/test/screw/unit.rb +37 -0
  71. data/test/screw/unit/assertion_failed_error.rb +14 -0
  72. data/test/screw/unit/assertions.rb +615 -0
  73. data/test/screw/unit/auto_runner.rb +227 -0
  74. data/test/screw/unit/collector.rb +45 -0
  75. data/test/screw/unit/collector/dir.rb +107 -0
  76. data/test/screw/unit/collector/objectspace.rb +28 -0
  77. data/test/screw/unit/error.rb +48 -0
  78. data/test/screw/unit/failure.rb +45 -0
  79. data/test/screw/unit/sugar.rb +25 -0
  80. data/test/screw/unit/test_case.rb +176 -0
  81. data/test/screw/unit/test_result.rb +73 -0
  82. data/test/screw/unit/test_suite.rb +70 -0
  83. data/test/screw/unit/ui.rb +4 -0
  84. data/test/screw/unit/ui/console/test_runner.rb +118 -0
  85. data/test/screw/unit/ui/fox/test_runner.rb +268 -0
  86. data/test/screw/unit/ui/gtk/test_runner.rb +416 -0
  87. data/test/screw/unit/ui/gtk2/testrunner.rb +465 -0
  88. data/test/screw/unit/ui/test_runner_mediator.rb +58 -0
  89. data/test/screw/unit/ui/test_runner_utilities.rb +46 -0
  90. data/test/screw/unit/ui/tk/test_runner.rb +260 -0
  91. data/test/screw/unit/util.rb +4 -0
  92. data/test/screw/unit/util/backtrace_filter.rb +40 -0
  93. data/test/screw/unit/util/observable.rb +82 -0
  94. data/test/screw/unit/util/proc_wrapper.rb +48 -0
  95. data/test/test_helper.rb +89 -0
  96. metadata +127 -69
  97. data/lib/treetop/api.rb +0 -3
  98. data/lib/treetop/api/load_grammar.rb +0 -16
  99. data/lib/treetop/api/malformed_grammar_exception.rb +0 -9
  100. data/lib/treetop/grammar.rb +0 -7
  101. data/lib/treetop/grammar/grammar.rb +0 -48
  102. data/lib/treetop/grammar/grammar_builder.rb +0 -35
  103. data/lib/treetop/grammar/parsing_expression_builder.rb +0 -5
  104. data/lib/treetop/grammar/parsing_expression_builder_helper.rb +0 -121
  105. data/lib/treetop/grammar/parsing_expressions.rb +0 -18
  106. data/lib/treetop/grammar/parsing_expressions/and_predicate.rb +0 -17
  107. data/lib/treetop/grammar/parsing_expressions/anything_symbol.rb +0 -20
  108. data/lib/treetop/grammar/parsing_expressions/character_class.rb +0 -24
  109. data/lib/treetop/grammar/parsing_expressions/node_instantiating_parsing_expression.rb +0 -14
  110. data/lib/treetop/grammar/parsing_expressions/node_propagating_parsing_expression.rb +0 -4
  111. data/lib/treetop/grammar/parsing_expressions/nonterminal_symbol.rb +0 -42
  112. data/lib/treetop/grammar/parsing_expressions/not_predicate.rb +0 -18
  113. data/lib/treetop/grammar/parsing_expressions/one_or_more.rb +0 -12
  114. data/lib/treetop/grammar/parsing_expressions/optional.rb +0 -14
  115. data/lib/treetop/grammar/parsing_expressions/ordered_choice.rb +0 -27
  116. data/lib/treetop/grammar/parsing_expressions/parsing_expression.rb +0 -36
  117. data/lib/treetop/grammar/parsing_expressions/predicate.rb +0 -25
  118. data/lib/treetop/grammar/parsing_expressions/repeating_parsing_expression.rb +0 -29
  119. data/lib/treetop/grammar/parsing_expressions/sequence.rb +0 -41
  120. data/lib/treetop/grammar/parsing_expressions/terminal_parsing_expression.rb +0 -11
  121. data/lib/treetop/grammar/parsing_expressions/terminal_symbol.rb +0 -31
  122. data/lib/treetop/grammar/parsing_expressions/zero_or_more.rb +0 -11
  123. data/lib/treetop/grammar/parsing_rule.rb +0 -10
  124. data/lib/treetop/metagrammar.rb +0 -2
  125. data/lib/treetop/metagrammar/metagrammar.rb +0 -14
  126. data/lib/treetop/metagrammar/metagrammar.treetop +0 -320
  127. data/lib/treetop/parser.rb +0 -11
  128. data/lib/treetop/parser/node_cache.rb +0 -25
  129. data/lib/treetop/parser/parse_cache.rb +0 -17
  130. data/lib/treetop/parser/parse_failure.rb +0 -22
  131. data/lib/treetop/parser/parse_result.rb +0 -26
  132. data/lib/treetop/parser/parser.rb +0 -24
  133. data/lib/treetop/parser/sequence_syntax_node.rb +0 -14
  134. data/lib/treetop/parser/syntax_node.rb +0 -31
  135. data/lib/treetop/parser/terminal_parse_failure.rb +0 -18
  136. data/lib/treetop/parser/terminal_syntax_node.rb +0 -7
  137. data/lib/treetop/protometagrammar.rb +0 -16
  138. data/lib/treetop/protometagrammar/anything_symbol_expression_builder.rb +0 -13
  139. data/lib/treetop/protometagrammar/block_expression_builder.rb +0 -17
  140. data/lib/treetop/protometagrammar/character_class_expression_builder.rb +0 -25
  141. data/lib/treetop/protometagrammar/grammar_expression_builder.rb +0 -38
  142. data/lib/treetop/protometagrammar/nonterminal_symbol_expression_builder.rb +0 -45
  143. data/lib/treetop/protometagrammar/ordered_choice_expression_builder.rb +0 -21
  144. data/lib/treetop/protometagrammar/parsing_rule_expression_builder.rb +0 -23
  145. data/lib/treetop/protometagrammar/parsing_rule_sequence_expression_builder.rb +0 -14
  146. data/lib/treetop/protometagrammar/prefix_expression_builder.rb +0 -25
  147. data/lib/treetop/protometagrammar/primary_expression_builder.rb +0 -71
  148. data/lib/treetop/protometagrammar/protometagrammar.rb +0 -25
  149. data/lib/treetop/protometagrammar/sequence_expression_builder.rb +0 -37
  150. data/lib/treetop/protometagrammar/suffix_expression_builder.rb +0 -33
  151. data/lib/treetop/protometagrammar/terminal_symbol_expression_builder.rb +0 -52
  152. data/lib/treetop/protometagrammar/trailing_block_expression_builder.rb +0 -30
  153. data/lib/treetop/ruby_extension.rb +0 -11
@@ -0,0 +1,58 @@
1
+ module Screw
2
+ module Unit
3
+ module UI
4
+
5
+ # Provides an interface to write any given UI against,
6
+ # hopefully making it easy to write new UIs.
7
+ class TestRunnerMediator
8
+ RESET = name + "::RESET"
9
+ STARTED = name + "::STARTED"
10
+ FINISHED = name + "::FINISHED"
11
+
12
+ include Util::Observable
13
+
14
+ # Creates a new TestRunnerMediator initialized to run
15
+ # the passed suite.
16
+ def initialize(suite)
17
+ @suite = suite
18
+ end
19
+
20
+ # Runs the suite the TestRunnerMediator was created
21
+ # with.
22
+ def run_suite
23
+ Unit.run = true
24
+ begin_time = Time.now
25
+ notify_listeners(RESET, @suite.size)
26
+ result = create_result
27
+ notify_listeners(STARTED, result)
28
+ result_listener = result.add_listener(TestResult::CHANGED) do |updated_result|
29
+ notify_listeners(TestResult::CHANGED, updated_result)
30
+ end
31
+
32
+ fault_listener = result.add_listener(TestResult::FAULT) do |fault|
33
+ notify_listeners(TestResult::FAULT, fault)
34
+ end
35
+
36
+ @suite.run(result) do |channel, value|
37
+ notify_listeners(channel, value)
38
+ end
39
+
40
+ result.remove_listener(TestResult::FAULT, fault_listener)
41
+ result.remove_listener(TestResult::CHANGED, result_listener)
42
+ end_time = Time.now
43
+ elapsed_time = end_time - begin_time
44
+ notify_listeners(FINISHED, elapsed_time) #"Finished in #{elapsed_time} seconds.")
45
+ return result
46
+ end
47
+
48
+ private
49
+ # A factory method to create the result the mediator
50
+ # should run with. Can be overridden by subclasses if
51
+ # one wants to use a different result.
52
+ def create_result
53
+ return TestResult.new
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,46 @@
1
+ #--
2
+ #
3
+ # Author:: Nathaniel Talbott.
4
+ # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
5
+ # License:: Ruby license.
6
+
7
+ module Screw
8
+ module Unit
9
+ module UI
10
+
11
+ SILENT = 0
12
+ PROGRESS_ONLY = 1
13
+ NORMAL = 2
14
+ VERBOSE = 3
15
+
16
+ # Provides some utilities common to most, if not all,
17
+ # TestRunners.
18
+ #
19
+ #--
20
+ #
21
+ # Perhaps there ought to be a TestRunner superclass? There
22
+ # seems to be a decent amount of shared code between test
23
+ # runners.
24
+
25
+ module TestRunnerUtilities
26
+
27
+ # Creates a new TestRunner and runs the suite.
28
+ def run(suite, output_level=NORMAL)
29
+ return new(suite, output_level).start
30
+ end
31
+
32
+ # Takes care of the ARGV parsing and suite
33
+ # determination necessary for running one of the
34
+ # TestRunners from the command line.
35
+ def start_command_line_test
36
+ if ARGV.empty?
37
+ puts "You should supply the name of a test suite file to the runner"
38
+ exit
39
+ end
40
+ require ARGV[0].gsub(/.+::/, '')
41
+ new(eval(ARGV[0])).start
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,260 @@
1
+ #--
2
+ #
3
+ # Original Author:: Nathaniel Talbott.
4
+ # Author:: Kazuhiro NISHIYAMA.
5
+ # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
6
+ # Copyright:: Copyright (c) 2003 Kazuhiro NISHIYAMA. All rights reserved.
7
+ # License:: Ruby license.
8
+
9
+ require 'tk'
10
+ require 'fancy/unit/ui/test_runnermediator'
11
+ require 'fancy/unit/ui/test_runnerutilities'
12
+
13
+ module Screw
14
+ module Unit
15
+ module UI
16
+ module Tk
17
+
18
+ # Runs a Screw::Unit::TestSuite in a Tk UI. Obviously,
19
+ # this one requires you to have Tk
20
+ # and the Ruby Tk extension installed.
21
+ class TestRunner
22
+ extend TestRunnerUtilities
23
+
24
+ # Creates a new TestRunner for running the passed
25
+ # suite.
26
+ def initialize(suite, output_level = NORMAL)
27
+ if (suite.respond_to?(:suite))
28
+ @suite = suite.suite
29
+ else
30
+ @suite = suite
31
+ end
32
+ @result = nil
33
+
34
+ @red = false
35
+ @fault_detail_list = []
36
+ @runner = Thread.current
37
+ @restart_signal = Class.new(Exception)
38
+ @viewer = Thread.start do
39
+ @runner.join rescue @runner.run
40
+ ::Tk.mainloop
41
+ end
42
+ @viewer.join rescue nil # wait deadlock to handshake
43
+ end
44
+
45
+ # Begins the test run.
46
+ def start
47
+ setup_ui
48
+ setup_mediator
49
+ attach_to_mediator
50
+ start_ui
51
+ @result
52
+ end
53
+
54
+ private
55
+ def setup_mediator
56
+ @mediator = TestRunnerMediator.new(@suite)
57
+ suite_name = @suite.to_s
58
+ if ( @suite.kind_of?(Module) )
59
+ suite_name = @suite.name
60
+ end
61
+ @suite_name_entry.value = suite_name
62
+ end
63
+
64
+ def attach_to_mediator
65
+ @run_button.command(method(:run_test))
66
+ @fault_list.bind('ButtonPress-1', proc{|y|
67
+ fault = @fault_detail_list[@fault_list.nearest(y)]
68
+ if fault
69
+ show_fault(fault)
70
+ end
71
+ }, '%y')
72
+ @mediator.add_listener(TestRunnerMediator::RESET, &method(:reset_ui))
73
+ @mediator.add_listener(TestResult::FAULT, &method(:add_fault))
74
+ @mediator.add_listener(TestResult::CHANGED, &method(:result_changed))
75
+ @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started))
76
+ @mediator.add_listener(TestCase::STARTED, &method(:test_started))
77
+ @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished))
78
+ end
79
+
80
+ def run_test
81
+ @runner.raise(@restart_signal)
82
+ end
83
+
84
+ def start_ui
85
+ @viewer.run
86
+ running = false
87
+ begin
88
+ loop do
89
+ if (running ^= true)
90
+ @run_button.configure('text'=>'Stop')
91
+ @mediator.run_suite
92
+ else
93
+ @run_button.configure('text'=>'Run')
94
+ @viewer.join
95
+ break
96
+ end
97
+ end
98
+ rescue @restart_signal
99
+ retry
100
+ rescue
101
+ end
102
+ end
103
+
104
+ def stop
105
+ ::Tk.exit
106
+ end
107
+
108
+ def reset_ui(count)
109
+ @test_total_count = count.to_f
110
+ @test_progress_bar.configure('background'=>'green')
111
+ @test_progress_bar.place('relwidth'=>(count.zero? ? 0 : 0/count))
112
+ @red = false
113
+
114
+ @test_count_label.value = 0
115
+ @assertion_count_label.value = 0
116
+ @failure_count_label.value = 0
117
+ @error_count_label.value = 0
118
+
119
+ @fault_list.delete(0, 'end')
120
+ @fault_detail_list = []
121
+ clear_fault
122
+ end
123
+
124
+ def add_fault(fault)
125
+ if ( ! @red )
126
+ @test_progress_bar.configure('background'=>'red')
127
+ @red = true
128
+ end
129
+ @fault_detail_list.push fault
130
+ @fault_list.insert('end', fault.short_display)
131
+ end
132
+
133
+ def show_fault(fault)
134
+ raw_show_fault(fault.long_display)
135
+ end
136
+
137
+ def raw_show_fault(string)
138
+ @detail_text.value = string
139
+ end
140
+
141
+ def clear_fault
142
+ raw_show_fault("")
143
+ end
144
+
145
+ def result_changed(result)
146
+ @test_count_label.value = result.run_count
147
+ @test_progress_bar.place('relwidth'=>result.run_count/@test_total_count)
148
+ @assertion_count_label.value = result.assertion_count
149
+ @failure_count_label.value = result.failure_count
150
+ @error_count_label.value = result.error_count
151
+ end
152
+
153
+ def started(result)
154
+ @result = result
155
+ output_status("Started...")
156
+ end
157
+
158
+ def test_started(test_name)
159
+ output_status("Running #{test_name}...")
160
+ end
161
+
162
+ def finished(elapsed_time)
163
+ output_status("Finished in #{elapsed_time} seconds")
164
+ end
165
+
166
+ def output_status(string)
167
+ @status_entry.value = string
168
+ end
169
+
170
+ def setup_ui
171
+ @status_entry = TkVariable.new
172
+ l = TkLabel.new(nil, 'textvariable'=>@status_entry, 'relief'=>'sunken')
173
+ l.pack('side'=>'bottom', 'fill'=>'x')
174
+
175
+ suite_frame = TkFrame.new.pack('fill'=>'x')
176
+
177
+ @run_button = TkButton.new(suite_frame, 'text'=>'Run')
178
+ @run_button.pack('side'=>'right')
179
+
180
+ TkLabel.new(suite_frame, 'text'=>'Suite:').pack('side'=>'left')
181
+ @suite_name_entry = TkVariable.new
182
+ l = TkLabel.new(suite_frame, 'textvariable'=>@suite_name_entry, 'relief'=>'sunken')
183
+ l.pack('side'=>'left', 'fill'=>'x', 'expand'=>true)
184
+
185
+ f = TkFrame.new(nil, 'relief'=>'sunken', 'borderwidth'=>3, 'height'=>20).pack('fill'=>'x', 'padx'=>1)
186
+ @test_progress_bar = TkFrame.new(f, 'background'=>'green').place('anchor'=>'nw', 'relwidth'=>0.0, 'relheight'=>1.0)
187
+
188
+ info_frame = TkFrame.new.pack('fill'=>'x')
189
+ @test_count_label = create_count_label(info_frame, 'Tests:')
190
+ @assertion_count_label = create_count_label(info_frame, 'Assertions:')
191
+ @failure_count_label = create_count_label(info_frame, 'Failures:')
192
+ @error_count_label = create_count_label(info_frame, 'Errors:')
193
+
194
+ if (::Tk.info('command', TkPanedWindow::TkCommandNames[0]) != "")
195
+ # use panedwindow
196
+ paned_frame = TkPanedWindow.new("orient"=>"vertical").pack('fill'=>'both', 'expand'=>true)
197
+
198
+ fault_list_frame = TkFrame.new(paned_frame)
199
+ detail_frame = TkFrame.new(paned_frame)
200
+
201
+ paned_frame.add(fault_list_frame, detail_frame)
202
+ else
203
+ # no panedwindow
204
+ paned_frame = nil
205
+ fault_list_frame = TkFrame.new.pack('fill'=>'both', 'expand'=>true)
206
+ detail_frame = TkFrame.new.pack('fill'=>'both', 'expand'=>true)
207
+ end
208
+
209
+ TkGrid.rowconfigure(fault_list_frame, 0, 'weight'=>1, 'minsize'=>0)
210
+ TkGrid.columnconfigure(fault_list_frame, 0, 'weight'=>1, 'minsize'=>0)
211
+
212
+ fault_scrollbar_y = TkScrollbar.new(fault_list_frame)
213
+ fault_scrollbar_x = TkScrollbar.new(fault_list_frame)
214
+ @fault_list = TkListbox.new(fault_list_frame)
215
+ @fault_list.yscrollbar(fault_scrollbar_y)
216
+ @fault_list.xscrollbar(fault_scrollbar_x)
217
+
218
+ TkGrid.rowconfigure(detail_frame, 0, 'weight'=>1, 'minsize'=>0)
219
+ TkGrid.columnconfigure(detail_frame, 0, 'weight'=>1, 'minsize'=>0)
220
+
221
+ ::Tk.grid(@fault_list, fault_scrollbar_y, 'sticky'=>'news')
222
+ ::Tk.grid(fault_scrollbar_x, 'sticky'=>'news')
223
+
224
+ detail_scrollbar_y = TkScrollbar.new(detail_frame)
225
+ detail_scrollbar_x = TkScrollbar.new(detail_frame)
226
+ @detail_text = TkText.new(detail_frame, 'height'=>10, 'wrap'=>'none') {
227
+ bindtags(bindtags - [TkText])
228
+ }
229
+ @detail_text.yscrollbar(detail_scrollbar_y)
230
+ @detail_text.xscrollbar(detail_scrollbar_x)
231
+
232
+ ::Tk.grid(@detail_text, detail_scrollbar_y, 'sticky'=>'news')
233
+ ::Tk.grid(detail_scrollbar_x, 'sticky'=>'news')
234
+
235
+ # rubber-style pane
236
+ if paned_frame
237
+ ::Tk.update
238
+ @height = paned_frame.winfo_height
239
+ paned_frame.bind('Configure', proc{|h|
240
+ paned_frame.sash_place(0, 0, paned_frame.sash_coord(0)[1] * h / @height)
241
+ @height = h
242
+ }, '%h')
243
+ end
244
+ end
245
+
246
+ def create_count_label(parent, label)
247
+ TkLabel.new(parent, 'text'=>label).pack('side'=>'left', 'expand'=>true)
248
+ v = TkVariable.new(0)
249
+ TkLabel.new(parent, 'textvariable'=>v).pack('side'=>'left', 'expand'=>true)
250
+ v
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
257
+
258
+ if __FILE__ == $0
259
+ Screw::Unit::UI::Tk::TestRunner.start_command_line_test
260
+ end
@@ -0,0 +1,4 @@
1
+ dir = File.dirname(__FILE__)
2
+ require File.join(dir, 'util', 'backtrace_filter')
3
+ require File.join(dir, 'util', 'observable')
4
+ require File.join(dir, 'util', 'proc_wrapper')
@@ -0,0 +1,40 @@
1
+ module Screw
2
+ module Unit
3
+ module Util
4
+ module BacktraceFilter
5
+ TESTUNIT_FILE_SEPARATORS = %r{[\\/:]}
6
+ TESTUNIT_PREFIX = __FILE__.split(TESTUNIT_FILE_SEPARATORS)[0..-3]
7
+ TESTUNIT_RB_FILE = /\.rb\Z/
8
+
9
+ def filter_backtrace(backtrace, prefix=nil)
10
+ return ["No backtrace"] unless(backtrace)
11
+ split_p = if(prefix)
12
+ prefix.split(TESTUNIT_FILE_SEPARATORS)
13
+ else
14
+ TESTUNIT_PREFIX
15
+ end
16
+ match = proc do |e|
17
+ split_e = e.split(TESTUNIT_FILE_SEPARATORS)[0, split_p.size]
18
+ next false unless(split_e[0..-2] == split_p[0..-2])
19
+ split_e[-1].sub(TESTUNIT_RB_FILE, '') == split_p[-1]
20
+ end
21
+ return backtrace unless(backtrace.detect(&match))
22
+ found_prefix = false
23
+ new_backtrace = backtrace.reverse.reject do |e|
24
+ if(match[e])
25
+ found_prefix = true
26
+ true
27
+ elsif(found_prefix)
28
+ false
29
+ else
30
+ true
31
+ end
32
+ end.reverse
33
+ new_backtrace = (new_backtrace.empty? ? backtrace : new_backtrace)
34
+ new_backtrace = new_backtrace.reject(&match)
35
+ new_backtrace.empty? ? backtrace : new_backtrace
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,82 @@
1
+ module Screw
2
+ module Unit
3
+ module Util
4
+
5
+ # This is a utility class that allows anything mixing
6
+ # it in to notify a set of listeners about interesting
7
+ # events.
8
+ module Observable
9
+ # We use this for defaults since nil might mean something
10
+ NOTHING = "NOTHING/#{__id__}"
11
+
12
+ # Adds the passed proc as a listener on the
13
+ # channel indicated by channel_name. listener_key
14
+ # is used to remove the listener later; if none is
15
+ # specified, the proc itself is used.
16
+ #
17
+ # Whatever is used as the listener_key is
18
+ # returned, making it very easy to use the proc
19
+ # itself as the listener_key:
20
+ #
21
+ # listener = add_listener("Channel") { ... }
22
+ # remove_listener("Channel", listener)
23
+ def add_listener(channel_name, listener_key=NOTHING, &listener) # :yields: value
24
+ unless(block_given?)
25
+ raise ArgumentError.new("No callback was passed as a listener")
26
+ end
27
+
28
+ key = listener_key
29
+ if (listener_key == NOTHING)
30
+ listener_key = listener
31
+ key = ProcWrapper.new(listener)
32
+ end
33
+
34
+ channels[channel_name] ||= {}
35
+ channels[channel_name][key] = listener
36
+ return listener_key
37
+ end
38
+
39
+ # Removes the listener indicated by listener_key
40
+ # from the channel indicated by
41
+ # channel_name. Returns the registered proc, or
42
+ # nil if none was found.
43
+ def remove_listener(channel_name, listener_key)
44
+ channel = channels[channel_name]
45
+ return nil unless (channel)
46
+ key = listener_key
47
+ if (listener_key.instance_of?(Proc))
48
+ key = ProcWrapper.new(listener_key)
49
+ end
50
+ if (channel.has_key?(key))
51
+ return channel.delete(key)
52
+ end
53
+ return nil
54
+ end
55
+
56
+ # Calls all the procs registered on the channel
57
+ # indicated by channel_name. If value is
58
+ # specified, it is passed in to the procs,
59
+ # otherwise they are called with no arguments.
60
+ #
61
+ #--
62
+ #
63
+ # Perhaps this should be private? Would it ever
64
+ # make sense for an external class to call this
65
+ # method directly?
66
+ def notify_listeners(channel_name, *arguments)
67
+ channel = channels[channel_name]
68
+ return 0 unless (channel)
69
+ listeners = channel.values
70
+ listeners.each { |listener| listener.call(*arguments) }
71
+ return listeners.size
72
+ end
73
+
74
+ private
75
+ def channels
76
+ @channels ||= {}
77
+ return @channels
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end