Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # encoding: utf-8
- if defined?(Encoding) then
- Encoding.default_external = 'utf-8'
- Encoding.default_internal = 'utf-8'
- else
- $KCODE = 'utf-8'
- end
- ENV["LANG"] = 'en_US.UTF-8'
- begin
- # Compatibility stuff
- unless IRB.conf[:AT_EXIT]
- IRB.conf[:AT_EXIT] = []
- Kernel.at_exit do
- IRB.conf[:AT_EXIT].each do |hook|
- hook.call
- end
- end
- end
- ## Some stuff I commonly use
- # Ok, I usually hate that and prefer plain requires, but due to begin/rescue for each of it, I'll do it this way
- %w[
- pp
- awesome_print
- yaml
- enumerator
- readline
- ].each do |path|
- begin
- require path
- rescue LoadError
- warn "Failed to load #{path.inspect} in #{__FILE__}:#{__LINE__-2}" if $VERBOSE
- end
- end
- module IRBUtilities; module_function
- MethodMethod = Object.instance_method(:method)
- MethodInstanceMethod = Module.instance_method(:instance_method)
- MethodIsA = Object.instance_method(:is_a?)
- MethodIsDescendant = Module.instance_method(:<)
- def self._method(obj, *args, &block)
- MethodMethod.bind(obj).call(*args, &block)
- end
- def self._instance_method(obj, *args, &block)
- MethodInstanceMethod.bind(obj).call(*args, &block)
- end
- def self._is_a?(obj, klass)
- MethodIsA.bind(obj).call(klass)
- end
- def self._is_descendant?(obj, klass)
- MethodIsDescendant.bind(obj).call(klass)
- end
- def pretty_print_methods(obj, meths)
- descs = meths.map { |n, m|
- i = 0
- params = m.parameters.map { |type, name|
- case type
- when :req then name || "arg#{i+=1}"
- when :opt then "#{name || "arg#{i+=1}"}=?"
- when :rest then "*#{name || "rest"}"
- when :block then "&#{name || "block"}"
- else "??"
- end
- }
- [" #{n}(#{params.join(", ")})", m.source_location ? m.source_location.join(':') : '[native]']
- }
- width = descs.map { |a,b| a.size }.max
- descs.each do |a,b|
- $stdout.printf "%-*s %s\n", width, a, b
- end
- descs.size
- end
- end
- ## Load history
- module IRBHistory
- @history_file = File.expand_path('~/.irb_session_history')
- @max_sessions = 20
- @max_lines_per_session = 1000
- @max_lines = 10000
- @sessions = {}
- @history = []
- @current_history = nil
- @current_wd = File.expand_path('.')
- @current_ruby = "#{defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'}-#{RUBY_VERSION}".gsub(/\s+/, '_')
- @current_ppid = Process.ppid
- @current_key = [@current_ppid, @current_wd, @current_ruby]
- class <<self
- attr_reader :sessions, :history_file, :history, :current_history
- attr_reader :max_sessions, :max_lines_per_session, :max_lines
- attr_reader :current_wd, :current_ruby, :current_ppid, :current_key
- end
- def self.push(line)
- @current_history.push([Time.now.to_i, line])
- @current_history.shift if @current_history.length > @max_lines
- end
- def self.restore
- read_history_log
- restore_history
- restore_readline_history
- end
- def self.read_history_log
- sessions = {}
- lost = []
- current = lost
- if File.exist?(@history_file) then
- File.foreach(@history_file).each_with_index do |line, line_no|
- if /^\# session time=(\d+), ppid=(\d+), ruby=(\S+), cwd=(.*)$/ =~ line then
- time, ppid, ruby, cwd = $1, $2, $3, $4
- current.replace(current.first(@max_lines_per_session)) # truncate array
- time = time.to_i
- ppid = ppid.to_i
- current = []
- session_key = [ppid, cwd, ruby]
- sessions[session_key] = [time, current]
- elsif /^(\d+) (.*)$/ =~ line then
- time, code = $1, $2
- current << [time.to_i, code]
- else
- warn "Malformed line #{line_no+1}: #{line.inspect}"
- end
- end
- warn "#{lost.size} log lines without session" unless lost.empty?
- current.replace(current.first(@max_lines_per_session)) # truncate array
- end
- sessions[@current_key] ||= [Time.now.to_i, []]
- sorted = sessions.sort_by { |key, (time, lines)| time }
- @sessions = Hash[sorted.last(@max_sessions)]
- @current_history = @sessions[@current_key] ? @sessions[@current_key].last : []
- nil
- end
- def self.restore_history
- @history = []
- @sessions.sort_by { |(ppid, cwd, ruby), (time, lines)|
- [
- ppid == @current_ppid ? 1 : 0, # matching ppid later (latest means first in history)
- cwd == @current_wd ? 1 : 0, # matching working directory later
- time # newer ones later
- ]
- # }.select { |(ppid, cwd, ruby), (time, lines)|
- # ruby == @current_ruby
- }.each do |(ppid, cwd, ruby), (time, lines)|
- @history.concat(lines)
- end
- @history.replace(@history.first(@max_lines)) # truncate
- end
- def self.restore_readline_history
- Readline::HISTORY.clear
- Readline::HISTORY.push(*@history.map(&:last))
- end
- def self.save
- return unless @current_history
- save_history = @current_history.first(@max_lines_per_session)
- @sessions.replace({@current_key => [Time.now.to_i, save_history]}.merge(@sessions))
- File.open(@history_file, 'a+:binary') do |fh|
- fh.flock(File::LOCK_EX)
- fh.truncate(0)
- @sessions.each do |(ppid, cwd, ruby), (time, lines)|
- fh.puts "\# session time=#{time}, ppid=#{ppid}, ruby=#{ruby}, cwd=#{cwd}"
- lines.each do |line_time, line|
- fh.puts("#{line_time} #{line}")
- end
- end
- end
- end
- # utility function
- def self.sort_hash_by!(hash, &block)
- hash.replace(Hash[hash.sort_by(&block)])
- end
- end
- if defined? Readline then
- # Compat
- unless Readline::HISTORY.respond_to? :clear
- hist = Readline::HISTORY
- def hist.clear
- length.times do pop end
- end
- end
- IRBHistory.restore
- IRB.conf[:AT_EXIT] << proc { IRBHistory.save }
- module IRB
- begin
- require "readline"
- ::NBSP = "\302\240"
- require 'irb/completion'
- class ReadlineInputMethod < InputMethod
- def gets
- if l = readline(@prompt, false)
- l.gsub!(/\302\240/, "") # this line does the trick - it's for poor swiss people who have {|} on opt-<key> combo, which means that pressing opt too early or releasing it too late you generate a non-breaking space (opt-space) which causes a syntax error
- HISTORY.push(l) unless l.empty?
- IRBHistory.push(l)
- @line[@line_no += 1] = "#{l}\n"
- else
- @eof = true
- l
- end
- end
- end
- Readline.completion_append_character = ""
- rescue LoadError
- end
- end
- end
- ## A couple of core patches to make life in IRB a little bit nicer
- alias q exit
- module OriginalInspect
- def irb_inspect
- inspect
- end
- def self.wrap(klass)
- klass.class_eval do
- alias original_inspect inspect
- def inspect
- r = original_inspect
- r.extend OriginalInspect
- r
- end
- end
- end
- end
- class Object
- def eigenclass
- class<<self;self;end
- end
- def eigendef(*a,&b)
- eigenclass.send(:define_method, *a, &b)
- end
- def __m
- meths = methods-Object.instance_methods
- meths -= Enumerable.instance_methods if IRBUtilities._is_a?(self, Enumerable)
- meths.sort
- end
- if Method.method_defined? :parameters then
- def __mx
- IRBUtilities.pretty_print_methods(self, __m.map { |m| [m, IRBUtilities._method(self, m)] })
- end
- else
- def __mx
- warn "__mx requires Method#parameters"
- __m
- end
- end
- def i
- $stdout.puts inspect
- self
- end
- def ii
- $stdout.puts pretty_inspect
- self
- end
- def irb_inspect
- original = inspect
- if original.length > 100 then
- $stdout.sprintf "#<%p %s>", self.class, instance_variables.join(" ")
- else
- original
- end
- rescue
- "<<could not inspect object>>"
- end
- end
- class Module
- def __im
- meths = instance_methods-Object.instance_methods
- meths -= Enumerable.instance_methods if IRBUtilities._is_descendant?(self, Enumerable)
- meths.sort
- end
- if Method.method_defined? :parameters then
- def __imx
- IRBUtilities.pretty_print_methods(self, __im.map { |m| [m, IRBUtilities._instance_method(self, m)] })
- end
- else
- def __imx
- warn "__imx requires Method#parameters"
- __im
- end
- end
- def __m
- if self.equal?(Module)
- super
- else
- meths = methods-Module.methods
- meths -= Enumerable.instance_methods if IRBUtilities._is_a?(self, Enumerable)
- meths.sort
- end
- end
- end
- class String
- # Convenience method, see Regexp#show_match
- def show_match(regex)
- regex.show_match(self)
- end
- OriginalInspect.wrap(self)
- # def irb_inspect
- # if length <= 100 then
- # original_inspect
- # else
- # sub(/\A(.{89}).*(.{10})/m, '\1…\2').original_inspect
- # end
- # end
- end
- class Array
- OriginalInspect.wrap(self)
- def irb_inspect
- if size <= 100 then
- "[#{map(&:irb_inspect).join(', ')}]"
- else
- "[#{first(89).map(&:irb_inspect).join(', ')}, …, #{last(10).map(&:irb_inspect).join(', ')}]"
- end
- end
- end
- class Hash
- OriginalInspect.wrap(self)
- def irb_inspect
- if size <= 100 then
- "{#{map{|k,v| "#{k.irb_inspect} => #{v.irb_inspect}"}.join(', ')}}"
- else
- ary = to_a
- "{#{ary.first(89).map{|k,v| "#{k.irb_inspect} => #{v.irb_inspect}"}.join(', ')}, …, " \
- "#{ary.last(10).map{|k,v| "#{k.irb_inspect} => #{v.irb_inspect}"}.join(', ')}}"
- end
- end
- end
- module Enumerable
- def __m
- (methods-Object.methods-Enumerable.instance_methods).sort
- end
- end
- module Kernel
- module_function
- # Prints memory and cpu footprint of the server (uses ps in a subshell,
- # portability is therefore limited)
- def print_resource_usage
- ps_out = `ps -o vsz,rss,%cpu,%mem -p #{$$}`
- vsz, rss, cpu, pmem = ps_out.scan(/\d+(?:[.,]\d+)?/).map { |e| e.gsub(/,/,'.').to_f } # ps on 10.5.1 outputs ',' instead of '.' for MEM%
- virtual, real = (vsz-rss).div(1024), rss.div(1024)
- $stdout.printf "%dMB real, %dMB virtual, %.1f%% CPU, %.1f%% MEM\n", real, virtual, cpu, pmem
- end
- # Terminate the current process - the hard way
- def t!
- `kill -9 #{$$}`
- end
- # write data to a file
- def putf(content, path='~/Desktop/irb_dump.txt')
- File.open(File.expand_path(path), 'w') { |fh| fh.write(content) }
- end
- # tiny bench method
- def bench(n=100, runs=10)
- n = n.to_i
- t = []
- runs.times do
- a = Time.now
- for i in 1..n
- yield
- end
- t << (Time.now-a)*1000/n
- end
- mean = t.inject { |a,b| a+b }.quo(t.size)
- stddev = t.map { |a| (a-mean)**2 }.inject { |a,b| a+b }.quo(t.size)**0.5
- [mean, stddev]
- end
- # tiny bench method with nice printing
- def pbench(n=1, runs=5, &b)
- m, s = *bench(n,runs,&b)
- p = (100.0*s)/m
- $stdout.printf "ø %fms (%.1f%%)\n", m, p
- end
- # tiny bench method with nice printing,
- # runs multiple tests
- def mbench(n, runs, benches)
- label_width = benches.keys.max_by(&:length).length+1
- measures = []
- benches.each do |label, b|
- m, s = *bench(n,runs,&b)
- p = (100.0*s)/m
- measures << [label, m]
- $stdout.printf "%-*s ø %fms (%.1f%%)\n", label_width, "#{label}:", m, p
- end
- measures.sort_by! { |l,m| m }
- rel = measures.first.last
- $stdout.puts measures.map { |l,m| sprintf "%s: %.1f", l, m/rel }.join(', ')
- nil
- end
- module PasswordString
- def inspect; "[PASSWORD]"; end
- def to_s; "[PASSWORD]"; end
- def dup; obj=super;obj.extend PasswordString; obj; end
- def clone; obj=super;obj.extend PasswordString; obj; end
- end
- def password
- `stty -echo`
- r = gets.chomp
- r.extend PasswordString
- r
- ensure
- `stty echo`
- end
- alias secret password
- # 1.9's p/pp return the arguments -> sucks in irb. let it return nil again.
- def p(*args)
- puts(args.map{|a|a.inspect})
- nil
- end
- def pp(*args)
- PP.pp(*args)
- nil
- end
- # Invoke an original method on an object that possibly overrides, fakes or removes it
- # Example:
- # cm some_obj, :inspect, Object
- # Object.instance_method(:inspect).bind(some_obj).call # is what that does
- def cm(obj, meth, klass=Object)
- klass.instance_method(meth).bind(obj).call
- end
- end
- class Regexp
- # Convenience method on Regexp so you can do
- # /an/.show_match("banana") # => "b<<an>>ana"
- def show_match(str)
- self =~ str
- "#{$`}<<#{$&}>>#{$'}"
- end
- end
- # Support methods for beedit
- require 'shellwords'
- module ::BBedit
- def self.open(obj)
- case obj
- when ::String
- `bbedit #{obj.shellescape}`
- when ::Method, ::UnboundMethod
- file, line = obj.source_location
- if file && File.readable?(file) then
- `bbedit #{file.shellescape}:#{line}`
- else
- "Can't open native method"
- end
- end
- end
- end
- module ::Sublime
- def self.open(obj)
- case obj
- when ::String
- `subl #{obj.shellescape}`
- when ::Method, ::UnboundMethod
- file, line = obj.source_location
- if file && File.readable?(file) then
- `subl #{file.shellescape}:#{line}`
- else
- "Can't open native method"
- end
- end
- end
- end
- class ::Method
- def bbedit
- BBedit.open(self)
- end
- def subl
- Sublime.open(self)
- end
- end
- class ::UnboundMethod
- def bbedit
- BBedit.open(self)
- end
- def subl
- Sublime.open(self)
- end
- end
- class ::Object
- def bbedit(name)
- method(name).bbedit
- end
- def subl(name)
- method(name).subl
- end
- end
- ## Configure IRB
- ruby = ENV["rvm_ruby_string"] || "#{defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'}-#{RUBY_VERSION}"
- prompt = {
- :PROMPT_I => "\001\e[42m\002 \001\e[0m\002 #{ruby}:%03n:%i>> ", # default prompt
- :PROMPT_S => "\001\e[42m\002 \001\e[0m\002 #{ruby}:%03n:%i%l> ", # known continuation
- :PROMPT_C => "\001\e[42m\002 \001\e[0m\002 #{ruby}:%03n:%i>> ",
- :PROMPT_N => "\001\e[42m\002 \001\e[0m\002 #{ruby}:%03n:%i*> ", # unknown continuation
- :RETURN => "\001\e[42m\002 \001\e[0m\002 # => %s\n",
- }
- #IRB.conf[:INSPECT_MODE] = "{ |obj| obj.irb_inspect }" # use that code to generate the reply-line
- IRB.conf[:INSPECT_MODE] = :inspect
- IRB.conf.delete(:AUTO_INDENT) # irb checks for presence, not content... stupid
- IRB.conf[:PROMPT][:APEIROS] = prompt
- IRB.conf[:PROMPT_MODE] = :APEIROS
- ## Load railsrc
- if defined?(Rails) then
- rails_rc = File.expand_path('~/.railsrc')
- load rails_rc if File.exist?(rails_rc)
- end
- rescue => e
- $stdout.puts e, *e.backtrace.first(5)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement