1# 2# xmp.rb - irb version of gotoken xmp 3# $Release Version: 0.9$ 4# $Revision: 38515 $ 5# by Keiju ISHITSUKA(Nippon Rational Inc.) 6# 7# -- 8# 9# 10# 11 12require "irb" 13require "irb/frame" 14 15# An example printer for irb. 16# 17# It's much like the standard library PrettyPrint, that shows the value of each 18# expression as it runs. 19# 20# In order to use this library, you must first require it: 21# 22# require 'irb/xmp' 23# 24# Now, you can take advantage of the Object#xmp convenience method. 25# 26# xmp <<END 27# foo = "bar" 28# baz = 42 29# END 30# #=> foo = "bar" 31# #==>"bar" 32# #=> baz = 42 33# #==>42 34# 35# You can also create an XMP object, with an optional binding to print 36# expressions in the given binding: 37# 38# ctx = binding 39# x = XMP.new ctx 40# x.puts 41# #=> today = "a good day" 42# #==>"a good day" 43# ctx.eval 'today # is what?' 44# #=> "a good day" 45class XMP 46 @RCS_ID='-$Id: xmp.rb 38515 2012-12-21 05:45:50Z zzak $-' 47 48 # Creates a new XMP object. 49 # 50 # The top-level binding or, optional +bind+ parameter will be used when 51 # creating the workspace. See WorkSpace.new for more information. 52 # 53 # This uses the +:XMP+ prompt mode, see IRB@Customizing+the+IRB+Prompt for 54 # full detail. 55 def initialize(bind = nil) 56 IRB.init_config(nil) 57 #IRB.parse_opts 58 #IRB.load_modules 59 60 IRB.conf[:PROMPT_MODE] = :XMP 61 62 bind = IRB::Frame.top(1) unless bind 63 ws = IRB::WorkSpace.new(bind) 64 @io = StringInputMethod.new 65 @irb = IRB::Irb.new(ws, @io) 66 @irb.context.ignore_sigint = false 67 68# IRB.conf[:IRB_RC].call(@irb.context) if IRB.conf[:IRB_RC] 69 IRB.conf[:MAIN_CONTEXT] = @irb.context 70 end 71 72 # Evaluates the given +exps+, for example: 73 # 74 # require 'irb/xmp' 75 # x = XMP.new 76 # 77 # x.puts '{:a => 1, :b => 2, :c => 3}' 78 # #=> {:a => 1, :b => 2, :c => 3} 79 # # ==>{:a=>1, :b=>2, :c=>3} 80 # x.puts 'foo = "bar"' 81 # # => foo = "bar" 82 # # ==>"bar" 83 def puts(exps) 84 @io.puts exps 85 86 if @irb.context.ignore_sigint 87 begin 88 trap_proc_b = trap("SIGINT"){@irb.signal_handle} 89 catch(:IRB_EXIT) do 90 @irb.eval_input 91 end 92 ensure 93 trap("SIGINT", trap_proc_b) 94 end 95 else 96 catch(:IRB_EXIT) do 97 @irb.eval_input 98 end 99 end 100 end 101 102 # A custom InputMethod class used by XMP for evaluating string io. 103 class StringInputMethod < IRB::InputMethod 104 # Creates a new StringInputMethod object 105 def initialize 106 super 107 @exps = [] 108 end 109 110 # Whether there are any expressions left in this printer. 111 def eof? 112 @exps.empty? 113 end 114 115 # Reads the next expression from this printer. 116 # 117 # See IO#gets for more information. 118 def gets 119 while l = @exps.shift 120 next if /^\s+$/ =~ l 121 l.concat "\n" 122 print @prompt, l 123 break 124 end 125 l 126 end 127 128 # Concatenates all expressions in this printer, separated by newlines. 129 # 130 # An Encoding::CompatibilityError is raised of the given +exps+'s encoding 131 # doesn't match the previous expression evaluated. 132 def puts(exps) 133 if @encoding and exps.encoding != @encoding 134 enc = Encoding.compatible?(@exps.join("\n"), exps) 135 if enc.nil? 136 raise Encoding::CompatibilityError, "Encoding in which the passed expression is encoded is not compatible to the preceding's one" 137 else 138 @encoding = enc 139 end 140 else 141 @encoding = exps.encoding 142 end 143 @exps.concat exps.split(/\n/) 144 end 145 146 # Returns the encoding of last expression printed by #puts. 147 attr_reader :encoding 148 end 149end 150 151# A convenience method that's only available when the you require the IRB::XMP standard library. 152# 153# Creates a new XMP object, using the given expressions as the +exps+ 154# parameter, and optional binding as +bind+ or uses the top-level binding. Then 155# evaluates the given expressions using the +:XMP+ prompt mode. 156# 157# For example: 158# 159# require 'irb/xmp' 160# ctx = binding 161# xmp 'foo = "bar"', ctx 162# #=> foo = "bar" 163# #==>"bar" 164# ctx.eval 'foo' 165# #=> "bar" 166# 167# See XMP.new for more information. 168def xmp(exps, bind = nil) 169 bind = IRB::Frame.top(1) unless bind 170 xmp = XMP.new(bind) 171 xmp.puts exps 172 xmp 173end 174