test-unit 1.2.3
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.
- data/History.txt +5 -0
 - data/Manifest.txt +48 -0
 - data/README.txt +27 -0
 - data/Rakefile +15 -0
 - data/bin/testrb +5 -0
 - data/lib/test/unit.rb +280 -0
 - data/lib/test/unit/assertionfailederror.rb +14 -0
 - data/lib/test/unit/assertions.rb +622 -0
 - data/lib/test/unit/autorunner.rb +220 -0
 - data/lib/test/unit/collector.rb +43 -0
 - data/lib/test/unit/collector/dir.rb +108 -0
 - data/lib/test/unit/collector/objectspace.rb +34 -0
 - data/lib/test/unit/error.rb +56 -0
 - data/lib/test/unit/failure.rb +51 -0
 - data/lib/test/unit/testcase.rb +160 -0
 - data/lib/test/unit/testresult.rb +80 -0
 - data/lib/test/unit/testsuite.rb +76 -0
 - data/lib/test/unit/ui/console/testrunner.rb +127 -0
 - data/lib/test/unit/ui/fox/testrunner.rb +268 -0
 - data/lib/test/unit/ui/gtk/testrunner.rb +416 -0
 - data/lib/test/unit/ui/gtk2/testrunner.rb +465 -0
 - data/lib/test/unit/ui/testrunnermediator.rb +68 -0
 - data/lib/test/unit/ui/testrunnerutilities.rb +46 -0
 - data/lib/test/unit/ui/tk/testrunner.rb +260 -0
 - data/lib/test/unit/util/backtracefilter.rb +40 -0
 - data/lib/test/unit/util/observable.rb +90 -0
 - data/lib/test/unit/util/procwrapper.rb +48 -0
 - data/lib/test/unit/version.rb +7 -0
 - data/sample/adder.rb +13 -0
 - data/sample/subtracter.rb +12 -0
 - data/sample/tc_adder.rb +18 -0
 - data/sample/tc_subtracter.rb +18 -0
 - data/sample/ts_examples.rb +7 -0
 - data/test/collector/test_dir.rb +406 -0
 - data/test/collector/test_objectspace.rb +98 -0
 - data/test/runit/test_assert.rb +402 -0
 - data/test/runit/test_testcase.rb +91 -0
 - data/test/runit/test_testresult.rb +144 -0
 - data/test/runit/test_testsuite.rb +49 -0
 - data/test/test_assertions.rb +528 -0
 - data/test/test_error.rb +26 -0
 - data/test/test_failure.rb +33 -0
 - data/test/test_testcase.rb +275 -0
 - data/test/test_testresult.rb +104 -0
 - data/test/test_testsuite.rb +129 -0
 - data/test/util/test_backtracefilter.rb +41 -0
 - data/test/util/test_observable.rb +102 -0
 - data/test/util/test_procwrapper.rb +36 -0
 - metadata +128 -0
 
| 
         @@ -0,0 +1,68 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #--
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Author:: Nathaniel Talbott.
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
         
     | 
| 
      
 5 
     | 
    
         
            +
            # License:: Ruby license.
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'test/unit'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'test/unit/util/observable'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'test/unit/testresult'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            module Test
         
     | 
| 
      
 12 
     | 
    
         
            +
              module Unit
         
     | 
| 
      
 13 
     | 
    
         
            +
                module UI
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  # Provides an interface to write any given UI against,
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # hopefully making it easy to write new UIs.
         
     | 
| 
      
 17 
     | 
    
         
            +
                  class TestRunnerMediator
         
     | 
| 
      
 18 
     | 
    
         
            +
                    RESET = name + "::RESET"
         
     | 
| 
      
 19 
     | 
    
         
            +
                    STARTED = name + "::STARTED"
         
     | 
| 
      
 20 
     | 
    
         
            +
                    FINISHED = name + "::FINISHED"
         
     | 
| 
      
 21 
     | 
    
         
            +
                    
         
     | 
| 
      
 22 
     | 
    
         
            +
                    include Util::Observable
         
     | 
| 
      
 23 
     | 
    
         
            +
                    
         
     | 
| 
      
 24 
     | 
    
         
            +
                    # Creates a new TestRunnerMediator initialized to run
         
     | 
| 
      
 25 
     | 
    
         
            +
                    # the passed suite.
         
     | 
| 
      
 26 
     | 
    
         
            +
                    def initialize(suite)
         
     | 
| 
      
 27 
     | 
    
         
            +
                      @suite = suite
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    # Runs the suite the TestRunnerMediator was created
         
     | 
| 
      
 31 
     | 
    
         
            +
                    # with.
         
     | 
| 
      
 32 
     | 
    
         
            +
                    def run_suite
         
     | 
| 
      
 33 
     | 
    
         
            +
                      Unit.run = true
         
     | 
| 
      
 34 
     | 
    
         
            +
                      begin_time = Time.now
         
     | 
