mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* lib/irb.rb, lib/irb/*: Documentation for IRB
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38515 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
4f7a6aafa5
commit
7e9eb32669
21 changed files with 611 additions and 60 deletions
|
@ -1,3 +1,7 @@
|
|||
Fri Dec 21 14:45:00 2012 Zachary Scott <zachary@zacharyscott.net>
|
||||
|
||||
* lib/irb.rb, lib/irb/*: Documentation for IRB
|
||||
|
||||
Fri Dec 21 11:31:02 2012 Eric Hodel <drbrain@segment7.net>
|
||||
|
||||
* lib/rake/*: Updated to rake 0.9.6
|
||||
|
|
97
lib/irb.rb
97
lib/irb.rb
|
@ -149,6 +149,52 @@ STDOUT.sync = true
|
|||
# :RETURN => "%s\n" # used to printf
|
||||
# }
|
||||
#
|
||||
# irb comes with a number of available modes:
|
||||
#
|
||||
# # :NULL:
|
||||
# # :PROMPT_I:
|
||||
# # :PROMPT_N:
|
||||
# # :PROMPT_S:
|
||||
# # :PROMPT_C:
|
||||
# # :RETURN: |
|
||||
# # %s
|
||||
# # :DEFAULT:
|
||||
# # :PROMPT_I: ! '%N(%m):%03n:%i> '
|
||||
# # :PROMPT_N: ! '%N(%m):%03n:%i> '
|
||||
# # :PROMPT_S: ! '%N(%m):%03n:%i%l '
|
||||
# # :PROMPT_C: ! '%N(%m):%03n:%i* '
|
||||
# # :RETURN: |
|
||||
# # => %s
|
||||
# # :CLASSIC:
|
||||
# # :PROMPT_I: ! '%N(%m):%03n:%i> '
|
||||
# # :PROMPT_N: ! '%N(%m):%03n:%i> '
|
||||
# # :PROMPT_S: ! '%N(%m):%03n:%i%l '
|
||||
# # :PROMPT_C: ! '%N(%m):%03n:%i* '
|
||||
# # :RETURN: |
|
||||
# # %s
|
||||
# # :SIMPLE:
|
||||
# # :PROMPT_I: ! '>> '
|
||||
# # :PROMPT_N: ! '>> '
|
||||
# # :PROMPT_S:
|
||||
# # :PROMPT_C: ! '?> '
|
||||
# # :RETURN: |
|
||||
# # => %s
|
||||
# # :INF_RUBY:
|
||||
# # :PROMPT_I: ! '%N(%m):%03n:%i> '
|
||||
# # :PROMPT_N:
|
||||
# # :PROMPT_S:
|
||||
# # :PROMPT_C:
|
||||
# # :RETURN: |
|
||||
# # %s
|
||||
# # :AUTO_INDENT: true
|
||||
# # :XMP:
|
||||
# # :PROMPT_I:
|
||||
# # :PROMPT_N:
|
||||
# # :PROMPT_S:
|
||||
# # :PROMPT_C:
|
||||
# # :RETURN: |2
|
||||
# # ==>%s
|
||||
#
|
||||
# == Restrictions
|
||||
#
|
||||
# Because irb evaluates input immediately after it is syntactically complete,
|
||||
|
@ -185,7 +231,8 @@ STDOUT.sync = true
|
|||
# A few commands for loading files within the session are also available:
|
||||
#
|
||||
# +source+::
|
||||
# Loads a given file in the current session, see IrbLoader#source_file
|
||||
# Loads a given file in the current session and displays the source lines,
|
||||
# see IrbLoader#source_file
|
||||
# +irb_load+::
|
||||
# Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
|
||||
# +irb_require+::
|
||||
|
@ -279,6 +326,7 @@ STDOUT.sync = true
|
|||
module IRB
|
||||
@RCS_ID='-$Id$-'
|
||||
|
||||
# An exception raised by IRB.irb_abort
|
||||
class Abort < Exception;end
|
||||
|
||||
@CONF = {}
|
||||
|
@ -287,11 +335,14 @@ module IRB
|
|||
# Displays current configuration.
|
||||
#
|
||||
# Modifing the configuration is achieved by sending a message to IRB.conf.
|
||||
#
|
||||
# See IRB@Configuration for more information.
|
||||
def IRB.conf
|
||||
@CONF
|
||||
end
|
||||
|
||||
# IRB version method
|
||||
# Returns the current version of IRB, including release version and last
|
||||
# updated date.
|
||||
def IRB.version
|
||||
if v = @CONF[:VERSION] then return v end
|
||||
|
||||
|
@ -300,11 +351,16 @@ module IRB
|
|||
@CONF[:VERSION] = format("irb %s(%s)", rv, @LAST_UPDATE_DATE)
|
||||
end
|
||||
|
||||
# The current IRB::Context of the session, see IRB.conf
|
||||
#
|
||||
# irb
|
||||
# irb(main):001:0> IRB.CurrentContext.irb_name = "foo"
|
||||
# foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo"
|
||||
def IRB.CurrentContext
|
||||
IRB.conf[:MAIN_CONTEXT]
|
||||
end
|
||||
|
||||
# initialize IRB and start TOP_LEVEL irb
|
||||
# Initializes IRB and creates a new Irb.irb object at the +TOPLEVEL_BINDING+
|
||||
def IRB.start(ap_path = nil)
|
||||
$0 = File::basename(ap_path, ".rb") if ap_path
|
||||
|
||||
|
@ -333,7 +389,7 @@ module IRB
|
|||
# print "\n"
|
||||
end
|
||||
|
||||
# Calls each of the IRB.conf[:AT_EXIT] hooks when the current session quits.
|
||||
# Calls each event hook of IRB.conf[:AT_EXIT] when the current session quits.
|
||||
def IRB.irb_at_exit
|
||||
@CONF[:AT_EXIT].each{|hook| hook.call}
|
||||
end
|
||||
|
@ -343,6 +399,9 @@ module IRB
|
|||
throw :IRB_EXIT, ret
|
||||
end
|
||||
|
||||
# Aborts then interrupts irb.
|
||||
#
|
||||
# Will raise an Abort exception, or the given +exception+.
|
||||
def IRB.irb_abort(irb, exception = Abort)
|
||||
if defined? Thread
|
||||
irb.context.thread.raise exception, "abort then interrupt!"
|
||||
|
@ -351,8 +410,8 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# irb interpreter main routine
|
||||
class Irb
|
||||
# Creates a new irb session
|
||||
def initialize(workspace = nil, input_method = nil, output_method = nil)
|
||||
@context = Context.new(self, workspace, input_method, output_method)
|
||||
@context.main.extend ExtendCommandBundle
|
||||
|
@ -361,9 +420,12 @@ module IRB
|
|||
@scanner = RubyLex.new
|
||||
@scanner.exception_on_syntax_error = false
|
||||
end
|
||||
# Returns the current context of this irb session
|
||||
attr_reader :context
|
||||
# The lexer used by this irb session
|
||||
attr_accessor :scanner
|
||||
|
||||
# Evaluates input for this session.
|
||||
def eval_input
|
||||
@scanner.set_prompt do
|
||||
|ltype, indent, continue, line_no|
|
||||
|
@ -462,6 +524,11 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Evaluates the given block using the given +path+ as the Context#irb_path
|
||||
# and +name+ as the Context#irb_name.
|
||||
#
|
||||
# Used by the irb command +source+, see IRB@IRB+Sessions for more
|
||||
# information.
|
||||
def suspend_name(path = nil, name = nil)
|
||||
@context.irb_path, back_path = path, @context.irb_path if path
|
||||
@context.irb_name, back_name = name, @context.irb_name if name
|
||||
|
@ -473,6 +540,11 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Evaluates the given block using the given +workspace+ as the
|
||||
# Context#workspace.
|
||||
#
|
||||
# Used by the irb command +irb_load+, see IRB@IRB+Sessions for more
|
||||
# information.
|
||||
def suspend_workspace(workspace)
|
||||
@context.workspace, back_workspace = workspace, @context.workspace
|
||||
begin
|
||||
|
@ -482,6 +554,11 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Evaluates the given block using the given +input_method+ as the
|
||||
# Context#io.
|
||||
#
|
||||
# Used by the irb commands +source+ and +irb_load+, see IRB@IRB+Sessions
|
||||
# for more information.
|
||||
def suspend_input_method(input_method)
|
||||
back_io = @context.io
|
||||
@context.instance_eval{@io = input_method}
|
||||
|
@ -492,6 +569,7 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Evaluates the given block using the given +context+ as the Context.
|
||||
def suspend_context(context)
|
||||
@context, back_context = context, @context
|
||||
begin
|
||||
|
@ -501,6 +579,7 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Handler for the signal SIGINT, see Kernel#trap for more information.
|
||||
def signal_handle
|
||||
unless @context.ignore_sigint?
|
||||
print "\nabort!\n" if @context.verbose?
|
||||
|
@ -522,6 +601,7 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Evaluates the given block using the given +status+.
|
||||
def signal_status(status)
|
||||
return yield if @signal_status == :IN_LOAD
|
||||
|
||||
|
@ -534,7 +614,7 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
def prompt(prompt, ltype, indent, line_no)
|
||||
def prompt(prompt, ltype, indent, line_no) # :nodoc:
|
||||
p = prompt.dup
|
||||
p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
|
||||
case $2
|
||||
|
@ -565,10 +645,12 @@ module IRB
|
|||
p
|
||||
end
|
||||
|
||||
def output_value
|
||||
def output_value # :nodoc:
|
||||
printf @context.return_format, @context.inspect_last_value
|
||||
end
|
||||
|
||||
# Outputs the local variables to this current session, including
|
||||
# #signal_status and #context, using IRB::Locale.
|
||||
def inspect
|
||||
ary = []
|
||||
for iv in instance_variables
|
||||
|
@ -585,7 +667,6 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Singleton method
|
||||
def @CONF.inspect
|
||||
IRB.version unless self[:VERSION]
|
||||
|
||||
|
|
|
@ -9,10 +9,12 @@
|
|||
require "readline"
|
||||
|
||||
module IRB
|
||||
module InputCompletor
|
||||
module InputCompletor # :nodoc:
|
||||
|
||||
@RCS_ID='-$Id$-'
|
||||
|
||||
# Set of reserved words used by Ruby, you should not use these for
|
||||
# constants or variables
|
||||
ReservedWords = [
|
||||
"BEGIN", "END",
|
||||
"alias", "and",
|
||||
|
@ -208,6 +210,7 @@ module IRB
|
|||
end
|
||||
}
|
||||
|
||||
# Set of available operators in Ruby
|
||||
Operators = ["%", "&", "*", "**", "+", "-", "/",
|
||||
"<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
|
||||
"[]", "[]=", "^", "!", "!=", "!~"]
|
||||
|
|
|
@ -12,6 +12,8 @@ require "irb/workspace"
|
|||
require "irb/inspector"
|
||||
|
||||
module IRB
|
||||
# A class that wraps the current state of the irb session, including the
|
||||
# configuration of IRB.conf.
|
||||
class Context
|
||||
# Creates a new IRB context.
|
||||
#
|
||||
|
@ -101,28 +103,49 @@ module IRB
|
|||
@debug_level = IRB.conf[:DEBUG_LEVEL]
|
||||
end
|
||||
|
||||
# The top-level workspace, see WorkSpace#main
|
||||
def main
|
||||
@workspace.main
|
||||
end
|
||||
|
||||
# The toplevel workspace, see #home_workspace
|
||||
attr_reader :workspace_home
|
||||
# WorkSpace in the current context
|
||||
attr_accessor :workspace
|
||||
# The current thread in this context
|
||||
attr_reader :thread
|
||||
# The current input method
|
||||
#
|
||||
# Can be either StdioInputMethod, ReadlineInputMethod, FileInputMethod or
|
||||
# other specified when the context is created. See ::new for more
|
||||
# information on +input_method+.
|
||||
attr_accessor :io
|
||||
|
||||
# Current irb session
|
||||
attr_accessor :irb
|
||||
# A copy of the default <code>IRB.conf[:AP_NAME]</code>
|
||||
attr_accessor :ap_name
|
||||
# A copy of the default <code>IRB.conf[:RC]</code>
|
||||
attr_accessor :rc
|
||||
# A copy of the default <code>IRB.conf[:LOAD_MODULES]</code>
|
||||
attr_accessor :load_modules
|
||||
# Can be either name from <code>IRB.conf[:IRB_NAME]</code>, or the number of
|
||||
# the current job set by JobManager, such as <code>irb#2</code>
|
||||
attr_accessor :irb_name
|
||||
# Can be either the #irb_name surrounded by parenthesis, or the
|
||||
# +input_method+ passed to Context.new
|
||||
attr_accessor :irb_path
|
||||
|
||||
# Whether +Readline+ is enabled or not.
|
||||
#
|
||||
# A copy of the default <code>IRB.conf[:USE_READLINE]</code>
|
||||
#
|
||||
# See #use_readline= for more information.
|
||||
attr_reader :use_readline
|
||||
# A copy of the default <code>IRB.conf[:INSPECT_MODE]</code>
|
||||
attr_reader :inspect_mode
|
||||
|
||||
# A copy of the default <code>IRB.conf[:PROMPT_MODE]</code>
|
||||
attr_reader :prompt_mode
|
||||
# Standard IRB prompt
|
||||
#
|
||||
|
@ -138,7 +161,11 @@ module IRB
|
|||
attr_accessor :prompt_c
|
||||
# See IRB@Customizing+the+IRB+Prompt for more information.
|
||||
attr_accessor :prompt_n
|
||||
# Can be either the deafult <code>IRB.conf[:AUTO_INDENT]</code>, or the
|
||||
# mode set by #prompt_mode=
|
||||
attr_accessor :auto_indent_mode
|
||||
# The format of the return statement, set by #prompt_mode= using the
|
||||
# +:RETURN+ of the +mode+ passed to set the current #prompt_mode.
|
||||
attr_accessor :return_format
|
||||
|
||||
# Whether <code>^C</code> (+control-c+) will be ignored or not.
|
||||
|
@ -154,8 +181,20 @@ module IRB
|
|||
#
|
||||
# If set to +false+, <code>^D</code> will quit irb.
|
||||
attr_accessor :ignore_eof
|
||||
# Whether to echo the return value to output or not.
|
||||
#
|
||||
# Uses IRB.conf[:ECHO] if available, or defaults to +true+.
|
||||
#
|
||||
# puts "hello"
|
||||
# # hello
|
||||
# #=> nil
|
||||
# IRB.CurrentContext.echo = false
|
||||
# puts "omg"
|
||||
# # omg
|
||||
attr_accessor :echo
|
||||
# Whether verbose messages are displayed or not.
|
||||
#
|
||||
# A copy of the default <code>IRB.conf[:VERBOSE]</code>
|
||||
attr_accessor :verbose
|
||||
# The debug level of irb
|
||||
#
|
||||
|
@ -194,18 +233,26 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Whether #verbose? is +true+, and +input_method+ is either
|
||||
# StdioInputMethod or ReadlineInputMethod, see #io for more information.
|
||||
def prompting?
|
||||
verbose? || (STDIN.tty? && @io.kind_of?(StdioInputMethod) ||
|
||||
(defined?(ReadlineInputMethod) && @io.kind_of?(ReadlineInputMethod)))
|
||||
end
|
||||
|
||||
# The return value of the last statement evaluated.
|
||||
attr_reader :last_value
|
||||
|
||||
# Sets the return value from the last statement evaluated in this context
|
||||
# to #last_value.
|
||||
def set_last_value(value)
|
||||
@last_value = value
|
||||
@workspace.evaluate self, "_ = IRB.CurrentContext.last_value"
|
||||
end
|
||||
|
||||
# Sets the +mode+ of the prompt in this context.
|
||||
#
|
||||
# See IRB@Customizing+the+IRB+Prompt for more information.
|
||||
def prompt_mode=(mode)
|
||||
@prompt_mode = mode
|
||||
pconf = IRB.conf[:PROMPT][mode]
|
||||
|
@ -221,10 +268,13 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Whether #inspect_mode is set or not, see #inspect_mode= for more detail.
|
||||
def inspect?
|
||||
@inspect_mode.nil? or @inspect_mode
|
||||
end
|
||||
|
||||
# Whether #io uses a File for the +input_method+ passed when creating the
|
||||
# current context, see ::new
|
||||
def file_input?
|
||||
@io.class == FileInputMethod
|
||||
end
|
||||
|
@ -236,6 +286,8 @@ module IRB
|
|||
# +nil+:: inspect mode in non-math mode,
|
||||
# non-inspect mode in math mode
|
||||
#
|
||||
# See IRB::INSPECTORS for more information.
|
||||
#
|
||||
# Can also be set using the +--inspect+ and +--noinspect+ command line
|
||||
# options.
|
||||
#
|
||||
|
@ -311,18 +363,19 @@ module IRB
|
|||
SLex.debug_level = value
|
||||
end
|
||||
|
||||
# Whether or not debug mode is enabled, see #debug_level=.
|
||||
def debug?
|
||||
@debug_level > 0
|
||||
end
|
||||
|
||||
def evaluate(line, line_no)
|
||||
def evaluate(line, line_no) # :nodoc:
|
||||
@line_no = line_no
|
||||
set_last_value(@workspace.evaluate(self, line, irb_path, line_no))
|
||||
# @workspace.evaluate("_ = IRB.conf[:MAIN_CONTEXT]._")
|
||||
# @_ = @workspace.evaluate(line, irb_path, line_no)
|
||||
end
|
||||
|
||||
def inspect_last_value
|
||||
def inspect_last_value # :nodoc:
|
||||
@inspect_method.inspect_value(@last_value)
|
||||
end
|
||||
|
||||
|
@ -332,12 +385,12 @@ module IRB
|
|||
IRB.irb_exit(@irb, ret)
|
||||
end
|
||||
|
||||
NOPRINTING_IVARS = ["@last_value"]
|
||||
NO_INSPECTING_IVARS = ["@irb", "@io"]
|
||||
IDNAME_IVARS = ["@prompt_mode"]
|
||||
NOPRINTING_IVARS = ["@last_value"] # :nodoc:
|
||||
NO_INSPECTING_IVARS = ["@irb", "@io"] # :nodoc:
|
||||
IDNAME_IVARS = ["@prompt_mode"] # :nodoc:
|
||||
|
||||
alias __inspect__ inspect
|
||||
def inspect
|
||||
def inspect # :nodoc:
|
||||
array = []
|
||||
for ivar in instance_variables.sort{|e1, e2| e1 <=> e2}
|
||||
ivar = ivar.to_s
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
module IRB # :nodoc:
|
||||
class Context
|
||||
|
||||
# Inherited from +TOPLEVEL_BINDING+.
|
||||
def home_workspace
|
||||
if defined? @home_workspace
|
||||
@home_workspace
|
||||
|
|
|
@ -15,6 +15,7 @@ module IRB # :nodoc:
|
|||
|
||||
NOPRINTING_IVARS.push "@eval_history_values"
|
||||
|
||||
# See #set_last_value
|
||||
alias _set_last_value set_last_value
|
||||
|
||||
def set_last_value(value)
|
||||
|
@ -57,7 +58,7 @@ module IRB # :nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
class History
|
||||
class History # :nodoc:
|
||||
@RCS_ID='-$Id$-'
|
||||
|
||||
def initialize(size = 16)
|
||||
|
|
|
@ -14,12 +14,16 @@ module IRB # :nodoc:
|
|||
# Raised in the event of an exception in a file loaded from an Irb session
|
||||
class LoadAbort < Exception;end
|
||||
|
||||
# Provides a few commands for loading files within an irb session.
|
||||
#
|
||||
# See ExtendCommandBundle for more information.
|
||||
module IrbLoader
|
||||
@RCS_ID='-$Id$-'
|
||||
|
||||
alias ruby_load load
|
||||
alias ruby_require require
|
||||
|
||||
# Loads the given file similarly to Kernel#load
|
||||
def irb_load(fn, priv = nil)
|
||||
path = search_file_from_ruby_path(fn)
|
||||
raise LoadError, "No such file to load -- #{fn}" unless path
|
||||
|
@ -27,7 +31,7 @@ module IRB # :nodoc:
|
|||
load_file(path, priv)
|
||||
end
|
||||
|
||||
def search_file_from_ruby_path(fn)
|
||||
def search_file_from_ruby_path(fn) # :nodoc:
|
||||
if /^#{Regexp.quote(File::Separator)}/ =~ fn
|
||||
return fn if File.exist?(fn)
|
||||
return nil
|
||||
|
@ -41,6 +45,9 @@ module IRB # :nodoc:
|
|||
return nil
|
||||
end
|
||||
|
||||
# Loads a given file in the current session and displays the source lines
|
||||
#
|
||||
# See Irb#suspend_input_method for more information.
|
||||
def source_file(path)
|
||||
irb.suspend_name(path, File.basename(path)) do
|
||||
irb.suspend_input_method(FileInputMethod.new(path)) do
|
||||
|
@ -60,6 +67,9 @@ module IRB # :nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
# Loads the given file in the current session's context and evaluates it.
|
||||
#
|
||||
# See Irb#suspend_input_method for more information.
|
||||
def load_file(path, priv = nil)
|
||||
irb.suspend_name(path, File.basename(path)) do
|
||||
|
||||
|
@ -88,7 +98,7 @@ module IRB # :nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
def old
|
||||
def old # :nodoc:
|
||||
back_io = @io
|
||||
back_path = @irb_path
|
||||
back_name = @irb_name
|
||||
|
|
|
@ -12,44 +12,61 @@ IRB.fail CantShiftToMultiIrbMode unless defined?(Thread)
|
|||
require "thread"
|
||||
|
||||
module IRB
|
||||
# job management class
|
||||
class JobManager
|
||||
@RCS_ID='-$Id$-'
|
||||
|
||||
# Creates a new JobManager object
|
||||
def initialize
|
||||
# @jobs = [[thread, irb],...]
|
||||
@jobs = []
|
||||
@current_job = nil
|
||||
end
|
||||
|
||||
# The active irb session
|
||||
attr_accessor :current_job
|
||||
|
||||
# The total number of irb sessions, used to set +irb_name+ of the current
|
||||
# Context.
|
||||
def n_jobs
|
||||
@jobs.size
|
||||
end
|
||||
|
||||
# Returns the thread for the given +key+ object, see #search for more
|
||||
# information.
|
||||
def thread(key)
|
||||
th, = search(key)
|
||||
th
|
||||
end
|
||||
|
||||
# Returns the irb session for the given +key+ object, see #search for more
|
||||
# information.
|
||||
def irb(key)
|
||||
_, irb = search(key)
|
||||
irb
|
||||
end
|
||||
|
||||
# Returns the top level thread.
|
||||
def main_thread
|
||||
@jobs[0][0]
|
||||
end
|
||||
|
||||
# Returns the top level irb session.
|
||||
def main_irb
|
||||
@jobs[0][1]
|
||||
end
|
||||
|
||||
# Add the given +irb+ session to the jobs Array.
|
||||
def insert(irb)
|
||||
@jobs.push [Thread.current, irb]
|
||||
end
|
||||
|
||||
# Changes the current active irb session to the given +key+ in the jobs
|
||||
# Array.
|
||||
#
|
||||
# Raises an IrbAlreadyDead exception if the given +key+ is no longer alive.
|
||||
#
|
||||
# If the given irb session is already active, an IrbSwitchedToCurrentThread
|
||||
# exception is raised.
|
||||
def switch(key)
|
||||
th, irb = search(key)
|
||||
IRB.fail IrbAlreadyDead unless th.alive?
|
||||
|
@ -60,6 +77,12 @@ module IRB
|
|||
@current_job = irb(Thread.current)
|
||||
end
|
||||
|
||||
# Terminates the irb sessions specified by the given +keys+.
|
||||
#
|
||||
# Raises an IrbAlreadyDead exception if one of the given +keys+ is already
|
||||
# terminated.
|
||||
#
|
||||
# See Thread#exit for more information.
|
||||
def kill(*keys)
|
||||
for key in keys
|
||||
th, _ = search(key)
|
||||
|
@ -68,6 +91,20 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Returns the associated job for the given +key+.
|
||||
#
|
||||
# If given an Integer, it will return the +key+ index for the jobs Array.
|
||||
#
|
||||
# When an instance of Irb is given, it will return the irb session
|
||||
# associated with +key+.
|
||||
#
|
||||
# If given an instance of Thread, it will return the associated thread
|
||||
# +key+ using Object#=== on the jobs Array.
|
||||
#
|
||||
# Otherwise returns the irb session with the same top-level binding as the
|
||||
# given +key+.
|
||||
#
|
||||
# Raises a NoSuchJob exception if no job can be found with the given +key+.
|
||||
def search(key)
|
||||
job = case key
|
||||
when Integer
|
||||
|
@ -83,6 +120,7 @@ module IRB
|
|||
job
|
||||
end
|
||||
|
||||
# Deletes the job at the given +key+.
|
||||
def delete(key)
|
||||
case key
|
||||
when Integer
|
||||
|
@ -106,6 +144,7 @@ module IRB
|
|||
@jobs.push assoc
|
||||
end
|
||||
|
||||
# Outputs a list of jobs, see the irb command +irb_jobs+, or +jobs+.
|
||||
def inspect
|
||||
ary = []
|
||||
@jobs.each_index do
|
||||
|
@ -135,10 +174,12 @@ module IRB
|
|||
|
||||
@JobManager = JobManager.new
|
||||
|
||||
# The current JobManager in the session
|
||||
def IRB.JobManager
|
||||
@JobManager
|
||||
end
|
||||
|
||||
# The current Context in this session
|
||||
def IRB.CurrentContext
|
||||
IRB.JobManager.irb(Thread.current).context
|
||||
end
|
||||
|
|
|
@ -11,21 +11,24 @@
|
|||
require "readline"
|
||||
|
||||
module IRB
|
||||
module HistorySavingAbility
|
||||
module HistorySavingAbility # :nodoc:
|
||||
@RCS_ID='-$Id$-'
|
||||
end
|
||||
|
||||
class Context
|
||||
def init_save_history
|
||||
def init_save_history# :nodoc:
|
||||
unless (class<<@io;self;end).include?(HistorySavingAbility)
|
||||
@io.extend(HistorySavingAbility)
|
||||
end
|
||||
end
|
||||
|
||||
# A copy of the default <code>IRB.conf[:SAVE_HISTORY]</code>
|
||||
def save_history
|
||||
IRB.conf[:SAVE_HISTORY]
|
||||
end
|
||||
|
||||
# Sets <code>IRB.conf[:SAVE_HISTORY]</code> to the given +val+ and calls
|
||||
# #init_save_history with this context.
|
||||
def save_history=(val)
|
||||
IRB.conf[:SAVE_HISTORY] = val
|
||||
if val
|
||||
|
@ -35,16 +38,18 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# A copy of the default <code>IRB.conf[:HISTORY_FILE]</code>
|
||||
def history_file
|
||||
IRB.conf[:HISTORY_FILE]
|
||||
end
|
||||
|
||||
# Set <code>IRB.conf[:HISTORY_FILE]</code> to the given +hist+.
|
||||
def history_file=(hist)
|
||||
IRB.conf[:HISTORY_FILE] = hist
|
||||
end
|
||||
end
|
||||
|
||||
module HistorySavingAbility
|
||||
module HistorySavingAbility # :nodoc:
|
||||
include Readline
|
||||
|
||||
# def HistorySavingAbility.create_finalizer
|
||||
|
|
|
@ -23,9 +23,16 @@ module IRB
|
|||
end
|
||||
|
||||
class Context
|
||||
# Whether Tracer is used when evaluating statements in this context.
|
||||
#
|
||||
# See +lib/tracer.rb+ for more information.
|
||||
attr_reader :use_tracer
|
||||
alias use_tracer? use_tracer
|
||||
|
||||
# Sets whether or not to use the Tracer library when evaluating statements
|
||||
# in this context.
|
||||
#
|
||||
# See +lib/tracer.rb+ for more information.
|
||||
def use_tracer=(opt)
|
||||
if opt
|
||||
Tracer.set_get_line_procs(@irb_path) {
|
||||
|
@ -41,6 +48,10 @@ module IRB
|
|||
|
||||
class WorkSpace
|
||||
alias __evaluate__ evaluate
|
||||
# Evaluate the context of this workspace and use the Tracer library to
|
||||
# output the exact lines of code are being executed in chronological order.
|
||||
#
|
||||
# See +lib/tracer.rb+ for more information.
|
||||
def evaluate(context, statements, file = nil, line = nil)
|
||||
if context.use_tracer? && file != nil && line != nil
|
||||
Tracer.on
|
||||
|
|
|
@ -18,16 +18,16 @@ class Object
|
|||
end
|
||||
|
||||
module IRB
|
||||
# :stopdoc:
|
||||
module ExtendCommandBundle
|
||||
# Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
|
||||
def irb_load(*opts, &b)
|
||||
ExtendCommand::Load.execute(irb_context, *opts, &b)
|
||||
end
|
||||
# Loads the given file similarly to Kernel#require
|
||||
def irb_require(*opts, &b)
|
||||
ExtendCommand::Require.execute(irb_context, *opts, &b)
|
||||
end
|
||||
end
|
||||
# :startdoc:
|
||||
|
||||
class Context
|
||||
|
||||
|
|
|
@ -12,11 +12,12 @@
|
|||
module IRB # :nodoc:
|
||||
class Context
|
||||
|
||||
# Size of the current WorkSpace stack
|
||||
def irb_level
|
||||
workspace_stack.size
|
||||
end
|
||||
|
||||
# Workspaces in the current stack
|
||||
# WorkSpaces in the current stack
|
||||
def workspaces
|
||||
if defined? @workspaces
|
||||
@workspaces
|
||||
|
|
|
@ -9,16 +9,22 @@
|
|||
#
|
||||
#
|
||||
module IRB # :nodoc:
|
||||
#
|
||||
# IRB extended command
|
||||
#
|
||||
# Installs the default irb extensions command bundle.
|
||||
module ExtendCommandBundle
|
||||
EXCB = ExtendCommandBundle
|
||||
EXCB = ExtendCommandBundle # :nodoc:
|
||||
|
||||
# See #install_alias_method.
|
||||
NO_OVERRIDE = 0
|
||||
# See #install_alias_method.
|
||||
OVERRIDE_PRIVATE_ONLY = 0x01
|
||||
# See #install_alias_method.
|
||||
OVERRIDE_ALL = 0x02
|
||||
|
||||
# Quits the current irb context
|
||||
#
|
||||
# +ret+ is the optional signal or message to send to Context#exit
|
||||
#
|
||||
# Same as <code>IRB.CurrentContext.exit</code>.
|
||||
def irb_exit(ret = 0)
|
||||
irb_context.exit(ret)
|
||||
end
|
||||
|
@ -108,13 +114,33 @@ module IRB # :nodoc:
|
|||
|
||||
]
|
||||
|
||||
# Installs the default irb commands:
|
||||
#
|
||||
# +irb_current_working_workspace+:: Context#main
|
||||
# +irb_change_workspace+:: Context#change_workspace
|
||||
# +irb_workspaces+:: Context#workspaces
|
||||
# +irb_push_workspace+:: Context#push_workspace
|
||||
# +irb_pop_workspace+:: Context#pop_workspace
|
||||
# +irb_load+:: #irb_load
|
||||
# +irb_require+:: #irb_require
|
||||
# +irb_source+:: IrbLoader#source_file
|
||||
# +irb+:: IRB.irb
|
||||
# +irb_jobs+:: JobManager
|
||||
# +irb_fg+:: JobManager#switch
|
||||
# +irb_kill+:: JobManager#kill
|
||||
# +irb_help+:: IRB@Command+line+options
|
||||
def self.install_extend_commands
|
||||
for args in @EXTEND_COMMANDS
|
||||
def_extend_command(*args)
|
||||
end
|
||||
end
|
||||
|
||||
# aliases = [commands_alias, flag], ...
|
||||
# Evaluate the given +cmd_name+ on the given +cmd_class+ Class.
|
||||
#
|
||||
# Will also define any given +aliases+ for the method.
|
||||
#
|
||||
# The optional +load_file+ parameter will be required within the method
|
||||
# definition.
|
||||
def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases)
|
||||
case cmd_class
|
||||
when Symbol
|
||||
|
@ -154,7 +180,8 @@ module IRB # :nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
# override = {NO_OVERRIDE, OVERRIDE_PRIVATE_ONLY, OVERRIDE_ALL}
|
||||
# Installs alias methods for the default irb commands, see
|
||||
# ::install_extend_commands.
|
||||
def install_alias_method(to, from, override = NO_OVERRIDE)
|
||||
to = to.id2name unless to.kind_of?(String)
|
||||
from = from.id2name unless from.kind_of?(String)
|
||||
|
@ -175,10 +202,12 @@ module IRB # :nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
def self.irb_original_method_name(method_name)
|
||||
def self.irb_original_method_name(method_name) # :nodoc:
|
||||
"irb_" + method_name + "_org"
|
||||
end
|
||||
|
||||
# Installs alias methods for the default irb commands on the given object
|
||||
# using #install_alias_method.
|
||||
def self.extend_object(obj)
|
||||
unless (class << obj; ancestors; end).include?(EXCB)
|
||||
super
|
||||
|
@ -191,9 +220,9 @@ module IRB # :nodoc:
|
|||
install_extend_commands
|
||||
end
|
||||
|
||||
# extension support for Context
|
||||
# Extends methods for the Context module
|
||||
module ContextExtender
|
||||
CE = ContextExtender
|
||||
CE = ContextExtender # :nodoc:
|
||||
|
||||
@EXTEND_COMMANDS = [
|
||||
[:eval_history=, "irb/ext/history.rb"],
|
||||
|
@ -203,12 +232,23 @@ module IRB # :nodoc:
|
|||
[:save_history=, "irb/ext/save-history.rb"],
|
||||
]
|
||||
|
||||
# Installs the default context extensions as irb commands:
|
||||
#
|
||||
# Context#eval_history=:: +irb/ext/history.rb+
|
||||
# Context#use_tracer=:: +irb/ext/tracer.rb+
|
||||
# Context#math_mode=:: +irb/ext/math-mode.rb+
|
||||
# Context#use_loader=:: +irb/ext/use-loader.rb+
|
||||
# Context#save_history=:: +irb/ext/save-history.rb+
|
||||
def self.install_extend_commands
|
||||
for args in @EXTEND_COMMANDS
|
||||
def_extend_command(*args)
|
||||
end
|
||||
end
|
||||
|
||||
# Evaluate the given +command+ from the given +load_file+ on the Context
|
||||
# module.
|
||||
#
|
||||
# Will also define any given +aliases+ for the method.
|
||||
def self.def_extend_command(cmd_name, load_file, *aliases)
|
||||
line = __LINE__; Context.module_eval %[
|
||||
def #{cmd_name}(*opts, &b)
|
||||
|
@ -225,7 +265,10 @@ module IRB # :nodoc:
|
|||
CE.install_extend_commands
|
||||
end
|
||||
|
||||
# A convenience module for extending Ruby methods.
|
||||
module MethodExtender
|
||||
# Extends the given +base_method+ with a prefix call to the given
|
||||
# +extend_method+.
|
||||
def def_pre_proc(base_method, extend_method)
|
||||
base_method = base_method.to_s
|
||||
extend_method = extend_method.to_s
|
||||
|
@ -240,6 +283,8 @@ module IRB # :nodoc:
|
|||
]
|
||||
end
|
||||
|
||||
# Extends the given +base_method+ with a postfix call to the given
|
||||
# +extend_method+.
|
||||
def def_post_proc(base_method, extend_method)
|
||||
base_method = base_method.to_s
|
||||
extend_method = extend_method.to_s
|
||||
|
@ -254,7 +299,13 @@ module IRB # :nodoc:
|
|||
]
|
||||
end
|
||||
|
||||
# return #{prefix}#{name}#{postfix}<num>
|
||||
# Returns a unique method name to use as an alias for the given +name+.
|
||||
#
|
||||
# Usually returns <code>#{prefix}#{name}#{postfix}<num></code>, example:
|
||||
#
|
||||
# new_alias_name('foo') #=> __alias_of__foo__
|
||||
# def bar; end
|
||||
# new_alias_name('bar') #=> __alias_of__bar__2
|
||||
def new_alias_name(name, prefix = "__alias_of__", postfix = "__")
|
||||
base_name = "#{prefix}#{name}#{postfix}"
|
||||
all_methods = instance_methods(true) + private_instance_methods(true)
|
||||
|
|
|
@ -17,13 +17,17 @@ module IRB
|
|||
def_exception :FrameOverflow, "frame overflow"
|
||||
def_exception :FrameUnderflow, "frame underflow"
|
||||
|
||||
# Default number of stack frames
|
||||
INIT_STACK_TIMES = 3
|
||||
# Default number of frames offset
|
||||
CALL_STACK_OFFSET = 3
|
||||
|
||||
# Creates a new stack frame
|
||||
def initialize
|
||||
@frames = [TOPLEVEL_BINDING] * INIT_STACK_TIMES
|
||||
end
|
||||
|
||||
# Used by Kernel#set_trace_func to register each event in the call stack
|
||||
def trace_func(event, file, line, id, binding)
|
||||
case event
|
||||
when 'call', 'class'
|
||||
|
@ -33,27 +37,37 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Returns the +n+ number of frames on the call stack from the last frame
|
||||
# initialized.
|
||||
#
|
||||
# Raises FrameUnderflow if there are no frames in the given stack range.
|
||||
def top(n = 0)
|
||||
bind = @frames[-(n + CALL_STACK_OFFSET)]
|
||||
Fail FrameUnderflow unless bind
|
||||
bind
|
||||
end
|
||||
|
||||
# Returns the +n+ number of frames on the call stack from the first frame
|
||||
# initialized.
|
||||
#
|
||||
# Raises FrameOverflow if there are no frames in the given stack range.
|
||||
def bottom(n = 0)
|
||||
bind = @frames[n]
|
||||
Fail FrameOverflow unless bind
|
||||
bind
|
||||
end
|
||||
|
||||
# singleton functions
|
||||
# Convenience method for Frame#bottom
|
||||
def Frame.bottom(n = 0)
|
||||
@backtrace.bottom(n)
|
||||
end
|
||||
|
||||
# Convenience method for Frame#top
|
||||
def Frame.top(n = 0)
|
||||
@backtrace.top(n)
|
||||
end
|
||||
|
||||
# Returns the binding context of the caller from the last frame initialized
|
||||
def Frame.sender
|
||||
eval "self", @backtrace.top
|
||||
end
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
require 'irb/magic-file'
|
||||
|
||||
module IRB
|
||||
# Outputs the irb help message, see IRB@Command+line+options.
|
||||
def IRB.print_usage
|
||||
lc = IRB.conf[:LC_MESSAGES]
|
||||
path = lc.find("irb/help-message")
|
||||
|
|
|
@ -12,34 +12,39 @@ require 'irb/src_encoding'
|
|||
require 'irb/magic-file'
|
||||
|
||||
module IRB
|
||||
#
|
||||
# InputMethod
|
||||
# StdioInputMethod
|
||||
# FileInputMethod
|
||||
# (ReadlineInputMethod)
|
||||
#
|
||||
STDIN_FILE_NAME = "(line)"
|
||||
STDIN_FILE_NAME = "(line)" # :nodoc:
|
||||
class InputMethod
|
||||
@RCS_ID='-$Id$-'
|
||||
|
||||
# Creates a new input method object
|
||||
def initialize(file = STDIN_FILE_NAME)
|
||||
@file_name = file
|
||||
end
|
||||
# The file name of this input method, usually given during initialization.
|
||||
attr_reader :file_name
|
||||
|
||||
# The irb prompt associated with this input method
|
||||
attr_accessor :prompt
|
||||
|
||||
# Reads the next line from this input method.
|
||||
#
|
||||
# See IO#gets for more information.
|
||||
def gets
|
||||
IRB.fail NotImplementedError, "gets"
|
||||
end
|
||||
public :gets
|
||||
|
||||
# Whether this input method is still readable when there is no more data to
|
||||
# read.
|
||||
#
|
||||
# See IO#eof for more information.
|
||||
def readable_atfer_eof?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
class StdioInputMethod < InputMethod
|
||||
# Creates a new input method object
|
||||
def initialize
|
||||
super
|
||||
@line_no = 0
|
||||
|
@ -48,40 +53,67 @@ module IRB
|
|||
@stdout = IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
|
||||
end
|
||||
|
||||
# Reads the next line from this input method.
|
||||
#
|
||||
# See IO#gets for more information.
|
||||
def gets
|
||||
print @prompt
|
||||
line = @stdin.gets
|
||||
@line[@line_no += 1] = line
|
||||
end
|
||||
|
||||
# Whether the end of this input method has been reached, returns +true+ if
|
||||
# there is no more data to read.
|
||||
#
|
||||
# See IO#eof? for more information.
|
||||
def eof?
|
||||
@stdin.eof?
|
||||
end
|
||||
|
||||
# Whether this input method is still readable when there is no more data to
|
||||
# read.
|
||||
#
|
||||
# See IO#eof for more information.
|
||||
def readable_atfer_eof?
|
||||
true
|
||||
end
|
||||
|
||||
# Returns the current line number for #io.
|
||||
#
|
||||
# #line counts the number of times #gets is called.
|
||||
#
|
||||
# See IO#lineno for more information.
|
||||
def line(line_no)
|
||||
@line[line_no]
|
||||
end
|
||||
|
||||
# The external encoding for standard input.
|
||||
def encoding
|
||||
@stdin.external_encoding
|
||||
end
|
||||
end
|
||||
|
||||
# Use a File for IO with irb, see InputMethod
|
||||
class FileInputMethod < InputMethod
|
||||
# Creates a new input method object
|
||||
def initialize(file)
|
||||
super
|
||||
@io = IRB::MagicFile.open(file)
|
||||
end
|
||||
# The file name of this input method, usually given during initialization.
|
||||
attr_reader :file_name
|
||||
|
||||
# Whether the end of this input method has been reached, returns +true+ if
|
||||
# there is no more data to read.
|
||||
#
|
||||
# See IO#eof? for more information.
|
||||
def eof?
|
||||
@io.eof?
|
||||
end
|
||||
|
||||
# Reads the next line from this input method.
|
||||
#
|
||||
# See IO#gets for more information.
|
||||
def gets
|
||||
print @prompt
|
||||
l = @io.gets
|
||||
|
@ -89,6 +121,7 @@ module IRB
|
|||
l
|
||||
end
|
||||
|
||||
# The external encoding for standard input.
|
||||
def encoding
|
||||
@io.external_encoding
|
||||
end
|
||||
|
@ -98,6 +131,7 @@ module IRB
|
|||
require "readline"
|
||||
class ReadlineInputMethod < InputMethod
|
||||
include Readline
|
||||
# Creates a new input method object using Readline
|
||||
def initialize
|
||||
super
|
||||
|
||||
|
@ -109,6 +143,9 @@ module IRB
|
|||
@stdout = IO.open(STDOUT.to_i, 'w', :external_encoding => IRB.conf[:LC_MESSAGES].encoding, :internal_encoding => "-")
|
||||
end
|
||||
|
||||
# Reads the next line from this input method.
|
||||
#
|
||||
# See IO#gets for more information.
|
||||
def gets
|
||||
Readline.input = @stdin
|
||||
Readline.output = @stdout
|
||||
|
@ -121,18 +158,32 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Whether the end of this input method has been reached, returns +true+
|
||||
# if there is no more data to read.
|
||||
#
|
||||
# See IO#eof? for more information.
|
||||
def eof?
|
||||
@eof
|
||||
end
|
||||
|
||||
# Whether this input method is still readable when there is no more data to
|
||||
# read.
|
||||
#
|
||||
# See IO#eof for more information.
|
||||
def readable_atfer_eof?
|
||||
true
|
||||
end
|
||||
|
||||
# Returns the current line number for #io.
|
||||
#
|
||||
# #line counts the number of times #gets is called.
|
||||
#
|
||||
# See IO#lineno for more information.
|
||||
def line(line_no)
|
||||
@line[line_no]
|
||||
end
|
||||
|
||||
# The external encoding for standard input.
|
||||
def encoding
|
||||
@stdin.external_encoding
|
||||
end
|
||||
|
|
|
@ -12,37 +12,73 @@
|
|||
|
||||
module IRB # :nodoc:
|
||||
|
||||
|
||||
# Convenience method to create a new Inspector, using the given +inspect+
|
||||
# proc, and optional +init+ proc and passes them to Inspector.new
|
||||
#
|
||||
# irb(main):001:0> ins = IRB::Inspector(proc{ |v| "omg! #{v}" })
|
||||
# irb(main):001:0> IRB.CurrentContext.inspect_mode = ins # => omg! #<IRB::Inspector:0x007f46f7ba7d28>
|
||||
# irb(main):001:0> "what?" #=> omg! what?
|
||||
#
|
||||
def IRB::Inspector(inspect, init = nil)
|
||||
Inspector.new(inspect, init)
|
||||
end
|
||||
|
||||
# An irb inspector
|
||||
#
|
||||
# In order to create your own custom inspector there are two things you
|
||||
# should be aware of:
|
||||
#
|
||||
# Inspector uses #inspect_value, or +inspect_proc+, for output of return values.
|
||||
#
|
||||
# This also allows for an optional #init+, or +init_proc+, which is called
|
||||
# when the inspector is activated.
|
||||
#
|
||||
# Knowing this, you can create a rudimentary inspector as follows:
|
||||
#
|
||||
# irb(main):001:0> ins = IRB::Inspector.new(proc{ |v| "omg! #{v}" })
|
||||
# irb(main):001:0> IRB.CurrentContext.inspect_mode = ins # => omg! #<IRB::Inspector:0x007f46f7ba7d28>
|
||||
# irb(main):001:0> "what?" #=> omg! what?
|
||||
#
|
||||
class Inspector
|
||||
# Creates a new inspector object, using the given +inspect_proc+ when
|
||||
# output return values in irb.
|
||||
def initialize(inspect_proc, init_proc = nil)
|
||||
@init = init_proc
|
||||
@inspect = inspect_proc
|
||||
end
|
||||
|
||||
# Proc to call when the inspector is activated, good for requiring
|
||||
# dependant libraries.
|
||||
def init
|
||||
@init.call if @init
|
||||
end
|
||||
|
||||
# Proc to call when the input is evaluated and output in irb.
|
||||
def inspect_value(v)
|
||||
@inspect.call(v)
|
||||
end
|
||||
end
|
||||
|
||||
# Default inspectors available to irb, this includes:
|
||||
#
|
||||
# +:pp+:: Using Kernel#pretty_inspect
|
||||
# +:yaml+:: Using YAML.dump
|
||||
# +:marshal+:: Using Marshal.dump
|
||||
INSPECTORS = {}
|
||||
|
||||
# Determines the inspector to use where +inspector+ is one of the keys passed
|
||||
# during inspector definition.
|
||||
def INSPECTORS.keys_with_inspector(inspector)
|
||||
select{|k,v| v == inspector}.collect{|k, v| k}
|
||||
end
|
||||
|
||||
# ex)
|
||||
# INSPECTORS.def_inspector(key, init_p=nil){|v| v.inspect}
|
||||
# INSPECTORS.def_inspector([key1,..], init_p=nil){|v| v.inspect}
|
||||
# INSPECTORS.def_inspector(key, inspector)
|
||||
# INSPECTORS.def_inspector([key1,...], inspector)
|
||||
|
||||
# Example
|
||||
#
|
||||
# INSPECTORS.def_inspector(key, init_p=nil){|v| v.inspect}
|
||||
# INSPECTORS.def_inspector([key1,..], init_p=nil){|v| v.inspect}
|
||||
# INSPECTORS.def_inspector(key, inspector)
|
||||
# INSPECTORS.def_inspector([key1,...], inspector)
|
||||
def INSPECTORS.def_inspector(key, arg=nil, &block)
|
||||
# if !block_given?
|
||||
# case arg
|
||||
|
|
|
@ -13,6 +13,7 @@ require "e2mmap"
|
|||
require "irb/output-method"
|
||||
|
||||
module IRB
|
||||
# An output formatter used internally by the lexer.
|
||||
module Notifier
|
||||
extend Exception2MessageMapper
|
||||
def_exception :ErrUndefinedNotifier,
|
||||
|
@ -20,59 +21,100 @@ module IRB
|
|||
def_exception :ErrUnrecognizedLevel,
|
||||
"unrecognized notifier level: %s is specified"
|
||||
|
||||
# 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, StdioOuputMethod 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
|
||||
|
||||
|
@ -80,17 +122,39 @@ module IRB
|
|||
@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
|
||||
|
@ -107,38 +171,61 @@ module IRB
|
|||
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
|
||||
D_NOMSG = NoMsgNotifier.new # :nodoc:
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,21 +12,25 @@
|
|||
require "e2mmap"
|
||||
|
||||
module IRB
|
||||
# OutputMethod
|
||||
# StdioOutputMethod
|
||||
|
||||
# An abstract output class for IO in irb. This is mainly used internally by
|
||||
# IRB::Notifier. You can define your own output method to use with Irb.new,
|
||||
# or Context.new
|
||||
class OutputMethod
|
||||
@RCS_ID='-$Id$-'
|
||||
|
||||
# Open this method to implement your own output method, raises a
|
||||
# NotImplementedError if you don't define #print in your own class.
|
||||
def print(*opts)
|
||||
IRB.fail NotImplementedError, "print"
|
||||
end
|
||||
|
||||
# Prints the given +opts+, with a newline delimiter.
|
||||
def printn(*opts)
|
||||
print opts.join(" "), "\n"
|
||||
end
|
||||
|
||||
# extend printf
|
||||
# Extends IO#printf to format the given +opts+ for Kernel#sprintf using
|
||||
# #parse_printf_format
|
||||
def printf(format, *opts)
|
||||
if /(%*)%I/ =~ format
|
||||
format, opts = parse_printf_format(format, opts)
|
||||
|
@ -34,16 +38,22 @@ module IRB
|
|||
print sprintf(format, *opts)
|
||||
end
|
||||
|
||||
# %
|
||||
# <flag> [#0- +]
|
||||
# <minimum field width> (\*|\*[1-9][0-9]*\$|[1-9][0-9]*)
|
||||
# <precision>.(\*|\*[1-9][0-9]*\$|[1-9][0-9]*|)?
|
||||
# #<length modifier>(hh|h|l|ll|L|q|j|z|t)
|
||||
# <conversion specifier>[diouxXeEfgGcsb%]
|
||||
# Returns an array of the given +format+ and +opts+ to be used by
|
||||
# Kernel#sprintf, if there was a successful Regexp match in the given
|
||||
# +format+ from #printf
|
||||
#
|
||||
# %
|
||||
# <flag> [#0- +]
|
||||
# <minimum field width> (\*|\*[1-9][0-9]*\$|[1-9][0-9]*)
|
||||
# <precision>.(\*|\*[1-9][0-9]*\$|[1-9][0-9]*|)?
|
||||
# #<length modifier>(hh|h|l|ll|L|q|j|z|t)
|
||||
# <conversion specifier>[diouxXeEfgGcsb%]
|
||||
def parse_printf_format(format, opts)
|
||||
return format, opts if $1.size % 2 == 1
|
||||
end
|
||||
|
||||
# Calls #print on each element in the given +objs+, followed by a newline
|
||||
# character.
|
||||
def puts(*objs)
|
||||
for obj in objs
|
||||
print(*obj)
|
||||
|
@ -51,17 +61,27 @@ module IRB
|
|||
end
|
||||
end
|
||||
|
||||
# Prints the given +objs+ calling Object#inspect on each.
|
||||
#
|
||||
# See #puts for more detail.
|
||||
def pp(*objs)
|
||||
puts(*objs.collect{|obj| obj.inspect})
|
||||
end
|
||||
|
||||
# Prints the given +objs+ calling Object#inspect on each and appending the
|
||||
# given +prefix+.
|
||||
#
|
||||
# See #puts for more detail.
|
||||
def ppx(prefix, *objs)
|
||||
puts(*objs.collect{|obj| prefix+obj.inspect})
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A standard output printer
|
||||
class StdioOutputMethod<OutputMethod
|
||||
# Prints the given +opts+ to standard output, see IO#print for more
|
||||
# information.
|
||||
def print(*opts)
|
||||
STDOUT.print(*opts)
|
||||
end
|
||||
|
|
|
@ -75,9 +75,13 @@ EOF
|
|||
eval("_=nil", @binding)
|
||||
end
|
||||
|
||||
# The Binding of this workspace
|
||||
attr_reader :binding
|
||||
# The top-level workspace of this context, also available as
|
||||
# <code>IRB.conf[:__MAIN__]</code>
|
||||
attr_reader :main
|
||||
|
||||
# Evaluate the given +statements+ within the context of this workspace.
|
||||
def evaluate(context, statements, file = __FILE__, line = __LINE__)
|
||||
eval(statements, @binding, file, line)
|
||||
end
|
||||
|
|
|
@ -12,9 +12,46 @@
|
|||
require "irb"
|
||||
require "irb/frame"
|
||||
|
||||
# An example printer for irb.
|
||||
#
|
||||
# It's much like the standard library PrettyPrint, that shows the value of each
|
||||
# expression as it runs.
|
||||
#
|
||||
# In order to use this library, you must first require it:
|
||||
#
|
||||
# require 'irb/xmp'
|
||||
#
|
||||
# Now, you can take advantage of the Object#xmp convenience method.
|
||||
#
|
||||
# xmp <<END
|
||||
# foo = "bar"
|
||||
# baz = 42
|
||||
# END
|
||||
# #=> foo = "bar"
|
||||
# #==>"bar"
|
||||
# #=> baz = 42
|
||||
# #==>42
|
||||
#
|
||||
# You can also create an XMP object, with an optional binding to print
|
||||
# expressions in the given binding:
|
||||
#
|
||||
# ctx = binding
|
||||
# x = XMP.new ctx
|
||||
# x.puts
|
||||
# #=> today = "a good day"
|
||||
# #==>"a good day"
|
||||
# ctx.eval 'today # is what?'
|
||||
# #=> "a good day"
|
||||
class XMP
|
||||
@RCS_ID='-$Id$-'
|
||||
|
||||
# Creates a new XMP object.
|
||||
#
|
||||
# The top-level binding or, optional +bind+ parameter will be used when
|
||||
# creating the workspace. See WorkSpace.new for more information.
|
||||
#
|
||||
# This uses the +:XMP+ prompt mode, see IRB@Customizing+the+IRB+Prompt for
|
||||
# full detail.
|
||||
def initialize(bind = nil)
|
||||
IRB.init_config(nil)
|
||||
#IRB.parse_opts
|
||||
|
@ -32,6 +69,17 @@ class XMP
|
|||
IRB.conf[:MAIN_CONTEXT] = @irb.context
|
||||
end
|
||||
|
||||
# Evaluates the given +exps+, for example:
|
||||
#
|
||||
# require 'irb/xmp'
|
||||
# x = XMP.new
|
||||
#
|
||||
# x.puts '{:a => 1, :b => 2, :c => 3}'
|
||||
# #=> {:a => 1, :b => 2, :c => 3}
|
||||
# # ==>{:a=>1, :b=>2, :c=>3}
|
||||
# x.puts 'foo = "bar"'
|
||||
# # => foo = "bar"
|
||||
# # ==>"bar"
|
||||
def puts(exps)
|
||||
@io.puts exps
|
||||
|
||||
|
@ -51,16 +99,22 @@ class XMP
|
|||
end
|
||||
end
|
||||
|
||||
# A custom InputMethod class used by XMP for evaluating string io.
|
||||
class StringInputMethod < IRB::InputMethod
|
||||
# Creates a new StringInputMethod object
|
||||
def initialize
|
||||
super
|
||||
@exps = []
|
||||
end
|
||||
|
||||
# Whether there are any expressions left in this printer.
|
||||
def eof?
|
||||
@exps.empty?
|
||||
end
|
||||
|
||||
# Reads the next expression from this printer.
|
||||
#
|
||||
# See IO#gets for more information.
|
||||
def gets
|
||||
while l = @exps.shift
|
||||
next if /^\s+$/ =~ l
|
||||
|
@ -71,6 +125,10 @@ class XMP
|
|||
l
|
||||
end
|
||||
|
||||
# Concatenates all expressions in this printer, separated by newlines.
|
||||
#
|
||||
# An Encoding::CompatibilityError is raised of the given +exps+'s encoding
|
||||
# doesn't match the previous expression evaluated.
|
||||
def puts(exps)
|
||||
if @encoding and exps.encoding != @encoding
|
||||
enc = Encoding.compatible?(@exps.join("\n"), exps)
|
||||
|
@ -85,10 +143,28 @@ class XMP
|
|||
@exps.concat exps.split(/\n/)
|
||||
end
|
||||
|
||||
# Returns the encoding of last expression printed by #puts.
|
||||
attr_reader :encoding
|
||||
end
|
||||
end
|
||||
|
||||
# A convenience method that's only available when the you require the IRB::XMP standard library.
|
||||
#
|
||||
# Creates a new XMP object, using the given expressions as the +exps+
|
||||
# parameter, and optional binding as +bind+ or uses the top-level binding. Then
|
||||
# evaluates the given expressions using the +:XMP+ prompt mode.
|
||||
#
|
||||
# For example:
|
||||
#
|
||||
# require 'irb/xmp'
|
||||
# ctx = binding
|
||||
# xmp 'foo = "bar"', ctx
|
||||
# #=> foo = "bar"
|
||||
# #==>"bar"
|
||||
# ctx.eval 'foo'
|
||||
# #=> "bar"
|
||||
#
|
||||
# See XMP.new for more information.
|
||||
def xmp(exps, bind = nil)
|
||||
bind = IRB::Frame.top(1) unless bind
|
||||
xmp = XMP.new(bind)
|
||||
|
|
Loading…
Reference in a new issue