ruby/lib/irb/notifier.rb

231 строка
7.2 KiB
Ruby

# frozen_string_literal: true
#
# notifier.rb - output methods used by irb
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
require_relative "output-method"
module IRB
# An output formatter used internally by the lexer.
module Notifier
class ErrUndefinedNotifier < StandardError
def initialize(val)
super("undefined notifier level: #{val} is specified")
end
end
class ErrUnrecognizedLevel < StandardError
def initialize(val)
super("unrecognized notifier level: #{val} is specified")
end
end
# Define a new Notifier output source, returning a new CompositeNotifier
# with the given +prefix+ and +output_method+.
#
# The optional +prefix+ will be appended to all objects being inspected
# during output, using the given +output_method+ as the output source. If
# no +output_method+ is given, StdioOutputMethod will be used, and all
# expressions will be sent directly to STDOUT without any additional
# formatting.
def def_notifier(prefix = "", output_method = StdioOutputMethod.new)
CompositeNotifier.new(prefix, output_method)
end
module_function :def_notifier
# An abstract class, or superclass, for CompositeNotifier and
# LeveledNotifier to inherit. It provides several wrapper methods for the
# OutputMethod object used by the Notifier.
class AbstractNotifier
# Creates a new Notifier object
def initialize(prefix, base_notifier)
@prefix = prefix
@base_notifier = base_notifier
end
# The +prefix+ for this Notifier, which is appended to all objects being
# inspected during output.
attr_reader :prefix
# A wrapper method used to determine whether notifications are enabled.
#
# Defaults to +true+.
def notify?
true
end
# See OutputMethod#print for more detail.
def print(*opts)
@base_notifier.print prefix, *opts if notify?
end
# See OutputMethod#printn for more detail.
def printn(*opts)
@base_notifier.printn prefix, *opts if notify?
end
# See OutputMethod#printf for more detail.
def printf(format, *opts)
@base_notifier.printf(prefix + format, *opts) if notify?
end
# See OutputMethod#puts for more detail.
def puts(*objs)
if notify?
@base_notifier.puts(*objs.collect{|obj| prefix + obj.to_s})
end
end
# Same as #ppx, except it uses the #prefix given during object
# initialization.
# See OutputMethod#ppx for more detail.
def pp(*objs)
if notify?
@base_notifier.ppx @prefix, *objs
end
end
# Same as #pp, except it concatenates the given +prefix+ with the #prefix
# given during object initialization.
#
# See OutputMethod#ppx for more detail.
def ppx(prefix, *objs)
if notify?
@base_notifier.ppx @prefix+prefix, *objs
end
end
# Execute the given block if notifications are enabled.
def exec_if
yield(@base_notifier) if notify?
end
end
# A class that can be used to create a group of notifier objects with the
# intent of representing a leveled notification system for irb.
#
# This class will allow you to generate other notifiers, and assign them
# the appropriate level for output.
#
# The Notifier class provides a class-method Notifier.def_notifier to
# create a new composite notifier. Using the first composite notifier
# object you create, sibling notifiers can be initialized with
# #def_notifier.
class CompositeNotifier < AbstractNotifier
# Create a new composite notifier object with the given +prefix+, and
# +base_notifier+ to use for output.
def initialize(prefix, base_notifier)
super
@notifiers = [D_NOMSG]
@level_notifier = D_NOMSG
end
# List of notifiers in the group
attr_reader :notifiers
# Creates a new LeveledNotifier in the composite #notifiers group.
#
# The given +prefix+ will be assigned to the notifier, and +level+ will
# be used as the index of the #notifiers Array.
#
# This method returns the newly created instance.
def def_notifier(level, prefix = "")
notifier = LeveledNotifier.new(self, level, prefix)
@notifiers[level] = notifier
notifier
end
# Returns the leveled notifier for this object
attr_reader :level_notifier
alias level level_notifier
# Sets the leveled notifier for this object.
#
# When the given +value+ is an instance of AbstractNotifier,
# #level_notifier is set to the given object.
#
# When an Integer is given, #level_notifier is set to the notifier at the
# index +value+ in the #notifiers Array.
#
# If no notifier exists at the index +value+ in the #notifiers Array, an
# ErrUndefinedNotifier exception is raised.
#
# An ErrUnrecognizedLevel exception is raised if the given +value+ is not
# found in the existing #notifiers Array, or an instance of
# AbstractNotifier
def level_notifier=(value)
case value
when AbstractNotifier
@level_notifier = value
when Integer
l = @notifiers[value]
raise ErrUndefinedNotifier, value unless l
@level_notifier = l
else
raise ErrUnrecognizedLevel, value unless l
end
end
alias level= level_notifier=
end
# A leveled notifier is comparable to the composite group from
# CompositeNotifier#notifiers.
class LeveledNotifier < AbstractNotifier
include Comparable
# Create a new leveled notifier with the given +base+, and +prefix+ to
# send to AbstractNotifier.new
#
# The given +level+ is used to compare other leveled notifiers in the
# CompositeNotifier group to determine whether or not to output
# notifications.
def initialize(base, level, prefix)
super(prefix, base)
@level = level
end
# The current level of this notifier object
attr_reader :level
# Compares the level of this notifier object with the given +other+
# notifier.
#
# See the Comparable module for more information.
def <=>(other)
@level <=> other.level
end
# Whether to output messages to the output method, depending on the level
# of this notifier object.
def notify?
@base_notifier.level >= self
end
end
# NoMsgNotifier is a LeveledNotifier that's used as the default notifier
# when creating a new CompositeNotifier.
#
# This notifier is used as the +zero+ index, or level +0+, for
# CompositeNotifier#notifiers, and will not output messages of any sort.
class NoMsgNotifier < LeveledNotifier
# Creates a new notifier that should not be used to output messages.
def initialize
@base_notifier = nil
@level = 0
@prefix = ""
end
# Ensures notifications are ignored, see AbstractNotifier#notify? for
# more information.
def notify?
false
end
end
D_NOMSG = NoMsgNotifier.new # :nodoc:
end
end