| 
      
 35 
     | 
    
         
            +
                      notify_listeners(RESET, @suite.size)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      result = create_result
         
     | 
| 
      
 37 
     | 
    
         
            +
                      notify_listeners(STARTED, result)
         
     | 
| 
      
 38 
     | 
    
         
            +
                      result_listener = result.add_listener(TestResult::CHANGED) do |updated_result|
         
     | 
| 
      
 39 
     | 
    
         
            +
                        notify_listeners(TestResult::CHANGED, updated_result)
         
     | 
| 
      
 40 
     | 
    
         
            +
                      end
         
     | 
| 
      
 41 
     | 
    
         
            +
                      
         
     | 
| 
      
 42 
     | 
    
         
            +
                      fault_listener = result.add_listener(TestResult::FAULT) do |fault|
         
     | 
| 
      
 43 
     | 
    
         
            +
                        notify_listeners(TestResult::FAULT, fault)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      end
         
     | 
| 
      
 45 
     | 
    
         
            +
                      
         
     | 
| 
      
 46 
     | 
    
         
            +
                      @suite.run(result) do |channel, value|
         
     | 
| 
      
 47 
     | 
    
         
            +
                        notify_listeners(channel, value)
         
     | 
| 
      
 48 
     | 
    
         
            +
                      end
         
     | 
| 
      
 49 
     | 
    
         
            +
                      
         
     | 
| 
      
 50 
     | 
    
         
            +
                      result.remove_listener(TestResult::FAULT, fault_listener)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      result.remove_listener(TestResult::CHANGED, result_listener)
         
     | 
| 
      
 52 
     | 
    
         
            +
                      end_time = Time.now
         
     | 
| 
      
 53 
     | 
    
         
            +
                      elapsed_time = end_time - begin_time
         
     | 
| 
      
 54 
     | 
    
         
            +
                      notify_listeners(FINISHED, elapsed_time) #"Finished in #{elapsed_time} seconds.")
         
     | 
| 
      
 55 
     | 
    
         
            +
                      return result
         
     | 
| 
      
 56 
     | 
    
         
            +
                    end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                    private
         
     | 
| 
      
 59 
     | 
    
         
            +
                    # A factory method to create the result the mediator
         
     | 
| 
      
 60 
     | 
    
         
            +
                    # should run with. Can be overridden by subclasses if
         
     | 
| 
      
 61 
     | 
    
         
            +
                    # one wants to use a different result.
         
     | 
| 
      
 62 
     | 
    
         
            +
                    def create_result
         
     | 
| 
      
 63 
     | 
    
         
            +
                      return TestResult.new
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
            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 Test
         
     | 
| 
      
 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 'test/unit/ui/testrunnermediator'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'test/unit/ui/testrunnerutilities'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            module Test
         
     | 
| 
      
 14 
     | 
    
         
            +
              module Unit
         
     | 
| 
      
 15 
     | 
    
         
            +
                module UI
         
     | 
| 
      
 16 
     | 
    
         
            +
                  module Tk
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    # Runs a Test::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 
     | 
    
         
            +
              Test::Unit::UI::Tk::TestRunner.start_command_line_test
         
     | 
| 
      
 260 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Test
         
     | 
| 
      
 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,90 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #--
         
     | 
| 
      
 2 
     | 
    
         
            +
            #
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Author:: Nathaniel Talbott.
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
         
     | 
| 
      
 5 
     | 
    
         
            +
            # License:: Ruby license.
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'test/unit/util/procwrapper'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            module Test
         
     | 
| 
      
 10 
     | 
    
         
            +
              module Unit
         
     | 
| 
      
 11 
     | 
    
         
            +
                module Util
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  # This is a utility class that allows anything mixing
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # it in to notify a set of listeners about interesting
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # events.
         
     | 
| 
      
 16 
     | 
    
         
            +
                  module Observable
         
     | 
| 
      
 17 
     | 
    
         
            +
                    # We use this for defaults since nil might mean something
         
     | 
| 
      
 18 
     | 
    
         
            +
                    NOTHING = "NOTHING/#{__id__}"
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    # Adds the passed proc as a listener on the
         
     | 
| 
      
 21 
     | 
    
         
            +
                    # channel indicated by channel_name. listener_key
         
     | 
| 
      
 22 
     | 
    
         
            +
                    # is used to remove the listener later; if none is
         
     | 
| 
      
 23 
     | 
    
         
            +
                    # specified, the proc itself is used.
         
     | 
| 
      
 24 
     | 
    
         
            +
                    #
         
     | 
| 
      
 25 
     | 
    
         
            +
                    # Whatever is used as the listener_key is
         
     | 
| 
      
 26 
     | 
    
         
            +
                    # returned, making it very easy to use the proc
         
     | 
| 
      
 27 
     | 
    
         
            +
                    # itself as the listener_key:
         
     | 
| 
      
 28 
     | 
    
         
            +
                    #
         
     | 
| 
      
 29 
     | 
    
         
            +
                    #  listener = add_listener("Channel") { ... }
         
     | 
