treetop 0.1.0 → 1.0.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 (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