Guest User

Untitled

a guest
Sep 24th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.61 KB | None | 0 0
  1. #!/usr/bin/env ruby
  2. # -*- coding: utf-8 -*-
  3.  
  4. require 'colorful_inspect'
  5. require 'term/ansicolor'
  6.  
  7. class String
  8. include Term::ANSIColor
  9. end
  10.  
  11. Pry.print = proc do |output, value|
  12. begin
  13. output.puts "=> #{value.pretty_inspect.chomp}"
  14. rescue Exception => e
  15. output.puts "=> (unknown: #{e})"
  16. end
  17. end
  18.  
  19. prompt = Proc.new do |target_self, nest_level, pry|
  20. if pry
  21. "pry(#{Pry.view_clip(target_self)}):#{pry.input_array.size}> "
  22. else
  23. "pry(#{Pry.view_clip(target_self)})> "
  24. end
  25. end
  26.  
  27. Pry.prompt = [prompt, prompt]
  28.  
  29. Pry.exception_handler = proc do |output, ex|
  30. output.puts "#{ex.class.name.red.bold}: #{ex.message.italic}"
  31. output.puts " from #{ex.backtrace.first}"
  32. end
  33.  
  34. Pry.pager = false
  35.  
  36. Pry.config.auto_indent = false
  37. Pry.config.correct_indent = false
  38.  
  39. begin
  40. require 'coolline'
  41.  
  42. Pry.config.input = Coolline.new do |cool|
  43. cool.word_boundaries = [" ", "\t", ",", ";", ".", '"', "'", "`", "<", ">",
  44. "=", ";", "|", "{", "}", "(", ")", "-"]
  45.  
  46. cool.history_file = Coolline::NullFile
  47.  
  48. cool.transform_proc = proc do
  49. CodeRay.scan(cool.line, :ruby).term
  50. end
  51. end
  52. rescue LoadError
  53. end if ENV["TERM"] != "dumb"
  54.  
  55. # Custom commands
  56.  
  57. require 'slop'
  58.  
  59. module LsHelpers
  60. def strip_colors_if_needed(str)
  61. Pry.color ? str : strip_color(str)
  62. end
  63.  
  64. def pretty(obj)
  65. strip_colors_if_needed(obj.pretty_inspect.chomp)
  66. end
  67.  
  68. def variables(scope, reg, verbose)
  69. var_array = target.eval("#{scope}_variables").grep(reg)
  70.  
  71. if verbose
  72. var_hash = {}
  73.  
  74. var_array.each do |name|
  75. var_hash[name.to_sym] = target.eval(name.to_s)
  76. end
  77.  
  78. var_hash
  79. else
  80. var_array
  81. end
  82. end
  83.  
  84. def constant_list(reg, verbose)
  85. const_array = target.eval("constants").grep(reg)
  86.  
  87. if verbose
  88. const_hash = {}
  89.  
  90. const_array.each do |name|
  91. const_hash[name.to_sym] = target.eval("self").const_get(name)
  92. end
  93.  
  94. const_hash
  95. else
  96. const_array
  97. end
  98. end
  99.  
  100. def method_info(method)
  101. args = ''
  102.  
  103. if method.respond_to?(:parameters) && (arg_ary = method.parameters)
  104. arg_ary.map!.each_with_index do |(type, name), index|
  105. name ||= "arg#{index + 1}"
  106.  
  107. case type
  108. when :req then "#{name}"
  109. when :opt then "#{name} = ?"
  110. when :rest then "*#{name}"
  111. when :block then "&#{name}"
  112. else name
  113. end
  114. end
  115.  
  116. args = '(' + arg_ary.join(', ') + ')'
  117. elsif method.arity == 0
  118. args = "()"
  119. elsif method.arity > 0
  120. n = method.arity
  121. args = '(' + (1..n).map { |i| "arg#{i}" }.join(", ") + ')'
  122. elsif method.arity < 0
  123. n = -method.arity
  124. args = '(' + (1..n).map { |i| "arg#{i}" }.join(", ") + ')'
  125. end
  126.  
  127. klass = if method.respond_to? :owner
  128. method.owner.name
  129. elsif method.inspect =~ /Method: (.*?)#/
  130. $1
  131. end
  132.  
  133. location = if method.respond_to? :source_location
  134. file, line = method.source_location
  135. "#{file}:#{line}" if file && line
  136. end
  137.  
  138. [method.name.to_s, args, klass.to_s, location]
  139. end
  140.  
  141. def print_method_list(output, methods, regexp, more, verbose, &block)
  142. methods -= Object.instance_methods unless more
  143.  
  144. methods = methods.grep(regexp)
  145.  
  146. data = methods.sort.map do |name|
  147. method_info(yield name)
  148. end
  149.  
  150. max_name = data.map { |item| item[0].size }.max
  151. max_args = data.map { |item| item[1].size }.max
  152. max_klass = data.map { |item| item[2].size }.max
  153.  
  154. data.each do |(name, args, klass, location)|
  155. str = " #{yellow(name.rjust(max_name))}"
  156. str << args.ljust(max_args).blue
  157. str << " #{gray(klass.ljust(max_klass))}"
  158. str << " (#{location})" if verbose && location
  159.  
  160. output.puts str
  161. end
  162. end
  163.  
  164. def italic(string)
  165. Pry.color ? "\033[#{3}m#{string}\033[0m" : string
  166. end
  167.  
  168. def yellow(string)
  169. Pry.color ? "\033[1;#{33}m#{string}\033[0m" : string
  170. end
  171.  
  172. def gray(string)
  173. Pry.color ? "\033[1;#{37}m#{string}\033[0m" : string
  174. end
  175. end
  176.  
  177. module YriHelpers
  178. def wrap_text(text, columns = 80)
  179. text = text.dup
  180. res = []
  181.  
  182. while text.length > columns
  183. if text[0, columns] =~ /^(.+\s)(\S+)$/
  184. res << $1
  185. text = $2 + text[columns..-1]
  186. else
  187. res << text[0, columns]
  188. text[0...columns] = ''
  189. end
  190. end
  191.  
  192. res << text
  193. res
  194. end
  195.  
  196. def signature_for(info)
  197. sig = "#{info.name.to_s.cyan}(" + info.parameters.map { |(param, default)|
  198. if default
  199. "#{param} = #{default}"
  200. else
  201. param
  202. end
  203. }.join(", ") + ")"
  204.  
  205. if yield_tag = info.tag("yield")
  206. args = yield_tag.types ? yield_tag.types.join(", ") : ""
  207. args = "|#{args}| " unless args.empty?
  208.  
  209. sig << " { #{args}... }"
  210. end
  211.  
  212. type = (tag = info.tag("return")) ? tag.type : "Object"
  213. sig << " # => #{type.yellow}"
  214. end
  215.  
  216. def format_parameter(param)
  217. types = if param.types
  218. param.types.map { |o| o.yellow }.join(', ')
  219. else
  220. "Object"
  221. end
  222.  
  223. default = if param.respond_to? :defaults and param.defaults
  224. " (default: #{param.defaults.join(", ")})"
  225. end
  226.  
  227. text = (param.text || "").gsub("\n", "\n" + " " * 6)
  228. " — (#{types}) #{param.name.bold}#{default} #{text}"
  229. end
  230.  
  231. def document_info(info, output)
  232. doc = info.docstring.split("\n")
  233. doc.each do |line|
  234. if line[0, 2] == " " * 2
  235. output.puts CodeRay.scan(line, :ruby).term
  236. else
  237. output.puts line
  238. end
  239. end
  240.  
  241. if deprecated = info.tag("deprecated")
  242. output.puts
  243. output.puts "#{'DEPRECATED:'.red.bold} #{deprecated.text}"
  244. end
  245.  
  246. if note = info.tag("note")
  247. output.puts
  248. output.puts "#{'NOTE:'.red.bold} #{note.text}"
  249. end
  250.  
  251. if abstract = info.tag("abstract")
  252. output.puts
  253. output.puts "#{'Abstract:'.bold} #{abstract.text}"
  254. end
  255.  
  256. unless info.tags("param").empty?
  257. output.puts
  258. output.puts "Parameters: ".italic
  259. info.tags("param").each do |param|
  260. output.puts format_parameter(param)
  261. end
  262. end
  263.  
  264. unless info.tags("option").empty?
  265. info.tags("option").group_by(&:name).each do |name, opts|
  266. output.puts
  267. output.puts "Options for #{name.bold}: ".italic
  268.  
  269. opts.each do |opt|
  270. output.puts format_parameter(opt.pair)
  271. end
  272. end
  273. end
  274.  
  275. if yield_tag = info.tag("yield")
  276. output.puts
  277. output.print "#{'Yields:'.bold.italic} "
  278. output.puts yield_tag.text.to_s.gsub("\n", "\n ")
  279.  
  280. unless info.tags("yieldparam").empty?
  281. output.puts
  282. output.puts "Block arguments: ".bold.italic
  283.  
  284. info.tags("yieldparam").each do |param|
  285. output.puts format_parameter(param)
  286. end
  287. end
  288.  
  289. if ret = info.tag("yieldreturn")
  290. output.print "Block returns: ".bold.italic
  291. output.print "(#{(ret.types || %w[Object]).join(', ')}) "
  292. output.puts ret.text.gsub("\n", "\n ")
  293. end
  294. end
  295.  
  296. unless info.tags("raise").empty?
  297. output.puts
  298. output.puts "Exceptions: ".bold
  299.  
  300. info.tags("raise").each do |tag|
  301. output.print " — #{(tag.types || %w[Object]).join(', ')}: ".italic
  302. output.puts tag.text
  303. end
  304. end
  305.  
  306. if ret = info.tag("return")
  307. output.print "Returns: ".bold.italic
  308. output.print "(#{(ret.types || %w[Object]).join(', ')}) "
  309. output.puts ret.text.to_s.gsub("\n", "\n ")
  310. end
  311.  
  312. unless info.tags("example").empty?
  313. info.tags("example").each do |ex|
  314. output.puts
  315. output.puts "Example: #{ex.name.bold}:".italic
  316.  
  317. code = " " + CodeRay.scan(ex.text, :ruby).term.gsub("\n", "\n ")
  318. output.puts code
  319. end
  320. end
  321.  
  322. unless info.tags("see").empty?
  323. output.puts
  324. output.puts "See also: ".bold
  325.  
  326. info.tags("see").each do |tag|
  327. output.puts " — #{tag.text}"
  328. end
  329. end
  330.  
  331. if author = info.tag("author")
  332. output.puts
  333. output.puts "#{'Author:'.bold} #{author.text}"
  334. end
  335. end
  336. end
  337.  
  338. Commands = Pry::CommandSet.new Pry::Commands do
  339. helpers do
  340. include YriHelpers
  341. include LsHelpers
  342. end
  343.  
  344. # Dependency check broken?
  345. # alias_command "gist", "gist-method"
  346.  
  347. # Confusing me
  348. alias_command "exit", "exit-all"
  349.  
  350. command "req" do |*args|
  351. args.each { |arg| require arg }
  352. end
  353.  
  354. command "ls", "List a lot of stuff" do |*args|
  355. show_help = args.empty?
  356.  
  357. opts = Slop.parse! args, :multiple_switches => true do
  358. on :v, :verbose, "Show value of variables and constants and locations of methods"
  359. on :L, :less, "Only show methods set by the receiver"
  360. on :a, :more, "Show all of the methods, including those defined in Object"
  361. on :f, :filter, "Regular expression to filter methods and variables",
  362. :optional => false, :default => ""
  363.  
  364. on :l, :locals, "Show local variables"
  365. on :g, :globals, "Show global variables"
  366. on :i, 'instance-variables', "Show instance variables"
  367. on :k, 'class-variables', "Show class variables"
  368.  
  369. on :c, :constants, "Show constants"
  370.  
  371. on :m, :methods, "Show methods"
  372. on :M, 'instance-methods', "Show instance methods"
  373.  
  374. on :h, :help, 'Print this help message', :tail => true
  375. end
  376.  
  377. if show_help || opts.help?
  378. puts opts.help
  379. next
  380. end
  381.  
  382. opts = opts.to_hash(true)
  383.  
  384. regexp = Regexp.new(opts[:filter], 'i')
  385.  
  386. unless args.empty?
  387. self.target = Pry.binding_for(target.eval(args.join(' ')))
  388. end
  389.  
  390. if opts[:locals]
  391. output.print italic("Local variables: ")
  392. output.puts pretty(variables(:local, regexp, opts[:verbose]))
  393. output.puts
  394. end
  395.  
  396. if opts[:globals]
  397. output.print italic("Global variables: ")
  398. output.puts pretty(variables(:global, regexp, opts[:verbose]))
  399. output.puts
  400. end
  401.  
  402. if opts[:"instance-variables"]
  403. output.print italic("Instance variables: ")
  404. output.puts pretty(variables(:instance, regexp, opts[:verbose]))
  405. output.puts
  406. end
  407.  
  408. if opts[:"class-variables"]
  409. output.print italic("Class variables: ")
  410.  
  411. if Module === target.eval('self')
  412. output.puts pretty(variables(:class, regexp, opts[:verbose]))
  413. else
  414. output.puts "(not a module)"
  415. end
  416.  
  417. output.puts
  418. end
  419.  
  420. if opts[:constants]
  421. output.print italic("Constant: ")
  422.  
  423. if Module === target.eval('self')
  424. output.puts pretty(constant_list(regexp, opts[:verbose]))
  425. else
  426. output.puts "(not a module)"
  427. end
  428.  
  429. output.puts
  430. end
  431.  
  432. if opts[:"instance-methods"]
  433. output.print italic("Instance methods: ")
  434.  
  435. if Module === target.eval('self')
  436. obj = target.eval("self")
  437.  
  438. output.puts
  439. print_method_list(output, obj.instance_methods(!opts[:less]),
  440. regexp, opts[:more], opts[:verbose]) do |name|
  441. obj.instance_method(name)
  442. end
  443. else
  444. output.puts "(not a module)"
  445. end
  446.  
  447. output.puts
  448. end
  449.  
  450. if opts[:methods]
  451. output.puts italic("Methods: ")
  452.  
  453. obj = target.eval("self")
  454.  
  455. print_method_list(output, obj.methods(!opts[:less]),
  456. regexp, opts[:more], opts[:verbose]) do |name|
  457. obj.method(name)
  458. end
  459.  
  460. output.puts
  461. end
  462. end
  463.  
  464. command "yri", "Retrieve documentation from YARD" do |*args|
  465. opts = Slop.parse! args do
  466. on :m, "Use methods"
  467. on :M, "Use instance methods"
  468. on :s, :source, "Show source code"
  469. end
  470.  
  471. method_name = args.shift
  472. method = get_method_or_raise(method_name, target, opts.to_hash(true))
  473.  
  474. unless method
  475. output.puts "Could not find the method!"
  476. next
  477. end
  478.  
  479. info = Pry::MethodInfo.info_for(method)
  480.  
  481. unless info
  482. output.puts "Could not find the documentation!"
  483. next
  484. end
  485.  
  486. output.puts "-" * 80
  487. if (overloads = info.tags("overload")).size > 0
  488. overloads.each do |overload|
  489. output.puts wrap_text(signature_for(overload))
  490. end
  491. else
  492. output.puts wrap_text(signature_for(info))
  493. end
  494.  
  495. output.puts "-" * 80
  496.  
  497. document_info(info, output)
  498.  
  499. info.tags("overload").each do |overload|
  500. output.puts
  501. output.puts "-" * 80
  502. output.puts "#{"Overload:".bold.italic} #{signature_for(overload)}"
  503. output.puts "-" * 80
  504.  
  505. document_info(overload, output)
  506. end
  507.  
  508. if opts.source?
  509. output.puts
  510. output.puts "Source code: ".bold.italic
  511.  
  512. source = CodeRay.scan(info.source.to_s, info.source_type).term
  513. output.puts " " + source.gsub("\n", "\n ")
  514. end
  515. end
  516.  
  517. alias_command "ri", "yri"
  518.  
  519. alias_command "?", "show-input"
  520. end
  521.  
  522. Pry.commands = Commands
  523.  
  524. # Apeiros' benchmarking methods
  525.  
  526. # tiny bench method
  527. def bench(n=100, runs=10)
  528. n = n.to_i
  529. t = []
  530. runs.times do
  531. a = Time.now
  532. for _ in 1..n
  533. yield
  534. end
  535. t << (Time.now-a)*1000/n
  536. end
  537. mean = t.inject { |a,b| a+b }.quo(t.size)
  538. stddev = t.map { |a| (a-mean)**2 }.inject { |a,b| a+b }.quo(t.size)**0.5
  539. [mean, stddev]
  540. end
  541.  
  542. # tiny bench method with nice printing
  543. def pbench(n=1, runs=5, &b)
  544. m, s = *bench(n,runs,&b)
  545. p = (100.0*s)/m
  546. printf "ø %fms (%.1f%%)\n", m, p
  547. end
  548.  
  549. # tiny bench method with nice printing,
  550. # runs multiple tests
  551. def mbench(n, runs, benches)
  552. label_width = benches.keys.max_by(&:length).length+1
  553. measures = []
  554. benches.each do |label, b|
  555. m, s = *bench(n,runs,&b)
  556. p = (100.0*s)/m
  557. measures << [label, m]
  558. printf "%-*s ø %fms (%.1f%%)\n", label_width, "#{label}:", m, p
  559. end
  560.  
  561. measures.sort_by! { |l,m| m }
  562. rel = measures.first.last
  563. puts measures.map { |l,m| sprintf "%s: %.1f", l, m/rel }.join(', ')
  564. nil
  565. end
  566.  
  567. # Require current project
  568. $: << File.expand_path('.')
  569.  
  570. if File.directory? "lib"
  571. $:.unshift File.expand_path("./lib")
  572. $:.unshift File.expand_path("./ext") if File.directory? "ext"
  573.  
  574. begin
  575. require File.basename(Dir.pwd)
  576. rescue LoadError
  577. end
  578. end
Add Comment
Please, Sign In to add comment