| 
      
 30 
     | 
    
         
            +
                    #  remove_listener("Channel", listener)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    def add_listener(channel_name, listener_key=NOTHING, &listener) # :yields: value
         
     | 
| 
      
 32 
     | 
    
         
            +
                      unless(block_given?)
         
     | 
| 
      
 33 
     | 
    
         
            +
                        raise ArgumentError.new("No callback was passed as a listener")
         
     | 
| 
      
 34 
     | 
    
         
            +
                      end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  
         
     | 
| 
      
 36 
     | 
    
         
            +
                      key = listener_key
         
     | 
| 
      
 37 
     | 
    
         
            +
                      if (listener_key == NOTHING)
         
     | 
| 
      
 38 
     | 
    
         
            +
                        listener_key = listener
         
     | 
| 
      
 39 
     | 
    
         
            +
                        key = ProcWrapper.new(listener)
         
     | 
| 
      
 40 
     | 
    
         
            +
                      end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  
         
     | 
| 
      
 42 
     | 
    
         
            +
                      channels[channel_name] ||= {}
         
     | 
| 
      
 43 
     | 
    
         
            +
                      channels[channel_name][key] = listener
         
     | 
| 
      
 44 
     | 
    
         
            +
                      return listener_key
         
     | 
| 
      
 45 
     | 
    
         
            +
                    end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    # Removes the listener indicated by listener_key
         
     | 
| 
      
 48 
     | 
    
         
            +
                    # from the channel indicated by
         
     | 
| 
      
 49 
     | 
    
         
            +
                    # channel_name. Returns the registered proc, or
         
     | 
| 
      
 50 
     | 
    
         
            +
                    # nil if none was found.
         
     | 
| 
      
 51 
     | 
    
         
            +
                    def remove_listener(channel_name, listener_key)
         
     | 
| 
      
 52 
     | 
    
         
            +
                      channel = channels[channel_name]
         
     | 
| 
      
 53 
     | 
    
         
            +
                      return nil unless (channel)
         
     | 
| 
      
 54 
     | 
    
         
            +
                      key = listener_key
         
     | 
| 
      
 55 
     | 
    
         
            +
                      if (listener_key.instance_of?(Proc))
         
     | 
| 
      
 56 
     | 
    
         
            +
                        key = ProcWrapper.new(listener_key)
         
     | 
| 
      
 57 
     | 
    
         
            +
                      end
         
     | 
| 
      
 58 
     | 
    
         
            +
                      if (channel.has_key?(key))
         
     | 
| 
      
 59 
     | 
    
         
            +
                        return channel.delete(key)
         
     | 
| 
      
 60 
     | 
    
         
            +
                      end
         
     | 
| 
      
 61 
     | 
    
         
            +
                      return nil
         
     | 
| 
      
 62 
     | 
    
         
            +
                    end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                    # Calls all the procs registered on the channel
         
     | 
| 
      
 65 
     | 
    
         
            +
                    # indicated by channel_name. If value is
         
     | 
| 
      
 66 
     | 
    
         
            +
                    # specified, it is passed in to the procs,
         
     | 
| 
      
 67 
     | 
    
         
            +
                    # otherwise they are called with no arguments.
         
     | 
| 
      
 68 
     | 
    
         
            +
                    #
         
     | 
| 
      
 69 
     | 
    
         
            +
                    #--
         
     | 
| 
      
 70 
     | 
    
         
            +
                    #
         
     | 
| 
      
 71 
     | 
    
         
            +
                    # Perhaps this should be private? Would it ever
         
     | 
| 
      
 72 
     | 
    
         
            +
                    # make sense for an external class to call this
         
     | 
| 
      
 73 
     | 
    
         
            +
                    # method directly?
         
     | 
| 
      
 74 
     | 
    
         
            +
                    def notify_listeners(channel_name, *arguments)
         
     | 
| 
      
 75 
     | 
    
         
            +
                      channel = channels[channel_name]
         
     | 
| 
      
 76 
     | 
    
         
            +
                      return 0 unless (channel)
         
     | 
| 
      
 77 
     | 
    
         
            +
                      listeners = channel.values
         
     | 
| 
      
 78 
     | 
    
         
            +
                      listeners.each { |listener| listener.call(*arguments) }
         
     | 
| 
      
 79 
     | 
    
         
            +
                      return listeners.size
         
     | 
| 
      
 80 
     | 
    
         
            +
                    end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                    private
         
     | 
| 
      
 83 
     | 
    
         
            +
                    def channels
         
     | 
| 
      
 84 
     | 
    
         
            +
                      @channels ||= {}
         
     | 
| 
      
 85 
     | 
    
         
            +
                      return @channels
         
     | 
| 
      
 86 
     | 
    
         
            +
                    end
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
                end
         
     | 
| 
      
 89 
     | 
    
         
            +
              end
         
     | 
| 
      
 90 
     | 
    
         
            +
            end
         
     |