1# 2# notifier.rb - output methods used by irb 3# $Release Version: 0.9.6$ 4# $Revision: 38515 $ 5# by Keiju ISHITSUKA(keiju@ruby-lang.org) 6# 7# -- 8# 9# 10# 11 12require "e2mmap" 13require "irb/output-method" 14 15module IRB 16 # An output formatter used internally by the lexer. 17 module Notifier 18 extend Exception2MessageMapper 19 def_exception :ErrUndefinedNotifier, 20 "undefined notifier level: %d is specified" 21 def_exception :ErrUnrecognizedLevel, 22 "unrecognized notifier level: %s is specified" 23 24 # Define a new Notifier output source, returning a new CompositeNotifier 25 # with the given +prefix+ and +output_method+. 26 # 27 # The optional +prefix+ will be appended to all objects being inspected 28 # during output, using the given +output_method+ as the output source. If 29 # no +output_method+ is given, StdioOuputMethod will be used, and all 30 # expressions will be sent directly to STDOUT without any additional 31 # formatting. 32 def def_notifier(prefix = "", output_method = StdioOutputMethod.new) 33 CompositeNotifier.new(prefix, output_method) 34 end 35 module_function :def_notifier 36 37 # An abstract class, or superclass, for CompositeNotifier and 38 # LeveledNotifier to inherit. It provides several wrapper methods for the 39 # OutputMethod object used by the Notifier. 40 class AbstractNotifier 41 # Creates a new Notifier object 42 def initialize(prefix, base_notifier) 43 @prefix = prefix 44 @base_notifier = base_notifier 45 end 46 47 # The +prefix+ for this Notifier, which is appended to all objects being 48 # inspected during output. 49 attr_reader :prefix 50 51 # A wrapper method used to determine whether notifications are enabled. 52 # 53 # Defaults to +true+. 54 def notify? 55 true 56 end 57 58 # See OutputMethod#print for more detail. 59 def print(*opts) 60 @base_notifier.print prefix, *opts if notify? 61 end 62 63 # See OutputMethod#printn for more detail. 64 def printn(*opts) 65 @base_notifier.printn prefix, *opts if notify? 66 end 67 68 # See OutputMethod#printf for more detail. 69 def printf(format, *opts) 70 @base_notifier.printf(prefix + format, *opts) if notify? 71 end 72 73 # See OutputMethod#puts for more detail. 74 def puts(*objs) 75 if notify? 76 @base_notifier.puts(*objs.collect{|obj| prefix + obj.to_s}) 77 end 78 end 79 80 # Same as #ppx, except it uses the #prefix given during object 81 # initialization. 82 # See OutputMethod#ppx for more detail. 83 def pp(*objs) 84 if notify? 85 @base_notifier.ppx @prefix, *objs 86 end 87 end 88 89 # Same as #pp, except it concatenates the given +prefix+ with the #prefix 90 # given during object initialization. 91 # 92 # See OutputMethod#ppx for more detail. 93 def ppx(prefix, *objs) 94 if notify? 95 @base_notifier.ppx @prefix+prefix, *objs 96 end 97 end 98 99 # Execute the given block if notifications are enabled. 100 def exec_if 101 yield(@base_notifier) if notify? 102 end 103 end 104 105 # A class that can be used to create a group of notifier objects with the 106 # intent of representing a leveled notification system for irb. 107 # 108 # This class will allow you to generate other notifiers, and assign them 109 # the appropriate level for output. 110 # 111 # The Notifier class provides a class-method Notifier.def_notifier to 112 # create a new composite notifier. Using the first composite notifier 113 # object you create, sibling notifiers can be initialized with 114 # #def_notifier. 115 class CompositeNotifier<AbstractNotifier 116 # Create a new composite notifier object with the given +prefix+, and 117 # +base_notifier+ to use for output. 118 def initialize(prefix, base_notifier) 119 super 120 121 @notifiers = [D_NOMSG] 122 @level_notifier = D_NOMSG 123 end 124 125 # List of notifiers in the group 126 attr_reader :notifiers 127 128 # Creates a new LeveledNotifier in the composite #notifiers group. 129 # 130 # The given +prefix+ will be assigned to the notifier, and +level+ will 131 # be used as the index of the #notifiers Array. 132 # 133 # This method returns the newly created instance. 134 def def_notifier(level, prefix = "") 135 notifier = LeveledNotifier.new(self, level, prefix) 136 @notifiers[level] = notifier 137 notifier 138 end 139 140 # Returns the leveled notifier for this object 141 attr_reader :level_notifier 142 alias level level_notifier 143 144 # Sets the leveled notifier for this object. 145 # 146 # When the given +value+ is an instance of AbstractNotifier, 147 # #level_notifier is set to the given object. 148 # 149 # When an Integer is given, #level_notifier is set to the notifier at the 150 # index +value+ in the #notifiers Array. 151 # 152 # If no notifier exists at the index +value+ in the #notifiers Array, an 153 # ErrUndefinedNotifier exception is raised. 154 # 155 # An ErrUnrecognizedLevel exception is raised if the given +value+ is not 156 # found in the existing #notifiers Array, or an instance of 157 # AbstractNotifier 158 def level_notifier=(value) 159 case value 160 when AbstractNotifier 161 @level_notifier = value 162 when Integer 163 l = @notifiers[value] 164 Notifier.Raise ErrUndefinedNotifer, value unless l 165 @level_notifier = l 166 else 167 Notifier.Raise ErrUnrecognizedLevel, value unless l 168 end 169 end 170 171 alias level= level_notifier= 172 end 173 174 # A leveled notifier is comparable to the composite group from 175 # CompositeNotifier#notifiers. 176 class LeveledNotifier<AbstractNotifier 177 include Comparable 178 179 # Create a new leveled notifier with the given +base+, and +prefix+ to 180 # send to AbstractNotifier.new 181 # 182 # The given +level+ is used to compare other leveled notifiers in the 183 # CompositeNotifier group to determine whether or not to output 184 # notifications. 185 def initialize(base, level, prefix) 186 super(prefix, base) 187 188 @level = level 189 end 190 191 # The current level of this notifier object 192 attr_reader :level 193 194 # Compares the level of this notifier object with the given +other+ 195 # notifier. 196 # 197 # See the Comparable module for more information. 198 def <=>(other) 199 @level <=> other.level 200 end 201 202 # Whether to output messages to the output method, depending on the level 203 # of this notifier object. 204 def notify? 205 @base_notifier.level >= self 206 end 207 end 208 209 # NoMsgNotifier is a LeveledNotifier that's used as the default notifier 210 # when creating a new CompositeNotifier. 211 # 212 # This notifier is used as the +zero+ index, or level +0+, for 213 # CompositeNotifier#notifiers, and will not output messages of any sort. 214 class NoMsgNotifier<LeveledNotifier 215 # Creates a new notifier that should not be used to output messages. 216 def initialize 217 @base_notifier = nil 218 @level = 0 219 @prefix = "" 220 end 221 222 # Ensures notifications are ignored, see AbstractNotifier#notify? for 223 # more information. 224 def notify? 225 false 226 end 227 end 228 229 D_NOMSG = NoMsgNotifier.new # :nodoc: 230 end 231end 232