pax_global_header00006660000000000000000000000064126075707170014526gustar00rootroot0000000000000052 comment=b41ff2437f270d11d3054d4688ea66b8fcd596a2 pry-0.10.3/000077500000000000000000000000001260757071700124215ustar00rootroot00000000000000pry-0.10.3/.gitignore000066400000000000000000000001751260757071700144140ustar00rootroot00000000000000Makefile *.so *.o *.def *.rbc *.bundle doc/ pkg/ coverage/ .yardoc/ /tags vendor *.gem .rbx/ .rvmrc Gemfile.lock *.swp **/*~ pry-0.10.3/.travis.yml000066400000000000000000000004541260757071700145350ustar00rootroot00000000000000rvm: - 1.9.2 - 1.9.3 - 2.0.0 - 2.1 - ruby-head - rbx-2 - jruby - jruby-head script: - rake spec matrix: allow_failures: - rvm: ruby-head - rvm: jruby-head notifications: irc: "irc.freenode.org#pry" recipients: - jrmair@gmail.com branches: only: - master pry-0.10.3/.yardopts000066400000000000000000000000571260757071700142710ustar00rootroot00000000000000--markup markdown --private --hide-void-return pry-0.10.3/CHANGELOG.md000066400000000000000000001026241260757071700142370ustar00rootroot00000000000000### 0.10.3 * cherry-pick 0d1d72b and e0e5c75 to fix the install of Pry on Windows. ### 0.10.2 * cherry-pick c2ed9ec135bd791a32c70fbe05cc0508ea17c4040e from master (fix inf. loop with prepended methods source retrieval) * Update some specs for recent ruby versions (2.2+) ### 0.10.1 * Fix bugs with jruby * Move to rspec for testing (from bacon) * Clean up ruby warnings ### 0.10.0 #### Features * Added a `watch` command that lets you see how values change over time. * Added an experimental `Pry.auto_resize!` method * Makes Pry notice that your window has resized and tell Readline about it * Fixes various bugs with command history after a window resize * Off by default, but can be called from your `.pryrc` if you're brave * `play` now has an `-e`/`--expression` flag * Evaluates until the end of the first valid expression * History gets appended to `~/.pry_history` after every input, not just at quit * Return values render with more accurate syntax highlighting * Return values start rendering immediately and stream into the pager * User can override `.pryrc` location by setting `$PRYRC` env var (#893) * User can whitelist objects whose inspect output should appear in prompt (#885) * See `Pry.config.prompt_safe_objects` * `whereami` is now aliased to `@` * Added arguments to `whereami`: * `-m` shows the surrounding method * `-c` shows the surrounding class * `-f` shows the entire file * Lazy load configuration values (Pry.config). (#1096) * Defer requiring `readline` until Pry is started for the first time. (#1117) * Add option to disable input completer through `_pry_.config.completer = nil` * Add `list-prompts` command. (#1175) * Lists the available prompts available for use. * Add `change-prompt` command. (#1175) * Switches the current prompt, by name. * Add `list-inspectors` command. (#1176) * Lists the inspectors available to print Ruby return values. * Add `change-inspector` command. (#1176) * Switches the current inspector, by name. * Add `show-source -e`. (#1185) * Evaluate the given Ruby expression and show the source of its return value. * Add `Pry.config.windows_console_warning`(#1218) * Windows JRuby users who don't want warnings about ansicon can set `Pry.config.windows_console_warning = false`. * Add arguments to `play` command. * `-p` prints the code before playing it. * `-e` allows you to play expressions from your session. * Add `cd -` to switch to the previous binding. * Allow prying into frozen objects. #### Dependency changes * Remove dependency on `ffi` gem on JRuby ([#1158](https://github.com/pry/pry/issues/1158)) * Remove optional dependency on Bond ([#1166](https://github.com/pry/pry/issues/1166)) * Bond support has been extracted to the `pry-bond` plugin * Remove dependency on `openstruct` ([#1096](https://github.com/pry/pry/issues/1096)) * Drop support for Ruby 1.8.7 (0.9.12.x will continue to be available) * Add support for Ruby 2.1 * Require Coderay `~> 1.1.0` * Remove deprecated hooks API ([#1209](https://github.com/pry/pry/pull/1209)) * Add 64-bit windows support. #### Bug fixes, etc. * The `gem-install` command can require gems like `net-ssh` thanks to better logic for guessing what path to require. (#1188) * `toggle-color` command toggles the local `_pry_.color` setting instead of the global `Pry.color`. * Update `Pry::CLIPPED_PRINT` to include a hex representation of object ID when printing a return value. (#1162) * Wrap exceptions in a proxy instead of adding singleton methods. (#1145) * `Pry#last_exception=` now supports exception objects that have been frozen. * `binding.pry` inside `.pryrc` file now works, with some limitations (@richo / #1118) * Add support for BasicObjects to `ls` (#984) * Allow `ls -c ` (#891) * Fix indentation not working if the `mathn` stdlib was loaded (#872) * Fix `hist`'s `--exclude-pry` switch (#874) * Fix `gem-install` on JRuby (#870) * Fix source lookup for instrumented classes (#923) * Improved thread safety when multiple instances are running (#944) * Make `edit` ignore `-n`/`--no-reload` flag and `disable_auto_reload` config in cases where the user was editing a tempfile * Make `gem-cd` use the most recent gem, not the oldest * Make `install-command` honor `.gemrc` switches (#666) * Make `hist` with no parameters show just the current session's history (#205) * `hist --all` shows older history * Make `-s`/`--super` flag of `show-source`/`show-doc` work when method name is being inferred from context (#877) * Rename `--installed-plugins` flag to `--plugins` * Strip ANSI codes from prompt before measuring length for indentation (#493) * Fix bug in `edit` regarding recognition of file names without suffix. * Reduced download size by removing tests etc. from distributed gem. #### Dev-facing changes * `CommandSet#commands`, sometimes referenced through `Pry.commands.commands`, renamed to `CommandSet#to_hash`. It returns a duplicate of the internal hash a CommandSet uses. * `CommandSet#keys` is now an alias of `CommandSet#list_commands`. * All commands should now reference configuration values via `_pry_.config` (local) and not `Pry.config` (global). (#1096) * This change improves support for concurrent environments and context-specific Pry sessions. `_pry_.config` inherits default values from `Pry.config` but can override them locally. * `rake pry` now accepts switches prefixed with `_` (e.g., `rake pry _v`) * Pagers now act like `IO`s and accept streaming output * See `_pry_.pager.page` and `_pry_.pager.open`. * The `Pry` class has been broken up into two smaller classes. * `Pry` represents non-UI-specific session state, including the eval string * `Pry::REPL` controls the user-facing interface * This should make it easier to drive Pry from alternative interfaces * `Pry.start` now has a `:driver` option that defaults to `Pry::REPL` * This involved a lot of refactoring and may break plugins that depend on the old layout * Add `ColorPrinter` subclass of `PP` for colorized object inspection * Add `[]` and `[]=` methods to `CommandSet`, which find and replace commands * Example: `Pry.commands["help"] = MyHelpCommand` * The completion API has been refactored (see fdb703a8de4ef3) * `Pry.config.input_stack` (and the input stack concept in general) no longer exists * There's a new `Pry::Terminal` class that implements a number of different methods of determining the terminal's dimensions * Add `ReplTester` class for high-level simulation of Pry sessions in tests * Add `Pry.main`. Returns the special instance of Object referenced by self of `TOPLEVEL_BINDING`: "main". * Changed second argument of `Pry.view_clip()` from Fixnum to Hash to support returning a string with or without a hex representation of object ID. (#1162) * The `output` and `pager` objects will now strip color-codes, so commands should always print in color. * Commands now have a `state` hash that is persistent across invocations of the command in the same pry session. ### 0.9.12.6 (2014/01/28) * Don't fail if Bond is not installed (#1106) ### 0.9.12.5 (2014/01/27) * Fix early readline errors by deferring require of readline (#1081, #1095) ### 0.9.12.4 (2013/11/23) * Fix issue with Coderay colors being black, even when on a black background (#1016) ### 0.9.12.3 (2013/09/11) * Bump Coderay dependency (#987) * Fix consecutive newlines in heredocs being collapsed (#962) * Fix pager not working in JRuby > 1.7.5 (#992) ### 0.9.12.2 (2013/05/10) * Make `reload-code` with no args reload "current" file (#920) ### 0.9.12.1 (2013/04/21) * Add workaround for JRuby crashing bug (#890) * Related to http://jira.codehaus.org/browse/JRUBY-7114 ### 0.9.12 (2013/02/12) #### Features * `pry --gem` (see 19bfc13aa) * `show-source` now works on commands created with `create_command` * `whereami` now has `-m` (method), `-c` (class), and `-f` (file) options * `show-source` now falls back to superclass (and displays warning) if it can't find class code * `show-source`/`show-doc` now indicate when `-a` option is available #### Bug fixes, etc. * Fix commands breaking due to Slop looking at `ARGV` instead of command parameters (#828) * Fix pager breaking in some situations (#845) * Fix broken rendering of some docs (#795) * Silence warnings during failed tab-completion attempts * Fix broken prompt when prompt is colored (#822 / #823) * Added `reload-method` as alias for `reload-code` (for backwards compatibility) * Reopen `Readline.output` if it is not a tty (see 1538bc0990) ### 0.9.11.4 (2013/01/20) * Fix pager not rendering color codes in some circumstances * Add `Pry.last_internal_error`, useful for devs debugging commands ### 0.9.11.3 (2013/01/17) * Fix `Pry.run_command` * Improve `ls` output * Add `:requires_gem => "jist"` to `gist` command (so dependencies can be installed via `install-command`) * Improve help for `edit` command ### 0.9.11.2 (2013/01/16) * Fix minor bug in `gist` on Windows: rescue `Jist::ClipboardError` rather than letting the scary error spill out to users and potentially having them think the gist didn't post. ### 0.9.11.1 (2013/01/16) * Fix minor bug in `gist` command where I neglected to remove a call to a non-existent method (`no_arg`) which was called when `gist` is invoked with no parameters ### 0.9.11 (2013/01/16) #### Dependency changes * Upgrade `slop` to `~> 3.4` * New optional dependency: `bond` * You'll need to perform `gem install bond` * It improves autocompletion if you use Readline * Does not work for libedit (More info: https://github.com/pry/pry/wiki/FAQ#wiki-readline) * Big thanks to cldwalker #### Features * Basic Ruby 2.0 support (#738) * JRuby 1.7.0+ support (#732) * New `reload-code` command * Reload code for methods, classes, commands, objects and so on * Examples: `reload-code MyClass`, `reload-code my_method`, `reload-code my_obj` * Bond tab completion (see "Dependency changes") * Consolidate "show" commands into `show-source` * `show-source` can now extract source for: * Classes * Methods * Procs * Pry commands * Arbitrary objects (it shows the source for the class of the object) * As a result, `show-command` is now removed * `gist`, `play`, and `save-file` now infer object type without requiring flags * Examples: `play MyClass`, `play my_file.rb`, `play my_method` * Consolidate editing commands into `edit` * `edit` can now edit: * Files * Methods * Classes * Pry commands * As a result, `edit-method` is now removed * Examples: `edit MyClass`, `edit my_file.rb`, `edit my_method` * `amend-line` and `play` now properly indent code added to input buffer * Support for multiple require switches (`pry -rubygems -r./a.rb`) (#674) * Support for multiple exec switches (`pry -e ':one' -e ':two'`) * Ability to customize the name displayed in the prompt (#695) * `--patch` switch for `edit --ex` command (#716) * Respect the `$PAGER` environment variable (#736) * `disable-pry` command (#497) * Two new hooks, `before_eval` and `after_eval` * Tab completion for `Array#` in `show-source` and `show-doc` * `gem-install` immediately requires gems * `-l` switch for `ls` command (displays local variables) * `gem-open` command * `fix-indent` command * Subcommands API * Public test API for plugin writers (see d1489a) * Tabular `ls` output * `--no-line-numbers` switch for `whereami` command * `--lines` switch for `play` command #### Bug fixes, etc. * Use single escape instead of double in `find-method` (#652) * Fix blank string delimiters (#657) * Fix unwanted `binding_impl_method` local in scratch bindings (#622) * Fix `edit-method -p` changing constant lookup (#645) * Fix `.pryrc` loading twice when invoked from `$HOME` directory (#682) * Fix Pry not remembering initial `pwd` (#675) * Fix multiline object coloring (#717) * Fix `show-method` not supporting `String::new` notation (#719) * Fix `whereami` command not showing correct line numbers (#754) * Fix buggy Cucumber AST output (#751) * Fix `while/until do` loops indentation (#787) * Fix `--no-plugins` switch (#526) * Ensure all errors go to the error handler (#774) * Fix `.pryrc` loading with wrong `__FILE__` * Fix pager not working if `less` is not available * Fix `^D` in nested REPL * Many small improvements to error message clarity and documentation formatting ### 0.9.10 (2012/07/04) #### Dependency changes * Upgrade `slop` to version 3 (#561) * Switch from `gist` gem to `jist` (#590) * Upgrade `method_source` to 0.8 #### Features * Add `--hist`, `-o` and `-k` flags to `gist` command (#572) * Support `show-source`/`show-doc` on methods defined in `class_eval` (#584) * Support `show-source`/`show-doc` on gem methods defined in C (#585) * Add `--disable-plugin` and `--select-plugin` options (#596) * Allow `cd -` to switch between bindings (#597) * Add `Pry.config.should_load_local_rc` to turn off `./.pryrc` (#612) * Allow running a file of Pry input with `pry ` * Support colours in `ri` command * Add `before_eval` hook * The prompt proc now gets a lot more data when its arity is 1 #### Bug fixes, etc. * Removed the `req` command (#554) * Fix rendering bugs when starting Pry (#567) * Fix `Array#pretty_print` on Jruby (#568) * Fix `edit` on Windows (#575) * Fix `find-method` in the presence of badly behaved objects (#576) * Fix `whereami` in ERb files on Rails (#580) * Raise fewer exceptions while tab completing (#632) * Don't immediately quit Pry when an error happens in Readline (#605) * Support for `ansicon` to give JRuby Windows users colour (#606) * Massive speed improvements to `show-source` for modules (#613) * Improve `whereami` command when not in a `binding.pry` (#620) * Support embedded documents (`=begin` ... `=end`) (#622) * Support editing files with spaces in the name (#627) * Renamed `__binding_impl__` to `__pry__` * Support for absolute paths in `$EDITOR` * Fix `cat` command on files with unknown extensions * Many, many internal refactorings and tidyings ### 0.9.9.6 (2012/05/09) * Fix `ZeroDivisionError` in `correct_indentation` (#558) ### 0.9.9.5 (2012/05/09) * Fix `ZeroDivisionError` in `correct_indentation` (#558) * Fix double highlighting in RDoc (#562) * Automatically create configuration for plugins (#548) ### 0.9.9.4 (2012/04/26) * Fix `NoMethodError: undefined method `winsize' for #>` (#549) * Fixes for JRuby * Fix syntax error on `exit` (550) * Heredoc content no longer auto-indented ### 0.9.9.3 (2012/04/19) * Fix `show-doc` failing on some core classes, like `Bignum` ### 0.9.9.2 (2012/04/18) * Make `correct_indentation`'s auto-colorization respect `Pry.color` ### 0.9.9.1 (2012/04/18) * Clear up confusion in `show-source`/`show-doc` docs * `-a` switch applies to classes as well as modules ### 0.9.9 (2012/04/18) #### New features * Lines of input are syntax highlighted upon Enter keypress * `show-source` command can now show class/module source code * Use `-a` to see all monkeypatches * Hard dependency on `ruby18_source_location` gem in MRI 1.8 * `show-doc` command can now show class/module docs * Use `-a` to see docs for all monkeypatches * Hard dependency on `ruby18_source_location` gem in MRI 1.8 * New `find-method` command * Performs a recursive search in a namespace for the existence of methods * Can find methods whose names match a regex or methods which contain provided code * This command is like a ruby-aware `grep`, very cool (thanks swarley) * [`pry-coolline`](https://github.com/pry/pry-coolline) now works properly * `alias_command` method now much more powerful * Example: `alias_command "lM", "ls -M"` * `whereami` is now more intelligent * Automatically shows entire source code of current method if current context is a method (thanks robgleeson) * New `raise-up` command * Allows you to raise an exception that will bubble out of pry (ending the session) and escape into enclosing program #### Bug fixes, etc. * Fixed crash when paging under Windows * Lines ending with `\` are incomplete (kudos to fowl) * `edit-method -n` no longer blocks (thanks misfo) * Show instance methods of modules by default in `ls` * Docs for REPL-defined methods can now be displayed using `show-doc` * Autoload `ruby18_source_location` on MRI 1.8, when available * See https://github.com/conradirwin/ruby18_source_location * Tab completion should work on first line now (historic bug fixed) * `:quiet => true` option added to `Pry.start`, turns off `whereami` * Another easter egg added * Show unloaded constants in yellow for `ls` * Improved documentation for `Pry.config` options * Improved auto-indentation * JRuby: heuristics used to clean up `ls` output * Fewer internal methods polluting output ### 0.9.8.4 (2012/6/3) * ~/.pry_history wasnt being created (if it did not exist)! FIXED * `hist --save` saved colors! FIXED * added Pry#add_sticky_local API for adding sticky locals to individual pry instances ### 0.9.8.3 (2012/3/2) * various tweaks to improve rbx support * commands now support optional block arguments * much improved help command * updated method_source dependencya * added wtf command * jruby should now work in windows (though without color) ### 0.9.8.2 (2012/2/9) * fixed bugs related to --super * upgraded slop dependency * added edit -c (edit current line) * edit now respects Pry.config.disable_autoreload option ### 0.9.8.1 (2012/1/30) * fixed broken --no-plugins option * Ensure ARGV is not mutated during option parsing. * Use a more rbx-friendly test for unicodeness * Use rbx-{18,19}mode as indicated http://about.travis-ci.org/docs/user/languages/ruby/ * Don't explode in gem-list [Fixes #453, #454] * Check for command-name collision on assignment [Fixes #450] ### 0.9.8 (2012/1/25) MAJOR NEW FEATURES - upgraded command api, https://github.com/pry/pry/wiki/Custom-commands - added a system of hooks for customizing pry behaviour - changed syntax checking to use eval() for improved accuracy - added save-file command - added gist command (removed gist-method, new gist command is more general) complete CHANGELOG: * CommandError's no longer cause the current input to be disgarded * Better syntax highlighting for rbx code code * added cat --in to show pry input history * prefixed temporary file names with 'pry' * show-doc now supports -l and -b options (line numbers) * play now supports -i and -d options * moved UserCommandAPI command-set to pry-developer_tools plugin * added :when_started event for hooks, called in Pry.start * added a man page * added rename method to Pry::CommandSet (commands can be renamed) * added CommandSet#{before_command,after_command} for enhancing builtin commands * added checking for namespace collisions with pry commands, set Pry.config.collision_warning * work around namespace collisions by ensuring lines starting with a space are executed as * ruby.work around namespace collisions by prensuring lines starting with a space are executed as ruby * added handlers for Ctrl+C (SIGINT) on jruby, these are now caught as in other ruby versions * removed dependency on ruby_parser * prevented colours leaking across the pry prompt * fixed edge cases in Pry::Method, for methods with crazy names and methods that have been 'undef'd * refactored history handling code for clarity and correctness * added Pry::WrappedModule as a counterpart to Pry::Method * made a trailing , cause pry to wait for further input * removed gist-method command, added gist command * added pry-backtrace command to show history of current session * fixed whereami within 'super' methods * replaced inline version guards by Pry::Helpers::BaseHelpers.{rbx?,jruby?,windows?} etc. * removed the CommandProcessor, its functionality is part of the new Command class * changed cd .. at the top level so it doesn't quit pry. * changed edit-command to no-longer need a command set argument * fixed empty lines so that they don't replace _ by nil * fixed SyntaxErrors at the REPL level so they don't replace _ex_. ### 0.9.7.4 (2011/11/5) * ls -M now works in modules (bugfix) * added exception msg for bad cd object/path * no longer die when encounter exceptions in .pryrc * baked in CoolLine support * Pry.config.input in .pryrc now respected ### 0.9.7.3 (2011/10/28) * really fixed indentation for 'super if' and friends * Fixed indentation for tmux * added Pry.config.correct_indent option (to toggle whether indentation * corrected optional param behaviour for method signatures: e.g Signature meth(param1=?, param2=?) ### 0.9.7.2 (2011/10/27) * fixed indentation for 'super if' and 'ensure', 'next if', etc * refactored Pry#run_command so it can accept an eval_string parameter (so amend-line and so on can work with it) * changed ^D so it no longer resets indent level automatically ### 0.9.7.1 (2011/10/26) * fixed gem dependecy issues ### 0.9.7 (2011/10/25) MAJOR NEW FEATURES: - upgraded ls command to have a more intuitive interface - added automatic indentation (thanks YorickPeterse!) - added Pry::Method wrapper class to encapsulate method-related functionality complete CHANGELOG: * fixed syntax highlighting for object literals * fixed ActiveSupport method-naming conflict with "in?" * added --super option to edit-method, show-method, and friends - making it easier to operate on superclass methods * officially added edit --in to open previous expressions in an editor * whereami now works for REPL-defined code * started using JRuby parser for input validation in JRuby (thanks pangloss!) * fixed bug where ~/.pryrc could be loaded more than once (thanks kelseyjudson!) * added parse_options! helper to pull option parsing out of commands * Pry now respects the terminal's input encoding * moved some requires out of the startup process for improved speed * added input_array info to DEFAULT_PROMPT, e.g [1] pry(main)> * added --no-history option to pry binary (prevent history being LOADED, history will still be saved) ### 0.9.6.2 (2011/9/27) * downgrading to CodeRay 0.9.8 due to problems with 1.0 and rails (autoloading problem) see #280 on pry and #6 on CodeRay * also added (as a minor feature) cirwin's implementation of edit --in * added early break/exit for objectpath errors (the 'cd 34/@hello/bad_path/23') ### 0.9.6 (2011/9/19) * restored previous behavior of command-line switches (allowing "-rfilename") * removed -p option (--play) from edit command * `edit` with no arguments now edits the current or most recent expression * `edit` auto-reloads .rb files (need to specify -n to suppress) * added -p option (--patch) to edit-method command, which allows monkeypatching methods without touching the original file * edit-method can now edit REPL-defined methods * cat --ex now works on exceptions in REPL-defined code * play -m now uses eval_string.replace() * play -m --open uses show-input to show play'd code * added "unindent" helper to make adding help to commands easier * local ./.pryrc now loaded after ~/.pryrc if it exists * cat --ex N and edit --ex N now can navigate through backtrace, where cat --ex (with no args) moves throuh successive levels of the backtrace automatically with state stored on the exceptino object itself * new option Pry.config.exception_window_size determines window size for cat --ex * input_stack now implemented - pushing objects onto a pry instance's input_stack causes the instance to read from those objects in turn as it encounters EOF on the previous object. On finishing the input_stack the input object for the pry instance is set back to Pry.config.input, if this fails, pry breaks out of the REPL (throw(:breakout)) with an error message * Pry.config.system() defines how pry runs system commands * now injecting target_self method into command scope * play now performs 'show-input' always unless eval_string contains a valid expression (i.e it's about to be eval'd) * play and hist --replay now push the current input object onto the input_stack before redirecting input to a StringIO (works much better with pry-remote now) ### 0.9.5 (2011/9/8) MAJOR NEW FEATURES: - JRuby support, including show-method/edit-method and editor integration on both 1.8 and 1.9 versions - extended cd syntax: cd ../@x/y - play command now works much better with _in_ array (this is a very powerful feature, esp with Pry::NAV_PROMPT) - history saving/loading is now lightning fast - 'edit' (entered by itself) now opens current lines in input buffer in an editor, and evals on exit - 'edit' command is also, in general more intelligent - ls output no longer in array format, and colors can be configured, e.g: Pry.config.ls.ivar_color = :bright_blue - new switch-to command for moving around the binding stack without exiting out of sessions - more sophisticated prompts, Pry::NAV_PROMPT to ease deep spelunking of code - major bug fix for windows systems - much better support for huge objects, should no longer hang pry (see #245) - cat --ex and edit --ex now work better complete CHANGELOG: * tempfile should end in .rb (for edit -t) * ls output should not be in array format * fix history saving (should not save all of Readline::HISTORY, but only what changed) * prevent blank lines going to Readline::HISTORY (thanks cirwin!) * ensure that cat --ex emulates the `whereami` format - includes line numbers and formatted the same, etc * fixed bug #200 ( https://github.com/pry/pry/issues/200 )- string interpolation bug (thanks to ryanf) * show-doc and stat now display method visibility (update WIKI) * got rid of warnings caused by stricter ruby 1.9.3 rules * remove interpolation of command names and fix interpolation error messag (update WIKI) (thanks ryanf!) * 'nested sessions' now use binding stacks (so each instance manages its own collection of bindings without spawning other instances) * 'cd ..' just pops a binding off the binding_stack with special behaviour when only one binding in stack - it breaks out of the repl loop * added switch-to command (like jump-to but doesnt unwind the stack) * show-method and show-doc now accept multiple method names * control_d hook added (Pry.config.control_d_handler) * behaviour of ^d is now to break out of current expr if in multi-line expr, or break out of current context if nested, or break out of pry repl loop if at top-level * can no longer interpolate command name itself e.g #{x}-#{y} where x = "show" and y = "doc" * ^C no longer captured * got rid of Pry.active_instance, Pry.last_exception and friends. * also special locals now shared among bindings in a pry instance (i.e _ex_ (and friends) re-injected into new binding entered with 'cd') * renamed inp and out to _in_ and _out_ (to avoid collisions with actual locals in debugging scope) * added third parameter to prompts, the pry instance itself (_pry) see https://github.com/pry/pry/issues/233 for why it's important * cd behaviour when no args performs the same as `cd /` * commands with keep_retval can now return nil (to suppress output now return 'void' instead) * Pry::CommandProcessor::Result introduced * Pry.view_clip() modified to be more robust and properly display Class#name * edit command when invoked with no args now works like edit -t * when edit is invoked (with no args or with -t) inside a multi-line expression input buffer, it dumps that buffer into a temp file and takes you to it * got rid of Pry#null_input? since all that was needed was eval_string.empty? * cd command now supports complex syntax: cd ../@y/y/../z * JRuby is no longer a 2nd class citizen, almost full JRuby support, passing 100% tests * added Pry::NAV_PROMPT (great new navigation prompt, per robgleeson) and Pry::SIMPLE_PRINT for simple (IRB-style) print output (just using inspect) * _pry_ now passed as 3rd parameter to :before_session hook * ls colors now configurable via Pry.config.ls.local_var_color = :bright_red etc * ls separator configurable via, e.g Pry.config.ls.separator = " " * Pry.view_clip() now only calls inspect on a few immediates, otherwise uses the #<> syntax, which has been truncated further to exclude teh mem address, again related to #245 ### 0.9.3 (2011/7/27) * cat --ex (cats 5 lines above and below line in file where exception was raised) * edit --ex (edits line in file where exception was raised) * edit -t (opens a temporary file and evals it in current context when closed) * `pry -r` requires now happen after plugin loading (so as not to interfere with * new Pry.config.disable_auto_reload option, for turning off auto reloading by edit-method and related (thanks ryanf) * add better error messages for `cd` command * fixed exotic object regression - BasicObject.new etc now return "=> unknown" * added reload-method command (reloads the associated file of a method) * converted: import => import-set, version => pry-version, install => install-command * Pry.config.command_prefix support (thanks ryanf!) * fixed indentation for simple-prompt * hist command now excludes last line of input (the command invocation itself) * hist now has `history` alias * missing plugins no longer raise exception, just print a warning to $stderr * fixed jedit editor support ### 0.9.2 (2011/6/21) * fixed string interpolation bug (caused valid ruby code not to execute, sorry!) * fixed `ls` command, so it can properly display members of Object and classes, and BasicObject, etc * added a few git related commands to experimental command set, blame and diff ### 0.9.0 (2011/6/17) * plugin system * regex commands * show-method works on methods defined in REPL * new command system/API * rubinius core support * more backports to ruby 1.8 * inp/out special locals * _ex_ backtrace navigation object (_ex_.line, _ex_.file) * readline history saving/loading * prompt stack * more hooks * amend-line * play * show-input * edit * much more comprehensive test suite * support for new and old rubygems API * changed -s behaviour of ls (now excludes Object methods) * removed eval-file, lls, lcd, and a few other commands ### 0.7.6.1 (2011/3/26) * added slightly better support for YARD * now @param and @return tags are colored green and markdown `code` is syntax highlighted using coderay ### 0.7.6 (2011/3/26) * `whereami` command now accepts parameter AROUND, to display AROUND lines on eitherside of invocation line. * made it so `whereami` is invoked even if no method exists in current context (i.e in rspec tests) * added rubinius support for `whereami` invocation in HOOKS by checking for __unknown__.rb rather than just
### 0.7.0 (2011/3/15) * add pry-doc support with syntax highlighting for docs * add 'mj' option to ls (restrict to singleton methods) * add _ex_ local to hold last exception raised in an exception ### 0.6.8 (2011/3/6) * add whereami command, a la the `ir_b` gem * make whereami run at the start of every session * make .pryrc be loaded by run-time pry sessions ### 0.6.7 (2011/3/4) * color support * --simple-prompt for pry commandline * -I mode for pry commandline * --color mode for pry commandline * clean up requires (put them all in one place) * simple-prompt command and toggle-color commandd. ### 0.6.3 (2011/2/28) * Using MethodSource 0.3.4 so 1.8 show-method support provided * `Set` class added to list of classes that are inspected ### 0.6.1 (2011/2/26) * !@ command alias for exit_all * `cd /` for breaking out to pry top level (jump-to 0) * made `-e` option work in a more effective way for `pry` command line invocation * exit and exit-all commands now accept a parameter, this parameter becomes the return value of repl() * `command` method from CommandBase now accepts a :keep_retval arg that determines if command value is returned to pry session or just `nil` (`nil` was old behaviour) * tests for new :keep_retval and exit-all/exit behaviour; :keep_retval will remain undocumented. ### 0.5.8 (2011/2/22) * Added -c (context) option to show-doc, show-methods and eval-file * Fixed up ordering issue of -c and -r parameters to command line pry ### 0.5.7 (2011/2/21) * Added pry executable, auto-loads .pryrc in user's home directory, if it exists. ### 0.5.5 (2011/2/19) * Added Pry.run_command * More useful error messages * Easter eggs (game and cohen-poem) ### 0.5.0 (2011/2/17) * Use clipped version of Pry.view() for large objects * Exit Pry session on ^d * Use Shellwords for breaking up parameters to pry commands * Use OptionParser to parse options for default pry commands * Add version command * Refactor 'status' command: add current method info * Add meth_name_from_binding utility lambda to commands.rb * Add -M, -m, -v(erbose), -a(ll), -s(uper), -l(ocals), -i(ivars), -k(klass vars), etc options to ls * add -M(instance method) options to show-method and show-doc * add --help option to most commands * Get rid of ls_method and ls_imethods (subsumed by more powerful ls) * Get rid of show_idoc and show_imethod * Add special eval-file command that evals target file in current context ### 0.4.5 (2011/1/27) * fixed show_method (though fragile as it references __binding_impl__ directly, making a name change to that method difficult ### 0.4.4 (2011/1/27) * oops, added examples/ directory ### 0.4.3 (2011/1/26) * added alias_command and desc methods to Pry::CommandBase * changed behaviour of ls_methods and ls_imethods to return sorted lists of methods ### 0.4.1 (2011/1/23) * made it so a 'def meth;end' in an object Pry session defines singleton methods, not methods on the class (except in the case of immediates) * reorganized documentation, moving customization to a separate wiki file * storing wiki in a nested git repo, as github wiki pages have their own repo * added more tests for new method definition behaviour ### 0.4.0 (2011/1/21) * added command API * added many new commands, i.e ls_methods and friends * modified other commands * now accepts greater customization, can modify: input, output, hooks, prompt, print object * added tab completion (even completes commands) * added extensive tests * added examples * many more changes ### 0.1.3 (2010/12/9) * Got rid of rubygems dependency, refactored some code. ### 0.1.2 (2010/12/8) * now rescuing SyntaxError as well as Racc::Parser error in valid_expression? ### 0.1.0 (2010/12/8) * release! pry-0.10.3/CONTRIBUTORS000066400000000000000000000034221260757071700143020ustar00rootroot00000000000000 1121 John Mair 505 Conrad Irwin 331 Ryan Fitzgerald 230 Kyrylo Silin 67 ☈king 54 Mon ouïe 51 Lee Jarvis 45 yui-knk 40 Jordon Bedwell 28 Yorick Peterse 18 David Palm 17 epitron 12 Andrew Vos 12 Shannon Skipper 11 Reginald Tan 10 Matt Carey 8 Trey Lawrence 8 Nicolas Viennot 8 Jason Laster 8 Eero Saynatkari 6 Deepender 5 Danielle Sucher 3 Richo Healey 3 Darrick Wiebe 3 WU Jun 3 fowlmouth 3 misfo 2 Ben Langfeld 2 Erik Michaels-Ober 2 Jonathan Jackson 2 Eric Christopherson 2 Uros Jurglic 2 Kelsey Judson 2 Ingrid 2 Jonathan Soeder 2 robgleeson 2 Bram Swenson 2 Uwe Stuehler 2 Vít Ondruch 2 Xavier Shay 1 ZPH 1 Zeh Rizzatti 1 hashrocketeer 1 shirmung 1 sonnym 1 Paul Chechetin 1 Alex Manelis 1 Andrey Ognevsky 1 Andy Monat 1 Ben Pickles 1 Christopher Sexton 1 Colin Shea 1 Danielle Sucher & Jason Laster 1 David Rodríguez 1 Eugene Diachkin 1 Geraud Puechaldou 1 Gerbert Olivé 1 Gosha Arinich 1 Greg Stearns 1 Havenwood 1 Ivo Wever 1 Janko Marohnić 1 Joe Peduto 1 Jonas Arvidsson 1 Jonathan Jackson and Travis Anderson 1 Jordan Running 1 Josh Adams 1 Josh Cheek 1 Kirill Lashuk 1 Kohei Suzuki 1 Larry Gilbert 1 Lars Haugseth 1 Loic Nageleisen 1 Matthew Carey 1 Michael Bensoussan 1 Michael Moore 1 Noah Davis 1 Patrick Ritchie 1 Aldric Giacomoni 1 Pradyumna 1 Renato Mascarenhas 1 René Föhring 1 Russell Jennings 1 Sean Bryant 1 Shawn Anderson 1 Sherin C 1 Sonali Sridhar 1 Tim Pope pry-0.10.3/Dockerfile000066400000000000000000000006161260757071700144160ustar00rootroot00000000000000FROM ubuntu:latest RUN apt-get update -y RUN apt-get install -y wget make git RUN wget --no-check-certificate -O ruby-install-0.4.3.tar.gz https://github.com/postmodern/ruby-install/archive/v0.4.3.tar.gz RUN tar -xzvf ruby-install-0.4.3.tar.gz RUN cd ruby-install-0.4.3 && make install RUN ruby-install ruby 1.9.3 RUN ruby-install ruby 2.1.1 RUN ruby-install ruby 2.1.2 ADD . /pry WORKDIR /pry pry-0.10.3/Gemfile000066400000000000000000000006221260757071700137140ustar00rootroot00000000000000source 'https://rubygems.org' gemspec gem 'rake', '~> 10.0' # For Guard group :development do gem 'gist' gem 'yard' gem 'rb-inotify', :require => false gem 'rb-fsevent', :require => false end group :test do gem 'rspec', '~> 3.0' end group :development, :test do gem 'simplecov', '~> 0.8' end platform :rbx do gem 'rubysl-singleton' gem 'rubysl-prettyprint' gem 'rb-readline' end pry-0.10.3/LICENSE000066400000000000000000000021211260757071700134220ustar00rootroot00000000000000License ------- (The MIT License) Copyright (c) 2013 John Mair (banisterfiend) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pry-0.10.3/README.md000066400000000000000000000354401260757071700137060ustar00rootroot00000000000000[![Build Status](https://img.shields.io/travis/pry/pry.svg)](https://travis-ci.org/pry/pry) [![Code Climate](https://img.shields.io/codeclimate/github/pry/pry.svg)](https://codeclimate.com/github/pry/pry) [![Inline docs](http://inch-ci.org/github/pry/pry.svg)](http://inch-ci.org/github/pry/pry)
![The Pry Logo](https://dl.dropbox.com/u/26521875/pry%20stuff/logo/pry_logo_350.png) © John Mair ([banisterfiend](https://twitter.com/banisterfiend)) 2013
**Please** [DONATE](http://www.pledgie.com/campaigns/15899) to the Pry project - Pry was a **huge** amount of work and every donation received is encouraging and supports Pry's continued development! **Sponsors** [Tealeaf Academy](http://www.gotealeaf.com)
[Atomic Object](http://www.atomicobject.com/)
[Hashrocket](http://hashrocket.com/)
[Intridea](http://intridea.com/)
[Gaslight](http://gaslight.co/home)
**Other Resources** [Skip to the website (recommended)](http://pry.github.com)
[Skip to the wiki](https://github.com/pry/pry/wiki)
Pry is a powerful alternative to the standard IRB shell for Ruby. It is written from scratch to provide a number of advanced features, including: * Source code browsing (including core C source with the pry-doc gem) * Documentation browsing * Live help system * Open methods in editors (`edit Class#method`) * Syntax highlighting * Command shell integration (start editors, run git, and rake from within Pry) * Gist integration * Navigation around state (`cd`, `ls` and friends) * Runtime invocation (use Pry as a developer console or debugger) * Exotic object support (BasicObject instances, IClasses, ...) * A Powerful and flexible command system * Ability to view and replay history * Many convenience commands inspired by IPython, Smalltalk and other advanced REPLs * A wide-range number of [plugins](https://github.com/pry/pry/wiki/Available-plugins) that provide remote sessions, full debugging functionality, and more. Pry also aims to be more than an IRB replacement; it is an attempt to bring REPL driven programming to the Ruby language. It is currently not as powerful as tools like [SLIME](http://en.wikipedia.org/wiki/SLIME) for lisp, but that is the general direction Pry is heading. Pry is also fairly flexible and allows significant user [customization](https://github.com/pry/pry/wiki/Customization-and-configuration) is trivial to set it to read from any object that has a `readline` method and write to any object that has a `puts` method - many other aspects of Pry are also configurable making it a good choice for implementing custom shells. Pry comes with an executable so it can be invoked at the command line. Just enter `pry` to start. A `.pryrc` file in the user's home directory will be loaded if it exists. Type `pry --help` at the command line for more information. Try `gem install pry-doc` for additional documentation on Ruby Core methods. The additional docs are accessed through the `show-doc` and `show-method` commands. * Install the [gem](https://rubygems.org/gems/pry): `gem install pry` * Browse the comprehensive [documentation at the official Pry wiki](https://github.com/pry/pry/wiki) * Read the [YARD API documentation](http://rdoc.info/github/pry/pry/master/file/README.markdown) * See the [source code](http://github.com/pry/pry) ### Commands Nearly every piece of functionality in a Pry session is implemented as a command. Commands are not methods and must start at the beginning of a line, with no whitespace in between. Commands support a flexible syntax and allow 'options' in the same way as shell commands, for example the following Pry command will show a list of all private instance methods (in scope) that begin with 'pa' pry(YARD::Parser::SourceParser):5> ls -Mp --grep ^pa YARD::Parser::SourceParser#methods: parse parser_class parser_type parser_type= parser_type_for_filename ### Navigating around state Pry allows us to pop in and out of different scopes (objects) using the `cd` command. This enables us to explore the run-time view of a program or library. To view which variables and methods are available within a particular scope we use the versatile [ls command.](https://gist.github.com/c0fc686ef923c8b87715) Here we will begin Pry at top-level, then Pry on a class and then on an instance variable inside that class: pry(main)> class Hello pry(main)* @x = 20 pry(main)* end => 20 pry(main)> cd Hello pry(Hello):1> ls -i instance variables: @x pry(Hello):1> cd @x pry(20):2> self + 10 => 30 pry(20):2> cd .. pry(Hello):1> cd .. pry(main)> cd .. The number after the `:` in the pry prompt indicates the nesting level. To display more information about nesting, use the `nesting` command. E.g pry("friend"):3> nesting Nesting status: 0. main (Pry top level) 1. Hello 2. 100 3. "friend" => nil We can then jump back to any of the previous nesting levels by using the `jump-to` command: pry("friend"):3> jump-to 1 => 100 pry(Hello):1> ### Runtime invocation Pry can be invoked in the middle of a running program. It opens a Pry session at the point it's called and makes all program state at that point available. It can be invoked on any object using the `my_object.pry` syntax or on the current binding (or any binding) using `binding.pry`. The Pry session will then begin within the scope of the object (or binding). When the session ends the program continues with any modifications you made to it. This functionality can be used for such things as: debugging, implementing developer consoles and applying hot patches. code: # test.rb require 'pry' class A def hello() puts "hello world!" end end a = A.new # start a REPL session binding.pry # program resumes here (after pry session) puts "program resumes here." Pry session: pry(main)> a.hello hello world! => nil pry(main)> def a.goodbye pry(main)* puts "goodbye cruel world!" pry(main)* end => nil pry(main)> a.goodbye goodbye cruel world! => nil pry(main)> exit program resumes here. ### Command Shell Integration A line of input that begins with a '.' will be forwarded to the command shell. This enables us to navigate the file system, spawn editors, and run git and rake directly from within Pry. Further, we can use the `shell-mode` command to incorporate the present working directory into the Pry prompt and bring in (limited at this stage, sorry) file name completion. We can also interpolate Ruby code directly into the shell by using the normal `#{}` string interpolation syntax. In the code below we're going to switch to `shell-mode` and edit the `.pryrc` file in the home directory. We'll then cat its contents and reload the file. pry(main)> shell-mode pry main:/home/john/ruby/projects/pry $ .cd ~ pry main:/home/john $ .emacsclient .pryrc pry main:/home/john $ .cat .pryrc def hello_world puts "hello world!" end pry main:/home/john $ load ".pryrc" => true pry main:/home/john $ hello_world hello world! We can also interpolate Ruby code into the shell. In the example below we use the shell command `cat` on a random file from the current directory and count the number of lines in that file with `wc`: pry main:/home/john $ .cat #{Dir['*.*'].sample} | wc -l 44 ### Code Browsing You can browse method source code with the `show-method` command. Nearly all Ruby methods (and some C methods, with the pry-doc gem) can have their source viewed. Code that is longer than a page is sent through a pager (such as less), and all code is properly syntax highlighted (even C code). The `show-method` command accepts two syntaxes, the typical ri `Class#method` syntax and also simply the name of a method that's in scope. You can optionally pass the `-l` option to show-method to include line numbers in the output. In the following example we will enter the `Pry` class, list the instance methods beginning with 're' and display the source code for the `rep` method: pry(main)> cd Pry pry(Pry):1> ls -M --grep re Pry#methods: re readline refresh rep repl repl_epilogue repl_prologue retrieve_line pry(Pry):1> show-method rep -l From: /home/john/ruby/projects/pry/lib/pry/pry_instance.rb @ line 143: Number of lines: 6 143: def rep(target=TOPLEVEL_BINDING) 144: target = Pry.binding_for(target) 145: result = re(target) 146: 147: show_result(result) if should_print? 148: end Note that we can also view C methods (from Ruby Core) using the `pry-doc` plugin; we also show off the alternate syntax for `show-method`: pry(main)> show-method Array#select From: array.c in Ruby Core (C Method): Number of lines: 15 static VALUE rb_ary_select(VALUE ary) { VALUE result; long i; RETURN_ENUMERATOR(ary, 0, 0); result = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) { rb_ary_push(result, rb_ary_elt(ary, i)); } } return result; } ### Documentation Browsing One use-case for Pry is to explore a program at run-time by `cd`-ing in and out of objects and viewing and invoking methods. In the course of exploring it may be useful to read the documentation for a specific method that you come across. Like `show-method` the `show-doc` command supports two syntaxes - the normal `ri` syntax as well as accepting the name of any method that is currently in scope. The Pry documentation system does not rely on pre-generated `rdoc` or `ri`, instead it grabs the comments directly above the method on demand. This results in speedier documentation retrieval and allows the Pry system to retrieve documentation for methods that would not be picked up by `rdoc`. Pry also has a basic understanding of both the rdoc and yard formats and will attempt to syntax highlight the documentation appropriately. Nonetheless, the `ri` functionality is very good and has an advantage over Pry's system in that it allows documentation lookup for classes as well as methods. Pry therefore has good integration with `ri` through the `ri` command. The syntax for the command is exactly as it would be in command-line - so it is not necessary to quote strings. In our example we will enter the `Gem` class and view the documentation for the `try_activate` method: pry(main)> cd Gem pry(Gem):1> show-doc try_activate From: /Users/john/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/site_ruby/1.9.1/rubygems.rb @ line 201: Number of lines: 3 Try to activate a gem containing path. Returns true if activation succeeded or wasn't needed because it was already activated. Returns false if it can't find the path in a gem. pry(Gem):1> We can also use `ri` in the normal way: pry(main) ri Array#each ----------------------------------------------------------- Array#each array.each {|item| block } -> array ------------------------------------------------------------------------ Calls _block_ once for each element in _self_, passing that element as a parameter. a = [ "a", "b", "c" ] a.each {|x| print x, " -- " } produces: a -- b -- c -- ### Gist integration If the `gist` gem is installed then method source or documentation can be gisted to github with the `gist` command. The `gist` command is capable of gisting [almost any REPL content](https://gist.github.com/cae143e4533416529726), including methods, documentation, input expressions, command source, and so on. In the example below we will gist the C source code for the `Symbol#to_proc` method to github: pry(main)> gist -m Symbol#to_proc Gist created at https://gist.github.com/5332c38afc46d902ce46 and added to clipboard. pry(main)> You can see the actual gist generated here: [https://gist.github.com/5332c38afc46d902ce46](https://gist.github.com/5332c38afc46d902ce46) ### Edit methods You can use `edit Class#method` or `edit my_method` (if the method is in scope) to open a method for editing directly in your favorite editor. Pry has knowledge of a few different editors and will attempt to open the file at the line the method is defined. You can set the editor to use by assigning to the `Pry.editor` accessor. `Pry.editor` will default to `$EDITOR` or failing that will use `nano` as the backup default. The file that is edited will be automatically reloaded after exiting the editor - reloading can be suppressed by passing the `--no-reload` option to `edit` In the example below we will set our default editor to "emacsclient" and open the `Pry#repl` method for editing: pry(main)> Pry.editor = "emacsclient" pry(main)> edit Pry#repl ### Live Help System Many other commands are available in Pry; to see the full list type `help` at the prompt. A short description of each command is provided with basic instructions for use; some commands have a more extensive help that can be accessed via typing `command_name --help`. A command will typically say in its description if the `--help` option is avaiable. ### Use Pry as your Rails Console The recommended way to use Pry as your Rails console is to add [the `pry-rails` gem](https://github.com/rweng/pry-rails) to your Gemfile. This replaces the default console with Pry, in addition to loading the Rails console helpers and adding some useful Rails-specific commands. If you don't want to change your Gemfile, you can still run a Pry console in your app's environment using Pry's `-r` flag: pry -r ./config/environment Also check out the [wiki](https://github.com/pry/pry/wiki/Setting-up-Rails-or-Heroku-to-use-Pry) for more information about integrating Pry with Rails. ### Limitations: * Tab completion is currently a bit broken/limited this will have a major overhaul in a future version. ### Syntax Highlighting Syntax highlighting is on by default in Pry. If you want to change the colors, check out the [pry-theme](https://github.com/kyrylo/pry-theme) gem. You can toggle the syntax highlighting on and off in a session by using the `toggle-color` command. Alternatively, you can turn it off permanently by putting the line `Pry.color = false` in your `~/.pryrc` file. ### Future Directions Many new features are planned such as: * Increase modularity (rely more on plugin system) * Much improved documentation system, better support for YARD * Better support for code and method reloading and saving code * Extended and more sophisticated command system, allowing piping between commands and running commands in background ### Contact Problems or questions? file an issue at [github](https://github.com/pry/pry/issues) ### Contributors Pry is primarily the work of [John Mair (banisterfiend)](http://github.com/banister), for full list of contributors see the [CONTRIBUTORS](https://github.com/pry/pry/blob/master/CONTRIBUTORS) file. pry-0.10.3/Rakefile000066400000000000000000000057401260757071700140740ustar00rootroot00000000000000require 'rake/clean' require 'rubygems/package_task' $:.unshift 'lib' require 'pry/version' CLOBBER.include('**/*~', '**/*#*', '**/*.log') CLEAN.include('**/*#*', '**/*#*.*', '**/*_flymake*.*', '**/*_flymake', '**/*.rbc', '**/.#*.*') desc "Set up and run tests" task :default => [:test] def run_specs paths format = ENV['VERBOSE'] ? '--format documentation ' : '' sh "rspec #{format}#{paths.join ' '}" end desc "Run tests" task :test do paths = if explicit_list = ENV['run'] explicit_list.split(',') else Dir['spec/**/*_spec.rb'].shuffle! end run_specs paths end task :spec => :test task :recspec do all = Dir['spec/**/*_spec.rb'].sort_by{|path| File.mtime(path)}.reverse warn "Running all, sorting by mtime: #{all[0..2].join(' ')} ...etc." run_specs all end desc "Run pry (you can pass arguments using _ in place of -)" task :pry do ARGV.shift if ARGV.first == "pry" ARGV.map! do |arg| arg.sub(/^_*/) { |m| "-" * m.size } end load 'bin/pry' end desc "Show pry version." task :version do puts "Pry version: #{Pry::VERSION}" end desc "Profile pry's startup time" task :profile do require 'profile' require 'pry' Pry.start(TOPLEVEL_BINDING, :input => StringIO.new('exit')) end def modify_base_gemspec eval(File.read('pry.gemspec')).tap { |s| yield s } end namespace :ruby do spec = modify_base_gemspec do |s| s.platform = Gem::Platform::RUBY end Gem::PackageTask.new(spec) do |pkg| pkg.need_zip = false pkg.need_tar = false end end namespace :jruby do spec = modify_base_gemspec do |s| s.add_dependency('spoon', '~> 0.0') s.platform = 'java' end Gem::PackageTask.new(spec) do |pkg| pkg.need_zip = false pkg.need_tar = false end end ['mswin32', 'mingw32'].each do |platform| namespace platform do spec = modify_base_gemspec do |s| s.add_dependency('win32console', '~> 1.3') s.platform = Gem::Platform.new ['universal', platform, nil] end Gem::PackageTask.new(spec) do |pkg| pkg.need_zip = false pkg.need_tar = false end end task gems: "#{platform}:gem" end desc "build all platform gems at once" task :gems => [:clean, :rmgems, 'ruby:gem', 'jruby:gem'] desc "remove all platform gems" task :rmgems => ['ruby:clobber_package'] task :rm_gems => :rmgems task :rm_pkgs => :rmgems desc "reinstall gem" task :reinstall => :gems do sh "gem uninstall pry" rescue nil sh "gem install #{File.dirname(__FILE__)}/pkg/pry-#{Pry::VERSION}.gem" end task :install => :reinstall desc "build and push latest gems" task :pushgems => :gems do chdir("#{File.dirname(__FILE__)}/pkg") do Dir["*.gem"].each do |gemfile| sh "gem push #{gemfile}" end end end namespace :docker do desc "build a docker container with multiple rubies" task :build do system "docker build -t pry/pry ." end desc "test pry on multiple ruby versions" task :test => :build do system "docker run -i -t -v /tmp/prytmp:/tmp/prytmp pry/pry ./multi_test_inside_docker.sh" end end pry-0.10.3/bin/000077500000000000000000000000001260757071700131715ustar00rootroot00000000000000pry-0.10.3/bin/pry000077500000000000000000000003431260757071700137310ustar00rootroot00000000000000#!/usr/bin/env ruby # (C) John Mair (banisterfiend) # MIT license $0 = 'pry' begin require 'pry' rescue LoadError require 'rubygems' require 'pry' end # Process command line options and run Pry Pry::CLI.parse_options pry-0.10.3/lib/000077500000000000000000000000001260757071700131675ustar00rootroot00000000000000pry-0.10.3/lib/pry.rb000066400000000000000000000124671260757071700143400ustar00rootroot00000000000000# (C) John Mair (banisterfiend) 2013 # MIT License # require 'pp' require 'pry/input_lock' require 'pry/exceptions' require 'pry/helpers/base_helpers' require 'pry/hooks' require 'forwardable' class Pry # The default hooks - display messages when beginning and ending Pry sessions. DEFAULT_HOOKS = Pry::Hooks.new.add_hook(:before_session, :default) do |out, target, _pry_| next if _pry_.quiet? _pry_.run_command("whereami --quiet") end # The default print DEFAULT_PRINT = proc do |output, value, _pry_| _pry_.pager.open do |pager| pager.print _pry_.config.output_prefix Pry::ColorPrinter.pp(value, pager, Pry::Terminal.width! - 1) end end # may be convenient when working with enormous objects and # pretty_print is too slow SIMPLE_PRINT = proc do |output, value| begin output.puts value.inspect rescue RescuableException output.puts "unknown" end end # useful when playing with truly enormous objects CLIPPED_PRINT = proc do |output, value| output.puts Pry.view_clip(value, id: true) end # Will only show the first line of the backtrace DEFAULT_EXCEPTION_HANDLER = proc do |output, exception, _| if UserError === exception && SyntaxError === exception output.puts "SyntaxError: #{exception.message.sub(/.*syntax error, */m, '')}" else output.puts "#{exception.class}: #{exception.message}" output.puts "from #{exception.backtrace.first}" end end DEFAULT_PROMPT_NAME = 'pry' # The default prompt; includes the target and nesting level DEFAULT_PROMPT = [ proc { |target_self, nest_level, pry| "[#{pry.input_array.size}] #{pry.config.prompt_name}(#{Pry.view_clip(target_self)})#{":#{nest_level}" unless nest_level.zero?}> " }, proc { |target_self, nest_level, pry| "[#{pry.input_array.size}] #{pry.config.prompt_name}(#{Pry.view_clip(target_self)})#{":#{nest_level}" unless nest_level.zero?}* " } ] DEFAULT_PROMPT_SAFE_OBJECTS = [String, Numeric, Symbol, nil, true, false] # A simple prompt - doesn't display target or nesting level SIMPLE_PROMPT = [proc { ">> " }, proc { " | " }] NO_PROMPT = [proc { '' }, proc { '' }] SHELL_PROMPT = [ proc { |target_self, _, _pry_| "#{_pry_.config.prompt_name} #{Pry.view_clip(target_self)}:#{Dir.pwd} $ " }, proc { |target_self, _, _pry_| "#{_pry_.config.prompt_name} #{Pry.view_clip(target_self)}:#{Dir.pwd} * " } ] # A prompt that includes the full object path as well as # input/output (_in_ and _out_) information. Good for navigation. NAV_PROMPT = [ proc do |_, _, _pry_| tree = _pry_.binding_stack.map { |b| Pry.view_clip(b.eval("self")) }.join " / " "[#{_pry_.input_array.count}] (#{_pry_.config.prompt_name}) #{tree}: #{_pry_.binding_stack.size - 1}> " end, proc do |_, _, _pry_| tree = _pry_.binding_stack.map { |b| Pry.view_clip(b.eval("self")) }.join " / " "[#{_pry_.input_array.count}] (#{ _pry_.config.prompt_name}) #{tree}: #{_pry_.binding_stack.size - 1}* " end, ] # Deal with the ^D key being pressed. Different behaviour in different cases: # 1. In an expression behave like `!` command. # 2. At top-level session behave like `exit` command. # 3. In a nested session behave like `cd ..`. DEFAULT_CONTROL_D_HANDLER = proc do |eval_string, _pry_| if !eval_string.empty? eval_string.replace('') # Clear input buffer. elsif _pry_.binding_stack.one? _pry_.binding_stack.clear throw(:breakout) else # Otherwise, saves current binding stack as old stack and pops last # binding out of binding stack (the old stack still has that binding). _pry_.command_state["cd"] ||= Pry::Config.from_hash({}) # FIXME _pry_.command_state['cd'].old_stack = _pry_.binding_stack.dup _pry_.binding_stack.pop end end DEFAULT_SYSTEM = proc do |output, cmd, _| if !system(cmd) output.puts "Error: there was a problem executing system command: #{cmd}" end end # Store the current working directory. This allows show-source etc. to work if # your process has changed directory since boot. [Issue #675] INITIAL_PWD = Dir.pwd # This is to keep from breaking under Rails 3.2 for people who are doing that # IRB = Pry thing. module ExtendCommandBundle; end end require 'method_source' require 'shellwords' require 'stringio' require 'coderay' require 'slop' require 'rbconfig' require 'tempfile' require 'pathname' require 'pry/version' require 'pry/repl' require 'pry/rbx_path' require 'pry/code' require 'pry/history_array' require 'pry/helpers' require 'pry/code_object' require 'pry/method' require 'pry/wrapped_module' require 'pry/history' require 'pry/command' require 'pry/command_set' require 'pry/commands' require 'pry/plugins' require 'pry/core_extensions' require 'pry/pry_class' require 'pry/pry_instance' require 'pry/cli' require 'pry/color_printer' require 'pry/pager' require 'pry/terminal' require 'pry/editor' require 'pry/rubygem' require "pry/indent" require "pry/last_exception" require "pry/prompt" require "pry/inspector" require 'pry/object_path' require 'pry/output' pry-0.10.3/lib/pry/000077500000000000000000000000001260757071700140015ustar00rootroot00000000000000pry-0.10.3/lib/pry/cli.rb000066400000000000000000000126711260757071700151040ustar00rootroot00000000000000class Pry # Manage the processing of command line options class CLI NoOptionsError = Class.new(StandardError) class << self # @return [Proc] The Proc defining the valid command line options. attr_accessor :options # @return [Array] The Procs that process the parsed options. Plugins can # utilize this facility in order to add and process their own Pry # options. attr_accessor :option_processors # @return [Array] The input array of strings to process # as CLI options. attr_accessor :input_args # Add another set of CLI options (a Slop block) def add_options(&block) if options old_options = options self.options = proc do instance_exec(&old_options) instance_exec(&block) end else self.options = block end self end # Bring in options defined in plugins def add_plugin_options Pry.plugins.values.each do |plugin| plugin.load_cli_options end self end # Add a block responsible for processing parsed options. def add_option_processor(&block) self.option_processors ||= [] option_processors << block self end # Clear `options` and `option_processors` def reset self.options = nil self.option_processors = nil end def parse_options(args=ARGV) unless options raise NoOptionsError, "No command line options defined! Use Pry::CLI.add_options to add command line options." end self.input_args = args begin opts = Slop.parse!( args, :help => true, :multiple_switches => false, :strict => true, &options ) rescue Slop::InvalidOptionError # Display help message on unknown switches and exit. puts Slop.new(&options) exit end # Option processors are optional. if option_processors option_processors.each { |processor| processor.call(opts) } end self end end reset end end # String that is built to be executed on start (created by -e and -exec switches) exec_string = "" # Bring in options defined by plugins Slop.new do on "no-plugins" do Pry.config.should_load_plugins = false end end.parse(ARGV.dup) if Pry.config.should_load_plugins Pry::CLI.add_plugin_options end # The default Pry command line options (before plugin options are included) Pry::CLI.add_options do banner %{Usage: pry [OPTIONS] Start a Pry session. See http://pryrepl.org/ for more information. Copyright (c) 2013 John Mair (banisterfiend) -- } on :e, :exec=, "A line of code to execute in context before the session starts" do |input| exec_string << input << "\n" end on "no-pager", "Disable pager for long output" do Pry.config.pager = false end on "no-history", "Disable history loading" do Pry.config.history.should_load = false end on "no-color", "Disable syntax highlighting for session" do Pry.config.color = false end on :f, "Suppress loading of ~/.pryrc and ./.pryrc" do Pry.config.should_load_rc = false Pry.config.should_load_local_rc = false end on :s, "select-plugin=", "Only load specified plugin (and no others)." do |plugin_name| Pry.config.should_load_plugins = false Pry.plugins[plugin_name].activate! end on :d, "disable-plugin=", "Disable a specific plugin." do |plugin_name| Pry.plugins[plugin_name].disable! end on "no-plugins", "Suppress loading of plugins." do Pry.config.should_load_plugins = false end on "plugins", "List installed plugins." do puts "Installed Plugins:" puts "--" Pry.locate_plugins.each do |plugin| puts "#{plugin.name}".ljust(18) << plugin.spec.summary end exit end on "simple-prompt", "Enable simple prompt mode" do Pry.config.prompt = Pry::SIMPLE_PROMPT end on "noprompt", "No prompt mode" do Pry.config.prompt = Pry::NO_PROMPT end on :r, :require=, "`require` a Ruby script at startup" do |file| Pry.config.requires << file end on :I=, "Add a path to the $LOAD_PATH", :as => Array, :delimiter => ":" do |load_path| load_path.map! do |path| /\A\.\// =~ path ? path : File.expand_path(path) end $LOAD_PATH.unshift(*load_path) end on "gem", "Shorthand for -I./lib -rgemname" do |load_path| $LOAD_PATH.unshift("./lib") Dir["./lib/*.rb"].each do |file| Pry.config.requires << file end end on :v, :version, "Display the Pry version" do puts "Pry version #{Pry::VERSION} on Ruby #{RUBY_VERSION}" exit end on(:c, :context=, "Start the session in the specified context. Equivalent to `context.pry` in a session.", :default => "Pry.toplevel_binding" ) end.add_option_processor do |opts| exit if opts.help? # invoked via cli Pry.cli = true # create the actual context if opts[:context] Pry.initial_session_setup context = Pry.binding_for(eval(opts[:context])) else context = Pry.toplevel_binding end if Pry::CLI.input_args.any? && Pry::CLI.input_args != ["pry"] full_name = File.expand_path(Pry::CLI.input_args.first) Pry.load_file_through_repl(full_name) exit end # Start the session (running any code passed with -e, if there is any) Pry.start(context, :input => StringIO.new(exec_string)) end pry-0.10.3/lib/pry/code.rb000066400000000000000000000242501260757071700152430ustar00rootroot00000000000000require 'pry/code/loc' require 'pry/code/code_range' require 'pry/code/code_file' class Pry class << self # Convert the given object into an instance of `Pry::Code`, if it isn't # already one. # # @param [Code, Method, UnboundMethod, Proc, Pry::Method, String, Array, # IO] obj def Code(obj) case obj when Code obj when ::Method, UnboundMethod, Proc, Pry::Method Code.from_method(obj) else Code.new(obj) end end end # `Pry::Code` is a class that encapsulates lines of source code and their # line numbers and formats them for terminal output. It can read from a file # or method definition or be instantiated with a `String` or an `Array`. # # In general, the formatting methods in `Code` return a new `Code` object # which will format the text as specified when `#to_s` is called. This allows # arbitrary chaining of formatting methods without mutating the original # object. class Code class << self include MethodSource::CodeHelpers # Instantiate a `Code` object containing code loaded from a file or # Pry's line buffer. # # @param [String] filename The name of a file, or "(pry)". # @param [Symbol] code_type The type of code the file contains. # @return [Code] def from_file(filename, code_type = nil) code_file = CodeFile.new(filename, code_type) new(code_file.code, 1, code_file.code_type) end # Instantiate a `Code` object containing code extracted from a # `::Method`, `UnboundMethod`, `Proc`, or `Pry::Method` object. # # @param [::Method, UnboundMethod, Proc, Pry::Method] meth The method # object. # @param [Integer, nil] start_line The line number to start on, or nil to # use the method's original line numbers. # @return [Code] def from_method(meth, start_line = nil) meth = Pry::Method(meth) start_line ||= meth.source_line || 1 new(meth.source, start_line, meth.source_type) end # Attempt to extract the source code for module (or class) `mod`. # # @param [Module, Class] mod The module (or class) of interest. # @param [Integer] candidate_rank The module candidate (by rank) # to use (see `Pry::WrappedModule::Candidate` for more information). # @param [Integer, nil] start_line The line number to start on, or nil to # use the method's original line numbers. # @return [Code] def from_module(mod, candidate_rank = 0, start_line=nil) candidate = Pry::WrappedModule(mod).candidate(candidate_rank) start_line ||= candidate.line new(candidate.source, start_line, :ruby) end end # @return [Symbol] The type of code stored in this wrapper. attr_accessor :code_type # Instantiate a `Code` object containing code from the given `Array`, # `String`, or `IO`. The first line will be line 1 unless specified # otherwise. If you need non-contiguous line numbers, you can create an # empty `Code` object and then use `#push` to insert the lines. # # @param [Array, String, IO] lines # @param [Integer?] start_line # @param [Symbol?] code_type def initialize(lines = [], start_line = 1, code_type = :ruby) if lines.is_a? String lines = lines.lines end @lines = lines.each_with_index.map { |line, lineno| LOC.new(line, lineno + start_line.to_i) } @code_type = code_type end # Append the given line. +lineno+ is one more than the last existing # line, unless specified otherwise. # # @param [String] line # @param [Integer?] lineno # @return [String] The inserted line. def push(line, lineno = nil) if lineno.nil? lineno = @lines.last.lineno + 1 end @lines.push(LOC.new(line, lineno)) line end alias << push # Filter the lines using the given block. # # @yield [LOC] # @return [Code] def select(&block) alter do @lines = @lines.select(&block) end end # Remove all lines that aren't in the given range, expressed either as a # `Range` object or a first and last line number (inclusive). Negative # indices count from the end of the array of lines. # # @param [Range, Integer] start_line # @param [Integer?] end_line # @return [Code] def between(start_line, end_line = nil) return self unless start_line code_range = CodeRange.new(start_line, end_line) alter do @lines = @lines[code_range.indices_range(@lines)] || [] end end # Take `num_lines` from `start_line`, forward or backwards. # # @param [Integer] start_line # @param [Integer] num_lines # @return [Code] def take_lines(start_line, num_lines) start_idx = if start_line >= 0 @lines.index { |loc| loc.lineno >= start_line } || @lines.length else [@lines.length + start_line, 0].max end alter do @lines = @lines.slice(start_idx, num_lines) end end # Remove all lines except for the +lines+ up to and excluding +lineno+. # # @param [Integer] lineno # @param [Integer] lines # @return [Code] def before(lineno, lines = 1) return self unless lineno select do |loc| loc.lineno >= lineno - lines && loc.lineno < lineno end end # Remove all lines except for the +lines+ on either side of and including # +lineno+. # # @param [Integer] lineno # @param [Integer] lines # @return [Code] def around(lineno, lines = 1) return self unless lineno select do |loc| loc.lineno >= lineno - lines && loc.lineno <= lineno + lines end end # Remove all lines except for the +lines+ after and excluding +lineno+. # # @param [Integer] lineno # @param [Integer] lines # @return [Code] def after(lineno, lines = 1) return self unless lineno select do |loc| loc.lineno > lineno && loc.lineno <= lineno + lines end end # Remove all lines that don't match the given `pattern`. # # @param [Regexp] pattern # @return [Code] def grep(pattern) return self unless pattern pattern = Regexp.new(pattern) select do |loc| loc.line =~ pattern end end # Format output with line numbers next to it, unless `y_n` is falsy. # # @param [Boolean?] y_n # @return [Code] def with_line_numbers(y_n = true) alter do @with_line_numbers = y_n end end # Format output with a marker next to the given +lineno+, unless +lineno+ is # falsy. # # @param [Integer?] lineno # @return [Code] def with_marker(lineno = 1) alter do @with_marker = !!lineno @marker_lineno = lineno end end # Format output with the specified number of spaces in front of every line, # unless `spaces` is falsy. # # @param [Integer?] spaces # @return [Code] def with_indentation(spaces = 0) alter do @with_indentation = !!spaces @indentation_num = spaces end end # @return [String] def inspect Object.instance_method(:to_s).bind(self).call end # @return [Integer] the number of digits in the last line. def max_lineno_width @lines.length > 0 ? @lines.last.lineno.to_s.length : 0 end # @return [String] a formatted representation (based on the configuration of # the object). def to_s print_to_output("", false) end # @return [String] a (possibly highlighted) copy of the source code. def highlighted print_to_output("", true) end # Writes a formatted representation (based on the configuration of the # object) to the given output, which must respond to `#<<`. def print_to_output(output, color=false) @lines.each do |loc| loc = loc.dup loc.colorize(@code_type) if color loc.add_line_number(max_lineno_width, color) if @with_line_numbers loc.add_marker(@marker_lineno) if @with_marker loc.indent(@indentation_num) if @with_indentation output << loc.line output << "\n" end output end # Get the comment that describes the expression on the given line number. # # @param [Integer] line_number (1-based) # @return [String] the code. def comment_describing(line_number) self.class.comment_describing(raw, line_number) end # Get the multiline expression that starts on the given line number. # # @param [Integer] line_number (1-based) # @return [String] the code. def expression_at(line_number, consume = 0) self.class.expression_at(raw, line_number, :consume => consume) end # Get the (approximate) Module.nesting at the give line number. # # @param [Integer] line_number line number starting from 1 # @param [Module] top_module the module in which this code exists # @return [Array] a list of open modules. def nesting_at(line_number, top_module = Object) Pry::Indent.nesting_at(raw, line_number) end # Return an unformatted String of the code. # # @return [String] def raw @lines.map(&:line).join("\n") << "\n" end # Return the number of lines stored. # # @return [Integer] def length @lines ? @lines.length : 0 end # Two `Code` objects are equal if they contain the same lines with the same # numbers. Otherwise, call `to_s` and `chomp` and compare as Strings. # # @param [Code, Object] other # @return [Boolean] def ==(other) if other.is_a?(Code) other_lines = other.instance_variable_get(:@lines) @lines.each_with_index.all? { |loc, i| loc == other_lines[i] } else to_s.chomp == other.to_s.chomp end end # Forward any missing methods to the output of `#to_s`. def method_missing(name, *args, &block) to_s.send(name, *args, &block) end undef =~ protected # An abstraction of the `dup.instance_eval` pattern used throughout this # class. def alter(&block) dup.tap { |o| o.instance_eval(&block) } end end end pry-0.10.3/lib/pry/code/000077500000000000000000000000001260757071700147135ustar00rootroot00000000000000pry-0.10.3/lib/pry/code/code_file.rb000066400000000000000000000060311260757071700171510ustar00rootroot00000000000000class Pry class CodeFile DEFAULT_EXT = '.rb' # List of all supported languages. # @return [Hash] EXTENSIONS = { %w(.py) => :python, %w(.js) => :javascript, %w(.css) => :css, %w(.xml) => :xml, %w(.php) => :php, %w(.html) => :html, %w(.diff) => :diff, %w(.java) => :java, %w(.json) => :json, %w(.c .h) => :c, %w(.rhtml) => :rhtml, %w(.yaml .yml) => :yaml, %w(.cpp .hpp .cc .h cxx) => :cpp, %w(.rb .ru .irbrc .gemspec .pryrc) => :ruby, } # @return [Symbol] The type of code stored in this wrapper. attr_reader :code_type # @param [String] filename The name of a file with code to be detected # @param [Symbol] code_type The type of code the `filename` contains def initialize(filename, code_type = type_from_filename(filename)) @filename = filename @code_type = code_type end # @return [String] The code contained in the current `@filename`. def code if @filename == Pry.eval_path Pry.line_buffer.drop(1) elsif Pry::Method::Patcher.code_for(@filename) Pry::Method::Patcher.code_for(@filename) elsif RbxPath.is_core_path?(@filename) File.read(RbxPath.convert_path_to_full(@filename)) else path = abs_path @code_type = type_from_filename(path) File.read(path) end end private # @raise [MethodSource::SourceNotFoundError] if the `filename` is not # readable for some reason. # @return [String] absolute path for the given `filename`. def abs_path code_path.detect { |path| readable?(path) } or raise MethodSource::SourceNotFoundError, "Cannot open #{ @filename.inspect } for reading." end # @param [String] path # @return [Boolean] if the path, with or without the default ext, # is a readable file then `true`, otherwise `false`. def readable?(path) File.readable?(path) && !File.directory?(path) or File.readable?(path << DEFAULT_EXT) end # @return [Array] All the paths that contain code that Pry can use for its # API's. Skips directories. def code_path [from_pwd, from_pry_init_pwd, *from_load_path] end # @param [String] filename # @param [Symbol] default (:unknown) the file type to assume if none could be # detected. # @return [Symbol, nil] The CodeRay type of a file from its extension, or # `nil` if `:unknown`. def type_from_filename(filename, default = :unknown) _, @code_type = EXTENSIONS.find do |k, _| k.any? { |ext| ext == File.extname(filename) } end code_type || default end # @return [String] def from_pwd File.expand_path(@filename, Dir.pwd) end # @return [String] def from_pry_init_pwd File.expand_path(@filename, Pry::INITIAL_PWD) end # @return [String] def from_load_path $LOAD_PATH.map { |path| File.expand_path(@filename, path) } end end end pry-0.10.3/lib/pry/code/code_range.rb000066400000000000000000000034601260757071700173310ustar00rootroot00000000000000class Pry class Code # Represents a range of lines in a code listing. # # @api private class CodeRange # @param [Integer] start_line # @param [Integer?] end_line def initialize(start_line, end_line = nil) @start_line = start_line @end_line = end_line force_set_end_line end # @param [Array] lines # @return [Range] def indices_range(lines) Range.new(*indices(lines)) end private def start_line; @start_line; end def end_line; @end_line; end # If `end_line` is equal to `nil`, then calculate it from the first # parameter, `start_line`. Otherwise, leave it as it is. # @return [void] def force_set_end_line if start_line.is_a?(Range) set_end_line_from_range else @end_line ||= start_line end end # Finds indices of `start_line` and `end_line` in the given Array of # +lines+. # # @param [Array] lines # @return [Array] def indices(lines) [find_start_index(lines), find_end_index(lines)] end # @return [Integer] def find_start_index(lines) return start_line if start_line < 0 lines.index { |loc| loc.lineno >= start_line } || lines.length end # @return [Integer] def find_end_index(lines) return end_line if end_line < 0 (lines.index { |loc| loc.lineno > end_line } || 0) - 1 end # For example, if the range is 4..10, then `start_line` would be equal to # 4 and `end_line` to 10. # @return [void] def set_end_line_from_range @end_line = start_line.last @end_line -= 1 if start_line.exclude_end? @start_line = start_line.first end end end end pry-0.10.3/lib/pry/code/loc.rb000066400000000000000000000044321260757071700160200ustar00rootroot00000000000000class Pry class Code # Represents a line of code. A line of code is a tuple, which consists of a # line and a line number. A `LOC` object's state (namely, the line # parameter) can be changed via instance methods. `Pry::Code` heavily uses # this class. # # @api private # @example # loc = LOC.new("def example\n :example\nend", 1) # puts loc.line # def example # :example # end # #=> nil # # loc.indent(3) # loc.line #=> " def example\n :example\nend" class LOC # @return [Array] attr_reader :tuple # @param [String] line The line of code. # @param [Integer] lineno The position of the +line+. def initialize(line, lineno) @tuple = [line.chomp, lineno.to_i] end # @return [Boolean] def ==(other) other.tuple == tuple end def dup self.class.new(line, lineno) end # @return [String] def line tuple.first end # @return [Integer] def lineno tuple.last end # Paints the `line` of code. # # @param [Symbol] code_type # @return [void] def colorize(code_type) tuple[0] = CodeRay.scan(line, code_type).term end # Prepends the line number `lineno` to the `line`. # # @param [Integer] max_width # @return [void] def add_line_number(max_width = 0, color = false) padded = lineno.to_s.rjust(max_width) colorized_lineno = color ? Pry::Helpers::BaseHelpers.colorize_code(padded) : padded tuple[0] = "#{ colorized_lineno }: #{ line }" end # Prepends a marker "=>" or an empty marker to the +line+. # # @param [Integer] marker_lineno If it is equal to the `lineno`, then # prepend a hashrocket. Otherwise, an empty marker. # @return [void] def add_marker(marker_lineno) tuple[0] = if lineno == marker_lineno " => #{ line }" else " #{ line }" end end # Indents the `line` with +distance+ spaces. # # @param [Integer] distance # @return [void] def indent(distance) tuple[0] = "#{ ' ' * distance }#{ line }" end end end end pry-0.10.3/lib/pry/code_object.rb000066400000000000000000000124671260757071700166000ustar00rootroot00000000000000class Pry # This class is responsible for taking a string (identifying a # command/class/method/etc) and returning the relevant type of object. # For example, if the user looks up "show-source" then a # `Pry::Command` will be returned. Alternatively, if the user passes in "Pry#repl" then # a `Pry::Method` object will be returned. # # The `CodeObject.lookup` method is responsible for 1. figuring out what kind of # object the user wants (applying precedence rules in doing so -- i.e methods # get precedence over commands with the same name) and 2. Returning # the appropriate object. If the user fails to provide a string # identifer for the object (i.e they pass in `nil` or "") then the # object looked up will be the 'current method' or 'current class' # associated with the Binding. # # TODO: This class is a clusterfuck. We need a much more robust # concept of what a "Code Object" really is. Currently # commands/classes/candidates/methods and so on just share a very # ill-defined interface. class CodeObject module Helpers # we need this helper as some Pry::Method objects can wrap Procs # @return [Boolean] def real_method_object? is_a?(::Method) || is_a?(::UnboundMethod) end def c_method? real_method_object? && source_type == :c end def module_with_yard_docs? is_a?(WrappedModule) && yard_docs? end def command? is_a?(Module) && self <= Pry::Command end end include Pry::Helpers::CommandHelpers class << self def lookup(str, _pry_, options={}) co = new(str, _pry_, options) co.default_lookup || co.method_or_class_lookup || co.command_lookup || co.empty_lookup end end attr_accessor :str attr_accessor :target attr_accessor :_pry_ attr_accessor :super_level def initialize(str, _pry_, options={}) options = { :super => 0, }.merge!(options) @str = str @_pry_ = _pry_ @target = _pry_.current_context @super_level = options[:super] end def command_lookup # TODO: just make it so find_command_by_match_or_listing doesn't # raise? _pry_.commands.find_command_by_match_or_listing(str) rescue nil end # when no paramter is given (i.e CodeObject.lookup(nil)), then we # lookup the 'current object' from the binding. def empty_lookup return nil if str && !str.empty? obj = if internal_binding?(target) mod = target_self.is_a?(Module) ? target_self : target_self.class Pry::WrappedModule(mod) else Pry::Method.from_binding(target) end # respect the super level (i.e user might have specified a # --super flag to show-source) lookup_super(obj, super_level) end # lookup variables and constants and `self` that are not modules def default_lookup # we skip instance methods as we want those to fall through to method_or_class_lookup() if safe_to_evaluate?(str) && !looks_like_an_instance_method?(str) obj = target.eval(str) # restrict to only objects we KNOW for sure support the full API # Do NOT support just any object that responds to source_location if sourcable_object?(obj) Pry::Method(obj) elsif !obj.is_a?(Module) Pry::WrappedModule(obj.class) else nil end end rescue Pry::RescuableException nil end def method_or_class_lookup obj = case str when /\S+\(\)\z/ Pry::Method.from_str(str.sub(/\(\)\z/, ''),target) || Pry::WrappedModule.from_str(str, target) else Pry::WrappedModule.from_str(str,target) || Pry::Method.from_str(str, target) end lookup_super(obj, super_level) end private def sourcable_object?(obj) [::Proc, ::Method, ::UnboundMethod].any? { |o| obj.is_a?(o) } end # Returns true if `str` looks like a method, i.e Klass#method # We need to consider this case because method lookups should fall # through to the `method_or_class_lookup()` method but a # defined?() on a "Klass#method` string will see the `#` as a # comment and only evaluate the `Klass` part. # @param [String] str # @return [Boolean] Whether the string looks like an instance method. def looks_like_an_instance_method?(str) str =~ /\S#\S/ end # We use this method to decide whether code is safe to eval. Method's are # generally not, but everything else is. # TODO: is just checking != "method" enough?? # TODO: see duplication of this method in Pry::WrappedModule # @param [String] str The string to lookup # @return [Boolean] def safe_to_evaluate?(str) return true if str.strip == "self" kind = target.eval("defined?(#{str})") kind =~ /variable|constant/ end def target_self target.eval('self') end # grab the nth (`super_level`) super of `obj # @param [Object] obj # @param [Fixnum] super_level How far up the super chain to ascend. def lookup_super(obj, super_level) return nil if !obj sup = obj.super(super_level) if !sup raise Pry::CommandError, "No superclass found for #{obj.wrapped}" else sup end end end end pry-0.10.3/lib/pry/color_printer.rb000066400000000000000000000027111260757071700172100ustar00rootroot00000000000000# PP subclass for streaming inspect output in color. class Pry class ColorPrinter < ::PP OBJ_COLOR = begin code = CodeRay::Encoders::Terminal::TOKEN_COLORS[:keyword] if code.start_with? "\e" code else "\e[0m\e[0;#{code}m" end end CodeRay::Encoders::Terminal::TOKEN_COLORS[:comment][:self] = "\e[1;34m" def self.pp(obj, out = $>, width = 79) q = ColorPrinter.new(out, width) q.guard_inspect_key { q.pp obj } q.flush out << "\n" end def text(str, width = str.length) # Don't recolorize output with color [Issue #751] if str.include?("\e[") super "#{str}\e[0m", width elsif str.start_with?('#<') || str == '=' || str == '>' super highlight_object_literal(str), width else super CodeRay.scan(str, :ruby).term, width end end def pp(obj) super rescue => e raise if e.is_a? Pry::Pager::StopPaging # Read the class name off of the singleton class to provide a default # inspect. singleton = class << obj; self; end ancestors = Pry::Method.safe_send(singleton, :ancestors) klass = ancestors.reject { |k| k == singleton }.first obj_id = obj.__id__.to_s(16) rescue 0 str = "#<#{klass}:0x#{obj_id}>" text highlight_object_literal(str) end private def highlight_object_literal(object_literal) "#{OBJ_COLOR}#{object_literal}\e[0m" end end end pry-0.10.3/lib/pry/command.rb000066400000000000000000000524361260757071700157560ustar00rootroot00000000000000require 'delegate' require 'pry/helpers/documentation_helpers' class Pry # The super-class of all commands, new commands should be created by calling # {Pry::CommandSet#command} which creates a BlockCommand or {Pry::CommandSet#create_command} # which creates a ClassCommand. Please don't use this class directly. class Command extend Helpers::DocumentationHelpers extend CodeObject::Helpers # represents a void return value for a command VOID_VALUE = Object.new # give it a nice inspect def VOID_VALUE.inspect() "void" end # Properties of the command itself (as passed as arguments to # {CommandSet#command} or {CommandSet#create_command}). class << self attr_writer :block attr_writer :description attr_writer :command_options attr_writer :match def match(arg=nil) if arg @command_options ||= default_options(arg) @command_options[:listing] = arg.is_a?(String) ? arg : arg.inspect @match = arg end @match ||= nil end # Define or get the command's description def description(arg=nil) @description = arg if arg @description ||= nil end # Define or get the command's options def command_options(arg=nil) @command_options ||= default_options(match) @command_options.merge!(arg) if arg @command_options end # backward compatibility alias_method :options, :command_options alias_method :options=, :command_options= # Define or get the command's banner def banner(arg=nil) @banner = arg if arg @banner || description end def block @block || instance_method(:process) end def source file, line = block.source_location strip_leading_whitespace(Pry::Code.from_file(file).expression_at(line)) end def doc new.help end def source_location block.source_location end def source_file Array(block.source_location).first end alias_method :file, :source_file def source_line Array(block.source_location).last end alias_method :line, :source_line def default_options(match) { :requires_gem => [], :keep_retval => false, :argument_required => false, :interpolate => true, :shellwords => true, :listing => (String === match ? match : match.inspect), :use_prefix => true, :takes_block => false } end end # Make those properties accessible to instances def name; self.class.name; end def match; self.class.match; end def description; self.class.description; end def block; self.class.block; end def command_options; self.class.options; end def command_name; self.class.command_name; end def source; self.class.source; end def source_location; self.class.source_location; end class << self def name super.to_s == "" ? "#" : super end def inspect name end def command_name self.options[:listing] end # Create a new command with the given properties. # @param [String, Regex] match The thing that triggers this command # @param [String] description The description to appear in `help` # @param [Hash] options Behavioral options (see {Pry::CommandSet#command}) # @param [Module] helpers A module of helper functions to be included. # @yield optional, used for BlockCommands # @return [Class] (a subclass of {Pry::Command}) def subclass(match, description, options, helpers, &block) klass = Class.new(self) klass.send(:include, helpers) klass.match = match klass.description = description klass.command_options = options klass.block = block klass end # Should this command be called for the given line? # @param [String] val A line input at the REPL # @return [Boolean] def matches?(val) command_regex =~ val end # How well does this command match the given line? # # Higher scores are better because they imply that this command matches # the line more closely. # # The score is calculated by taking the number of characters at the start # of the string that are used only to identify the command, not as part of # the arguments. # # @example # /\.(.*)/.match_score(".foo") #=> 1 # /\.*(.*)/.match_score("...foo") #=> 3 # 'hi'.match_score("hi there") #=> 2 # # @param [String] val A line input at the REPL # @return [Fixnum] def match_score(val) if command_regex =~ val Regexp.last_match.size > 1 ? Regexp.last_match.begin(1) : Regexp.last_match.end(0) else -1 end end # Store hooks to be run before or after the command body. # @see {Pry::CommandSet#before_command} # @see {Pry::CommandSet#after_command} def hooks @hooks ||= {:before => [], :after => []} end def command_regex pr = Pry.respond_to?(:config) ? Pry.config.command_prefix : "" prefix = convert_to_regex(pr) prefix = "(?:#{prefix})?" unless options[:use_prefix] /^#{prefix}#{convert_to_regex(match)}(?!\S)/ end def convert_to_regex(obj) case obj when String Regexp.escape(obj) else obj end end # The group in which the command should be displayed in "help" output. # This is usually auto-generated from directory naming, but it can be # manually overridden if necessary. # Group should not be changed once it is initialized. def group(name=nil) @group ||= if name name else case Pry::Method(block).source_file when %r{/pry/.*_commands/(.*).rb} $1.capitalize.gsub(/_/, " ") when %r{(pry-\w+)-([\d\.]+([\w\.]+)?)} name, version = $1, $2 "#{name.to_s} (v#{version.to_s})" when /pryrc/ "~/.pryrc" else "(other)" end end end end # Properties of one execution of a command (passed by {Pry#run_command} as a hash of # context and expanded in `#initialize` attr_accessor :output attr_accessor :target attr_accessor :captures attr_accessor :eval_string attr_accessor :arg_string attr_accessor :context attr_accessor :command_set attr_accessor :_pry_ # The block we pass *into* a command so long as `:takes_block` is # not equal to `false` # @example # my-command | do # puts "block content" # end attr_accessor :command_block # Run a command from another command. # @param [String] command_string The string that invokes the command # @param [Array] args Further arguments to pass to the command # @example # run "show-input" # @example # run ".ls" # @example # run "amend-line", "5", 'puts "hello world"' def run(command_string, *args) command_string = _pry_.config.command_prefix.to_s + command_string complete_string = "#{command_string} #{args.join(" ")}".rstrip command_set.process_line(complete_string, context) end def commands command_set.to_hash end def text Pry::Helpers::Text end def void VOID_VALUE end include Pry::Helpers::BaseHelpers include Pry::Helpers::CommandHelpers # Instantiate a command, in preparation for calling it. # @param [Hash] context The runtime context to use with this command. def initialize(context={}) self.context = context self.target = context[:target] self.output = context[:output] self.eval_string = context[:eval_string] self.command_set = context[:command_set] self._pry_ = context[:pry_instance] end # @return [Object] The value of `self` inside the `target` binding. def target_self; target.eval('self'); end # @return [Hash] Pry commands can store arbitrary state # here. This state persists between subsequent command invocations. # All state saved here is unique to the command, it does not # need to be namespaced. # @example # state.my_state = "my state" # this will not conflict with any # # `state.my_state` used in another command. def state _pry_.command_state[match] ||= Pry::Config.from_hash({}) end # Revaluate the string (str) and perform interpolation. # @param [String] str The string to reevaluate with interpolation. # # @return [String] The reevaluated string with interpolations # applied (if any). def interpolate_string(str) dumped_str = str.dump if dumped_str.gsub!(/\\\#\{/, '#{') target.eval(dumped_str) else str end end # Display a warning if a command collides with a local/method in # the current scope. def check_for_command_collision(command_match, arg_string) collision_type = target.eval("defined?(#{command_match})") collision_type ||= 'local-variable' if arg_string.match(%r{\A\s*[-+*/%&|^]*=}) if collision_type output.puts "#{text.bold('WARNING:')} Calling Pry command '#{command_match}', which conflicts with a #{collision_type}.\n\n" end rescue Pry::RescuableException end # Extract necessary information from a line that Command.matches? this # command. # # Returns an array of four elements: # # ``` # [String] the portion of the line that matched with the Command match # [String] a string of all the arguments (i.e. everything but the match) # [Array] the captures caught by the command_regex # [Array] the arguments obtained by splitting the arg_string # ``` # # @param [String] val The line of input # @return [Array] def tokenize(val) val.replace(interpolate_string(val)) if command_options[:interpolate] self.class.command_regex =~ val # please call Command.matches? before Command#call_safely raise CommandError, "fatal: called a command which didn't match?!" unless Regexp.last_match captures = Regexp.last_match.captures pos = Regexp.last_match.end(0) arg_string = val[pos..-1] # remove the one leading space if it exists arg_string.slice!(0) if arg_string.start_with?(" ") # process and pass a block if one is found pass_block(arg_string) if command_options[:takes_block] if arg_string args = command_options[:shellwords] ? Shellwords.shellwords(arg_string) : arg_string.split(" ") else args = [] end [val[0..pos].rstrip, arg_string, captures, args] end # Process a line that Command.matches? this command. # @param [String] line The line to process # @return [Object, Command::VOID_VALUE] def process_line(line) command_match, arg_string, captures, args = tokenize(line) check_for_command_collision(command_match, arg_string) if Pry.config.collision_warning self.arg_string = arg_string self.captures = captures call_safely(*(captures + args)) end # Pass a block argument to a command. # @param [String] arg_string The arguments (as a string) passed to the command. # We inspect these for a '| do' or a '| {' and if we find it we use it # to start a block input sequence. Once we have a complete # block, we save it to an accessor that can be retrieved from the command context. # Note that if we find the '| do' or '| {' we delete this and the # elements following it from `arg_string`. def pass_block(arg_string) # Workaround for weird JRuby bug where rindex in this case can return nil # even when there's a match. arg_string.scan(/\| *(?:do|\{)/) block_index = $~ && $~.offset(0)[0] return if !block_index block_init_string = arg_string.slice!(block_index..-1)[1..-1] prime_string = "proc #{block_init_string}\n" if !Pry::Code.complete_expression?(prime_string) block_string = _pry_.r(target, prime_string) else block_string = prime_string end begin self.command_block = target.eval(block_string) rescue Pry::RescuableException raise CommandError, "Incomplete block definition." end end private :pass_block # Run the command with the given `args`. # # This is a public wrapper around `#call` which ensures all preconditions # are met. # # @param [Array] args The arguments to pass to this command. # @return [Object] The return value of the `#call` method, or # {Command::VOID_VALUE}. def call_safely(*args) unless dependencies_met? gems_needed = Array(command_options[:requires_gem]) gems_not_installed = gems_needed.select { |g| !Rubygem.installed?(g) } output.puts "\nThe command '#{command_name}' is #{text.bold("unavailable")} because it requires the following gems to be installed: #{(gems_not_installed.join(", "))}" output.puts "-" output.puts "Type `install-command #{command_name}` to install the required gems and activate this command." return void end if command_options[:argument_required] && args.empty? raise CommandError, "The command '#{command_name}' requires an argument." end ret = call_with_hooks(*args) command_options[:keep_retval] ? ret : void end # Are all the gems required to use this command installed? # # @return Boolean def dependencies_met? @dependencies_met ||= command_dependencies_met?(command_options) end # Generate completions for this command # # @param [String] search The line typed so far # @return [Array] Completion words def complete(search) [] end private # Run the `#call` method and all the registered hooks. # @param [Array] args The arguments to `#call` # @return [Object] The return value from `#call` def call_with_hooks(*args) self.class.hooks[:before].each do |block| instance_exec(*args, &block) end ret = call(*args) self.class.hooks[:after].each do |block| ret = instance_exec(*args, &block) end ret end # Fix the number of arguments we pass to a block to avoid arity warnings. # @param [Fixnum] arity The arity of the block # @param [Array] args The arguments to pass # @return [Array] A (possibly shorter) array of the arguments to pass def correct_arg_arity(arity, args) case when arity < 0 args when arity == 0 [] when arity > 0 args.values_at(*(0..(arity - 1)).to_a) end end end # A super-class for Commands that are created with a single block. # # This class ensures that the block is called with the correct number of arguments # and the right context. # # Create subclasses using {Pry::CommandSet#command}. class BlockCommand < Command # backwards compatibility alias_method :opts, :context # Call the block that was registered with this command. # @param [Array] args The arguments passed # @return [Object] The return value of the block def call(*args) instance_exec(*correct_arg_arity(block.arity, args), &block) end def help "#{command_options[:listing].to_s.ljust(18)} #{description}" end end # A super-class of Commands with structure. # # This class implements the bare-minimum functionality that a command should # have, namely a --help switch, and then delegates actual processing to its # subclasses. # # Create subclasses using {Pry::CommandSet#create_command}, and override the # `options(opt)` method to set up an instance of Slop, and the `process` # method to actually run the command. If necessary, you can also override # `setup` which will be called before `options`, for example to require any # gems your command needs to run, or to set up state. class ClassCommand < Command class << self # Ensure that subclasses inherit the options, description and # match from a ClassCommand super class. def inherited(klass) klass.match match klass.description description klass.command_options options end def source source_object.source end def doc new.help end def source_location source_object.source_location end def source_file source_object.source_file end alias_method :file, :source_file def source_line source_object.source_line end alias_method :line, :source_line private # The object used to extract the source for the command. # # This should be a `Pry::Method(block)` for a command made with `create_command` # and a `Pry::WrappedModule(self)` for a command that's a standard class. # @return [Pry::WrappedModule, Pry::Method] def source_object @source_object ||= if name =~ /^[A-Z]/ Pry::WrappedModule(self) else Pry::Method(block) end end end attr_accessor :opts attr_accessor :args # Set up `opts` and `args`, and then call `process`. # # This method will display help if necessary. # # @param [Array] args The arguments passed # @return [Object] The return value of `process` or VOID_VALUE def call(*args) setup self.opts = slop self.args = self.opts.parse!(args) if opts.present?(:help) output.puts slop.help void else process(*correct_arg_arity(method(:process).arity, args)) end end # Return the help generated by Slop for this command. def help slop.help end # Return an instance of Slop that can parse either subcommands or the # options that this command accepts. def slop Slop.new do |opt| opt.banner(unindent(self.class.banner)) subcommands(opt) options(opt) opt.on :h, :help, 'Show this message.' end end # Generate shell completions # @param [String] search The line typed so far # @return [Array] the words to complete def complete(search) slop.map do |opt| [opt.long && "--#{opt.long} " || opt.short && "-#{opt.short}"] end.flatten(1).compact + super end # A method called just before `options(opt)` as part of `call`. # # This method can be used to set up any context your command needs to run, # for example requiring gems, or setting default values for options. # # @example # def setup # require 'gist' # @action = :method # end def setup; end # A method to setup Slop commands so it can parse the subcommands your # command expects. If you need to set up default values, use `setup` # instead. # # @example A minimal example # def subcommands(cmd) # cmd.command :download do |opt| # description 'Downloads a content from a server' # # opt.on :verbose, 'Use verbose output' # # run do |options, arguments| # ContentDownloader.download(options, arguments) # end # end # end # # @example Define the invokation block anywhere you want # def subcommands(cmd) # cmd.command :download do |opt| # description 'Downloads a content from a server' # # opt.on :verbose, 'Use verbose output' # end # end # # def process # # Perform calculations... # opts.fetch_command(:download).run do |options, arguments| # ContentDownloader.download(options, arguments) # end # # More calculations... # end def subcommands(cmd); end # A method to setup Slop so it can parse the options your command expects. # # @note Please don't do anything side-effecty in the main part of this # method, as it may be called by Pry at any time for introspection reasons. # If you need to set up default values, use `setup` instead. # # @example # def options(opt) # opt.banner "Gists methods or classes" # opt.on(:c, :class, "gist a class") do # @action = :class # end # end def options(opt); end # The actual body of your command should go here. # # The `opts` mehod can be called to get the options that Slop has passed, # and `args` gives the remaining, unparsed arguments. # # The return value of this method is discarded unless the command was # created with `:keep_retval => true`, in which case it is returned to the # repl. # # @example # def process # if opts.present?(:class) # gist_class # else # gist_method # end # end def process; raise CommandError, "command '#{command_name}' not implemented" end end end pry-0.10.3/lib/pry/command_set.rb000066400000000000000000000366311260757071700166300ustar00rootroot00000000000000class Pry class NoCommandError < StandardError def initialize(match, owner) super "Command '#{match}' not found in command set #{owner}" end end # This class is used to create sets of commands. Commands can be imported from # different sets, aliased, removed, etc. class CommandSet include Enumerable include Pry::Helpers::BaseHelpers attr_reader :helper_module # @param [Array] imported_sets # Sets which will be imported automatically # @yield Optional block run to define commands def initialize(*imported_sets, &block) @commands = {} @helper_module = Module.new import(*imported_sets) instance_eval(&block) if block end # Defines a new Pry command. # @param [String, Regexp] match The start of invocations of this command. # @param [String] description A description of the command. # @param [Hash] options The optional configuration parameters. # @option options [Boolean] :keep_retval Whether or not to use return value # of the block for return of `command` or just to return `nil` # (the default). # @option options [Array] :requires_gem Whether the command has # any gem dependencies, if it does and dependencies not met then # command is disabled and a stub proc giving instructions to # install command is provided. # @option options [Boolean] :interpolate Whether string #{} based # interpolation is applied to the command arguments before # executing the command. Defaults to true. # @option options [String] :listing The listing name of the # command. That is the name by which the command is looked up by # help and by show-command. Necessary for commands with regex matches. # @option options [Boolean] :use_prefix Whether the command uses # `Pry.config.command_prefix` prefix (if one is defined). Defaults # to true. # @option options [Boolean] :shellwords Whether the command's arguments # should be split using Shellwords instead of just split on spaces. # Defaults to true. # @yield The action to perform. The parameters in the block # determines the parameters the command will receive. All # parameters passed into the block will be strings. Successive # command parameters are separated by whitespace at the Pry prompt. # @example # MyCommands = Pry::CommandSet.new do # command "greet", "Greet somebody" do |name| # puts "Good afternoon #{name.capitalize}!" # end # end # # # From pry: # # pry(main)> _pry_.commands = MyCommands # # pry(main)> greet john # # Good afternoon John! # # pry(main)> help greet # # Greet somebody # @example Regexp command # MyCommands = Pry::CommandSet.new do # command /number-(\d+)/, "number-N regex command", :listing => "number" do |num, name| # puts "hello #{name}, nice number: #{num}" # end # end # # # From pry: # # pry(main)> _pry_.commands = MyCommands # # pry(main)> number-10 john # # hello john, nice number: 10 # # pry(main)> help number # # number-N regex command def block_command(match, description="No description.", options={}, &block) description, options = ["No description.", description] if description.is_a?(Hash) options = Pry::Command.default_options(match).merge!(options) @commands[match] = Pry::BlockCommand.subclass(match, description, options, helper_module, &block) end alias_method :command, :block_command # Defines a new Pry command class. # # @param [String, Regexp] match The start of invocations of this command. # @param [String] description A description of the command. # @param [Hash] options The optional configuration parameters, see {#command} # @yield The class body's definition. # # @example # Pry::Commands.create_command "echo", "echo's the input", :shellwords => false do # def options(opt) # opt.banner "Usage: echo [-u | -d] " # opt.on :u, :upcase, "ensure the output is all upper-case" # opt.on :d, :downcase, "ensure the output is all lower-case" # end # # def process # raise Pry::CommandError, "-u and -d makes no sense" if opts.present?(:u) && opts.present?(:d) # result = args.join(" ") # result.downcase! if opts.present?(:downcase) # result.upcase! if opts.present?(:upcase) # output.puts result # end # end # def create_command(match, description="No description.", options={}, &block) description, options = ["No description.", description] if description.is_a?(Hash) options = Pry::Command.default_options(match).merge!(options) @commands[match] = Pry::ClassCommand.subclass(match, description, options, helper_module, &block) @commands[match].class_eval(&block) @commands[match] end # Execute a block of code before a command is invoked. The block also # gets access to parameters that will be passed to the command and # is evaluated in the same context. # @param [String, Regexp] search The match or listing of the command. # @yield The block to be run before the command. # @example Display parameter before invoking command # Pry.config.commands.before_command("whereami") do |n| # output.puts "parameter passed was #{n}" # end def before_command(search, &block) cmd = find_command_by_match_or_listing(search) cmd.hooks[:before].unshift block end # Execute a block of code after a command is invoked. The block also # gets access to parameters that will be passed to the command and # is evaluated in the same context. # @param [String, Regexp] search The match or listing of the command. # @yield The block to be run after the command. # @example Display text 'command complete' after invoking command # Pry.config.commands.after_command("whereami") do |n| # output.puts "command complete!" # end def after_command(search, &block) cmd = find_command_by_match_or_listing(search) cmd.hooks[:after] << block end def each(&block) @commands.each(&block) end # Removes some commands from the set # @param [Array] searches the matches or listings of the commands to remove def delete(*searches) searches.each do |search| cmd = find_command_by_match_or_listing(search) @commands.delete cmd.match end end # Imports all the commands from one or more sets. # @param [Array] sets Command sets, all of the commands of which # will be imported. # @return [Pry::CommandSet] Returns the reciever (a command set). def import(*sets) sets.each do |set| @commands.merge! set.to_hash helper_module.send :include, set.helper_module end self end # Imports some commands from a set # @param [CommandSet] set Set to import commands from # @param [Array] matches Commands to import # @return [Pry::CommandSet] Returns the reciever (a command set). def import_from(set, *matches) helper_module.send :include, set.helper_module matches.each do |match| cmd = set.find_command_by_match_or_listing(match) @commands[cmd.match] = cmd end self end # @param [String, Regexp] match_or_listing The match or listing of a command. # of the command to retrieve. # @return [Command] The command object matched. def find_command_by_match_or_listing(match_or_listing) cmd = (@commands[match_or_listing] || Pry::Helpers::BaseHelpers.find_command(match_or_listing, @commands)) cmd or raise ArgumentError, "Cannot find a command: '#{match_or_listing}'!" end # Aliases a command # @param [String, Regex] match The match of the alias (can be a regex). # @param [String] action The action to be performed (typically # another command). # @param [Hash] options The optional configuration parameters, # accepts the same as the `command` method, but also allows the # command description to be passed this way too as `:desc` # @example Creating an alias for `ls -M` # Pry.config.commands.alias_command "lM", "ls -M" # @example Pass explicit description (overriding default). # Pry.config.commands.alias_command "lM", "ls -M", :desc => "cutiepie" def alias_command(match, action, options={}) cmd = find_command(action) or fail "Command: `#{action}` not found" original_options = cmd.options.dup options = original_options.merge!({ :desc => "Alias for `#{action}`", :listing => match }).merge!(options) # ensure default description is used if desc is nil desc = options.delete(:desc).to_s c = block_command match, desc, options do |*args| run action, *args end c.class_eval do define_method(:complete) do |input| cmd.new(context).complete(input) end end c.group "Aliases" c end # Rename a command. Accepts either match or listing for the search. # # @param [String, Regexp] new_match The new match for the command. # @param [String, Regexp] search The command's current match or listing. # @param [Hash] options The optional configuration parameters, # accepts the same as the `command` method, but also allows the # command description to be passed this way too. # @example Renaming the `ls` command and changing its description. # Pry.config.commands.rename "dir", "ls", :description => "DOS friendly ls" def rename_command(new_match, search, options={}) cmd = find_command_by_match_or_listing(search) options = { :listing => new_match, :description => cmd.description }.merge!(options) @commands[new_match] = cmd.dup @commands[new_match].match = new_match @commands[new_match].description = options.delete(:description) @commands[new_match].options.merge!(options) @commands.delete(cmd.match) end def disabled_command(name_of_disabled_command, message, matcher=name_of_disabled_command) create_command name_of_disabled_command do match matcher description "" define_method(:process) do output.puts "DISABLED: #{message}" end end end # Sets or gets the description for a command (replacing the old # description). Returns current description if no description # parameter provided. # @param [String, Regexp] search The command match. # @param [String?] description (nil) The command description. # @example Setting # MyCommands = Pry::CommandSet.new do # desc "help", "help description" # end # @example Getting # Pry.config.commands.desc "amend-line" def desc(search, description=nil) cmd = find_command_by_match_or_listing(search) return cmd.description if !description cmd.description = description end # Defines helpers methods for this command sets. # Those helpers are only defined in this command set. # # @yield A block defining helper methods # @example # helpers do # def hello # puts "Hello!" # end # # include OtherModule # end def helpers(&block) helper_module.class_eval(&block) end # @return [Array] # The list of commands provided by the command set. def list_commands @commands.keys end alias_method :keys, :list_commands def to_hash @commands.dup end alias_method :to_h, :to_hash # Find a command that matches the given line # @param [String] pattern The line that might be a command invocation # @return [Pry::Command, nil] def [](pattern) @commands.values.select do |command| command.matches?(pattern) end.sort_by do |command| command.match_score(pattern) end.last end alias_method :find_command, :[] # # Re-assign the command found at _pattern_ with _command_. # # @param [Regexp, String] pattern # The command to add or replace(found at _pattern_). # # @param [Pry::Command] command # The command to add. # # @return [Pry::Command] # Returns the new command (matched with "pattern".) # # @example # Pry.config.commands["help"] = MyHelpCommand # def []=(pattern, command) if command.equal?(nil) return @commands.delete(pattern) end unless Class === command && command < Pry::Command raise TypeError, "command is not a subclass of Pry::Command" end bind_command_to_pattern = pattern != command.match if bind_command_to_pattern command_copy = command.dup command_copy.match = pattern @commands[pattern] = command_copy else @commands[pattern] = command end end # # Add a command to set. # # @param [Command] command # a subclass of Pry::Command. # def add_command(command) self[command.match] = command end # Find the command that the user might be trying to refer to. # @param [String] search The user's search. # @return [Pry::Command?] def find_command_for_help(search) find_command(search) || (begin find_command_by_match_or_listing(search) rescue ArgumentError nil end) end # Is the given line a command invocation? # @param [String] val # @return [Boolean] def valid_command?(val) !!find_command(val) end # Process the given line to see whether it needs executing as a command. # @param [String] val The line to execute # @param [Hash] context The context to execute the commands with # @return [CommandSet::Result] def process_line(val, context={}) if command = find_command(val) context = context.merge(:command_set => self) retval = command.new(context).process_line(val) Result.new(true, retval) else Result.new(false) end end # @private (used for testing) def run_command(context, match, *args) command = @commands[match] or raise NoCommandError.new(match, self) command.new(context).call_safely(*args) end # Generate completions for the user's search. # @param [String] search The line to search for # @param [Hash] context The context to create the command with # @return [Array] def complete(search, context={}) if command = find_command(search) command.new(context).complete(search) else @commands.keys.select do |key| String === key && key.start_with?(search) end.map{ |key| key + " " } end end end # Wraps the return result of process_commands, indicates if the # result IS a command and what kind of command (e.g void) class Result attr_reader :retval def initialize(is_command, retval = nil) @is_command, @retval = is_command, retval end # Is the result a command? # @return [Boolean] def command? @is_command end # Is the result a command and if it is, is it a void command? # (one that does not return a value) # @return [Boolean] def void_command? retval == Command::VOID_VALUE end end end pry-0.10.3/lib/pry/commands.rb000066400000000000000000000002411260757071700161240ustar00rootroot00000000000000# Default commands used by Pry. Pry::Commands = Pry::CommandSet.new Dir[File.expand_path('../commands', __FILE__) << '/*.rb'].each do |file| require file end pry-0.10.3/lib/pry/commands/000077500000000000000000000000001260757071700156025ustar00rootroot00000000000000pry-0.10.3/lib/pry/commands/amend_line.rb000066400000000000000000000066251260757071700202330ustar00rootroot00000000000000class Pry class Command::AmendLine < Pry::ClassCommand match(/amend-line(?: (-?\d+)(?:\.\.(-?\d+))?)?/) group 'Editing' description 'Amend a line of input in multi-line mode.' command_options :interpolate => false, :listing => 'amend-line' banner <<-'BANNER' Amend a line of input in multi-line mode. `amend-line N`, where the N represents line to replace. Can also specify a range of lines using `amend-line N..M` syntax. Passing "!" as replacement content deletes the line(s) instead. amend-line 1 puts 'new' # replace line 1 amend-line 1..4 ! # delete lines 1..4 amend-line 3 >puts 'bye' # insert before line 3 amend-line puts 'appended' # no line number modifies immediately preceding line BANNER def process raise CommandError, "No input to amend." if eval_string.empty? eval_string.replace amended_input(eval_string) run "fix-indent" run "show-input" end private # @param [String] string The string to amend. # @return [String] A new string with the amendments applied to it. def amended_input(string) input_array = eval_string.each_line.to_a if arg_string == "!" delete_from_array(input_array, line_range) elsif arg_string.start_with?(">") insert_into_array(input_array, line_range) else replace_in_array(input_array, line_range) end input_array.join end def delete_from_array(array, range) array.slice!(range) end def insert_into_array(array, range) insert_slot = Array(range).first array.insert(insert_slot, arg_string[1..-1] << "\n") end def replace_in_array(array, range) array[range] = arg_string + "\n" end # @return [Fixnum] The number of lines currently in `eval_string` (the input buffer). def line_count eval_string.lines.count end # Returns the (one-indexed) start and end lines given by the user. # The lines in this range will be affected by the `amend-line`. # Returns `nil` if no lines were specified by the user. # @return [Array, nil] def start_and_end_line_number start_line_number, end_line_number = args end_line_number ||= start_line_number.to_i [start_line_number.to_i, end_line_number.to_i] if start_line_number end # Takes two numbers that are 1-indexed, and returns a range (or # number) that is 0-indexed. 1-indexed means the first element is # indentified by 1 rather than by 0 (as is the case for Ruby arrays). # @param [Fixnum] start_line_number One-indexed number. # @param [Fixnum] end_line_number One-indexed number. # @return [Range] The zero-indexed range. def zero_indexed_range_from_one_indexed_numbers(start_line_number, end_line_number) # FIXME: one_index_number is a horrible name for this method one_index_number(start_line_number)..one_index_number(end_line_number) end # The lines (or line) that will be modified by the `amend-line`. # @return [Range, Fixnum] The lines or line. def line_range start_line_number, end_line_number = start_and_end_line_number if start_line_number zero_indexed_range_from_one_indexed_numbers(start_line_number, end_line_number) else line_count - 1 end end end Pry::Commands.add_command(Pry::Command::AmendLine) end pry-0.10.3/lib/pry/commands/bang.rb000066400000000000000000000007421260757071700170410ustar00rootroot00000000000000class Pry class Command::Bang < Pry::ClassCommand match(/^\s*!\s*$/) group 'Editing' description 'Clear the input buffer.' command_options :use_prefix => false banner <<-'BANNER' Clear the input buffer. Useful if the parsing process goes wrong and you get stuck in the read loop. BANNER def process output.puts 'Input buffer cleared!' eval_string.replace('') end end Pry::Commands.add_command(Pry::Command::Bang) end pry-0.10.3/lib/pry/commands/bang_pry.rb000066400000000000000000000005661260757071700177370ustar00rootroot00000000000000class Pry class Command::BangPry < Pry::ClassCommand match '!pry' group 'Navigating Pry' description 'Start a Pry session on current self.' banner <<-'BANNER' Start a Pry session on current self. Also works mid multi-line expression. BANNER def process target.pry end end Pry::Commands.add_command(Pry::Command::BangPry) end pry-0.10.3/lib/pry/commands/cat.rb000066400000000000000000000045101260757071700166760ustar00rootroot00000000000000class Pry class Command::Cat < Pry::ClassCommand require 'pry/commands/cat/abstract_formatter.rb' require 'pry/commands/cat/input_expression_formatter.rb' require 'pry/commands/cat/exception_formatter.rb' require 'pry/commands/cat/file_formatter.rb' match 'cat' group 'Input and Output' description "Show code from a file, Pry's input buffer, or the last exception." banner <<-'BANNER' Usage: cat FILE cat --ex [STACK_INDEX] cat --in [INPUT_INDEX_OR_RANGE] `cat` is capable of showing part or all of a source file, the context of the last exception, or an expression from Pry's input history. `cat --ex` defaults to showing the lines surrounding the location of the last exception. Invoking it more than once travels up the exception's backtrace, and providing a number shows the context of the given index of the backtrace. BANNER def options(opt) opt.on :ex, "Show the context of the last exception", :optional_argument => true, :as => Integer opt.on :i, :in, "Show one or more entries from Pry's expression history", :optional_argument => true, :as => Range, :default => -5..-1 opt.on :s, :start, "Starting line (defaults to the first line)", :optional_argument => true, :as => Integer opt.on :e, :end, "Ending line (defaults to the last line)", :optional_argument => true, :as => Integer opt.on :l, :'line-numbers', "Show line numbers" opt.on :t, :type, "The file type for syntax highlighting (e.g., 'ruby' or 'python')", :argument => true, :as => Symbol end def process output = case when opts.present?(:ex) ExceptionFormatter.new(_pry_.last_exception, _pry_, opts).format when opts.present?(:in) InputExpressionFormatter.new(_pry_.input_array, opts).format else FileFormatter.new(args.first, _pry_, opts).format end _pry_.pager.page output end def complete(search) super | load_path_completions end def load_path_completions $LOAD_PATH.flat_map do |path| Dir[path + '/**/*'].map { |f| next if File.directory?(f) f.sub!(path + '/', '') } end end end Pry::Commands.add_command(Pry::Command::Cat) end pry-0.10.3/lib/pry/commands/cat/000077500000000000000000000000001260757071700163515ustar00rootroot00000000000000pry-0.10.3/lib/pry/commands/cat/abstract_formatter.rb000066400000000000000000000011201260757071700225560ustar00rootroot00000000000000class Pry class Command::Cat class AbstractFormatter include Pry::Helpers::CommandHelpers include Pry::Helpers::BaseHelpers private def decorate(content) content.code_type = code_type content.between(*between_lines). with_line_numbers(use_line_numbers?).highlighted end def code_type opts[:type] || :ruby end def use_line_numbers? opts.present?(:'line-numbers') || opts.present?(:ex) end def between_lines [opts[:start] || 1, opts[:end] || -1] end end end end pry-0.10.3/lib/pry/commands/cat/exception_formatter.rb000066400000000000000000000040431260757071700227600ustar00rootroot00000000000000class Pry class Command::Cat class ExceptionFormatter < AbstractFormatter attr_reader :ex attr_reader :opts attr_reader :_pry_ def initialize(exception, _pry_, opts) @ex = exception @opts = opts @_pry_ = _pry_ end def format check_for_errors set_file_and_dir_locals(backtrace_file, _pry_, _pry_.current_context) code = decorate(Pry::Code.from_file(backtrace_file). between(*start_and_end_line_for_code_window). with_marker(backtrace_line)) "#{header}#{code}" end private def code_window_size _pry_.config.default_window_size || 5 end def backtrace_level return @backtrace_level if @backtrace_level bl = if opts[:ex].nil? ex.bt_index else ex.bt_index = absolute_index_number(opts[:ex], ex.backtrace.size) end increment_backtrace_level @backtrace_level = bl end def increment_backtrace_level ex.inc_bt_index end def backtrace_file Array(ex.bt_source_location_for(backtrace_level)).first end def backtrace_line Array(ex.bt_source_location_for(backtrace_level)).last end def check_for_errors raise CommandError, "No exception found." unless ex raise CommandError, "The given backtrace level is out of bounds." unless backtrace_file end def start_and_end_line_for_code_window start_line = backtrace_line - code_window_size start_line = 1 if start_line < 1 [start_line, backtrace_line + code_window_size] end def header unindent %{ #{Helpers::Text.bold 'Exception:'} #{ex.class}: #{ex.message} -- #{Helpers::Text.bold('From:')} #{backtrace_file} @ line #{backtrace_line} @ #{Helpers::Text.bold("level: #{backtrace_level}")} of backtrace (of #{ex.backtrace.size - 1}). } end end end end pry-0.10.3/lib/pry/commands/cat/file_formatter.rb000066400000000000000000000031021260757071700216740ustar00rootroot00000000000000class Pry class Command::Cat class FileFormatter < AbstractFormatter attr_reader :file_with_embedded_line attr_reader :opts attr_reader :_pry_ def initialize(file_with_embedded_line, _pry_, opts) @file_with_embedded_line = file_with_embedded_line @opts = opts @_pry_ = _pry_ @code_from_file = Pry::Code.from_file(file_name) end def format raise CommandError, "Must provide a filename, --in, or --ex." if !file_with_embedded_line set_file_and_dir_locals(file_name, _pry_, _pry_.current_context) decorate(@code_from_file) end def file_and_line file_name, line_num = file_with_embedded_line.split(/:(?!\/|\\)/) [file_name, line_num ? line_num.to_i : nil] end private def file_name file_and_line.first end def line_number file_and_line.last end def code_window_size _pry_.config.default_window_size || 7 end def decorate(content) line_number ? super.around(line_number, code_window_size) : super end def code_type opts[:type] || detect_code_type_from_file(file_name) end def detect_code_type_from_file(file_name) code_type = @code_from_file.code_type if code_type == :unknown name = File.basename(file_name).split('.', 2).first case name when "Rakefile", "Gemfile" :ruby else :text end else code_type end end end end end pry-0.10.3/lib/pry/commands/cat/input_expression_formatter.rb000066400000000000000000000022041260757071700243750ustar00rootroot00000000000000class Pry class Command::Cat class InputExpressionFormatter < AbstractFormatter attr_accessor :input_expressions attr_accessor :opts def initialize(input_expressions, opts) @input_expressions = input_expressions @opts = opts end def format raise CommandError, "No input expressions!" if numbered_input_items.length < 1 if numbered_input_items.length > 1 content = "" numbered_input_items.each do |i, s| content << "#{Helpers::Text.bold(i.to_s)}:\n" << decorate(Pry::Code(s).with_indentation(2)).to_s end content else decorate(Pry::Code(selected_input_items.first)) end end private def selected_input_items input_expressions[normalized_expression_range] || [] end def numbered_input_items @numbered_input_items ||= normalized_expression_range.zip(selected_input_items). reject { |_, s| s.nil? || s == "" } end def normalized_expression_range absolute_index_range(opts[:i], input_expressions.length) end end end end pry-0.10.3/lib/pry/commands/cd.rb000066400000000000000000000021061260757071700165140ustar00rootroot00000000000000class Pry class Command::Cd < Pry::ClassCommand match 'cd' group 'Context' description 'Move into a new context (object or scope).' banner <<-'BANNER' Usage: cd [OPTIONS] [--help] Move into new context (object or scope). As in UNIX shells use `cd ..` to go back, `cd /` to return to Pry top-level and `cd -` to toggle between last two scopes. Complex syntax (e.g `cd ../@x/@y`) also supported. cd @x cd .. cd / cd - https://github.com/pry/pry/wiki/State-navigation#wiki-Changing_scope BANNER def process state.old_stack ||= [] if arg_string.strip == "-" unless state.old_stack.empty? _pry_.binding_stack, state.old_stack = state.old_stack, _pry_.binding_stack end else stack = ObjectPath.new(arg_string, _pry_.binding_stack).resolve if stack && stack != _pry_.binding_stack state.old_stack = _pry_.binding_stack _pry_.binding_stack = stack end end end end Pry::Commands.add_command(Pry::Command::Cd) end pry-0.10.3/lib/pry/commands/change_inspector.rb000066400000000000000000000014221260757071700214410ustar00rootroot00000000000000class Pry::Command::ChangeInspector < Pry::ClassCommand match 'change-inspector' group 'Input and Output' description 'Change the current inspector proc.' command_options argument_required: true banner <<-BANNER Usage: change-inspector NAME Change the proc used to print return values. See list-inspectors for a list of available procs and a short description of what each one does. BANNER def process(inspector) if inspector_map.key?(inspector) _pry_.print = inspector_map[inspector][:value] output.puts "Switched to the '#{inspector}' inspector!" else raise Pry::CommandError, "'#{inspector}' isn't a known inspector!" end end private def inspector_map Pry::Inspector::MAP end Pry::Commands.add_command(self) end pry-0.10.3/lib/pry/commands/change_prompt.rb000066400000000000000000000011501260757071700207520ustar00rootroot00000000000000class Pry::Command::ChangePrompt < Pry::ClassCommand match 'change-prompt' group 'Input and Output' description 'Change the current prompt.' command_options argument_required: true banner <<-BANNER Usage: change-prompt NAME Change the current prompt. See list-prompts for a list of available prompts. BANNER def process(prompt) if prompt_map.key?(prompt) _pry_.prompt = prompt_map[prompt][:value] else raise Pry::CommandError, "'#{prompt}' isn't a known prompt!" end end private def prompt_map Pry::Prompt::MAP end Pry::Commands.add_command(self) end pry-0.10.3/lib/pry/commands/code_collector.rb000066400000000000000000000115051260757071700211110ustar00rootroot00000000000000class Pry class Command::CodeCollector include Helpers::CommandHelpers attr_reader :args attr_reader :opts attr_reader :_pry_ # The name of the explicitly given file (if any). attr_accessor :file class << self attr_accessor :input_expression_ranges attr_accessor :output_result_ranges end @input_expression_ranges = [] @output_result_ranges = [] def initialize(args, opts, _pry_) @args = args @opts = opts @_pry_ = _pry_ end # Add the `--lines`, `-o`, `-i`, `-s`, `-d` options. def self.inject_options(opt) @input_expression_ranges = [] @output_result_ranges = [] opt.on :l, :lines, "Restrict to a subset of lines. Takes a line number or range", :optional_argument => true, :as => Range, :default => 1..-1 opt.on :o, :out, "Select lines from Pry's output result history. Takes an index or range", :optional_argument => true, :as => Range, :default => -5..-1 do |r| output_result_ranges << (r || (-5..-1)) end opt.on :i, :in, "Select lines from Pry's input expression history. Takes an index or range", :optional_argument => true, :as => Range, :default => -5..-1 do |r| input_expression_ranges << (r || (-5..-1)) end opt.on :s, :super, "Select the 'super' method. Can be repeated to traverse the ancestors", :as => :count opt.on :d, :doc, "Select lines from the code object's documentation" end # The content (i.e code/docs) for the selected object. # If the user provided a bare code object, it returns the source. # If the user provided the `-i` or `-o` switches, it returns the # selected input/output lines joined as a string. If the user used # `-d CODE_OBJECT` it returns the docs for that code object. # # @return [String] def content return @content if @content raise CommandError, "Only one of --out, --in, --doc and CODE_OBJECT may be specified." if bad_option_combination? content = case when opts.present?(:o) pry_output_content when opts.present?(:i) pry_input_content when opts.present?(:d) code_object_doc else code_object_source_or_file end @content ||= restrict_to_lines(content, line_range) end # The code object # # @return [Pry::WrappedModule, Pry::Method, Pry::Command] def code_object Pry::CodeObject.lookup(obj_name, _pry_, :super => opts[:super]) end # Given a string and a range, return the `range` lines of that # string. # # @param [String] content # @param [Range, Fixnum] range # @return [String] The string restricted to the given range def restrict_to_lines(content, range) Array(content.lines.to_a[range]).join end # The selected `_pry_.output_array` as a string, as specified by # the `-o` switch. # # @return [String] def pry_output_content pry_array_content_as_string(_pry_.output_array, self.class.output_result_ranges) do |v| _pry_.config.gist.inspecter.call(v) end end # The selected `_pry_.input_array` as a string, as specified by # the `-i` switch. # # @return [String] def pry_input_content pry_array_content_as_string(_pry_.input_array, self.class.input_expression_ranges) { |v| v } end # The line range passed to `--lines`, converted to a 0-indexed range. def line_range opts.present?(:lines) ? one_index_range_or_number(opts[:lines]) : 0..-1 end # Name of the object argument def obj_name @obj_name ||= args.empty? ? "" : args.join(" ") end private def bad_option_combination? [opts.present?(:in), opts.present?(:out), !args.empty?].count(true) > 1 end def pry_array_content_as_string(array, ranges, &block) all = '' ranges.each do |range| raise CommandError, "Minimum value for range is 1, not 0." if convert_to_range(range).first == 0 ranged_array = Array(array[range]) || [] ranged_array.compact.each { |v| all << block.call(v) } end all end def code_object_doc (code_object && code_object.doc) or could_not_locate(obj_name) end def code_object_source_or_file (code_object && code_object.source) || file_content end def file_content if File.exists?(obj_name) # Set the file accessor. self.file = obj_name File.read(obj_name) else could_not_locate(obj_name) end end def could_not_locate(name) raise CommandError, "Cannot locate: #{name}!" end def convert_to_range(n) if !n.is_a?(Range) (n..n) else n end end end end pry-0.10.3/lib/pry/commands/disable_pry.rb000066400000000000000000000015351260757071700204300ustar00rootroot00000000000000class Pry class Command::DisablePry < Pry::ClassCommand match 'disable-pry' group 'Navigating Pry' description 'Stops all future calls to pry and exits the current session.' banner <<-'BANNER' Usage: disable-pry After this command is run any further calls to pry will immediately return `nil` without interrupting the flow of your program. This is particularly useful when you've debugged the problem you were having, and now wish the program to run to the end. As alternatives, consider using `exit!` to force the current Ruby process to quit immediately; or using `edit-method -p` to remove the `binding.pry` from the code. BANNER def process ENV['DISABLE_PRY'] = 'true' _pry_.run_command "exit" end end Pry::Commands.add_command(Pry::Command::DisablePry) end pry-0.10.3/lib/pry/commands/disabled_commands.rb000066400000000000000000000002371260757071700215610ustar00rootroot00000000000000Pry::Commands.disabled_command("edit-method", "Use `edit` instead.") Pry::Commands.disabled_command("show-command", "Use show-source [command_name] instead.") pry-0.10.3/lib/pry/commands/easter_eggs.rb000066400000000000000000000063001260757071700204160ustar00rootroot00000000000000class Pry Pry::Commands.instance_eval do command "nyan-cat", "", :requires_gem => ["nyancat"] do run ".nyancat" end command(/!s\/(.*?)\/(.*?)/, "") do |source, dest| eval_string.gsub!(/#{source}/) { dest } run "show-input" end command "get-naked", "" do text = %{ -- We dont have to take our clothes off to have a good time. We could dance & party all night And drink some cherry wine. -- Jermaine Stewart } output.puts text text end command "east-coker", "" do text = %{ -- Now the light falls Across the open field, leaving the deep lane Shuttered with branches, dark in the afternoon, Where you lean against a bank while a van passes, And the deep lane insists on the direction Into the village, in the electric heat Hypnotised. In a warm haze the sultry light Is absorbed, not refracted, by grey stone. The dahlias sleep in the empty silence. Wait for the early owl. -- T.S Eliot } output.puts text text end command "cohen-poem", "" do text = %{ -- When this American woman, whose thighs are bound in casual red cloth, comes thundering past my sitting place like a forest-burning Mongol tribe, the city is ravished and brittle buildings of a hundred years splash into the street; and my eyes are burnt for the embroidered Chinese girls, already old, and so small between the thin pines on these enormous landscapes, that if you turn your head they are lost for hours. -- Leonard Cohen } output.puts text text end command "pessoa-poem", "" do output.puts <<-TEXT -- I've gone to bed with every feeling, I've been the pimp of every emotion, All felt sensations have bought me drinks, I've traded glances with every motive for every act, I've held hands with every urge to depart, .. Rage, foam, the vastness that doesn't fit in my handkerchief, The dog in heat howling in the night, The pond from the farm going in circles around my insomnia, The woods as they were, on our late-afternoon walks, the rose, The indifferent tuft of hair, the moss, the pines, The rage of not containing all this, not retaining all this, O abstract hunger for things, impotent libido for moments, Intellectual orgy of feeling life! -- Fernando Pessoa TEXT end command "test-ansi", "" do prev_color = _pry_.config.color _pry_.config.color = true picture = unindent <<-'EOS'.gsub(/[[:alpha:]!]/) { |s| text.red(s) } ____ _______________________ / \ | A W G | / O O \ | N I O N ! | | | | S S R I ! | \ \__/ / __| I K ! | \____/ \________________________| EOS if windows_ansi? move_up = proc { |n| "\e[#{n}F" } else move_up = proc { |n| "\e[#{n}A\e[0G" } end output.puts "\n" * 6 output.puts picture.lines.map(&:chomp).reverse.join(move_up[1]) output.puts "\n" * 6 output.puts "** ENV['TERM'] is #{ENV['TERM']} **\n\n" _pry_.config.color = prev_color end end end pry-0.10.3/lib/pry/commands/edit.rb000066400000000000000000000146371260757071700170670ustar00rootroot00000000000000class Pry class Command::Edit < Pry::ClassCommand require 'pry/commands/edit/exception_patcher' require 'pry/commands/edit/file_and_line_locator' match 'edit' group 'Editing' description 'Invoke the default editor on a file.' banner <<-'BANNER' Usage: edit [--no-reload|--reload|--patch] [--line LINE] [--temp|--ex|FILE[:LINE]|OBJECT|--in N] Open a text editor. When no FILE is given, edits the pry input buffer. When a method/module/command is given, the code is opened in an editor. Ensure `Pry.config.editor` or `_pry_.config.editor` is set to your editor of choice. edit sample.rb edit -p MyClass#my_method edit sample.rb --line 105 edit MyClass edit MyClass#my_method edit --ex edit --method edit --ex -p https://github.com/pry/pry/wiki/Editor-integration#wiki-Edit_command BANNER def options(opt) opt.on :e, :ex, "Open the file that raised the most recent exception (_ex_.file)", :optional_argument => true, :as => Integer opt.on :i, :in, "Open a temporary file containing the Nth input expression. N may be a range", :optional_argument => true, :as => Range, :default => -1..-1 opt.on :t, :temp, "Open an empty temporary file" opt.on :l, :line, "Jump to this line in the opened file", :argument => true, :as => Integer opt.on :n, :"no-reload", "Don't automatically reload the edited file" opt.on :c, :current, "Open the current __FILE__ and at __LINE__ (as returned by `whereami`)" opt.on :r, :reload, "Reload the edited code immediately (default for ruby files)" opt.on :p, :patch, "Instead of editing the object's file, try to edit in a tempfile and apply as a monkey patch" opt.on :m, :method, "Explicitly edit the _current_ method (when inside a method context)." end def process if bad_option_combination? raise CommandError, "Only one of --ex, --temp, --in, --method and FILE may be specified." end if repl_edit? # code defined in pry, eval'd within pry. repl_edit elsif runtime_patch? # patch code without persisting changes apply_runtime_patch else # code stored in actual files, eval'd at top-level file_edit end end def repl_edit? !opts.present?(:ex) && !opts.present?(:current) && !opts.present?(:method) && filename_argument.empty? end def repl_edit content = Pry::Editor.new(_pry_).edit_tempfile_with_content(initial_temp_file_content, initial_temp_file_content.lines.count) silence_warnings do eval_string.replace content end end def file_based_exception? opts.present?(:ex) && !opts.present?(:patch) end def runtime_patch? !file_based_exception? && (opts.present?(:patch) || pry_method?(code_object)) end def apply_runtime_patch if patch_exception? ExceptionPatcher.new(_pry_, state, file_and_line_for_current_exception).perform_patch else if code_object.is_a?(Pry::Method) code_object.redefine Pry::Editor.new(_pry_).edit_tempfile_with_content(code_object.source) else raise NotImplementedError, "Cannot yet patch #{code_object} objects!" end end end def ensure_file_name_is_valid(file_name) raise CommandError, "Cannot find a valid file for #{filename_argument}" if !file_name raise CommandError, "#{file_name} is not a valid file name, cannot edit!" if not_a_real_file?(file_name) end def file_and_line_for_current_exception FileAndLineLocator.from_exception(_pry_.last_exception, opts[:ex].to_i) end def file_and_line file_name, line = if opts.present?(:current) FileAndLineLocator.from_binding(target) elsif opts.present?(:ex) file_and_line_for_current_exception elsif code_object FileAndLineLocator.from_code_object(code_object, filename_argument) else # when file and line are passed as a single arg, e.g my_file.rb:30 FileAndLineLocator.from_filename_argument(filename_argument) end [file_name, opts.present?(:line) ? opts[:l].to_i : line] end def file_edit file_name, line = file_and_line ensure_file_name_is_valid(file_name) Pry::Editor.new(_pry_).invoke_editor(file_name, line, reload?(file_name)) set_file_and_dir_locals(file_name) if reload?(file_name) silence_warnings do load file_name end end end def filename_argument args.join(' ') end def code_object @code_object ||= !probably_a_file?(filename_argument) && Pry::CodeObject.lookup(filename_argument, _pry_) end def pry_method?(code_object) code_object.is_a?(Pry::Method) && code_object.pry_method? end def patch_exception? opts.present?(:ex) && opts.present?(:patch) end def bad_option_combination? [opts.present?(:ex), opts.present?(:temp), opts.present?(:in), opts.present?(:method), !filename_argument.empty?].count(true) > 1 end def input_expression case opts[:i] when Range (_pry_.input_array[opts[:i]] || []).join when Fixnum _pry_.input_array[opts[:i]] || "" else raise Pry::CommandError, "Not a valid range: #{opts[:i]}" end end def reloadable? opts.present?(:reload) || opts.present?(:ex) end def never_reload? opts.present?(:'no-reload') || _pry_.config.disable_auto_reload end def reload?(file_name="") (reloadable? || file_name.end_with?(".rb")) && !never_reload? end def initial_temp_file_content case when opts.present?(:temp) "" when opts.present?(:in) input_expression when eval_string.strip != "" eval_string else _pry_.input_array.reverse_each.find { |x| x && x.strip != "" } || "" end end def probably_a_file?(str) [".rb", ".c", ".py", ".yml", ".gemspec"].include?(File.extname(str)) || str =~ /\/|\\/ end end Pry::Commands.add_command(Pry::Command::Edit) end pry-0.10.3/lib/pry/commands/edit/000077500000000000000000000000001260757071700165275ustar00rootroot00000000000000pry-0.10.3/lib/pry/commands/edit/exception_patcher.rb000066400000000000000000000012211260757071700225540ustar00rootroot00000000000000class Pry class Command::Edit class ExceptionPatcher attr_accessor :_pry_ attr_accessor :state attr_accessor :file_and_line def initialize(_pry_, state, exception_file_and_line) @_pry_ = _pry_ @state = state @file_and_line = exception_file_and_line end # perform the patch def perform_patch file_name, _ = file_and_line lines = state.dynamical_ex_file || File.read(file_name) source = Pry::Editor.new(_pry_).edit_tempfile_with_content(lines) _pry_.evaluate_ruby source state.dynamical_ex_file = source.split("\n") end end end end pry-0.10.3/lib/pry/commands/edit/file_and_line_locator.rb000066400000000000000000000022671260757071700233560ustar00rootroot00000000000000class Pry class Command::Edit module FileAndLineLocator class << self def from_binding(target) [target.eval("__FILE__"), target.eval("__LINE__")] end def from_code_object(code_object, filename_argument) if File.exists?(code_object.source_file.to_s) [code_object.source_file, code_object.source_line] else raise CommandError, "Cannot find a file for #{filename_argument}!" end end def from_exception(exception, backtrace_level) raise CommandError, "No exception found." if exception.nil? file_name, line = exception.bt_source_location_for(backtrace_level) raise CommandError, "Exception has no associated file." if file_name.nil? raise CommandError, "Cannot edit exceptions raised in REPL." if Pry.eval_path == file_name [file_name, line] end # when file and line are passed as a single arg, e.g my_file.rb:30 def from_filename_argument(filename_argument) f = File.expand_path(filename_argument) l = f.sub!(/:(\d+)$/, "") ? $1.to_i : 1 [f, l] end end end end end pry-0.10.3/lib/pry/commands/exit.rb000066400000000000000000000022311260757071700170760ustar00rootroot00000000000000class Pry class Command::Exit < Pry::ClassCommand match 'exit' group 'Navigating Pry' description 'Pop the previous binding.' command_options :keep_retval => true banner <<-'BANNER' Usage: exit [OPTIONS] [--help] Aliases: quit Pop the previous binding (does NOT exit program). It can be useful to exit a context with a user-provided value. For instance an exit value can be used to determine program flow. exit "pry this" exit https://github.com/pry/pry/wiki/State-navigation#wiki-Exit_with_value BANNER def process if _pry_.binding_stack.one? _pry_.run_command "exit-all #{arg_string}" else # otherwise just pop a binding and return user supplied value process_pop_and_return end end def process_pop_and_return popped_object = _pry_.binding_stack.pop.eval('self') # return a user-specified value if given otherwise return the object return target.eval(arg_string) unless arg_string.empty? popped_object end end Pry::Commands.add_command(Pry::Command::Exit) Pry::Commands.alias_command 'quit', 'exit' end pry-0.10.3/lib/pry/commands/exit_all.rb000066400000000000000000000013021260757071700177240ustar00rootroot00000000000000class Pry class Command::ExitAll < Pry::ClassCommand match 'exit-all' group 'Navigating Pry' description 'End the current Pry session.' banner <<-'BANNER' Usage: exit-all [--help] Aliases: !!@ End the current Pry session (popping all bindings and returning to caller). Accepts optional return value. BANNER def process # calculate user-given value exit_value = target.eval(arg_string) # clear the binding stack _pry_.binding_stack.clear # break out of the repl loop throw(:breakout, exit_value) end end Pry::Commands.add_command(Pry::Command::ExitAll) Pry::Commands.alias_command '!!@', 'exit-all' end pry-0.10.3/lib/pry/commands/exit_program.rb000066400000000000000000000010541260757071700206270ustar00rootroot00000000000000class Pry class Command::ExitProgram < Pry::ClassCommand match 'exit-program' group 'Navigating Pry' description 'End the current program.' banner <<-'BANNER' Usage: exit-program [--help] Aliases: quit-program !!! End the current program. BANNER def process Kernel.exit target.eval(arg_string).to_i end end Pry::Commands.add_command(Pry::Command::ExitProgram) Pry::Commands.alias_command 'quit-program', 'exit-program' Pry::Commands.alias_command '!!!', 'exit-program' end pry-0.10.3/lib/pry/commands/find_method.rb000066400000000000000000000126531260757071700204160ustar00rootroot00000000000000class Pry class Command::FindMethod < Pry::ClassCommand extend Pry::Helpers::BaseHelpers match 'find-method' group 'Context' description 'Recursively search for a method within a Class/Module or the current namespace.' command_options :shellwords => false banner <<-'BANNER' Usage: find-method [-n|-c] METHOD [NAMESPACE] Recursively search for a method within a Class/Module or the current namespace. Use the `-n` switch (the default) to search for methods whose name matches the given regex. Use the `-c` switch to search for methods that contain the given code. # Find all methods whose name match /re/ inside # the Pry namespace. Matches Pry#repl, etc. find-method re Pry # Find all methods that contain the code: # output.puts inside the Pry namepsace. find-method -c 'output.puts' Pry BANNER def options(opt) opt.on :n, :name, "Search for a method by name" opt.on :c, :content, "Search for a method based on content in Regex form" end def process return if args.size < 1 klass = search_class matches = if opts.content? content_search(klass) else name_search(klass) end show_search_results(matches) end private # @return [Regexp] The pattern to search for. def pattern @pattern ||= ::Regexp.new args[0] end # Output the result of the search. # # @param [Array] matches def show_search_results(matches) if matches.empty? output.puts text.bold("No Methods Matched") else print_matches(matches) end end # The class to search for methods. # We only search classes, so if the search object is an # instance, return its class. If no search object is given # search `target_self`. def search_class klass = if args[1] target.eval(args[1]) else target_self end klass.is_a?(Module) ? klass : klass.class end # pretty-print a list of matching methods. # # @param [Array] matches def print_matches(matches) grouped = matches.group_by(&:owner) order = grouped.keys.sort_by{ |x| x.name || x.to_s } order.each do |klass| print_matches_for_class(klass, grouped) end end # Print matched methods for a class def print_matches_for_class(klass, grouped) output.puts text.bold(klass.name) grouped[klass].each do |method| header = method.name_with_owner output.puts header + additional_info(header, method) end end # Return the matched lines of method source if `-c` is given or "" # if `-c` was not given def additional_info(header, method) if opts.content? ": " << colorize_code(matched_method_lines(header, method)) else "" end end def matched_method_lines(header, method) method.source.split(/\n/).select {|x| x =~ pattern }.join("\n#{' ' * header.length}") end # Run the given block against every constant in the provided namespace. # # @param [Module] klass The namespace in which to start the search. # @param [Hash] done The namespaces we've already visited (private) # @yieldparam klass Each class/module in the namespace. # def recurse_namespace(klass, done={}, &block) return if !(Module === klass) || done[klass] done[klass] = true yield klass klass.constants.each do |name| next if klass.autoload?(name) begin const = klass.const_get(name) rescue RescuableException # constant loading is an inexact science at the best of times, # this often happens when a constant was .autoload? but someone # tried to load it. It's now not .autoload? but will still raise # a NameError when you access it. else recurse_namespace(const, done, &block) end end end # Gather all the methods in a namespace that pass the given block. # # @param [Module] namespace The namespace in which to search. # @yieldparam [Method] method The method to test # @yieldreturn [Boolean] # @return [Array] # def search_all_methods(namespace) done = Hash.new{ |h,k| h[k] = {} } matches = [] recurse_namespace(namespace) do |klass| (Pry::Method.all_from_class(klass) + Pry::Method.all_from_obj(klass)).each do |method| next if done[method.owner][method.name] done[method.owner][method.name] = true matches << method if yield method end end matches end # Search for all methods with a name that matches the given regex # within a namespace. # # @param [Module] namespace The namespace to search # @return [Array] # def name_search(namespace) search_all_methods(namespace) do |meth| meth.name =~ pattern end end # Search for all methods who's implementation matches the given regex # within a namespace. # # @param [Module] namespace The namespace to search # @return [Array] # def content_search(namespace) search_all_methods(namespace) do |meth| begin meth.source =~ pattern rescue RescuableException false end end end end Pry::Commands.add_command(Pry::Command::FindMethod) end pry-0.10.3/lib/pry/commands/fix_indent.rb000066400000000000000000000006451260757071700202630ustar00rootroot00000000000000class Pry class Command::FixIndent < Pry::ClassCommand match 'fix-indent' group 'Input and Output' description "Correct the indentation for contents of the input buffer" banner <<-USAGE Usage: fix-indent USAGE def process indented_str = Pry::Indent.indent(eval_string) eval_string.replace indented_str end end Pry::Commands.add_command(Pry::Command::FixIndent) end pry-0.10.3/lib/pry/commands/gem_cd.rb000066400000000000000000000011211260757071700173400ustar00rootroot00000000000000class Pry class Command::GemCd < Pry::ClassCommand match 'gem-cd' group 'Gems' description "Change working directory to specified gem's directory." command_options :argument_required => true banner <<-'BANNER' Usage: gem-cd GEM_NAME Change the current working directory to that in which the given gem is installed. BANNER def process(gem) Dir.chdir(Rubygem.spec(gem).full_gem_path) output.puts(Dir.pwd) end def complete(str) Rubygem.complete(str) end end Pry::Commands.add_command(Pry::Command::GemCd) end pry-0.10.3/lib/pry/commands/gem_install.rb000066400000000000000000000015161260757071700204300ustar00rootroot00000000000000class Pry class Command::GemInstall < Pry::ClassCommand match 'gem-install' group 'Gems' description 'Install a gem and refresh the gem cache.' command_options :argument_required => true banner <<-'BANNER' Usage: gem-install GEM_NAME Installs the given gem, refreshes the gem cache, and requires the gem for you based on a best guess from the gem name. gem-install pry-stack_explorer BANNER def setup require 'rubygems/dependency_installer' unless defined? Gem::DependencyInstaller end def process(gem) Rubygem.install(gem) output.puts "Gem `#{ text.green(gem) }` installed." require gem rescue LoadError require_path = gem.split('-').join('/') require require_path end end Pry::Commands.add_command(Pry::Command::GemInstall) end pry-0.10.3/lib/pry/commands/gem_list.rb000066400000000000000000000016171260757071700177370ustar00rootroot00000000000000class Pry class Command::GemList < Pry::ClassCommand match 'gem-list' group 'Gems' description 'List and search installed gems.' banner <<-'BANNER' Usage: gem-list [REGEX] List all installed gems, when a regex is provided, limit the output to those that match the regex. BANNER def process(pattern = nil) pattern = Regexp.compile(pattern || '') gems = Rubygem.list(pattern).group_by(&:name) gems.each do |gem, specs| specs.sort! do |a,b| Gem::Version.new(b.version) <=> Gem::Version.new(a.version) end versions = specs.each_with_index.map do |spec, index| index == 0 ? text.bright_green(spec.version.to_s) : text.green(spec.version.to_s) end output.puts "#{text.default gem} (#{versions.join ', '})" end end end Pry::Commands.add_command(Pry::Command::GemList) end pry-0.10.3/lib/pry/commands/gem_open.rb000066400000000000000000000013041260757071700177160ustar00rootroot00000000000000class Pry class Command::GemOpen < Pry::ClassCommand match 'gem-open' group 'Gems' description 'Opens the working directory of the gem in your editor.' command_options :argument_required => true banner <<-'BANNER' Usage: gem-open GEM_NAME Change the current working directory to that in which the given gem is installed, and then opens your text editor. gem-open pry-exception_explorer BANNER def process(gem) Dir.chdir(Rubygem.spec(gem).full_gem_path) do Pry::Editor.invoke_editor(".", 0, false) end end def complete(str) Rubygem.complete(str) end end Pry::Commands.add_command(Pry::Command::GemOpen) end pry-0.10.3/lib/pry/commands/gist.rb000066400000000000000000000055061260757071700171030ustar00rootroot00000000000000class Pry class Command::Gist < Pry::ClassCommand match 'gist' group 'Misc' description 'Upload code, docs, history to https://gist.github.com/.' command_options :requires_gem => "gist" banner <<-'BANNER' Usage: gist [OPTIONS] [--help] The gist command enables you to gist code from files and methods to github. gist -i 20 --lines 1..3 gist Pry#repl --lines 1..-1 gist Rakefile --lines 5 BANNER def setup require 'gist' end def options(opt) CodeCollector.inject_options(opt) opt.on :login, "Authenticate the gist gem with GitHub" opt.on :p, :public, "Create a public gist (default: false)", :default => false opt.on :clip, "Copy the selected content to clipboard instead, do NOT gist it", :default => false end def process return ::Gist.login! if opts.present?(:login) cc = CodeCollector.new(args, opts, _pry_) if cc.content =~ /\A\s*\z/ raise CommandError, "Found no code to gist." end if opts.present?(:clip) clipboard_content(cc.content) else # we're overriding the default behavior of the 'in' option (as # defined on CodeCollector) with our local behaviour. content = opts.present?(:in) ? input_content : cc.content gist_content content, cc.file end end def clipboard_content(content) ::Gist.copy(content) output.puts "Copied content to clipboard!" end def input_content content = "" CodeCollector.input_expression_ranges.each do |range| input_expressions = _pry_.input_array[range] || [] Array(input_expressions).each_with_index do |code, index| corrected_index = index + range.first if code && code != "" content << code if code !~ /;\Z/ content << "#{comment_expression_result_for_gist(_pry_.config.gist.inspecter.call(_pry_.output_array[corrected_index]))}" end end end end content end def comment_expression_result_for_gist(result) content = "" result.lines.each_with_index do |line, index| if index == 0 content << "# => #{line}" else content << "# #{line}" end end content end def gist_content(content, filename) response = ::Gist.gist(content, :filename => filename || "pry_gist.rb", :public => !!opts[:p]) if response url = response['html_url'] message = "Gist created at URL #{url}" begin ::Gist.copy(url) message << ", which is now in the clipboard." rescue ::Gist::ClipboardError end output.puts message end end end Pry::Commands.add_command(Pry::Command::Gist) Pry::Commands.alias_command 'clipit', 'gist --clip' end pry-0.10.3/lib/pry/commands/help.rb000066400000000000000000000115061260757071700170620ustar00rootroot00000000000000class Pry class Command::Help < Pry::ClassCommand match 'help' group 'Help' description 'Show a list of commands or information about a specific command.' banner <<-'BANNER' Usage: help [COMMAND] With no arguments, help lists all the available commands along with their descriptions. When given a command name as an argument, shows the help for that command. BANNER # We only want to show commands that have descriptions, so that the # easter eggs don't show up. def visible_commands visible = {} commands.each do |key, command| visible[key] = command if command.description && !command.description.empty? end visible end # Get a hash of available commands grouped by the "group" name. def command_groups visible_commands.values.group_by(&:group) end def process if args.empty? display_index(command_groups) else display_search(args.first) end end # Display the index view, with headings and short descriptions per command. # # @param [Hash>] groups def display_index(groups) help_text = [] sorted_group_names(groups).each do |group_name| commands = sorted_commands(groups[group_name]) if commands.any? help_text << help_text_for_commands(group_name, commands) end end _pry_.pager.page help_text.join("\n\n") end # Given a group name and an array of commands, # return the help string for those commands. # # @param [String] name The group name. # @param [Array] commands # @return [String] The generated help string. def help_text_for_commands(name, commands) "#{text.bold(name.capitalize)}\n" << commands.map do |command| " #{command.options[:listing].to_s.ljust(18)} #{command.description.capitalize}" end.join("\n") end # @param [Hash] groups # @return [Array] An array of sorted group names. def sorted_group_names(groups) groups.keys.sort_by(&method(:group_sort_key)) end # Sort an array of commands by their `listing` name. # # @param [Array] commands The commands to sort # @return [Array] commands sorted by listing name. def sorted_commands(commands) commands.sort_by{ |command| command.options[:listing].to_s } end # Display help for an individual command or group. # # @param [String] search The string to search for. def display_search(search) if command = command_set.find_command_for_help(search) display_command(command) else display_filtered_search_results(search) end end # Display help for a searched item, filtered first by group # and if that fails, filtered by command name. # # @param [String] search The string to search for. def display_filtered_search_results(search) groups = search_hash(search, command_groups) if groups.size > 0 display_index(groups) else display_filtered_commands(search) end end # Display help for a searched item, filtered by group # # @param [String] search The string to search for. def display_filtered_commands(search) filtered = search_hash(search, visible_commands) raise CommandError, "No help found for '#{args.first}'" if filtered.empty? if filtered.size == 1 display_command(filtered.values.first) else display_index({"'#{search}' commands" => filtered.values}) end end # Display help for an individual command. # # @param [Pry::Command] command def display_command(command) _pry_.pager.page command.new.help end # Find a subset of a hash that matches the user's search term. # # If there's an exact match a Hash of one element will be returned, # otherwise a sub-Hash with every key that matches the search will # be returned. # # @param [String] search the search term # @param [Hash] hash the hash to search def search_hash(search, hash) matching = {} hash.each_pair do |key, value| next unless key.is_a?(String) if normalize(key) == normalize(search) return {key => value} elsif normalize(key).start_with?(normalize(search)) matching[key] = value end end matching end # Clean search terms to make it easier to search group names # # @param [String] key # @return [String] def normalize(key) key.downcase.gsub(/pry\W+/, '') end def group_sort_key(group_name) [%w(Help Context Editing Introspection Input_and_output Navigating_pry Gems Basic Commands).index(group_name.gsub(' ', '_')) || 99, group_name] end end Pry::Commands.add_command(Pry::Command::Help) end pry-0.10.3/lib/pry/commands/hist.rb000066400000000000000000000127471260757071700171110ustar00rootroot00000000000000class Pry class Command::Hist < Pry::ClassCommand match 'hist' group 'Editing' description 'Show and replay Readline history.' banner <<-'BANNER' Usage: hist [--head|--tail] hist --all hist --head N hist --tail N hist --show START..END hist --grep PATTERN hist --clear hist --replay START..END hist --save [START..END] FILE Aliases: history Show and replay Readline history. BANNER def options(opt) opt.on :a, :all, "Display all history" opt.on :H, :head, "Display the first N items", :optional_argument => true, :as => Integer opt.on :T, :tail, "Display the last N items", :optional_argument => true, :as => Integer opt.on :s, :show, "Show the given range of lines", :optional_argument => true, :as => Range opt.on :G, :grep, "Show lines matching the given pattern", :argument => true, :as => String opt.on :c, :clear , "Clear the current session's history" opt.on :r, :replay, "Replay a line or range of lines", :argument => true, :as => Range opt.on :save, "Save history to a file", :argument => true, :as => Range opt.on :e, :'exclude-pry', "Exclude Pry commands from the history" opt.on :n, :'no-numbers', "Omit line numbers" end def process @history = find_history if opts.present?(:show) @history = @history.between(opts[:show]) end if opts.present?(:grep) @history = @history.grep(opts[:grep]) end @history = case when opts.present?(:head) @history.take_lines(1, opts[:head] || 10) when opts.present?(:tail) @history.take_lines(-(opts[:tail] || 10), opts[:tail] || 10) when opts.present?(:show) @history.between(opts[:show]) else @history end if opts.present?(:'exclude-pry') @history = @history.select do |loc| !command_set.valid_command?(loc.line) end end if opts.present?(:save) process_save elsif opts.present?(:clear) process_clear elsif opts.present?(:replay) process_replay else process_display end end private def process_display unless opts.present?(:'no-numbers') @history = @history.with_line_numbers end _pry_.pager.open do |pager| @history.print_to_output(pager, true) end end def process_save case opts[:save] when Range @history = @history.between(opts[:save]) unless args.first raise CommandError, "Must provide a file name." end file_name = File.expand_path(args.first) when String file_name = File.expand_path(opts[:save]) end output.puts "Saving history in #{file_name}..." File.open(file_name, 'w') { |f| f.write(@history.raw) } output.puts "History saved." end def process_clear Pry.history.clear output.puts "History cleared." end def process_replay @history = @history.between(opts[:r]) replay_sequence = @history.raw # If we met follow-up "hist" call, check for the "--replay" option # presence. If "hist" command is called with other options, proceed # further. check_for_juxtaposed_replay(replay_sequence) replay_sequence.lines.each do |line| _pry_.eval line, :generated => true end end # Checks +replay_sequence+ for the presence of neighboring replay calls. # @example # [1] pry(main)> hist --show 46894 # 46894: hist --replay 46675..46677 # [2] pry(main)> hist --show 46675..46677 # 46675: 1+1 # 46676: a = 100 # 46677: hist --tail # [3] pry(main)> hist --replay 46894 # Error: Replay index 46894 points out to another replay call: `hist -r 46675..46677` # [4] pry(main)> # # @raise [Pry::CommandError] If +replay_sequence+ contains another # "hist --replay" call # @param [String] replay_sequence The sequence of commands to be replayed # (per saltum) # @return [Boolean] `false` if +replay_sequence+ does not contain another # "hist --replay" call def check_for_juxtaposed_replay(replay_sequence) if replay_sequence =~ /\Ahist(?:ory)?\b/ # Create *fresh* instance of Options for parsing of "hist" command. _slop = self.slop _slop.parse replay_sequence.split(' ')[1..-1] if _slop.present?(:r) replay_sequence = replay_sequence.split("\n").join('; ') index = opts[:r] index = index.min if index.min == index.max || index.max.nil? raise CommandError, "Replay index #{ index } points out to another replay call: `#{ replay_sequence }`" end else false end end # Finds history depending on the given switch. # # @return [Pry::Code] if it finds `--all` (or `-a`) switch, returns all # entries in history. Without the switch returns only the entries from the # current Pry session. def find_history h = if opts.present?(:all) Pry.history.to_a else Pry.history.to_a.last(Pry.history.session_line_count) end # The last value in history will be the 'hist' command itself. Pry::Code(h[0..-2]) end end Pry::Commands.add_command(Pry::Command::Hist) Pry::Commands.alias_command 'history', 'hist' end pry-0.10.3/lib/pry/commands/import_set.rb000066400000000000000000000010661260757071700203170ustar00rootroot00000000000000class Pry class Command::ImportSet < Pry::ClassCommand match 'import-set' group 'Commands' # TODO: Provide a better description with examples and a general conception # of this command. description 'Import a Pry command set.' banner <<-'BANNER' Import a Pry command set. BANNER def process(command_set_name) raise CommandError, "Provide a command set name" if command_set.nil? set = target.eval(arg_string) _pry_.commands.import set end end Pry::Commands.add_command(Pry::Command::ImportSet) end pry-0.10.3/lib/pry/commands/install_command.rb000066400000000000000000000031571260757071700213010ustar00rootroot00000000000000class Pry class Command::InstallCommand < Pry::ClassCommand match 'install-command' group 'Commands' description 'Install a disabled command.' banner <<-'BANNER' Usage: install-command COMMAND Installs the gems necessary to run the given COMMAND. You will generally not need to run this unless told to by an error message. BANNER def process(name) require 'rubygems/dependency_installer' unless defined? Gem::DependencyInstaller command = find_command(name) unless command output.puts "Command #{ text.green(name) } is not found" return end if command_dependencies_met?(command.options) output.puts "Dependencies for #{ text.green(name) } are met. Nothing to do" return end output.puts "Attempting to install #{ text.green(name) } command..." gems_to_install = Array(command.options[:requires_gem]) gems_to_install.each do |g| next if Rubygem.installed?(g) output.puts "Installing #{ text.green(g) } gem..." Rubygem.install(g) end gems_to_install.each do |g| begin require g rescue LoadError fail_msg = "Required gem #{ text.green(g) } installed but not found." fail_msg += " Aborting command installation\n" fail_msg += 'Tips: 1. Check your PATH; 2. Run `bundle update`' raise CommandError, fail_msg end end output.puts "Installation of #{ text.green(name) } successful! Type `help #{name}` for information" end end Pry::Commands.add_command(Pry::Command::InstallCommand) end pry-0.10.3/lib/pry/commands/jump_to.rb000066400000000000000000000015151260757071700176060ustar00rootroot00000000000000class Pry class Command::JumpTo < Pry::ClassCommand match 'jump-to' group 'Navigating Pry' description 'Jump to a binding further up the stack.' banner <<-'BANNER' Jump to a binding further up the stack, popping all bindings below. BANNER def process(break_level) break_level = break_level.to_i nesting_level = _pry_.binding_stack.size - 1 case break_level when nesting_level output.puts "Already at nesting level #{nesting_level}" when (0...nesting_level) _pry_.binding_stack.slice!(break_level + 1, _pry_.binding_stack.size) else max_nest_level = nesting_level - 1 output.puts "Invalid nest level. Must be between 0 and #{max_nest_level}. Got #{break_level}." end end end Pry::Commands.add_command(Pry::Command::JumpTo) end pry-0.10.3/lib/pry/commands/list_inspectors.rb000066400000000000000000000015611260757071700213560ustar00rootroot00000000000000class Pry::Command::ListInspectors < Pry::ClassCommand match 'list-inspectors' group 'Input and Output' description 'List the inspector procs available for use.' banner <<-BANNER Usage: list-inspectors List the inspector procs available to print return values. You can use change-inspector to switch between them. BANNER def process output.puts heading("Available inspectors") + "\n" inspector_map.each do |name, inspector| output.write "Name: #{text.bold(name)}" output.puts selected_inspector?(inspector) ? selected_text : "" output.puts inspector[:description] output.puts end end private def inspector_map Pry::Inspector::MAP end def selected_text text.red " (selected) " end def selected_inspector?(inspector) _pry_.print == inspector[:value] end Pry::Commands.add_command(self) end pry-0.10.3/lib/pry/commands/list_prompts.rb000066400000000000000000000014361260757071700206720ustar00rootroot00000000000000class Pry::Command::ListPrompts < Pry::ClassCommand match 'list-prompts' group 'Input and Output' description 'List the prompts available for use.' banner <<-BANNER Usage: list-prompts List the available prompts. You can use change-prompt to switch between them. BANNER def process output.puts heading("Available prompts") + "\n" prompt_map.each do |name, prompt| output.write "Name: #{text.bold(name)}" output.puts selected_prompt?(prompt) ? selected_text : "" output.puts prompt[:description] output.puts end end private def prompt_map Pry::Prompt::MAP end def selected_text text.red " (selected) " end def selected_prompt?(prompt) _pry_.prompt == prompt[:value] end Pry::Commands.add_command(self) end pry-0.10.3/lib/pry/commands/ls.rb000066400000000000000000000120021260757071700165400ustar00rootroot00000000000000require 'pry/commands/ls/ls_entity' class Pry class Command::Ls < Pry::ClassCommand DEFAULT_OPTIONS = { :heading_color => :bright_blue, :public_method_color => :default, :private_method_color => :blue, :protected_method_color => :blue, :method_missing_color => :bright_red, :local_var_color => :yellow, :pry_var_color => :default, # e.g. _, _pry_, _file_ :instance_var_color => :blue, # e.g. @foo :class_var_color => :bright_blue, # e.g. @@foo :global_var_color => :default, # e.g. $CODERAY_DEBUG, $eventmachine_library :builtin_global_color => :cyan, # e.g. $stdin, $-w, $PID :pseudo_global_color => :cyan, # e.g. $~, $1..$9, $LAST_MATCH_INFO :constant_color => :default, # e.g. VERSION, ARGF :class_constant_color => :blue, # e.g. Object, Kernel :exception_constant_color => :magenta, # e.g. Exception, RuntimeError :unloaded_constant_color => :yellow, # Any constant that is still in .autoload? state :separator => " ", :ceiling => [Object, Module, Class] } match 'ls' group 'Context' description 'Show the list of vars and methods in the current scope.' command_options :shellwords => false, :interpolate => false banner <<-'BANNER' Usage: ls [-m|-M|-p|-pM] [-q|-v] [-c|-i] [Object] ls [-g] [-l] ls shows you which methods, constants and variables are accessible to Pry. By default it shows you the local variables defined in the current shell, and any public methods or instance variables defined on the current object. The colours used are configurable using Pry.config.ls.*_color, and the separator is Pry.config.ls.separator. Pry.config.ls.ceiling is used to hide methods defined higher up in the inheritance chain, this is by default set to [Object, Module, Class] so that methods defined on all Objects are omitted. The -v flag can be used to ignore this setting and show all methods, while the -q can be used to set the ceiling much lower and show only methods defined on the object or its direct class. Also check out `find-method` command (run `help find-method`). BANNER def options(opt) opt.on :m, :methods, "Show public methods defined on the Object" opt.on :M, "instance-methods", "Show public methods defined in a Module or Class" opt.on :p, :ppp, "Show public, protected (in yellow) and private (in green) methods" opt.on :q, :quiet, "Show only methods defined on object.singleton_class and object.class" opt.on :v, :verbose, "Show methods and constants on all super-classes (ignores Pry.config.ls.ceiling)" opt.on :g, :globals, "Show global variables, including those builtin to Ruby (in cyan)" opt.on :l, :locals, "Show hash of local vars, sorted by descending size" opt.on :c, :constants, "Show constants, highlighting classes (in blue), and exceptions (in purple).\n" << " " * 32 << "Constants that are pending autoload? are also shown (in yellow)" opt.on :i, :ivars, "Show instance variables (in blue) and class variables (in bright blue)" opt.on :G, :grep, "Filter output by regular expression", :argument => true if jruby? opt.on :J, "all-java", "Show all the aliases for methods from java (default is to show only prettiest)" end end # Exclude -q, -v and --grep because they, # don't specify what the user wants to see. def no_user_opts? !(opts[:methods] || opts['instance-methods'] || opts[:ppp] || opts[:globals] || opts[:locals] || opts[:constants] || opts[:ivars]) end def process @interrogatee = args.empty? ? target_self : target.eval(args.join(' ')) raise_errors_if_arguments_are_weird ls_entity = LsEntity.new({ :interrogatee => @interrogatee, :no_user_opts => no_user_opts?, :opts => opts, :args => args, :_pry_ => _pry_ }) _pry_.pager.page ls_entity.entities_table end private def error_list any_args = args.any? non_mod_interrogatee = !(Module === @interrogatee) [ ['-l does not make sense with a specified Object', :locals, any_args], ['-g does not make sense with a specified Object', :globals, any_args], ['-q does not make sense with -v', :quiet, opts.present?(:verbose)], ['-M only makes sense with a Module or a Class', 'instance-methods', non_mod_interrogatee], ['-c only makes sense with a Module or a Class', :constants, any_args && non_mod_interrogatee] ] end def raise_errors_if_arguments_are_weird error_list.each do |message, option, invalid_expr| raise Pry::CommandError, message if opts.present?(option) && invalid_expr end end end Pry::Commands.add_command(Pry::Command::Ls) end pry-0.10.3/lib/pry/commands/ls/000077500000000000000000000000001260757071700162205ustar00rootroot00000000000000pry-0.10.3/lib/pry/commands/ls/constants.rb000066400000000000000000000024471260757071700205700ustar00rootroot00000000000000require 'pry/commands/ls/interrogatable' class Pry class Command::Ls < Pry::ClassCommand class Constants < Pry::Command::Ls::Formatter include Pry::Command::Ls::Interrogatable def initialize(interrogatee, no_user_opts, opts, _pry_) super(_pry_) @interrogatee = interrogatee @no_user_opts = no_user_opts @default_switch = opts[:constants] @verbose_switch = opts[:verbose] end def correct_opts? super || (@no_user_opts && interrogating_a_module?) end def output_self mod = interrogatee_mod constants = WrappedModule.new(mod).constants(@verbose_switch) output_section('constants', grep.regexp[format(mod, constants)]) end private def format(mod, constants) constants.sort_by(&:downcase).map do |name| if const = (!mod.autoload?(name) && (mod.const_get(name) || true) rescue nil) if (const < Exception rescue false) color(:exception_constant, name) elsif (Module === mod.const_get(name) rescue false) color(:class_constant, name) else color(:constant, name) end else color(:unloaded_constant, name) end end end end end end pry-0.10.3/lib/pry/commands/ls/formatter.rb000066400000000000000000000020251260757071700205470ustar00rootroot00000000000000class Pry class Command::Ls < Pry::ClassCommand class Formatter attr_writer :grep attr_reader :_pry_ def initialize(_pry_) @_pry_ = _pry_ @target = _pry_.current_context end def write_out return false unless correct_opts? output_self end private def color(type, str) Pry::Helpers::Text.send _pry_.config.ls["#{type}_color"], str end # Add a new section to the output. # Outputs nothing if the section would be empty. def output_section(heading, body) return '' if body.compact.empty? fancy_heading = Pry::Helpers::Text.bold(color(:heading, heading)) Pry::Helpers.tablify_or_one_line(fancy_heading, body) end def format_value(value) Pry::ColorPrinter.pp(value, '') end def correct_opts? @default_switch end def output_self raise NotImplementedError end def grep @grep || proc { |x| x } end end end end pry-0.10.3/lib/pry/commands/ls/globals.rb000066400000000000000000000032671260757071700202000ustar00rootroot00000000000000class Pry class Command::Ls < Pry::ClassCommand class Globals < Pry::Command::Ls::Formatter # Taken from "puts global_variables.inspect". BUILTIN_GLOBALS = %w($" $$ $* $, $-0 $-F $-I $-K $-W $-a $-d $-i $-l $-p $-v $-w $. $/ $\\ $: $; $< $= $> $0 $ARGV $CONSOLE $DEBUG $DEFAULT_INPUT $DEFAULT_OUTPUT $FIELD_SEPARATOR $FILENAME $FS $IGNORECASE $INPUT_LINE_NUMBER $INPUT_RECORD_SEPARATOR $KCODE $LOADED_FEATURES $LOAD_PATH $NR $OFS $ORS $OUTPUT_FIELD_SEPARATOR $OUTPUT_RECORD_SEPARATOR $PID $PROCESS_ID $PROGRAM_NAME $RS $VERBOSE $deferr $defout $stderr $stdin $stdout) # `$SAFE` and `$?` are thread-local, the exception stuff only works in a # rescue clause, everything else is basically a local variable with a `$` # in its name. PSEUDO_GLOBALS = %w($! $' $& $` $@ $? $+ $_ $~ $1 $2 $3 $4 $5 $6 $7 $8 $9 $CHILD_STATUS $SAFE $ERROR_INFO $ERROR_POSITION $LAST_MATCH_INFO $LAST_PAREN_MATCH $LAST_READ_LINE $MATCH $POSTMATCH $PREMATCH) def initialize(opts, _pry_) super(_pry_) @default_switch = opts[:globals] end def output_self variables = format(@target.eval('global_variables')) output_section('global variables', grep.regexp[variables]) end private def format(globals) globals.map(&:to_s).sort_by(&:downcase).map do |name| if PSEUDO_GLOBALS.include?(name) color(:pseudo_global, name) elsif BUILTIN_GLOBALS.include?(name) color(:builtin_global, name) else color(:global_var, name) end end end end end end pry-0.10.3/lib/pry/commands/ls/grep.rb000066400000000000000000000005341260757071700175040ustar00rootroot00000000000000class Pry class Command::Ls < Pry::ClassCommand class Grep def initialize(grep_regexp) @grep_regexp = grep_regexp end def regexp proc { |x| if x.instance_of?(Array) x.grep(@grep_regexp) else x =~ @grep_regexp end } end end end end pry-0.10.3/lib/pry/commands/ls/instance_vars.rb000066400000000000000000000021551260757071700214070ustar00rootroot00000000000000require 'pry/commands/ls/interrogatable' class Pry class Command::Ls < Pry::ClassCommand class InstanceVars < Pry::Command::Ls::Formatter include Pry::Command::Ls::Interrogatable def initialize(interrogatee, no_user_opts, opts, _pry_) super(_pry_) @interrogatee = interrogatee @no_user_opts = no_user_opts @default_switch = opts[:ivars] end def correct_opts? super || @no_user_opts end def output_self ivars = if Object === @interrogatee Pry::Method.safe_send(@interrogatee, :instance_variables) else [] #TODO: BasicObject support end kvars = Pry::Method.safe_send(interrogatee_mod, :class_variables) ivars_out = output_section('instance variables', format(:instance_var, ivars)) kvars_out = output_section('class variables', format(:class_var, kvars)) ivars_out + kvars_out end private def format(type, vars) vars.sort_by { |var| var.to_s.downcase }.map { |var| color(type, var) } end end end end pry-0.10.3/lib/pry/commands/ls/interrogatable.rb000066400000000000000000000005501260757071700215470ustar00rootroot00000000000000module Pry::Command::Ls::Interrogatable private def interrogating_a_module? Module === @interrogatee end def interrogatee_mod if interrogating_a_module? @interrogatee else singleton = Pry::Method.singleton_class_of(@interrogatee) singleton.ancestors.grep(::Class).reject { |c| c == singleton }.first end end end pry-0.10.3/lib/pry/commands/ls/jruby_hacks.rb000066400000000000000000000027551260757071700210620ustar00rootroot00000000000000module Pry::Command::Ls::JRubyHacks private # JRuby creates lots of aliases for methods imported from java in an attempt # to make life easier for ruby programmers. (e.g. getFooBar becomes # get_foo_bar and foo_bar, and maybe foo_bar? if it returns a Boolean). The # full transformations are in the assignAliases method of: # https://github.com/jruby/jruby/blob/master/src/org/jruby/javasupport/JavaClass.java # # This has the unfortunate side-effect of making the output of ls even more # incredibly verbose than it normally would be for these objects; and so we # filter out all but the nicest of these aliases here. # # TODO: This is a little bit vague, better heuristics could be used. # JRuby also has a lot of scala-specific logic, which we don't copy. def trim_jruby_aliases(methods) grouped = methods.group_by do |m| m.name.sub(/\A(is|get|set)(?=[A-Z_])/, '').gsub(/[_?=]/, '').downcase end grouped.map do |key, values| values = values.sort_by do |m| rubbishness(m.name) end found = [] values.select do |x| (!found.any? { |y| x == y }) && found << x end end.flatten(1) end # When removing jruby aliases, we want to keep the alias that is # "least rubbish" according to this metric. def rubbishness(name) name.each_char.map { |x| case x when /[A-Z]/ 1 when '?', '=', '!' -2 else 0 end }.inject(&:+) + (name.size / 100.0) end end pry-0.10.3/lib/pry/commands/ls/local_names.rb000066400000000000000000000014401260757071700210210ustar00rootroot00000000000000class Pry class Command::Ls < Pry::ClassCommand class LocalNames < Pry::Command::Ls::Formatter def initialize(no_user_opts, args, _pry_) super(_pry_) @no_user_opts = no_user_opts @args = args @sticky_locals = _pry_.sticky_locals end def correct_opts? super || (@no_user_opts && @args.empty?) end def output_self local_vars = grep.regexp[@target.eval('local_variables')] output_section('locals', format(local_vars)) end private def format(locals) locals.sort_by(&:downcase).map do |name| if @sticky_locals.include?(name.to_sym) color(:pry_var, name) else color(:local_var, name) end end end end end end pry-0.10.3/lib/pry/commands/ls/local_vars.rb000066400000000000000000000021061260757071700206710ustar00rootroot00000000000000class Pry class Command::Ls < Pry::ClassCommand class LocalVars < Pry::Command::Ls::Formatter def initialize(opts, _pry_) super(_pry_) @default_switch = opts[:locals] @sticky_locals = _pry_.sticky_locals end def output_self name_value_pairs = @target.eval('local_variables').reject { |e| @sticky_locals.keys.include?(e.to_sym) }.map { |name| [name, (@target.eval(name.to_s))] } format(name_value_pairs).join('') end private def format(name_value_pairs) name_value_pairs.sort_by { |name, value| value.to_s.size }.reverse.map { |name, value| colorized_assignment_style(name, format_value(value)) } end def colorized_assignment_style(lhs, rhs, desired_width = 7) colorized_lhs = color(:local_var, lhs) color_escape_padding = colorized_lhs.size - lhs.size pad = desired_width + color_escape_padding "%-#{pad}s = %s" % [color(:local_var, colorized_lhs), rhs] end end end end pry-0.10.3/lib/pry/commands/ls/ls_entity.rb000066400000000000000000000032221260757071700205560ustar00rootroot00000000000000require 'pry/commands/ls/grep' require 'pry/commands/ls/formatter' require 'pry/commands/ls/globals' require 'pry/commands/ls/constants' require 'pry/commands/ls/methods' require 'pry/commands/ls/self_methods' require 'pry/commands/ls/instance_vars' require 'pry/commands/ls/local_names' require 'pry/commands/ls/local_vars' class Pry class Command::Ls < Pry::ClassCommand class LsEntity attr_reader :_pry_ def initialize(opts) @interrogatee = opts[:interrogatee] @no_user_opts = opts[:no_user_opts] @opts = opts[:opts] @args = opts[:args] @grep = Grep.new(Regexp.new(opts[:opts][:G] || '.')) @_pry_ = opts.delete(:_pry_) end def entities_table entities.map(&:write_out).reject { |o| !o }.join('') end private def grep(entity) entity.tap { |o| o.grep = @grep } end def globals grep Globals.new(@opts, _pry_) end def constants grep Constants.new(@interrogatee, @no_user_opts, @opts, _pry_) end def methods grep(Methods.new(@interrogatee, @no_user_opts, @opts, _pry_)) end def self_methods grep SelfMethods.new(@interrogatee, @no_user_opts, @opts, _pry_) end def instance_vars grep InstanceVars.new(@interrogatee, @no_user_opts, @opts, _pry_) end def local_names grep LocalNames.new(@no_user_opts, @args, _pry_) end def local_vars LocalVars.new(@opts, _pry_) end def entities [globals, constants, methods, self_methods, instance_vars, local_names, local_vars] end end end end pry-0.10.3/lib/pry/commands/ls/methods.rb000066400000000000000000000035271260757071700202170ustar00rootroot00000000000000require 'pry/commands/ls/methods_helper' require 'pry/commands/ls/interrogatable' class Pry class Command::Ls < Pry::ClassCommand class Methods < Pry::Command::Ls::Formatter include Pry::Command::Ls::Interrogatable include Pry::Command::Ls::MethodsHelper def initialize(interrogatee, no_user_opts, opts, _pry_) super(_pry_) @interrogatee = interrogatee @no_user_opts = no_user_opts @default_switch = opts[:methods] @instance_methods_switch = opts['instance-methods'] @ppp_switch = opts[:ppp] @jruby_switch = opts['all-java'] @quiet_switch = opts[:quiet] @verbose_switch = opts[:verbose] end def output_self methods = all_methods.group_by(&:owner) # Reverse the resolution order so that the most useful information # appears right by the prompt. resolution_order.take_while(&below_ceiling).reverse.map do |klass| methods_here = (methods[klass] || []).select { |m| grep.regexp[m.name] } heading = "#{ Pry::WrappedModule.new(klass).method_prefix }methods" output_section(heading, format(methods_here)) end.join('') end private def correct_opts? super || @instance_methods_switch || @ppp_switch || @no_user_opts end # Get a lambda that can be used with `take_while` to prevent over-eager # traversal of the Object's ancestry graph. def below_ceiling ceiling = if @quiet_switch [Pry::Method.safe_send(interrogatee_mod, :ancestors)[1]] + _pry_.config.ls.ceiling elsif @verbose_switch [] else _pry_.config.ls.ceiling.dup end lambda { |klass| !ceiling.include?(klass) } end end end end pry-0.10.3/lib/pry/commands/ls/methods_helper.rb000066400000000000000000000023241260757071700215500ustar00rootroot00000000000000require 'pry/commands/ls/jruby_hacks' module Pry::Command::Ls::MethodsHelper include Pry::Command::Ls::JRubyHacks private # Get all the methods that we'll want to output. def all_methods(instance_methods = false) methods = if instance_methods || @instance_methods_switch Pry::Method.all_from_class(@interrogatee) else Pry::Method.all_from_obj(@interrogatee) end if Pry::Helpers::BaseHelpers.jruby? && !@jruby_switch methods = trim_jruby_aliases(methods) end methods.select { |method| @ppp_switch || method.visibility == :public } end def resolution_order if @instance_methods_switch Pry::Method.instance_resolution_order(@interrogatee) else Pry::Method.resolution_order(@interrogatee) end end def format(methods) methods.sort_by(&:name).map do |method| if method.name == 'method_missing' color(:method_missing, 'method_missing') elsif method.visibility == :private color(:private_method, method.name) elsif method.visibility == :protected color(:protected_method, method.name) else color(:public_method, method.name) end end end end pry-0.10.3/lib/pry/commands/ls/self_methods.rb000066400000000000000000000015221260757071700212210ustar00rootroot00000000000000require 'pry/commands/ls/interrogatable' require 'pry/commands/ls/methods_helper' class Pry class Command::Ls < Pry::ClassCommand class SelfMethods < Pry::Command::Ls::Formatter include Pry::Command::Ls::Interrogatable include Pry::Command::Ls::MethodsHelper def initialize(interrogatee, no_user_opts, opts, _pry_) super(_pry_) @interrogatee = interrogatee @no_user_opts = no_user_opts end def output_self methods = all_methods(true).select do |m| m.owner == @interrogatee && grep.regexp[m.name] end heading = "#{ Pry::WrappedModule.new(@interrogatee).method_prefix }methods" output_section(heading, format(methods)) end private def correct_opts? @no_user_opts && interrogating_a_module? end end end end pry-0.10.3/lib/pry/commands/nesting.rb000066400000000000000000000011641260757071700176000ustar00rootroot00000000000000class Pry class Command::Nesting < Pry::ClassCommand match 'nesting' group 'Navigating Pry' description 'Show nesting information.' banner <<-'BANNER' Show nesting information. BANNER def process output.puts 'Nesting status:' output.puts '--' _pry_.binding_stack.each_with_index do |obj, level| if level == 0 output.puts "#{level}. #{Pry.view_clip(obj.eval('self'))} (Pry top level)" else output.puts "#{level}. #{Pry.view_clip(obj.eval('self'))}" end end end end Pry::Commands.add_command(Pry::Command::Nesting) end pry-0.10.3/lib/pry/commands/play.rb000066400000000000000000000056071260757071700171040ustar00rootroot00000000000000class Pry class Command::Play < Pry::ClassCommand match 'play' group 'Editing' description 'Playback a string variable, method, line, or file as input.' banner <<-'BANNER' Usage: play [OPTIONS] [--help] The play command enables you to replay code from files and methods as if they were entered directly in the Pry REPL. play --lines 149..153 # assumes current context play -i 20 --lines 1..3 # assumes lines of the input expression at 20 play -o 4 # the output of of an expression at 4 play Pry#repl -l 1..-1 # play the contents of Pry#repl method play -e 2 # play from specified line until end of valid expression play hello.rb # play a file play Rakefile -l 5 # play line 5 of a file play -d hi # play documentation of hi method play hi --open # play hi method and leave it open https://github.com/pry/pry/wiki/User-Input#wiki-Play BANNER def options(opt) CodeCollector.inject_options(opt) opt.on :open, 'Plays the selected content except the last line. Useful' \ ' for replaying methods and leaving the method definition' \ ' "open". `amend-line` can then be used to' \ ' modify the method.' opt.on :e, :expression=, 'Executes until end of valid expression', :as => Integer opt.on :p, :print, 'Prints executed code' end def process @cc = CodeCollector.new(args, opts, _pry_) perform_play show_input end def perform_play eval_string << content_after_options run "fix-indent" end def show_input if opts.present?(:print) or !Pry::Code.complete_expression?(eval_string) run "show-input" end end def content_after_options if opts.present?(:open) restrict_to_lines(content, (0..-2)) elsif opts.present?(:expression) content_at_expression else content end end def content_at_expression code_object.expression_at(opts[:expression]) end def code_object Pry::Code.new(content) end def should_use_default_file? !args.first && !opts.present?(:in) && !opts.present?(:out) end def content if should_use_default_file? file_content else @cc.content end end # The file to play from when no code object is specified. # e.g `play --lines 4..10` def default_file target.eval("__FILE__") && File.expand_path(target.eval("__FILE__")) end def file_content if default_file && File.exists?(default_file) @cc.restrict_to_lines(File.read(default_file), @cc.line_range) else raise CommandError, "File does not exist! File was: #{default_file.inspect}" end end end Pry::Commands.add_command(Pry::Command::Play) end pry-0.10.3/lib/pry/commands/pry_backtrace.rb000066400000000000000000000015111260757071700207360ustar00rootroot00000000000000class Pry class Command::PryBacktrace < Pry::ClassCommand match 'pry-backtrace' group 'Context' description 'Show the backtrace for the Pry session.' banner <<-BANNER Usage: pry-backtrace [OPTIONS] [--help] Show the backtrace for the position in the code where Pry was started. This can be used to infer the behavior of the program immediately before it entered Pry, just like the backtrace property of an exception. NOTE: if you are looking for the backtrace of the most recent exception raised, just type: `_ex_.backtrace` instead. See: https://github.com/pry/pry/wiki/Special-Locals BANNER def process _pry_.pager.page text.bold('Backtrace:') << "\n--\n" << _pry_.backtrace.join("\n") end end Pry::Commands.add_command(Pry::Command::PryBacktrace) end pry-0.10.3/lib/pry/commands/pry_version.rb000066400000000000000000000005401260757071700205050ustar00rootroot00000000000000class Pry class Command::Version < Pry::ClassCommand match 'pry-version' group 'Misc' description 'Show Pry version.' banner <<-'BANNER' Show Pry version. BANNER def process output.puts "Pry version: #{Pry::VERSION} on Ruby #{RUBY_VERSION}." end end Pry::Commands.add_command(Pry::Command::Version) end pry-0.10.3/lib/pry/commands/raise_up.rb000066400000000000000000000022251260757071700177370ustar00rootroot00000000000000class Pry # N.B. using a regular expresion here so that "raise-up 'foo'" does the right thing. class Command::RaiseUp < Pry::ClassCommand match(/raise-up(!?\b.*)/) group 'Context' description 'Raise an exception out of the current pry instance.' command_options :listing => 'raise-up' banner <<-BANNER Raise up, like exit, allows you to quit pry. Instead of returning a value however, it raises an exception. If you don't provide the exception to be raised, it will use the most recent exception (in pry `_ex_`). When called as raise-up! (with an exclamation mark), this command raises the exception through any nested prys you have created by "cd"ing into objects. raise-up "get-me-out-of-here" # This is equivalent to the command above. raise "get-me-out-of-here" raise-up BANNER def process return _pry.pager.page help if captures[0] =~ /(-h|--help)\b/ # Handle 'raise-up', 'raise-up "foo"', 'raise-up RuntimeError, 'farble' in a rubyesque manner target.eval("_pry_.raise_up#{captures[0]}") end end Pry::Commands.add_command(Pry::Command::RaiseUp) end pry-0.10.3/lib/pry/commands/reload_code.rb000066400000000000000000000036451260757071700203770ustar00rootroot00000000000000class Pry class Command::ReloadCode < Pry::ClassCommand match 'reload-code' group 'Misc' description 'Reload the source file that contains the specified code object.' banner <<-'BANNER' Reload the source file that contains the specified code object. e.g reload-code MyClass#my_method #=> reload a method reload-code MyClass #=> reload a class reload-code my-command #=> reload a pry command reload-code self #=> reload the current object reload-code #=> reload the current file or object BANNER def process if !args.empty? reload_object(args.join(" ")) elsif internal_binding?(target) reload_object("self") else reload_current_file end end private def current_file File.expand_path target.eval("__FILE__") end def reload_current_file if !File.exists?(current_file) raise CommandError, "Current file: #{current_file} cannot be found on disk!" end load current_file output.puts "The current file: #{current_file} was reloaded!" end def reload_object(identifier) code_object = Pry::CodeObject.lookup(identifier, _pry_) check_for_reloadability(code_object, identifier) load code_object.source_file output.puts "#{identifier} was reloaded!" end def check_for_reloadability(code_object, identifier) if !code_object || !code_object.source_file raise CommandError, "Cannot locate #{identifier}!" elsif !File.exists?(code_object.source_file) raise CommandError, "Cannot reload #{identifier} as it has no associated file on disk. " \ "File found was: #{code_object.source_file}" end end end Pry::Commands.add_command(Pry::Command::ReloadCode) Pry::Commands.alias_command 'reload-method', 'reload-code' end pry-0.10.3/lib/pry/commands/reset.rb000066400000000000000000000005351260757071700172540ustar00rootroot00000000000000class Pry class Command::Reset < Pry::ClassCommand match 'reset' group 'Context' description 'Reset the REPL to a clean state.' banner <<-'BANNER' Reset the REPL to a clean state. BANNER def process output.puts 'Pry reset.' exec 'pry' end end Pry::Commands.add_command(Pry::Command::Reset) end pry-0.10.3/lib/pry/commands/ri.rb000066400000000000000000000027501260757071700165450ustar00rootroot00000000000000class Pry class Command::Ri < Pry::ClassCommand match 'ri' group 'Introspection' description 'View ri documentation.' banner <<-'BANNER' Usage: ri [spec] View ri documentation. Relies on the "rdoc" gem being installed. See also "show-doc" command. ri Array#each BANNER def process(spec) # Lazily load RI require 'rdoc/ri/driver' unless defined? RDoc::RI::PryDriver # Subclass RI so that it formats its output nicely, and uses `lesspipe`. subclass = Class.new(RDoc::RI::Driver) # the hard way. subclass.class_eval do def initialize(pager, opts) @pager = pager super opts end def page paging_text = StringIO.new yield paging_text @pager.page(paging_text.string) end def formatter(io) if @formatter_klass @formatter_klass.new else RDoc::Markup::ToAnsi.new end end end RDoc::RI.const_set :PryDriver, subclass # hook it up! end # Spin-up an RI insance. ri = RDoc::RI::PryDriver.new _pry_.pager, :use_stdout => true, :interactive => false begin ri.display_names [spec] # Get the documentation (finally!) rescue RDoc::RI::Driver::NotFoundError => e output.puts "error: '#{e.name}' not found" end end end Pry::Commands.add_command(Pry::Command::Ri) end pry-0.10.3/lib/pry/commands/save_file.rb000066400000000000000000000026631260757071700200730ustar00rootroot00000000000000require 'pry/commands/code_collector' class Pry class Command::SaveFile < Pry::ClassCommand match 'save-file' group 'Input and Output' description 'Export to a file using content from the REPL.' banner <<-'BANNER' Usage: save-file [OPTIONS] --to [FILE] Export to a file using content from the REPL. save-file my_method --to hello.rb save-file -i 1..10 --to hello.rb --append save-file show-method --to my_command.rb save-file sample_file.rb --lines 2..10 --to output_file.rb BANNER def options(opt) CodeCollector.inject_options(opt) opt.on :to=, "Specify the output file path" opt.on :a, :append, "Append output to file" end def process @cc = CodeCollector.new(args, opts, _pry_) raise CommandError, "Found no code to save." if @cc.content.empty? if !file_name display_content else save_file end end def file_name opts[:to] || nil end def save_file File.open(file_name, mode) do |f| f.puts @cc.content end output.puts "#{file_name} successfully saved" end def display_content output.puts @cc.content output.puts "\n\n--\nPlease use `--to FILE` to export to a file." output.puts "No file saved!\n--" end def mode opts.present?(:append) ? "a" : "w" end end Pry::Commands.add_command(Pry::Command::SaveFile) end pry-0.10.3/lib/pry/commands/shell_command.rb000066400000000000000000000022441260757071700207360ustar00rootroot00000000000000class Pry class Command::ShellCommand < Pry::ClassCommand match(/\.(.*)/) group 'Input and Output' description "All text following a '.' is forwarded to the shell." command_options :listing => '.', :use_prefix => false, :takes_block => true banner <<-'BANNER' Usage: .COMMAND_NAME All text following a "." is forwarded to the shell. .ls -aF .uname BANNER def process(cmd) if cmd =~ /^cd\s*(.*)/i process_cd parse_destination($1) else pass_block(cmd) if command_block command_block.call `#{cmd}` else _pry_.config.system.call(output, cmd, _pry_) end end end private def parse_destination(dest) return "~" if dest.empty? return dest unless dest == "-" state.old_pwd || raise(CommandError, "No prior directory available") end def process_cd(dest) state.old_pwd = Dir.pwd Dir.chdir File.expand_path(dest) rescue Errno::ENOENT raise CommandError, "No such directory: #{dest}" end end Pry::Commands.add_command(Pry::Command::ShellCommand) end pry-0.10.3/lib/pry/commands/shell_mode.rb000066400000000000000000000013051260757071700202410ustar00rootroot00000000000000class Pry class Command::ShellMode < Pry::ClassCommand match 'shell-mode' group 'Input and Output' description 'Toggle shell mode. Bring in pwd prompt and file completion.' banner <<-'BANNER' Toggle shell mode. Bring in pwd prompt and file completion. BANNER def process case _pry_.prompt when Pry::SHELL_PROMPT _pry_.pop_prompt _pry_.custom_completions = _pry_.config.file_completions else _pry_.push_prompt Pry::SHELL_PROMPT _pry_.custom_completions = _pry_.config.command_completions end end end Pry::Commands.add_command(Pry::Command::ShellMode) Pry::Commands.alias_command 'file-mode', 'shell-mode' end pry-0.10.3/lib/pry/commands/show_doc.rb000066400000000000000000000050371260757071700177410ustar00rootroot00000000000000require 'pry/commands/show_info' class Pry class Command::ShowDoc < Command::ShowInfo include Pry::Helpers::DocumentationHelpers match 'show-doc' group 'Introspection' description 'Show the documentation for a method or class.' banner <<-BANNER Usage: show-doc [OPTIONS] [METH] Aliases: ? Show the documentation for a method or class. Tries instance methods first and then methods by default. show-doc hi_method # docs for hi_method show-doc Pry # for Pry class show-doc Pry -a # for all definitions of Pry class (all monkey patches) BANNER # The docs for code_object prepared for display. def content_for(code_object) Code.new(render_doc_markup_for(code_object), start_line_for(code_object), :text). with_line_numbers(use_line_numbers?).to_s end # process the markup (if necessary) and apply colors def render_doc_markup_for(code_object) docs = docs_for(code_object) if code_object.command? # command '--help' shouldn't use markup highlighting docs else if docs.empty? raise CommandError, "No docs found for: #{ obj_name ? obj_name : 'current context' }" end process_comment_markup(docs) end end # Return docs for the code_object, adjusting for whether the code_object # has yard docs available, in which case it returns those. # (note we only have to check yard docs for modules since they can # have multiple docs, but methods can only be doc'd once so we # dont need to check them) def docs_for(code_object) if code_object.module_with_yard_docs? # yard docs code_object.yard_doc else # normal docs (i.e comments above method/module/command) code_object.doc end end # Which sections to include in the 'header', can toggle: :owner, # :signature and visibility. def header_options super.merge :signature => true end # figure out start line of docs by back-calculating based on # number of lines in the comment and the start line of the code_object # @return [Fixnum] start line of docs def start_line_for(code_object) if code_object.command? || opts.present?(:'base-one') 1 else code_object.source_line.nil? ? 1 : (code_object.source_line - code_object.doc.lines.count) end end end Pry::Commands.add_command(Pry::Command::ShowDoc) Pry::Commands.alias_command '?', 'show-doc' end pry-0.10.3/lib/pry/commands/show_info.rb000066400000000000000000000152011260757071700201210ustar00rootroot00000000000000class Pry class Command::ShowInfo < Pry::ClassCommand extend Pry::Helpers::BaseHelpers command_options :shellwords => false, :interpolate => false def options(opt) opt.on :s, :super, "Select the 'super' method. Can be repeated to traverse the ancestors", :as => :count opt.on :l, "line-numbers", "Show line numbers" opt.on :b, "base-one", "Show line numbers but start numbering at 1 (useful for `amend-line` and `play` commands)" opt.on :a, :all, "Show all definitions and monkeypatches of the module/class" end def process code_object = Pry::CodeObject.lookup(obj_name, _pry_, :super => opts[:super]) raise CommandError, no_definition_message if !code_object @original_code_object = code_object if show_all_modules?(code_object) # show all monkey patches for a module result = content_and_headers_for_all_module_candidates(code_object) else # show a specific code object co = code_object_with_accessible_source(code_object) result = content_and_header_for_code_object(co) end set_file_and_dir_locals(code_object.source_file) _pry_.pager.page result end # This method checks whether the `code_object` is a WrappedModule, # if it is, then it returns the first candidate (monkeypatch) with # accessible source (or docs). If `code_object` is not a WrappedModule (i.e a # method or a command) then the `code_object` itself is just # returned. # # @return [Pry::WrappedModule, Pry::Method, Pry::Command] def code_object_with_accessible_source(code_object) if code_object.is_a?(WrappedModule) candidate = code_object.candidates.find(&:source) if candidate return candidate else raise CommandError, no_definition_message if !valid_superclass?(code_object) @used_super = true code_object_with_accessible_source(code_object.super) end else code_object end end def valid_superclass?(code_object) code_object.super && code_object.super.wrapped != Object end def content_and_header_for_code_object(code_object) header(code_object) << content_for(code_object) end def content_and_headers_for_all_module_candidates(mod) result = "Found #{mod.number_of_candidates} candidates for `#{mod.name}` definition:\n" mod.number_of_candidates.times do |v| candidate = mod.candidate(v) begin result << "\nCandidate #{v+1}/#{mod.number_of_candidates}: #{candidate.source_file} @ line #{candidate.source_line}:\n" content = content_for(candidate) result << "Number of lines: #{content.lines.count}\n\n" << content rescue Pry::RescuableException result << "\nNo content found.\n" next end end result end def no_definition_message "Couldn't locate a definition for #{obj_name}!" end # Generate a header (meta-data information) for all the code # object types: methods, modules, commands, procs... def header(code_object) file_name, line_num = file_and_line_for(code_object) h = "\n#{Pry::Helpers::Text.bold('From:')} #{file_name} " h << code_object_header(code_object, line_num) h << "\n#{Pry::Helpers::Text.bold('Number of lines:')} " << "#{content_for(code_object).lines.count}\n\n" h << Helpers::Text.bold('** Warning:') << " Cannot find code for #{@original_code_object.nonblank_name}. Showing superclass #{code_object.nonblank_name} instead. **\n\n" if @used_super h end def code_object_header(code_object, line_num) if code_object.real_method_object? method_header(code_object, line_num) # It sucks we have to test for both Pry::WrappedModule and WrappedModule::Candidate, # probably indicates a deep refactor needs to happen in those classes. elsif code_object.is_a?(Pry::WrappedModule) || code_object.is_a?(Pry::WrappedModule::Candidate) module_header(code_object, line_num) else "" end end def method_header(code_object, line_num) h = "" h << (code_object.c_method? ? "(C Method):" : "@ line #{line_num}:") h << method_sections(code_object)[:owner] h << method_sections(code_object)[:visibility] h << method_sections(code_object)[:signature] h end def module_header(code_object, line_num) h = "" h << "@ line #{line_num}:\n" h << text.bold(code_object.module? ? "Module" : "Class") h << " #{text.bold('name:')} #{code_object.nonblank_name}" if code_object.number_of_candidates > 1 h << (text.bold("\nNumber of monkeypatches: ") << code_object.number_of_candidates.to_s) h << ". Use the `-a` option to display all available monkeypatches" end h end def method_sections(code_object) { :owner => "\n#{text.bold("Owner:")} #{code_object.owner || "N/A"}\n", :visibility => "#{text.bold("Visibility:")} #{code_object.visibility}", :signature => "\n#{text.bold("Signature:")} #{code_object.signature}" }.merge(header_options) { |key, old, new| (new && old).to_s } end def header_options { :owner => true, :visibility => true, :signature => nil } end def show_all_modules?(code_object) code_object.is_a?(Pry::WrappedModule) && opts.present?(:all) end def obj_name @obj_name ||= args.empty? ? nil : args.join(' ') end def use_line_numbers? opts.present?(:b) || opts.present?(:l) end def start_line_for(code_object) if opts.present?(:'base-one') 1 else code_object.source_line || 1 end end # takes into account possible yard docs, and returns yard_file / yard_line # Also adjusts for start line of comments (using start_line_for), which it has to infer # by subtracting number of lines of comment from start line of code_object def file_and_line_for(code_object) if code_object.module_with_yard_docs? [code_object.yard_file, code_object.yard_line] else [code_object.source_file, start_line_for(code_object)] end end def complete(input) if input =~ /([^ ]*)#([a-z0-9_]*)\z/ prefix, search = [$1, $2] methods = begin Pry::Method.all_from_class(binding.eval(prefix)) rescue RescuableException return super end methods.map do |method| [prefix, method.name].join('#') if method.name.start_with?(search) end.compact else super end end end end pry-0.10.3/lib/pry/commands/show_input.rb000066400000000000000000000007141260757071700203300ustar00rootroot00000000000000class Pry class Command::ShowInput < Pry::ClassCommand match 'show-input' group 'Editing' description 'Show the contents of the input buffer for the current multi-line expression.' banner <<-'BANNER' Show the contents of the input buffer for the current multi-line expression. BANNER def process output.puts Code.new(eval_string).with_line_numbers end end Pry::Commands.add_command(Pry::Command::ShowInput) end pry-0.10.3/lib/pry/commands/show_source.rb000066400000000000000000000031511260757071700204670ustar00rootroot00000000000000require 'pry/commands/show_info' class Pry class Command::ShowSource < Command::ShowInfo match 'show-source' group 'Introspection' description 'Show the source for a method or class.' banner <<-'BANNER' Usage: show-source [OPTIONS] [METH|CLASS] Aliases: $, show-method Show the source for a method or class. Tries instance methods first and then methods by default. show-source hi_method show-source hi_method show-source Pry#rep # source for Pry#rep method show-source Pry # for Pry class show-source Pry -a # for all Pry class definitions (all monkey patches) show-source Pry.foo -e # for class of the return value of expression `Pry.foo` show-source Pry --super # for superclass of Pry (Object class) https://github.com/pry/pry/wiki/Source-browsing#wiki-Show_method BANNER def options(opt) opt.on :e, :eval, "evaluate the command's argument as a ruby expression and show the class its return value" super(opt) end def process if opts.present?(:e) obj = target.eval(args.first) self.args = Array.new(1) { Module === obj ? obj.name : obj.class.name } end super end # The source for code_object prepared for display. def content_for(code_object) Code.new(code_object.source, start_line_for(code_object)). with_line_numbers(use_line_numbers?).highlighted end end Pry::Commands.add_command(Pry::Command::ShowSource) Pry::Commands.alias_command 'show-method', 'show-source' Pry::Commands.alias_command '$', 'show-source' end pry-0.10.3/lib/pry/commands/simple_prompt.rb000066400000000000000000000007061260757071700210240ustar00rootroot00000000000000class Pry class Command::SimplePrompt < Pry::ClassCommand match 'simple-prompt' group 'prompts' description 'Toggle the simple prompt.' banner <<-'BANNER' Toggle the simple prompt. BANNER def process case _pry_.prompt when Pry::SIMPLE_PROMPT _pry_.pop_prompt else _pry_.push_prompt Pry::SIMPLE_PROMPT end end end Pry::Commands.add_command(Pry::Command::SimplePrompt) end pry-0.10.3/lib/pry/commands/stat.rb000066400000000000000000000021351260757071700171030ustar00rootroot00000000000000class Pry class Command::Stat < Pry::ClassCommand match 'stat' group 'Introspection' description 'View method information and set _file_ and _dir_ locals.' command_options :shellwords => false banner <<-'BANNER' Usage: stat [OPTIONS] [METH] Show method information for method METH and set _file_ and _dir_ locals. stat hello_method BANNER def options(opt) method_options(opt) end def process meth = method_object aliases = meth.aliases output.puts unindent <<-EOS Method Information: -- Name: #{meth.name} Alias#{ "es" if aliases.length > 1 }: #{ aliases.any? ? aliases.join(", ") : "None." } Owner: #{meth.owner ? meth.owner : "Unknown"} Visibility: #{meth.visibility} Type: #{meth.is_a?(::Method) ? "Bound" : "Unbound"} Arity: #{meth.arity} Method Signature: #{meth.signature} Source Location: #{meth.source_location ? meth.source_location.join(":") : "Not found."} EOS end end Pry::Commands.add_command(Pry::Command::Stat) end pry-0.10.3/lib/pry/commands/switch_to.rb000066400000000000000000000012551260757071700201350ustar00rootroot00000000000000class Pry class Command::SwitchTo < Pry::ClassCommand match 'switch-to' group 'Navigating Pry' description 'Start a new subsession on a binding in the current stack.' banner <<-'BANNER' Start a new subsession on a binding in the current stack (numbered by nesting). BANNER def process(selection) selection = selection.to_i if selection < 0 || selection > _pry_.binding_stack.size - 1 raise CommandError, "Invalid binding index #{selection} - use `nesting` command to view valid indices." else Pry.start(_pry_.binding_stack[selection]) end end end Pry::Commands.add_command(Pry::Command::SwitchTo) end pry-0.10.3/lib/pry/commands/toggle_color.rb000066400000000000000000000007231260757071700206100ustar00rootroot00000000000000class Pry class Command::ToggleColor < Pry::ClassCommand match 'toggle-color' group 'Misc' description 'Toggle syntax highlighting.' banner <<-'BANNER' Usage: toggle-color Toggle syntax highlighting. BANNER def process _pry_.color = color_toggle output.puts "Syntax highlighting #{_pry_.color ? "on" : "off"}" end def color_toggle !_pry_.color end Pry::Commands.add_command(self) end end pry-0.10.3/lib/pry/commands/watch_expression.rb000066400000000000000000000061231260757071700215160ustar00rootroot00000000000000class Pry class Command::WatchExpression < Pry::ClassCommand require 'pry/commands/watch_expression/expression.rb' match 'watch' group 'Context' description 'Watch the value of an expression and print a notification whenever it changes.' command_options :use_prefix => false banner <<-'BANNER' Usage: watch [EXPRESSION] watch watch --delete [INDEX] watch [EXPRESSION] adds an expression to the list of those being watched. It will be re-evaluated every time you hit enter in pry. If its value has changed, the new value will be printed to the console. This is useful if you are step-through debugging and want to see how something changes over time. It's also useful if you're trying to write a method inside pry and want to check that it gives the right answers every time you redefine it. watch on its own displays all the currently watched expressions and their values, and watch --delete [INDEX] allows you to delete expressions from the list being watched. BANNER def options(opt) opt.on :d, :delete, "Delete the watch expression with the given index. If no index is given; clear all watch expressions.", :optional_argument => true, :as => Integer opt.on :l, :list, "Show all current watch expressions and their values. Calling watch with no expressions or options will also show the watch expressions." end def process case when opts.present?(:delete) delete opts[:delete] when opts.present?(:list) || args.empty? list else add_hook add_expression(args) end end private def expressions _pry_.config.watch_expressions ||= [] end def delete(index) if index output.puts "Deleting watch expression ##{index}: #{expressions[index-1]}" expressions.delete_at(index-1) else output.puts "Deleting all watched expressions" expressions.clear end end def list if expressions.empty? output.puts "No watched expressions" else _pry_.pager.open do |pager| pager.puts "Listing all watched expressions:" pager.puts "" expressions.each_with_index do |expr, index| pager.print text.with_line_numbers(expr.to_s, index+1) end pager.puts "" end end end def eval_and_print_changed(output) expressions.each do |expr| expr.eval! if expr.changed? output.puts "#{text.blue "watch"}: #{expr.to_s}" end end end def add_expression(arguments) expressions << Expression.new(_pry_, target, arg_string) output.puts "Watching #{Code.new(arg_string).highlighted}" end def add_hook hook = [:after_eval, :watch_expression] unless _pry_.hooks.hook_exists?(*hook) _pry_.hooks.add_hook(*hook) do |_, _pry_| eval_and_print_changed _pry_.output end end end end Pry::Commands.add_command(Pry::Command::WatchExpression) end pry-0.10.3/lib/pry/commands/watch_expression/000077500000000000000000000000001260757071700211675ustar00rootroot00000000000000pry-0.10.3/lib/pry/commands/watch_expression/expression.rb000066400000000000000000000016341260757071700237170ustar00rootroot00000000000000class Pry class Command::WatchExpression class Expression attr_reader :target, :source, :value, :previous_value, :_pry_ def initialize(_pry_, target, source) @_pry_ = _pry_ @target = target @source = Code.new(source).strip end def eval! @previous_value = @value @value = Pry::ColorPrinter.pp(target_eval(target, source), "") end def to_s "#{Code.new(source).highlighted.strip} => #{value}" end # Has the value of the expression changed? # # We use the pretty-printed string represenation to detect differences # as this avoids problems with dup (causes too many differences) and == (causes too few) def changed? (value != previous_value) end private def target_eval(target, source) target.eval(source) rescue => e e end end end end pry-0.10.3/lib/pry/commands/whereami.rb000066400000000000000000000116401260757071700177320ustar00rootroot00000000000000class Pry class Command::Whereami < Pry::ClassCommand class << self attr_accessor :method_size_cutoff end @method_size_cutoff = 30 match 'whereami' description 'Show code surrounding the current context.' group 'Context' banner <<-'BANNER' Usage: whereami [-qn] [LINES] Describe the current location. If you use `binding.pry` inside a method then whereami will print out the source for that method. If a number is passed, then LINES lines before and after the current line will be shown instead of the method itself. The `-q` flag can be used to suppress error messages in the case that there's no code to show. This is used by pry in the default before_session hook to show you when you arrive at a `binding.pry`. The `-n` flag can be used to hide line numbers so that code can be copy/pasted effectively. When pry was started on an Object and there is no associated method, whereami will instead output a brief description of the current object. BANNER def setup @file = expand_path(target.eval('__FILE__')) @line = target.eval('__LINE__') @method = Pry::Method.from_binding(target) end def options(opt) opt.on :q, :quiet, "Don't display anything in case of an error" opt.on :n, :"no-line-numbers", "Do not display line numbers" opt.on :m, :"method", "Show the complete source for the current method." opt.on :c, :"class", "Show the complete source for the current class or module." opt.on :f, :"file", "Show the complete source for the current file." end def code @code ||= if opts.present?(:m) method_code or raise CommandError, "Cannot find method code." elsif opts.present?(:c) class_code or raise CommandError, "Cannot find class code." elsif opts.present?(:f) Pry::Code.from_file(@file) elsif args.any? code_window else default_code end end def code? !!code rescue MethodSource::SourceNotFoundError false end def bad_option_combination? [opts.present?(:m), opts.present?(:f), opts.present?(:c), args.any?].count(true) > 1 end def location "#{@file} @ line #{@line} #{@method && @method.name_with_owner}" end def process if bad_option_combination? raise CommandError, "Only one of -m, -c, -f, and LINES may be specified." end if nothing_to_do? return elsif internal_binding?(target) handle_internal_binding return end set_file_and_dir_locals(@file) out = "\n#{text.bold('From:')} #{location}:\n\n" << code.with_line_numbers(use_line_numbers?).with_marker(marker).highlighted << "\n" _pry_.pager.page out end private def nothing_to_do? opts.quiet? && (internal_binding?(target) || !code?) end def use_line_numbers? !opts.present?(:n) end def marker !opts.present?(:n) && @line end def top_level? target_self == Pry.main end def handle_internal_binding if top_level? output.puts "At the top level." else output.puts "Inside #{Pry.view_clip(target_self)}." end end def small_method? @method.source_range.count < self.class.method_size_cutoff end def default_code if method_code && small_method? method_code else code_window end end def code_window Pry::Code.from_file(@file).around(@line, window_size) end def method_code return @method_code if @method_code if valid_method? @method_code = Pry::Code.from_method(@method) end end # This either returns the `target_self` # or it returns the class of `target_self` if `target_self` is not a class. # @return [Pry::WrappedModule] def target_class target_self.is_a?(Module) ? Pry::WrappedModule(target_self) : Pry::WrappedModule(target_self.class) end def class_code return @class_code if @class_code mod = @method ? Pry::WrappedModule(@method.owner) : target_class idx = mod.candidates.find_index { |v| expand_path(v.source_file) == @file } @class_code = idx && Pry::Code.from_module(mod, idx) end def valid_method? @method && @method.source? && expand_path(@method.source_file) == @file && @method.source_range.include?(@line) end def expand_path(f) return if !f if Pry.eval_path == f f else File.expand_path(f) end end def window_size if args.empty? _pry_.config.default_window_size else args.first.to_i end end end Pry::Commands.add_command(Pry::Command::Whereami) Pry::Commands.alias_command '@', 'whereami' end pry-0.10.3/lib/pry/commands/wtf.rb000066400000000000000000000025051260757071700167310ustar00rootroot00000000000000class Pry class Command::Wtf < Pry::ClassCommand match(/wtf([?!]*)/) group 'Context' description 'Show the backtrace of the most recent exception.' options :listing => 'wtf?' banner <<-'BANNER' Usage: wtf[?|!] Show's a few lines of the backtrace of the most recent exception (also available as `_ex_.backtrace`). If you want to see more lines, add more question marks or exclamation marks. wtf? wtf?!???!?!? # To see the entire backtrace, pass the `-v` or `--verbose` flag. wtf -v BANNER def options(opt) opt.on :v, :verbose, "Show the full backtrace" end def process raise Pry::CommandError, "No most-recent exception" unless exception output.puts "#{text.bold('Exception:')} #{exception.class}: #{exception}\n--" if opts.verbose? output.puts with_line_numbers(backtrace) else output.puts with_line_numbers(backtrace.first(size_of_backtrace)) end end private def exception _pry_.last_exception end def with_line_numbers(bt) Pry::Code.new(bt, 0, :text).with_line_numbers.to_s end def backtrace exception.backtrace end def size_of_backtrace [captures[0].size, 0.5].max * 10 end end Pry::Commands.add_command(Pry::Command::Wtf) end pry-0.10.3/lib/pry/config.rb000066400000000000000000000010721260757071700155730ustar00rootroot00000000000000class Pry::Config require_relative 'config/behavior' require_relative 'config/default' require_relative 'config/convenience' include Pry::Config::Behavior def self.shortcuts Convenience::SHORTCUTS end # # FIXME # @param [Pry::Hooks] hooks # def hooks=(hooks) if hooks.is_a?(Hash) warn "Hash-based hooks are now deprecated! Use a `Pry::Hooks` object " \ "instead! http://rubydoc.info/github/pry/pry/master/Pry/Hooks" self["hooks"] = Pry::Hooks.from_hash(hooks) else self["hooks"] = hooks end end end pry-0.10.3/lib/pry/config/000077500000000000000000000000001260757071700152465ustar00rootroot00000000000000pry-0.10.3/lib/pry/config/behavior.rb000066400000000000000000000055541260757071700174030ustar00rootroot00000000000000module Pry::Config::Behavior ASSIGNMENT = "=".freeze NODUP = [TrueClass, FalseClass, NilClass, Symbol, Numeric, Module, Proc].freeze INSPECT_REGEXP = /#{Regexp.escape "default=#<"}/ module Builder def from_hash(hash, default = nil) new(default).tap do |config| config.merge!(hash) end end end def self.included(klass) unless defined?(RESERVED_KEYS) const_set :RESERVED_KEYS, instance_methods(false).map(&:to_s).freeze end klass.extend(Builder) end def initialize(default = Pry.config) @default = default @lookup = {} end # # @return [Pry::Config::Behavior] # returns the default used if a matching value for a key isn't found in self # def default @default end def [](key) @lookup[key.to_s] end def []=(key, value) key = key.to_s if RESERVED_KEYS.include?(key) raise ArgumentError, "few things are reserved by pry, but using '#{key}' as a configuration key is." end @lookup[key] = value end def method_missing(name, *args, &block) key = name.to_s if key[-1] == ASSIGNMENT short_key = key[0..-2] self[short_key] = args[0] elsif key?(key) self[key] elsif @default.respond_to?(name) value = @default.public_send(name, *args, &block) # FIXME: refactor Pry::Hook so that it stores config on the config object, # so that we can use the normal strategy. self[key] = value = value.dup if key == 'hooks' value else nil end end def merge!(other) other = try_convert_to_hash(other) raise TypeError, "unable to convert argument into a Hash" unless other other.each do |key, value| self[key] = value end end def ==(other) @lookup == try_convert_to_hash(other) end alias_method :eql?, :== def respond_to_missing?(key, include_private=false) key?(key) or @default.respond_to?(key) or super(key, include_private) end def key?(key) key = key.to_s @lookup.key?(key) end def clear @lookup.clear true end alias_method :refresh, :clear def forget(key) @lookup.delete(key.to_s) end def keys @lookup.keys end def to_hash @lookup.dup end alias_method :to_h, :to_hash def inspect key_str = keys.map { |key| "'#{key}'" }.join(",") "#<#{_clip_inspect(self)} local_keys=[#{key_str}] default=#{@default.inspect}>" end def pretty_print(q) q.text inspect[1..-1].gsub(INSPECT_REGEXP, "default=<") end private def _clip_inspect(obj) "#{obj.class}:0x%x" % obj.object_id << 1 end def _dup(value) if NODUP.any? { |klass| klass === value } value else value.dup end end def try_convert_to_hash(obj) if Hash === obj obj elsif obj.respond_to?(:to_h) obj.to_h elsif obj.respond_to?(:to_hash) obj.to_hash else nil end end end pry-0.10.3/lib/pry/config/convenience.rb000066400000000000000000000011351260757071700200670ustar00rootroot00000000000000module Pry::Config::Convenience SHORTCUTS = [ :input, :output, :commands, :print, :exception_handler, :hooks, :color, :pager, :editor, :memory_size, :extra_sticky_locals ] def config_shortcut(*names) names.each do |name| reader = name setter = "#{name}=" define_method(reader) { config.public_send(name) } define_method(setter) { |value| config.public_send(setter, value) } end end end pry-0.10.3/lib/pry/config/default.rb000066400000000000000000000065411260757071700172250ustar00rootroot00000000000000class Pry::Config::Default include Pry::Config::Behavior default = { input: proc { lazy_readline }, output: proc { $stdout }, commands: proc { Pry::Commands }, prompt_name: proc { Pry::DEFAULT_PROMPT_NAME }, prompt: proc { Pry::DEFAULT_PROMPT }, prompt_safe_objects: proc { Pry::DEFAULT_PROMPT_SAFE_OBJECTS }, print: proc { Pry::DEFAULT_PRINT }, quiet: proc { false }, exception_handler: proc { Pry::DEFAULT_EXCEPTION_HANDLER }, exception_whitelist: proc { Pry::DEFAULT_EXCEPTION_WHITELIST }, hooks: proc { Pry::DEFAULT_HOOKS }, pager: proc { true }, system: proc { Pry::DEFAULT_SYSTEM }, color: proc { Pry::Helpers::BaseHelpers.use_ansi_codes? }, default_window_size: proc { 5 }, editor: proc { Pry.default_editor_for_platform }, # TODO: Pry::Platform.editor should_load_rc: proc { true }, should_load_local_rc: proc { true }, should_trap_interrupts: proc { Pry::Helpers::BaseHelpers.jruby? }, # TODO: Pry::Platform.jruby? disable_auto_reload: proc { false }, command_prefix: proc { "" }, auto_indent: proc { Pry::Helpers::BaseHelpers.use_ansi_codes? }, correct_indent: proc { true }, collision_warning: proc { false }, output_prefix: proc { "=> " }, requires: proc { [] }, should_load_requires: proc { true }, should_load_plugins: proc { true }, windows_console_warning: proc { true }, control_d_handler: proc { Pry::DEFAULT_CONTROL_D_HANDLER }, memory_size: proc { 100 }, extra_sticky_locals: proc { {} }, command_completions: proc { proc { commands.keys } }, file_completions: proc { proc { Dir["."] } }, ls: proc { Pry::Config.from_hash(Pry::Command::Ls::DEFAULT_OPTIONS) }, completer: proc { require "pry/input_completer" Pry::InputCompleter } } def initialize super(nil) configure_gist configure_history end default.each do |key, value| define_method(key) do if default[key].equal?(value) default[key] = instance_eval(&value) end default[key] end end private # TODO: # all of this configure_* stuff is a relic of old code. # we should try move this code to being command-local. def configure_gist self["gist"] = Pry::Config.from_hash(inspecter: proc(&:pretty_inspect)) end def configure_history self["history"] = Pry::Config.from_hash "should_save" => true, "should_load" => true history.file = File.expand_path("~/.pry_history") rescue nil if history.file.nil? self.should_load_rc = false history.should_save = false history.should_load = false end end def lazy_readline require 'readline' Readline rescue LoadError warn "Sorry, you can't use Pry without Readline or a compatible library." warn "Possible solutions:" warn " * Rebuild Ruby with Readline support using `--with-readline`" warn " * Use the rb-readline gem, which is a pure-Ruby port of Readline" warn " * Use the pry-coolline gem, a pure-ruby alternative to Readline" raise end end pry-0.10.3/lib/pry/core_extensions.rb000066400000000000000000000107331260757071700175410ustar00rootroot00000000000000class Pry # @return [Array] Code of the method used when implementing Pry's # __binding__, along with line indication to be used with instance_eval (and # friends). # # @see Object#__binding__ BINDING_METHOD_IMPL = [<<-METHOD, __FILE__, __LINE__ + 1] # Get a binding with 'self' set to self, and no locals. # # The default definee is determined by the context in which the # definition is eval'd. # # Please don't call this method directly, see {__binding__}. # # @return [Binding] def __pry__ binding end METHOD end class Object # Start a Pry REPL on self. # # If `self` is a Binding then that will be used to evaluate expressions; # otherwise a new binding will be created. # # @param [Object] object the object or binding to pry # (__deprecated__, use `object.pry`) # @param [Hash] hash the options hash # @example With a binding # binding.pry # @example On any object # "dummy".pry # @example With options # def my_method # binding.pry :quiet => true # end # my_method() # @see Pry.start def pry(object=nil, hash={}) if object.nil? || Hash === object Pry.start(self, object || {}) else Pry.start(object, hash) end end # Return a binding object for the receiver. # # The `self` of the binding is set to the current object, and it contains no # local variables. # # The default definee (http://yugui.jp/articles/846) is set such that: # # * If `self` is a class or module, then new methods created in the binding # will be defined in that class or module (as in `class Foo; end`). # * If `self` is a normal object, then new methods created in the binding will # be defined on its singleton class (as in `class << self; end`). # * If `self` doesn't have a real singleton class (i.e. it is a Fixnum, Float, # Symbol, nil, true, or false), then new methods will be created on the # object's class (as in `self.class.class_eval{ }`) # # Newly created constants, including classes and modules, will also be added # to the default definee. # # @return [Binding] def __binding__ # If you ever feel like changing this method, be careful about variables # that you use. They shouldn't be inserted into the binding that will # eventually be returning. # When you're cd'd into a class, methods you define should be added to it. if is_a?(Module) # class_eval sets both self and the default definee to this class. return class_eval "binding" end unless respond_to?(:__pry__) # The easiest way to check whether an object has a working singleton class # is to try and define a method on it. (just checking for the presence of # the singleton class gives false positives for `true` and `false`). # __pry__ is just the closest method we have to hand, and using # it has the nice property that we can memoize this check. begin # instance_eval sets the default definee to the object's singleton class instance_eval(*Pry::BINDING_METHOD_IMPL) # If we can't define methods on the Object's singleton_class. Then we fall # back to setting the default definee to be the Object's class. That seems # nicer than having a REPL in which you can't define methods. rescue TypeError, Pry::FrozenObjectException # class_eval sets the default definee to self.class self.class.class_eval(*Pry::BINDING_METHOD_IMPL) end end __pry__ end end class BasicObject # Return a binding object for the receiver. # # The `self` of the binding is set to the current object, and it contains no # local variables. # # The default definee (http://yugui.jp/articles/846) is set such that new # methods defined will be added to the singleton class of the BasicObject. # # @return [Binding] def __binding__ # BasicObjects don't have respond_to?, so we just define the method # every time. As they also don't have `.freeze`, this call won't # fail as it can for normal Objects. (class << self; self; end).class_eval <<-EOF, __FILE__, __LINE__ + 1 # Get a binding with 'self' set to self, and no locals. # # The default definee is determined by the context in which the # definition is eval'd. # # Please don't call this method directly, see {__binding__}. # # @return [Binding] def __pry__ ::Kernel.binding end EOF self.__pry__ end end pry-0.10.3/lib/pry/editor.rb000066400000000000000000000102331260757071700156130ustar00rootroot00000000000000class Pry class Editor include Pry::Helpers::BaseHelpers include Pry::Helpers::CommandHelpers attr_reader :_pry_ def initialize(_pry_) @_pry_ = _pry_ end def edit_tempfile_with_content(initial_content, line=1) temp_file do |f| f.puts(initial_content) f.flush f.close(false) invoke_editor(f.path, line, true) File.read(f.path) end end def invoke_editor(file, line, blocking=true) raise CommandError, "Please set Pry.config.editor or export $VISUAL or $EDITOR" unless _pry_.config.editor editor_invocation = build_editor_invocation_string(file, line, blocking) return nil unless editor_invocation if jruby? open_editor_on_jruby(editor_invocation) else open_editor(editor_invocation) end end private # Generate the string that's used to start the editor. This includes # all the flags we want as well as the file and line number we # want to open at. def build_editor_invocation_string(file, line, blocking) if _pry_.config.editor.respond_to?(:call) args = [file, line, blocking][0...(_pry_.config.editor.arity)] _pry_.config.editor.call(*args) else sanitized_file = if windows? file.gsub(/\//, '\\') else Shellwords.escape(file) end "#{_pry_.config.editor} #{blocking_flag_for_editor(blocking)} #{start_line_syntax_for_editor(sanitized_file, line)}" end end # Start the editor running, using the calculated invocation string def open_editor(editor_invocation) # Note we dont want to use Pry.config.system here as that # may be invoked non-interactively (i.e via Open4), whereas we want to # ensure the editor is always interactive system(*Shellwords.split(editor_invocation)) or raise CommandError, "`#{editor_invocation}` gave exit status: #{$?.exitstatus}" end # We need JRuby specific code here cos just shelling out using # system() appears to be pretty broken :/ def open_editor_on_jruby(editor_invocation) begin require 'spoon' pid = Spoon.spawnp(*Shellwords.split(editor_invocation)) Process.waitpid(pid) rescue FFI::NotFoundError system(editor_invocation) end end # Some editors that run outside the terminal allow you to control whether or # not to block the process from which they were launched (in this case, Pry). # For those editors, return the flag that produces the desired behavior. def blocking_flag_for_editor(blocking) case editor_name when /^emacsclient/ '--no-wait' unless blocking when /^[gm]vim/ '--nofork' if blocking when /^jedit/ '-wait' if blocking when /^mate/, /^subl/, /^redcar/ '-w' if blocking end end # Return the syntax for a given editor for starting the editor # and moving to a particular line within that file def start_line_syntax_for_editor(file_name, line_number) # special case for 1st line return file_name if line_number <= 1 case editor_name when /^[gm]?vi/, /^emacs/, /^nano/, /^pico/, /^gedit/, /^kate/ "+#{line_number} #{file_name}" when /^mate/, /^geany/ "-l #{line_number} #{file_name}" when /^subl/ "#{file_name}:#{line_number}" when /^uedit32/ "#{file_name}/#{line_number}" when /^jedit/ "#{file_name} +line:#{line_number}" when /^redcar/ "-l#{line_number} #{file_name}" else if windows? "#{file_name}" else "+#{line_number} #{file_name}" end end end # Get the name of the binary that Pry.config.editor points to. # # This is useful for deciding which flags we pass to the editor as # we can just use the program's name and ignore any absolute paths. # # @example # Pry.config.editor="/home/conrad/bin/textmate -w" # editor_name # # => textmate # def editor_name File.basename(_pry_.config.editor).split(" ").first end end end pry-0.10.3/lib/pry/exceptions.rb000066400000000000000000000050231260757071700165070ustar00rootroot00000000000000class Pry # As a REPL, we often want to catch any unexpected exceptions that may have # been raised; however we don't want to go overboard and prevent the user # from exiting Pry when they want to. module RescuableException def self.===(exception) case exception # Catch when the user hits ^C (Interrupt < SignalException), and assume # that they just wanted to stop the in-progress command (just like bash # etc.) when Interrupt true # Don't catch signals (particularly not SIGTERM) as these are unlikely # to be intended for pry itself. We should also make sure that # Kernel#exit works. when *Pry.config.exception_whitelist false # All other exceptions will be caught. else true end end end # Catches SecurityErrors if $SAFE is set module Pry::TooSafeException def self.===(exception) $SAFE > 0 && SecurityError === exception end end # An Exception Tag (cf. Exceptional Ruby) that instructs Pry to show the error # in a more user-friendly manner. This should be used when the exception # happens within Pry itself as a direct consequence of the user typing # something wrong. # # This allows us to distinguish between the user typing: # # pry(main)> def ) # SyntaxError: unexpected ) # # pry(main)> method_that_evals("def )") # SyntaxError: (eval):1: syntax error, unexpected ')' # from ./a.rb:2 in `eval' module UserError; end # When we try to get a binding for an object, we try to define a method on # that Object's singleton class. This doesn't work for "frozen" Object's, and # the exception is just a vanilla RuntimeError. module FrozenObjectException def self.===(exception) ["can't modify frozen class/module", "can't modify frozen Class", "can't modify frozen object" ].include?(exception.message) end end # Don't catch these exceptions DEFAULT_EXCEPTION_WHITELIST = [SystemExit, SignalException, Pry::TooSafeException] # CommandErrors are caught by the REPL loop and displayed to the user. They # indicate an exceptional condition that's fatal to the current command. class CommandError < StandardError; end class MethodNotFound < CommandError; end # indicates obsolete API class ObsoleteError < StandardError; end # This is to keep from breaking under Rails 3.2 for people who are doing that # IRB = Pry thing. module ExtendCommandBundle end end pry-0.10.3/lib/pry/helpers.rb000066400000000000000000000002461260757071700157720ustar00rootroot00000000000000require "pry/helpers/base_helpers" require "pry/helpers/options_helpers" require "pry/helpers/command_helpers" require "pry/helpers/text" require "pry/helpers/table" pry-0.10.3/lib/pry/helpers/000077500000000000000000000000001260757071700154435ustar00rootroot00000000000000pry-0.10.3/lib/pry/helpers/base_helpers.rb000066400000000000000000000054741260757071700204360ustar00rootroot00000000000000class Pry module Helpers module BaseHelpers module_function def silence_warnings old_verbose = $VERBOSE $VERBOSE = nil begin yield ensure $VERBOSE = old_verbose end end # Acts like send but ignores any methods defined below Object or Class in the # inheritance hierarchy. # This is required to introspect methods on objects like Net::HTTP::Get that # have overridden the `method` method. def safe_send(obj, method, *args, &block) (Module === obj ? Module : Object).instance_method(method).bind(obj).call(*args, &block) end public :safe_send def find_command(name, set = Pry::Commands) command_match = set.find do |_, command| (listing = command.options[:listing]) == name && listing != nil end command_match.last if command_match end def not_a_real_file?(file) file =~ /(\(.*\))|<.*>/ || file =~ /__unknown__/ || file == "" || file == "-e" end def command_dependencies_met?(options) return true if !options[:requires_gem] Array(options[:requires_gem]).all? do |g| Rubygem.installed?(g) end end def use_ansi_codes? windows_ansi? || ENV['TERM'] && ENV['TERM'] != "dumb" end def colorize_code(code) CodeRay.scan(code, :ruby).term end def highlight(string, regexp, highlight_color=:bright_yellow) string.gsub(regexp) { |match| "<#{highlight_color}>#{match}" } end # formatting def heading(text) text = "#{text}\n--" "\e[1m#{text}\e[0m" end # have fun on the Windows platform. def windows? RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ end # are we able to use ansi on windows? def windows_ansi? defined?(Win32::Console) || ENV['ANSICON'] || (windows? && mri_2?) end def jruby? RbConfig::CONFIG['ruby_install_name'] == 'jruby' end def jruby_19? jruby? && RbConfig::CONFIG['ruby_version'] == '1.9' end def rbx? RbConfig::CONFIG['ruby_install_name'] == 'rbx' end def mri? RbConfig::CONFIG['ruby_install_name'] == 'ruby' end def mri_19? mri? && RUBY_VERSION =~ /^1\.9/ end def mri_2? mri? && RUBY_VERSION =~ /^2/ end def mri_20? mri? && RUBY_VERSION =~ /^2\.0/ end def mri_21? mri? && RUBY_VERSION =~ /^2\.1/ end # Send the given text through the best available pager (if Pry.config.pager is # enabled). Infers where to send the output if used as a mixin. # DEPRECATED. def stagger_output(text, out = nil) Pry.new.pager.page text end end end end pry-0.10.3/lib/pry/helpers/command_helpers.rb000066400000000000000000000120141260757071700211260ustar00rootroot00000000000000class Pry module Helpers module CommandHelpers include OptionsHelpers module_function # Open a temp file and yield it to the block, closing it after # @return [String] The path of the temp file def temp_file(ext='.rb') file = Tempfile.new(['pry', ext]) yield file ensure file.close(true) if file end def internal_binding?(target) m = target.eval("::Kernel.__method__").to_s # class_eval is here because of http://jira.codehaus.org/browse/JRUBY-6753 ["__binding__", "__pry__", "class_eval"].include?(m) end def get_method_or_raise(name, target, opts={}, omit_help=false) meth = Pry::Method.from_str(name, target, opts) if name && !meth command_error("The method '#{name}' could not be found.", omit_help, MethodNotFound) end (opts[:super] || 0).times do if meth.super meth = meth.super else command_error("'#{meth.name_with_owner}' has no super method.", omit_help, MethodNotFound) end end if !meth || (!name && internal_binding?(target)) command_error("No method name given, and context is not a method.", omit_help, MethodNotFound) end set_file_and_dir_locals(meth.source_file) meth end def command_error(message, omit_help, klass=CommandError) message += " Type `#{command_name} --help` for help." unless omit_help raise klass, message end # Remove any common leading whitespace from every line in `text`. # # This can be used to make a HEREDOC line up with the left margin, without # sacrificing the indentation level of the source code. # # e.g. # opt.banner unindent <<-USAGE # Lorem ipsum dolor sit amet, consectetur adipisicing elit, # sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. # "Ut enim ad minim veniam." # USAGE # # Heavily based on textwrap.dedent from Python, which is: # Copyright (C) 1999-2001 Gregory P. Ward. # Copyright (C) 2002, 2003 Python Software Foundation. # Written by Greg Ward # # Licensed under # From # # @param [String] text The text from which to remove indentation # @return [String] The text with indentation stripped. def unindent(text, left_padding = 0) # Empty blank lines text = text.sub(/^[ \t]+$/, '') # Find the longest common whitespace to all indented lines # Ignore lines containing just -- or ++ as these seem to be used by # comment authors as delimeters. margin = text.scan(/^[ \t]*(?!--\n|\+\+\n)(?=[^ \t\n])/).inject do |current_margin, next_indent| if next_indent.start_with?(current_margin) current_margin elsif current_margin.start_with?(next_indent) next_indent else "" end end text.gsub(/^#{margin}/, ' ' * left_padding) end # Restrict a string to the given range of lines (1-indexed) # @param [String] content The string. # @param [Range, Fixnum] lines The line(s) to restrict it to. # @return [String] The resulting string. def restrict_to_lines(content, lines) line_range = one_index_range_or_number(lines) Array(content.lines.to_a[line_range]).join end def one_index_number(line_number) if line_number > 0 line_number - 1 else line_number end end # convert a 1-index range to a 0-indexed one def one_index_range(range) Range.new(one_index_number(range.begin), one_index_number(range.end)) end def one_index_range_or_number(range_or_number) case range_or_number when Range one_index_range(range_or_number) else one_index_number(range_or_number) end end def absolute_index_number(line_number, array_length) if line_number >= 0 line_number else [array_length + line_number, 0].max end end def absolute_index_range(range_or_number, array_length) case range_or_number when Range a = absolute_index_number(range_or_number.begin, array_length) b = absolute_index_number(range_or_number.end, array_length) else a = b = absolute_index_number(range_or_number, array_length) end Range.new(a, b) end def set_file_and_dir_locals(file_name, _pry_=_pry_(), target=target()) return if !target or !file_name _pry_.last_file = File.expand_path(file_name) _pry_.inject_local("_file_", _pry_.last_file, target) _pry_.last_dir = File.dirname(_pry_.last_file) _pry_.inject_local("_dir_", _pry_.last_dir, target) end end end end pry-0.10.3/lib/pry/helpers/documentation_helpers.rb000066400000000000000000000046651260757071700223760ustar00rootroot00000000000000class Pry module Helpers # This class contains methods useful for extracting # documentation from methods and classes. module DocumentationHelpers module_function def process_rdoc(comment) comment = comment.dup comment.gsub(/(?:\s*\n)?(.*?)\s*<\/code>/m) { CodeRay.scan($1, :ruby).term }. gsub(/(?:\s*\n)?(.*?)\s*<\/em>/m) { "\e[1m#{$1}\e[0m" }. gsub(/(?:\s*\n)?(.*?)\s*<\/i>/m) { "\e[1m#{$1}\e[0m" }. gsub(/\B\+(\w+?)\+\B/) { "\e[32m#{$1}\e[0m" }. gsub(/((?:^[ \t]+.+(?:\n+|\Z))+)/) { CodeRay.scan($1, :ruby).term }. gsub(/`(?:\s*\n)?([^\e]*?)\s*`/) { "`#{CodeRay.scan($1, :ruby).term}`" } end def process_yardoc_tag(comment, tag) in_tag_block = nil comment.lines.map do |v| if in_tag_block && v !~ /^\S/ Pry::Helpers::Text.strip_color Pry::Helpers::Text.strip_color(v) elsif in_tag_block in_tag_block = false v else in_tag_block = true if v =~ /^@#{tag}/ v end end.join end def process_yardoc(comment) yard_tags = ["param", "return", "option", "yield", "attr", "attr_reader", "attr_writer", "deprecate", "example", "raise"] (yard_tags - ["example"]).inject(comment) { |a, v| process_yardoc_tag(a, v) }. gsub(/^@(#{yard_tags.join("|")})/) { "\e[33m#{$1}\e[0m" } end def process_comment_markup(comment) process_yardoc process_rdoc(comment) end # @param [String] code # @return [String] def strip_comments_from_c_code(code) code.sub(/\A\s*\/\*.*?\*\/\s*/m, '') end # Given a string that makes up a comment in a source-code file parse out the content # that the user is intended to read. (i.e. without leading indentation, #-characters # or shebangs) # # @param [String] comment # @return [String] def get_comment_content(comment) comment = comment.dup # Remove #!/usr/bin/ruby comment.gsub!(/\A\#!.*$/, '') # Remove leading empty comment lines comment.gsub!(/\A\#+?$/, '') comment.gsub!(/^\s*#/, '') strip_leading_whitespace(comment) end # @param [String] text # @return [String] def strip_leading_whitespace(text) Pry::Helpers::CommandHelpers.unindent(text) end end end end pry-0.10.3/lib/pry/helpers/options_helpers.rb000066400000000000000000000021271260757071700212070ustar00rootroot00000000000000class Pry module Helpers module OptionsHelpers module_function # Add method options to the Slop instance def method_options(opt) @method_target = target opt.on :M, "instance-methods", "Operate on instance methods." opt.on :m, :methods, "Operate on methods." opt.on :s, :super, "Select the 'super' method. Can be repeated to traverse the ancestors.", :as => :count opt.on :c, :context, "Select object context to run under.", :argument => true do |context| @method_target = Pry.binding_for(target.eval(context)) end end # Get the method object parsed by the slop instance def method_object @method_object ||= get_method_or_raise(args.empty? ? nil : args.join(" "), @method_target, :super => opts[:super], :instance => opts.present?(:'instance-methods') && !opts.present?(:'methods'), :methods => opts.present?(:'methods') && !opts.present?(:'instance-methods') ) end end end end pry-0.10.3/lib/pry/helpers/table.rb000066400000000000000000000054551260757071700170700ustar00rootroot00000000000000class Pry module Helpers def self.tablify_or_one_line(heading, things) plain_heading = Pry::Helpers::Text.strip_color(heading) attempt = Table.new(things, :column_count => things.size) if attempt.fits_on_line?(Terminal.width! - plain_heading.size - 2) "#{heading}: #{attempt}\n" else "#{heading}: \n#{tablify_to_screen_width(things, :indent => ' ')}\n" end end def self.tablify_to_screen_width(things, options = {}) things = things.compact if indent = options[:indent] usable_width = Terminal.width! - indent.size tablify(things, usable_width).to_s.gsub(/^/, indent) else tablify(things, Terminal.width!).to_s end end def self.tablify(things, line_length) table = Table.new(things, :column_count => things.size) table.column_count -= 1 until 1 == table.column_count or table.fits_on_line?(line_length) table end class Table attr_reader :items, :column_count def initialize items, args = {} @column_count = args[:column_count] self.items = items end def to_s rows_to_s.join("\n") end def rows_to_s style = :color_on widths = columns.map{|e| _max_width(e)} @rows_without_colors.map do |r| padded = [] r.each_with_index do |e,i| next unless e item = e.ljust(widths[i]) item.sub! e, _recall_color_for(e) if :color_on == style padded << item end padded.join(Pry.config.ls.separator) end end def items= items @items = items _rebuild_colorless_cache _recolumn items end def column_count= n @column_count = n _recolumn end def fits_on_line? line_length _max_width(rows_to_s :no_color) <= line_length end def columns @rows_without_colors.transpose end def ==(other); items == other.to_a end def to_a; items.to_a end private def _max_width(things) things.compact.map(&:size).max || 0 end def _rebuild_colorless_cache @colorless_cache = {} @plain_items = [] items.map do |e| plain = Pry::Helpers::Text.strip_color(e) @colorless_cache[plain] = e @plain_items << plain end end def _recolumn @rows_without_colors = [] return if items.size.zero? row_count = (items.size.to_f/column_count).ceil row_count.times do |i| row_indices = (0...column_count).map{|e| row_count*e+i} @rows_without_colors << row_indices.map{|e| @plain_items[e]} end end def _recall_color_for thing @colorless_cache[thing] end end end end pry-0.10.3/lib/pry/helpers/text.rb000066400000000000000000000054251260757071700167620ustar00rootroot00000000000000class Pry module Helpers # The methods defined on {Text} are available to custom commands via {Pry::Command#text}. module Text COLORS = { "black" => 0, "red" => 1, "green" => 2, "yellow" => 3, "blue" => 4, "purple" => 5, "magenta" => 5, "cyan" => 6, "white" => 7 } class << self COLORS.each_pair do |color, value| define_method color do |text| "\033[0;#{30+value}m#{text}\033[0m" end define_method "bright_#{color}" do |text| "\033[1;#{30+value}m#{text}\033[0m" end end # Remove any color codes from _text_. # # @param [String, #to_s] text # @return [String] _text_ stripped of any color codes. def strip_color(text) text.to_s.gsub(/\e\[.*?(\d)+m/ , '') end # Returns _text_ as bold text for use on a terminal. # # @param [String, #to_s] text # @return [String] _text_ def bold(text) "\e[1m#{text}\e[0m" end # Returns `text` in the default foreground colour. # Use this instead of "black" or "white" when you mean absence of colour. # # @param [String, #to_s] text # @return [String] def default(text) text.to_s end alias_method :bright_default, :bold # Executes the block with `Pry.config.color` set to false. # @yield # @return [void] def no_color(&block) boolean = Pry.config.color Pry.config.color = false yield ensure Pry.config.color = boolean end # Executes the block with `Pry.config.pager` set to false. # @yield # @return [void] def no_pager(&block) boolean = Pry.config.pager Pry.config.pager = false yield ensure Pry.config.pager = boolean end # Returns _text_ in a numbered list, beginning at _offset_. # # @param [#each_line] text # @param [Fixnum] offset # @return [String] def with_line_numbers(text, offset, color=:blue) lines = text.each_line.to_a max_width = (offset + lines.count).to_s.length lines.each_with_index.map do |line, index| adjusted_index = (index + offset).to_s.rjust(max_width) "#{self.send(color, adjusted_index)}: #{line}" end.join end # Returns _text_ indented by _chars_ spaces. # # @param [String] text # @param [Fixnum] chars def indent(text, chars) text.lines.map { |l| "#{' ' * chars}#{l}" }.join end end end end end pry-0.10.3/lib/pry/history.rb000066400000000000000000000067011260757071700160330ustar00rootroot00000000000000class Pry # The History class is responsible for maintaining the user's input history, # both internally and within Readline. class History attr_accessor :loader, :saver, :pusher, :clearer # @return [Fixnum] Number of lines in history when Pry first loaded. attr_reader :original_lines def initialize(options={}) @history = [] @original_lines = 0 @file_path = options[:file_path] restore_default_behavior end # Assign the default methods for loading, saving, pushing, and clearing. def restore_default_behavior Pry.config.input # force Readline to load if applicable @loader = method(:read_from_file) @saver = method(:save_to_file) if defined?(Readline) @pusher = method(:push_to_readline) @clearer = method(:clear_readline) else @pusher = proc { } @clearer = proc { } end end # Load the input history using `History.loader`. # @return [Integer] The number of lines loaded def load @loader.call do |line| @pusher.call(line.chomp) @history << line.chomp @original_lines += 1 end end # Add a line to the input history, ignoring blank and duplicate lines. # @param [String] line # @return [String] The same line that was passed in def push(line) unless line.empty? || (@history.last && line == @history.last) @pusher.call(line) @history << line @saver.call(line) if Pry.config.history.should_save end line end alias << push # Clear this session's history. This won't affect the contents of the # history file. def clear @clearer.call @history = [] end # @return [Fixnum] The number of lines in history. def history_line_count @history.count end # @return [Fixnum] The number of lines in history from just this session. def session_line_count @history.count - @original_lines end # Return an Array containing all stored history. # @return [Array] An Array containing all lines of history loaded # or entered by the user in the current session. def to_a @history.dup end private # The default loader. Yields lines from `Pry.history.config.file`. def read_from_file path = history_file_path if File.exists?(path) File.foreach(path) { |line| yield(line) } end rescue => error warn "History file not loaded: #{error.message}" end # The default pusher. Appends the given line to Readline::HISTORY. # @param [String] line def push_to_readline(line) Readline::HISTORY << line end # The default clearer. Clears Readline::HISTORY. def clear_readline Readline::HISTORY.shift until Readline::HISTORY.empty? end # The default saver. Appends the given line to `Pry.history.config.file`. def save_to_file(line) history_file.puts line if history_file end # The history file, opened for appending. def history_file if defined?(@history_file) @history_file else @history_file = File.open(history_file_path, 'a', 0600).tap do |file| file.sync = true end end rescue Errno::EACCES warn 'History not saved; unable to open your history file for writing.' @history_file = false end def history_file_path File.expand_path(@file_path || Pry.config.history.file) end end end pry-0.10.3/lib/pry/history_array.rb000066400000000000000000000057311260757071700172330ustar00rootroot00000000000000class Pry # A history array is an array to which you can only add elements. Older # entries are removed progressively, so that the array never contains more than # N elements. # # History arrays are used by Pry to store the output of the last commands. # # @example # ary = Pry::HistoryArray.new 10 # ary << 1 << 2 << 3 # ary[0] # => 1 # ary[1] # => 2 # 10.times { |n| ary << n } # ary[0] # => nil # ary[-1] # => 9 class HistoryArray include Enumerable # @param [Integer] size Maximum amount of objects in the array def initialize(size) @max_size = size @hash = {} @count = 0 end # Pushes an object at the end of the array # @param [Object] value Object to be added def <<(value) @hash[@count] = value if @hash.size > max_size @hash.delete(@count - max_size) end @count += 1 self end # @overload [](index) # @param [Integer] index Index of the item to access. # @return [Object, nil] Item at that index or nil if it has been removed. # @overload [](index, size) # @param [Integer] index Index of the first item to access. # @param [Integer] size Amount of items to access # @return [Array, nil] The selected items. Nil if index is greater than # the size of the array. # @overload [](range) # @param [Range] range Range of indices to access. # @return [Array, nil] The selected items. Nil if index is greater than # the size of the array. def [](index_or_range, size = nil) if index_or_range.is_a? Integer index = convert_index(index_or_range) if size end_index = index + size index > @count ? nil : (index...[end_index, @count].min).map do |n| @hash[n] end else @hash[index] end else range = convert_range(index_or_range) range.begin > @count ? nil : range.map { |n| @hash[n] } end end # @return [Integer] Amount of objects in the array def size @count end alias count size alias length size def empty? size == 0 end def each ((@count - size)...@count).each do |n| yield @hash[n] end end def to_a ((@count - size)...@count).map { |n| @hash[n] } end # Returns [Hash] copy of the internal @hash history def to_h @hash.dup end def pop! @hash.delete @count - 1 @count -= 1 end def inspect "#<#{self.class} size=#{size} first=#{@count - size} max_size=#{max_size}>" end # @return [Integer] Maximum amount of objects in the array attr_reader :max_size private def convert_index(n) n >= 0 ? n : @count + n end def convert_range(range) end_index = convert_index(range.end) end_index += 1 unless range.exclude_end? Range.new(convert_index(range.begin), [end_index, @count].min, true) end end end pry-0.10.3/lib/pry/hooks.rb000066400000000000000000000171241260757071700154560ustar00rootroot00000000000000class Pry # Implements a hooks system for Pry. A hook is a callable that is # associated with an event. A number of events are currently # provided by Pry, these include: `:when_started`, `:before_session`, `:after_session`. # A hook must have a name, and is connected with an event by the # `Pry::Hooks#add_hook` method. # @example Adding a hook for the `:before_session` event. # Pry.config.hooks.add_hook(:before_session, :say_hi) do # puts "hello" # end class Hooks # Converts a hash to a `Pry::Hooks` instance. All hooks defined # this way are anonymous. This functionality is primarily to # provide backwards-compatibility with the old hash-based hook # system in Pry versions < 0.9.8 # @param [Hash] hash The hash to convert to `Pry::Hooks`. # @return [Pry::Hooks] The resulting `Pry::Hooks` instance. def self.from_hash(hash) return hash if hash.instance_of?(self) instance = new hash.each do |k, v| instance.add_hook(k, nil, v) end instance end def initialize @hooks = {} end # Ensure that duplicates have their @hooks object def initialize_copy(orig) hooks_dup = @hooks.dup @hooks.each do |k, v| hooks_dup[k] = v.dup end @hooks = hooks_dup end def hooks @hooks end protected :hooks def errors @errors ||= [] end # Destructively merge the contents of two `Pry:Hooks` instances. # @param [Pry::Hooks] other The `Pry::Hooks` instance to merge # @return [Pry:Hooks] Returns the receiver. # @example # hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" } # Pry::Hooks.new.merge!(hooks) def merge!(other) @hooks.merge!(other.dup.hooks) do |key, v1, v2| merge_arrays(v1, v2) end self end def merge_arrays(array1, array2) uniq_keeping_last(array1 + array2, &:first) end private :merge_arrays def uniq_keeping_last(input, &block) hash, output = {}, [] input.reverse.each{ |i| hash[block[i]] ||= (output.unshift i) } output end private :uniq_keeping_last # Return a new `Pry::Hooks` instance containing a merge of the contents of two `Pry:Hooks` instances, # @param [Pry::Hooks] other The `Pry::Hooks` instance to merge # @return [Pry::Hooks] The new hash. # @example # hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" } # Pry::Hooks.new.merge(hooks) def merge(other) self.dup.tap do |v| v.merge!(other) end end # Add a new hook to be executed for the `name` even. # @param [Symbol] event_name The name of the event. # @param [Symbol] hook_name The name of the hook. # @param [#call] callable The callable. # @yield The block to use as the callable (if `callable` parameter not provided) # @return [Pry:Hooks] Returns the receiver. # @example # Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" } def add_hook(event_name, hook_name, callable=nil, &block) @hooks[event_name] ||= [] # do not allow duplicates, but allow multiple `nil` hooks # (anonymous hooks) if hook_exists?(event_name, hook_name) && !hook_name.nil? raise ArgumentError, "Hook with name '#{hook_name}' already defined!" end if !block && !callable raise ArgumentError, "Must provide a block or callable." end # ensure we only have one anonymous hook @hooks[event_name].delete_if { |h, k| h.nil? } if hook_name.nil? if block @hooks[event_name] << [hook_name, block] elsif callable @hooks[event_name] << [hook_name, callable] end self end # Execute the list of hooks for the `event_name` event. # @param [Symbol] event_name The name of the event. # @param [Array] args The arguments to pass to each hook function. # @return [Object] The return value of the last executed hook. # @example # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" } # my_hooks.exec_hook(:before_session) #=> OUTPUT: "hi!" def exec_hook(event_name, *args, &block) @hooks[event_name] ||= [] @hooks[event_name].map do |hook_name, callable| begin callable.call(*args, &block) rescue RescuableException => e errors << e e end end.last end # Return the number of hook functions registered for the `event_name` event. # @param [Symbol] event_name The name of the event. # @return [Fixnum] The number of hook functions for `event_name`. # @example # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" } # my_hooks.count(:before_session) #=> 1 def hook_count(event_name) @hooks[event_name] ||= [] @hooks[event_name].size end # Return a specific hook for a given event. # @param [Symbol] event_name The name of the event. # @param [Symbol] hook_name The name of the hook # @return [#call] The requested hook. # @example # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" } # my_hooks.get_hook(:before_session, :say_hi).call #=> "hi!" def get_hook(event_name, hook_name) @hooks[event_name] ||= [] hook = @hooks[event_name].find { |current_hook_name, callable| current_hook_name == hook_name } hook.last if hook end # Return the hash of hook names / hook functions for a # given event. (Note that modifying the returned hash does not # alter the hooks, use add_hook/delete_hook for that). # @param [Symbol] event_name The name of the event. # @return [Hash] The hash of hook names / hook functions. # @example # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" } # my_hooks.get_hooks(:before_session) #=> {:say_hi=>#} def get_hooks(event_name) @hooks[event_name] ||= [] Hash[@hooks[event_name]] end # Delete a hook for an event. # @param [Symbol] event_name The name of the event. # @param [Symbol] hook_name The name of the hook. # to delete. # @return [#call] The deleted hook. # @example # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" } # my_hooks.delete_hook(:before_session, :say_hi) def delete_hook(event_name, hook_name) @hooks[event_name] ||= [] deleted_callable = nil @hooks[event_name].delete_if do |current_hook_name, callable| if current_hook_name == hook_name deleted_callable = callable true else false end end deleted_callable end # Clear all hooks functions for a given event. # @param [String] event_name The name of the event. # @example # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" } # my_hooks.delete_hook(:before_session) def delete_hooks(event_name) @hooks[event_name] = [] end alias_method :clear, :delete_hooks # Remove all events and hooks, clearing out the Pry::Hooks # instance completely. # @example # my_hooks = Pry::Hooks.new.add_hook(:before_session, :say_hi) { puts "hi!" } # my_hooks.clear_all def clear_all @hooks = {} end # @param [Symbol] event_name Name of the event. # @param [Symbol] hook_name Name of the hook. # @return [Boolean] Whether the hook by the name `hook_name` def hook_exists?(event_name, hook_name) !!(@hooks[event_name] && @hooks[event_name].find { |name, _| name == hook_name }) end end end pry-0.10.3/lib/pry/indent.rb000066400000000000000000000330351260757071700156130ustar00rootroot00000000000000require 'coderay' class Pry ## # Pry::Indent is a class that can be used to indent a number of lines # containing Ruby code similar as to how IRB does it (but better). The class # works by tokenizing a string using CodeRay and then looping over those # tokens. Based on the tokens in a line of code that line (or the next one) # will be indented or un-indented by correctly. # class Indent include Helpers::BaseHelpers # Raised if {#module_nesting} would not work. class UnparseableNestingError < StandardError; end # @return [String] String containing the spaces to be inserted before the next line. attr_reader :indent_level # @return [Array] The stack of open tokens. attr_reader :stack # The amount of spaces to insert for each indent level. SPACES = ' ' # Hash containing all the tokens that should increase the indentation # level. The keys of this hash are open tokens, the values the matching # tokens that should prevent a line from being indented if they appear on # the same line. OPEN_TOKENS = { 'def' => 'end', 'class' => 'end', 'module' => 'end', 'do' => 'end', 'if' => 'end', 'unless' => 'end', 'while' => 'end', 'until' => 'end', 'for' => 'end', 'case' => 'end', 'begin' => 'end', '[' => ']', '{' => '}', '(' => ')' } # Which tokens can either be open tokens, or appear as modifiers on # a single-line. SINGLELINE_TOKENS = %w(if while until unless rescue) # Which tokens can be followed by an optional "do" keyword. OPTIONAL_DO_TOKENS = %w(for while until) # Collection of token types that should be ignored. Without this list # keywords such as "class" inside strings would cause the code to be # indented incorrectly. # # :pre_constant and :preserved_constant are the CodeRay 0.9.8 and 1.0.0 # classifications of "true", "false", and "nil". IGNORE_TOKENS = [:space, :content, :string, :method, :ident, :constant, :pre_constant, :predefined_constant] # Tokens that indicate the end of a statement (i.e. that, if they appear # directly before an "if" indicates that that if applies to the same line, # not the next line) # # :reserved and :keywords are the CodeRay 0.9.8 and 1.0.0 respectively # classifications of "super", "next", "return", etc. STATEMENT_END_TOKENS = IGNORE_TOKENS + [:regexp, :integer, :float, :keyword, :delimiter, :reserved] # Collection of tokens that should appear dedented even though they # don't affect the surrounding code. MIDWAY_TOKENS = %w(when else elsif ensure rescue) # Clean the indentation of a fragment of ruby. # # @param [String] str # @return [String] def self.indent(str) new.indent(str) end # Get the module nesting at the given point in the given string. # # NOTE If the line specified contains a method definition, then the nesting # at the start of the method definition is used. Otherwise the nesting from # the end of the line is used. # # @param [String] str The ruby code to analyze # @param [Fixnum] line_number The line number (starting from 1) # @return [Array] def self.nesting_at(str, line_number) indent = new lines = str.split("\n") n = line_number - 1 to_indent = lines[0...n] << (lines[n] || "").split("def").first(1) indent.indent(to_indent.join("\n") << "\n") indent.module_nesting end def initialize reset end # reset internal state def reset @stack = [] @indent_level = '' @heredoc_queue = [] @close_heredocs = {} @string_start = nil @awaiting_class = false @module_nesting = [] self end # Indents a string and returns it. This string can either be a single line # or multiple ones. # # @example # str = <] def module_nesting @module_nesting.map do |(kind, token)| raise UnparseableNestingError, @module_nesting.inspect if token.nil? "#{kind} #{token}" end end # Return a string which, when printed, will rewrite the previous line with # the correct indentation. Mostly useful for fixing 'end'. # # @param [String] prompt The user's prompt # @param [String] code The code the user just typed in. # @param [Fixnum] overhang (0) The number of chars to erase afterwards (i.e., # the difference in length between the old line and the new one). # @return [String] def correct_indentation(prompt, code, overhang=0) prompt = prompt.delete("\001\002") line_to_measure = Pry::Helpers::Text.strip_color(prompt) << code whitespace = ' ' * overhang _, cols = Terminal.screen_size cols = cols.to_i lines = (cols != 0 ? (line_to_measure.length / cols + 1) : 1).to_i if Pry::Helpers::BaseHelpers.windows_ansi? move_up = "\e[#{lines}F" move_down = "\e[#{lines}E" else move_up = "\e[#{lines}A\e[0G" move_down = "\e[#{lines}B\e[0G" end "#{move_up}#{prompt}#{colorize_code(code)}#{whitespace}#{move_down}" end end end pry-0.10.3/lib/pry/input_completer.rb000066400000000000000000000216361260757071700175470ustar00rootroot00000000000000# taken from irb # Implements tab completion for Readline in Pry class Pry::InputCompleter NUMERIC_REGEXP = /^(-?(0[dbo])?[0-9_]+(\.[0-9_]+)?([eE]-?[0-9]+)?)\.([^.]*)$/ ARRAY_REGEXP = /^([^\]]*\])\.([^.]*)$/ SYMBOL_REGEXP = /^(:[^:.]*)$/ SYMBOL_METHOD_CALL_REGEXP = /^(:[^:.]+)\.([^.]*)$/ REGEX_REGEXP = /^(\/[^\/]*\/)\.([^.]*)$/ PROC_OR_HASH_REGEXP = /^([^\}]*\})\.([^.]*)$/ TOPLEVEL_LOOKUP_REGEXP = /^::([A-Z][^:\.\(]*)$/ CONSTANT_REGEXP = /^([A-Z][A-Za-z0-9]*)$/ CONSTANT_OR_METHOD_REGEXP = /^([A-Z].*)::([^:.]*)$/ HEX_REGEXP = /^(-?0x[0-9a-fA-F_]+)\.([^.]*)$/ GLOBALVARIABLE_REGEXP = /^(\$[^.]*)$/ VARIABLE_REGEXP = /^([^."].*)\.([^.]*)$/ ReservedWords = [ "BEGIN", "END", "alias", "and", "begin", "break", "case", "class", "def", "defined", "do", "else", "elsif", "end", "ensure", "false", "for", "if", "in", "module", "next", "nil", "not", "or", "redo", "rescue", "retry", "return", "self", "super", "then", "true", "undef", "unless", "until", "when", "while", "yield" ] Operators = [ "%", "&", "*", "**", "+", "-", "/", "<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>", "[]", "[]=", "^", "!", "!=", "!~" ] WORD_ESCAPE_STR = " \t\n\"\\'`><=;|&{(" def initialize(input, pry = nil) @pry = pry @input = input @input.basic_word_break_characters = WORD_ESCAPE_STR if @input.respond_to?(:basic_word_break_characters=) @input.completion_append_character = nil if @input.respond_to?(:completion_append_character=) end # # Return a new completion proc for use by Readline. # def call(str, options = {}) custom_completions = options[:custom_completions] || [] # if there are multiple contexts e.g. cd 1/2/3 # get new target for 1/2 and find candidates for 3 path, input = build_path(str) if path.call.empty? target = options[:target] else # Assume the user is tab-completing the 'cd' command begin target = Pry::ObjectPath.new(path.call, @pry.binding_stack).resolve.last # but if that doesn't work, assume they're doing division with no spaces rescue Pry::CommandError target = options[:target] end end begin bind = target # Complete stdlib symbols case input when REGEX_REGEXP # Regexp receiver = $1 message = Regexp.quote($2) candidates = Regexp.instance_methods.collect(&:to_s) select_message(path, receiver, message, candidates) when ARRAY_REGEXP # Array receiver = $1 message = Regexp.quote($2) candidates = Array.instance_methods.collect(&:to_s) select_message(path, receiver, message, candidates) when PROC_OR_HASH_REGEXP # Proc or Hash receiver = $1 message = Regexp.quote($2) candidates = Proc.instance_methods.collect(&:to_s) candidates |= Hash.instance_methods.collect(&:to_s) select_message(path, receiver, message, candidates) when SYMBOL_REGEXP # Symbol if Symbol.respond_to?(:all_symbols) sym = Regexp.quote($1) candidates = Symbol.all_symbols.collect{|s| ":" << s.id2name} candidates.grep(/^#{sym}/) else [] end when TOPLEVEL_LOOKUP_REGEXP # Absolute Constant or class methods receiver = $1 candidates = Object.constants.collect(&:to_s) candidates.grep(/^#{receiver}/).collect{|e| "::" << e} when CONSTANT_REGEXP # Constant message = $1 begin context = target.eval("self") context = context.class unless context.respond_to? :constants candidates = context.constants.collect(&:to_s) rescue candidates = [] end candidates = candidates.grep(/^#{message}/).collect(&path) when CONSTANT_OR_METHOD_REGEXP # Constant or class methods receiver = $1 message = Regexp.quote($2) begin candidates = eval("#{receiver}.constants.collect(&:to_s)", bind) candidates |= eval("#{receiver}.methods.collect(&:to_s)", bind) rescue Pry::RescuableException candidates = [] end candidates.grep(/^#{message}/).collect{|e| receiver + "::" + e} when SYMBOL_METHOD_CALL_REGEXP # method call on a Symbol receiver = $1 message = Regexp.quote($2) candidates = Symbol.instance_methods.collect(&:to_s) select_message(path, receiver, message, candidates) when NUMERIC_REGEXP # Numeric receiver = $1 message = Regexp.quote($5) begin candidates = eval(receiver, bind).methods.collect(&:to_s) rescue Pry::RescuableException candidates = [] end select_message(path, receiver, message, candidates) when HEX_REGEXP # Numeric(0xFFFF) receiver = $1 message = Regexp.quote($2) begin candidates = eval(receiver, bind).methods.collect(&:to_s) rescue Pry::RescuableException candidates = [] end select_message(path, receiver, message, candidates) when GLOBALVARIABLE_REGEXP # global regmessage = Regexp.new(Regexp.quote($1)) candidates = global_variables.collect(&:to_s).grep(regmessage) when VARIABLE_REGEXP # variable receiver = $1 message = Regexp.quote($2) gv = eval("global_variables", bind).collect(&:to_s) lv = eval("local_variables", bind).collect(&:to_s) cv = eval("self.class.constants", bind).collect(&:to_s) if (gv | lv | cv).include?(receiver) or /^[A-Z]/ =~ receiver && /\./ !~ receiver # foo.func and foo is local var. OR # Foo::Bar.func begin candidates = eval("#{receiver}.methods", bind).collect(&:to_s) rescue Pry::RescuableException candidates = [] end else # func1.func2 candidates = [] ObjectSpace.each_object(Module){|m| begin name = m.name.to_s rescue Pry::RescuableException name = "" end next if name != "IRB::Context" and /^(IRB|SLex|RubyLex|RubyToken)/ =~ name # jruby doesn't always provide #instance_methods() on each # object. if m.respond_to?(:instance_methods) candidates.concat m.instance_methods(false).collect(&:to_s) end } candidates.sort! candidates.uniq! end select_message(path, receiver, message, candidates) when /^\.([^.]*)$/ # Unknown(maybe String) receiver = "" message = Regexp.quote($1) candidates = String.instance_methods(true).collect(&:to_s) select_message(path, receiver, message, candidates) else candidates = eval( "methods | private_methods | local_variables | " \ "self.class.constants | instance_variables", bind ).collect(&:to_s) if eval("respond_to?(:class_variables)", bind) candidates += eval("class_variables", bind).collect(&:to_s) end candidates = (candidates|ReservedWords|custom_completions).grep(/^#{Regexp.quote(input)}/) candidates.collect(&path) end rescue Pry::RescuableException [] end end def select_message(path, receiver, message, candidates) candidates.grep(/^#{message}/).collect { |e| case e when /^[a-zA-Z_]/ path.call(receiver + "." << e) when /^[0-9]/ when *Operators #receiver + " " << e end }.compact end # build_path seperates the input into two parts: path and input. # input is the partial string that should be completed # path is a proc that takes an input and builds a full path. def build_path(input) # check to see if the input is a regex return proc {|i| i.to_s }, input if input[/\/\./] trailing_slash = input.end_with?('/') contexts = input.chomp('/').split(/\//) input = contexts[-1] path = proc do |i| p = contexts[0..-2].push(i).join('/') p += '/' if trailing_slash && !i.nil? p end return path, input end end pry-0.10.3/lib/pry/input_lock.rb000066400000000000000000000115771260757071700165100ustar00rootroot00000000000000require 'thread' class Pry # There is one InputLock per input (such as STDIN) as two REPLs on the same # input makes things delirious. InputLock serializes accesses to the input so # that threads to not conflict with each other. The latest thread to request # ownership of the input wins. class InputLock class Interrupt < Exception; end class << self attr_accessor :input_locks attr_accessor :global_lock end self.input_locks = {} self.global_lock = Mutex.new def self.for(input) # XXX This method leaks memory, as we never unregister an input once we # are done with it. Fortunately, the leak is tiny (or so we hope). In # usual scenarios, we would leak the StringIO that is passed to be # evaluated from the command line. global_lock.synchronize do input_locks[input] ||= Pry::InputLock.new end end def initialize @mutex = Mutex.new @cond = ConditionVariable.new @owners = [] @interruptible = false end # Adds ourselves to the ownership list. The last one in the list may access # the input through interruptible_region(). def __with_ownership(&block) @mutex.synchronize do # Three cases: # 1) There are no owners, in this case we are good to go. # 2) The current owner of the input is not reading the input (it might # just be evaluating some ruby that the user typed). # The current owner will figure out that it cannot go back to reading # the input since we are adding ourselves to the @owners list, which # in turns makes us the current owner. # 3) The owner of the input is in the interruptible region, reading from # the input. It's safe to send an Interrupt exception to interrupt # the owner. It will then proceed like in case 2). # We wait until the owner sets the interruptible flag back # to false, meaning that he's out of the interruptible region. # Note that the owner may receive multiple interrupts since, but that # should be okay (and trying to avoid it is futile anyway). while @interruptible @owners.last.raise Interrupt @cond.wait(@mutex) end @owners << Thread.current end block.call ensure @mutex.synchronize do # We are releasing any desire to have the input ownership by removing # ourselves from the list. @owners.delete(Thread.current) # We need to wake up the thread at the end of the @owners list, but # sadly Ruby doesn't allow us to choose which one we wake up, so we wake # them all up. @cond.broadcast end end def with_ownership(&block) # If we are in a nested with_ownership() call (nested pry context), we do nothing. nested = @mutex.synchronize { @owners.include?(Thread.current) } nested ? block.call : __with_ownership(&block) end def enter_interruptible_region @mutex.synchronize do # We patiently wait until we are the owner. This may happen as another # thread calls with_ownership() because of a binding.pry happening in # another thread. @cond.wait(@mutex) until @owners.last == Thread.current # We are the legitimate owner of the input. We mark ourselves as # interruptible, so other threads can send us an Interrupt exception # while we are blocking from reading the input. @interruptible = true end end def leave_interruptible_region @mutex.synchronize do # We check if we are still the owner, because we could have received an # Interrupt right after the following @cond.broadcast, making us retry. @interruptible = false if @owners.last == Thread.current @cond.broadcast end rescue Interrupt # We need to guard against a spurious interrupt delivered while we are # trying to acquire the lock (the rescue block is no longer in our scope). retry end def interruptible_region(&block) enter_interruptible_region # XXX Note that there is a chance that we get the interrupt right after # the readline call succeeded, but we'll never know, and we will retry the # call, discarding that piece of input. block.call rescue Interrupt # We were asked to back off. The one requesting the interrupt will be # waiting on the conditional for the interruptible flag to change to false. # Note that there can be some inefficiency, as we could immediately # succeed in enter_interruptible_region(), even before the one requesting # the ownership has the chance to register itself as an owner. # To mitigate the issue, we sleep a little bit. leave_interruptible_region sleep 0.01 retry ensure leave_interruptible_region end end end pry-0.10.3/lib/pry/inspector.rb000066400000000000000000000015111260757071700163320ustar00rootroot00000000000000class Pry::Inspector MAP = { "default" => { value: Pry::DEFAULT_PRINT, description: <<-DESCRIPTION.each_line.map(&:lstrip!) The default Pry inspector. It has paging and color support, and uses pretty_inspect when printing an object. DESCRIPTION }, "simple" => { value: Pry::SIMPLE_PRINT, description: <<-DESCRIPTION.each_line.map(&:lstrip) A simple inspector that uses #puts and #inspect when printing an object. It has no pager, color, or pretty_inspect support. DESCRIPTION }, "clipped" => { value: Pry::CLIPPED_PRINT, description: <<-DESCRIPTION.each_line.map(&:lstrip) The clipped inspector has the same features as the 'simple' inspector but prints large objects as a smaller string. DESCRIPTION } } end pry-0.10.3/lib/pry/last_exception.rb000066400000000000000000000023251260757071700173510ustar00rootroot00000000000000# # {Pry::LastException} is a proxy class who wraps an Exception object for # {Pry#last_exception}. it extends the exception object with methods that # help pry commands be useful. # # the original exception object is not modified and method calls are forwarded # to the wrapped exception object. # class Pry::LastException < BasicObject attr_accessor :bt_index def initialize(e) @e = e @bt_index = 0 @file, @line = bt_source_location_for(0) end def method_missing(name, *args, &block) if @e.respond_to?(name) @e.public_send(name, *args, &block) else super end end def respond_to_missing?(name, include_private = false) @e.respond_to?(name) end # # @return [String] # returns the path to a file for the current backtrace. see {#bt_index}. # def file @file end # # @return [Fixnum] # returns the line for the current backtrace. see {#bt_index}. # def line @line end # @return [Exception] # returns the wrapped exception # def wrapped_exception @e end def bt_source_location_for(index) backtrace[index] =~ /(.*):(\d+)/ [$1, $2.to_i] end def inc_bt_index @bt_index = (@bt_index + 1) % backtrace.size end end pry-0.10.3/lib/pry/method.rb000066400000000000000000000447641260757071700156250ustar00rootroot00000000000000require 'pry/helpers/documentation_helpers' class Pry class << self # If the given object is a `Pry::Method`, return it unaltered. If it's # anything else, return it wrapped in a `Pry::Method` instance. def Method(obj) if obj.is_a? Pry::Method obj else Pry::Method.new(obj) end end end # This class wraps the normal `Method` and `UnboundMethod` classes # to provide extra functionality useful to Pry. class Method require 'pry/method/weird_method_locator' require 'pry/method/disowned' require 'pry/method/patcher' extend Helpers::BaseHelpers include Helpers::BaseHelpers include Helpers::DocumentationHelpers include CodeObject::Helpers class << self # Given a string representing a method name and optionally a binding to # search in, find and return the requested method wrapped in a `Pry::Method` # instance. # # @param [String] name The name of the method to retrieve. # @param [Binding] target The context in which to search for the method. # @param [Hash] options # @option options [Boolean] :instance Look for an instance method if `name` doesn't # contain any context. # @option options [Boolean] :methods Look for a bound/singleton method if `name` doesn't # contain any context. # @return [Pry::Method, nil] A `Pry::Method` instance containing the requested # method, or `nil` if name is `nil` or no method could be located matching the parameters. def from_str(name, target=TOPLEVEL_BINDING, options={}) if name.nil? nil elsif name.to_s =~ /(.+)\#(\S+)\Z/ context, meth_name = $1, $2 from_module(target.eval(context), meth_name, target) elsif name.to_s =~ /(.+)(\[\])\Z/ context, meth_name = $1, $2 from_obj(target.eval(context), meth_name, target) elsif name.to_s =~ /(.+)(\.|::)(\S+)\Z/ context, meth_name = $1, $3 from_obj(target.eval(context), meth_name, target) elsif options[:instance] from_module(target.eval("self"), name, target) elsif options[:methods] from_obj(target.eval("self"), name, target) else from_str(name, target, :instance => true) or from_str(name, target, :methods => true) end rescue Pry::RescuableException nil end # Given a `Binding`, try to extract the `::Method` it originated from and # use it to instantiate a `Pry::Method`. Return `nil` if this isn't # possible. # # @param [Binding] b # @return [Pry::Method, nil] # def from_binding(b) meth_name = b.eval('::Kernel.__method__') if [:__script__, nil].include?(meth_name) nil else method = begin if Object === b.eval('self') new(Kernel.instance_method(:method).bind(b.eval("self")).call(meth_name)) else new(b.eval('class << self; self; end.instance_method(::Kernel.__method__).bind(self)')) end rescue NameError, NoMethodError Disowned.new(b.eval('self'), meth_name.to_s) end if WeirdMethodLocator.weird_method?(method, b) WeirdMethodLocator.new(method, b).get_method || method else method end end end # In order to support 2.0 Refinements we need to look up methods # inside the relevant Binding. # @param [Object] obj The owner/receiver of the method. # @param [Symbol] method_name The name of the method. # @param [Symbol] method_type The type of method: :method or :instance_method # @param [Binding] target The binding where the method is looked up. # @return [Method, UnboundMethod] The 'refined' method object. def lookup_method_via_binding(obj, method_name, method_type, target=TOPLEVEL_BINDING) Pry.current[:obj] = obj Pry.current[:name] = method_name receiver = obj.is_a?(Module) ? "Module" : "Kernel" target.eval("::#{receiver}.instance_method(:#{method_type}).bind(Pry.current[:obj]).call(Pry.current[:name])") ensure Pry.current[:obj] = Pry.current[:name] = nil end # Given a `Class` or `Module` and the name of a method, try to # instantiate a `Pry::Method` containing the instance method of # that name. Return `nil` if no such method exists. # # @param [Class, Module] klass # @param [String] name # @param [Binding] target The binding where the method is looked up. # @return [Pry::Method, nil] def from_class(klass, name, target=TOPLEVEL_BINDING) new(lookup_method_via_binding(klass, name, :instance_method, target)) rescue nil end alias from_module from_class # Given an object and the name of a method, try to instantiate # a `Pry::Method` containing the method of that name bound to # that object. Return `nil` if no such method exists. # # @param [Object] obj # @param [String] name # @param [Binding] target The binding where the method is looked up. # @return [Pry::Method, nil] def from_obj(obj, name, target=TOPLEVEL_BINDING) new(lookup_method_via_binding(obj, name, :method, target)) rescue nil end # Get all of the instance methods of a `Class` or `Module` # @param [Class,Module] klass # @param [Boolean] include_super Whether to include methods from ancestors. # @return [Array[Pry::Method]] def all_from_class(klass, include_super=true) %w(public protected private).map do |visibility| safe_send(klass, :"#{visibility}_instance_methods", include_super).map do |method_name| new(safe_send(klass, :instance_method, method_name), :visibility => visibility.to_sym) end end.flatten(1) end # # Get all of the methods on an `Object` # # @param [Object] obj # # @param [Boolean] include_super # indicates whether or not to include methods from ancestors. # # @return [Array[Pry::Method]] # def all_from_obj(obj, include_super=true) all_from_class(singleton_class_of(obj), include_super) end # # @deprecated # please use {#all_from_obj} instead. # the `method_type` argument is ignored. # def all_from_common(obj, method_type = nil, include_super=true) all_from_obj(obj, include_super) end # Get every `Class` and `Module`, in order, that will be checked when looking # for an instance method to call on this object. # @param [Object] obj # @return [Array[Class, Module]] def resolution_order(obj) if Class === obj singleton_class_resolution_order(obj) + instance_resolution_order(Class) else klass = singleton_class_of(obj) rescue obj.class instance_resolution_order(klass) end end # Get every `Class` and `Module`, in order, that will be checked when looking # for methods on instances of the given `Class` or `Module`. # This does not treat singleton classes of classes specially. # @param [Class, Module] klass # @return [Array[Class, Module]] def instance_resolution_order(klass) # include klass in case it is a singleton class, ([klass] + Pry::Method.safe_send(klass, :ancestors)).uniq end def method_definition?(name, definition_line) singleton_method_definition?(name, definition_line) || instance_method_definition?(name, definition_line) end def singleton_method_definition?(name, definition_line) /^define_singleton_method\(?\s*[:\"\']#{Regexp.escape(name)}|^def\s*self\.#{Regexp.escape(name)}/ =~ definition_line.strip end def instance_method_definition?(name, definition_line) /^define_method\(?\s*[:\"\']#{Regexp.escape(name)}|^def\s*#{Regexp.escape(name)}/ =~ definition_line.strip end # Get the singleton classes of superclasses that could define methods on # the given class object, and any modules they include. # If a module is included at multiple points in the ancestry, only # the lowest copy will be returned. def singleton_class_resolution_order(klass) ancestors = Pry::Method.safe_send(klass, :ancestors) resolution_order = ancestors.grep(Class).map do |anc| [singleton_class_of(anc), *singleton_class_of(anc).included_modules] end.flatten(1) resolution_order.reverse.uniq.reverse - Class.included_modules end def singleton_class_of(obj) begin class << obj; self; end rescue TypeError # can't define singleton. Fixnum, Symbol, Float, ... obj.class end end end # A new instance of `Pry::Method` wrapping the given `::Method`, `UnboundMethod`, or `Proc`. # # @param [::Method, UnboundMethod, Proc] method # @param [Hash] known_info Can be used to pre-cache expensive to compute stuff. # @return [Pry::Method] def initialize(method, known_info={}) @method = method @visibility = known_info[:visibility] end # Get the name of the method as a String, regardless of the underlying Method#name type. # @return [String] def name @method.name.to_s end # Get the owner of the method as a Pry::Module # @return [Pry::Module] def wrapped_owner @wrapped_owner ||= Pry::WrappedModule.new(owner) end # Get underlying object wrapped by this Pry::Method instance # @return [Method, UnboundMethod, Proc] def wrapped @method end # Is the method undefined? (aka `Disowned`) # @return [Boolean] false def undefined? false end # Get the name of the method including the class on which it was defined. # @example # method(:puts).method_name # => "Kernel.puts" # @return [String] def name_with_owner "#{wrapped_owner.method_prefix}#{name}" end # @return [String, nil] The source code of the method, or `nil` if it's unavailable. def source @source ||= case source_type when :c c_source when :ruby ruby_source end end # Update the live copy of the method's source. def redefine(source) Patcher.new(self).patch_in_ram source Pry::Method(owner.instance_method(name)) end # Can we get the source code for this method? # @return [Boolean] def source? !!source rescue MethodSource::SourceNotFoundError false end # @return [String, nil] The documentation for the method, or `nil` if it's # unavailable. def doc @doc ||= case source_type when :c info = pry_doc_info info.docstring if info when :ruby get_comment_content(comment) end end # @return [Symbol] The source type of the method. The options are # `:ruby` for Ruby methods or `:c` for methods written in C. def source_type source_location.nil? ? :c : :ruby end # @return [String, nil] The name of the file the method is defined in, or # `nil` if the filename is unavailable. def source_file if source_location.nil? if !rbx? and source_type == :c info = pry_doc_info info.file if info end else source_location.first end end # @return [Fixnum, nil] The line of code in `source_file` which begins # the method's definition, or `nil` if that information is unavailable. def source_line source_location.nil? ? nil : source_location.last end # @return [Range, nil] The range of lines in `source_file` which contain # the method's definition, or `nil` if that information is unavailable. def source_range source_location.nil? ? nil : (source_line)..(source_line + source.lines.count - 1) end # @return [Symbol] The visibility of the method. May be `:public`, # `:protected`, or `:private`. def visibility @visibility ||= if owner.public_instance_methods.any? { |m| m.to_s == name } :public elsif owner.protected_instance_methods.any? { |m| m.to_s == name } :protected elsif owner.private_instance_methods.any? { |m| m.to_s == name } :private else :none end end # @return [String] A representation of the method's signature, including its # name and parameters. Optional and "rest" parameters are marked with `*` # and block parameters with `&`. If the parameter names are unavailable, # they're given numbered names instead. # Paraphrased from `awesome_print` gem. def signature if respond_to?(:parameters) args = parameters.inject([]) do |arr, (type, name)| name ||= (type == :block ? 'block' : "arg#{arr.size + 1}") arr << case type when :req then name.to_s when :opt then "#{name}=?" when :rest then "*#{name}" when :block then "&#{name}" else '?' end end else args = (1..arity.abs).map { |i| "arg#{i}" } args[-1] = "*#{args[-1]}" if arity < 0 end "#{name}(#{args.join(', ')})" end # @return [Pry::Method, nil] The wrapped method that is called when you # use "super" in the body of this method. def super(times=1) if UnboundMethod === @method sup = super_using_ancestors(Pry::Method.instance_resolution_order(owner), times) else sup = super_using_ancestors(Pry::Method.resolution_order(receiver), times) sup &&= sup.bind(receiver) end Pry::Method.new(sup) if sup end # @return [String, nil] The original name the method was defined under, # before any aliasing, or `nil` if it can't be determined. def original_name return nil if source_type != :ruby method_name_from_first_line(source.lines.first) end # @return [Boolean] Was the method defined outside a source file? def dynamically_defined? !!(source_file and source_file =~ /(\(.*\))|<.*>/) end # @return [Boolean] Whether the method is unbound. def unbound_method? is_a?(::UnboundMethod) end # @return [Boolean] Whether the method is bound. def bound_method? is_a?(::Method) end # @return [Boolean] Whether the method is a singleton method. def singleton_method? wrapped_owner.singleton_class? end # @return [Boolean] Was the method defined within the Pry REPL? def pry_method? source_file == Pry.eval_path end # @return [Array] All known aliases for the method. def aliases owner = @method.owner # Avoid using `to_sym` on {Method#name}, which returns a `String`, because # it won't be garbage collected. name = @method.name all_methods_to_compare = owner.instance_methods | owner.private_instance_methods alias_list = all_methods_to_compare.combination(2).select do |pair| pair.include?(name) && owner.instance_method(pair.first) == owner.instance_method(pair.last) end.flatten alias_list.delete(name) alias_list.map(&:to_s) end # @return [Boolean] Is the method definitely an alias? def alias? name != original_name end # @return [Boolean] def ==(obj) if obj.is_a? Pry::Method obj == @method else @method == obj end end # @param [Class] klass # @return [Boolean] def is_a?(klass) klass == Pry::Method or @method.is_a?(klass) end alias kind_of? is_a? # @param [String, Symbol] method_name # @return [Boolean] def respond_to?(method_name) super or @method.respond_to?(method_name) end # Delegate any unknown calls to the wrapped method. def method_missing(method_name, *args, &block) @method.send(method_name, *args, &block) end def comment Pry::Code.from_file(source_file).comment_describing(source_line) end private # @return [YARD::CodeObjects::MethodObject] # @raise [CommandError] when the method can't be found or `pry-doc` isn't installed. def pry_doc_info if Pry.config.has_pry_doc Pry::MethodInfo.info_for(@method) or raise CommandError, "Cannot locate this method: #{name}. (source_location returns nil)" else fail_msg = "Cannot locate this method: #{name}." if mri? fail_msg += ' Try `gem-install pry-doc` to get access to Ruby Core documentation.' end raise CommandError, fail_msg end end # @param [Class, Module] ancestors The ancestors to investigate # @return [Method] The unwrapped super-method def super_using_ancestors(ancestors, times=1) next_owner = self.owner times.times do i = ancestors.index(next_owner) + 1 while ancestors[i] && !(ancestors[i].method_defined?(name) || ancestors[i].private_method_defined?(name)) i += 1 end next_owner = ancestors[i] or return nil end safe_send(next_owner, :instance_method, name) rescue nil end # @param [String] first_ln The first line of a method definition. # @return [String, nil] def method_name_from_first_line(first_ln) return nil if first_ln.strip !~ /^def / tokens = CodeRay.scan(first_ln, :ruby) tokens = tokens.tokens.each_slice(2) if tokens.respond_to?(:tokens) tokens.each_cons(2) do |t1, t2| if t2.last == :method || t2.last == :ident && t1 == [".", :operator] return t2.first end end nil end def c_source info = pry_doc_info if info and info.source strip_comments_from_c_code(info.source) end end def ruby_source # clone of MethodSource.source_helper that knows to use our # hacked version of source_location for rbx core methods, and # our input buffer for methods defined in (pry) file, line = *source_location raise SourceNotFoundError, "Could not locate source for #{name_with_owner}!" unless file begin code = Pry::Code.from_file(file).expression_at(line) rescue SyntaxError => e raise MethodSource::SourceNotFoundError.new(e.message) end strip_leading_whitespace(code) end end end pry-0.10.3/lib/pry/method/000077500000000000000000000000001260757071700152615ustar00rootroot00000000000000pry-0.10.3/lib/pry/method/disowned.rb000066400000000000000000000026661260757071700174340ustar00rootroot00000000000000class Pry class Method # A Disowned Method is one that's been removed from the class on which it was defined. # # e.g. # class C # def foo # C.send(:undefine_method, :foo) # Pry::Method.from_binding(binding) # end # end # # In this case we assume that the "owner" is the singleton class of the receiver. # # This occurs mainly in Sinatra applications. class Disowned < Method attr_reader :receiver, :name # Create a new Disowned method. # # @param [Object] receiver # @param [String] method_name def initialize(receiver, method_name, binding=nil) @receiver, @name = receiver, method_name end # Is the method undefined? (aka `Disowned`) # @return [Boolean] true def undefined? true end # Can we get the source for this method? # @return [Boolean] false def source? false end # Get the hypothesized owner of the method. # # @return [Object] def owner class << receiver; self; end end # Raise a more useful error message instead of trying to forward to nil. def method_missing(meth_name, *args, &block) raise "Cannot call '#{meth_name}' on an undef'd method." if method(:name).respond_to?(meth_name) Object.instance_method(:method_missing).bind(self).call(meth_name, *args, &block) end end end end pry-0.10.3/lib/pry/method/patcher.rb000066400000000000000000000103531260757071700172360ustar00rootroot00000000000000class Pry class Method class Patcher attr_accessor :method @@source_cache = {} def initialize(method) @method = method end def self.code_for(filename) @@source_cache[filename] end # perform the patch def patch_in_ram(source) if method.alias? with_method_transaction do redefine source end else redefine source end end private def redefine(source) @@source_cache[cache_key] = source TOPLEVEL_BINDING.eval wrap(source), cache_key end def cache_key "pry-redefined(0x#{method.owner.object_id.to_s(16)}##{method.name})" end # Run some code ensuring that at the end target#meth_name will not have changed. # # When we're redefining aliased methods we will overwrite the method at the # unaliased name (so that super continues to work). By wrapping that code in a # transation we make that not happen, which means that alias_method_chains, etc. # continue to work. # # @param [String] meth_name The method name before aliasing # @param [Module] target The owner of the method def with_method_transaction temp_name = "__pry_#{method.original_name}__" method = self.method method.owner.class_eval do alias_method temp_name, method.original_name yield alias_method method.name, method.original_name alias_method method.original_name, temp_name end ensure method.send(:remove_method, temp_name) rescue nil end # Update the definition line so that it can be eval'd directly on the Method's # owner instead of from the original context. # # In particular this takes `def self.foo` and turns it into `def foo` so that we # don't end up creating the method on the singleton class of the singleton class # by accident. # # This is necessarily done by String manipulation because we can't find out what # syntax is needed for the argument list by ruby-level introspection. # # @param [String] line The original definition line. e.g. def self.foo(bar, baz=1) # @return [String] The new definition line. e.g. def foo(bar, baz=1) def definition_for_owner(line) if line =~ /\Adef (?:.*?\.)?#{Regexp.escape(method.original_name)}(?=[\(\s;]|$)/ "def #{method.original_name}#{$'}" else raise CommandError, "Could not find original `def #{method.original_name}` line to patch." end end # Apply wrap_for_owner and wrap_for_nesting successively to `source` # @param [String] source # @return [String] The wrapped source. def wrap(source) wrap_for_nesting(wrap_for_owner(source)) end # Update the source code so that when it has the right owner when eval'd. # # This (combined with definition_for_owner) is backup for the case that # wrap_for_nesting fails, to ensure that the method will stil be defined in # the correct place. # # @param [String] source The source to wrap # @return [String] def wrap_for_owner(source) Pry.current[:pry_owner] = method.owner owner_source = definition_for_owner(source) visibility_fix = "#{method.visibility.to_s} #{method.name.to_sym.inspect}" "Pry.current[:pry_owner].class_eval do; #{owner_source}\n#{visibility_fix}\nend" end # Update the new source code to have the correct Module.nesting. # # This method uses syntactic analysis of the original source file to determine # the new nesting, so that we can tell the difference between: # # class A; def self.b; end; end # class << A; def b; end; end # # The resulting code should be evaluated in the TOPLEVEL_BINDING. # # @param [String] source The source to wrap. # @return [String] def wrap_for_nesting(source) nesting = Pry::Code.from_file(method.source_file).nesting_at(method.source_line) (nesting + [source] + nesting.map{ "end" } + [""]).join(";") rescue Pry::Indent::UnparseableNestingError source end end end end pry-0.10.3/lib/pry/method/weird_method_locator.rb000066400000000000000000000145261260757071700220130ustar00rootroot00000000000000class Pry class Method # This class is responsible for locating the *real* `Pry::Method` # object captured by a binding. # # Given a `Binding` from inside a method and a 'seed' Pry::Method object, # there are primarily two situations where the seed method doesn't match # the Binding: # 1. The Pry::Method is from a subclass 2. The Pry::Method represents a method of the same name # while the original was renamed to something else. For 1. we # search vertically up the inheritance chain, # and for 2. we search laterally along the object's method table. # # When we locate the method that matches the Binding we wrap it in # Pry::Method and return it, or return nil if we fail. class WeirdMethodLocator class << self # Whether the given method object matches the associated binding. # If the method object does not match the binding, then it's # most likely not the method captured by the binding, and we # must commence a search. # # @param [Pry::Method] method # @param [Binding] b # @return [Boolean] def normal_method?(method, b) method && (method.source_file && method.source_range rescue false) && File.expand_path(method.source_file) == File.expand_path(b.eval('__FILE__')) && method.source_range.include?(b.eval('__LINE__')) end def weird_method?(method, b) !normal_method?(method, b) end end attr_accessor :method attr_accessor :target # @param [Pry::Method] method The seed method. # @param [Binding] target The Binding that captures the method # we want to locate. def initialize(method, target) @method, @target = method, target end # @return [Pry::Method, nil] The Pry::Method that matches the # given binding. def get_method find_method_in_superclass || find_renamed_method end # @return [Boolean] Whether the Pry::Method is unrecoverable # This usually happens when the method captured by the Binding # has been subsequently deleted. def lost_method? !!(get_method.nil? && renamed_method_source_location) end private def normal_method?(method) self.class.normal_method?(method, target) end def target_self target.eval('self') end def target_file pry_file? ? target.eval('__FILE__') : File.expand_path(target.eval('__FILE__')) end def target_line target.eval('__LINE__') end def pry_file? Pry.eval_path == target.eval('__FILE__') end # it's possible in some cases that the method we find by this approach is a sub-method of # the one we're currently in, consider: # # class A; def b; binding.pry; end; end # class B < A; def b; super; end; end # # Given that we can normally find the source_range of methods, and that we know which # __FILE__ and __LINE__ the binding is at, we can hope to disambiguate these cases. # # This obviously won't work if the source is unavaiable for some reason, or if both # methods have the same __FILE__ and __LINE__, or if we're in rbx where b.eval('__LINE__') # is broken. # # @return [Pry::Method, nil] The Pry::Method representing the # superclass method. def find_method_in_superclass guess = method while guess # needs rescue if this is a Disowned method or a C method or something... # TODO: Fix up the exception handling so we don't need a bare rescue if normal_method?(guess) return guess elsif guess != guess.super guess = guess.super else break end end # Uhoh... none of the methods in the chain had the right __FILE__ and __LINE__ # This may be caused by rbx https://github.com/rubinius/rubinius/issues/953, # or other unknown circumstances (TODO: we should warn the user when this happens) nil end # This is the case where the name of a method has changed # (via alias_method) so we locate the Method object for the # renamed method. # # @return [Pry::Method, nil] The Pry::Method representing the # renamed method def find_renamed_method return if !valid_file?(target_file) alias_name = all_methods_for(target_self).find do |v| expanded_source_location(target_self.method(v).source_location) == renamed_method_source_location end alias_name && Pry::Method(target_self.method(alias_name)) end def expanded_source_location(sl) return if !sl if pry_file? sl else [File.expand_path(sl.first), sl.last] end end # Use static analysis to locate the start of the method definition. # We have the `__FILE__` and `__LINE__` from the binding and the # original name of the method so we search up until we find a # def/define_method, etc defining a method of the appropriate name. # # @return [Array] The `source_location` of the # renamed method def renamed_method_source_location return @original_method_source_location if defined?(@original_method_source_location) source_index = lines_for_file(target_file)[0..(target_line - 1)].rindex do |v| Pry::Method.method_definition?(method.name, v) end @original_method_source_location = source_index && [target_file, index_to_line_number(source_index)] end def index_to_line_number(index) # Pry.line_buffer is 0-indexed pry_file? ? index : index + 1 end def valid_file?(file) (File.exist?(file) && !File.directory?(file)) || Pry.eval_path == file end def lines_for_file(file) @lines_for_file ||= {} @lines_for_file[file] ||= if Pry.eval_path == file Pry.line_buffer else File.readlines(file) end end def all_methods_for(obj) obj.public_methods(false) + obj.private_methods(false) + obj.protected_methods(false) end end end end pry-0.10.3/lib/pry/module_candidate.rb000066400000000000000000000124101260757071700176050ustar00rootroot00000000000000require 'pry/helpers/documentation_helpers' require 'forwardable' class Pry class WrappedModule # This class represents a single candidate for a module/class definition. # It provides access to the source, documentation, line and file # for a monkeypatch (reopening) of a class/module. class Candidate include Pry::Helpers::DocumentationHelpers include Pry::CodeObject::Helpers extend Forwardable # @return [String] The file where the module definition is located. attr_reader :file alias_method :source_file, :file # @return [Fixnum] The line where the module definition is located. attr_reader :line alias_method :source_line, :line # Methods to delegate to associated `Pry::WrappedModule # instance`. private_delegates = [:lines_for_file, :method_candidates, :yard_docs?] public_delegates = [:wrapped, :module?, :class?, :name, :nonblank_name, :number_of_candidates] def_delegators :@wrapper, *(private_delegates + public_delegates) private(*private_delegates) public(*public_delegates) # @raise [Pry::CommandError] If `rank` is out of bounds. # @param [Pry::WrappedModule] wrapper The associated # `Pry::WrappedModule` instance that owns the candidates. # @param [Fixnum] rank The rank of the candidate to # retrieve. Passing 0 returns 'primary candidate' (the candidate with largest # number of methods), passing 1 retrieves candidate with # second largest number of methods, and so on, up to # `Pry::WrappedModule#number_of_candidates() - 1` def initialize(wrapper, rank) @wrapper = wrapper if number_of_candidates <= 0 raise CommandError, "Cannot find a definition for #{name} module!" elsif rank > (number_of_candidates - 1) raise CommandError, "No such module candidate. Allowed candidates range is from 0 to #{number_of_candidates - 1}" end @rank = rank @file, @line = source_location end # @raise [Pry::CommandError] If source code cannot be found. # @return [String] The source for the candidate, i.e the # complete module/class definition. def source return nil if file.nil? return @source if @source @source = strip_leading_whitespace(Pry::Code.from_file(file).expression_at(line, number_of_lines_in_first_chunk)) end # @raise [Pry::CommandError] If documentation cannot be found. # @return [String] The documentation for the candidate. def doc return nil if file.nil? return @doc if @doc @doc = get_comment_content(Pry::Code.from_file(file).comment_describing(line)) end # @return [Array, nil] A `[String, Fixnum]` pair representing the # source location (file and line) for the candidate or `nil` # if no source location found. def source_location return @source_location if @source_location file, line = first_method_source_location return nil if !file.is_a?(String) @source_location = [file, first_line_of_module_definition(file, line)] rescue Pry::RescuableException nil end private # Locate the first line of the module definition. # @param [String] file The file that contains the module # definition (somewhere). # @param [Fixnum] line The module definition should appear # before this line (if it exists). # @return [Fixnum] The line where the module is defined. This # line number is one-indexed. def first_line_of_module_definition(file, line) searchable_lines = lines_for_file(file)[0..(line - 2)] searchable_lines.rindex { |v| class_regexes.any? { |r| r =~ v } } + 1 end def class_regexes mod_type_string = wrapped.class.to_s.downcase [/^\s*#{mod_type_string}\s+(?:(?:\w*)::)*?#{wrapped.name.split(/::/).last}/, /^\s*(::)?#{wrapped.name.split(/::/).last}\s*?=\s*?#{wrapped.class}/, /^\s*(::)?#{wrapped.name.split(/::/).last}\.(class|instance)_eval/] end # This method is used by `Candidate#source_location` as a # starting point for the search for the candidate's definition. # @return [Array] The source location of the base method used to # calculate the source location of the candidate. def first_method_source_location @first_method_source_location ||= method_candidates[@rank].first.source_location end # @return [Array] The source location of the last method in this # candidate's module definition. def last_method_source_location @end_method_source_location ||= method_candidates[@rank].last.source_location end # Return the number of lines between the start of the class definition # and the start of the last method. We use this value so we can # quickly grab these lines from the file (without having to # check each intervening line for validity, which is expensive) speeding up source extraction. # @return [Fixum] Number of lines. def number_of_lines_in_first_chunk end_method_line = last_method_source_location.last end_method_line - line end end end end pry-0.10.3/lib/pry/object_path.rb000066400000000000000000000043601260757071700166130ustar00rootroot00000000000000class Pry # `ObjectPath` implements the resolution of "object paths", which are strings # that are similar to filesystem paths but meant for traversing Ruby objects. # Examples of valid object paths include: # # x # @foo/@bar # "string"/upcase # Pry/Method # # Object paths are mostly relevant in the context of the `cd` command. # @see https://github.com/pry/pry/wiki/State-navigation class ObjectPath SPECIAL_TERMS = ["", "::", ".", ".."] # @param [String] path_string The object path expressed as a string. # @param [Array] current_stack The current state of the binding # stack. def initialize(path_string, current_stack) @path_string = path_string @current_stack = current_stack end # @return [Array] a new stack resulting from applying the given # path to the current stack. def resolve scanner = StringScanner.new(@path_string.strip) stack = @current_stack.dup begin next_segment = "" loop do # Scan for as long as we don't see a slash next_segment << scanner.scan(/[^\/]*/) if complete?(next_segment) || scanner.eos? scanner.getch # consume the slash break else next_segment << scanner.getch # append the slash end end case next_segment.chomp when "" stack = [stack.first] when "::" stack.push(TOPLEVEL_BINDING) when "." next when ".." stack.pop unless stack.size == 1 else stack.push(Pry.binding_for(stack.last.eval(next_segment))) end rescue RescuableException => e return handle_failure(next_segment, e) end until scanner.eos? stack end private def complete?(segment) SPECIAL_TERMS.include?(segment) || Pry::Code.complete_expression?(segment) end def handle_failure(context, err) msg = [ "Bad object path: #{@path_string.inspect}", "Failed trying to resolve: #{context.inspect}", "Exception: #{err.inspect}" ].join("\n") raise CommandError.new(msg).tap { |e| e.set_backtrace err.backtrace } end end end pry-0.10.3/lib/pry/output.rb000066400000000000000000000016501260757071700156700ustar00rootroot00000000000000class Pry class Output attr_reader :_pry_ def initialize(_pry_) @_pry_ = _pry_ end def puts(*objs) return print "\n" if objs.empty? objs.each do |obj| if ary = Array.try_convert(obj) puts(*ary) else print "#{obj.to_s.chomp}\n" end end nil end def print(*objs) objs.each do |obj| _pry_.config.output.print decolorize_maybe(obj.to_s) end nil end alias << print alias write print # If _pry_.config.color is currently false, removes ansi escapes from the string. def decolorize_maybe(str) if _pry_.config.color str else Helpers::Text.strip_color str end end def method_missing(name, *args, &block) _pry_.config.output.send(name, *args, &block) end def respond_to_missing?(*a) _pry_.config.respond_to?(*a) end end end pry-0.10.3/lib/pry/pager.rb000066400000000000000000000133101260757071700154220ustar00rootroot00000000000000require 'pry/terminal' # A pager is an `IO`-like object that accepts text and either prints it # immediately, prints it one page at a time, or streams it to an external # program to print one page at a time. class Pry::Pager class StopPaging < StandardError end attr_reader :_pry_ def initialize(_pry_) @_pry_ = _pry_ end # Send the given text through the best available pager (if `Pry.config.pager` is # enabled). # If you want to send text through in chunks as you generate it, use `open` to # get a writable object instead. # @param [String] text A piece of text to run through a pager. # @param [IO] output (`$stdout`) An object to send output to. def page(text) open do |pager| pager << text end end # Yields a pager object (`NullPager`, `SimplePager`, or `SystemPager`). All # pagers accept output with `#puts`, `#print`, `#write`, and `#<<`. # @param [IO] output (`$stdout`) An object to send output to. def open pager = best_available yield pager rescue StopPaging ensure pager.close if pager end private def enabled?; !!@enabled; end def output; @output; end # Return an instance of the "best" available pager class -- `SystemPager` if # possible, `SimplePager` if `SystemPager` isn't available, and `NullPager` # if the user has disabled paging. All pagers accept output with `#puts`, # `#print`, `#write`, and `#<<`. You must call `#close` when you're done # writing output to a pager, and you must rescue `Pry::Pager::StopPaging`. # These requirements can be avoided by using `.open` instead. # @param [#<<] output ($stdout) An object to send output to. def best_available if !_pry_.config.pager NullPager.new(_pry_.output) elsif !SystemPager.available? || Pry::Helpers::BaseHelpers.jruby? SimplePager.new(_pry_.output) else SystemPager.new(_pry_.output) end end # `NullPager` is a "pager" that actually just prints all output as it comes # in. Used when `Pry.config.pager` is false. class NullPager def initialize(out) @out = out end def puts(str) print "#{str.chomp}\n" end def print(str) write str end alias << print def write(str) @out.write str end def close end private def height @height ||= Pry::Terminal.height! end def width @width ||= Pry::Terminal.width! end end # `SimplePager` is a straightforward pure-Ruby pager. We use it on JRuby and # when we can't find a usable external pager. class SimplePager < NullPager def initialize(*) super @tracker = PageTracker.new(height - 3, width) end def write(str) str.lines.each do |line| @out.print line @tracker.record line if @tracker.page? @out.print "\n" @out.print "\e[0m" @out.print " --- Press enter to continue " \ "( q to break ) --- \n" raise StopPaging if Readline.readline("").chomp == "q" @tracker.reset end end end end # `SystemPager` buffers output until we're pretty sure it's at least a page # long, then invokes an external pager and starts streaming output to it. If # `#close` is called before then, it just prints out the buffered content. class SystemPager < NullPager def self.default_pager pager = ENV["PAGER"] || "" # Default to less, and make sure less is being passed the correct options if pager.strip.empty? or pager =~ /^less\b/ pager = "less -R -F -X" end pager end def self.available? if @system_pager.nil? @system_pager = begin pager_executable = default_pager.split(' ').first `which #{pager_executable}` $?.success? rescue false end else @system_pager end end def initialize(*) super @tracker = PageTracker.new(height, width) @buffer = "" end def write(str) if invoked_pager? write_to_pager str else @tracker.record str @buffer << str if @tracker.page? write_to_pager @buffer end end rescue Errno::EPIPE raise StopPaging end def close if invoked_pager? pager.close else @out.puts @buffer end end private def write_to_pager(text) pager.write @out.decolorize_maybe(text) end def invoked_pager? @pager end def pager @pager ||= IO.popen(self.class.default_pager, 'w') end end # `PageTracker` tracks output to determine whether it's likely to take up a # whole page. This doesn't need to be super precise, but we can use it for # `SimplePager` and to avoid invoking the system pager unnecessarily. # # One simplifying assumption is that we don't need `#page?` to return `true` # on the basis of an incomplete line. Long lines should be counted as # multiple lines, but we don't have to transition from `false` to `true` # until we see a newline. class PageTracker def initialize(rows, cols) @rows, @cols = rows, cols reset end def record(str) str.lines.each do |line| if line.end_with? "\n" @row += ((@col + line_length(line) - 1) / @cols) + 1 @col = 0 else @col += line_length(line) end end end def page? @row >= @rows end def reset @row = 0 @col = 0 end private # Approximation of the printable length of a given line, without the # newline and without ANSI color codes. def line_length(line) line.chomp.gsub(/\e\[[\d;]*m/, '').length end end end pry-0.10.3/lib/pry/plugins.rb000066400000000000000000000056571260757071700160240ustar00rootroot00000000000000class Pry class PluginManager PRY_PLUGIN_PREFIX = /^pry-/ # Placeholder when no associated gem found, displays warning class NoPlugin def initialize(name) @name = name end def method_missing(*args) warn "Warning: The plugin '#{@name}' was not found! (no gem found)" end end class Plugin attr_accessor :name, :gem_name, :enabled, :spec, :active def initialize(name, gem_name, spec, enabled) @name, @gem_name, @enabled, @spec = name, gem_name, enabled, spec end # Disable a plugin. (prevents plugin from being loaded, cannot # disable an already activated plugin) def disable! self.enabled = false end # Enable a plugin. (does not load it immediately but puts on # 'white list' to be loaded) def enable! self.enabled = true end # Load the Command line options defined by this plugin (if they exist) def load_cli_options cli_options_file = File.join(spec.full_gem_path, "lib/#{spec.name}/cli.rb") require cli_options_file if File.exist?(cli_options_file) end # Activate the plugin (require the gem - enables/loads the # plugin immediately at point of call, even if plugin is # disabled) # Does not reload plugin if it's already active. def activate! # Create the configuration object for the plugin. Pry.config.send("#{gem_name.gsub('-', '_')}=", Pry::Config.from_hash({})) begin require gem_name if !active? rescue LoadError => e warn "Found plugin #{gem_name}, but could not require '#{gem_name}'" warn e rescue => e warn "require '#{gem_name}' # Failed, saying: #{e}" end self.active = true self.enabled = true end alias active? active alias enabled? enabled end def initialize @plugins = [] end # Find all installed Pry plugins and store them in an internal array. def locate_plugins Gem.refresh (Gem::Specification.respond_to?(:each) ? Gem::Specification : Gem.source_index.find_name('')).each do |gem| next if gem.name !~ PRY_PLUGIN_PREFIX plugin_name = gem.name.split('-', 2).last @plugins << Plugin.new(plugin_name, gem.name, gem, true) if !gem_located?(gem.name) end @plugins end # @return [Hash] A hash with all plugin names (minus the 'pry-') as # keys and Plugin objects as values. def plugins h = Hash.new { |_, key| NoPlugin.new(key) } @plugins.each do |plugin| h[plugin.name] = plugin end h end # Require all enabled plugins, disabled plugins are skipped. def load_plugins @plugins.each do |plugin| plugin.activate! if plugin.enabled? end end private def gem_located?(gem_name) @plugins.any? { |plugin| plugin.gem_name == gem_name } end end end pry-0.10.3/lib/pry/prompt.rb000066400000000000000000000013231260757071700156460ustar00rootroot00000000000000class Pry::Prompt MAP = { "default" => { value: Pry::DEFAULT_PROMPT, description: "The default Pry prompt. Includes information about the\n" \ "current expression number, evaluation context, and nesting\n" \ "level, plus a reminder that you're using Pry." }, "simple" => { value: Pry::SIMPLE_PROMPT, description: "A simple '>>'." }, "nav" => { value: Pry::NAV_PROMPT, description: "A prompt that displays the binding stack as a path and\n" \ "includes information about _in_ and _out_." }, "none" => { value: Pry::NO_PROMPT, description: "Wave goodbye to the Pry prompt." } } end pry-0.10.3/lib/pry/pry_class.rb000066400000000000000000000263731260757071700163400ustar00rootroot00000000000000require 'pry/config' class Pry HOME_RC_FILE = ENV["PRYRC"] || "~/.pryrc" LOCAL_RC_FILE = "./.pryrc" class << self extend Forwardable attr_accessor :custom_completions attr_accessor :current_line attr_accessor :line_buffer attr_accessor :eval_path attr_accessor :cli attr_accessor :quiet attr_accessor :last_internal_error attr_accessor :config attr_writer :history def_delegators :@plugin_manager, :plugins, :load_plugins, :locate_plugins extend Pry::Config::Convenience config_shortcut(*Pry::Config.shortcuts) def prompt=(value) config.prompt = value end def prompt config.prompt end def history @history ||= History.new end end # # @return [main] # returns the special instance of Object, "main". # def self.main @main ||= TOPLEVEL_BINDING.eval "self" end # # @return [Pry::Config] # Returns a value store for an instance of Pry running on the current thread. # def self.current Thread.current[:__pry__] ||= Pry::Config.from_hash({}, nil) end # Load the given file in the context of `Pry.toplevel_binding` # @param [String] file The unexpanded file path. def self.load_file_at_toplevel(file) toplevel_binding.eval(File.read(file), file) rescue RescuableException => e puts "Error loading #{file}: #{e}\n#{e.backtrace.first}" end # Load HOME_RC_FILE and LOCAL_RC_FILE if appropriate # This method can also be used to reload the files if they have changed. def self.load_rc_files rc_files_to_load.each do |file| critical_section do load_file_at_toplevel(file) end end end # Load the local RC file (./.pryrc) def self.rc_files_to_load files = [] files << HOME_RC_FILE if Pry.config.should_load_rc files << LOCAL_RC_FILE if Pry.config.should_load_local_rc files.map { |file| real_path_to(file) }.compact.uniq end # Expand a file to its canonical name (following symlinks as appropriate) def self.real_path_to(file) expanded = Pathname.new(File.expand_path(file)).realpath.to_s # For rbx 1.9 mode [see rubinius issue #2165] File.exist?(expanded) ? expanded : nil rescue Errno::ENOENT nil end # Load any Ruby files specified with the -r flag on the command line. def self.load_requires Pry.config.requires.each do |file| require file end end # Trap interrupts on jruby, and make them behave like MRI so we can # catch them. def self.load_traps trap('INT'){ raise Interrupt } end def self.load_win32console begin require 'win32console' # The mswin and mingw versions of pry require win32console, so this should # only fail on jruby (where win32console doesn't work). # Instead we'll recommend ansicon, which does. rescue LoadError warn <<-WARNING if Pry.config.windows_console_warning For a better Pry experience on Windows, please use ansicon: https://github.com/adoxa/ansicon If you use an alternative to ansicon and don't want to see this warning again, you can add "Pry.config.windows_console_warning = false" to your .pryrc. WARNING end end # Do basic setup for initial session. # Including: loading .pryrc, loading plugins, loading requires, and # loading history. def self.initial_session_setup return unless initial_session? @initial_session = false # note these have to be loaded here rather than in pry_instance as # we only want them loaded once per entire Pry lifetime. load_rc_files load_plugins if Pry.config.should_load_plugins load_requires if Pry.config.should_load_requires load_history if Pry.config.history.should_load load_traps if Pry.config.should_trap_interrupts load_win32console if Pry::Helpers::BaseHelpers.windows? && !Pry::Helpers::BaseHelpers.windows_ansi? end # Start a Pry REPL. # This method also loads `~/.pryrc` and `./.pryrc` as necessary the # first time it is invoked. # @param [Object, Binding] target The receiver of the Pry session # @param [Hash] options # @option options (see Pry#initialize) # @example # Pry.start(Object.new, :input => MyInput.new) def self.start(target=nil, options={}) return if ENV['DISABLE_PRY'] options = options.to_hash if in_critical_section? output.puts "ERROR: Pry started inside Pry." output.puts "This can happen if you have a binding.pry inside a #to_s or #inspect function." return end options[:target] = Pry.binding_for(target || toplevel_binding) options[:hooks] = Pry::Hooks.from_hash options.delete(:hooks) if options.key?(:hooks) initial_session_setup # Unless we were given a backtrace, save the current one if options[:backtrace].nil? options[:backtrace] = caller # If Pry was started via `binding.pry`, elide that from the backtrace if options[:backtrace].first =~ /pry.*core_extensions.*pry/ options[:backtrace].shift end end driver = options[:driver] || Pry::REPL # Enter the matrix driver.start(options) rescue Pry::TooSafeException puts "ERROR: Pry cannot work with $SAFE > 0" raise end # Execute the file through the REPL loop, non-interactively. # @param [String] file_name File name to load through the REPL. def self.load_file_through_repl(file_name) require "pry/repl_file_loader" REPLFileLoader.new(file_name).load end # # An inspector that clips the output to `max_length` chars. # In case of > `max_length` chars the `# notation is used. # # @param [Object] obj # The object to view. # # @param [Hash] options # @option options [Integer] :max_length (60) # The maximum number of chars before clipping occurs. # # @option options [Boolean] :id (false) # Boolean to indicate whether or not a hex reprsentation of the object ID # is attached to the return value when the length of inspect is greater than # value of `:max_length`. # # @return [String] # The string representation of `obj`. # def self.view_clip(obj, options = {}) max = options.fetch :max_length, 60 id = options.fetch :id, false if obj.kind_of?(Module) && obj.name.to_s != "" && obj.name.to_s.length <= max obj.name.to_s elsif Pry.main == obj # special-case to support jruby. # fixed as of https://github.com/jruby/jruby/commit/d365ebd309cf9df3dde28f5eb36ea97056e0c039 # we can drop in the future. obj.to_s elsif Pry.config.prompt_safe_objects.any? { |v| v === obj } && obj.inspect.length <= max obj.inspect else id == true ? "#<#{obj.class}:0x%x>" % (obj.object_id << 1) : "#<#{obj.class}>" end rescue RescuableException "unknown" end # Load Readline history if required. def self.load_history Pry.history.load end # @return [Boolean] Whether this is the first time a Pry session has # been started since loading the Pry class. def self.initial_session? @initial_session end # Run a Pry command from outside a session. The commands available are # those referenced by `Pry.config.commands` (the default command set). # @param [String] command_string The Pry command (including arguments, # if any). # @param [Hash] options Optional named parameters. # @return [Object] The return value of the Pry command. # @option options [Object, Binding] :target The object to run the # command under. Defaults to `TOPLEVEL_BINDING` (main). # @option options [Boolean] :show_output Whether to show command # output. Defaults to true. # @example Run at top-level with no output. # Pry.run_command "ls" # @example Run under Pry class, returning only public methods. # Pry.run_command "ls -m", :target => Pry # @example Display command output. # Pry.run_command "ls -av", :show_output => true def self.run_command(command_string, options={}) options = { :target => TOPLEVEL_BINDING, :show_output => true, :output => Pry.config.output, :commands => Pry.config.commands }.merge!(options) # :context for compatibility with <= 0.9.11.4 target = options[:context] || options[:target] output = options[:show_output] ? options[:output] : StringIO.new pry = Pry.new(:output => output, :target => target, :commands => options[:commands]) pry.eval command_string end def self.default_editor_for_platform return ENV['VISUAL'] if ENV['VISUAL'] and not ENV['VISUAL'].empty? return ENV['EDITOR'] if ENV['EDITOR'] and not ENV['EDITOR'].empty? if Helpers::BaseHelpers.windows? 'notepad' else %w(editor nano vi).detect do |editor| system("which #{editor} > /dev/null 2>&1") end end end def self.auto_resize! Pry.config.input # by default, load Readline if !defined?(Readline) || Pry.config.input != Readline warn "Sorry, you must be using Readline for Pry.auto_resize! to work." return end if Readline::VERSION =~ /edit/i warn <<-EOT Readline version #{Readline::VERSION} detected - will not auto_resize! correctly. For the fix, use GNU Readline instead: https://github.com/guard/guard/wiki/Add-proper-Readline-support-to-Ruby-on-Mac-OS-X EOT return end trap :WINCH do begin Readline.set_screen_size(*Terminal.size!) rescue => e warn "\nPry.auto_resize!'s Readline.set_screen_size failed: #{e}" end begin Readline.refresh_line rescue => e warn "\nPry.auto_resize!'s Readline.refresh_line failed: #{e}" end end end # Set all the configurable options back to their default values def self.reset_defaults @initial_session = true self.config = Pry::Config.new Pry::Config::Default.new self.cli = false self.current_line = 1 self.line_buffer = [""] self.eval_path = "(pry)" end # Basic initialization. def self.init @plugin_manager ||= PluginManager.new reset_defaults locate_plugins end # Return a `Binding` object for `target` or return `target` if it is # already a `Binding`. # In the case where `target` is top-level then return `TOPLEVEL_BINDING` # @param [Object] target The object to get a `Binding` object for. # @return [Binding] The `Binding` object. def self.binding_for(target) if Binding === target target else if Pry.main == target TOPLEVEL_BINDING else target.__binding__ end end end def self.toplevel_binding unless defined?(@toplevel_binding) && @toplevel_binding # Grab a copy of the TOPLEVEL_BINDING without any local variables. # This binding has a default definee of Object, and new methods are # private (just as in TOPLEVEL_BINDING). TOPLEVEL_BINDING.eval <<-RUBY def self.__pry__ binding end Pry.toplevel_binding = __pry__ class << self; undef __pry__; end RUBY end @toplevel_binding.eval('private') @toplevel_binding end def self.toplevel_binding=(binding) @toplevel_binding = binding end def self.in_critical_section? Thread.current[:pry_critical_section] ||= 0 Thread.current[:pry_critical_section] > 0 end def self.critical_section(&block) Thread.current[:pry_critical_section] ||= 0 Thread.current[:pry_critical_section] += 1 yield ensure Thread.current[:pry_critical_section] -= 1 end end Pry.init pry-0.10.3/lib/pry/pry_instance.rb000066400000000000000000000511551260757071700170330ustar00rootroot00000000000000# -*- coding: utf-8 -*- ## # Pry is a powerful alternative to the standard IRB shell for Ruby. It # features syntax highlighting, a flexible plugin architecture, runtime # invocation and source and documentation browsing. # # Pry can be started similar to other command line utilities by simply running # the following command: # # pry # # Once inside Pry you can invoke the help message: # # help # # This will show a list of available commands and their usage. For more # information about Pry you can refer to the following resources: # # * http://pry.github.com/ # * https://github.com/pry/pry # * the IRC channel, which is #pry on the Freenode network # class Pry attr_accessor :binding_stack attr_accessor :custom_completions attr_accessor :eval_string attr_accessor :backtrace attr_accessor :suppress_output attr_accessor :last_result attr_accessor :last_file attr_accessor :last_dir attr_reader :last_exception attr_reader :command_state attr_reader :exit_value attr_reader :input_array attr_reader :output_array attr_reader :config extend Pry::Config::Convenience config_shortcut(*Pry::Config.shortcuts) EMPTY_COMPLETIONS = [].freeze # Create a new {Pry} instance. # @param [Hash] options # @option options [#readline] :input # The object to use for input. # @option options [#puts] :output # The object to use for output. # @option options [Pry::CommandBase] :commands # The object to use for commands. # @option options [Hash] :hooks # The defined hook Procs. # @option options [Array] :prompt # The array of Procs to use for prompts. # @option options [Proc] :print # The Proc to use for printing return values. # @option options [Boolean] :quiet # Omit the `whereami` banner when starting. # @option options [Array] :backtrace # The backtrace of the session's `binding.pry` line, if applicable. # @option options [Object] :target # The initial context for this session. def initialize(options={}) @binding_stack = [] @indent = Pry::Indent.new @command_state = {} @eval_string = "" @backtrace = options.delete(:backtrace) || caller target = options.delete(:target) @config = Pry::Config.new config.merge!(options) push_prompt(config.prompt) @input_array = Pry::HistoryArray.new config.memory_size @output_array = Pry::HistoryArray.new config.memory_size @custom_completions = config.command_completions set_last_result nil @input_array << nil push_initial_binding(target) exec_hook(:when_started, target, options, self) end # The current prompt. # This is the prompt at the top of the prompt stack. # # @example # self.prompt = Pry::SIMPLE_PROMPT # self.prompt # => Pry::SIMPLE_PROMPT # # @return [Array] Current prompt. def prompt prompt_stack.last end def prompt=(new_prompt) if prompt_stack.empty? push_prompt new_prompt else prompt_stack[-1] = new_prompt end end # Initialize this instance by pushing its initial context into the binding # stack. If no target is given, start at the top level. def push_initial_binding(target=nil) push_binding(target || Pry.toplevel_binding) end # The currently active `Binding`. # @return [Binding] The currently active `Binding` for the session. def current_binding binding_stack.last end alias current_context current_binding # support previous API # Push a binding for the given object onto the stack. If this instance is # currently stopped, mark it as usable again. def push_binding(object) @stopped = false binding_stack << Pry.binding_for(object) end # # Generate completions. # # @param [String] input # What the user has typed so far # # @return [Array] # Possible completions # def complete(str) return EMPTY_COMPLETIONS unless config.completer Pry.critical_section do completer = config.completer.new(config.input, self) completer.call str, target: current_binding, custom_completions: custom_completions.call.push(*sticky_locals.keys) end end # # Injects a local variable into the provided binding. # # @param [String] name # The name of the local to inject. # # @param [Object] value # The value to set the local to. # # @param [Binding] b # The binding to set the local on. # # @return [Object] # The value the local was set to. # def inject_local(name, value, b) value = Proc === value ? value.call : value if b.respond_to?(:local_variable_set) b.local_variable_set name, value else # < 2.1 begin Pry.current[:pry_local] = value b.eval "#{name} = ::Pry.current[:pry_local]" ensure Pry.current[:pry_local] = nil end end end undef :memory_size if method_defined? :memory_size # @return [Integer] The maximum amount of objects remembered by the inp and # out arrays. Defaults to 100. def memory_size @output_array.max_size end undef :memory_size= if method_defined? :memory_size= def memory_size=(size) @input_array = Pry::HistoryArray.new(size) @output_array = Pry::HistoryArray.new(size) end # Inject all the sticky locals into the current binding. def inject_sticky_locals! sticky_locals.each_pair do |name, value| inject_local(name, value, current_binding) end end # Add a sticky local to this Pry instance. # A sticky local is a local that persists between all bindings in a session. # @param [Symbol] name The name of the sticky local. # @yield The block that defines the content of the local. The local # will be refreshed at each tick of the repl loop. def add_sticky_local(name, &block) config.extra_sticky_locals[name] = block end def sticky_locals { _in_: input_array, _out_: output_array, _pry_: self, _ex_: last_exception && last_exception.wrapped_exception, _file_: last_file, _dir_: last_dir, _: proc { last_result }, __: proc { output_array[-2] } }.merge(config.extra_sticky_locals) end # Reset the current eval string. If the user has entered part of a multiline # expression, this discards that input. def reset_eval_string @eval_string = "" end # Pass a line of input to Pry. # # This is the equivalent of `Binding#eval` but with extra Pry! # # In particular: # 1. Pry commands will be executed immediately if the line matches. # 2. Partial lines of input will be queued up until a complete expression has # been accepted. # 3. Output is written to `#output` in pretty colours, not returned. # # Once this method has raised an exception or returned false, this instance # is no longer usable. {#exit_value} will return the session's breakout # value if applicable. # # @param [String?] line The line of input; `nil` if the user types `` # @option options [Boolean] :generated Whether this line was generated automatically. # Generated lines are not stored in history. # @return [Boolean] Is Pry ready to accept more input? # @raise [Exception] If the user uses the `raise-up` command, this method # will raise that exception. def eval(line, options={}) return false if @stopped exit_value = nil exception = catch(:raise_up) do exit_value = catch(:breakout) do handle_line(line, options) # We use 'return !@stopped' here instead of 'return true' so that if # handle_line has stopped this pry instance (e.g. by opening _pry_.repl and # then popping all the bindings) we still exit immediately. return !@stopped end exception = false end @stopped = true @exit_value = exit_value # TODO: make this configurable? raise exception if exception return false end def handle_line(line, options) if line.nil? config.control_d_handler.call(@eval_string, self) return end ensure_correct_encoding!(line) Pry.history << line unless options[:generated] @suppress_output = false inject_sticky_locals! begin if !process_command_safely(line.lstrip) @eval_string << "#{line.chomp}\n" if !line.empty? || !@eval_string.empty? end rescue RescuableException => e self.last_exception = e result = e Pry.critical_section do show_result(result) end return end # This hook is supposed to be executed after each line of ruby code # has been read (regardless of whether eval_string is yet a complete expression) exec_hook :after_read, eval_string, self begin complete_expr = Pry::Code.complete_expression?(@eval_string) rescue SyntaxError => e output.puts "SyntaxError: #{e.message.sub(/.*syntax error, */m, '')}" reset_eval_string end if complete_expr if @eval_string =~ /;\Z/ || @eval_string.empty? || @eval_string =~ /\A *#.*\n\z/ @suppress_output = true end # A bug in jruby makes java.lang.Exception not rescued by # `rescue Pry::RescuableException` clause. # # * https://github.com/pry/pry/issues/854 # * https://jira.codehaus.org/browse/JRUBY-7100 # # Until that gets fixed upstream, treat java.lang.Exception # as an additional exception to be rescued explicitly. # # This workaround has a side effect: java exceptions specified # in `Pry.config.exception_whitelist` are ignored. jruby_exceptions = [] if Pry::Helpers::BaseHelpers.jruby? jruby_exceptions << Java::JavaLang::Exception end begin # Reset eval string, in case we're evaluating Ruby that does something # like open a nested REPL on this instance. eval_string = @eval_string reset_eval_string result = evaluate_ruby(eval_string) rescue RescuableException, *jruby_exceptions => e # Eliminate following warning: # warning: singleton on non-persistent Java type X # (http://wiki.jruby.org/Persistence) if Pry::Helpers::BaseHelpers.jruby? && e.class.respond_to?('__persistent__') e.class.__persistent__ = true end self.last_exception = e result = e end Pry.critical_section do show_result(result) end end throw(:breakout) if current_binding.nil? end private :handle_line # Potentially deprecated — Use `Pry::REPL.new(pry, :target => target).start` # (If nested sessions are going to exist, this method is fine, but a goal is # to come up with an alternative to nested sessions altogether.) def repl(target = nil) Pry::REPL.new(self, :target => target).start end def evaluate_ruby(code) inject_sticky_locals! exec_hook :before_eval, code, self result = current_binding.eval(code, Pry.eval_path, Pry.current_line) set_last_result(result, code) ensure update_input_history(code) exec_hook :after_eval, result, self end # Output the result or pass to an exception handler (if result is an exception). def show_result(result) if last_result_is_exception? exception_handler.call(output, result, self) elsif should_print? print.call(output, result, self) else # nothin' end rescue RescuableException => e # Being uber-paranoid here, given that this exception arose because we couldn't # serialize something in the user's program, let's not assume we can serialize # the exception either. begin output.puts "(pry) output error: #{e.inspect}" rescue RescuableException => e if last_result_is_exception? output.puts "(pry) output error: failed to show exception" else output.puts "(pry) output error: failed to show result" end end ensure output.flush if output.respond_to?(:flush) end # Force `eval_string` into the encoding of `val`. [Issue #284] def ensure_correct_encoding!(val) if @eval_string.empty? && val.respond_to?(:encoding) && val.encoding != @eval_string.encoding @eval_string.force_encoding(val.encoding) end end private :ensure_correct_encoding! # If the given line is a valid command, process it in the context of the # current `eval_string` and binding. # @param [String] val The line to process. # @return [Boolean] `true` if `val` is a command, `false` otherwise def process_command(val) val = val.chomp result = commands.process_line(val, :target => current_binding, :output => output, :eval_string => @eval_string, :pry_instance => self ) # set a temporary (just so we can inject the value we want into eval_string) Pry.current[:pry_cmd_result] = result # note that `result` wraps the result of command processing; if a # command was matched and invoked then `result.command?` returns true, # otherwise it returns false. if result.command? if !result.void_command? # the command that was invoked was non-void (had a return value) and so we make # the value of the current expression equal to the return value # of the command. @eval_string.replace "::Pry.current[:pry_cmd_result].retval\n" end true else false end end # Same as process_command, but outputs exceptions to `#output` instead of # raising. # @param [String] val The line to process. # @return [Boolean] `true` if `val` is a command, `false` otherwise def process_command_safely(val) process_command(val) rescue CommandError, Slop::InvalidOptionError, MethodSource::SourceNotFoundError => e Pry.last_internal_error = e output.puts "Error: #{e.message}" true end # Run the specified command. # @param [String] val The command (and its params) to execute. # @return [Pry::Command::VOID_VALUE] # @example # pry_instance.run_command("ls -m") def run_command(val) commands.process_line(val, :eval_string => @eval_string, :target => current_binding, :pry_instance => self, :output => output ) Pry::Command::VOID_VALUE end # Execute the specified hook. # @param [Symbol] name The hook name to execute # @param [*Object] args The arguments to pass to the hook # @return [Object, Exception] The return value of the hook or the exception raised # # If executing a hook raises an exception, we log that and then continue sucessfully. # To debug such errors, use the global variable $pry_hook_error, which is set as a # result. def exec_hook(name, *args, &block) e_before = hooks.errors.size hooks.exec_hook(name, *args, &block).tap do hooks.errors[e_before..-1].each do |e| output.puts "#{name} hook failed: #{e.class}: #{e.message}" output.puts "#{e.backtrace.first}" output.puts "(see _pry_.hooks.errors to debug)" end end end # Set the last result of an eval. # This method should not need to be invoked directly. # @param [Object] result The result. # @param [String] code The code that was run. def set_last_result(result, code="") @last_result_is_exception = false @output_array << result self.last_result = result unless code =~ /\A\s*\z/ end # # Set the last exception for a session. # # @param [Exception] e # the last exception. # def last_exception=(e) last_exception = Pry::LastException.new(e) @last_result_is_exception = true @output_array << last_exception @last_exception = last_exception end # Update Pry's internal state after evalling code. # This method should not need to be invoked directly. # @param [String] code The code we just eval'd def update_input_history(code) # Always push to the @input_array as the @output_array is always pushed to. @input_array << code if code Pry.line_buffer.push(*code.each_line) Pry.current_line += code.lines.count end end # @return [Boolean] True if the last result is an exception that was raised, # as opposed to simply an instance of Exception (like the result of # Exception.new) def last_result_is_exception? @last_result_is_exception end # Whether the print proc should be invoked. # Currently only invoked if the output is not suppressed. # @return [Boolean] Whether the print proc should be invoked. def should_print? !@suppress_output end # Returns the appropriate prompt to use. # @return [String] The prompt. def select_prompt object = current_binding.eval('self') open_token = @indent.open_delimiters.any? ? @indent.open_delimiters.last : @indent.stack.last c = Pry::Config.from_hash({ :object => object, :nesting_level => binding_stack.size - 1, :open_token => open_token, :session_line => Pry.history.session_line_count + 1, :history_line => Pry.history.history_line_count + 1, :expr_number => input_array.count, :_pry_ => self, :binding_stack => binding_stack, :input_array => input_array, :eval_string => @eval_string, :cont => !@eval_string.empty?}) Pry.critical_section do # If input buffer is empty then use normal prompt if eval_string.empty? generate_prompt(Array(prompt).first, c) # Otherwise use the wait prompt (indicating multi-line expression) else generate_prompt(Array(prompt).last, c) end end end def generate_prompt(prompt_proc, conf) if prompt_proc.arity == 1 prompt_proc.call(conf) else prompt_proc.call(conf.object, conf.nesting_level, conf._pry_) end end private :generate_prompt # the array that the prompt stack is stored in def prompt_stack @prompt_stack ||= Array.new end private :prompt_stack # Pushes the current prompt onto a stack that it can be restored from later. # Use this if you wish to temporarily change the prompt. # @param [Array] new_prompt # @return [Array] new_prompt # @example # new_prompt = [ proc { '>' }, proc { '>>' } ] # push_prompt(new_prompt) # => new_prompt def push_prompt(new_prompt) prompt_stack.push new_prompt end # Pops the current prompt off of the prompt stack. # If the prompt you are popping is the last prompt, it will not be popped. # Use this to restore the previous prompt. # @return [Array] Prompt being popped. # @example # prompt1 = [ proc { '>' }, proc { '>>' } ] # prompt2 = [ proc { '$' }, proc { '>' } ] # pry = Pry.new :prompt => prompt1 # pry.push_prompt(prompt2) # pry.pop_prompt # => prompt2 # pry.pop_prompt # => prompt1 # pry.pop_prompt # => prompt1 def pop_prompt prompt_stack.size > 1 ? prompt_stack.pop : prompt end undef :pager if method_defined? :pager # Returns the currently configured pager # @example # _pry_.pager.page text def pager Pry::Pager.new(self) end undef :output if method_defined? :output # Returns an output device # @example # _pry_.output.puts "ohai!" def output Pry::Output.new(self) end # Raise an exception out of Pry. # # See Kernel#raise for documentation of parameters. # See rb_make_exception for the inbuilt implementation. # # This is necessary so that the raise-up command can tell the # difference between an exception the user has decided to raise, # and a mistake in specifying that exception. # # (i.e. raise-up RunThymeError.new should not be the same as # raise-up NameError, "unititialized constant RunThymeError") # def raise_up_common(force, *args) exception = if args == [] last_exception || RuntimeError.new elsif args.length == 1 && args.first.is_a?(String) RuntimeError.new(args.first) elsif args.length > 3 raise ArgumentError, "wrong number of arguments" elsif !args.first.respond_to?(:exception) raise TypeError, "exception class/object expected" elsif args.length === 1 args.first.exception else args.first.exception(args[1]) end raise TypeError, "exception object expected" unless exception.is_a? Exception exception.set_backtrace(args.length === 3 ? args[2] : caller(1)) if force || binding_stack.one? binding_stack.clear throw :raise_up, exception else binding_stack.pop raise exception end end def raise_up(*args); raise_up_common(false, *args); end def raise_up!(*args); raise_up_common(true, *args); end # Convenience accessor for the `quiet` config key. # @return [Boolean] def quiet? config.quiet end end pry-0.10.3/lib/pry/rbx_path.rb000066400000000000000000000010561260757071700161370ustar00rootroot00000000000000class Pry module RbxPath module_function def is_core_path?(path) Pry::Helpers::BaseHelpers.rbx? && (path.start_with?("kernel") || path.start_with?("lib")) && File.exist?(convert_path_to_full(path)) end def convert_path_to_full(path) if path.start_with?("kernel") File.join File.dirname(Rubinius::KERNEL_PATH), path elsif path.start_with?("lib") File.join File.dirname(Rubinius::LIB_PATH), path else path end end def rvm_ruby?(path) !!(path =~ /\.rvm/) end end end pry-0.10.3/lib/pry/repl.rb000066400000000000000000000144551260757071700153010ustar00rootroot00000000000000require 'forwardable' class Pry class REPL extend Forwardable def_delegators :@pry, :input, :output # @return [Pry] The instance of {Pry} that the user is controlling. attr_accessor :pry # Instantiate a new {Pry} instance with the given options, then start a # {REPL} instance wrapping it. # @option options See {Pry#initialize} def self.start(options) new(Pry.new(options)).start end # Create an instance of {REPL} wrapping the given {Pry}. # @param [Pry] pry The instance of {Pry} that this {REPL} will control. # @param [Hash] options Options for this {REPL} instance. # @option options [Object] :target The initial target of the session. def initialize(pry, options = {}) @pry = pry @indent = Pry::Indent.new if options[:target] @pry.push_binding options[:target] end end # Start the read-eval-print loop. # @return [Object?] If the session throws `:breakout`, return the value # thrown with it. # @raise [Exception] If the session throws `:raise_up`, raise the exception # thrown with it. def start prologue Pry::InputLock.for(:all).with_ownership { repl } ensure epilogue end private # Set up the repl session. # @return [void] def prologue pry.exec_hook :before_session, pry.output, pry.current_binding, pry # Clear the line before starting Pry. This fixes issue #566. if pry.config.correct_indent Kernel.print Pry::Helpers::BaseHelpers.windows_ansi? ? "\e[0F" : "\e[0G" end end # The actual read-eval-print loop. # # The {REPL} instance is responsible for reading and looping, whereas the # {Pry} instance is responsible for evaluating user input and printing # return values and command output. # # @return [Object?] If the session throws `:breakout`, return the value # thrown with it. # @raise [Exception] If the session throws `:raise_up`, raise the exception # thrown with it. def repl loop do case val = read when :control_c output.puts "" pry.reset_eval_string when :no_more_input output.puts "" if output.tty? break else output.puts "" if val.nil? && output.tty? return pry.exit_value unless pry.eval(val) end end end # Clean up after the repl session. # @return [void] def epilogue pry.exec_hook :after_session, pry.output, pry.current_binding, pry end # Read a line of input from the user. # @return [String] The line entered by the user. # @return [nil] On ``. # @return [:control_c] On ``. # @return [:no_more_input] On EOF. def read @indent.reset if pry.eval_string.empty? current_prompt = pry.select_prompt indentation = pry.config.auto_indent ? @indent.current_prefix : '' val = read_line("#{current_prompt}#{indentation}") # Return nil for EOF, :no_more_input for error, or :control_c for return val unless String === val if pry.config.auto_indent original_val = "#{indentation}#{val}" indented_val = @indent.indent(val) if output.tty? && pry.config.correct_indent && Pry::Helpers::BaseHelpers.use_ansi_codes? output.print @indent.correct_indentation( current_prompt, indented_val, original_val.length - indented_val.length ) output.flush end else indented_val = val end indented_val end # Manage switching of input objects on encountering `EOFError`s. # @return [Object] Whatever the given block returns. # @return [:no_more_input] Indicates that no more input can be read. def handle_read_errors should_retry = true exception_count = 0 begin yield rescue EOFError pry.config.input = Pry.config.input if !should_retry output.puts "Error: Pry ran out of things to read from! " \ "Attempting to break out of REPL." return :no_more_input end should_retry = false retry # Handle like Bash: empty the current input buffer, but don't # quit. This is only for MRI 1.9; other versions of Ruby don't let you # send Interrupt from within Readline. rescue Interrupt return :control_c # If we get a random error when trying to read a line we don't want to # automatically retry, as the user will see a lot of error messages # scroll past and be unable to do anything about it. rescue RescuableException => e puts "Error: #{e.message}" output.puts e.backtrace exception_count += 1 if exception_count < 5 retry end puts "FATAL: Pry failed to get user input using `#{input}`." puts "To fix this you may be able to pass input and output file " \ "descriptors to pry directly. e.g." puts " Pry.config.input = STDIN" puts " Pry.config.output = STDOUT" puts " binding.pry" return :no_more_input end end # Returns the next line of input to be sent to the {Pry} instance. # @param [String] current_prompt The prompt to use for input. # @return [String?] The next line of input, or `nil` on . def read_line(current_prompt) handle_read_errors do if defined? Coolline and input.is_a? Coolline input.completion_proc = proc do |cool| completions = @pry.complete cool.completed_word completions.compact end elsif input.respond_to? :completion_proc= input.completion_proc = proc do |input| @pry.complete input end end if defined?(Readline) and input == Readline input_readline(current_prompt, false) # false since we'll add it manually elsif defined? Coolline and input.is_a? Coolline input_readline(current_prompt) else if input.method(:readline).arity == 1 input_readline(current_prompt) else input_readline end end end end def input_readline(*args) Pry::InputLock.for(:all).interruptible_region do input.readline(*args) end end end end pry-0.10.3/lib/pry/repl_file_loader.rb000066400000000000000000000052561260757071700176250ustar00rootroot00000000000000class Pry # A class to manage the loading of files through the REPL loop. # This is an interesting trick as it processes your file as if it # was user input in an interactive session. As a result, all Pry # commands are available, and they are executed non-interactively. Furthermore # the session becomes interactive when the repl loop processes a # 'make-interactive' command in the file. The session also becomes # interactive when an exception is encountered, enabling you to fix # the error before returning to non-interactive processing with the # 'make-non-interactive' command. class REPLFileLoader def initialize(file_name) full_name = File.expand_path(file_name) raise RuntimeError, "No such file: #{full_name}" if !File.exists?(full_name) define_additional_commands @content = File.read(full_name) end # Switch to interactive mode, i.e take input from the user # and use the regular print and exception handlers. # @param [Pry] _pry_ the Pry instance to make interactive. def interactive_mode(_pry_) _pry_.config.input = Pry.config.input _pry_.config.print = Pry.config.print _pry_.config.exception_handler = Pry.config.exception_handler Pry::REPL.new(_pry_).start end # Switch to non-interactive mode. Essentially # this means there is no result output # and that the session becomes interactive when an exception is encountered. # @param [Pry] _pry_ the Pry instance to make non-interactive. def non_interactive_mode(_pry_, content) _pry_.print = proc {} _pry_.exception_handler = proc do |o, e, _p_| _p_.run_command "cat --ex" o.puts "...exception encountered, going interactive!" interactive_mode(_pry_) end content.lines.each do |line| break unless _pry_.eval line, :generated => true end unless _pry_.eval_string.empty? _pry_.output.puts "#{_pry_.eval_string}...exception encountered, going interactive!" interactive_mode(_pry_) end end # Define a few extra commands useful for flipping back & forth # between interactive/non-interactive modes def define_additional_commands s = self Pry::Commands.command "make-interactive", "Make the session interactive" do s.interactive_mode(_pry_) end Pry::Commands.command "load-file", "Load another file through the repl" do |file_name| s.non_interactive_mode(_pry_, File.read(File.expand_path(file_name))) end end # Actually load the file through the REPL by setting file content # as the REPL input stream. def load non_interactive_mode(Pry.new, @content) end end end pry-0.10.3/lib/pry/rubygem.rb000066400000000000000000000046411260757071700160050ustar00rootroot00000000000000require 'rubygems' class Pry module Rubygem class << self def installed?(name) if Gem::Specification.respond_to?(:find_all_by_name) Gem::Specification.find_all_by_name(name).any? else Gem.source_index.find_name(name).first end end # Get the gem spec object for the given gem name. # # @param [String] name # @return [Gem::Specification] def spec(name) specs = if Gem::Specification.respond_to?(:each) Gem::Specification.find_all_by_name(name) else Gem.source_index.find_name(name) end first_spec = specs.sort_by{ |spec| Gem::Version.new(spec.version) }.last first_spec or raise CommandError, "Gem `#{name}` not found" end # List gems matching a pattern. # # @param [Regexp] pattern # @return [Array] def list(pattern = /.*/) if Gem::Specification.respond_to?(:each) Gem::Specification.select{|spec| spec.name =~ pattern } else Gem.source_index.gems.values.select{|spec| spec.name =~ pattern } end end # Completion function for gem-cd and gem-open. # # @param [String] so_far what the user's typed so far # @return [Array] completions def complete(so_far) if so_far =~ / ([^ ]*)\z/ self.list(%r{\A#{$2}}).map(&:name) else self.list.map(&:name) end end # Installs a gem with all its dependencies. # # @param [String] name # @return [void] def install(name) gemrc_opts = Gem.configuration['gem'].split(' ') destination = if gemrc_opts.include?('--user-install') Gem.user_dir elsif File.writable?(Gem.dir) Gem.dir else Gem.user_dir end installer = Gem::DependencyInstaller.new(:install_dir => destination) installer.install(name) rescue Errno::EACCES raise CommandError, "Insufficient permissions to install #{ Pry::Helpers::Text.green(name) }." rescue Gem::GemNotFoundException raise CommandError, "Gem #{ Pry::Helpers::Text.green(name) } not found. Aborting installation." else Gem.refresh end end end end pry-0.10.3/lib/pry/terminal.rb000066400000000000000000000044221260757071700161430ustar00rootroot00000000000000class Pry::Terminal class << self # Return a pair of [rows, columns] which gives the size of the window. # # If the window size cannot be determined, return nil. def screen_size rows, cols = actual_screen_size if rows.to_i != 0 && cols.to_i != 0 [rows.to_i, cols.to_i] else nil end end # Return a screen size or a default if that fails. def size! default = [27, 80] screen_size || default end # Return a screen width or the default if that fails. def width! size![1] end # Return a screen height or the default if that fails. def height! size![0] end def actual_screen_size # The best way, if possible (requires non-jruby ≥1.9 or io-console gem) screen_size_according_to_io_console or # Fall back to the old standby, though it might be stale: screen_size_according_to_env or # Fall further back, though this one is also out of date without something # calling Readline.set_screen_size screen_size_according_to_readline or # Windows users can otherwise run ansicon and get a decent answer: screen_size_according_to_ansicon_env end def screen_size_according_to_io_console return if Pry::Helpers::BaseHelpers.jruby? require 'io/console' $stdout.winsize if $stdout.tty? and $stdout.respond_to?(:winsize) rescue LoadError # They probably don't have the io/console stdlib or the io-console gem. # We'll keep trying. end def screen_size_according_to_env size = [ENV['LINES'] || ENV['ROWS'], ENV['COLUMNS']] size if nonzero_column?(size) end def screen_size_according_to_readline if defined?(Readline) && Readline.respond_to?(:get_screen_size) size = Readline.get_screen_size size if nonzero_column?(size) end rescue Java::JavaLang::NullPointerException # This rescue won't happen on jrubies later than: # https://github.com/jruby/jruby/pull/436 nil end def screen_size_according_to_ansicon_env return unless ENV['ANSICON'] =~ /\((.*)x(.*)\)/ size = [$2, $1] size if nonzero_column?(size) end private def nonzero_column?(size) size[1].to_i > 0 end end end pry-0.10.3/lib/pry/test/000077500000000000000000000000001260757071700147605ustar00rootroot00000000000000pry-0.10.3/lib/pry/test/helper.rb000066400000000000000000000073111260757071700165660ustar00rootroot00000000000000require 'pry' # in case the tests call reset_defaults, ensure we reset them to # amended (test friendly) values class << Pry alias_method :orig_reset_defaults, :reset_defaults def reset_defaults orig_reset_defaults Pry.config.color = false Pry.config.pager = false Pry.config.should_load_rc = false Pry.config.should_load_local_rc= false Pry.config.should_load_plugins = false Pry.config.history.should_load = false Pry.config.history.should_save = false Pry.config.correct_indent = false Pry.config.hooks = Pry::Hooks.new Pry.config.collision_warning = false end end Pry.reset_defaults # A global space for storing temporary state during tests. module PryTestHelpers module_function # inject a variable into a binding def inject_var(name, value, b) Pry.current[:pry_local] = value b.eval("#{name} = ::Pry.current[:pry_local]") ensure Pry.current[:pry_local] = nil end def constant_scope(*names) names.each do |name| Object.remove_const name if Object.const_defined?(name) end yield ensure names.each do |name| Object.remove_const name if Object.const_defined?(name) end end # Open a temp file and yield it to the block, closing it after # @return [String] The path of the temp file def temp_file(ext='.rb') file = Tempfile.new(['pry', ext]) yield file ensure file.close(true) if file File.unlink("#{file.path}c") if File.exists?("#{file.path}c") # rbx end def unindent(*args) Pry::Helpers::CommandHelpers.unindent(*args) end def mock_command(cmd, args=[], opts={}) output = StringIO.new pry = Pry.new(output: output) ret = cmd.new(opts.merge(pry_instance: pry, :output => output)).call_safely(*args) Struct.new(:output, :return).new(output.string, ret) end def mock_exception(*mock_backtrace) StandardError.new.tap do |e| e.define_singleton_method(:backtrace) { mock_backtrace } end end end def pry_tester(*args, &block) if args.length == 0 || args[0].is_a?(Hash) args.unshift(Pry.toplevel_binding) end PryTester.new(*args).tap do |t| (class << t; self; end).class_eval(&block) if block end end def pry_eval(*eval_strs) if eval_strs.first.is_a? String binding = Pry.toplevel_binding else binding = Pry.binding_for(eval_strs.shift) end pry_tester(binding).eval(*eval_strs) end class PryTester extend Forwardable attr_reader :pry, :out def_delegators :@pry, :eval_string, :eval_string= def initialize(target = TOPLEVEL_BINDING, options = {}) @pry = Pry.new(options.merge(:target => target)) @history = options[:history] @pry.inject_sticky_locals! reset_output end def eval(*strs) reset_output result = nil strs.flatten.each do |str| str = "#{str.strip}\n" @history.push str if @history if @pry.process_command(str) result = last_command_result_or_output else result = @pry.evaluate_ruby(str) end end result end def push(*lines) Array(lines).flatten.each do |line| @pry.eval(line) end end def push_binding(context) @pry.push_binding context end def last_output @out.string if @out end def process_command(command_str) @pry.process_command(command_str) or raise "Not a valid command" last_command_result_or_output end def last_command_result result = Pry.current[:pry_cmd_result] result.retval if result end protected def last_command_result_or_output result = last_command_result if result != Pry::Command::VOID_VALUE result else last_output end end def reset_output @out = StringIO.new @pry.output = @out end end pry-0.10.3/lib/pry/version.rb000066400000000000000000000000431260757071700160100ustar00rootroot00000000000000class Pry VERSION = "0.10.3" end pry-0.10.3/lib/pry/wrapped_module.rb000066400000000000000000000316161260757071700173440ustar00rootroot00000000000000require 'pry/module_candidate' class Pry class << self # If the given object is a `Pry::WrappedModule`, return it unaltered. If it's # anything else, return it wrapped in a `Pry::WrappedModule` instance. def WrappedModule(obj) if obj.is_a? Pry::WrappedModule obj else Pry::WrappedModule.new(obj) end end end class WrappedModule include Helpers::BaseHelpers include CodeObject::Helpers attr_reader :wrapped # Convert a string to a module. # # @param [String] mod_name # @param [Binding] target The binding where the lookup takes place. # @return [Module, nil] The module or `nil` (if conversion failed). # @example # Pry::WrappedModule.from_str("Pry::Code") def self.from_str(mod_name, target=TOPLEVEL_BINDING) if safe_to_evaluate?(mod_name, target) Pry::WrappedModule.new(target.eval(mod_name)) else nil end rescue RescuableException nil end class << self private # We use this method to decide whether code is safe to eval. Method's are # generally not, but everything else is. # TODO: is just checking != "method" enough?? # TODO: see duplication of this method in Pry::CodeObject # @param [String] str The string to lookup. # @param [Binding] target Where the lookup takes place. # @return [Boolean] def safe_to_evaluate?(str, target) return true if str.strip == "self" kind = target.eval("defined?(#{str})") kind =~ /variable|constant/ end end # @raise [ArgumentError] if the argument is not a `Module` # @param [Module] mod def initialize(mod) raise ArgumentError, "Tried to initialize a WrappedModule with a non-module #{mod.inspect}" unless ::Module === mod @wrapped = mod @memoized_candidates = [] @host_file_lines = nil @source = nil @source_location = nil @doc = nil end # Returns an array of the names of the constants accessible in the wrapped # module. This avoids the problem of accidentally calling the singleton # method `Module.constants`. # @param [Boolean] inherit Include the names of constants from included # modules? def constants(inherit = true) Module.instance_method(:constants).bind(@wrapped).call(inherit) end # The prefix that would appear before methods defined on this class. # # i.e. the "String." or "String#" in String.new and String#initialize. # # @return String def method_prefix if singleton_class? if Module === singleton_instance "#{WrappedModule.new(singleton_instance).nonblank_name}." else "self." end else "#{nonblank_name}#" end end # The name of the Module if it has one, otherwise #. # # @return [String] def nonblank_name if name.to_s == "" wrapped.inspect else name end end # Is this a singleton class? # @return [Boolean] def singleton_class? if Pry::Method.safe_send(wrapped, :respond_to?, :singleton_class?) Pry::Method.safe_send(wrapped, :singleton_class?) elsif defined?(Rubinius) # https://github.com/rubinius/rubinius/commit/2e71722dba53d1a92c54d5e3968d64d1042486fe singleton_class? added 30 Jul 2014 # https://github.com/rubinius/rubinius/commit/4310f6b2ef3c8fc88135affe697db4e29e4621c4 has been around since 2011 !!Rubinius::Type.singleton_class_object(wrapped) else wrapped != Pry::Method.safe_send(wrapped, :ancestors).first end end # Is this strictly a module? (does not match classes) # @return [Boolean] def module? wrapped.instance_of?(Module) end # Is this strictly a class? # @return [Boolean] def class? wrapped.instance_of?(Class) end # Get the instance associated with this singleton class. # # @raise ArgumentError: tried to get instance of non singleton class # # @return [Object] def singleton_instance raise ArgumentError, "tried to get instance of non singleton class" unless singleton_class? if Helpers::BaseHelpers.jruby? wrapped.to_java.attached else @singleton_instance ||= ObjectSpace.each_object(wrapped).detect{ |x| (class << x; self; end) == wrapped } end end # Forward method invocations to the wrapped module def method_missing(method_name, *args, &block) wrapped.send(method_name, *args, &block) end def respond_to?(method_name) super || wrapped.respond_to?(method_name) end # Retrieve the source location of a module. Return value is in same # format as Method#source_location. If the source location # cannot be found this method returns `nil`. # # @param [Module] mod The module (or class). # @return [Array, nil] The source location of the # module (or class), or `nil` if no source location found. def source_location @source_location ||= primary_candidate.source_location rescue Pry::RescuableException nil end # @return [String, nil] The associated file for the module (i.e # the primary candidate: highest ranked monkeypatch). def file Array(source_location).first end alias_method :source_file, :file # @return [Fixnum, nil] The associated line for the module (i.e # the primary candidate: highest ranked monkeypatch). def line Array(source_location).last end alias_method :source_line, :line # Returns documentation for the module. # This documentation is for the primary candidate, if # you would like documentation for other candidates use # `WrappedModule#candidate` to select the candidate you're # interested in. # @raise [Pry::CommandError] If documentation cannot be found. # @return [String] The documentation for the module. def doc @doc ||= primary_candidate.doc end # Returns the source for the module. # This source is for the primary candidate, if # you would like source for other candidates use # `WrappedModule#candidate` to select the candidate you're # interested in. # @raise [Pry::CommandError] If source cannot be found. # @return [String] The source for the module. def source @source ||= primary_candidate.source end # @return [String] Return the associated file for the # module from YARD, if one exists. def yard_file YARD::Registry.at(name).file if yard_docs? end # @return [Fixnum] Return the associated line for the # module from YARD, if one exists. def yard_line YARD::Registry.at(name).line if yard_docs? end # @return [String] Return the YARD docs for this module. def yard_doc YARD::Registry.at(name).docstring.to_s if yard_docs? end # Return a candidate for this module of specified rank. A `rank` # of 0 is equivalent to the 'primary candidate', which is the # module definition with the highest number of methods. A `rank` # of 1 is the module definition with the second highest number of # methods, and so on. Module candidates are necessary as modules # can be reopened multiple times and in multiple places in Ruby, # the candidate API gives you access to the module definition # representing each of those reopenings. # @raise [Pry::CommandError] If the `rank` is out of range. That # is greater than `number_of_candidates - 1`. # @param [Fixnum] rank # @return [Pry::WrappedModule::Candidate] def candidate(rank) @memoized_candidates[rank] ||= Candidate.new(self, rank) end # @return [Fixnum] The number of candidate definitions for the # current module. def number_of_candidates method_candidates.count end # @note On JRuby 1.9 and higher, in certain conditions, this method chucks # away its ability to be quick (when there are lots of monkey patches, # like in Rails). However, it should be efficient enough on other rubies. # @see https://github.com/jruby/jruby/issues/525 # @return [Enumerator, Array] on JRuby 1.9 and higher returns Array, on # other rubies returns Enumerator def candidates enum = Enumerator.new do |y| (0...number_of_candidates).each do |num| y.yield candidate(num) end end Pry::Helpers::BaseHelpers.jruby_19? ? enum.to_a : enum end # @return [Boolean] Whether YARD docs are available for this module. def yard_docs? !!(defined?(YARD) && YARD::Registry.at(name)) end # @param [Fixnum] times How far to travel up the ancestor chain. # @return [Pry::WrappedModule, nil] The wrapped module that is the # superclass. # When `self` is a `Module` then return the # nth ancestor, otherwise (in the case of classes) return the # nth ancestor that is a class. def super(times=1) return self if times.zero? if wrapped.is_a?(Class) sup = ancestors.select { |v| v.is_a?(Class) }[times] else sup = ancestors[times] end Pry::WrappedModule(sup) if sup end private # @return [Pry::WrappedModule::Candidate] The candidate with the # highest rank, that is the 'monkey patch' of this module with the # highest number of methods, which contains a source code line that # defines the module. It is considered the 'canonical' definition # for the module. In the absense of a suitable candidate, the # candidate of rank 0 will be returned, or a CommandError raised if # there are no candidates at all. def primary_candidate @primary_candidate ||= candidates.find { |c| c.file } || # This will raise an exception if there is no candidate at all. candidate(0) end # @return [Array>] The array of `Pry::Method` objects, # there are two associated with each candidate. The first is the 'base # method' for a candidate and it serves as the start point for # the search in uncovering the module definition. The second is # the last method defined for that candidate and it is used to # speed up source code extraction. def method_candidates @method_candidates ||= all_source_locations_by_popularity.map do |group| methods_sorted_by_source_line = group.last.sort_by(&:source_line) [methods_sorted_by_source_line.first, methods_sorted_by_source_line.last] end end # A helper method. def all_source_locations_by_popularity return @all_source_locations_by_popularity if @all_source_locations_by_popularity ims = all_relevant_methods_for(wrapped) @all_source_locations_by_popularity = ims.group_by { |v| Array(v.source_location).first }. sort_by do |path, methods| expanded = File.expand_path(path) load_order = $LOADED_FEATURES.index{ |file| expanded.end_with?(file) } [-methods.size, load_order || (1.0 / 0.0)] end end # We only want methods that have a non-nil `source_location`. We also # skip some spooky internal methods. # (i.e we skip `__class_init__` because it's an odd rbx specific thing that causes tests to fail.) # @return [Array] def all_relevant_methods_for(mod) methods = all_methods_for(mod).select(&:source_location). reject{ |x| x.name == '__class_init__' || method_defined_by_forwardable_module?(x) } return methods unless methods.empty? safe_send(mod, :constants).map do |const_name| if const = nested_module?(mod, const_name) all_relevant_methods_for(const) else [] end end.flatten end # Return all methods (instance methods and class methods) for a # given module. # @return [Array] def all_methods_for(mod) Pry::Method.all_from_obj(mod, false) + Pry::Method.all_from_class(mod, false) end def nested_module?(parent, name) return if safe_send(parent, :autoload?, name) child = safe_send(parent, :const_get, name) return unless Module === child return unless safe_send(child, :name) == "#{safe_send(parent, :name)}::#{name}" child end # Detect methods that are defined with `def_delegator` from the Forwardable # module. We want to reject these methods as they screw up module # extraction since the `source_location` for such methods points at forwardable.rb # TODO: make this more robust as valid user-defined files called # forwardable.rb are also skipped. def method_defined_by_forwardable_module?(method) method.source_location.first =~ /forwardable\.rb/ end # memoized lines for file def lines_for_file(file) @lines_for_file ||= {} if file == Pry.eval_path @lines_for_file[file] ||= Pry.line_buffer.drop(1) else @lines_for_file[file] ||= File.readlines(file) end end end end pry-0.10.3/multi_test_inside_docker.sh000077500000000000000000000006521260757071700200360ustar00rootroot00000000000000#!/bin/bash -e export ORIGINAL_PATH=$PATH function test { version=$1 export PATH=$ORIGINAL_PATH export GEM_HOME=/tmp/prytmp/$version export PATH=/opt/rubies/$version/bin:$GEM_HOME/bin:$PATH export RUBY_ROOT=/opt/rubies/$version if [ ! -f $GEM_HOME/bin/bundle ]; then gem install bundler --no-rdoc --no-ri fi bundle install --quiet rake test } for ruby in `ls /opt/rubies` do test $ruby || : done pry-0.10.3/pry.gemspec000066400000000000000000000014321260757071700146000ustar00rootroot00000000000000# -*- encoding: utf-8 -*- require File.expand_path('../lib/pry/version', __FILE__) Gem::Specification.new do |s| s.name = "pry" s.version = Pry::VERSION s.authors = ["John Mair (banisterfiend)", "Conrad Irwin", "Ryan Fitzgerald"] s.email = ["jrmair@gmail.com", "conrad.irwin@gmail.com", "rwfitzge@gmail.com"] s.summary = "An IRB alternative and runtime developer console" s.description = s.summary s.homepage = "http://pryrepl.org" s.licenses = ['MIT'] s.executables = ["pry"] s.require_paths = ["lib"] s.files = `git ls-files bin lib *.md LICENSE`.split("\n") s.add_dependency 'coderay', '~> 1.1.0' s.add_dependency 'slop', '~> 3.4' s.add_dependency 'method_source', '~> 0.8.1' s.add_development_dependency 'bundler', '~> 1.0' end pry-0.10.3/spec/000077500000000000000000000000001260757071700133535ustar00rootroot00000000000000pry-0.10.3/spec/Procfile000066400000000000000000000001541260757071700150410ustar00rootroot00000000000000# Run this with: # gem install foreman && foreman start -f spec/Procfile pryhere: sh -c '(cd ..; rake pry)' pry-0.10.3/spec/cli_spec.rb000066400000000000000000000041171260757071700154640ustar00rootroot00000000000000require_relative 'helper' describe Pry::Hooks do before do Pry::CLI.reset end describe "parsing options" do it 'should raise if no options defined' do expect { Pry::CLI.parse_options(["--nothing"]) }.to raise_error Pry::CLI::NoOptionsError end it "should remove args from ARGV by default" do argv = ['filename', '-v'] Pry::CLI.add_options do on :v, "Display the Pry version" do # irrelevant end end.parse_options(argv) argv.include?('-v').should == false end end describe "adding options" do it "should be able to add an option" do run = false Pry::CLI.add_options do on :optiontest, "A test option" do run = true end end.parse_options(["--optiontest"]) run.should == true end it "should be able to add multiple options" do run = false run2 = false Pry::CLI.add_options do on :optiontest, "A test option" do run = true end end.add_options do on :optiontest2, "Another test option" do run2 = true end end.parse_options(["--optiontest", "--optiontest2"]) run.should equal true run2.should equal true end end describe "processing options" do it "should be able to process an option" do run = false Pry::CLI.add_options do on :optiontest, "A test option" end.add_option_processor do |opts| run = true if opts.present?(:optiontest) end.parse_options(["--optiontest"]) run.should == true end it "should be able to process multiple options" do run = false run2 = false Pry::CLI.add_options do on :optiontest, "A test option" on :optiontest2, "Another test option" end.add_option_processor do |opts| run = true if opts.present?(:optiontest) end.add_option_processor do |opts| run2 = true if opts.present?(:optiontest2) end.parse_options(["--optiontest", "--optiontest2"]) run.should == true run2.should == true end end end pry-0.10.3/spec/code_object_spec.rb000066400000000000000000000175201260757071700171570ustar00rootroot00000000000000require_relative 'helper' describe Pry::CodeObject do describe "basic lookups" do before do @obj = Object.new def @obj.ziggy "a flight of scarlet pigeons thunders round my thoughts" end class ClassyWassy def piggy binding end end @p = Pry.new @p.binding_stack = [binding] end after do Object.remove_const(:ClassyWassy) end it 'should lookup methods' do m = Pry::CodeObject.lookup("@obj.ziggy", @p) m.is_a?(Pry::Method).should == true m.name.to_sym.should == :ziggy end it 'should lookup modules' do m = Pry::CodeObject.lookup("ClassyWassy", @p) m.is_a?(Pry::WrappedModule).should == true m.source.should =~ /piggy/ end it 'should lookup procs' do my_proc = proc { :hello } @p.binding_stack = [binding] m = Pry::CodeObject.lookup("my_proc", @p) m.is_a?(Pry::Method).should == true m.source.should =~ /hello/ end describe 'commands lookup' do before do @p = Pry.new @p.binding_stack = [binding] end it 'should return command class' do @p.commands.command "jeremy-jones" do "lobster" end m = Pry::CodeObject.lookup("jeremy-jones", @p) (m <= Pry::Command).should == true m.source.should =~ /lobster/ end describe "class commands" do before do class LobsterLady < Pry::ClassCommand match "lobster-lady" description "nada." def process "lobster" end end end after do Object.remove_const(:LobsterLady) end it 'should return Pry::ClassCommand class when looking up class command' do Pry.config.commands.add_command(LobsterLady) m = Pry::CodeObject.lookup("lobster-lady", @p) (m <= Pry::ClassCommand).should == true m.source.should =~ /class LobsterLady/ Pry.config.commands.delete("lobster-lady") end it 'should return Pry::WrappedModule when looking up command class directly (as a class, not as a command)' do Pry.config.commands.add_command(LobsterLady) m = Pry::CodeObject.lookup("LobsterLady", @p) m.is_a?(Pry::WrappedModule).should == true m.source.should =~ /class LobsterLady/ Pry.config.commands.delete("lobster-lady") end end it 'looks up commands by :listing name as well' do @p.commands.command /jeremy-.*/, "", :listing => "jeremy-baby" do "lobster" end m = Pry::CodeObject.lookup("jeremy-baby", @p) (m <= Pry::Command).should == true m.source.should =~ /lobster/ end it 'finds nothing when passing nil as the first argument' do Pry::CodeObject.lookup(nil, @p).should == nil end end it 'should lookup instance methods defined on classes accessed via local variable' do o = Class.new do def princess_bubblegum "mathematic!" end end @p.binding_stack = [binding] m = Pry::CodeObject.lookup("o#princess_bubblegum", @p) m.is_a?(Pry::Method).should == true m.source.should =~ /mathematic!/ end it 'should lookup class methods defined on classes accessed via local variable' do o = Class.new do def self.finn "4 realzies" end end @p.binding_stack = [binding] m = Pry::CodeObject.lookup("o.finn", @p) m.is_a?(Pry::Method).should == true m.source.should =~ /4 realzies/ end it 'should lookup the class of an object (when given a variable)' do moddy = ClassyWassy.new @p.binding_stack = [binding] m = Pry::CodeObject.lookup("moddy", @p) m.is_a?(Pry::WrappedModule).should == true m.source.should =~ /piggy/ end describe "inferring object from binding when lookup str is empty/nil" do before do @b1 = Pry.binding_for(ClassyWassy) @b2 = Pry.binding_for(ClassyWassy.new) end describe "infer module objects" do it 'should infer module object when binding self is a module' do ["", nil].each do |v| @p.binding_stack = [@b1] m = Pry::CodeObject.lookup(v, @p) m.is_a?(Pry::WrappedModule).should == true m.name.should =~ /ClassyWassy/ end end it 'should infer module object when binding self is an instance' do ["", nil].each do |v| @p.binding_stack = [@b2] m = Pry::CodeObject.lookup(v, @p) m.is_a?(Pry::WrappedModule).should == true m.name.should =~ /ClassyWassy/ end end end describe "infer method objects" do it 'should infer method object from binding when inside method context' do b = ClassyWassy.new.piggy ["", nil].each do |v| @p.binding_stack = [b] m = Pry::CodeObject.lookup(v, @p) m.is_a?(Pry::Method).should == true m.name.should =~ /piggy/ end end end end end describe "lookups with :super" do before do class MyClassyWassy; end class CuteSubclass < MyClassyWassy; end @p = Pry.new @p.binding_stack = [binding] end after do Object.remove_const(:MyClassyWassy) Object.remove_const(:CuteSubclass) end it 'should lookup original class with :super => 0' do m = Pry::CodeObject.lookup("CuteSubclass", @p, :super => 0) m.is_a?(Pry::WrappedModule).should == true m.wrapped.should == CuteSubclass end it 'should lookup immediate super class with :super => 1' do m = Pry::CodeObject.lookup("CuteSubclass", @p, :super => 1) m.is_a?(Pry::WrappedModule).should == true m.wrapped.should == MyClassyWassy end it 'should ignore :super parameter for commands' do p = Pry.new p.commands.command "jeremy-jones" do "lobster" end p.binding_stack = [binding] m = Pry::CodeObject.lookup("jeremy-jones", p, :super => 10) m.source.should =~ /lobster/ end end describe "precedence" do before do class ClassyWassy class Puff def tiggy end end def Puff end def piggy end end Object.class_eval do def ClassyWassy :ducky end end @p = Pry.new @p.binding_stack = [binding] end after do Object.remove_const(:ClassyWassy) Object.remove_method(:ClassyWassy) end it 'should look up classes before methods (at top-level)' do m = Pry::CodeObject.lookup("ClassyWassy", @p) m.is_a?(Pry::WrappedModule).should == true m.source.should =~ /piggy/ end it 'should look up methods before classes when ending in () (at top-level)' do m = Pry::CodeObject.lookup("ClassyWassy()", @p) m.is_a?(Pry::Method).should == true m.source.should =~ /ducky/ end it 'should look up classes before methods when namespaced' do m = Pry::CodeObject.lookup("ClassyWassy::Puff", @p) m.is_a?(Pry::WrappedModule).should == true m.source.should =~ /tiggy/ end it 'should look up locals before methods' do b = Pry.binding_for(ClassyWassy) b.eval("piggy = Puff.new") @p.binding_stack = [b] o = Pry::CodeObject.lookup("piggy", @p) o.is_a?(Pry::WrappedModule).should == true end # actually locals are never looked up (via co.default_lookup) when they're classes, it # just falls through to co.method_or_class it 'should look up classes before locals' do c = ClassyWassy @p.binding_stack = [binding] o = Pry::CodeObject.lookup("c", @p) o.is_a?(Pry::WrappedModule).should == true o.wrapped.should == ClassyWassy end end end pry-0.10.3/spec/code_spec.rb000066400000000000000000000154431260757071700156330ustar00rootroot00000000000000require_relative 'helper' describe Pry::Code do describe '.from_file' do should 'read lines from a file on disk' do Pry::Code.from_file('lib/pry.rb').length.should > 0 end should 'read lines from Pry\'s line buffer' do pry_eval ':hay_guys' Pry::Code.from_file('(pry)').grep(/:hay_guys/).length.should == 1 end should 'default to unknown' do temp_file('') do |f| Pry::Code.from_file(f.path).code_type.should == :unknown end end should 'check the extension' do temp_file('.c') do |f| Pry::Code.from_file(f.path).code_type.should == :c end end should 'raise an error if the file doesn\'t exist' do expect do Pry::Code.from_file('/knalkjsdnalsd/alkjdlkq') end.to raise_error MethodSource::SourceNotFoundError end should 'check for files relative to origin pwd' do Dir.chdir('spec') do |f| Pry::Code.from_file('spec/' + File.basename(__FILE__)).code_type.should == :ruby end end should 'check for Ruby files relative to origin pwd with `.rb` omitted' do Dir.chdir('spec') do |f| Pry::Code.from_file('spec/' + File.basename(__FILE__, '.*')).code_type.should == :ruby end end should 'find files that are relative to the current working directory' do Dir.chdir('spec') do |f| Pry::Code.from_file(File.basename(__FILE__)).code_type.should == :ruby end end describe 'find Ruby files relative to $LOAD_PATH' do before do $LOAD_PATH << 'spec/fixtures' end after do $LOAD_PATH.delete 'spec/fixtures' end it 'finds files with `.rb` extension' do Pry::Code.from_file('slinky.rb').code_type.should == :ruby end it 'finds files with `.rb` omitted' do Pry::Code.from_file('slinky').code_type.should == :ruby end it 'finds files in a relative directory with `.rb` extension' do Pry::Code.from_file('../helper.rb').code_type.should == :ruby end it 'finds files in a relative directory with `.rb` omitted' do Pry::Code.from_file('../helper').code_type.should == :ruby end it "doesn't confuse files with the same name, but without an extension" do Pry::Code.from_file('cat_load_path').code_type.should == :unknown end it "doesn't confuse files with the same name, but with an extension" do Pry::Code.from_file('cat_load_path.rb').code_type.should == :ruby end end end describe '.from_method' do should 'read lines from a method\'s definition' do m = Pry::Method.from_obj(Pry, :load_history) Pry::Code.from_method(m).length.should > 0 end end describe '#initialize' do before do @str = Pry::Helpers::CommandHelpers.unindent <<-CODE def hay :guys end CODE @array = ['def hay', ' :guys', 'end'] end should 'break a string into lines' do Pry::Code.new(@str).length.should == 3 end should 'accept an array' do Pry::Code.new(@array).length.should == 3 end it 'an array or string should produce an equivalent object' do Pry::Code.new(@str).should == Pry::Code.new(@array) end end describe 'filters and formatters' do before do @code = Pry::Code(Pry::Helpers::CommandHelpers.unindent <<-STR) class MyProgram def self.main puts 'Hello, world!' end end STR end describe 'filters' do describe '#between' do should 'work with an inclusive range' do @code = @code.between(1..3) @code.length.should == 3 @code.should =~ /\Aclass MyProgram/ @code.should =~ /world!'\Z/ end should 'default to an inclusive range' do @code = @code.between(3, 5) @code.length.should == 3 end should 'work with an exclusive range' do @code = @code.between(2...4) @code.length.should == 2 @code.should =~ /\A def self/ @code.should =~ /world!'\Z/ end should 'use real line numbers for positive indices' do @code = @code.after(3, 3) @code = @code.between(4, 4) @code.length.should == 1 @code.should =~ /\A end\Z/ end end describe '#before' do should 'work' do @code = @code.before(3, 1) @code.should =~ /\A def self\.main\Z/ end end describe '#around' do should 'work' do @code = @code.around(3, 1) @code.length.should == 3 @code.should =~ /\A def self/ @code.should =~ / end\Z/ end end describe '#after' do should 'work' do @code = @code.after(3, 1) @code.should =~ /\A end\Z/ end end describe '#grep' do should 'work' do @code = @code.grep(/end/) @code.length.should == 2 end end end describe 'formatters' do describe '#with_line_numbers' do should 'show line numbers' do @code = @code.with_line_numbers @code.should =~ /1:/ end should 'disable line numbers when falsy' do @code = @code.with_line_numbers @code = @code.with_line_numbers(false) @code.should_not =~ /1:/ end end describe '#with_marker' do should 'show a marker in the right place' do @code = @code.with_marker(2) @code.should =~ /^ => def self/ end should 'disable the marker when falsy' do @code = @code.with_marker(2) @code = @code.with_marker(false) @code.should =~ /^ def self/ end end describe '#with_indentation' do should 'indent the text' do @code = @code.with_indentation(2) @code.should =~ /^ def self/ end should 'disable the indentation when falsy' do @code = @code.with_indentation(2) @code = @code.with_indentation(false) @code.should =~ /^ def self/ end end end describe 'composition' do describe 'grep and with_line_numbers' do should 'work' do @code = @code.grep(/end/).with_line_numbers @code.should =~ /\A4: end/ @code.should =~ /5: end\Z/ end end describe 'grep and before and with_line_numbers' do should 'work' do @code = @code.grep(/e/).before(5, 5).with_line_numbers @code.should =~ /\A2: def self.main\n3:/ @code.should =~ /4: end\Z/ end end describe 'before and after' do should 'work' do @code = @code.before(4, 2).after(2) @code.should == " puts 'Hello, world!'" end end end end end pry-0.10.3/spec/command_helpers_spec.rb000066400000000000000000000014171260757071700200550ustar00rootroot00000000000000require_relative 'helper' describe Pry::Helpers::CommandHelpers do before do @helper = Pry::Helpers::CommandHelpers end describe "unindent" do it "should remove the same prefix from all lines" do @helper.unindent(" one\n two\n").should == "one\ntwo\n" end it "should not be phased by empty lines" do @helper.unindent(" one\n\n two\n").should == "one\n\ntwo\n" end it "should only remove a common prefix" do @helper.unindent(" one\n two\n").should == " one\ntwo\n" end it "should also remove tabs if present" do @helper.unindent("\tone\n\ttwo\n").should == "one\ntwo\n" end it "should ignore lines starting with --" do @helper.unindent(" one\n--\n two\n").should == "one\n--\ntwo\n" end end end pry-0.10.3/spec/command_integration_spec.rb000066400000000000000000000365201260757071700207410ustar00rootroot00000000000000require_relative 'helper' describe "commands" do before do @str_output = StringIO.new @o = Object.new # Shortcuts. They save a lot of typing. @bs1 = "Pad.bs1 = _pry_.binding_stack.dup" @bs2 = "Pad.bs2 = _pry_.binding_stack.dup" @bs3 = "Pad.bs3 = _pry_.binding_stack.dup" @self = "Pad.self = self" @command_tester = Pry::CommandSet.new do command "command1", "command 1 test" do output.puts "command1" end command "command2", "command 2 test" do |arg| output.puts arg end end Pad.bong = "bong" end after do Pad.clear Pry.reset_defaults end describe "alias_command" do it 'should make an aliasd command behave like its original' do set = Pry::CommandSet.new do command "test-command" do output.puts "testing 1, 2, 3" end alias_command "test-alias", "test-command" end pry_tester(:commands => set).tap do |t| t.eval('test-command').should == t.eval('test-alias') end end it 'should pass on arguments to original' do set = Pry::CommandSet.new do command "test-command" do |*args| output.puts "testing #{args.join(' ')}" end alias_command "test-alias", "test-command" end t = pry_tester(:commands => set) t.process_command "test-alias hello baby duck" t.last_output.should =~ /testing hello baby duck/ end it 'should pass option arguments to original' do set = Pry::CommandSet.new do import Pry::Commands alias_command "test-alias", "ls" end obj = Class.new { @x = 10 } t = pry_tester(obj, :commands => set) t.process_command "test-alias -i" t.last_output.should =~ /@x/ end it 'should pass option arguments to original with additional parameters' do set = Pry::CommandSet.new do import Pry::Commands alias_command "test-alias", "ls -M" end obj = Class.new { @x = Class.new { define_method(:plymouth) {} } } t = pry_tester(obj, :commands => set) t.process_command "test-alias @x" t.last_output.should =~ /plymouth/ end it 'should be able to alias a regex command' do set = Pry::CommandSet.new do command /du.k/ do output.puts "ducky" end alias_command "test-alias", "duck" end t = pry_tester(:commands => set) t.process_command "test-alias" t.last_output.should =~ /ducky/ end it 'should be able to make the alias a regex' do set = Pry::CommandSet.new do command /du.k/ do output.puts "ducky" end alias_command /test-ali.s/, "duck" end redirect_pry_io(InputTester.new("test-alias"), out1 = StringIO.new) do Pry.start self, :commands => set end out1.string.should =~ /ducky/ end end describe "Pry::Command#run" do it 'should allow running of commands with following whitespace' do set = Pry::CommandSet.new do import Pry::Commands command "test-run" do run "cd / " end end redirect_pry_io(InputTester.new("cd 1/2/3/4/5/6", @bs1, "test-run", @self, @bs2, "exit-all")) do Pry.start(@o, :commands => set) end Pad.bs1.size.should == 7 Pad.self.should == @o Pad.bs2.size.should == 1 end it 'should allow running of cd command when contained in a single string' do set = Pry::CommandSet.new do import Pry::Commands command "test-run" do run "cd /" end end redirect_pry_io(InputTester.new("cd 1/2/3/4/5/6", @bs1, "test-run", @self, @bs2, "exit-all")) do Pry.start(@o, :commands => set) end Pad.bs1.size.should == 7 Pad.self.should == @o Pad.bs2.size.should == 1 end it 'should allow running of cd command when split into array' do set = Pry::CommandSet.new do import Pry::Commands command "test-run" do run "cd", "/" end end redirect_pry_io(InputTester.new("cd 1/2/3/4/5/6", @bs1, "test-run", @self, @bs2, "exit-all")) do Pry.start(@o, :commands => set) end Pad.bs1.size.should == 7 Pad.self.should == @o Pad.bs2.size.should == 1 end it 'should run a command from within a command' do klass = Pry::CommandSet.new do command "v" do output.puts "v command" end command "run_v" do run "v" end end pry_tester(:commands => klass).eval('run_v').should =~ /v command/ end it 'should run a regex command from within a command' do klass = Pry::CommandSet.new do command /v(.*)?/ do |arg| output.puts "v #{arg}" end command "run_v" do run "vbaby" end end pry_tester(:commands => klass).eval('run_v').should =~ /v baby/ end it 'should run a command from within a command with arguments' do klass = Pry::CommandSet.new do command /v(\w+)/ do |arg1, arg2| output.puts "v #{arg1} #{arg2}" end command "run_v_explicit_parameter" do run "vbaby", "param" end command "run_v_embedded_parameter" do run "vbaby param" end end ["run_v_explicit_parameter", "run_v_embedded_parameter"].each do |cmd| pry_tester(:commands => klass).eval(cmd).should =~ /v baby param/ end end end describe "Pry#run_command" do it 'should run a command that modifies the passed in eval_string' do p = Pry.new(:output => @str_output) p.eval "def hello\npeter pan\n" p.run_command "amend-line !" p.eval_string.should =~ /def hello/ p.eval_string.should_not =~ /peter pan/ end it 'should run a command in the context of a session' do pry_tester(Object.new).tap do |t| t.eval "@session_ivar = 10", "_pry_.run_command('ls')" t.last_output.should =~ /@session_ivar/ end end end it 'should interpolate ruby code into commands' do set = Pry::CommandSet.new do command "hello", "", :keep_retval => true do |arg| arg end end pry_tester(:commands => set).eval('hello #{Pad.bong}').should =~ /bong/ end # bug fix for https://github.com/pry/pry/issues/170 it 'should not choke on complex string interpolation when checking if ruby code is a command' do redirect_pry_io(InputTester.new('/#{Regexp.escape(File.expand_path("."))}/'), @str_output) do pry end @str_output.string.should_not =~ /SyntaxError/ end it 'should NOT interpolate ruby code into commands if :interpolate => false' do set = Pry::CommandSet.new do command "hello", "", :keep_retval => true, :interpolate => false do |arg| arg end end pry_tester(:commands => set).eval('hello #{Pad.bong}'). should =~ /Pad\.bong/ end it 'should NOT try to interpolate pure ruby code (no commands) ' do # These should raise RuntimeError instead of NameError expect { pry_eval 'raise \'#{aggy}\'' }.to raise_error RuntimeError expect { pry_eval 'raise #{aggy}' }.to raise_error RuntimeError pry_eval('format \'#{my_var}\'').should == "\#{my_var}" end it 'should create a command with a space in its name zzz' do set = Pry::CommandSet.new do command "hello baby", "" do output.puts "hello baby command" end end pry_tester(:commands => set).eval('hello baby'). should =~ /hello baby command/ end it 'should create a command with a space in its name and pass an argument' do set = Pry::CommandSet.new do command "hello baby", "" do |arg| output.puts "hello baby command #{arg}" end end pry_tester(:commands => set).eval('hello baby john'). should =~ /hello baby command john/ end it 'should create a regex command and be able to invoke it' do set = Pry::CommandSet.new do command /hello(.)/, "" do c = captures.first output.puts "hello#{c}" end end pry_tester(:commands => set).eval('hello1').should =~ /hello1/ end it 'should create a regex command and pass captures into the args list before regular arguments' do set = Pry::CommandSet.new do command /hello(.)/, "" do |c1, a1| output.puts "hello #{c1} #{a1}" end end pry_tester(:commands => set).eval('hello1 baby').should =~ /hello 1 baby/ end it 'should create a regex command and interpolate the captures' do set = Pry::CommandSet.new do command /hello (.*)/, "" do |c1| output.puts "hello #{c1}" end end bong = "bong" pry_tester(binding, :commands => set).eval('hello #{bong}'). should =~ /hello bong/ end it 'should create a regex command and arg_string should be interpolated' do set = Pry::CommandSet.new do command /hello(\w+)/, "" do |c1, a1, a2, a3| output.puts "hello #{c1} #{a1} #{a2} #{a3}" end end bing = 'bing' bong = 'bong' bang = 'bang' pry_tester(binding, :commands => set). eval('hellojohn #{bing} #{bong} #{bang}'). should =~ /hello john bing bong bang/ end it 'if a regex capture is missing it should be nil' do set = Pry::CommandSet.new do command /hello(.)?/, "" do |c1, a1| output.puts "hello #{c1.inspect} #{a1}" end end pry_tester(:commands => set).eval('hello baby').should =~ /hello nil baby/ end it 'should create a command in a nested context and that command should be accessible from the parent' do pry_tester(Object.new).eval(*(<<-RUBY.split("\n"))).should =~ /instance variables:\s+@x/m @x = nil cd 7 _pry_.commands.instance_eval { command('bing') { |arg| run arg } } cd .. bing ls RUBY end it 'should define a command that keeps its return value' do klass = Pry::CommandSet.new do command "hello", "", :keep_retval => true do :kept_hello end end t = pry_tester(:commands => klass) t.eval("hello\n") t.last_command_result.should == :kept_hello end it 'should define a command that does NOT keep its return value' do klass = Pry::CommandSet.new do command "hello", "", :keep_retval => false do :kept_hello end end t = pry_tester(:commands => klass) t.eval("hello\n").should == '' t.last_command_result.should == Pry::Command::VOID_VALUE end it 'should define a command that keeps its return value even when nil' do klass = Pry::CommandSet.new do command "hello", "", :keep_retval => true do nil end end t = pry_tester(:commands => klass) t.eval("hello\n") t.last_command_result.should == nil end it 'should define a command that keeps its return value but does not return when value is void' do klass = Pry::CommandSet.new do command "hello", "", :keep_retval => true do void end end pry_tester(:commands => klass).eval("hello\n").empty?.should == true end it 'a command (with :keep_retval => false) that replaces eval_string with a valid expression should not have the expression value suppressed' do klass = Pry::CommandSet.new do command "hello", "" do eval_string.replace("6") end end output = StringIO.new redirect_pry_io(InputTester.new('def yo', 'hello'), output) do Pry.start self, :commands => klass end output.string.should =~ /6/ end it 'a command (with :keep_retval => true) that replaces eval_string with a valid expression should overwrite the eval_string with the return value' do klass = Pry::CommandSet.new do command "hello", "", :keep_retval => true do eval_string.replace("6") 7 end end pry_tester(:commands => klass).eval("def yo\nhello\n").should == 7 end it 'a command that return a value in a multi-line expression should clear the expression and return the value' do klass = Pry::CommandSet.new do command "hello", "", :keep_retval => true do 5 end end pry_tester(:commands => klass).eval("def yo\nhello\n").should == 5 end it 'should set the commands default, and the default should be overridable' do klass = Pry::CommandSet.new do command "hello" do output.puts "hello world" end end other_klass = Pry::CommandSet.new do command "goodbye", "" do output.puts "goodbye world" end end Pry.config.commands = klass pry_tester.eval("hello").should == "hello world\n" pry_tester(:commands => other_klass).eval("goodbye").should == "goodbye world\n" end it 'should inherit commands from Pry::Commands' do klass = Pry::CommandSet.new Pry::Commands do command "v" do end end klass.to_hash.include?("nesting").should == true klass.to_hash.include?("jump-to").should == true klass.to_hash.include?("cd").should == true klass.to_hash.include?("v").should == true end it 'should change description of a command using desc' do klass = Pry::CommandSet.new do import Pry::Commands end orig = klass["help"].description klass.instance_eval do desc "help", "blah" end commands = klass.to_hash commands["help"].description.should_not == orig commands["help"].description.should == "blah" end it 'should enable an inherited method to access opts and output and target, due to instance_exec' do klass = Pry::CommandSet.new do command "v" do output.puts "#{target.eval('self')}" end end child_klass = Pry::CommandSet.new klass do end mock_pry(Pry.binding_for('john'), "v", :print => proc {}, :commands => child_klass, :output => @str_output) @str_output.string.should == "john\n" end it 'should import commands from another command object' do klass = Pry::CommandSet.new do import_from Pry::Commands, "ls", "jump-to" end klass.to_hash.include?("ls").should == true klass.to_hash.include?("jump-to").should == true end it 'should delete some inherited commands when using delete method' do klass = Pry::CommandSet.new Pry::Commands do command "v" do end delete "show-doc", "show-method" delete "ls" end commands = klass.to_hash commands.include?("nesting").should == true commands.include?("jump-to").should == true commands.include?("cd").should == true commands.include?("v").should == true commands.include?("show-doc").should == false commands.include?("show-method").should == false commands.include?("ls").should == false end it 'should override some inherited commands' do klass = Pry::CommandSet.new Pry::Commands do command "jump-to" do output.puts "jump-to the music" end command "help" do output.puts "help to the music" end end t = pry_tester(:commands => klass) t.eval('jump-to').should == "jump-to the music\n" t.eval('help').should == "help to the music\n" end it 'should run a command with no parameter' do pry_tester(:commands => @command_tester).eval('command1'). should == "command1\n" end it 'should run a command with one parameter' do pry_tester(:commands => @command_tester).eval('command2 horsey'). should == "horsey\n" end end pry-0.10.3/spec/command_set_spec.rb000066400000000000000000000450401260757071700172060ustar00rootroot00000000000000require_relative 'helper' describe Pry::CommandSet do before do @set = Pry::CommandSet.new do import Pry::Commands end @ctx = { :target => binding, :command_set => @set, :pry_instance => Pry.new(output: StringIO.new) } end describe "[]=" do it "removes a command from the command set" do @set["help"].should_not == nil @set["help"] = nil @set["help"].should == nil expect { @set.run_command(TOPLEVEL_BINDING, "help") }.to raise_error Pry::NoCommandError end it "replaces a command" do old_help = @set["help"] @set["help"] = @set["pry-version"] @set["help"].should_not == old_help end it "rebinds the command with key" do @set["help-1"] = @set["help"] @set["help-1"].match.should == "help-1" end it "raises a TypeError when command is not a subclass of Pry::Command" do expect { @set["help"] = "hello" }.to raise_error TypeError end end it 'should call the block used for the command when it is called' do run = false @set.command 'foo' do run = true end @set.run_command @ctx, 'foo' run.should == true end it 'should pass arguments of the command to the block' do @set.command 'foo' do |*args| args.should == [1, 2, 3] end @set.run_command @ctx, 'foo', 1, 2, 3 end it 'should use the first argument as context' do ctx = @ctx @set.command 'foo' do self.context.should == ctx end @set.run_command @ctx, 'foo' end it 'should raise an error when calling an undefined command' do @set.command('foo') {} expect { @set.run_command @ctx, 'bar' }.to raise_error Pry::NoCommandError end it 'should be able to remove its own commands' do @set.command('foo') {} @set.delete 'foo' expect { @set.run_command @ctx, 'foo' }.to raise_error Pry::NoCommandError end it 'should be able to remove its own commands, by listing name' do @set.command(/^foo1/, 'desc', :listing => 'foo') {} @set.delete 'foo' expect { @set.run_command @ctx, /^foo1/ }.to raise_error Pry::NoCommandError end it 'should be able to import some commands from other sets' do run = false other_set = Pry::CommandSet.new do command('foo') { run = true } command('bar') {} end @set.import_from(other_set, 'foo') @set.run_command @ctx, 'foo' run.should == true expect { @set.run_command @ctx, 'bar' }.to raise_error Pry::NoCommandError end it 'should return command set after import' do run = false other_set = Pry::CommandSet.new do command('foo') { run = true } command('bar') {} end @set.import(other_set).should == @set end it 'should return command set after import_from' do run = false other_set = Pry::CommandSet.new do command('foo') { run = true } command('bar') {} end @set.import_from(other_set, 'foo').should == @set end it 'should be able to import some commands from other sets using listing name' do run = false other_set = Pry::CommandSet.new do command(/^foo1/, 'desc', :listing => 'foo') { run = true } end @set.import_from(other_set, 'foo') @set.run_command @ctx, /^foo1/ run.should == true end it 'should be able to import a whole set' do run = [] other_set = Pry::CommandSet.new do command('foo') { run << true } command('bar') { run << true } end @set.import other_set @set.run_command @ctx, 'foo' @set.run_command @ctx, 'bar' run.should == [true, true] end it 'should be able to import sets at creation' do run = false @set.command('foo') { run = true } Pry::CommandSet.new(@set).run_command @ctx, 'foo' run.should == true end it 'should set the descriptions of commands' do @set.command('foo', 'some stuff') {} @set['foo'].description.should == 'some stuff' end describe "aliases" do it 'should be able to alias command' do run = false @set.command('foo', 'stuff') { run = true } @set.alias_command 'bar', 'foo' @set['bar'].match.should == 'bar' @set['bar'].description.should == 'Alias for `foo`' @set.run_command @ctx, 'bar' run.should == true end it "should be able to alias command with command_prefix" do run = false begin @set.command('owl', 'stuff') { run = true } @set.alias_command 'owlet', 'owl' Pry.config.command_prefix = '%' @set['%owlet'].match.should == 'owlet' @set['%owlet'].description.should == 'Alias for `owl`' @set.run_command @ctx, 'owlet' run.should == true ensure Pry.config.command_prefix = '' end end it 'should inherit options from original command' do run = false @set.command('foo', 'stuff', :shellwords => true, :interpolate => false) { run = true } @set.alias_command 'bar', 'foo' @set['bar'].options[:shellwords].should == @set['foo'].options[:shellwords] @set['bar'].options[:interpolate].should == @set['foo'].options[:interpolate] # however some options should not be inherited @set['bar'].options[:listing].should_not == @set['foo'].options[:listing] @set['bar'].options[:listing].should == "bar" end it 'should be able to specify alias\'s description when aliasing' do run = false @set.command('foo', 'stuff') { run = true } @set.alias_command 'bar', 'foo', :desc => "tobina" @set['bar'].match.should == 'bar' @set['bar'].description.should == "tobina" @set.run_command @ctx, 'bar' run.should == true end it "should be able to alias a command by its invocation line" do run = false @set.command(/^foo1/, 'stuff', :listing => 'foo') { run = true } @set.alias_command 'bar', 'foo1' @set['bar'].match.should == 'bar' @set['bar'].description.should == 'Alias for `foo1`' @set.run_command @ctx, 'bar' run.should == true end it "should be able to specify options when creating alias" do run = false @set.command(/^foo1/, 'stuff', :listing => 'foo') { run = true } @set.alias_command /^b.r/, 'foo1', :listing => "bar" @set.to_hash[/^b.r/].options[:listing].should == "bar" end it "should set description to default if description parameter is nil" do run = false @set.command(/^foo1/, 'stuff', :listing => 'foo') { run = true } @set.alias_command "bar", 'foo1' @set["bar"].description.should == "Alias for `foo1`" end end it 'should be able to change the descriptions of commands' do @set.command('foo', 'bar') {} @set.desc 'foo', 'baz' @set['foo'].description.should == 'baz' end it 'should get the descriptions of commands' do @set.command('foo', 'bar') {} @set.desc('foo').should == 'bar' end it 'should get the descriptions of commands, by listing' do @set.command(/^foo1/, 'bar', :listing => 'foo') {} @set.desc('foo').should == 'bar' end it 'should return Pry::Command::VOID_VALUE for commands by default' do @set.command('foo') { 3 } @set.run_command(@ctx, 'foo').should == Pry::Command::VOID_VALUE end it 'should be able to keep return values' do @set.command('foo', '', :keep_retval => true) { 3 } @set.run_command(@ctx, 'foo').should == 3 end it 'should be able to keep return values, even if return value is nil' do @set.command('foo', '', :keep_retval => true) { nil } @set.run_command(@ctx, 'foo').should == nil end it 'should be able to have its own helpers' do @set.command('foo') { my_helper } @set.helpers { def my_helper; end } @set.run_command(@ctx, 'foo') Pry::Command.subclass('foo', '', {}, Module.new) .new({:target => binding}) .should_not(respond_to :my_helper) end it 'should not recreate a new helper module when helpers is called' do @set.command('foo') do my_helper my_other_helper end @set.helpers do def my_helper; end end @set.helpers do def my_other_helper; end end @set.run_command(@ctx, 'foo') end it 'should import helpers from imported sets' do imported_set = Pry::CommandSet.new do helpers do def imported_helper_method; end end end @set.import imported_set @set.command('foo') { imported_helper_method } @set.run_command(@ctx, 'foo') end it 'should import helpers even if only some commands are imported' do imported_set = Pry::CommandSet.new do helpers do def imported_helper_method; end end command('bar') {} end @set.import_from imported_set, 'bar' @set.command('foo') { imported_helper_method } @set.run_command(@ctx, 'foo') end it 'should provide a :listing for a command that defaults to its name' do @set.command 'foo', "" do;end @set['foo'].options[:listing].should == 'foo' end it 'should provide a :listing for a command that differs from its name' do @set.command 'foo', "", :listing => 'bar' do;end @set['foo'].options[:listing].should == 'bar' end it "should provide a 'help' command" do @ctx[:command_set] = @set @ctx[:output] = StringIO.new expect { @set.run_command(@ctx, 'help') }.to_not raise_error end describe "renaming a command" do it 'should be able to rename and run a command' do run = false @set.command('foo') { run = true } @set.rename_command('bar', 'foo') @set.run_command(@ctx, 'bar') run.should == true end it 'should accept listing name when renaming a command' do run = false @set.command('foo', "", :listing => 'love') { run = true } @set.rename_command('bar', 'love') @set.run_command(@ctx, 'bar') run.should == true end it 'should raise exception trying to rename non-existent command' do expect { @set.rename_command('bar', 'foo') }.to raise_error ArgumentError end it 'should make old command name inaccessible' do @set.command('foo') { } @set.rename_command('bar', 'foo') expect { @set.run_command(@ctx, 'foo') }.to raise_error Pry::NoCommandError end it 'should be able to pass in options when renaming command' do desc = "hello" listing = "bing" @set.command('foo') { } @set.rename_command('bar', 'foo', :description => desc, :listing => listing, :keep_retval => true) @set['bar'].description.should == desc @set['bar'].options[:listing].should == listing @set['bar'].options[:keep_retval].should == true end end describe "command decorators - before_command and after_command" do describe "before_command" do it 'should be called before the original command' do foo = [] @set.command('foo') { foo << 1 } @set.before_command('foo') { foo << 2 } @set.run_command(@ctx, 'foo') foo.should == [2, 1] end it 'should be called before the original command, using listing name' do foo = [] @set.command(/^foo1/, '', :listing => 'foo') { foo << 1 } @set.before_command('foo') { foo << 2 } @set.run_command(@ctx, /^foo1/) foo.should == [2, 1] end it 'should share the context with the original command' do @ctx[:target] = "test target string".__binding__ before_val = nil orig_val = nil @set.command('foo') { orig_val = target } @set.before_command('foo') { before_val = target } @set.run_command(@ctx, 'foo') before_val.should == @ctx[:target] orig_val.should == @ctx[:target] end it 'should work when applied multiple times' do foo = [] @set.command('foo') { foo << 1 } @set.before_command('foo') { foo << 2 } @set.before_command('foo') { foo << 3 } @set.before_command('foo') { foo << 4 } @set.run_command(@ctx, 'foo') foo.should == [4, 3, 2, 1] end end describe "after_command" do it 'should be called after the original command' do foo = [] @set.command('foo') { foo << 1 } @set.after_command('foo') { foo << 2 } @set.run_command(@ctx, 'foo') foo.should == [1, 2] end it 'should be called after the original command, using listing name' do foo = [] @set.command(/^foo1/, '', :listing => 'foo') { foo << 1 } @set.after_command('foo') { foo << 2 } @set.run_command(@ctx, /^foo1/) foo.should == [1, 2] end it 'should share the context with the original command' do @ctx[:target] = "test target string".__binding__ after_val = nil orig_val = nil @set.command('foo') { orig_val = target } @set.after_command('foo') { after_val = target } @set.run_command(@ctx, 'foo') after_val.should == @ctx[:target] orig_val.should == @ctx[:target] end it 'should determine the return value for the command' do @set.command('foo', 'bar', :keep_retval => true) { 1 } @set.after_command('foo') { 2 } @set.run_command(@ctx, 'foo').should == 2 end it 'should work when applied multiple times' do foo = [] @set.command('foo') { foo << 1 } @set.after_command('foo') { foo << 2 } @set.after_command('foo') { foo << 3 } @set.after_command('foo') { foo << 4 } @set.run_command(@ctx, 'foo') foo.should == [1, 2, 3, 4] end end describe "before_command and after_command" do it 'should work when combining both before_command and after_command' do foo = [] @set.command('foo') { foo << 1 } @set.after_command('foo') { foo << 2 } @set.before_command('foo') { foo << 3 } @set.run_command(@ctx, 'foo') foo.should == [3, 1, 2] end end end describe 'find_command' do it 'should find commands with the right string' do cmd = @set.command('rincewind'){ } @set.find_command('rincewind').should == cmd end it 'should not find commands with spaces before' do cmd = @set.command('luggage'){ } @set.find_command(' luggage').should == nil end it 'should find commands with arguments after' do cmd = @set.command('vetinari'){ } @set.find_command('vetinari --knock 3').should == cmd end it 'should find commands with names containing spaces' do cmd = @set.command('nobby nobbs'){ } @set.find_command('nobby nobbs --steal petty-cash').should == cmd end it 'should find command defined by regex' do cmd = @set.command(/(capt|captain) vimes/i){ } @set.find_command('Capt Vimes').should == cmd end it 'should find commands defined by regex with arguments' do cmd = @set.command(/(cpl|corporal) Carrot/i){ } @set.find_command('cpl carrot --write-home').should == cmd end it 'should not find commands by listing' do cmd = @set.command(/werewol(f|ve)s?/, 'only once a month', :listing => "angua"){ } @set.find_command('angua').should == nil end it 'should not find commands without command_prefix' do begin Pry.config.command_prefix = '%' cmd = @set.command('detritus'){ } @set.find_command('detritus').should == nil ensure Pry.config.command_prefix = '' end end it "should find commands that don't use the prefix" do begin Pry.config.command_prefix = '%' cmd = @set.command('colon', 'Sergeant Fred', :use_prefix => false){ } @set.find_command('colon').should == cmd ensure Pry.config.command_prefix = '' end end it "should find the command that has the longest match" do cmd = @set.command(/\.(.*)/){ } cmd2 = @set.command(/\.\|\|(.*)/){ } @set.find_command('.||').should == cmd2 end it "should find the command that has the longest name" do cmd = @set.command(/\.(.*)/){ } cmd2 = @set.command('.||'){ } @set.find_command('.||').should == cmd2 end end describe '.valid_command?' do it 'should be true for commands that can be found' do cmd = @set.command('archchancellor') @set.valid_command?('archchancellor of_the?(:University)').should == true end it 'should be false for commands that can\'' do @set.valid_command?('def monkey(ape)').should == false end it 'should not cause argument interpolation' do cmd = @set.command('hello') expect { @set.valid_command?('hello #{raise "futz"}') }.to_not raise_error end end describe '.process_line' do it 'should return Result.new(false) if there is no matching command' do result = @set.process_line('1 + 42') result.command?.should == false result.void_command?.should == false result.retval.should == nil end it 'should return Result.new(true, VOID) if the command is not keep_retval' do @set.create_command('mrs-cake') do def process; 42; end end result = @set.process_line('mrs-cake') result.command?.should == true result.void_command?.should == true result.retval.should == Pry::Command::VOID_VALUE end it 'should return Result.new(true, retval) if the command is keep_retval' do @set.create_command('magrat', 'the maiden', :keep_retval => true) do def process; 42; end end result = @set.process_line('magrat') result.command?.should == true result.void_command?.should == false result.retval.should == 42 end it 'should pass through context' do ctx = { :eval_string => "bloomers", :pry_instance => Object.new, :output => StringIO.new, :target => binding } @set.create_command('agnes') do define_method(:process) do eval_string.should == ctx[:eval_string] output.should == ctx[:output] target.should == ctx[:target] _pry_.should == ctx[:pry_instance] end end @set.process_line('agnes', ctx) end it 'should add command_set to context' do set = @set @set.create_command(/nann+y ogg+/) do define_method(:process) do command_set.should == set end end @set.process_line('nannnnnny oggggg') end end if defined?(Bond) describe '.complete' do it "should list all command names" do @set.create_command('susan'){ } @set.complete('sus').should.include 'susan ' end it "should delegate to commands" do @set.create_command('susan'){ def complete(search); ['--foo']; end } @set.complete('susan ').should == ['--foo'] end end end end pry-0.10.3/spec/command_spec.rb000066400000000000000000000573311260757071700163410ustar00rootroot00000000000000require_relative 'helper' describe "Pry::Command" do before do @set = Pry::CommandSet.new @set.import Pry::Commands end describe 'call_safely' do it 'should display a message if gems are missing' do cmd = @set.create_command "ford-prefect", "From a planet near Beetlegeuse", :requires_gem => %w(ghijkl) do # end mock_command(cmd, %w(hello world)).output.should =~ /install-command ford-prefect/ end it 'should abort early if arguments are required' do cmd = @set.create_command 'arthur-dent', "Doesn't understand Thursdays", :argument_required => true do # end expect { mock_command(cmd, %w()) }.to raise_error Pry::CommandError end it 'should return VOID without keep_retval' do cmd = @set.create_command 'zaphod-beeblebrox', "Likes pan-Galactic Gargle Blasters" do def process 3 end end mock_command(cmd).return.should == Pry::Command::VOID_VALUE end it 'should return the return value with keep_retval' do cmd = @set.create_command 'tricia-mcmillian', "a.k.a Trillian", :keep_retval => true do def process 5 end end mock_command(cmd).return.should == 5 end it 'should call hooks in the right order' do cmd = @set.create_command 'marvin', "Pained by the diodes in his left side" do def process output.puts 3 + args[0].to_i end end @set.before_command 'marvin' do |i| output.puts 2 + i.to_i end @set.before_command 'marvin' do |i| output.puts 1 + i.to_i end @set.after_command 'marvin' do |i| output.puts 4 + i.to_i end @set.after_command 'marvin' do |i| output.puts 5 + i.to_i end mock_command(cmd, %w(2)).output.should == "3\n4\n5\n6\n7\n" end # TODO: This strikes me as rather silly... it 'should return the value from the last hook with keep_retval' do cmd = @set.create_command 'slartibartfast', "Designs Fjords", :keep_retval => true do def process 22 end end @set.after_command 'slartibartfast' do 10 end mock_command(cmd).return.should == 10 end end describe 'help' do it 'should default to the description for blocky commands' do @set.command 'oolon-colluphid', "Raving Atheist" do # end mock_command(@set['help'], %w(oolon-colluphid), :command_set => @set).output.should =~ /Raving Atheist/ end it 'should use slop to generate the help for classy commands' do @set.create_command 'eddie', "The ship-board computer" do def options(opt) opt.banner "Over-cheerful, and makes a ticking noise." end end mock_command(@set['help'], %w(eddie), :command_set => @set).output.should =~ /Over-cheerful/ end it 'should provide --help for classy commands' do cmd = @set.create_command 'agrajag', "Killed many times by Arthur" do def options(opt) opt.on :r, :retaliate, "Try to get Arthur back" end end mock_command(cmd, %w(--help)).output.should =~ /--retaliate/ end it 'should provide a -h for classy commands' do cmd = @set.create_command 'zarniwoop', "On an intergalactic cruise, in his office." do def options(opt) opt.on :e, :escape, "Help zaphod escape the Total Perspective Vortex" end end mock_command(cmd, %w(--help)).output.should =~ /Total Perspective Vortex/ end it 'should use the banner provided' do cmd = @set.create_command 'deep-thought', "The second-best computer ever" do banner <<-BANNER Who's merest operational parameters, I am not worthy to compute. BANNER end mock_command(cmd, %w(--help)).output.should =~ /Who\'s merest/ end end describe 'context' do context = { :target => binding, :output => StringIO.new, :eval_string => "eval-string", :command_set => @set, :pry_instance => Pry.new } it 'should capture lots of stuff from the hash passed to new before setup' do cmd = @set.create_command 'fenchurch', "Floats slightly off the ground" do define_method(:setup) do self.context.should == context target.should == context[:target] target_self.should == context[:target].eval('self') output.should == context[:output] end define_method(:process) do eval_string.should == "eval-string" command_set.should == @set _pry_.should == context[:pry_instance] end end cmd.new(context).call end end describe 'classy api' do it 'should call setup, then subcommands, then options, then process' do cmd = @set.create_command 'rooster', "Has a tasty towel" do def setup output.puts "setup" end def subcommands(cmd) output.puts "subcommands" end def options(opt) output.puts "options" end def process output.puts "process" end end mock_command(cmd).output.should == "setup\nsubcommands\noptions\nprocess\n" end it 'should raise a command error if process is not overridden' do cmd = @set.create_command 'jeltz', "Commander of a Vogon constructor fleet" do def proccces # end end expect { mock_command(cmd) }.to raise_error Pry::CommandError end it 'should work if neither options, nor setup is overridden' do cmd = @set.create_command 'wowbagger', "Immortal, insulting.", :keep_retval => true do def process 5 end end mock_command(cmd).return.should == 5 end it 'should provide opts and args as provided by slop' do cmd = @set.create_command 'lintilla', "One of 800,000,000 clones" do def options(opt) opt.on :f, :four, "A numeric four", :as => Integer, :optional_argument => true end def process args.should == ['four'] opts[:f].should == 4 end end mock_command(cmd, %w(--four 4 four)) end it 'should allow overriding options after definition' do cmd = @set.create_command /number-(one|two)/, "Lieutenants of the Golgafrinchan Captain", :shellwords => false do command_options :listing => 'number-one' end cmd.command_options[:shellwords].should == false cmd.command_options[:listing].should == 'number-one' end it "should create subcommands" do cmd = @set.create_command 'mum', 'Your mum' do def subcommands(cmd) cmd.command :yell end def process opts.fetch_command(:blahblah).should == nil opts.fetch_command(:yell).present?.should == true end end mock_command(cmd, ['yell']) end it "should create subcommand options" do cmd = @set.create_command 'mum', 'Your mum' do def subcommands(cmd) cmd.command :yell do on :p, :person end end def process args.should == ['papa'] opts.fetch_command(:yell).present?.should == true opts.fetch_command(:yell).person?.should == true end end mock_command(cmd, %w|yell --person papa|) end it "should accept top-level arguments" do cmd = @set.create_command 'mum', 'Your mum' do def subcommands(cmd) cmd.on :yell end def process args.should == ['yell', 'papa', 'sonny', 'daughter'] end end mock_command(cmd, %w|yell papa sonny daughter|) end describe "explicit classes" do before do @x = Class.new(Pry::ClassCommand) do options :baby => :pig match /goat/ description "waaaninngggiiigygygygygy" end end it 'subclasses should inherit options, match and description from superclass' do k = Class.new(@x) k.options.should == @x.options k.match.should == @x.match k.description.should == @x.description end end end describe 'tokenize' do it 'should interpolate string with #{} in them' do cmd = @set.command 'random-dent' do |*args| args.should == ["3", "8"] end foo = 5 cmd.new(:target => binding).process_line 'random-dent #{1 + 2} #{3 + foo}' end it 'should not fail if interpolation is not needed and target is not set' do cmd = @set.command 'the-book' do |*args| args.should == ['--help'] end cmd.new.process_line 'the-book --help' end it 'should not interpolate commands with :interpolate => false' do cmd = @set.command 'thor', 'norse god', :interpolate => false do |*args| args.should == ['%(#{foo})'] end cmd.new.process_line 'thor %(#{foo})' end it 'should use shell-words to split strings' do cmd = @set.command 'eccentrica' do |*args| args.should == ['gallumbits', 'eroticon', '6'] end cmd.new.process_line %(eccentrica "gallumbits" 'erot''icon' 6) end it 'should split on spaces if shellwords is not used' do cmd = @set.command 'bugblatter-beast', 'would eat its grandmother', :shellwords => false do |*args| args.should == ['"of', 'traal"'] end cmd.new.process_line %(bugblatter-beast "of traal") end it 'should add captures to arguments for regex commands' do cmd = @set.command /perfectly (normal)( beast)?/i do |*args| args.should == ['Normal', ' Beast', '(honest!)'] end cmd.new.process_line %(Perfectly Normal Beast (honest!)) end end describe 'process_line' do it 'should check for command name collisions if configured' do old = Pry.config.collision_warning Pry.config.collision_warning = true cmd = @set.command 'frankie' do end frankie = 'boyle' output = StringIO.new cmd.new(:target => binding, :output => output).process_line %(frankie mouse) output.string.should =~ /command .* conflicts/ Pry.config.collision_warning = old end it 'should spot collision warnings on assignment if configured' do old = Pry.config.collision_warning Pry.config.collision_warning = true cmd = @set.command 'frankie' do end output = StringIO.new cmd.new(:target => binding, :output => output).process_line %(frankie = mouse) output.string.should =~ /command .* conflicts/ Pry.config.collision_warning = old end it "should set the commands' arg_string and captures" do cmd = @set.command /benj(ie|ei)/ do |*args| self.arg_string.should == "mouse" self.captures.should == ['ie'] args.should == ['ie', 'mouse'] end cmd.new.process_line %(benjie mouse) end it "should raise an error if the line doesn't match the command" do cmd = @set.command 'grunthos', 'the flatulent' expect { cmd.new.process_line %(grumpos) }.to raise_error Pry::CommandError end end describe "block parameters" do before do @context = Object.new @set.command "walking-spanish", "down the hall", :takes_block => true do PryTestHelpers.inject_var(:@x, command_block.call, target) end @set.import Pry::Commands @t = pry_tester(@context, :commands => @set) end it 'should accept multiline blocks' do @t.eval <<-EOS walking-spanish | do :jesus end EOS @context.instance_variable_get(:@x).should == :jesus end it 'should accept normal parameters along with block' do @set.block_command "walking-spanish", "litella's been screeching for a blind pig.", :takes_block => true do |x, y| PryTestHelpers.inject_var(:@x, x, target) PryTestHelpers.inject_var(:@y, y, target) PryTestHelpers.inject_var(:@block_var, command_block.call, target) end @t.eval 'walking-spanish john carl| { :jesus }' @context.instance_variable_get(:@x).should == "john" @context.instance_variable_get(:@y).should == "carl" @context.instance_variable_get(:@block_var).should == :jesus end describe "single line blocks" do it 'should accept blocks with do ; end' do @t.eval 'walking-spanish | do ; :jesus; end' @context.instance_variable_get(:@x).should == :jesus end it 'should accept blocks with do; end' do @t.eval 'walking-spanish | do; :jesus; end' @context.instance_variable_get(:@x).should == :jesus end it 'should accept blocks with { }' do @t.eval 'walking-spanish | { :jesus }' @context.instance_variable_get(:@x).should == :jesus end end describe "block-related content removed from arguments" do describe "arg_string" do it 'should remove block-related content from arg_string (with one normal arg)' do @set.block_command "walking-spanish", "down the hall", :takes_block => true do |x, y| PryTestHelpers.inject_var(:@arg_string, arg_string, target) PryTestHelpers.inject_var(:@x, x, target) end @t.eval 'walking-spanish john| { :jesus }' @context.instance_variable_get(:@arg_string).should == @context.instance_variable_get(:@x) end it 'should remove block-related content from arg_string (with no normal args)' do @set.block_command "walking-spanish", "down the hall", :takes_block => true do PryTestHelpers.inject_var(:@arg_string, arg_string, target) end @t.eval 'walking-spanish | { :jesus }' @context.instance_variable_get(:@arg_string).should == "" end it 'should NOT remove block-related content from arg_string when :takes_block => false' do block_string = "| { :jesus }" @set.block_command "walking-spanish", "homemade special", :takes_block => false do PryTestHelpers.inject_var(:@arg_string, arg_string, target) end @t.eval "walking-spanish #{block_string}" @context.instance_variable_get(:@arg_string).should == block_string end end describe "args" do describe "block_command" do it "should remove block-related content from arguments" do @set.block_command "walking-spanish", "glass is full of sand", :takes_block => true do |x, y| PryTestHelpers.inject_var(:@x, x, target) PryTestHelpers.inject_var(:@y, y, target) end @t.eval 'walking-spanish | { :jesus }' @context.instance_variable_get(:@x).should == nil @context.instance_variable_get(:@y).should == nil end it "should NOT remove block-related content from arguments if :takes_block => false" do @set.block_command "walking-spanish", "litella screeching for a blind pig", :takes_block => false do |x, y| PryTestHelpers.inject_var(:@x, x, target) PryTestHelpers.inject_var(:@y, y, target) end @t.eval 'walking-spanish | { :jesus }' @context.instance_variable_get(:@x).should == "|" @context.instance_variable_get(:@y).should == "{" end end describe "create_command" do it "should remove block-related content from arguments" do @set.create_command "walking-spanish", "punk sanders carved one out of wood", :takes_block => true do def process(x, y) PryTestHelpers.inject_var(:@x, x, target) PryTestHelpers.inject_var(:@y, y, target) end end @t.eval 'walking-spanish | { :jesus }' @context.instance_variable_get(:@x).should == nil @context.instance_variable_get(:@y).should == nil end it "should NOT remove block-related content from arguments if :takes_block => false" do @set.create_command "walking-spanish", "down the hall", :takes_block => false do def process(x, y) PryTestHelpers.inject_var(:@x, x, target) PryTestHelpers.inject_var(:@y, y, target) end end @t.eval 'walking-spanish | { :jesus }' @context.instance_variable_get(:@x).should == "|" @context.instance_variable_get(:@y).should == "{" end end end end describe "blocks can take parameters" do describe "{} style blocks" do it 'should accept multiple parameters' do @set.block_command "walking-spanish", "down the hall", :takes_block => true do PryTestHelpers.inject_var(:@x, command_block.call(1, 2), target) end @t.eval 'walking-spanish | { |x, y| [x, y] }' @context.instance_variable_get(:@x).should == [1, 2] end end describe "do/end style blocks" do it 'should accept multiple parameters' do @set.create_command "walking-spanish", "litella", :takes_block => true do def process PryTestHelpers.inject_var(:@x, command_block.call(1, 2), target) end end @t.eval <<-EOS walking-spanish | do |x, y| [x, y] end EOS @context.instance_variable_get(:@x).should == [1, 2] end end end describe "closure behaviour" do it 'should close over locals in the definition context' do @t.eval 'var = :hello', 'walking-spanish | { var }' @context.instance_variable_get(:@x).should == :hello end end describe "exposing block parameter" do describe "block_command" do it "should expose block in command_block method" do @set.block_command "walking-spanish", "glass full of sand", :takes_block => true do PryTestHelpers.inject_var(:@x, command_block.call, target) end @t.eval 'walking-spanish | { :jesus }' @context.instance_variable_get(:@x).should == :jesus end end describe "create_command" do it "should NOT expose &block in create_command's process method" do @set.create_command "walking-spanish", "down the hall", :takes_block => true do def process(&block) block.call end end @out = StringIO.new expect { @t.eval 'walking-spanish | { :jesus }' }.to raise_error(NoMethodError) end it "should expose block in command_block method" do @set.create_command "walking-spanish", "homemade special", :takes_block => true do def process PryTestHelpers.inject_var(:@x, command_block.call, target) end end @t.eval 'walking-spanish | { :jesus }' @context.instance_variable_get(:@x).should == :jesus end end end end describe "a command made with a custom sub-class" do before do class MyTestCommand < Pry::ClassCommand match /my-*test/ description 'So just how many sound technicians does it take to' \ 'change a lightbulb? 1? 2? 3? 1-2-3? Testing?' options :shellwords => false, :listing => 'my-test' def process output.puts command_name * 2 end end Pry.config.commands.add_command MyTestCommand end after do Pry.config.commands.delete 'my-test' end it "allows creation of custom subclasses of Pry::Command" do pry_eval('my---test').should =~ /my-testmy-test/ end it "shows the source of the process method" do pry_eval('show-source my-test').should =~ /output.puts command_name/ end describe "command options hash" do it "is always present" do options_hash = { :requires_gem => [], :keep_retval => false, :argument_required => false, :interpolate => true, :shellwords => false, :listing => 'my-test', :use_prefix => true, :takes_block => false } MyTestCommand.options.should == options_hash end describe ":listing option" do it "defaults to :match if not set explicitly" do class HappyNewYear < Pry::ClassCommand match 'happy-new-year' description 'Happy New Year 2013' end Pry.config.commands.add_command HappyNewYear HappyNewYear.options[:listing].should == 'happy-new-year' Pry.config.commands.delete 'happy-new-year' end it "can be set explicitly" do class MerryChristmas < Pry::ClassCommand match 'merry-christmas' description 'Merry Christmas!' command_options :listing => 'happy-holidays' end Pry.config.commands.add_command MerryChristmas MerryChristmas.options[:listing].should == 'happy-holidays' Pry.config.commands.delete 'merry-christmas' end it "equals to :match option's inspect, if :match is Regexp" do class CoolWinter < Pry::ClassCommand match(/.*winter/) description 'Is winter cool or cool?' end Pry.config.commands.add_command CoolWinter CoolWinter.options[:listing].should == '/.*winter/' Pry.config.commands.delete /.*winter/ end end end end describe "commands can save state" do before do @set = Pry::CommandSet.new do create_command "litella", "desc" do def process state.my_state ||= 0 state.my_state += 1 end end create_command "sanders", "desc" do def process state.my_state = "wood" end end create_command /[Hh]ello-world/, "desc" do def process state.my_state ||= 0 state.my_state += 2 end end end.import Pry::Commands @t = pry_tester(:commands => @set) end it 'should save state for the command on the Pry#command_state hash' do @t.eval 'litella' @t.pry.command_state["litella"].my_state.should == 1 end it 'should ensure state is maintained between multiple invocations of command' do @t.eval 'litella' @t.eval 'litella' @t.pry.command_state["litella"].my_state.should == 2 end it 'should ensure state with same name stored seperately for each command' do @t.eval 'litella', 'sanders' @t.pry.command_state["litella"].my_state.should == 1 @t.pry.command_state["sanders"].my_state.should =="wood" end it 'should ensure state is properly saved for regex commands' do @t.eval 'hello-world', 'Hello-world' @t.pry.command_state[/[Hh]ello-world/].my_state.should == 4 end end if defined?(Bond) describe 'complete' do it 'should return the arguments that are defined' do @set.create_command "torrid" do def options(opt) opt.on :test opt.on :lest opt.on :pests end end @set.complete('torrid ').should.include('--test ') end end end describe 'group' do before do @set.import( Pry::CommandSet.new do create_command("magic") { group("Not for a public use") } end ) end it 'should be correct for default commands' do @set["help"].group.should == "Help" end it 'should not change once it is initialized' do @set["magic"].group("-==CD COMMAND==-") @set["magic"].group.should == "Not for a public use" end it 'should not disappear after the call without parameters' do @set["magic"].group @set["magic"].group.should == "Not for a public use" end end end pry-0.10.3/spec/commands/000077500000000000000000000000001260757071700151545ustar00rootroot00000000000000pry-0.10.3/spec/commands/amend_line_spec.rb000066400000000000000000000121701260757071700206070ustar00rootroot00000000000000require_relative '../helper' describe "amend-line" do before do @t = pry_tester end it 'should amend the last line of input when no line number specified' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing STR @t.process_command 'amend-line puts :blah' @t.eval_string.should == unindent(<<-STR) def hello puts :blah STR end it 'should amend the specified line of input when line number given' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang STR @t.process_command 'amend-line 1 def goodbye' @t.eval_string.should == unindent(<<-STR) def goodbye puts :bing puts :bang STR end it 'should amend the first line of input when 0 given as line number' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang STR @t.process_command 'amend-line 0 def goodbye' @t.eval_string.should == unindent(<<-STR) def goodbye puts :bing puts :bang STR end it 'should amend a specified line when negative number given' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang STR @t.process_command 'amend-line -1 puts :bink' @t.eval_string.should == unindent(<<-STR) def hello puts :bing puts :bink STR @t.process_command 'amend-line -2 puts :bink' @t.eval_string.should == unindent(<<-STR) def hello puts :bink puts :bink STR end it 'should amend a range of lines of input when negative numbers given' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang puts :boat STR @t.process_command 'amend-line -3..-2 puts :bink' @t.eval_string.should == unindent(<<-STR) def hello puts :bink puts :boat STR end it 'should correctly amend the specified line with interpolated text' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang STR @t.process_command 'amend-line puts "#{goodbye}"' @t.eval_string.should == unindent(<<-'STR') def hello puts :bing puts "#{goodbye}" STR end it 'should display error if nothing to amend' do error = nil begin @t.process_command 'amend-line' rescue Pry::CommandError => e error = e end error.should_not equal nil error.message.should =~ /No input to amend/ end it 'should correctly amend the specified range of lines' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang puts :heart STR @t.process_command 'amend-line 2..3 puts :bong' @t.eval_string.should == unindent(<<-STR) def hello puts :bong puts :heart STR end it 'should correctly delete a specific line using the ! for content' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang puts :boast puts :heart STR @t.process_command 'amend-line 3 !' @t.eval_string.should == unindent(<<-STR) def hello puts :bing puts :boast puts :heart STR end it 'should correctly delete a range of lines using the ! for content' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang puts :boast puts :heart STR @t.process_command 'amend-line 2..4 !' @t.eval_string.should == unindent(<<-STR) def hello puts :heart STR end it 'should correctly delete the previous line using the ! for content' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang puts :boast puts :heart STR @t.process_command 'amend-line !' @t.eval_string.should == unindent(<<-STR) def hello puts :bing puts :bang puts :boast STR end it 'should amend the specified range of lines, with numbers < 0 in range' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang puts :boast puts :heart STR @t.process_command 'amend-line 2..-2 puts :bong' @t.eval_string.should == unindent(<<-STR) def hello puts :bong puts :heart STR end it 'should correctly insert a line before a specified line using >' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang STR @t.process_command 'amend-line 2 > puts :inserted' @t.eval_string.should == unindent(<<-STR) def hello puts :inserted puts :bing puts :bang STR end it 'should ignore second value of range with > syntax' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing puts :bang STR @t.process_command 'amend-line 2..21 > puts :inserted' @t.eval_string.should == unindent(<<-STR) def hello puts :inserted puts :bing puts :bang STR end end pry-0.10.3/spec/commands/bang_spec.rb000066400000000000000000000007451260757071700174300ustar00rootroot00000000000000require_relative '../helper' describe "!" do before do @t = pry_tester end it 'should correctly clear the input buffer ' do @t.push unindent(<<-STR) def hello puts :bing STR @t.process_command '!' @t.last_output.should =~ /Input buffer cleared!/ @t.eval_string.should == '' end it 'should not clear the input buffer for negation' do @t.push '! false' @t.last_output.should =~ /true/ @t.eval_string.should == '' end end pry-0.10.3/spec/commands/cat/000077500000000000000000000000001260757071700157235ustar00rootroot00000000000000pry-0.10.3/spec/commands/cat/file_formatter_spec.rb000066400000000000000000000060251260757071700222670ustar00rootroot00000000000000require_relative '../../helper' describe Pry::Command::Cat::FileFormatter do describe "#file_and_line" do before do @p = Pry.new @opt = Slop.new expect(Pry::Code).to receive(:from_file) end describe "windows filesystem" do it "should parse '/'style absolute path without line_num" do file_with_embedded_line = "C:/Ruby193/pry_instance.rb" ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt) file_name, line_num = ff.file_and_line file_name.should == "C:/Ruby193/pry_instance.rb" line_num.should == nil end it "should parse '/'style absolute path with line_num" do file_with_embedded_line = "C:/Ruby193/pry_instance.rb:2" ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt) file_name, line_num = ff.file_and_line file_name.should == "C:/Ruby193/pry_instance.rb" line_num.should == 2 end it "should parse '\\'style absolute path without line_num" do file_with_embedded_line = "C:\\Ruby193\\pry_instance.rb" ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt) file_name, line_num = ff.file_and_line file_name.should == "C:\\Ruby193\\pry_instance.rb" line_num.should == nil end it "should parse '\\'style absolute path with line_num" do file_with_embedded_line = "C:\\Ruby193\\pry_instance.rb:2" ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt) file_name, line_num = ff.file_and_line file_name.should == "C:\\Ruby193\\pry_instance.rb" line_num.should == 2 end end describe "UNIX-like filesystem" do it "should parse absolute path without line_num" do file_with_embedded_line = "/Ruby193/pry_instance.rb" ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt) file_name, line_num = ff.file_and_line file_name.should == "/Ruby193/pry_instance.rb" line_num.should == nil end it "should parse absolute path with line_num" do file_with_embedded_line = "/Ruby193/pry_instance.rb:2" ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt) file_name, line_num = ff.file_and_line file_name.should == "/Ruby193/pry_instance.rb" line_num.should == 2 end end it "should parse relative path without line_num" do file_with_embedded_line = "pry_instance.rb" ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt) file_name, line_num = ff.file_and_line file_name.should == "pry_instance.rb" line_num.should == nil end it "should parse relative path with line_num" do file_with_embedded_line = "pry_instance.rb:2" ff = Pry::Command::Cat::FileFormatter.new(file_with_embedded_line, @p, @opt) file_name, line_num = ff.file_and_line file_name.should == "pry_instance.rb" line_num.should == 2 end end end pry-0.10.3/spec/commands/cat_spec.rb000066400000000000000000000103331260757071700172620ustar00rootroot00000000000000require_relative '../helper' describe "cat" do before do @str_output = StringIO.new @t = pry_tester do def insert_nil_input @pry.update_input_history(nil) end def last_exception=(e) @pry.last_exception = e end end end describe "on receiving a file that does not exist" do it 'should display an error message' do expect { @t.eval 'cat supercalifragilicious66' }.to raise_error(StandardError, /Cannot open/) end end describe "with --in" do it 'should display the last few expressions with indices' do @t.eval('10', '20', 'cat --in').should == unindent(<<-STR) 1: 10 2: 20 STR end end describe "with --in 1" do it 'should display the first expression with no index' do @t.eval('10', '20', 'cat --in 1').should == "10\n" end end describe "with --in -1" do it 'should display the last expression with no index' do @t.eval('10', '20', 'cat --in -1').should == "20\n" end end describe "with --in 1..2" do it 'should display the given range with indices, omitting nils' do @t.eval '10' @t.insert_nil_input # normally happens when a command is executed @t.eval ':hello' @t.eval('cat --in 1..3').should == unindent(<<-EOS) 1: 10 3: :hello EOS end end # this doesnt work so well on rbx due to differences in backtrace # so we currently skip rbx until we figure out a workaround describe "with --ex" do before do @o = Object.new # this is to test exception code (cat --ex) def @o.broken_method this method is broken end end if !Pry::Helpers::BaseHelpers.rbx? it 'cat --ex should display repl code that generated exception' do @t.eval unindent(<<-EOS) begin this raises error rescue => e _pry_.last_exception = e end EOS @t.eval('cat --ex').should =~ /\d+:(\s*) this raises error/ end it 'cat --ex should correctly display code that generated exception' do begin @o.broken_method rescue => e @t.last_exception = e end @t.eval('cat --ex').should =~ /this method is broken/ end end end describe "with --ex N" do it 'should cat first level of backtrace when --ex used with no argument ' do temp_file do |f| f << "bt number 1" f.flush @t.last_exception = mock_exception("#{f.path}:1", 'x', 'x') @t.eval('cat --ex').should =~ /bt number 1/ end end it 'should cat first level of backtrace when --ex 0 used ' do temp_file do |f| f << "bt number 1" f.flush @t.last_exception = mock_exception("#{f.path}:1", 'x', 'x') @t.eval('cat --ex 0').should =~ /bt number 1/ end end it 'should cat second level of backtrace when --ex 1 used ' do temp_file do |f| f << "bt number 2" f.flush @t.last_exception = mock_exception('x', "#{f.path}:1", 'x') @t.eval('cat --ex 1').should =~ /bt number 2/ end end it 'should cat third level of backtrace when --ex 2 used' do temp_file do |f| f << "bt number 3" f.flush @t.last_exception = mock_exception('x', 'x', "#{f.path}:1") @t.eval('cat --ex 2').should =~ /bt number 3/ end end it 'should show error when backtrace level out of bounds' do @t.last_exception = mock_exception('x', 'x', 'x') expect { @t.eval('cat --ex 3') }.to raise_error(Pry::CommandError, /out of bounds/) end it 'each successive cat --ex should show the next level of backtrace, and going past the final level should return to the first' do temp_files = [] 3.times do |i| temp_files << Tempfile.new(['pry', '.rb']) temp_files.last << "bt number #{i}" temp_files.last.flush end @t.last_exception = mock_exception(*temp_files.map { |f| "#{f.path}:1" }) 3.times do |i| @t.eval('cat --ex').should =~ /bt number #{i}/ end @t.eval('cat --ex').should =~ /bt number 0/ temp_files.each do |file| file.close(true) end end end end pry-0.10.3/spec/commands/cd_spec.rb000066400000000000000000000151321260757071700171030ustar00rootroot00000000000000require_relative '../helper' describe 'cd' do before do @o, @obj = Object.new, Object.new @obj.instance_variable_set(:@x, 66) @obj.instance_variable_set(:@y, 79) @o.instance_variable_set(:@obj, @obj) @t = pry_tester(@o) do def assert_binding_stack(other) binding_stack.map { |b| b.eval('self') }.should == other end def binding_stack pry.binding_stack.dup end def command_state pry.command_state["cd"] end def old_stack pry.command_state['cd'].old_stack.dup end end end describe 'state' do it 'should not to be set up in fresh instance' do @t.command_state.should equal nil end end describe 'old stack toggling with `cd -`' do describe 'in fresh pry instance' do it 'should not toggle when there is no old stack' do 2.times do @t.eval 'cd -' @t.assert_binding_stack [@o] end end end describe 'when an error was raised' do it 'should not toggle and should keep correct stacks' do expect { @t.eval 'cd %' }.to raise_error Pry::CommandError @t.old_stack.should == [] @t.assert_binding_stack [@o] @t.eval 'cd -' @t.old_stack.should == [] @t.assert_binding_stack [@o] end end describe 'when using simple cd syntax' do it 'should toggle' do @t.eval 'cd :mon_dogg', 'cd -' @t.assert_binding_stack [@o] @t.eval 'cd -' @t.assert_binding_stack [@o, :mon_dogg] end end describe "when using complex cd syntax" do it 'should toggle with a complex path (simple case)' do @t.eval 'cd 1/2/3', 'cd -' @t.assert_binding_stack [@o] @t.eval 'cd -' @t.assert_binding_stack [@o, 1, 2, 3] end it 'should toggle with a complex path (more complex case)' do @t.eval 'cd 1/2/3', 'cd ../4', 'cd -' @t.assert_binding_stack [@o, 1, 2, 3] @t.eval 'cd -' @t.assert_binding_stack [@o, 1, 2, 4] end end describe 'series of cd calls' do it 'should toggle with fuzzy `cd -` calls' do @t.eval 'cd :mon_dogg', 'cd -', 'cd 42', 'cd -' @t.assert_binding_stack [@o] @t.eval 'cd -' @t.assert_binding_stack [@o, 42] end end describe 'when using cd ..' do it 'should toggle with a simple path' do @t.eval 'cd :john_dogg', 'cd ..' @t.assert_binding_stack [@o] @t.eval 'cd -' @t.assert_binding_stack [@o, :john_dogg] end it 'should toggle with a complex path' do @t.eval 'cd 1/2/3/../4', 'cd -' @t.assert_binding_stack [@o] @t.eval 'cd -' @t.assert_binding_stack [@o, 1, 2, 4] end end describe 'when using cd ::' do it 'should toggle' do @t.eval 'cd ::', 'cd -' @t.assert_binding_stack [@o] @t.eval 'cd -' @t.assert_binding_stack [@o, TOPLEVEL_BINDING.eval('self')] end end describe 'when using cd /' do it 'should toggle' do @t.eval 'cd /', 'cd -' @t.assert_binding_stack [@o] @t.eval 'cd :john_dogg', 'cd /', 'cd -' @t.assert_binding_stack [@o, :john_dogg] end end describe 'when using ^D (Control-D) key press' do it 'should keep correct old binding' do @t.eval 'cd :john_dogg', 'cd :mon_dogg', 'cd :kyr_dogg', 'Pry::DEFAULT_CONTROL_D_HANDLER.call("", _pry_)' @t.assert_binding_stack [@o, :john_dogg, :mon_dogg] @t.eval 'cd -' @t.assert_binding_stack [@o, :john_dogg, :mon_dogg, :kyr_dogg] @t.eval 'cd -' @t.assert_binding_stack [@o, :john_dogg, :mon_dogg] end end end it 'should cd into simple input' do @t.eval 'cd :mon_ouie' @t.eval('self').should == :mon_ouie end it 'should break out of session with cd ..' do @t.eval 'cd :outer', 'cd :inner' @t.eval('self').should == :inner @t.eval 'cd ..' @t.eval('self').should == :outer end it "should not leave the REPL session when given 'cd ..'" do @t.eval 'cd ..' @t.eval('self').should == @o end it 'should break out to outer-most session with cd /' do @t.eval 'cd :inner' @t.eval('self').should == :inner @t.eval 'cd 5' @t.eval('self').should == 5 @t.eval 'cd /' @t.eval('self').should == @o end it 'should break out to outer-most session with just cd (no args)' do @t.eval 'cd :inner' @t.eval('self').should == :inner @t.eval 'cd 5' @t.eval('self').should == 5 @t.eval 'cd' @t.eval('self').should == @o end it 'should cd into an object and its ivar using cd obj/@ivar syntax' do @t.eval 'cd @obj/@x' @t.assert_binding_stack [@o, @obj, 66] end it 'should cd into an object and its ivar using cd obj/@ivar/ syntax (note following /)' do @t.eval 'cd @obj/@x/' @t.assert_binding_stack [@o, @obj, 66] end it 'should cd into previous object and its local using cd ../local syntax' do @t.eval 'cd @obj', 'local = :local', 'cd @x', 'cd ../local' @t.assert_binding_stack [@o, @obj, :local] end it 'should cd into an object and its ivar and back again using cd obj/@ivar/.. syntax' do @t.eval 'cd @obj/@x/..' @t.assert_binding_stack [@o, @obj] end it 'should cd into an object and its ivar and back and then into another ivar using cd obj/@ivar/../@y syntax' do @t.eval 'cd @obj/@x/../@y' @t.assert_binding_stack [@o, @obj, 79] end it 'should cd back to top-level and then into another ivar using cd /@ivar/ syntax' do @t.eval '@z = 20', 'cd @obj/@x/', 'cd /@z' @t.assert_binding_stack [@o, 20] end it 'should start a session on TOPLEVEL_BINDING with cd ::' do @t.eval 'cd ::' @t.eval('self').should == TOPLEVEL_BINDING.eval('self') end it 'should cd into complex input (with spaces)' do def @o.hello(x, y, z) :mon_ouie end @t.eval 'cd hello 1, 2, 3' @t.eval('self').should == :mon_ouie end it 'should not cd into complex input when it encounters an exception' do expect { @t.eval 'cd 1/2/swoop_a_doop/3' }.to raise_error Pry::CommandError @t.assert_binding_stack [@o] end it 'can cd into an expression containing a string with slashes in it' do @t.eval 'cd ["http://google.com"]' @t.eval('self').should == ["http://google.com"] end it 'can cd into an expression with division in it' do @t.eval 'cd (10/2)/even?' @t.eval('self').should == false end # Regression test for ticket #516. it 'should be able to cd into the Object BasicObject' do expect { @t.eval 'cd BasicObject.new' }.to_not raise_error end end pry-0.10.3/spec/commands/disable_pry_spec.rb000066400000000000000000000007131260757071700210110ustar00rootroot00000000000000require_relative '../helper' describe "disable-pry" do before do @t = pry_tester end after do ENV.delete 'DISABLE_PRY' end it 'should quit the current session' do expect { @t.process_command 'disable-pry' }.to throw_symbol :breakout end it "should set DISABLE_PRY" do ENV['DISABLE_PRY'].should == nil expect { @t.process_command 'disable-pry' }.to throw_symbol :breakout ENV['DISABLE_PRY'].should == 'true' end end pry-0.10.3/spec/commands/edit_spec.rb000066400000000000000000000501001260757071700174340ustar00rootroot00000000000000require 'pathname' require_relative '../helper' describe "edit" do before do @old_editor = Pry.config.editor @file = @line = @contents = nil Pry.config.editor = lambda do |file, line| @file = file; @line = line; @contents = File.read(@file) nil end end after do Pry.config.editor = @old_editor end describe "with FILE" do before do # OS-specific tempdir name. For GNU/Linux it's "tmp", for Windows it's # something "Temp". @tf_dir = if Pry::Helpers::BaseHelpers.mri_19? Pathname.new(Dir::Tmpname.tmpdir) else Pathname.new(Dir.tmpdir) end @tf_path = File.expand_path(File.join(@tf_dir.to_s, 'bar.rb')) FileUtils.touch(@tf_path) end after do FileUtils.rm(@tf_path) if File.exists?(@tf_path) end it "should not allow patching any known kind of file" do ["file.rb", "file.c", "file.py", "file.yml", "file.gemspec", "/tmp/file", "\\\\Temp\\\\file"].each do |file| expect { pry_eval "edit -p #{file}" }.to raise_error(NotImplementedError, /Cannot yet patch false objects!/) end end it "should invoke Pry.config.editor with absolutified filenames" do pry_eval 'edit lib/pry.rb' @file.should == File.expand_path('lib/pry.rb') pry_eval "edit #@tf_path" @file.should == @tf_path end it "should guess the line number from a colon" do pry_eval 'edit lib/pry.rb:10' @line.should == 10 end it "should use the line number from -l" do pry_eval 'edit -l 10 lib/pry.rb' @line.should == 10 end it "should not delete the file!" do pry_eval 'edit Rakefile' File.exist?(@file).should == true end it "works with files that contain blanks in their names" do tf_path = File.join(File.dirname(@tf_path), 'swoop and doop.rb') FileUtils.touch(tf_path) pry_eval "edit #{ tf_path }" @file.should == tf_path FileUtils.rm(tf_path) end if respond_to?(:require_relative, true) it "should work with require relative" do Pry.config.editor = lambda { |file, line| File.open(file, 'w'){ |f| f << 'require_relative "baz.rb"' } File.open(file.gsub('bar.rb', 'baz.rb'), 'w'){ |f| f << "Pad.required = true; FileUtils.rm(__FILE__)" } if defined?(Rubinius::Compiler) File.unlink Rubinius::Compiler.compiled_name file end nil } pry_eval "edit #@tf_path" Pad.required.should == true end end describe do before do Pad.counter = 0 Pry.config.editor = lambda { |file, line| File.open(file, 'w') { |f| f << "Pad.counter = Pad.counter + 1" } nil } end it "should reload the file if it is a ruby file" do temp_file do |tf| counter = Pad.counter path = tf.path pry_eval "edit #{path}" Pad.counter.should == counter + 1 end end it "should not reload the file if it is not a ruby file" do temp_file('.py') do |tf| counter = Pad.counter path = tf.path pry_eval "edit #{path}" Pad.counter.should == counter end end it "should not reload a ruby file if -n is given" do temp_file do |tf| counter = Pad.counter path = tf.path Pad.counter.should == counter end end it "should reload a non-ruby file if -r is given" do temp_file('.pryrc') do |tf| counter = Pad.counter path = tf.path pry_eval "edit -r #{path}" Pad.counter.should == counter + 1 end end end describe do before do @reloading = nil Pry.config.editor = lambda do |file, line, reloading| @file = file; @line = line; @reloading = reloading nil end end it "should pass the editor a reloading arg" do pry_eval 'edit lib/pry.rb' @reloading.should == true pry_eval 'edit -n lib/pry.rb' @reloading.should == false end end end describe "with --ex" do before do @t = pry_tester do def last_exception=(exception) @pry.last_exception = exception end def last_exception; @pry.last_exception; end end end describe "with a real file" do before do @tf = Tempfile.new(["pry", ".rb"]) @path = @tf.path @tf << "1\n2\nraise RuntimeError" @tf.flush begin load @path rescue RuntimeError => e @t.last_exception = e end end after do @tf.close(true) File.unlink("#{@path}c") if File.exists?("#{@path}c") #rbx end it "should reload the file" do Pry.config.editor = lambda {|file, line| File.open(file, 'w'){|f| f << "FOO = 'BAR'" } if defined?(Rubinius::Compiler) File.unlink Rubinius::Compiler.compiled_name file end nil } defined?(FOO).should equal nil @t.eval 'edit --ex' FOO.should == 'BAR' end # regression test (this used to edit the current method instead # of the exception) it 'edits the exception even when in a patched method context' do source_location = nil Pry.config.editor = lambda {|file, line| source_location = [file, line] nil } Pad.le = @t.last_exception redirect_pry_io(InputTester.new("def broken_method", "binding.pry", "end", "broken_method", "_pry_.last_exception = Pad.le", "edit --ex -n", "exit-all", "exit-all")) do Object.new.pry end source_location.should == [@path, 3] Pad.clear end it "should not reload the file if -n is passed" do Pry.config.editor = lambda {|file, line| File.open(file, 'w'){|f| f << "FOO2 = 'BAZ'" } nil } defined?(FOO2).should equal nil @t.eval 'edit -n --ex' defined?(FOO2).should equal nil end describe "with --patch" do # Original source code must be untouched. it "should apply changes only in memory (monkey patching)" do Pry.config.editor = lambda {|file, line| File.open(file, 'w'){|f| f << "FOO3 = 'PIYO'" } @patched_def = File.open(file, 'r').read nil } defined?(FOO3).should equal nil @t.eval 'edit --ex --patch' FOO3.should == 'PIYO' @tf.rewind @tf.read.should == "1\n2\nraise RuntimeError" @patched_def.should == "FOO3 = 'PIYO'" end end end describe "with --ex NUM" do before do Pry.config.editor = proc do |file, line| @__ex_file__ = file @__ex_line__ = line nil end @t.last_exception = mock_exception('a:1', 'b:2', 'c:3') end it 'should start on first level of backtrace with just --ex' do @t.eval 'edit -n --ex' @__ex_file__.should == "a" @__ex_line__.should == 1 end it 'should start editor on first level of backtrace with --ex 0' do @t.eval 'edit -n --ex 0' @__ex_file__.should == "a" @__ex_line__.should == 1 end it 'should start editor on second level of backtrace with --ex 1' do @t.eval 'edit -n --ex 1' @__ex_file__.should == "b" @__ex_line__.should == 2 end it 'should start editor on third level of backtrace with --ex 2' do @t.eval 'edit -n --ex 2' @__ex_file__.should == "c" @__ex_line__.should == 3 end it 'should display error message when backtrace level is invalid' do expect { @t.eval 'edit -n --ex 4' }.to raise_error Pry::CommandError end end end describe "without FILE" do before do @t = pry_tester end it "should edit the current expression if it's incomplete" do @t.push 'def a' @t.process_command 'edit' @contents.should == "def a\n" end it "should edit the previous expression if the current is empty" do @t.eval 'def a; 2; end', 'edit' @contents.should == "def a; 2; end\n" end it "should use a blank file if -t is specified" do @t.eval 'def a; 5; end', 'edit -t' @contents.should == "\n" end it "should use a blank file if -t given, even during an expression" do @t.push 'def a;' @t.process_command 'edit -t' @contents.should == "\n" end it "should position the cursor at the end of the expression" do @t.eval "def a; 2;\nend" @t.process_command 'edit' @line.should == 2 end it "should evaluate the expression" do Pry.config.editor = lambda {|file, line| File.open(file, 'w'){|f| f << "'FOO'\n" } nil } @t.process_command 'edit' @t.eval_string.should == "'FOO'\n" end it "should ignore -n for tempfiles" do Pry.config.editor = lambda {|file, line| File.open(file, 'w'){|f| f << "'FOO'\n" } nil } @t.process_command "edit -n" @t.eval_string.should == "'FOO'\n" end it "should not evaluate a file with -n" do Pry.config.editor = lambda {|file, line| File.open(file, 'w'){|f| f << "'FOO'\n" } nil } begin @t.process_command 'edit -n spec/fixtures/foo.rb' File.read("spec/fixtures/foo.rb").should == "'FOO'\n" @t.eval_string.should == '' ensure FileUtils.rm "spec/fixtures/foo.rb" end end end describe "with --in" do it "should edit the nth line of _in_" do pry_eval '10', '11', 'edit --in -2' @contents.should == "10\n" end it "should edit the last line if no argument is given" do pry_eval '10', '11', 'edit --in' @contents.should == "11\n" end it "should edit a range of lines if a range is given" do pry_eval "10", "11", "edit -i 1,2" @contents.should == "10\n11\n" end it "should edit a multi-line expression as it occupies one line of _in_" do pry_eval "class Fixnum\n def invert; -self; end\nend", "edit -i 1" @contents.should == "class Fixnum\n def invert; -self; end\nend\n" end it "should not work with a filename" do expect { pry_eval 'edit ruby.rb -i' }.to raise_error(Pry::CommandError, /Only one of --ex, --temp, --in, --method and FILE/) end it "should not work with nonsense" do expect { pry_eval 'edit --in three' }.to raise_error(Pry::CommandError, /Not a valid range: three/) end end describe "old edit-method tests now migrated to edit" do describe "on a method defined in a file" do before do @tempfile = (Tempfile.new(['pry', '.rb'])) @tempfile.puts <<-EOS module A def a :yup end def b :kinda end end class X include A def self.x :double_yup end def x :nope end def b super end alias c b def y? :because end class B G = :nawt def foo :possibly G end end end EOS @tempfile.flush load @tempfile.path @tempfile_path = @tempfile.path end after do @tempfile.close(true) end describe 'without -p' do before do @file = @line = @contents = nil Pry.config.editor = lambda do |file, line| @file = file; @line = line nil end end it "should correctly find a class method" do pry_eval 'edit X.x' @file.should == @tempfile_path @line.should == 14 end it "should correctly find an instance method" do pry_eval 'edit X#x' @file.should == @tempfile_path @line.should == 18 end it "should correctly find a method on an instance" do pry_eval 'x = X.new', 'edit x.x' @file.should == @tempfile_path @line.should == 18 end it "should correctly find a method from a module" do pry_eval 'edit X#a' @file.should == @tempfile_path @line.should == 2 end it "should correctly find an aliased method" do pry_eval 'edit X#c' @file.should == @tempfile_path @line.should == 22 end end describe 'with -p' do before do Pry.config.editor = lambda do |file, line| lines = File.read(file).lines.to_a lines[1] = ":maybe\n" File.open(file, 'w') do |f| f.write(lines.join) end @patched_def = String(lines[1]).chomp nil end end it "should successfully replace a class method" do pry_eval 'edit -p X.x' class << X X.method(:x).owner.should == self end X.method(:x).receiver.should == X X.x.should == :maybe end it "should successfully replace an instance method" do pry_eval 'edit -p X#x' X.instance_method(:x).owner.should == X X.new.x.should == :maybe end it "should successfully replace a method on an instance" do pry_eval 'instance = X.new', 'edit -p instance.x' instance = X.new instance.method(:x).owner.should == X instance.x.should == :maybe end it "should successfully replace a method from a module" do pry_eval 'edit -p X#a' X.instance_method(:a).owner.should == A X.new.a.should == :maybe end it "should successfully replace a method with a question mark" do pry_eval 'edit -p X#y?' X.instance_method(:y?).owner.should == X X.new.y?.should == :maybe end it "should preserve module nesting" do pry_eval 'edit -p X::B#foo' X::B.instance_method(:foo).owner.should == X::B X::B.new.foo.should == :nawt end describe "monkey-patching" do before do @edit = 'edit --patch ' # A shortcut. end # @param [Integer] lineno # @return [String] the stripped line from the tempfile at +lineno+ def stripped_line_at(lineno) @tempfile.rewind @tempfile.lines.to_a[lineno].strip end # Applies the monkey patch for +method+ with help of evaluation of # +eval_strs+. The idea is to capture the initial line number (before # the monkey patch), because it gets overwritten by the line number from # the monkey patch. And our goal is to check that the original # definition hasn't changed. # @param [UnboundMethod] method # @param [Array] eval_strs # @return [Array e e.status.should == 66 else raise "Failed to raise SystemExit" end end end pry-0.10.3/spec/commands/exit_spec.rb000066400000000000000000000014541260757071700174700ustar00rootroot00000000000000require_relative '../helper' describe "exit" do before { @pry = Pry.new(:target => :outer, :output => StringIO.new) } it "should pop a binding" do @pry.eval "cd :inner" @pry.evaluate_ruby("self").should == :inner @pry.eval "exit" @pry.evaluate_ruby("self").should == :outer end it "should break out of the repl when binding_stack has only one binding" do @pry.eval("exit").should equal false @pry.exit_value.should equal nil end it "should break out of the repl and return user-given value" do @pry.eval("exit :john").should equal false @pry.exit_value.should == :john end it "should break out of the repl even after an exception" do @pry.eval "exit = 42" @pry.output.string.should =~ /^SyntaxError/ @pry.eval("exit").should equal false end end pry-0.10.3/spec/commands/find_method_spec.rb000066400000000000000000000031441260757071700207750ustar00rootroot00000000000000require_relative '../helper' describe "find-method" do MyKlass = Class.new do def hello "timothy" end def goodbye "jenny" end def tea_tim? "timothy" end def tea_time? "polly" end end describe "find matching methods by name regex (-n option)" do it "should find a method by regex" do pry_eval(binding, "find-method hell MyKlass").should =~ /MyKlass.*?hello/m end it "should NOT match a method that does not match the regex" do pry_eval(binding, "find-method hell MyKlass").should_not =~ /MyKlass.*?goodbye/m end end describe "find matching methods by content regex (-c option)" do it "should find a method by regex" do pry_eval(binding, "find-method -c timothy MyKlass").should =~ /MyKlass.*?hello/m end it "should NOT match a method that does not match the regex" do pry_eval(binding, "find-method timothy MyKlass").should_not =~ /MyKlass.*?goodbye/m end end it "should work with badly behaved constants" do MyKlass::X = Object.new def (MyKlass::X).hash raise "mooo" end pry_eval(binding, "find-method -c timothy MyKlass").should =~ /MyKlass.*?hello/m end it "should escape regexes correctly" do good = /tea_time\?/ bad = /tea_tim\?/ pry_eval(binding, 'find-method tea_time? MyKlass').should =~ good pry_eval(binding, 'find-method tea_time? MyKlass').should =~ good pry_eval(binding, 'find-method tea_time\? MyKlass').should_not =~ bad pry_eval(binding, 'find-method tea_time\? MyKlass').should =~ good end end pry-0.10.3/spec/commands/gem_list_spec.rb000066400000000000000000000010351260757071700203150ustar00rootroot00000000000000require_relative '../helper' describe "gem-list" do it 'should not raise when invoked' do expect { pry_eval(self, 'gem-list') }.to_not raise_error end it 'should work arglessly' do list = pry_eval('gem-list') list.should =~ /slop \(/ list.should =~ /rspec \(/ end it 'should find arg' do prylist = pry_eval('gem-list slop') prylist.should =~ /slop \(/ prylist.should_not =~ /rspec/ end it 'should return non-results as silence' do pry_eval('gem-list aoeuoueouaou').should be_empty end end pry-0.10.3/spec/commands/gist_spec.rb000066400000000000000000000014541260757071700174650ustar00rootroot00000000000000# These tests are out of date. # THey need to be updated for the new 'gist' API, but im too sleepy to # do that now. require_relative '../helper' describe 'gist' do it 'has a dependency on the jist gem' do Pry::Command::Gist.command_options[:requires_gem].should == "gist" end before do Pad.gist_calls = {} end # In absence of normal mocking, just monkeysmash these with no undoing after. module ::Gist class << self def login!; Pad.gist_calls[:login!] = true end def gist(*args) Pad.gist_calls[:gist_args] = args {'html_url' => 'http://gist.blahblah'} end def copy(content); Pad.gist_calls[:copy_args] = content end end end it 'nominally logs in' do pry_eval 'gist --login' Pad.gist_calls[:login!].should_not be_nil end end pry-0.10.3/spec/commands/help_spec.rb000066400000000000000000000031171260757071700174450ustar00rootroot00000000000000require_relative '../helper' describe "help" do before do @oldset = Pry.config.commands @set = Pry.config.commands = Pry::CommandSet.new do import Pry::Commands end end after do Pry.config.commands = @oldset end it 'should display help for a specific command' do pry_eval('help ls').should =~ /Usage: ls/ end it 'should display help for a regex command with a "listing"' do @set.command /bar(.*)/, "Test listing", :listing => "foo" do; end pry_eval('help foo').should =~ /Test listing/ end it 'should display help for a command with a spaces in its name' do @set.command "cmd with spaces", "desc of a cmd with spaces" do; end pry_eval('help "cmd with spaces"').should =~ /desc of a cmd with spaces/ end it 'should display help for all commands with a description' do @set.command /bar(.*)/, "Test listing", :listing => "foo" do; end @set.command "b", "description for b", :listing => "foo" do; end @set.command "c" do;end @set.command "d", "" do;end output = pry_eval('help') output.should =~ /Test listing/ output.should =~ /Description for b/ output.should =~ /No description/ end it "should sort the output of the 'help' command" do @set.command 'faa', "Fooerizes" do; end @set.command 'gaa', "Gooerizes" do; end @set.command 'maa', "Mooerizes" do; end @set.command 'baa', "Booerizes" do; end doc = pry_eval('help') order = [doc.index("baa"), doc.index("faa"), doc.index("gaa"), doc.index("maa")] order.should == order.sort end end pry-0.10.3/spec/commands/hist_spec.rb000066400000000000000000000130301260757071700174570ustar00rootroot00000000000000require_relative '../helper' describe "hist" do before do Pry.history.clear @hist = Pry.history @str_output = StringIO.new @t = pry_tester :history => @hist do # For looking at what hist pushes into the input stack. The implementation # of this helper will definitely have to change at some point. def next_input @pry.input.string end end end it 'should replay history correctly (single item)' do o = Object.new @hist.push "@x = 10" @hist.push "@y = 20" @hist.push "@z = 30" @t.push_binding o @t.eval 'hist --replay -1' o.instance_variable_get(:@z).should == 30 end it 'should replay a range of history correctly (range of items)' do o = Object.new @hist.push "@x = 10" @hist.push "@y = 20" @t.push_binding o @t.eval 'hist --replay 0..2' @t.eval('[@x, @y]').should == [10, 20] end # this is to prevent a regression where input redirection is # replaced by just appending to `eval_string` it 'should replay a range of history correctly (range of commands)' do o = Object.new @hist.push "cd 1" @hist.push "cd 2" @t.eval("hist --replay 0..2") stack = @t.eval("Pad.stack = _pry_.binding_stack.dup") stack.map{ |b| b.eval("self") }.should == [TOPLEVEL_BINDING.eval("self"), 1, 2] end it 'should grep for correct lines in history' do @hist.push "abby" @hist.push "box" @hist.push "button" @hist.push "pepper" @hist.push "orange" @hist.push "grape" @hist.push "def blah 1" @hist.push "def boink 2" @hist.push "place holder" @t.eval('hist --grep o').should =~ /\d:.*?box\n\d:.*?button\n\d:.*?orange/ # test more than one word in a regex match (def blah) @t.eval('hist --grep def blah').should =~ /def blah 1/ # test more than one word with leading white space in a regex match (def boink) @t.eval('hist --grep def boink').should =~ /def boink 2/ end it 'should return last N lines in history with --tail switch' do ("a".."z").each do |v| @hist.push v end out = @t.eval 'hist --tail 3' out.each_line.count.should == 3 out.should =~ /x\n\d+:.*y\n\d+:.*z/ end it "should start from beginning if tail number is longer than history" do @hist.push 'Hyacinth' out = @t.eval 'hist --tail' out.should =~ /Hyacinth/ end it 'should apply --tail after --grep' do @hist.push "print 1" @hist.push "print 2" @hist.push "puts 3" @hist.push "print 4" @hist.push "puts 5" out = @t.eval 'hist --tail 2 --grep print' out.each_line.count.should == 2 out.should =~ /\d:.*?print 2\n\d:.*?print 4/ end it 'should apply --head after --grep' do @hist.push "puts 1" @hist.push "print 2" @hist.push "puts 3" @hist.push "print 4" @hist.push "print 5" out = @t.eval 'hist --head 2 --grep print' out.each_line.count.should == 2 out.should =~ /\d:.*?print 2\n\d:.*?print 4/ end # strangeness in this test is due to bug in Readline::HISTORY not # always registering first line of input it 'should return first N lines in history with --head switch' do ("a".."z").each do |v| @hist.push v end out = @t.eval 'hist --head 4' out.each_line.count.should == 4 out.should =~ /a\n\d+:.*b\n\d+:.*c/ end # strangeness in this test is due to bug in Readline::HISTORY not # always registering first line of input it 'should show lines between lines A and B with the --show switch' do ("a".."z").each do |v| @hist.push v end out = @t.eval 'hist --show 1..4' out.each_line.count.should == 4 out.should =~ /b\n\d+:.*c\n\d+:.*d/ end it "should store a call with `--replay` flag" do @t.eval ":banzai" @t.eval "hist --replay 1" @t.eval("hist").should =~ /hist --replay 1/ end it "should not contain lines produced by `--replay` flag" do @t.eval ":banzai" @t.eval ":geronimo" @t.eval ":huzzah" @t.eval("hist --replay 1..3") output = @t.eval("hist") output.should == "1: :banzai\n2: :geronimo\n3: :huzzah\n4: hist --replay 1..3\n" end it "should raise CommandError when index of `--replay` points out to another `hist --replay`" do @t.eval ":banzai" @t.eval "hist --replay 1" expect { @t.eval "hist --replay 2" }.to raise_error(Pry::CommandError, /Replay index 2 points out to another replay call: `hist --replay 1`/) end it "should disallow execution of `--replay ` when CommandError raised" do @t.eval "a = 0" @t.eval "a += 1" @t.eval "hist --replay 2" expect { @t.eval "hist --replay 3" }.to raise_error Pry::CommandError @t.eval("a").should == 2 @t.eval("hist").lines.to_a.size.should == 5 end it "excludes Pry commands from the history with `-e` switch" do @hist.push('a = 20') @hist.push('ls') pry_eval('hist -e').should == "1: a = 20\n" end describe "sessions" do before do @old_file = Pry.config.history.file Pry.config.history.file = File.expand_path('spec/fixtures/pry_history') @hist.load end after do Pry.config.history.file = @old_file end it "displays history only for current session" do @hist.push('hello') @hist.push('world') @t.eval('hist').should =~ /1:\shello\n2:\sworld/ end it "displays all history (including the current sesion) with `--all` switch" do @hist.push('goodbye') @hist.push('world') output = @t.eval('hist --all') output.should =~ /1:\s:athos\n2:\s:porthos\n3:\s:aramis\n/ output.should =~ /4:\sgoodbye\n5:\sworld/ end end end pry-0.10.3/spec/commands/jump_to_spec.rb000066400000000000000000000007561260757071700202000ustar00rootroot00000000000000require_relative '../helper' describe "jump-to" do it 'should jump to the proper binding index in the stack' do pry_eval('cd 1', 'cd 2', 'jump-to 1', 'self').should == 1 end it 'should print error when trying to jump to a non-existent binding index' do pry_eval("cd 1", "cd 2", "jump-to 100").should =~ /Invalid nest level/ end it 'should print error when trying to jump to the same binding index' do pry_eval("cd 1", "cd 2", "jump-to 2").should =~ /Already/ end end pry-0.10.3/spec/commands/ls_spec.rb000066400000000000000000000203161260757071700171330ustar00rootroot00000000000000require_relative '../helper' describe "ls" do describe "below ceiling" do it "should stop before Object by default" do pry_eval("cd Class.new{ def goo; end }.new", "ls").should_not =~ /Object/ pry_eval("cd Class.new{ def goo; end }", "ls -M").should_not =~ /Object/ end it "should include object if -v is given" do pry_eval("cd Class.new{ def goo; end }.new", "ls -m -v").should =~ /Object/ pry_eval("cd Class.new{ def goo; end }", "ls -vM").should =~ /Object/ end it "should include super-classes by default" do pry_eval( "cd Class.new(Class.new{ def goo; end; public :goo }).new", "ls").should =~ /goo/ pry_eval( "cd Class.new(Class.new{ def goo; end; public :goo })", "ls -M").should =~ /goo/ end it "should not include super-classes when -q is given" do pry_eval("cd Class.new(Class.new{ def goo; end }).new", "ls -q").should_not =~ /goo/ pry_eval("cd Class.new(Class.new{ def goo; end })", "ls -M -q").should_not =~ /goo/ end end describe "help" do it 'should show help with -h' do pry_eval("ls -h").should =~ /Usage: ls/ end end describe "BasicObject" do it "should work on BasicObject" do pry_eval("ls BasicObject.new").should =~ /BasicObject#methods:.*__send__/m end it "should work on subclasses of BasicObject" do pry_eval( "class LessBasic < BasicObject; def jaroussky; 5; end; end", "ls LessBasic.new" ).should =~ /LessBasic#methods:.*jaroussky/m end end describe "immediates" do it "should work on Fixnum" do pry_eval("ls 5").should =~ /Fixnum#methods:.*modulo/m end end describe "methods" do it "should show public methods by default" do output = pry_eval("ls Class.new{ def goo; end; public :goo }.new") output.should =~ /methods: goo/ end it "should not show protected/private by default" do pry_eval("ls -M Class.new{ def goo; end; private :goo }").should_not =~ /goo/ pry_eval("ls Class.new{ def goo; end; protected :goo }.new").should_not =~ /goo/ end it "should show public methods with -p" do pry_eval("ls -p Class.new{ def goo; end }.new").should =~ /methods: goo/ end it "should show protected/private methods with -p" do pry_eval("ls -pM Class.new{ def goo; end; protected :goo }").should =~ /methods: goo/ pry_eval("ls -p Class.new{ def goo; end; private :goo }.new").should =~ /methods: goo/ end it "should work for objects with an overridden method method" do require 'net/http' # This doesn't actually touch the network, promise! pry_eval("ls Net::HTTP::Get.new('localhost')").should =~ /Net::HTTPGenericRequest#methods/ end it "should work for objects which instance_variables returns array of symbol but there is no Symbol#downcase" do test_case = "class Object; alias :fg :instance_variables; def instance_variables; fg.map(&:to_sym); end end;" normalize = "class Object; def instance_variables; fg; end end;" test = lambda do begin pry_eval(test_case, "class GeFromulate2; @flurb=1.3; end", "cd GeFromulate2", "ls") pry_eval(normalize) rescue pry_eval(normalize) raise end end expect(test).to_not raise_error end it "should show error message when instance is given with -M option" do expect { pry_eval("ls -M String.new") }.to raise_error(Pry::CommandError, /-M only makes sense with a Module or a Class/) end # see: https://travis-ci.org/pry/pry/jobs/5071918 unless Pry::Helpers::BaseHelpers.rbx? it "should handle classes that (pathologically) define .ancestors" do output = pry_eval("ls Class.new{ def self.ancestors; end; def hihi; end }") output.should =~ /hihi/ end end end describe 'with -l' do focus 'should find locals and sort by descending size' do result = pry_eval(Object.new, "aa = 'asdf'; bb = 'xyz'", 'ls -l') result.should_not =~ /=>/ result.should_not =~ /0x\d{5}/ result.should =~ /asdf.*xyz/m end it 'should not list pry noise' do pry_eval('ls -l').should_not =~ /_(?:dir|file|ex|pry|out|in)_/ end end describe "when inside Modules" do it "should still work" do pry_eval( "cd Module.new{ def foobie; end; public :foobie }", "ls -M").should =~ /foobie/ end it "should work for ivars" do pry_eval( "module StigmaT1sm; def foobie; @@gharble = 456; end; end", "Object.new.tap{ |o| o.extend(StigmaT1sm) }.foobie", "cd StigmaT1sm", "ls -i").should =~ /@@gharble/ end it "should include instance methods by default" do output = pry_eval( "ls Module.new{ def shinanagarns; 4; end; public :shinanagarns }") output.should =~ /shinanagarns/ end it "should behave normally when invoked on Module itself" do pry_eval("ls Module").should_not =~ /Pry/ end end describe "constants" do it "works on top-level" do toplevel_consts = pry_eval('ls -c') [/RUBY_PLATFORM/, /ARGF/, /STDOUT/].each do |const| toplevel_consts.should =~ const end end it "should show constants defined on the current module" do pry_eval("class TempFoo1; BARGHL = 1; end", "ls TempFoo1").should =~ /BARGHL/ end it "should not show constants defined on parent modules by default" do pry_eval("class TempFoo2; LHGRAB = 1; end; class TempFoo3 < TempFoo2; BARGHL = 1; end", "ls TempFoo3").should_not =~ /LHGRAB/ end it "should show constants defined on ancestors with -v" do pry_eval("class TempFoo4; LHGRAB = 1; end; class TempFoo5 < TempFoo4; BARGHL = 1; end", "ls -v TempFoo5").should =~ /LHGRAB/ end it "should not autoload constants!" do autoload :McflurgleTheThird, "/tmp/this-file-d000esnat-exist.rb" expect { pry_eval("ls -c") }.to_not raise_error end it "should show constants for an object's class regardless of mixins" do pry_eval( "cd Pry.new", "extend Module.new", "ls -c" ).should match(/Method/) end end describe "grep" do it "should reduce the number of outputted things" do pry_eval("ls -c Object").should =~ /ArgumentError/ pry_eval("ls -c Object --grep Run").should_not =~ /ArgumentError/ end it "should still output matching things" do pry_eval("ls -c Object --grep Run").should =~ /RuntimeError/ end end describe "when no arguments given" do describe "when at the top-level" do # rubinius has a bug that means local_variables of "main" aren't reported inside eval() unless Pry::Helpers::BaseHelpers.rbx? it "should show local variables" do pry_eval("ls").should =~ /_pry_/ pry_eval("arbitrar = 1", "ls").should =~ /arbitrar/ end end end describe "when in a class" do it "should show constants" do pry_eval("class GeFromulate1; FOOTIFICATE=1.3; end", "cd GeFromulate1", "ls").should =~ /FOOTIFICATE/ end it "should show class variables" do pry_eval("class GeFromulate2; @@flurb=1.3; end", "cd GeFromulate2", "ls").should =~ /@@flurb/ end it "should show methods" do pry_eval("class GeFromulate3; def self.mooflight; end ; end", "cd GeFromulate3", "ls").should =~ /mooflight/ end end describe "when in an object" do it "should show methods" do pry_eval("cd Class.new{ def self.fooerise; end; self }", "ls").should =~ /fooerise/ end it "should show instance variables" do pry_eval("cd Class.new", "@alphooent = 1", "ls").should =~ /@alphooent/ end end end if Pry::Helpers::BaseHelpers.jruby? describe 'on java objects' do it 'should omit java-esque aliases by default' do pry_eval('ls java.lang.Thread.current_thread').should =~ /\bthread_group\b/ pry_eval('ls java.lang.Thread.current_thread').should_not =~ /\bgetThreadGroup\b/ end it 'should include java-esque aliases if requested' do pry_eval('ls java.lang.Thread.current_thread -J').should =~ /\bthread_group\b/ pry_eval('ls java.lang.Thread.current_thread -J').should =~ /\bgetThreadGroup\b/ end end end end pry-0.10.3/spec/commands/play_spec.rb000066400000000000000000000107311260757071700174620ustar00rootroot00000000000000# This command needs a TONNE more tests for it, but i can't figure out # how to do them yet, and i really want to release. Sorry. Someone # come along and do a better job. require_relative '../helper' describe "play" do before do @o = Object.new @t = pry_tester(@o) end describe "with an argument" do # can't think of a f*cking way to test this!! describe "implied file" do # it 'should play from the file associated with the current binding' do # # require 'fixtures/play_helper' # end # describe "integer" do # it "should process one line from _pry_.last_file" do # @t.process_command 'play --lines 1', @eval_str # @eval_str.should =~ /bing = :bing\n/ # end # end # describe "range" do # it "should process multiple lines at once from _pry_.last_file" do # @t.process_command 'play --lines 1..3', @eval_str # [/bing = :bing\n/, /bang = :bang\n/, /bong = :bong\n/].each { |str| # @eval_str.should =~ str # } # end end end describe "playing a file" do it 'should play a file' do @t.process_command 'play spec/fixtures/whereami_helper.rb' @t.eval_string.should == unindent(<<-STR) class Cor def a; end def b; end def c; end def d; end end STR end it 'should output file contents with print option' do @t.process_command 'play --print spec/fixtures/whereami_helper.rb' @t.last_output.should == unindent(<<-STR) 1: class Cor 2: def a; end 3: def b; end 4: def c; end 5: def d; end 6: end STR end end describe "whatever" do before do def @o.test_method :test_method_content end end it 'should play documentation with the -d switch' do # @v = 10 # @y = 20 def @o.test_method :test_method_content end @t.process_command 'play -d test_method' @t.eval_string.should == unindent(<<-STR) @v = 10 @y = 20 STR end it 'should restrict -d switch with --lines' do # @x = 0 # @v = 10 # @y = 20 # @z = 30 def @o.test_method :test_method_content end @t.process_command 'play -d test_method --lines 2..3' @t.eval_string.should == unindent(<<-STR) @v = 10 @y = 20 STR end it 'has pretty error messages when -d cant find object' do expect { @t.process_command "play -d sdfsdf" }.to raise_error(Pry::CommandError, /Cannot locate/) end it 'should play a method (a single line)' do @t.process_command 'play test_method --lines 2' @t.eval_string.should == ":test_method_content\n" end it 'should properly reindent lines' do def @o.test_method 'hello world' end @t.process_command 'play test_method --lines 2' @t.eval_string.should == "'hello world'\n" end it 'should APPEND to the input buffer when playing a method line, not replace it' do @t.eval_string = unindent(<<-STR) def another_test_method STR @t.process_command 'play test_method --lines 2' @t.eval_string.should == unindent(<<-STR) def another_test_method :test_method_content STR end it 'should play a method (multiple lines)' do def @o.test_method @var0 = 10 @var1 = 20 @var2 = 30 @var3 = 40 end @t.process_command 'play test_method --lines 3..4' @t.eval_string.should == unindent(<<-STR, 0) @var1 = 20 @var2 = 30 STR end describe "play -i" do it 'should play multi-ranged input expressions' do a = b = c = d = e = 0 redirect_pry_io(InputTester.new('a += 1', 'b += 1', 'c += 1', 'd += 1', 'e += 1', "play -i 1..3"), StringIO.new) do binding.pry end [a, b, c].all? { |v| v.should == 2 } d.should == 1 end end describe "play -e" do it 'should run an expression from given line number' do def @o.test_method @s = [ 1,2,3, 4,5,6 ] end @t.process_command 'play test_method -e 2' @t.eval_string.should == unindent(<<-STR, 0) @s = [ 1,2,3, 4,5,6 ] STR end end end end pry-0.10.3/spec/commands/raise_up_spec.rb000066400000000000000000000035451260757071700203310ustar00rootroot00000000000000require_relative '../helper' describe "raise-up" do before do @self = "Pad.self = self" @inner = "Pad.inner = self" @outer = "Pad.outer = self" end after do Pad.clear end it "should raise the exception with raise-up" do redirect_pry_io(InputTester.new("raise NoMethodError", "raise-up NoMethodError")) do expect { Object.new.pry }.to raise_error NoMethodError end end it "should raise an unamed exception with raise-up" do redirect_pry_io(InputTester.new("raise 'stop'","raise-up 'noreally'")) do expect { Object.new.pry }.to raise_error(RuntimeError, "noreally") end end it "should eat the exception at the last new pry instance on raise-up" do redirect_pry_io(InputTester.new(":inner.pry", "raise NoMethodError", @inner, "raise-up NoMethodError", @outer, "exit-all")) do Pry.start(:outer) end Pad.inner.should == :inner Pad.outer.should == :outer end it "should raise the most recently raised exception" do expect { mock_pry("raise NameError, 'homographery'","raise-up") }.to raise_error(NameError, 'homographery') end it "should allow you to cd up and (eventually) out" do redirect_pry_io(InputTester.new("cd :inner", "raise NoMethodError", @inner, "deep = :deep", "cd deep","Pad.deep = self", "raise-up NoMethodError", "raise-up", @outer, "raise-up", "exit-all")) do expect { Pry.start(:outer) }.to raise_error NoMethodError end Pad.deep.should == :deep Pad.inner.should == :inner Pad.outer.should == :outer end it "should jump immediately out of nested contexts with !" do expect { mock_pry("cd 1", "cd 2", "cd 3", "raise-up! 'fancy that...'") }.to raise_error(RuntimeError, 'fancy that...') end end pry-0.10.3/spec/commands/reload_code_spec.rb000066400000000000000000000010661260757071700207560ustar00rootroot00000000000000require_relative '../helper' describe "reload_code" do describe "reload_current_file" do it 'raises an error source code not found' do expect do eval <<-RUBY, TOPLEVEL_BINDING, 'does_not_exist.rb', 1 pry_eval(binding, "reload-code") RUBY end.to raise_error(Pry::CommandError) end it 'raises an error when class not found' do expect do pry_eval( "cd Class.new(Class.new{ def goo; end; public :goo })", "reload-code") end.to raise_error(Pry::CommandError) end end end pry-0.10.3/spec/commands/save_file_spec.rb000066400000000000000000000122121260757071700204460ustar00rootroot00000000000000require_relative '../helper' describe "save-file" do before do @tf = Tempfile.new(["pry", ".py"]) @path = @tf.path @t = pry_tester end after do @tf.close(true) end describe "-f" do it 'should save a file to a file' do temp_file do |f| path = f.path f.puts ":cute_horse" f.flush @t.eval("save-file '#{path}' --to '#{@path}'") File.read(@path).should == File.read(path) end end end describe "-i" do it 'should save input expressions to a file (single expression)' do @t.eval ':horse_nostrils' @t.eval "save-file -i 1 --to '#{@path}'" File.read(@path).should == ":horse_nostrils\n" end it "should display a success message on save" do @t.eval ':horse_nostrils' @t.eval("save-file -i 1 --to '#{@path}'").should =~ /successfully saved/ end it 'should save input expressions to a file (range)' do @t.eval ':or_nostrils', ':sucking_up_all_the_oxygen', ':or_whatever' @t.eval "save-file -i 1..2 --to '#{@path}'" File.read(@path).should == ":or_nostrils\n:sucking_up_all_the_oxygen\n" end it 'should save multi-ranged input expressions' do @t.eval ':or_nostrils', ':sucking_up_all_the_oxygen', ':or_whatever', ':baby_ducks', ':cannot_escape' @t.eval "save-file -i 1..2 -i 4..5 --to '#{@path}'" File.read(@path).should == ":or_nostrils\n:sucking_up_all_the_oxygen\n:baby_ducks\n:cannot_escape\n" end end describe "saving methods" do before do @o = Object.new def @o.baby :baby end def @o.bang :bang end @t = pry_tester(@o) end describe "single method" do it 'should save a method to a file' do @t.eval "save-file --to '#{@path}' baby" File.read(@path).should == Pry::Method.from_obj(@o, :baby).source end it "should display a success message on save" do @t.eval("save-file --to '#{@path}' baby").should =~ /successfully saved/ end it 'should save a method to a file truncated by --lines' do @t.eval "save-file --to '#{@path}' baby --lines 2..4" # must add 1 as first line of method is 1 File.read(@path).should == Pry::Method.from_obj(@o, :baby).source.lines.to_a[1..5].join end end # TODO: do we want to reintroduce this spec?? # # describe "multiple method" do # it 'should save multiple methods to a file' do # @t.eval "save-file #{@path} -m baby -m bang" # File.read(@path).should == Pry::Method.from_obj(@o, :baby).source + # Pry::Method.from_obj(@o, :bang).source # end # it 'should save multiple methods to a file trucated by --lines' do # @t.eval "save-file #{@path} -m baby -m bang --lines 2..-2" # # must add 1 as first line of method is 1 # File.read(@path).should == (Pry::Method.from_obj(@o, :baby).source + # Pry::Method.from_obj(@o, :bang).source).lines.to_a[1..-2].join # end # it 'should save multiple methods to a file trucated by --lines 1 ' \ # '(single parameter, not range)' do # @t.eval "save-file #{@path} -m baby -m bang --lines 1" # # must add 1 as first line of method is 1 # File.read(@path).should == (Pry::Method.from_obj(@o, :baby).source + # Pry::Method.from_obj(@o, :bang).source).lines.to_a[0] # end # end end describe "overwrite by default (no --append)" do it 'should overwrite specified file with new input' do @t.eval ':horse_nostrils' @t.eval "save-file -i 1 --to '#{@path}'" @t.eval ':sucking_up_all_the_oxygen' @t.eval "save-file -i 2 --to '#{@path}'" File.read(@path).should == ":sucking_up_all_the_oxygen\n" end end describe "--append" do it 'should append to end of specified file' do @t.eval ':horse_nostrils' @t.eval "save-file -i 1 --to '#{@path}'" @t.eval ':sucking_up_all_the_oxygen' @t.eval "save-file -i 2 --to '#{@path}' -a" File.read(@path).should == ":horse_nostrils\n:sucking_up_all_the_oxygen\n" end end describe "saving commands" do it 'should save a command to a file' do @t.eval "save-file --to '#{@path}' show-source" cmd_source = Pry.config.commands["show-source"].source File.read(@path).should == cmd_source end end # TODO: reintroduce these specs at some point? # # describe "combined options" do # before do # @o = Object.new # def @o.baby # :baby # end # @t = pry_tester(@o) # end # it 'should save input cache and a method to a file (in that order)' do # @t.eval ":horse_nostrils" # @t.eval "save-file -i 1 -m baby #{@path}" # File.read(@path).should == ":horse_nostrils\n" + # Pry::Method.from_obj(@o, :baby).source # end # it 'should select a portion to save using --lines' do # @t.eval ":horse_nostrils" # @t.eval "save-file -i 1 -m baby #{@path} --lines 2..-2" # str = ":horse_nostrils\n" + Pry::Method.from_obj(@o, :baby).source # File.read(@path).should == str.lines.to_a[1..-2].join # end # end end pry-0.10.3/spec/commands/shell_command_spec.rb000066400000000000000000000034241260757071700213230ustar00rootroot00000000000000require_relative '../helper' describe "Command::ShellCommand" do describe 'cd' do before do @o = Object.new @t = pry_tester(@o) do def command_state pry.command_state[Pry::Command::ShellCommand.match] end end end describe ".cd" do before do allow(Dir).to receive(:chdir) end it "saves the current working directory" do expect(Dir).to receive(:pwd).at_least(:once).and_return("initial_path") # called once in MRI, 2x in RBX @t.eval ".cd new_path" @t.command_state.old_pwd.should == "initial_path" end describe "given a path" do it "sends the path to File.expand_path" do expect(Dir).to receive(:chdir).with(File.expand_path("new_path")) @t.eval ".cd new_path" end end describe "given an empty string" do it "sends ~ to File.expand_path" do expect(Dir).to receive(:chdir).with(File.expand_path("~")) @t.eval ".cd " end end describe "given a dash" do describe "given no prior directory" do it "raises the correct error" do expect { @t.eval ".cd -" }.to raise_error(StandardError, "No prior directory available") end end describe "given a prior directory" do it "sends the user's last pry working directory to File.expand_path" do expect(Dir).to receive(:pwd).at_least(:twice).and_return("initial_path") # called 2x in MRI, 3x in RBX expect(Dir).to receive(:chdir).with(File.expand_path("new_path")) @t.eval ".cd new_path" expect(Dir).to receive(:chdir).with(File.expand_path("initial_path")) @t.eval ".cd -" end end end end end end pry-0.10.3/spec/commands/show_doc_spec.rb000066400000000000000000000366651260757071700203400ustar00rootroot00000000000000require_relative '../helper' require "fixtures/show_source_doc_examples" describe "show-doc" do before do @o = Object.new # sample doc def @o.sample_method :sample end def @o.no_docs;end end it 'should output a method\'s documentation' do pry_eval(binding, "show-doc @o.sample_method").should =~ /sample doc/ end it 'should raise exception when cannot find docs' do expect { pry_eval(binding, "show-doc @o.no_docs") }.to raise_error Pry::CommandError end it 'should output a method\'s documentation with line numbers' do pry_eval(binding, "show-doc @o.sample_method -l").should =~ /\d: sample doc/ end it 'should output a method\'s documentation with line numbers (base one)' do pry_eval(binding, "show-doc @o.sample_method -b").should =~ /1: sample doc/ end it 'should output a method\'s documentation if inside method without needing to use method name' do # sample comment def @o.sample pry_eval(binding, 'show-doc').should =~ /sample comment/ end @o.sample end describe "finding find super method docs with help of `--super` switch" do before do class Daddy # daddy initialize! def initialize(*args); end end class Classy < Daddy # classy initialize! def initialize(*args); end end class Grungy < Classy # grungy initialize?? def initialize(*args); end end @o = Grungy.new # instancey initialize! def @o.initialize; end end after do Object.remove_const(:Grungy) Object.remove_const(:Classy) Object.remove_const(:Daddy) end it "finds super method docs" do output = pry_eval(binding, 'show-doc --super @o.initialize') output.should =~ /grungy initialize/ end it "traverses ancestor chain and finds super method docs" do output = pry_eval(binding, 'show-doc -ss @o.initialize') output.should =~ /classy initialize/ end it "traverses ancestor chain even higher and finds super method doc" do output = pry_eval(binding, 'show-doc @o.initialize -sss') output.should =~ /daddy initialize/ end it "finds super method docs without explicit method argument" do fatty = Grungy.new # fatty initialize! def fatty.initialize pry_eval(binding, 'show-doc --super') end output = fatty.initialize output.should =~ /grungy initialize/ end it "finds super method docs without `--super` but with the `super` keyword" do fatty = Grungy.new fatty.extend Module.new { def initialize :nibble end } # fatty initialize! def fatty.initialize pry_eval(binding, 'show-doc --super --super') end output = fatty.initialize output.should =~ /grungy initialize/ end end describe "rdoc highlighting" do it "should syntax highlight code in rdoc" do c = Class.new{ # This can initialize your class: # # a = c.new :foo # # @param foo def initialize(foo); end } begin t = pry_tester(binding) t.eval("show-doc c#initialize").should =~ /c.new :foo/ Pry.config.color = true # I don't want the test to rely on which colour codes are there, just to # assert that "something" is being colourized. t.eval("show-doc c#initialize").should_not =~ /c.new :foo/ ensure Pry.config.color = false end end it "should syntax highlight `code` in rdoc" do c = Class.new{ # After initializing your class with `c.new(:foo)`, go have fun! # # @param foo def initialize(foo); end } begin t = pry_tester(binding) t.eval("show-doc c#initialize").should =~ /c.new\(:foo\)/ Pry.config.color = true # I don't want the test to rely on which colour codes are there, just to # assert that "something" is being colourized. t.eval("show-doc c#initialize").should_not =~ /c.new\(:foo\)/ ensure Pry.config.color = false end end it "should not syntax highlight `` inside code" do c = Class.new{ # Convert aligned output (from many shell commands) into nested arrays: # # a = decolumnize `ls -l $HOME` # # @param output def decolumnize(output); end } begin t = pry_tester(binding) Pry.config.color = true t.eval("show-doc c#decolumnize").should =~ /ls -l \$HOME/ t.eval("show-doc c#decolumnize").should_not =~ /`ls -l \$HOME`/ ensure Pry.config.color = false end end end describe "on sourcable objects" do it "should show documentation for object" do # this is a documentation hello = proc { puts 'hello world!' } mock_pry(binding, "show-doc hello").should =~ /this is a documentation/ end end describe "on modules" do before do # god this is boring1 class ShowSourceTestClass def alpha end end # god this is boring2 module ShowSourceTestModule def alpha end end # god this is boring3 ShowSourceTestClassWeirdSyntax = Class.new do def beta end end # god this is boring4 ShowSourceTestModuleWeirdSyntax = Module.new do def beta end end end after do Object.remove_const :ShowSourceTestClass Object.remove_const :ShowSourceTestClassWeirdSyntax Object.remove_const :ShowSourceTestModule Object.remove_const :ShowSourceTestModuleWeirdSyntax end describe "basic functionality, should show docs for top-level module definitions" do it 'should show docs for a class' do pry_eval("show-doc ShowSourceTestClass").should =~ /god this is boring1/ end it 'should show docs for a module' do pry_eval("show-doc ShowSourceTestModule").should =~ /god this is boring2/ end it 'should show docs for a class when Const = Class.new syntax is used' do pry_eval("show-doc ShowSourceTestClassWeirdSyntax").should =~ /god this is boring3/ end it 'should show docs for a module when Const = Module.new syntax is used' do pry_eval("show-doc ShowSourceTestModuleWeirdSyntax").should =~ /god this is boring4/ end end describe "in REPL" do it 'should find class defined in repl' do t = pry_tester t.eval <<-RUBY # hello tobina class TobinaMyDog def woof end end RUBY t.eval('show-doc TobinaMyDog').should =~ /hello tobina/ Object.remove_const :TobinaMyDog end end it 'should lookup module name with respect to current context' do constant_scope(:AlphaClass, :BetaClass) do # top-level beta class BetaClass def alpha end end class AlphaClass # nested beta class BetaClass def beta end end end pry_eval(AlphaClass, "show-doc BetaClass").should =~ /nested beta/ end end it 'should look up nested modules' do constant_scope(:AlphaClass) do class AlphaClass # nested beta class BetaClass def beta end end end pry_eval("show-doc AlphaClass::BetaClass").should =~ /nested beta/ end end describe "show-doc -a" do it 'should show the docs for all monkeypatches defined in different files' do # local monkeypatch class TestClassForShowSource def beta end end result = pry_eval("show-doc TestClassForShowSource -a") result.should =~ /used by/ result.should =~ /local monkeypatch/ end describe "messages relating to -a" do it "displays the original definition by default (not a doc of a monkeypatch)" do class TestClassForCandidatesOrder def beta end end result = pry_eval("show-doc TestClassForCandidatesOrder") result.should =~ /Number of monkeypatches: 2/ result.should =~ /The first definition/ end it 'indicates all available monkeypatches can be shown with -a ' \ '(when -a not used and more than one candidate exists for class)' do # Still reading boring tests, eh? class TestClassForShowSource def beta end end result = pry_eval('show-doc TestClassForShowSource') result.should =~ /available monkeypatches/ end it 'shouldnt say anything about monkeypatches when only one candidate exists for selected class' do # Do not remove me. class Aarrrrrghh def o;end end result = pry_eval('show-doc Aarrrrrghh') result.should_not =~ /available monkeypatches/ Object.remove_const(:Aarrrrrghh) end end end describe "when no class/module arg is given" do before do module TestHost # hello there froggy module M def d; end def e; end end end end after do Object.remove_const(:TestHost) end it 'should return doc for current module' do pry_eval(TestHost::M, "show-doc").should =~ /hello there froggy/ end end # FIXME: THis is nto a good spec anyway, because i dont think it # SHOULD skip! describe "should skip over broken modules" do before do module TestHost # hello module M binding.eval("def a; end", "dummy.rb", 1) binding.eval("def b; end", "dummy.rb", 2) binding.eval("def c; end", "dummy.rb", 3) end # goodbye module M def d; end def e; end end end end after do Object.remove_const(:TestHost) end it 'should return doc for first valid module' do result = pry_eval("show-doc TestHost::M") result.should =~ /goodbye/ result.should_not =~ /hello/ end end end describe "on commands" do # mostly copied & modified from test_help.rb before do @oldset = Pry.config.commands @set = Pry.config.commands = Pry::CommandSet.new do import Pry::Commands end end after do Pry.config.commands = @oldset end it 'should display help for a specific command' do pry_eval('show-doc ls').should =~ /Usage: ls/ end it 'should display help for a regex command with a "listing"' do @set.command /bar(.*)/, "Test listing", :listing => "foo" do; end pry_eval('show-doc foo').should =~ /Test listing/ end it 'should display help for a command with a spaces in its name' do @set.command "command with spaces", "description of a command with spaces" do; end pry_eval('show-doc command with spaces').should =~ /description of a command with spaces/ end describe "class commands" do before do # pretty pink pincers class LobsterLady < Pry::ClassCommand match "lobster-lady" description "nada." def process "lobster" end end Pry.config.commands.add_command(LobsterLady) end after do Object.remove_const(:LobsterLady) end it 'should display "help" when looking up by command name' do pry_eval('show-doc lobster-lady').should =~ /nada/ Pry.config.commands.delete("lobster-lady") end it 'should display actual preceding comment for a class command, when class is used (rather than command name) when looking up' do pry_eval('show-doc LobsterLady').should =~ /pretty pink pincers/ Pry.config.commands.delete("lobster-lady") end end end describe "should set _file_ and _dir_" do it 'should set _file_ and _dir_ to file containing method source' do t = pry_tester t.process_command "show-doc TestClassForShowSource#alpha" t.pry.last_file.should =~ /show_source_doc_examples/ t.pry.last_dir.should =~ /fixtures/ end end unless Pry::Helpers::BaseHelpers.rbx? describe "can't find class docs" do describe "for classes" do before do module Jesus class Brian; end # doink-doc class Jingle def a; :doink; end end class Jangle < Jingle; end class Bangle < Jangle; end end end after do Object.remove_const(:Jesus) end it 'shows superclass doc' do t = pry_tester t.process_command "show-doc Jesus::Jangle" t.last_output.should =~ /doink-doc/ end it 'errors when class has no superclass to show' do t = pry_tester expect { t.process_command "show-doc Jesus::Brian" }.to raise_error(Pry::CommandError, /Couldn't locate/) end it 'shows warning when reverting to superclass docs' do t = pry_tester t.process_command "show-doc Jesus::Jangle" t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Jangle.*Showing.*Jesus::Jingle instead/ end it 'shows nth level superclass docs (when no intermediary superclasses have code either)' do t = pry_tester t.process_command "show-doc Jesus::Bangle" t.last_output.should =~ /doink-doc/ end it 'shows correct warning when reverting to nth level superclass' do t = pry_tester t.process_command "show-doc Jesus::Bangle" t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Bangle.*Showing.*Jesus::Jingle instead/ end end describe "for modules" do before do module Jesus # alpha-doc module Alpha def alpha; :alpha; end end module Zeta; end module Beta include Alpha end module Gamma include Beta end end end after do Object.remove_const(:Jesus) end it 'shows included module doc' do t = pry_tester t.process_command "show-doc Jesus::Beta" t.last_output.should =~ /alpha-doc/ end it 'shows warning when reverting to included module doc' do t = pry_tester t.process_command "show-doc Jesus::Beta" t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Beta.*Showing.*Jesus::Alpha instead/ end it 'errors when module has no included module to show' do t = pry_tester expect { t.process_command "show-source Jesus::Zeta" }.to raise_error(Pry::CommandError, /Couldn't locate/) end it 'shows nth level included module doc (when no intermediary modules have code either)' do t = pry_tester t.process_command "show-doc Jesus::Gamma" t.last_output.should =~ /alpha-doc/ end it 'shows correct warning when reverting to nth level included module' do t = pry_tester t.process_command "show-source Jesus::Gamma" t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Gamma.*Showing.*Jesus::Alpha instead/ end end end end end pry-0.10.3/spec/commands/show_input_spec.rb000066400000000000000000000005531260757071700207150ustar00rootroot00000000000000require_relative '../helper' describe "show-input" do before do @t = pry_tester end it 'should correctly show the current lines in the input buffer' do @t.push *unindent(<<-STR).split("\n") def hello puts :bing STR @t.process_command 'show-input' @t.last_output.should =~ /\A\d+: def hello\n\d+: puts :bing/ end end pry-0.10.3/spec/commands/show_source_spec.rb000066400000000000000000000564541260757071700210710ustar00rootroot00000000000000require_relative '../helper' require "fixtures/show_source_doc_examples" describe "show-source" do before do @o = Object.new def @o.sample_method :sample end Object.const_set(:Test, Module.new) end after do Pad.clear end it "should output a method's source" do pry_eval(binding, 'show-source @o.sample_method').should =~ /def @o.sample/ end it "should output help" do pry_eval('show-source -h').should =~ /Usage:\s+show-source/ end it "should output a method's source with line numbers" do pry_eval(binding, 'show-source -l @o.sample_method').should =~ /\d+: def @o.sample/ end it "should output a method's source with line numbers starting at 1" do pry_eval(binding, 'show-source -b @o.sample_method').should =~ /1: def @o.sample/ end it "should output a method's source if inside method and no name given" do def @o.sample pry_eval(binding, 'show-source').should =~ /def @o.sample/ end @o.sample end it "should output a method's source inside method using the -l switch" do def @o.sample pry_eval(binding, 'show-source -l').should =~ /def @o.sample/ end @o.sample end it "should find methods even if there are spaces in the arguments" do def @o.foo(*bars) "Mr flibble" self end out = pry_eval(binding, "show-source @o.foo('bar', 'baz bam').foo") out.should =~ /Mr flibble/ end it "should find methods even if the object overrides method method" do c = Class.new{ def method; 98 end } pry_eval(binding, "show-source c.new.method").should =~ /98/ end it "should not show the source when a non-extant method is requested" do c = Class.new{ def method; 98; end } mock_pry(binding, "show-source c#wrongmethod").should =~ /Couldn't locate/ end it "should find instance_methods if the class overrides instance_method" do c = Class.new{ def method; 98 end def self.instance_method; 789; end } pry_eval(binding, "show-source c#method").should =~ /98/ end it "should find instance methods with self#moo" do c = Class.new{ def moo; "ve over!"; end } pry_eval(binding, "cd c", "show-source self#moo").should =~ /ve over/ end it "should not find instance methods with self.moo" do c = Class.new{ def moo; "ve over!"; end } expect { pry_eval(binding, 'cd c', 'show-source self.moo') }.to raise_error(Pry::CommandError, /Couldn't locate/) end it "should find normal methods with self.moo" do c = Class.new{ def self.moo; "ve over!"; end } pry_eval(binding, 'cd c', 'show-source self.moo').should =~ /ve over/ end it "should not find normal methods with self#moo" do c = Class.new{ def self.moo; "ve over!"; end } expect { pry_eval(binding, 'cd c', 'show-source self#moo') }.to raise_error(Pry::CommandError, /Couldn't locate/) end it "should find normal methods (i.e non-instance methods) by default" do c = Class.new{ def self.moo; "ve over!"; end } pry_eval(binding, "cd c", "show-source moo").should =~ /ve over/ end it "should find instance methods if no normal methods available" do c = Class.new{ def moo; "ve over!"; end } pry_eval(binding, "cd c", "show-source moo").should =~ /ve over/ end describe "with -e option" do before do class FooBar def bar :bar end end end after do Object.remove_const(:FooBar) end it "evaluates the argument as ruby and shows the source code for the returned value" do ReplTester.start target: binding do input 'show-source -e FooBar.new' output /class FooBar/ end end end it "should raise a CommandError when super method doesn't exist" do def @o.foo(*bars); end expect { pry_eval(binding, "show-source --super @o.foo") }.to raise_error(Pry::CommandError, /No superclass found/) end it "should output the source of a method defined inside Pry" do out = pry_eval("def dyn_method\n:test\nend", 'show-source dyn_method') out.should =~ /def dyn_method/ Object.remove_method :dyn_method end it 'should output source for an instance method defined inside pry' do pry_tester.tap do |t| t.eval "class Test::A\n def yo\n end\nend" t.eval('show-source Test::A#yo').should =~ /def yo/ end end it 'should output source for a repl method defined using define_method' do pry_tester.tap do |t| t.eval "class Test::A\n define_method(:yup) {}\nend" t.eval('show-source Test::A#yup').should =~ /define_method\(:yup\)/ end end it "should output the source of a command defined inside Pry" do command_definition = %{ Pry.config.commands.command "hubba-hubba" do puts "that's what she said!" end } out = pry_eval(command_definition, 'show-source hubba-hubba') out.should =~ /what she said/ Pry.config.commands.delete "hubba-hubba" end describe "finding super methods with help of `--super` switch" do before do class Foo def foo(*bars) :super_wibble end end end after do Object.remove_const(:Foo) end it "finds super methods with explicit method argument" do o = Foo.new def o.foo(*bars) :wibble end pry_eval(binding, "show-source --super o.foo").should =~ /:super_wibble/ end it "finds super methods without explicit method argument" do o = Foo.new def o.foo(*bars) :wibble pry_eval(binding, 'show-source --super') end o.foo.should =~ /:super_wibble/ end it "finds super methods with multiple --super " do o = Foo.new o.extend Module.new { def foo :nibble end } def o.foo(*bars) :wibble pry_eval(binding, 'show-source --super --super') end o.foo.should =~ /:super_wibble/ end end describe "on sourcable objects" do it "should output source defined inside pry" do pry_tester.tap do |t| t.eval "hello = proc { puts 'hello world!' }" t.eval("show-source hello").should =~ /proc \{ puts/ end end it "should output source for procs/lambdas stored in variables" do hello = proc { puts 'hello world!' } pry_eval(binding, 'show-source hello').should =~ /proc \{ puts/ end it "should output source for procs/lambdas stored in constants" do HELLO = proc { puts 'hello world!' } pry_eval(binding, "show-source HELLO").should =~ /proc \{ puts/ Object.remove_const(:HELLO) end it "should output source for method objects" do def @o.hi; puts 'hi world'; end meth = @o.method(:hi) pry_eval(binding, "show-source meth").should =~ /puts 'hi world'/ end describe "on variables that shadow methods" do before do @t = pry_tester.eval unindent(<<-EOS) class ::TestHost def hello hello = proc { ' smile ' } pry_tester(binding) end end ::TestHost.new.hello EOS end after do Object.remove_const(:TestHost) end it "source of variable should take precedence over method that is being shadowed" do source = @t.eval('show-source hello') source.should_not =~ /def hello/ source.should =~ /proc \{ ' smile ' \}/ end it "source of method being shadowed should take precedence over variable if given self.meth_name syntax" do @t.eval('show-source self.hello').should =~ /def hello/ end end end describe "on variable or constant" do before do class TestHost def hello "hi there" end end end after do Object.remove_const(:TestHost) end it "should output source of its class if variable doesn't respond to source_location" do test_host = TestHost.new pry_eval(binding, 'show-source test_host'). should =~ /class TestHost\n.*def hello/ end it "should output source of its class if constant doesn't respond to source_location" do TEST_HOST = TestHost.new pry_eval(binding, 'show-source TEST_HOST'). should =~ /class TestHost\n.*def hello/ Object.remove_const(:TEST_HOST) end end describe "on modules" do before do class ShowSourceTestSuperClass def alpha end end class ShowSourceTestClass "bar" do; end pry_eval('show-source bar').should =~ /:body_of_foo_bar_regex/ end end describe "create_command commands" do it 'should show source for a command' do @set.create_command "foo", "babble" do def process() :body_of_foo end end pry_eval('show-source foo').should =~ /:body_of_foo/ end it 'should show source for a command defined inside pry' do pry_eval %{ _pry_.commands.create_command "foo", "babble" do def process() :body_of_foo end end } pry_eval('show-source foo').should =~ /:body_of_foo/ end end describe "real class-based commands" do before do class ::TemporaryCommand < Pry::ClassCommand match 'temp-command' def process() :body_of_temp end end Pry.config.commands.add_command(::TemporaryCommand) end after do Object.remove_const(:TemporaryCommand) end it 'should show source for a command' do pry_eval('show-source temp-command').should =~ /:body_of_temp/ end it 'should show source for a command defined inside pry' do pry_eval %{ class ::TemporaryCommandInPry < Pry::ClassCommand match 'temp-command-in-pry' def process() :body_of_temp end end } Pry.config.commands.add_command(::TemporaryCommandInPry) pry_eval('show-source temp-command-in-pry').should =~ /:body_of_temp/ Object.remove_const(:TemporaryCommandInPry) end end end describe "should set _file_ and _dir_" do it 'should set _file_ and _dir_ to file containing method source' do t = pry_tester t.process_command "show-source TestClassForShowSource#alpha" t.pry.last_file.should =~ /show_source_doc_examples/ t.pry.last_dir.should =~ /fixtures/ end end unless Pry::Helpers::BaseHelpers.rbx? describe "can't find class/module code" do describe "for classes" do before do module Jesus module Pig def lillybing; :lillybing; end end class Brian; end class Jingle def a; :doink; end end class Jangle < Jingle; include Pig; end class Bangle < Jangle; end end end after do Object.remove_const(:Jesus) end it 'shows superclass code' do t = pry_tester t.process_command "show-source Jesus::Jangle" t.last_output.should =~ /doink/ end it 'ignores included modules' do t = pry_tester t.process_command "show-source Jesus::Jangle" t.last_output.should_not =~ /lillybing/ end it 'errors when class has no superclass to show' do t = pry_tester expect { t.process_command "show-source Jesus::Brian" }.to raise_error(Pry::CommandError, /Couldn't locate/) end it 'shows warning when reverting to superclass code' do t = pry_tester t.process_command "show-source Jesus::Jangle" t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Jangle.*Showing.*Jesus::Jingle instead/ end it 'shows nth level superclass code (when no intermediary superclasses have code either)' do t = pry_tester t.process_command "show-source Jesus::Bangle" t.last_output.should =~ /doink/ end it 'shows correct warning when reverting to nth level superclass' do t = pry_tester t.process_command "show-source Jesus::Bangle" t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Bangle.*Showing.*Jesus::Jingle instead/ end end describe "for modules" do before do module Jesus module Alpha def alpha; :alpha; end end module Zeta; end module Beta include Alpha end module Gamma include Beta end end end after do Object.remove_const(:Jesus) end it 'shows included module code' do t = pry_tester t.process_command "show-source Jesus::Beta" t.last_output.should =~ /alpha/ end it 'shows warning when reverting to included module code' do t = pry_tester t.process_command "show-source Jesus::Beta" t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Beta.*Showing.*Jesus::Alpha instead/ end it 'errors when module has no included module to show' do t = pry_tester expect { t.process_command "show-source Jesus::Zeta" }.to raise_error(Pry::CommandError, /Couldn't locate/) end it 'shows nth level included module code (when no intermediary modules have code either)' do t = pry_tester t.process_command "show-source Jesus::Gamma" t.last_output.should =~ /alpha/ end it 'shows correct warning when reverting to nth level included module' do t = pry_tester t.process_command "show-source Jesus::Gamma" t.last_output.should =~ /Warning.*?Cannot find.*?Jesus::Gamma.*Showing.*Jesus::Alpha instead/ end end end end end pry-0.10.3/spec/commands/watch_expression_spec.rb000066400000000000000000000046101260757071700221010ustar00rootroot00000000000000require_relative '../helper' describe "watch expression" do # Custom eval that will: # 1) Create an instance of pry that can use for multiple calls # 2) Exercise the after_eval hook # 3) Return the output def eval(expr) output = @tester.eval expr @tester.pry.hooks.exec_hook :after_eval, nil, @tester.pry output end before do @tester = pry_tester @tester.pry.hooks.clear :after_eval eval "watch --delete" end it "registers the after_eval hook" do eval 'watch 1+1' @tester.pry.hooks.hook_exists?(:after_eval, :watch_expression).should == true end it "prints no watched expressions" do eval('watch').should =~ /No watched expressions/ end it "watches an expression" do eval "watch 1+1" eval('watch').should =~ /=> 2/ end it "watches a local variable" do eval 'foo = :bar' eval 'watch foo' eval('watch').should =~ /=> :bar/ end it "prints when an expression changes" do ReplTester.start do input 'a = 1' output '=> 1' input 'watch a' output "Watching a\nwatch: a => 1" input "a = 2" output "watch: a => 2\n=> 2" end end it "prints when an expression is mutated" do ReplTester.start do input 'a = "one"' output '=> "one"' input 'watch a' output %(Watching a\nwatch: a => "one") input "a.sub! 'o', 'p'" output %(watch: a => "pne"\n=> "pne") end end it "doesn't print when an expresison remains the same" do ReplTester.start do input 'a = 1' output '=> 1' input 'watch a' output "Watching a\nwatch: a => 1" input "a = 1" output "=> 1" end end it "continues to work if you start a second pry instance" do ReplTester.start do input 'a = 1' output '=> 1' input 'watch a' output "Watching a\nwatch: a => 1" input "a = 2" output "watch: a => 2\n=> 2" end ReplTester.start do input 'b = 1' output '=> 1' input 'watch b' output "Watching b\nwatch: b => 1" input "b = 2" output "watch: b => 2\n=> 2" end end describe "deleting expressions" do before do eval 'watch :keeper' eval 'watch :delete' eval 'watch -d 2' end it "keeps keeper" do eval('watch').should =~ /keeper/ end it "deletes delete" do eval('watch').should_not =~ /delete/ end end end pry-0.10.3/spec/commands/whereami_spec.rb000066400000000000000000000154061260757071700203220ustar00rootroot00000000000000require_relative '../helper' describe "whereami" do it 'should work with methods that have been undefined' do class Cor def blimey! Cor.send :undef_method, :blimey! Pad.binding = binding end end Cor.new.blimey! # using [.] so the regex doesn't match itself pry_eval(Pad.binding, 'whereami').should =~ /self[.]blimey!/ Object.remove_const(:Cor) end it 'should work in objects with no method methods' do class Cor def blimey! pry_eval(binding, 'whereami').should =~ /Cor[#]blimey!/ end def method; "moo"; end end Cor.new.blimey! Object.remove_const(:Cor) end it 'should properly set _file_, _line_ and _dir_' do class Cor def blimey! pry_eval(binding, 'whereami', '_file_'). should == File.expand_path(__FILE__) end end Cor.new.blimey! Object.remove_const(:Cor) end if RUBY_VERSION > "2.0.0" it 'should work with prepended methods' do module Cor2 def blimey! super end end class Cor prepend Cor2 def blimey! pry_eval(binding, 'whereami').should =~ /Cor2[#]blimey!/ end end Cor.new.blimey! Object.remove_const(:Cor) Object.remove_const(:Cor2) end end it 'should work in BasicObjects' do cor = Class.new(BasicObject) do def blimey! ::Kernel.binding # omnom end end.new.blimey! pry_eval(cor, 'whereami').should =~ /::Kernel.binding [#] omnom/ end it 'should show description and correct code when __LINE__ and __FILE__ are outside @method.source_location' do class Cor def blimey! eval <<-END, binding, "spec/fixtures/example.erb", 1 pry_eval(binding, 'whereami') END end end Cor.instance_method(:blimey!).source.should =~ /pry_eval/ Cor.new.blimey!.should =~ /Cor#blimey!.*Look at me/m Object.remove_const(:Cor) end it 'should show description and correct code when @method.source_location would raise an error' do class Cor eval <<-END, binding, "spec/fixtures/example.erb", 1 def blimey! pry_eval(binding, 'whereami') end END end expect { Cor.instance_method(:blimey!).source }.to raise_error MethodSource::SourceNotFoundError Cor.new.blimey!.should =~ /Cor#blimey!.*Look at me/m Object.remove_const(:Cor) end # Now that we use stagger_output (paging output) we no longer get # the "From: " line, as we output everything in one go (not separate output.puts) # and so the user just gets a single `Error: Cannot open # "not.found.file.erb" for reading.` # which is good enough IMO. Unfortunately we can't test for it # though, as we don't hook stdout. # # it 'should display a description and error if reading the file goes wrong' do # class Cor # def blimey! # eval <<-END, binding, "not.found.file.erb", 7 # Pad.tester = pry_tester(binding) # Pad.tester.eval('whereami') # END # end # end # proc { Cor.new.blimey! }.should.raise(MethodSource::SourceNotFoundError) # Pad.tester.last_output.should =~ # /From: not.found.file.erb @ line 7 Cor#blimey!:/ # Object.remove_const(:Cor) # end it 'should show code window (not just method source) if parameter passed to whereami' do class Cor def blimey! pry_eval(binding, 'whereami 3').should =~ /class Cor/ end end Cor.new.blimey! Object.remove_const(:Cor) end it 'should show entire method when -m option used' do old_size, Pry.config.default_window_size = Pry.config.default_window_size, 1 old_cutoff, Pry::Command::Whereami.method_size_cutoff = Pry::Command::Whereami.method_size_cutoff, 1 class Cor def blimey! 1 2 pry_eval(binding, 'whereami -m').should =~ /def blimey/ end end Pry::Command::Whereami.method_size_cutoff, Pry.config.default_window_size = old_cutoff, old_size Cor.new.blimey! Object.remove_const(:Cor) end it 'should show entire file when -f option used' do class Cor def blimey! 1 2 pry_eval(binding, 'whereami -f').should =~ /show entire file when -f option used/ end end Cor.new.blimey! Object.remove_const(:Cor) end describe "-c" do it 'should show class when -c option used, and locate correct candidate' do require 'fixtures/whereami_helper' class Cor def blimey! 1 2 out = pry_eval(binding, 'whereami -c') out.should =~ /class Cor/ out.should =~ /blimey/ end end Cor.new.blimey! Object.remove_const(:Cor) end it 'should show class when -c option used, and locate correct superclass' do class Cor def blimey! 1 2 out = pry_eval(binding, 'whereami -c') out.should =~ /class Cor/ out.should =~ /blimey/ end end class Horse < Cor def pig;end end Horse.new.blimey! Object.remove_const(:Cor) Object.remove_const(:Horse) end # https://github.com/rubinius/rubinius/pull/2247 unless Pry::Helpers::BaseHelpers.rbx? it 'should show class when -c option used, and binding is outside a method' do class Cor def blimey;end out = pry_eval(binding, 'whereami -c') out.should =~ /class Cor/ out.should =~ /blimey/ end Object.remove_const(:Cor) end end end it 'should not show line numbers or marker when -n switch is used' do class Cor def blimey! out = pry_eval(binding, 'whereami -n') out.should =~ /^\s*def/ out.should_not =~ /\=\>/ end end Cor.new.blimey! Object.remove_const(:Cor) end it 'should use Pry.config.default_window_size for window size when outside a method context' do old_size, Pry.config.default_window_size = Pry.config.default_window_size, 1 :litella :pig out = pry_eval(binding, 'whereami') :punk :sanders out.should_not =~ /:litella/ out.should =~ /:pig/ out.should =~ /:punk/ out.should_not =~ /:sanders/ Pry.config.default_window_size = old_size end it "should work at the top level" do pry_eval(Pry.toplevel_binding, 'whereami').should =~ /At the top level/ end it "should work inside a class" do pry_eval(Pry, 'whereami').should =~ /Inside Pry/ end it "should work inside an object" do pry_eval(Object.new, 'whereami').should =~ /Inside # Pry.binding_for(bind)).include?(symbol).should == assert_flag} return proc {|*symbols| symbols.each(&test) } end describe Pry::InputCompleter do before do # The AMQP gem has some classes like this: # pry(main)> AMQP::Protocol::Test::ContentOk.name # => :content_ok module SymbolyName def self.name; :symboly_name; end end @before_completer = Pry.config.completer Pry.config.completer = Pry::InputCompleter end after do Pry.config.completer = @before_completer Object.remove_const :SymbolyName end # another jruby hack :(( if !Pry::Helpers::BaseHelpers.jruby? it "should not crash if there's a Module that has a symbolic name." do expect { Pry::InputCompleter.new(Readline).call "a.to_s.", :target => Pry.binding_for(Object.new) }.not_to raise_error Exception end end it 'should take parenthesis and other characters into account for symbols' do expect { Pry::InputCompleter.new(Readline).call ":class)", :target => Pry.binding_for(Object.new) }.not_to raise_error end it 'should complete instance variables' do object = Class.new.new # set variables in appropriate scope object.instance_variable_set(:'@name', 'Pry') object.class.send(:class_variable_set, :'@@number', 10) # check to see if variables are in scope object.instance_variables. map { |v| v.to_sym }. include?(:'@name').should == true object.class.class_variables. map { |v| v.to_sym }. include?(:'@@number').should == true # Complete instance variables. b = Pry.binding_for(object) completer_test(b).call('@name', '@name.downcase') # Complete class variables. b = Pry.binding_for(object.class) completer_test(b).call('@@number', '@@number.class') end it 'should complete for stdlib symbols' do o = Object.new # Regexp completer_test(o).call('/foo/.extend') # Array completer_test(o).call('[1].push') # Hash completer_test(o).call('{"a" => "b"}.keys') # Proc completer_test(o).call('{2}.call') # Symbol completer_test(o).call(':symbol.to_s') # Absolute Constant completer_test(o).call('::IndexError') end it 'should complete for target symbols' do o = Object.new # Constant module Mod Con = 'Constant' module Mod2 end end completer_test(Mod).call('Con') # Constants or Class Methods completer_test(o).call('Mod::Con') # Symbol foo = :symbol completer_test(o).call(':symbol') # Variables class << o attr_accessor :foo end o.foo = 'bar' completer_test(binding).call('o.foo') # trailing slash Pry::InputCompleter.new(Readline).call('Mod2/', :target => Pry.binding_for(Mod)).include?('Mod2/').should == true end it 'should complete for arbitrary scopes' do module Bar @barvar = :bar end module Baz @bar = Bar @bazvar = :baz Con = :constant end pry = Pry.new(:target => Baz) pry.push_binding(Bar) b = Pry.binding_for(Bar) completer_test(b, pry).call("../@bazvar") completer_test(b, pry).call('/Con') end it 'should complete for stdlib symbols' do o = Object.new # Regexp completer_test(o).call('/foo/.extend') # Array completer_test(o).call('[1].push') # Hash completer_test(o).call('{"a" => "b"}.keys') # Proc completer_test(o).call('{2}.call') # Symbol completer_test(o).call(':symbol.to_s') # Absolute Constant completer_test(o).call('::IndexError') end it 'should complete for target symbols' do o = Object.new # Constant module Mod Con = 'Constant' module Mod2 end end completer_test(Mod).call('Con') # Constants or Class Methods completer_test(o).call('Mod::Con') # Symbol foo = :symbol completer_test(o).call(':symbol') # Variables class << o attr_accessor :foo end o.foo = 'bar' completer_test(binding).call('o.foo') # trailing slash Pry::InputCompleter.new(Readline).call('Mod2/', :target => Pry.binding_for(Mod)).include?('Mod2/').should == true end it 'should complete for arbitrary scopes' do module Bar @barvar = :bar end module Baz @bar = Bar @bazvar = :baz Con = :constant end pry = Pry.new(:target => Baz) pry.push_binding(Bar) b = Pry.binding_for(Bar) completer_test(b, pry).call("../@bazvar") completer_test(b, pry).call('/Con') end it 'should not return nil in its output' do pry = Pry.new Pry::InputCompleter.new(Readline, pry).call("pry.", :target => binding).should_not include nil end end pry-0.10.3/spec/config_spec.rb000066400000000000000000000117421260757071700161640ustar00rootroot00000000000000require_relative 'helper' describe Pry::Config do describe "reserved keys" do it "raises an ArgumentError on assignment of a reserved key" do local = Pry::Config.new Pry::Config::RESERVED_KEYS.each do |key| expect { local[key] = 1 }.to raise_error ArgumentError end end end describe "traversal to parent" do it "traverses back to the parent when a local key is not found" do local = Pry::Config.new Pry::Config.from_hash(foo: 1) local.foo.should == 1 end it "stores a local key and prevents traversal to the parent" do local = Pry::Config.new Pry::Config.from_hash(foo: 1) local.foo = 2 local.foo.should == 2 end it "traverses through a chain of parents" do root = Pry::Config.from_hash({foo: 21}) local1 = Pry::Config.new(root) local2 = Pry::Config.new(local1) local3 = Pry::Config.new(local2) local3.foo.should == 21 end it "stores a local copy of the parent's hooks upon accessing them" do parent = Pry::Config.from_hash(hooks: "parent_hooks") local = Pry::Config.new parent local.hooks.gsub! 'parent', 'local' local.hooks.should == 'local_hooks' parent.hooks.should == 'parent_hooks' end end describe ".from_hash" do it "returns an object without a default" do local = Pry::Config.from_hash({}) local.default.should == nil end it "returns an object with a default" do default = Pry::Config.new(nil) local = Pry::Config.from_hash({}, default) local.default.should == local end end describe "#respond_to_missing?" do before do @config = Pry::Config.new(nil) end it "returns a Method object for a dynamic key" do @config["key"] = 1 method_obj = @config.method(:key) method_obj.name.should == :key method_obj.call.should == 1 end end describe "#respond_to?" do before do @config = Pry::Config.new(nil) end it "returns true for a local key" do @config.zzfoo = 1 @config.respond_to?(:zzfoo).should == true end it "returns false for an unknown key" do @config.respond_to?(:blahblah).should == false end end describe "#default" do it "returns nil" do local = Pry::Config.new(nil) local.default.should == nil end it "returns the default" do default = Pry::Config.new(nil) local = Pry::Config.new(default) local.default.should == default end end describe "#keys" do it "returns an array of local keys" do root = Pry::Config.from_hash({zoo: "boo"}, nil) local = Pry::Config.from_hash({foo: "bar"}, root) local.keys.should == ["foo"] end end describe "#==" do it "compares equality through the underlying lookup table" do local1 = Pry::Config.new(nil) local2 = Pry::Config.new(nil) local1.foo = "hi" local2.foo = "hi" local1.should == local2 end it "compares equality against an object who does not implement #to_hash" do local1 = Pry::Config.new(nil) local1.should_not == Object.new end end describe "#forget" do it "forgets a local key" do local = Pry::Config.new Pry::Config.from_hash(foo: 1) local.foo = 2 local.foo.should == 2 local.forget(:foo) local.foo.should == 1 end end describe "#to_hash" do it "provides a copy of local key & value pairs as a Hash" do local = Pry::Config.new Pry::Config.from_hash(bar: true) local.foo = "21" local.to_hash.should == { "foo" => "21" } end it "returns a duplicate of the lookup table" do local = Pry::Config.new(nil) local.to_hash.merge!("foo" => 42) local.foo.should_not == 42 end end describe "#merge!" do before do @config = Pry::Config.new(nil) end it "merges an object who returns a Hash through #to_hash" do obj = Class.new { def to_hash() {epoch: 1} end }.new @config.merge!(obj) @config.epoch.should == 1 end it "merges an object who returns a Hash through #to_h" do obj = Class.new { def to_h() {epoch: 2} end }.new @config.merge!(obj) @config.epoch.should == 2 end it "merges a Hash" do @config.merge!(epoch: 420) @config.epoch.should == 420 end it "raises a TypeError for objects who can't become a Hash" do expect { @config.merge!(Object.new) }.to raise_error TypeError end end describe "#clear" do before do @local = Pry::Config.new(nil) end it "returns true" do @local.clear.should == true end it "clears local assignments" do @local.foo = 1 @local.clear @local.to_hash.should == {} end it "is aliased as #refresh" do @local.method(:clear).should == @local.method(:refresh) end end describe "#[]=" do it "stores keys as strings" do local = Pry::Config.from_hash({}) local[:zoo] = "hello" local.to_hash.should == { "zoo" => "hello" } end end end pry-0.10.3/spec/control_d_handler_spec.rb000066400000000000000000000027611260757071700204000ustar00rootroot00000000000000require_relative 'helper' describe Pry::DEFAULT_CONTROL_D_HANDLER do describe "control-d press" do before do # Simulates a ^D press. @control_d = "Pry::DEFAULT_CONTROL_D_HANDLER.call('', _pry_)" end describe "in an expression" do it "should clear out passed string" do str = 'hello world' Pry::DEFAULT_CONTROL_D_HANDLER.call(str, nil) str.should == '' end end describe 'at top-level session' do it 'should break out of a REPL loop' do instance = Pry.new instance.binding_stack.should_not be_empty instance.eval(nil).should equal false instance.binding_stack.should be_empty end end describe 'in a nested session' do it 'should pop last binding from the binding stack' do t = pry_tester t.eval "cd Object.new" t.eval("_pry_.binding_stack.size").should == 2 t.eval("_pry_.eval(nil)").should equal true t.eval("_pry_.binding_stack.size").should == 1 end it "breaks out of the parent session" do ReplTester.start do input 'Pry::REPL.new(_pry_, :target => 10).start' output '' prompt(/10.*> $/) input 'self' output '=> 10' input nil # Ctrl-D output '' input 'self' output '=> main' input nil # Ctrl-D output '=> nil' # Exit value of nested REPL. assert_exited end end end end end pry-0.10.3/spec/documentation_helper_spec.rb000066400000000000000000000040211260757071700211170ustar00rootroot00000000000000require_relative 'helper' describe Pry::Helpers::DocumentationHelpers do before do @helper = Pry::Helpers::DocumentationHelpers end describe "get_comment_content" do it "should strip off the hash and unindent" do @helper.get_comment_content(" # hello\n # world\n").should == "hello\nworld\n" end it "should strip out leading lines of hashes" do @helper.get_comment_content("###############\n#hello\n#world\n").should == "hello\nworld\n" end it "should remove shebangs" do @helper.get_comment_content("#!/usr/bin/env ruby\n# This is a program\n").should == "This is a program\n" end it "should unindent past separators" do @helper.get_comment_content(" # Copyright Me \n #--\n # So there.\n").should == "Copyright Me \n--\nSo there.\n" end end describe "process_rdoc" do before do Pry.config.color = true end after do Pry.config.color = false end it "should syntax highlight indented code" do @helper.process_rdoc(" 4 + 4\n").should_not == " 4 + 4\n" end it "should highlight words surrounded by +s" do @helper.process_rdoc("the +parameter+").should =~ /the \e.*parameter\e.*/ end it "should syntax highlight things in backticks" do @helper.process_rdoc("for `Example`").should =~ /for `\e.*Example\e.*`/ end it "should emphasise em tags" do @helper.process_rdoc("for science").should == "for \e[1mscience\e[0m" end it "should emphasise italic tags" do @helper.process_rdoc("for science").should == "for \e[1mscience\e[0m" end it "should syntax highlight code in " do @helper.process_rdoc("for Example").should =~ /for \e.*Example\e.*/ end it "should not double-highlight backticks inside indented code" do @helper.process_rdoc(" `echo 5`").should =~ /echo 5/ end it "should not remove ++" do @helper.process_rdoc("--\n comment in a bubble\n++").should =~ /\+\+/ end end end pry-0.10.3/spec/editor_spec.rb000066400000000000000000000032561260757071700162060ustar00rootroot00000000000000require 'pathname' require_relative 'helper' describe Pry::Editor do class Pry::Editor public :build_editor_invocation_string end before do # OS-specific tempdir name. For GNU/Linux it's "tmp", for Windows it's # something "Temp". @tf_dir = if Pry::Helpers::BaseHelpers.mri_19? Pathname.new(Dir::Tmpname.tmpdir) else Pathname.new(Dir.tmpdir) end @tf_path = File.join(@tf_dir.to_s, 'hello world.rb') @editor = Pry::Editor.new(Pry.new) end unless Pry::Helpers::BaseHelpers.windows? describe "build_editor_invocation_string" do it 'should shell-escape files' do invocation_str = @editor.build_editor_invocation_string(@tf_path, 5, true) invocation_str.should =~ /#@tf_dir.+hello\\ world\.rb/ end end end describe "build_editor_invocation_string on windows" do before do class Pry::Editor def windows?; true; end end end after do class Pry::Editor undef windows? end end it "should replace / by \\" do invocation_str = @editor.build_editor_invocation_string(@tf_path, 5, true) invocation_str.should =~ %r(\\#{@tf_dir.basename}\\) end it "should not shell-escape files" do invocation_str = @editor.build_editor_invocation_string(@tf_path, 5, true) invocation_str.should =~ /hello world\.rb/ end end describe 'invoke_editor with a proc' do it 'should not shell-escape files' do editor = Pry::Editor.new(Pry.new(editor: proc{ |file, line, blocking| @file = file nil })) editor.invoke_editor(@tf_path, 10, true) @file.should == @tf_path end end end pry-0.10.3/spec/exception_whitelist_spec.rb000066400000000000000000000013411260757071700210030ustar00rootroot00000000000000require_relative 'helper' describe "Pry.config.exception_whitelist" do before do @str_output = StringIO.new end it 'should rescue all exceptions NOT specified on whitelist' do Pry.config.exception_whitelist.include?(NameError).should == false expect { Pry.start(self, :input => StringIO.new("raise NameError\nexit"), :output => @str_output) }.not_to raise_error end it 'should NOT rescue exceptions specified on whitelist' do old_whitelist = Pry.config.exception_whitelist Pry.config.exception_whitelist = [NameError] expect { Pry.start(self, :input => StringIO.new("raise NameError"), :output => @str_output) }.to raise_error NameError Pry.config.exception_whitelist = old_whitelist end end pry-0.10.3/spec/fixtures/000077500000000000000000000000001260757071700152245ustar00rootroot00000000000000pry-0.10.3/spec/fixtures/candidate_helper1.rb000066400000000000000000000001311260757071700211000ustar00rootroot00000000000000# rank 0 class CandidateTest def test1 end def test2 end def test3 end end pry-0.10.3/spec/fixtures/candidate_helper2.rb000066400000000000000000000001061260757071700211030ustar00rootroot00000000000000# rank 1 class CandidateTest def test4 end def test5 end end pry-0.10.3/spec/fixtures/cat_load_path000066400000000000000000000000001260757071700177170ustar00rootroot00000000000000pry-0.10.3/spec/fixtures/cat_load_path.rb000066400000000000000000000000001260757071700203210ustar00rootroot00000000000000pry-0.10.3/spec/fixtures/example.erb000066400000000000000000000000571260757071700173530ustar00rootroot00000000000000 Look at me, testing my erb! pry-0.10.3/spec/fixtures/example_nesting.rb000066400000000000000000000031501260757071700207320ustar00rootroot00000000000000 # [] class A # ["class A"] def a; end # ["class A"] class B; def b; end; end # ["class A", "class B"] end # [] # [] class << A # ["class << A"] class B # ["class << A", "class B"] def c; end # ["class << A", "class B"] end # ["class << A"] # ["class << A"] module F::B # ["class << A", "module F::B"] def foo; end # ["class << A", "module F::B"] end # ["class << A"] end # [] # [] module (:symbol.class)::Exciting # def foo; end # class B # def goo; end # end # end # [] # [] module C # ["module C"] class D # ["module C", "class D"] def guh; foo.end; end # ["module C", "class D"] end # ["module C"] def bar; :end; end # ["module C"] class << new.bar; end # ["module C"] class << new.bar; def f; end; end # # ["module C"] class << self; def mug; end; end # ["module C", "class << self"] end # [] pry-0.10.3/spec/fixtures/pry_history000066400000000000000000000000301260757071700175330ustar00rootroot00000000000000:athos :porthos :aramis pry-0.10.3/spec/fixtures/show_source_doc_examples.rb000066400000000000000000000005451260757071700226400ustar00rootroot00000000000000# used by show_source_spec.rb and show_doc_spec.rb class TestClassForShowSource #doc def alpha end end class TestClassForShowSourceClassEval def alpha end end class TestClassForShowSourceInstanceEval def alpha end end # The first definition (find the second one in show_doc_spec.rb). class TestClassForCandidatesOrder def alpha end end pry-0.10.3/spec/fixtures/slinky.rb000066400000000000000000000000001260757071700170500ustar00rootroot00000000000000pry-0.10.3/spec/fixtures/slinky/000077500000000000000000000000001260757071700165355ustar00rootroot00000000000000pry-0.10.3/spec/fixtures/slinky/stinky.rb000066400000000000000000000000001260757071700203710ustar00rootroot00000000000000pry-0.10.3/spec/fixtures/testlinkrc000077700000000000000000000000001260757071700205532testrcustar00rootroot00000000000000pry-0.10.3/spec/fixtures/testrc000066400000000000000000000000761260757071700164560ustar00rootroot00000000000000TEST_RC = [] if !Object.const_defined?(:TEST_RC) TEST_RC << 0 pry-0.10.3/spec/fixtures/testrcbad000066400000000000000000000000551260757071700171220ustar00rootroot00000000000000TEST_BEFORE_RAISE = 1 raise "messin with ya" pry-0.10.3/spec/fixtures/whereami_helper.rb000066400000000000000000000001021260757071700207020ustar00rootroot00000000000000class Cor def a; end def b; end def c; end def d; end end pry-0.10.3/spec/helper.rb000066400000000000000000000020561260757071700151620ustar00rootroot00000000000000require 'bundler/setup' require 'pry/test/helper' Bundler.require :default, :test require_relative 'spec_helpers/mock_pry' require_relative 'spec_helpers/repl_tester' if ENV["COVERAGE"] require "simplecov" SimpleCov.start end class Module public :remove_const public :remove_method end # turn warnings off (esp for Pry::Hooks which will generate warnings # in tests) $VERBOSE = nil Pad = Class.new do include Pry::Config::Behavior end.new(nil) # to help with tracking down bugs that cause an infinite loop in the test suite if ENV["SET_TRACE_FUNC"] require 'set_trace' if Pry::Helpers::BaseHelpers.rbx? set_trace_func proc { |event, file, line, id, binding, classname| STDERR.printf "%8s %s:%-2d %10s %8s\n", event, file, line, id, classname } end puts "Ruby v#{RUBY_VERSION} (#{defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"}), Pry v#{Pry::VERSION}, method_source v#{MethodSource::VERSION}, CodeRay v#{CodeRay::VERSION}, Slop v#{Slop::VERSION}" RSpec.configure do |config| config.alias_example_to :should config.include PryTestHelpers end pry-0.10.3/spec/helpers/000077500000000000000000000000001260757071700150155ustar00rootroot00000000000000pry-0.10.3/spec/helpers/table_spec.rb000066400000000000000000000055451260757071700174540ustar00rootroot00000000000000require_relative '../helper' describe 'Formatting Table' do it 'knows about colorized fitting' do t = Pry::Helpers::Table.new %w(hihi), :column_count => 1 t.fits_on_line?(4).should == true t.items = [] t.fits_on_line?(4).should == true t.items = %w(hi hi) t.fits_on_line?(4).should == true t.column_count = 2 t.fits_on_line?(4).should == false t.items = %w( a ccc bb dddd ).sort t.fits_on_line?(8).should == true t.fits_on_line?(7).should == false end describe 'formatting - should order downward and wrap to columns' do FAKE_COLUMNS = 62 def try_round_trip(expected) things = expected.split(/\s+/).sort actual = Pry::Helpers.tablify(things, FAKE_COLUMNS).to_s.strip [expected, actual].each{|e| e.gsub! /\s+$/, ''} if actual != expected bar = '-'*25 puts \ bar+'expected'+bar, expected, bar+'actual'+bar, actual end actual.should == expected end it 'should handle a tiny case' do try_round_trip(<<-eot) asdf asfddd fdass eot end it 'should handle the basic case' do try_round_trip(<<-eot) aadd ddasffssdad sdsaadaasd ssfasaafssd adassdfffaasds f sdsfasddasfds ssssdaa assfsafsfsds fsasa ssdsssafsdasdf eot end it 'should handle... another basic case' do try_round_trip(<<-EOT) aaad dasaasffaasf fdasfdfss safdfdddsasd aaadfasassdfff ddadadassasdf fddsasadfssdss sasf aaddaafaf dddasaaaaaa fdsasad sddsa aas dfsddffdddsdfd ff sddsfsaa adasadfaaffds dsfafdsfdfssda ffadsfafsaafa ss asddaadaaadfdd dssdss ffssfsfafaadss ssas asdsdaa faadf fsddfff ssdfssff asfadsssaaad fasfaafdssd s EOT end it 'should handle colors' do try_round_trip(<<-EOT) \e[31maaaaaaaaaa\e[0m \e[31mccccccccccccccccccccccccccccc\e[0m \e[31mbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\e[0m \e[31mddddddddddddd\e[0m EOT end it 'should handle empty input' do try_round_trip('') end it 'should handle one-token input' do try_round_trip('asdf') end end describe 'line length is smaller than the length of the longest word' do before do element = 'swizzle' @elem_len = element.length @out = [element, 'crime', 'fun'] end it 'should not raise error' do expect { Pry::Helpers.tablify(@out, @elem_len - 1) }.not_to raise_error end it 'should format output as one column' do table = Pry::Helpers.tablify(@out, @elem_len - 1).to_s table.should == "swizzle\ncrime \nfun " end end should 'decide between one-line or indented output' do Pry::Helpers.tablify_or_one_line('head', %w(ing)).should == "head: ing\n" end end pry-0.10.3/spec/history_array_spec.rb000066400000000000000000000032561260757071700176170ustar00rootroot00000000000000require_relative 'helper' describe Pry::HistoryArray do before do @array = Pry::HistoryArray.new 10 @populated = @array.dup << 1 << 2 << 3 << 4 end it 'should have a maximum size specifed at creation time' do @array.max_size.should == 10 end it 'should be able to be added objects to' do @populated.size.should == 4 @populated.to_a.should == [1, 2, 3, 4] end it 'should be able to access single elements' do @populated[2].should == 3 end it 'should be able to access negative indices' do @populated[-1].should == 4 end it 'should be able to access ranges' do @populated[1..2].should == [2, 3] end it 'should be able to access ranges starting from a negative index' do @populated[-2..3].should == [3, 4] end it 'should be able to access ranges ending at a negative index' do @populated[2..-1].should == [3, 4] end it 'should be able to access ranges using only negative indices' do @populated[-2..-1].should == [3, 4] end it 'should be able to use range where end is excluded' do @populated[-2...-1].should == [3] end it 'should be able to access slices using a size' do @populated[-3, 2].should == [2, 3] end it 'should remove older entries' do 11.times { |n| @array << n } @array[0].should == nil @array[1].should == 1 @array[10].should == 10 end it 'should not be larger than specified maximum size' do 12.times { |n| @array << n } @array.entries.compact.size.should == 10 end it 'should pop!' do @populated.pop! @populated.to_a.should == [1, 2, 3] end it 'should return an indexed hash' do @populated.to_h[0].should == @populated[0] end end pry-0.10.3/spec/history_spec.rb000066400000000000000000000107511260757071700164170ustar00rootroot00000000000000require_relative 'helper' require 'tempfile' describe Pry do before do Pry.history.clear @saved_history = "1\n2\n3\n" Pry.history.loader = proc do |&blk| @saved_history.lines.each { |l| blk.call(l) } end Pry.load_history end after do Pry.history.clear Pry.history.restore_default_behavior Pry.history.instance_variable_set(:@original_lines, 0) end describe '#push' do it "does not record duplicated lines" do Pry.history << '3' Pry.history << '_ += 1' Pry.history << '_ += 1' Pry.history.to_a.grep('_ += 1').count.should == 1 end it "does not record empty lines" do c = Pry.history.to_a.count Pry.history << '' Pry.history.to_a.count.should == c end end describe "#clear" do before do @old_file = Pry.config.history.file @hist_file_path = File.expand_path('spec/fixtures/pry_history') Pry.config.history.file = @hist_file_path Pry.history.clear Pry.history.restore_default_behavior Pry.load_history end after do Pry.config.history.file = @old_file end it "clears this session's history" do Pry.history.to_a.size.should > 0 Pry.history.clear Pry.history.to_a.size.should == 0 end it "doesn't affect the contents of the history file" do Pry.history.to_a.size.should == 3 Pry.history.clear File.open(@hist_file_path, 'r') { |fh| file = fh.to_a file.length.should == 3 file.any? { |a| a =~ /athos/ }.should == true } end end describe "#history_line_count" do it "counts entries in history" do Pry.history.clear saved_history = "olgierd\ngustlik\njanek\ngrzes\ntomek\n" Pry.history.loader = proc do |&blk| saved_history.lines.each { |l| blk.call(l) } end Pry.load_history Pry.history.history_line_count.should == 5 end end describe "#restore_default_behavior" do it "restores loader" do Pry.history.loader = proc {} Pry.history.restore_default_behavior Pry.history.loader.class.should == Method Pry.history.loader.name.to_sym.should == :read_from_file end it "restores saver" do Pry.history.saver = proc {} Pry.history.restore_default_behavior Pry.history.saver.class.should == Method Pry.history.saver.name.to_sym.should == :save_to_file end it "restores pusher" do Pry.history.pusher = proc {} Pry.history.restore_default_behavior Pry.history.pusher.class.should == Method Pry.history.pusher.name.to_sym.should == :push_to_readline end it "restores clearer" do Pry.history.clearer = proc {} Pry.history.restore_default_behavior Pry.history.clearer.class.should == Method Pry.history.clearer.name.to_sym.should == :clear_readline end end describe "#session_line_count" do it "returns the number of lines in history from just this session" do Pry.history << 'you?' Pry.history << 'you are so precious' Pry.history.session_line_count.should == 2 end end describe ".load_history" do it "reads the contents of the file" do Pry.history.to_a[-2..-1].should == %w(2 3) end end describe "saving to a file" do before do @histfile = Tempfile.new(["pryhistory", "txt"]) @history = Pry::History.new(:file_path => @histfile.path) Pry.config.history.should_save = true @history.pusher = proc{ } end after do @histfile.close(true) Pry.config.history.should_save = false end it "saves lines to a file as they are written" do @history.push "5" File.read(@histfile.path).should == "5\n" end it "interleaves lines from many places" do @history.push "5" File.open(@histfile.path, 'a'){ |f| f.puts "6" } @history.push "7" File.read(@histfile.path).should == "5\n6\n7\n" end end describe "expanding the history file path" do before { Pry.config.history.should_save = true } after { Pry.config.history.should_save = false } it "recognizes ~ (#1262)" do # This is a pretty dumb way of testing this, but at least it shouldn't # succeed spuriously. history = Pry::History.new(file_path: '~/test_history') error = Class.new(RuntimeError) expect(File).to receive(:open). with(File.join(ENV['HOME'].to_s, "/test_history"), 'a', 0600). and_raise(error) expect { history.push 'a line' }.to raise_error error end end end pry-0.10.3/spec/hooks_spec.rb000066400000000000000000000363161260757071700160460ustar00rootroot00000000000000require_relative 'helper' describe Pry::Hooks do before do @hooks = Pry::Hooks.new end describe "adding a new hook" do it 'should not execute hook while adding it' do run = false @hooks.add_hook(:test_hook, :my_name) { run = true } run.should == false end it 'should not allow adding of a hook with a duplicate name' do @hooks.add_hook(:test_hook, :my_name) {} expect { @hooks.add_hook(:test_hook, :my_name) {} }.to raise_error end it 'should create a new hook with a block' do @hooks.add_hook(:test_hook, :my_name) { } @hooks.hook_count(:test_hook).should == 1 end it 'should create a new hook with a callable' do @hooks.add_hook(:test_hook, :my_name, proc { }) @hooks.hook_count(:test_hook).should == 1 end it 'should use block if given both block and callable' do run = false foo = false @hooks.add_hook(:test_hook, :my_name, proc { foo = true }) { run = true } @hooks.hook_count(:test_hook).should == 1 @hooks.exec_hook(:test_hook) run.should == true foo.should == false end it 'should raise if not given a block or any other object' do expect { @hooks.add_hook(:test_hook, :my_name) }.to raise_error ArgumentError end it 'should create multiple hooks for an event' do @hooks.add_hook(:test_hook, :my_name) {} @hooks.add_hook(:test_hook, :my_name2) {} @hooks.hook_count(:test_hook).should == 2 end it 'should return a count of 0 for an empty hook' do @hooks.hook_count(:test_hook).should == 0 end end describe "Pry::Hooks#merge" do describe "merge!" do it 'should merge in the Pry::Hooks' do h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {} h2 = Pry::Hooks.new h2.merge!(h1) h2.get_hook(:test_hook, :testing).should == h1.get_hook(:test_hook, :testing) end it 'should not share merged elements with original' do h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {} h2 = Pry::Hooks.new h2.merge!(h1) h2.add_hook(:test_hook, :testing2) {} h2.get_hook(:test_hook, :testing2).should_not == h1.get_hook(:test_hook, :testing2) end it 'should NOT overwrite hooks belonging to shared event in receiver' do h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {} callable = proc {} h2 = Pry::Hooks.new.add_hook(:test_hook, :testing2, callable) h2.merge!(h1) h2.get_hook(:test_hook, :testing2).should == callable end it 'should overwrite identical hook in receiver' do callable1 = proc { :one } h1 = Pry::Hooks.new.add_hook(:test_hook, :testing, callable1) callable2 = proc { :two } h2 = Pry::Hooks.new.add_hook(:test_hook, :testing, callable2) h2.merge!(h1) h2.get_hook(:test_hook, :testing).should == callable1 h2.hook_count(:test_hook).should == 1 end it 'should preserve hook order' do name = "" h1 = Pry::Hooks.new h1.add_hook(:test_hook, :testing3) { name << "h" } h1.add_hook(:test_hook, :testing4) { name << "n" } h2 = Pry::Hooks.new h2.add_hook(:test_hook, :testing1) { name << "j" } h2.add_hook(:test_hook, :testing2) { name << "o" } h2.merge!(h1) h2.exec_hook(:test_hook) name.should == "john" end describe "merge" do it 'should return a fresh, independent instance' do h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {} h2 = Pry::Hooks.new h3 = h2.merge(h1) h3.should_not == h1 h3.should_not == h2 end it 'should contain hooks from original instance' do h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {} h2 = Pry::Hooks.new.add_hook(:test_hook2, :testing) {} h3 = h2.merge(h1) h3.get_hook(:test_hook, :testing).should == h1.get_hook(:test_hook, :testing) h3.get_hook(:test_hook2, :testing).should == h2.get_hook(:test_hook2, :testing) end it 'should not affect original instances when new hooks are added' do h1 = Pry::Hooks.new.add_hook(:test_hook, :testing) {} h2 = Pry::Hooks.new.add_hook(:test_hook2, :testing) {} h3 = h2.merge(h1) h3.add_hook(:test_hook3, :testing) {} h1.get_hook(:test_hook3, :testing).should == nil h2.get_hook(:test_hook3, :testing).should == nil end end end end describe "dupping a Pry::Hooks instance" do it 'should share hooks with original' do @hooks.add_hook(:test_hook, :testing) do :none_such end hooks_dup = @hooks.dup hooks_dup.get_hook(:test_hook, :testing).should == @hooks.get_hook(:test_hook, :testing) end it 'adding a new event to dupped instance should not affect original' do @hooks.add_hook(:test_hook, :testing) { :none_such } hooks_dup = @hooks.dup hooks_dup.add_hook(:other_test_hook, :testing) { :okay_man } hooks_dup.get_hook(:other_test_hook, :testing).should_not == @hooks.get_hook(:other_test_hook, :testing) end it 'adding a new hook to dupped instance should not affect original' do @hooks.add_hook(:test_hook, :testing) { :none_such } hooks_dup = @hooks.dup hooks_dup.add_hook(:test_hook, :testing2) { :okay_man } hooks_dup.get_hook(:test_hook, :testing2).should_not == @hooks.get_hook(:test_hook, :testing2) end end describe "getting hooks" do describe "get_hook" do it 'should return the correct requested hook' do run = false fun = false @hooks.add_hook(:test_hook, :my_name) { run = true } @hooks.add_hook(:test_hook, :my_name2) { fun = true } @hooks.get_hook(:test_hook, :my_name).call run.should == true fun.should == false end it 'should return nil if hook does not exist' do @hooks.get_hook(:test_hook, :my_name).should == nil end end describe "get_hooks" do it 'should return a hash of hook names/hook functions for an event' do hook1 = proc { 1 } hook2 = proc { 2 } @hooks.add_hook(:test_hook, :my_name1, hook1) @hooks.add_hook(:test_hook, :my_name2, hook2) hash = @hooks.get_hooks(:test_hook) hash.size.should == 2 hash[:my_name1].should == hook1 hash[:my_name2].should == hook2 end it 'should return an empty hash if no hooks defined' do @hooks.get_hooks(:test_hook).should == {} end end end describe "clearing all hooks for an event" do it 'should clear all hooks' do @hooks.add_hook(:test_hook, :my_name) { } @hooks.add_hook(:test_hook, :my_name2) { } @hooks.add_hook(:test_hook, :my_name3) { } @hooks.clear(:test_hook) @hooks.hook_count(:test_hook).should == 0 end end describe "deleting a hook" do it 'should successfully delete a hook' do @hooks.add_hook(:test_hook, :my_name) {} @hooks.delete_hook(:test_hook, :my_name) @hooks.hook_count(:test_hook).should == 0 end it 'should return the deleted hook' do run = false @hooks.add_hook(:test_hook, :my_name) { run = true } @hooks.delete_hook(:test_hook, :my_name).call run.should == true end it 'should return nil if hook does not exist' do @hooks.delete_hook(:test_hook, :my_name).should == nil end end describe "executing a hook" do it 'should execute block hook' do run = false @hooks.add_hook(:test_hook, :my_name) { run = true } @hooks.exec_hook(:test_hook) run.should == true end it 'should execute proc hook' do run = false @hooks.add_hook(:test_hook, :my_name, proc { run = true }) @hooks.exec_hook(:test_hook) run.should == true end it 'should execute a general callable hook' do callable = Object.new.tap do |obj| obj.instance_variable_set(:@test_var, nil) class << obj attr_accessor :test_var def call() @test_var = true; end end end @hooks.add_hook(:test_hook, :my_name, callable) @hooks.exec_hook(:test_hook) callable.test_var.should == true end it 'should execute all hooks for an event if more than one is defined' do x = nil y = nil @hooks.add_hook(:test_hook, :my_name1) { y = true } @hooks.add_hook(:test_hook, :my_name2) { x = true } @hooks.exec_hook(:test_hook) x.should == true y.should == true end it 'should execute hooks in order' do array = [] @hooks.add_hook(:test_hook, :my_name1) { array << 1 } @hooks.add_hook(:test_hook, :my_name2) { array << 2 } @hooks.add_hook(:test_hook, :my_name3) { array << 3 } @hooks.exec_hook(:test_hook) array.should == [1, 2, 3] end it 'return value of exec_hook should be that of last executed hook' do @hooks.add_hook(:test_hook, :my_name1) { 1 } @hooks.add_hook(:test_hook, :my_name2) { 2 } @hooks.add_hook(:test_hook, :my_name3) { 3 } @hooks.exec_hook(:test_hook).should == 3 end it 'should add exceptions to the errors array' do @hooks.add_hook(:test_hook, :foo1) { raise 'one' } @hooks.add_hook(:test_hook, :foo2) { raise 'two' } @hooks.add_hook(:test_hook, :foo3) { raise 'three' } @hooks.exec_hook(:test_hook) @hooks.errors.map(&:message).should == ['one', 'two', 'three'] end it 'should return the last exception raised as the return value' do @hooks.add_hook(:test_hook, :foo1) { raise 'one' } @hooks.add_hook(:test_hook, :foo2) { raise 'two' } @hooks.add_hook(:test_hook, :foo3) { raise 'three' } @hooks.exec_hook(:test_hook).should == @hooks.errors.last end end describe "integration tests" do describe "when_started hook" do it 'should yield options to the hook' do options = nil Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _| options = opt } redirect_pry_io(StringIO.new("exit"), out=StringIO.new) do Pry.start binding, :hello => :baby end options[:hello].should == :baby Pry.config.hooks.delete_hook(:when_started, :test_hook) end describe "target" do it 'should yield the target, as a binding ' do b = nil Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _| b = target } redirect_pry_io(StringIO.new("exit"), out=StringIO.new) do Pry.start 5, :hello => :baby end b.is_a?(Binding).should == true Pry.config.hooks.delete_hook(:when_started, :test_hook) end it 'should yield the target to the hook' do b = nil Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _| b = target } redirect_pry_io(StringIO.new("exit"), out=StringIO.new) do Pry.start 5, :hello => :baby end b.eval('self').should == 5 Pry.config.hooks.delete_hook(:when_started, :test_hook) end end it 'should allow overriding of target (and binding_stack)' do options = nil o = Object.new class << o; attr_accessor :value; end Pry.config.hooks.add_hook(:when_started, :test_hook) { |target, opt, _pry_| _pry_.binding_stack = [Pry.binding_for(o)] } redirect_pry_io(InputTester.new("@value = true","exit-all")) do Pry.start binding, :hello => :baby end o.value.should == true Pry.config.hooks.delete_hook(:when_started, :test_hook) end end describe "after_session hook" do it 'should always run, even if uncaught exception bubbles out of repl' do o = OpenStruct.new o.great_escape = Class.new(StandardError) old_ew = Pry.config.exception_whitelist Pry.config.exception_whitelist << o.great_escape array = [1, 2, 3, 4, 5] begin redirect_pry_io(StringIO.new("raise great_escape"), out=StringIO.new) do Pry.start o, :hooks => Pry::Hooks.new.add_hook(:after_session, :cleanup) { array = nil } end rescue => ex exception = ex end # ensure that an exception really was raised and it broke out # of the repl exception.is_a?(o.great_escape).should == true # check that after_session hook ran array.should == nil # cleanup after test Pry.config.exception_whitelist = old_ew end describe "before_eval hook" do describe "modifying input code" do it 'should replace input code with code determined by hook' do hooks = Pry::Hooks.new.add_hook(:before_eval, :quirk) { |code, pry| code.replace(":little_duck") } redirect_pry_io(InputTester.new(":jemima", "exit-all"), out = StringIO.new) do Pry.start(self, :hooks => hooks) end out.string.should =~ /little_duck/ out.string.should_not =~ /jemima/ end it 'should not interfere with command processing when replacing input code' do commands = Pry::CommandSet.new do import_from Pry::Commands, "exit-all" command "how-do-you-like-your-blue-eyed-boy-now-mister-death" do output.puts "in hours of bitterness i imagine balls of sapphire, of metal" end end hooks = Pry::Hooks.new.add_hook(:before_eval, :quirk) { |code, pry| code.replace(":little_duck") } redirect_pry_io(InputTester.new("how-do-you-like-your-blue-eyed-boy-now-mister-death", "exit-all"), out = StringIO.new) do Pry.start(self, :hooks => hooks, :commands => commands) end out.string.should =~ /in hours of bitterness i imagine balls of sapphire, of metal/ out.string.should_not =~ /little_duck/ end end end describe "exceptions" do before do Pry.config.hooks.add_hook(:after_eval, :baddums){ raise "Baddums" } Pry.config.hooks.add_hook(:after_eval, :simbads){ raise "Simbads" } end after do Pry.config.hooks.delete_hook(:after_eval, :baddums) Pry.config.hooks.delete_hook(:after_eval, :simbads) end it "should not raise exceptions" do expect { mock_pry("1", "2", "3") }.to_not raise_error end it "should print out a notice for each exception raised" do mock_pry("1").should =~ /after_eval hook failed: RuntimeError: Baddums\n.*after_eval hook failed: RuntimeError: Simbads/m end end end end describe "anonymous hooks" do it 'should allow adding of hook without a name' do @hooks.add_hook(:test_hook, nil) {} @hooks.hook_count(:test_hook).should == 1 end it 'should only allow one anonymous hook to exist' do @hooks.add_hook(:test_hook, nil) { } @hooks.add_hook(:test_hook, nil) { } @hooks.hook_count(:test_hook).should == 1 end it 'should execute most recently added anonymous hook' do x = nil y = nil @hooks.add_hook(:test_hook, nil) { y = 1 } @hooks.add_hook(:test_hook, nil) { x = 2 } @hooks.exec_hook(:test_hook) y.should == nil x.should == 2 end end end pry-0.10.3/spec/indent_spec.rb000066400000000000000000000143011260757071700161720ustar00rootroot00000000000000require_relative 'helper' # Please keep in mind that any hash signs ("#") in the heredoc strings are # placed on purpose. Without these editors might remove the whitespace on empty # lines. describe Pry::Indent do before do @indent = Pry::Indent.new end it 'should indent an array' do input = "array = [\n10,\n15\n]" output = "array = [\n 10,\n 15\n]" @indent.indent(input).should == output end it 'should indent a hash' do input = "hash = {\n:name => 'Ruby'\n}" output = "hash = {\n :name => 'Ruby'\n}" @indent.indent(input).should == output end it 'should indent a function' do input = "def\nreturn 10\nend" output = "def\n return 10\nend" @indent.indent(input).should == output end it 'should indent a module and class' do input = "module Foo\n# Hello world\nend" output = "module Foo\n # Hello world\nend" input_class = "class Foo\n# Hello world\nend" output_class = "class Foo\n # Hello world\nend" @indent.indent(input).should == output @indent.indent(input_class).should == output_class end it 'should indent separate lines' do @indent.indent('def foo').should == 'def foo' @indent.indent('return 10').should == ' return 10' @indent.indent('end').should == 'end' end it 'should not indent single line statements' do input = < do" do input = "while 5 do\n5\nend" @indent.indent(input).should == "while 5 do\n 5\nend" end it "should ident case statements" do input = <\n[]}]\n]").should == "[[{\n [] =>\n []}]\n]" end it "should not indent single-line ifs" do @indent.indent("foo if bar\n#").should == "foo if bar\n#" @indent.reset.indent("foo() if bar\n#").should == "foo() if bar\n#" @indent.reset.indent("foo 'hi' if bar\n#").should == "foo 'hi' if bar\n#" @indent.reset.indent("foo 1 while bar\n#").should == "foo 1 while bar\n#" @indent.reset.indent("super if true\n#").should == "super if true\n#" @indent.reset.indent("true if false\n#").should == "true if false\n#" @indent.reset.indent("String if false\n#").should == "String if false\n#" end it "should indent cunningly disguised ifs" do @indent.indent("{1 => if bar\n#").should == "{1 => if bar\n #" @indent.reset.indent("foo(if bar\n#").should == "foo(if bar\n #" @indent.reset.indent("bar(baz, if bar\n#").should == "bar(baz, if bar\n #" @indent.reset.indent("[if bar\n#").should == "[if bar\n #" @indent.reset.indent("true; while bar\n#").should == "true; while bar\n #" end it "should differentiate single/multi-line unless" do @indent.indent("foo unless bar\nunless foo\nbar\nend").should == "foo unless bar\nunless foo\n bar\nend" end it "should not indent single/multi-line until" do @indent.indent("%w{baz} until bar\nuntil foo\nbar\nend").should == "%w{baz} until bar\nuntil foo\n bar\nend" end it "should indent begin rescue end" do input = < :wrong rescue => e doit :right end INPUT output = < :wrong rescue => e doit :right end OUTPUT @indent.indent(input).should == output end it "should not indent inside strings" do @indent.indent(%(def a\n"foo\nbar"\n end)).should == %(def a\n "foo\nbar"\nend) @indent.indent(%(def a\nputs %w(foo\nbar), 'foo\nbar'\n end)).should == %(def a\n puts %w(foo\nbar), 'foo\nbar'\nend) end it "should not indent inside HEREDOCs" do @indent.indent(%(def a\nputs < true}) meth.should == klass.instance_method(:hello) end it 'should look up methods if :methods option provided' do klass = Class.new { def hello; end; def self.hello; end } meth = Pry::Method.from_str(:hello, Pry.binding_for(klass), {:methods => true}) meth.should == klass.method(:hello) end it 'should look up instance methods using the Class#method syntax' do klass = Class.new { def hello; end; def self.hello; end } meth = Pry::Method.from_str("klass#hello", Pry.binding_for(binding)) meth.should == klass.instance_method(:hello) end it 'should look up methods using the object.method syntax' do klass = Class.new { def hello; end; def self.hello; end } meth = Pry::Method.from_str("klass.hello", Pry.binding_for(binding)) meth.should == klass.method(:hello) end it 'should NOT look up instance methods using the Class#method syntax if no instance methods defined' do klass = Class.new { def self.hello; end } meth = Pry::Method.from_str("klass#hello", Pry.binding_for(binding)) meth.should == nil end it 'should NOT look up methods using the object.method syntax if no methods defined' do klass = Class.new { def hello; end } meth = Pry::Method.from_str("klass.hello", Pry.binding_for(binding)) meth.should == nil end it 'should look up methods using klass.new.method syntax' do klass = Class.new { def hello; :hello; end } meth = Pry::Method.from_str("klass.new.hello", Pry.binding_for(binding)) meth.name.should == "hello" end it 'should take care of corner cases like mongo[] e.g Foo::Bar.new[]- issue 998' do klass = Class.new { def []; :hello; end } meth = Pry::Method.from_str("klass.new[]", Pry.binding_for(binding)) meth.name.should == "[]" end it 'should take care of cases like $ mongo[] - issue 998' do f = Class.new { def []; :hello; end }.new meth = Pry::Method.from_str("f[]", Pry.binding_for(binding)) meth.name.should == "[]" end it 'should look up instance methods using klass.meth#method syntax' do klass = Class.new { def self.meth; Class.new; end } meth = Pry::Method.from_str("klass.meth#initialize", Pry.binding_for(binding)) meth.name.should == "initialize" end it 'should look up methods using instance::bar syntax' do klass = Class.new{ def self.meth; Class.new; end } meth = Pry::Method.from_str("klass::meth", Pry.binding_for(binding)) meth.name.should == "meth" end it 'should not raise an exception if receiver does not exist' do expect { Pry::Method.from_str("random_klass.meth", Pry.binding_for(binding)) }.to_not raise_error end end describe '.from_binding' do it 'should be able to pick a method out of a binding' do Pry::Method.from_binding(Class.new{ def self.foo; binding; end }.foo).name.should == "foo" end it 'should NOT find a method from the toplevel binding' do Pry::Method.from_binding(TOPLEVEL_BINDING).should == nil end it "should find methods that have been undef'd" do c = Class.new do def self.bar class << self; undef bar; end binding end end m = Pry::Method.from_binding(c.bar) m.name.should == "bar" end # Our source_location trick doesn't work, due to https://github.com/rubinius/rubinius/issues/953 unless Pry::Helpers::BaseHelpers.rbx? it 'should find the super method correctly' do a = Class.new{ def gag33; binding; end; def self.line; __LINE__; end } b = Class.new(a){ def gag33; super; end } g = b.new.gag33 m = Pry::Method.from_binding(g) m.owner.should == a m.source_line.should == a.line m.name.should == "gag33" end end it 'should find the right method if a super method exists' do a = Class.new{ def gag; binding; end; } b = Class.new(a){ def gag; super; binding; end; def self.line; __LINE__; end } m = Pry::Method.from_binding(b.new.gag) m.owner.should == b m.source_line.should == b.line m.name.should == "gag" end # Temporarily disabled to work around rubinius/rubinius#2871. unless Pry::Helpers::BaseHelpers.rbx? it "should find the right method from a BasicObject" do a = Class.new(BasicObject) { def gag; ::Kernel.binding; end; def self.line; __LINE__; end } m = Pry::Method.from_binding(a.new.gag) m.owner.should == a m.source_file.should == __FILE__ m.source_line.should == a.line end end it 'should find the right method even if it was renamed and replaced' do o = Object.new class << o def borscht "nips" binding end alias paella borscht def borscht() paella end end m = Pry::Method.from_binding(o.borscht) m.source.should == Pry::Method(o.method(:paella)).source end end describe 'super' do it 'should be able to find the super method on a bound method' do a = Class.new{ def rar; 4; end } b = Class.new(a){ def rar; super; end } obj = b.new zuper = Pry::Method(obj.method(:rar)).super zuper.owner.should == a zuper.receiver.should == obj end it 'should be able to find the super method of an unbound method' do a = Class.new{ def rar; 4; end } b = Class.new(a){ def rar; super; end } zuper = Pry::Method(b.instance_method(:rar)).super zuper.owner.should == a end it 'should return nil if no super method exists' do a = Class.new{ def rar; super; end } Pry::Method(a.instance_method(:rar)).super.should == nil end it 'should be able to find super methods defined on modules' do m = Module.new{ def rar; 4; end } a = Class.new{ def rar; super; end; include m } zuper = Pry::Method(a.new.method(:rar)).super zuper.owner.should == m end it 'should be able to find super methods defined on super-classes when there are modules in the way' do a = Class.new{ def rar; 4; end } m = Module.new{ def mooo; 4; end } b = Class.new(a){ def rar; super; end; include m } zuper = Pry::Method(b.new.method(:rar)).super zuper.owner.should == a end it 'should be able to jump up multiple levels of bound method, even through modules' do a = Class.new{ def rar; 4; end } m = Module.new{ def rar; 4; end } b = Class.new(a){ def rar; super; end; include m } zuper = Pry::Method(b.new.method(:rar)).super zuper.owner.should == m zuper.super.owner.should == a end end describe 'all_from_class' do def should_find_method(name) Pry::Method.all_from_class(@class).map(&:name).should include name end it 'should be able to find public instance methods defined in a class' do @class = Class.new{ def meth; 1; end } should_find_method('meth') end it 'should be able to find private and protected instance methods defined in a class' do @class = Class.new { protected; def prot; 1; end; private; def priv; 1; end } should_find_method('priv') should_find_method('prot') end it 'should find methods all the way up to Kernel' do @class = Class.new should_find_method('exit!') end it 'should be able to find instance methods defined in a super-class' do @class = Class.new(Class.new{ def meth; 1; end }) {} should_find_method('meth') end it 'should be able to find instance methods defined in modules included into this class' do @class = Class.new{ include Module.new{ def meth; 1; end; } } should_find_method('meth') end it 'should be able to find instance methods defined in modules included into super-classes' do @class = Class.new(Class.new{ include Module.new{ def meth; 1; end; } }) should_find_method('meth') end it 'should attribute overridden methods to the sub-class' do @class = Class.new(Class.new{ include Module.new{ def meth; 1; end; } }) { def meth; 2; end } Pry::Method.all_from_class(@class).detect{ |x| x.name == 'meth' }.owner.should == @class end it 'should be able to find methods defined on a singleton class' do @class = (class << Object.new; def meth; 1; end; self; end) should_find_method('meth') end it 'should be able to find methods on super-classes when given a singleton class' do @class = (class << Class.new{ def meth; 1; end}.new; self; end) should_find_method('meth') end end describe 'all_from_obj' do describe 'on normal objects' do def should_find_method(name) Pry::Method.all_from_obj(@obj).map(&:name).should include name end it "should find methods defined in the object's class" do @obj = Class.new{ def meth; 1; end }.new should_find_method('meth') end it "should find methods defined in modules included into the object's class" do @obj = Class.new{ include Module.new{ def meth; 1; end } }.new should_find_method('meth') end it "should find methods defined in the object's singleton class" do @obj = Object.new class << @obj; def meth; 1; end; end should_find_method('meth') end it "should find methods in modules included into the object's singleton class" do @obj = Object.new @obj.extend Module.new{ def meth; 1; end } should_find_method('meth') end it "should find methods all the way up to Kernel" do @obj = Object.new should_find_method('exit!') end it "should not find methods defined on the classes singleton class" do @obj = Class.new{ class << self; def meth; 1; end; end }.new Pry::Method.all_from_obj(@obj).map(&:name).should_not include 'meth' end it "should work in the face of an overridden send" do @obj = Class.new{ def meth; 1; end; def send; raise EOFError; end }.new should_find_method('meth') end end describe 'on classes' do def should_find_method(name) Pry::Method.all_from_obj(@class).map(&:name).should include name end it "should find methods defined in the class' singleton class" do @class = Class.new{ class << self; def meth; 1; end; end } should_find_method('meth') end it "should find methods defined on modules extended into the class" do @class = Class.new{ extend Module.new{ def meth; 1; end; } } should_find_method('meth') end it "should find methods defined on the singleton class of super-classes" do @class = Class.new(Class.new{ class << self; def meth; 1; end; end }) should_find_method('meth') end it "should not find methods defined within the class" do @class = Class.new{ def meth; 1; end } Pry::Method.all_from_obj(@obj).map(&:name).should_not include 'meth' end it "should find methods defined on Class" do @class = Class.new should_find_method('allocate') end it "should find methods defined on Kernel" do @class = Class.new should_find_method('exit!') end it "should attribute overridden methods to the sub-class' singleton class" do @class = Class.new(Class.new{ class << self; def meth; 1; end; end }) { class << self; def meth; 1; end; end } Pry::Method.all_from_obj(@class).detect{ |x| x.name == 'meth' }.owner.should == (class << @class; self; end) end it "should attrbute overridden methods to the class not the module" do @class = Class.new { class << self; def meth; 1; end; end; extend Module.new{ def meth; 1; end; } } Pry::Method.all_from_obj(@class).detect{ |x| x.name == 'meth' }.owner.should == (class << @class; self; end) end it "should attribute overridden methods to the relevant singleton class in preference to Class" do @class = Class.new { class << self; def allocate; 1; end; end } Pry::Method.all_from_obj(@class).detect{ |x| x.name == 'allocate' }.owner.should == (class << @class; self; end) end end describe 'method resolution order' do module LS class Top; end class Next < Top; end module M; end module N; include M; end module O; include M; end module P; end class Low < Next; include N; include P; end class Lower < Low; extend N; end class Bottom < Lower; extend O; end end def singleton_class2(obj); class << obj; self; end; end it "should look at a class and then its superclass" do Pry::Method.instance_resolution_order(LS::Next).should == [LS::Next] + Pry::Method.instance_resolution_order(LS::Top) end it "should include the included modules between a class and its superclass" do Pry::Method.instance_resolution_order(LS::Low).should == [LS::Low, LS::P, LS::N, LS::M] + Pry::Method.instance_resolution_order(LS::Next) end it "should not include modules extended into the class" do Pry::Method.instance_resolution_order(LS::Bottom).should == [LS::Bottom] + Pry::Method.instance_resolution_order(LS::Lower) end it "should include included modules for Modules" do Pry::Method.instance_resolution_order(LS::O).should == [LS::O, LS::M] end it "should include the singleton class of objects" do obj = LS::Low.new Pry::Method.resolution_order(obj).should == [singleton_class2(obj)] + Pry::Method.instance_resolution_order(LS::Low) end it "should not include singleton classes of numbers" do Pry::Method.resolution_order(4).should == Pry::Method.instance_resolution_order(Fixnum) end it "should include singleton classes for classes" do Pry::Method.resolution_order(LS::Low).should == [singleton_class2(LS::Low)] + Pry::Method.resolution_order(LS::Next) end it "should include modules included into singleton classes" do Pry::Method.resolution_order(LS::Lower).should == [singleton_class2(LS::Lower), LS::N, LS::M] + Pry::Method.resolution_order(LS::Low) end it "should include modules at most once" do Pry::Method.resolution_order(LS::Bottom).count(LS::M).should == 1 end it "should include modules at the point which they would be reached" do Pry::Method.resolution_order(LS::Bottom).should == [singleton_class2(LS::Bottom), LS::O] + (Pry::Method.resolution_order(LS::Lower)) end it "should include the Pry::Method.instance_resolution_order of Class after the singleton classes" do Pry::Method.resolution_order(LS::Top).should == [singleton_class2(LS::Top), singleton_class2(Object), singleton_class2(BasicObject), *Pry::Method.instance_resolution_order(Class)] end end end describe 'method_name_from_first_line' do it 'should work in all simple cases' do meth = Pry::Method.new(nil) meth.send(:method_name_from_first_line, "def x").should == "x" meth.send(:method_name_from_first_line, "def self.x").should == "x" meth.send(:method_name_from_first_line, "def ClassName.x").should == "x" meth.send(:method_name_from_first_line, "def obj_name.x").should == "x" end end describe 'method aliases' do before do @class = Class.new { def eat end alias fress eat alias_method :omnomnom, :fress def eruct end } end it 'should be able to find method aliases' do meth = Pry::Method(@class.new.method(:eat)) aliases = Set.new(meth.aliases) aliases.should == Set.new(["fress", "omnomnom"]) end it 'should return an empty Array if cannot find aliases' do meth = Pry::Method(@class.new.method(:eruct)) meth.aliases.should be_empty end it 'should not include the own name in the list of aliases' do meth = Pry::Method(@class.new.method(:eat)) meth.aliases.should_not include "eat" end it 'should find aliases for top-level methods' do # top-level methods get added as private instance methods on Object class Object private def my_top_level_method ; end alias my_other_top_level_method my_top_level_method end meth = Pry::Method.new(method(:my_top_level_method)) meth.aliases.should include 'my_other_top_level_method' class Object remove_method :my_top_level_method end end it 'should be able to find aliases for methods implemented in C' do meth = Pry::Method(Hash.new.method(:key?)) aliases = Set.new(meth.aliases) aliases.should == Set.new(["include?", "member?", "has_key?"]) end end end pry-0.10.3/spec/pager_spec.rb000066400000000000000000000031521260757071700160110ustar00rootroot00000000000000require_relative "helper" describe "Pry::Pager" do describe "PageTracker" do before do @pt = Pry::Pager::PageTracker.new(10, 10) end def record_short_line @pt.record "012345678\n" end def record_long_line @pt.record "0123456789012\n" end def record_multiline @pt.record "0123456789012\n01\n" end def record_string_without_newline @pt.record "0123456789" end def record_string_with_color_codes @pt.record(CodeRay.scan("0123456789", :ruby).term + "\n") end it "records short lines that don't add up to a page" do 9.times { record_short_line } @pt.page?.should equal false end it "records short lines that do add up to a page" do 10.times { record_short_line } @pt.page?.should equal true end it "treats a long line as taking up more than one row" do 4.times { record_long_line } @pt.page?.should equal false record_long_line @pt.page?.should equal true end it "records a string with an embedded newline" do 3.times { record_multiline } @pt.page?.should equal false record_short_line @pt.page?.should equal true end it "doesn't count a line until it ends" do 12.times { record_string_without_newline } @pt.page?.should equal false record_short_line @pt.page?.should equal true end it "doesn't count ansi color codes towards length" do 9.times { record_string_with_color_codes } @pt.page?.should equal false record_string_with_color_codes @pt.page?.should equal true end end end pry-0.10.3/spec/prompt_spec.rb000066400000000000000000000037501260757071700162400ustar00rootroot00000000000000require_relative 'helper' describe "Prompts" do describe "one-parameter prompt proc" do it 'should get full config object' do config = nil redirect_pry_io(InputTester.new("exit-all")) do Pry.start(self, :prompt => proc { |v| config = v }) end config.is_a?(Pry::Config).should == true end it 'should get full config object, when using a proc array' do config1 = nil redirect_pry_io(InputTester.new("exit-all")) do Pry.start(self, :prompt => [proc { |v| config1 = v }, proc { |v| config2 = v }]) end config1.is_a?(Pry::Config).should == true end it 'should receive correct data in the config object' do config = nil redirect_pry_io(InputTester.new("def hello", "exit-all")) do Pry.start(self, :prompt => proc { |v| config = v }) end config.eval_string.should =~ /def hello/ config.nesting_level.should == 0 config.expr_number.should == 1 config.cont.should == true config._pry_.is_a?(Pry).should == true expect(config.object).to eq self end end describe "BACKWARDS COMPATIBILITY: 3 parameter prompt proc" do it 'should get 3 parameters' do o = n = p = nil redirect_pry_io(InputTester.new("exit-all")) do Pry.start(:test, :prompt => proc { |obj, nesting, _pry_| o, n, p = obj, nesting, _pry_ }) end o.should == :test n.should == 0 p.is_a?(Pry).should == true end it 'should get 3 parameters, when using proc array' do o1 = n1 = p1 = nil redirect_pry_io(InputTester.new("exit-all")) do Pry.start(:test, :prompt => [proc { |obj, nesting, _pry_| o1, n1, p1 = obj, nesting, _pry_ }, proc { |obj, nesting, _pry_| o2, n2, p2 = obj, nesting, _pry_ }]) end o1.should == :test n1.should == 0 p1.is_a?(Pry).should == true end end end pry-0.10.3/spec/pry_defaults_spec.rb000066400000000000000000000324641260757071700174240ustar00rootroot00000000000000require_relative 'helper' version = 1 describe "test Pry defaults" do before do @str_output = StringIO.new end after do Pry.reset_defaults Pry.config.color = false end describe "input" do after do Pry.reset_defaults Pry.config.color = false end it 'should set the input default, and the default should be overridable' do Pry.config.input = InputTester.new("5") Pry.config.output = @str_output Object.new.pry @str_output.string.should =~ /5/ Pry.config.output = @str_output Object.new.pry :input => InputTester.new("6") @str_output.string.should =~ /6/ end it 'should pass in the prompt if readline arity is 1' do Pry.prompt = proc { "A" } arity_one_input = Class.new do attr_accessor :prompt def readline(prompt) @prompt = prompt "exit-all" end end.new Pry.start(self, :input => arity_one_input, :output => StringIO.new) arity_one_input.prompt.should == Pry.prompt.call end it 'should not pass in the prompt if the arity is 0' do Pry.prompt = proc { "A" } arity_zero_input = Class.new do def readline "exit-all" end end.new expect { Pry.start(self, :input => arity_zero_input, :output => StringIO.new) }.to_not raise_error end it 'should not pass in the prompt if the arity is -1' do Pry.prompt = proc { "A" } arity_multi_input = Class.new do attr_accessor :prompt def readline(*args) @prompt = args.first "exit-all" end end.new Pry.start(self, :input => arity_multi_input, :output => StringIO.new) arity_multi_input.prompt.should == nil end end it 'should set the output default, and the default should be overridable' do Pry.config.output = @str_output Pry.config.input = InputTester.new("5") Object.new.pry @str_output.string.should =~ /5/ Pry.config.input = InputTester.new("6") Object.new.pry @str_output.string.should =~ /5\n.*6/ Pry.config.input = InputTester.new("7") @str_output = StringIO.new Object.new.pry :output => @str_output @str_output.string.should_not =~ /5\n.*6/ @str_output.string.should =~ /7/ end it "should set the print default, and the default should be overridable" do new_print = proc { |out, value| out.puts "=> LOL" } Pry.config.print = new_print Pry.new.print.should == Pry.config.print Object.new.pry :input => InputTester.new("\"test\""), :output => @str_output @str_output.string.should == "=> LOL\n" @str_output = StringIO.new Object.new.pry :input => InputTester.new("\"test\""), :output => @str_output, :print => proc { |out, value| out.puts value.reverse } @str_output.string.should == "tset\n" Pry.new.print.should == Pry.config.print @str_output = StringIO.new Object.new.pry :input => InputTester.new("\"test\""), :output => @str_output @str_output.string.should == "=> LOL\n" end describe "pry return values" do it 'should return nil' do Pry.start(self, :input => StringIO.new("exit-all"), :output => StringIO.new).should == nil end it 'should return the parameter given to exit-all' do Pry.start(self, :input => StringIO.new("exit-all 10"), :output => StringIO.new).should == 10 end it 'should return the parameter (multi word string) given to exit-all' do Pry.start(self, :input => StringIO.new("exit-all \"john mair\""), :output => StringIO.new).should == "john mair" end it 'should return the parameter (function call) given to exit-all' do Pry.start(self, :input => StringIO.new("exit-all 'abc'.reverse"), :output => StringIO.new).should == 'cba' end it 'should return the parameter (self) given to exit-all' do Pry.start("carl", :input => StringIO.new("exit-all self"), :output => StringIO.new).should == "carl" end end describe "prompts" do before do Pry.config.output = StringIO.new end def get_prompts(pry) a = pry.select_prompt pry.eval "[" b = pry.select_prompt pry.eval "]" [a, b] end it 'should set the prompt default, and the default should be overridable (single prompt)' do Pry.prompt = proc { "test prompt> " } new_prompt = proc { "A" } pry = Pry.new pry.prompt.should == Pry.prompt get_prompts(pry).should == ["test prompt> ", "test prompt> "] pry = Pry.new(:prompt => new_prompt) pry.prompt.should == new_prompt get_prompts(pry).should == ["A", "A"] pry = Pry.new pry.prompt.should == Pry.prompt get_prompts(pry).should == ["test prompt> ", "test prompt> "] end it 'should set the prompt default, and the default should be overridable (multi prompt)' do Pry.prompt = [proc { "test prompt> " }, proc { "test prompt* " }] new_prompt = [proc { "A" }, proc { "B" }] pry = Pry.new pry.prompt.should == Pry.prompt get_prompts(pry).should == ["test prompt> ", "test prompt* "] pry = Pry.new(:prompt => new_prompt) pry.prompt.should == new_prompt get_prompts(pry).should == ["A", "B"] pry = Pry.new pry.prompt.should == Pry.prompt get_prompts(pry).should == ["test prompt> ", "test prompt* "] end describe 'storing and restoring the prompt' do before do make = lambda do |name,i| prompt = [ proc { "#{i}>" } , proc { "#{i+1}>" } ] (class << prompt; self; end).send(:define_method, :inspect) { "" } prompt end @a , @b , @c = make[:a,0] , make[:b,1] , make[:c,2] @pry = Pry.new :prompt => @a end it 'should have a prompt stack' do @pry.push_prompt @b @pry.push_prompt @c @pry.prompt.should == @c @pry.pop_prompt @pry.prompt.should == @b @pry.pop_prompt @pry.prompt.should == @a end it 'should restore overridden prompts when returning from file-mode' do pry = Pry.new(:prompt => [ proc { 'P>' } ] * 2) pry.select_prompt.should == "P>" pry.process_command('shell-mode') pry.select_prompt.should =~ /\Apry .* \$ \z/ pry.process_command('shell-mode') pry.select_prompt.should == "P>" end it '#pop_prompt should return the popped prompt' do @pry.push_prompt @b @pry.push_prompt @c @pry.pop_prompt.should == @c @pry.pop_prompt.should == @b end it 'should not pop the last prompt' do @pry.push_prompt @b @pry.pop_prompt.should == @b @pry.pop_prompt.should == @a @pry.pop_prompt.should == @a @pry.prompt.should == @a end describe '#prompt= should replace the current prompt with the new prompt' do it 'when only one prompt on the stack' do @pry.prompt = @b @pry.prompt.should == @b @pry.pop_prompt.should == @b @pry.pop_prompt.should == @b end it 'when several prompts on the stack' do @pry.push_prompt @b @pry.prompt = @c @pry.pop_prompt.should == @c @pry.pop_prompt.should == @a end end end end describe "view_clip used for displaying an object in a truncated format" do DEFAULT_OPTIONS = { max_length: 60 } MAX_LENGTH = DEFAULT_OPTIONS[:max_length] describe "given an object with an #inspect string" do it "returns the #<> format of the object (never use inspect)" do o = Object.new def o.inspect; "a" * MAX_LENGTH; end Pry.view_clip(o, DEFAULT_OPTIONS).should =~ /# format of the special-cased immediate object if #inspect is longer than maximum" do o = "o" * (MAX_LENGTH + 1) Pry.view_clip(o, DEFAULT_OPTIONS).should =~ /# format of the object (never use inspect)" do o = Object.new def o.inspect; "a" * DEFAULT_OPTIONS; end Pry.view_clip(o, DEFAULT_OPTIONS).should =~ /# format" do o = Object.new def o.inspect; "a" * (DEFAULT_OPTIONS + 1); end Pry.view_clip(o, DEFAULT_OPTIONS).should =~ /# format" do c, m = Class.new, Module.new Pry.view_clip(c, DEFAULT_OPTIONS).should =~ /# format" do c, m = Class.new, Module.new def c.name; "a" * (MAX_LENGTH + 1); end def m.name; "a" * (MAX_LENGTH + 1); end Pry.view_clip(c, DEFAULT_OPTIONS).should =~ /# format" do c, m = Class.new, Module.new def c.name; "a" * MAX_LENGTH; end def m.name; "a" * MAX_LENGTH; end Pry.view_clip(c, DEFAULT_OPTIONS).should == c.name Pry.view_clip(m, DEFAULT_OPTIONS).should == m.name end end end end end describe 'quiet' do it 'should show whereami by default' do Pry.start(binding, :input => InputTester.new("1", "exit-all"), :output => @str_output, :hooks => Pry::DEFAULT_HOOKS) @str_output.string.should =~ /[w]hereami by default/ end it 'should hide whereami if quiet is set' do Pry.new(:input => InputTester.new("exit-all"), :output => @str_output, :quiet => true, :hooks => Pry::DEFAULT_HOOKS) @str_output.string.should == "" end end describe 'toplevel_binding' do it 'should be devoid of local variables' do pry_eval(Pry.toplevel_binding, "ls -l").should_not =~ /version/ end it 'should have self the same as TOPLEVEL_BINDING' do Pry.toplevel_binding.eval('self').should.equal? TOPLEVEL_BINDING.eval('self') end # https://github.com/rubinius/rubinius/issues/1779 unless Pry::Helpers::BaseHelpers.rbx? it 'should define private methods on Object' do TOPLEVEL_BINDING.eval 'def gooey_fooey; end' method(:gooey_fooey).owner.should == Object Pry::Method(method(:gooey_fooey)).visibility.should == :private end end end it 'should set the hooks default, and the default should be overridable' do Pry.config.input = InputTester.new("exit-all") Pry.config.hooks = Pry::Hooks.new. add_hook(:before_session, :my_name) { |out,_,_| out.puts "HELLO" }. add_hook(:after_session, :my_name) { |out,_,_| out.puts "BYE" } Object.new.pry :output => @str_output @str_output.string.should =~ /HELLO/ @str_output.string.should =~ /BYE/ Pry.config.input.rewind @str_output = StringIO.new Object.new.pry :output => @str_output, :hooks => Pry::Hooks.new. add_hook( :before_session, :my_name) { |out,_,_| out.puts "MORNING" }. add_hook(:after_session, :my_name) { |out,_,_| out.puts "EVENING" } @str_output.string.should =~ /MORNING/ @str_output.string.should =~ /EVENING/ # try below with just defining one hook Pry.config.input.rewind @str_output = StringIO.new Object.new.pry :output => @str_output, :hooks => Pry::Hooks.new. add_hook(:before_session, :my_name) { |out,_,_| out.puts "OPEN" } @str_output.string.should =~ /OPEN/ Pry.config.input.rewind @str_output = StringIO.new Object.new.pry :output => @str_output, :hooks => Pry::Hooks.new. add_hook(:after_session, :my_name) { |out,_,_| out.puts "CLOSE" } @str_output.string.should =~ /CLOSE/ Pry.reset_defaults Pry.config.color = false end end pry-0.10.3/spec/pry_output_spec.rb000066400000000000000000000062431260757071700171510ustar00rootroot00000000000000require_relative 'helper' describe Pry do describe "output failsafe" do after do Pry.config.print = Pry::DEFAULT_PRINT end it "should catch serialization exceptions" do Pry.config.print = lambda { |*a| raise "catch-22" } expect { mock_pry("1") }.to_not raise_error end it "should display serialization exceptions" do Pry.config.print = lambda { |*a| raise "catch-22" } mock_pry("1").should =~ /\(pry\) output error: #/ end it "should catch errors serializing exceptions" do Pry.config.print = lambda do |*a| raise Exception.new("catch-22").tap{ |e| class << e; def inspect; raise e; end; end } end mock_pry("1").should =~ /\(pry\) output error: failed to show result/ end end describe "DEFAULT_PRINT" do it "should output the right thing" do mock_pry("[1]").should =~ /^=> \[1\]/ end it "should include the =>" do pry = Pry.new accumulator = StringIO.new pry.config.output = accumulator pry.config.print.call(accumulator, [1], pry) accumulator.string.should == "=> \[1\]\n" end it "should not be phased by un-inspectable things" do mock_pry("class NastyClass; undef pretty_inspect; end", "NastyClass.new").should =~ /#<.*NastyClass:0x.*?>/ end it "doesn't leak colour for object literals" do mock_pry("Object.new").should =~ /=> #\n/ end end describe "output_prefix" do it "should be able to change output_prefix" do pry = Pry.new accumulator = StringIO.new pry.config.output = accumulator pry.config.output_prefix = "-> " pry.config.print.call(accumulator, [1], pry) accumulator.string.should == "-> \[1\]\n" end end describe "color" do before do Pry.config.color = true end after do Pry.config.color = false end it "should colorize strings as though they were ruby" do pry = Pry.new accumulator = StringIO.new colorized = CodeRay.scan("[1]", :ruby).term pry.config.output = accumulator pry.config.print.call(accumulator, [1], pry) accumulator.string.should == "=> #{colorized}\n" end it "should not colorize strings that already include color" do pry = Pry.new f = Object.new def f.inspect "\e[1;31mFoo\e[0m" end accumulator = StringIO.new pry.config.output = accumulator pry.config.print.call(accumulator, f, pry) # We add an extra \e[0m to prevent color leak accumulator.string.should == "=> \e[1;31mFoo\e[0m\e[0m\n" end end describe "output suppression" do before do @t = pry_tester end it "should normally output the result" do mock_pry("1 + 2").should == "=> 3\n" end it "should not output anything if the input ends with a semicolon" do mock_pry("1 + 2;").should == "" end it "should output something if the input ends with a comment" do mock_pry("1 + 2 # basic addition").should == "=> 3\n" end it "should not output something if the input is only a comment" do mock_pry("# basic addition").should == "" end end end pry-0.10.3/spec/pry_repl_spec.rb000066400000000000000000000042231260757071700165470ustar00rootroot00000000000000require_relative 'helper' describe "The whole thing" do it "should let you run commands in the middle of multiline expressions" do ReplTester.start do input 'def a' input '!' output /^Input buffer cleared/ input '5' output '=> 5' end end it "should rescue exceptions" do ReplTester.start do input 'raise "lorum"' output /^RuntimeError: lorum/ if defined?(java) input 'raise java.lang.Exception.new("foo")' output /Exception: foo/ input 'raise java.io.IOException.new("bar")' output /IOException: bar/ end end end describe "eval_string and binding_stack" do it "shouldn't break if we start a nested REPL" do ReplTester.start do input 'Pry::REPL.new(_pry_, :target => 10).start' output '' prompt /10.*> $/ input 'self' output '=> 10' input nil # Ctrl-D output '' input 'self' output '=> main' end end it "shouldn't break if we start a nested instance" do ReplTester.start do input 'Pry.start(10, _pry_.config)' output '' prompt /10.*> $/ input 'self' output '=> 10' input nil # Ctrl-D output '=> nil' # return value of Pry session input 'self' output '=> main' end end it "shouldn't break if we pop bindings in Ruby" do ReplTester.start do input 'cd 10' output '' prompt /10.*> $/ input '_pry_.binding_stack.pop' output /^=> # $/ input '_pry_.binding_stack.pop' output /^=> # set) do input 'def x' output '' prompt /\* $/ input 'hello!' output '=> "hello"' prompt /> $/ end end end end pry-0.10.3/spec/pry_spec.rb000066400000000000000000000306371260757071700155350ustar00rootroot00000000000000require_relative 'helper' describe Pry do before do @str_output = StringIO.new end describe "Exotic object support" do # regression test for exotic object support it "Should not error when return value is a BasicObject instance" do ReplTester.start do input('BasicObject.new').should =~ /^=> # proc{ was_called = true }) was_called.should == false end it 'should notice when exceptions are raised' do was_called = false mock_pry("raise RuntimeError", :exception_handler => proc{ was_called = true }) was_called.should == true end it 'should not try to catch intended exceptions' do expect { mock_pry("raise SystemExit") }.to raise_error SystemExit # SIGTERM expect { mock_pry("raise SignalException.new(15)") }.to raise_error SignalException end describe "multi-line input" do it "works" do mock_pry('x = ', '1 + 4').should =~ /5/ end it 'should suppress output if input ends in a ";" (multi-line)' do mock_pry('def self.blah', ':test', 'end;').should == '' end describe "newline stripping from an empty string" do it "with double quotes" do mock_pry('"', '"').should =~ %r|"\\n"| mock_pry('"', "\n", "\n", "\n", '"').should =~ %r|"\\n\\n\\n\\n"| end it "with single quotes" do mock_pry("'", "'").should =~ %r|"\\n"| mock_pry("'", "\n", "\n", "\n", "'").should =~ %r|"\\n\\n\\n\\n"| end it "with fancy delimiters" do mock_pry('%(', ')').should =~ %r|"\\n"| mock_pry('%|', "\n", "\n", '|').should =~ %r|"\\n\\n\\n"| mock_pry('%q[', "\n", "\n", ']').should =~ %r|"\\n\\n\\n"| end end describe "newline stripping from an empty regexp" do it "with regular regexp delimiters" do mock_pry('/', '/').should =~ %r{/\n/} end it "with fancy delimiters" do mock_pry('%r{', "\n", "\n", '}').should =~ %r{/\n\n\n/} mock_pry('%r<', "\n", '>').should =~ %r{/\n\n/} end end describe "newline from an empty heredoc" do it "works" do mock_pry('< input, :output => StringIO.new) o.instance_variable_get(:@x).should == 10 end end describe "complete_expression?" do it "should not mutate the input!" do clean = "puts <<-FOO\nhi\nFOO\n" a = clean.dup Pry::Code.complete_expression?(a) a.should == clean end end describe "history arrays" do it 'sets _ to the last result' do t = pry_tester t.eval ":foo" t.eval("_").should == :foo t.eval "42" t.eval("_").should == 42 end it 'sets out to an array with the result' do t = pry_tester t.eval ":foo" t.eval "42" res = t.eval "_out_" res.should be_a_kind_of Pry::HistoryArray res[1..2].should == [:foo, 42] end it 'sets _in_ to an array with the entered lines' do t = pry_tester t.eval ":foo" t.eval "42" res = t.eval "_in_" res.should be_a_kind_of Pry::HistoryArray res[1..2].should == [":foo\n", "42\n"] end it 'uses 100 as the size of _in_ and _out_' do pry_tester.eval("[_in_.max_size, _out_.max_size]").should == [100, 100] end it 'can change the size of the history arrays' do pry_tester(:memory_size => 1000).eval("[_out_, _in_].map(&:max_size)").should == [1000, 1000] end it 'store exceptions' do mock_pry("foo!", "Pad.in = _in_[-1]; Pad.out = _out_[-1]") Pad.in.should == "foo!\n" expect(Pad.out).to be_a_kind_of NoMethodError end end describe "last_result" do it "should be set to the most recent value" do pry_eval("2", "_ + 82").should == 84 end # This test needs mock_pry because the command retvals work by # replacing the eval_string, so _ won't be modified without Pry doing # a REPL loop. it "should be set to the result of a command with :keep_retval" do Pry::Commands.block_command '++', '', :keep_retval => true do |a| a.to_i + 1 end mock_pry('++ 86', '++ #{_}').should =~ /88/ end it "should be preserved over an empty line" do pry_eval("2 + 2", " ", "\t", " ", "_ + 92").should == 96 end it "should be preserved when evalling a command without :keep_retval" do pry_eval("2 + 2", "ls -l", "_ + 96").should == 100 end end describe "nesting" do after do Pry.reset_defaults Pry.config.color = false end it 'should nest properly' do Pry.config.input = InputTester.new("cd 1", "cd 2", "cd 3", "\"nest:\#\{(_pry_.binding_stack.size - 1)\}\"", "exit-all") Pry.config.output = @str_output o = Object.new pry_tester = o.pry @str_output.string.should =~ /nest:3/ end end describe "defining methods" do it 'should define a method on the singleton class of an object when performing "def meth;end" inside the object' do [Object.new, {}, []].each do |val| pry_eval(val, 'def hello; end') val.methods(false).map(&:to_sym).include?(:hello).should == true end end it 'should define an instance method on the module when performing "def meth;end" inside the module' do hello = Module.new pry_eval(hello, "def hello; end") hello.instance_methods(false).map(&:to_sym).include?(:hello).should == true end it 'should define an instance method on the class when performing "def meth;end" inside the class' do hello = Class.new pry_eval(hello, "def hello; end") hello.instance_methods(false).map(&:to_sym).include?(:hello).should == true end it 'should define a method on the class of an object when performing "def meth;end" inside an immediate value or Numeric' do [:test, 0, true, false, nil, (0.0 unless Pry::Helpers::BaseHelpers.jruby?)].each do |val| pry_eval(val, "def hello; end"); val.class.instance_methods(false).map(&:to_sym).include?(:hello).should == true end end end describe "Object#pry" do after do Pry.reset_defaults Pry.config.color = false end it "should start a pry session on the receiver (first form)" do Pry.config.input = InputTester.new("self", "exit-all") str_output = StringIO.new Pry.config.output = str_output 20.pry str_output.string.should =~ /20/ end it "should start a pry session on the receiver (second form)" do Pry.config.input = InputTester.new("self", "exit-all") str_output = StringIO.new Pry.config.output = str_output pry 20 str_output.string.should =~ /20/ end it "should raise if more than two arguments are passed to Object#pry" do expect { pry(20, :quiet, :input => Readline) }.to raise_error ArgumentError end end describe "Pry.binding_for" do it 'should return TOPLEVEL_BINDING if parameter self is main' do _main_ = lambda { TOPLEVEL_BINDING.eval('self') } Pry.binding_for(_main_.call).is_a?(Binding).should == true Pry.binding_for(_main_.call).should == TOPLEVEL_BINDING Pry.binding_for(_main_.call).should == Pry.binding_for(_main_.call) end end end end describe 'setting custom options' do it 'does not raise for unrecognized options' do expect { instance = Pry.new(:custom_option => 'custom value') }.to_not raise_error end it 'correctly handles the :quiet option (#1261)' do instance = Pry.new(:quiet => true) instance.quiet?.should == true end end describe "a fresh instance" do it "should use `caller` as its backtrace" do location = "#{__FILE__}:#{__LINE__ + 1}"[1..-1] # omit leading . backtrace = Pry.new.backtrace backtrace.should_not equal nil backtrace.any? { |l| l.include?(location) }.should equal true end end end pry-0.10.3/spec/pryrc_spec.rb000066400000000000000000000061631260757071700160570ustar00rootroot00000000000000require_relative 'helper' describe Pry do describe 'loading rc files' do before do Pry::HOME_RC_FILE.replace "spec/fixtures/testrc" Pry::LOCAL_RC_FILE.replace "spec/fixtures/testrc/../testrc" Pry.instance_variable_set(:@initial_session, true) Pry.config.should_load_rc = true Pry.config.should_load_local_rc = true end after do Pry::HOME_RC_FILE.replace "~/.pryrc" Pry::LOCAL_RC_FILE.replace "./.pryrc" Pry.config.should_load_rc = false Object.remove_const(:TEST_RC) if defined?(TEST_RC) end it "should never run the rc file twice" do Pry.start(self, :input => StringIO.new("exit-all\n"), :output => StringIO.new) TEST_RC.should == [0] Pry.start(self, :input => StringIO.new("exit-all\n"), :output => StringIO.new) TEST_RC.should == [0] end # Resolving symlinks doesn't work on jruby 1.9 [jruby issue #538] unless Pry::Helpers::BaseHelpers.jruby_19? it "should not load the rc file twice if it's symlinked differently" do Pry::HOME_RC_FILE.replace "spec/fixtures/testrc" Pry::LOCAL_RC_FILE.replace "spec/fixtures/testlinkrc" Pry.start(self, :input => StringIO.new("exit-all\n"), :output => StringIO.new) TEST_RC.should == [0] end end it "should not load the pryrc if it cannot expand ENV[HOME]" do old_home = ENV['HOME'] ENV['HOME'] = nil Pry.config.should_load_rc = true expect { Pry.start(self, :input => StringIO.new("exit-all\n"), :output => StringIO.new) }.to_not raise_error ENV['HOME'] = old_home end it "should not run the rc file at all if Pry.config.should_load_rc is false" do Pry.config.should_load_rc = false Pry.config.should_load_local_rc = false Pry.start(self, :input => StringIO.new("exit-all\n"), :output => StringIO.new) Object.const_defined?(:TEST_RC).should == false end describe "that raise exceptions" do before do Pry::HOME_RC_FILE = "spec/fixtures/testrcbad" Pry.config.should_load_local_rc = false putsed = nil # YUCK! horrible hack to get round the fact that output is not configured # at the point this message is printed. (class << Pry; self; end).send(:define_method, :puts) { |str| putsed = str } @doing_it = lambda{ Pry.start(self, :input => StringIO.new("Object::TEST_AFTER_RAISE=1\nexit-all\n"), :output => StringIO.new) putsed } end after do Object.remove_const(:TEST_BEFORE_RAISE) Object.remove_const(:TEST_AFTER_RAISE) (class << Pry; undef_method :puts; end) end it "should not raise exceptions" do expect(&@doing_it).to_not raise_error end it "should continue to run pry" do @doing_it[] Object.const_defined?(:TEST_BEFORE_RAISE).should == true Object.const_defined?(:TEST_AFTER_RAISE).should == true end it "should output an error" do @doing_it.call.split("\n").first.should =~ %r{Error loading .*spec/fixtures/testrcbad: messin with ya} end end end end pry-0.10.3/spec/regression/000077500000000000000000000000001260757071700155335ustar00rootroot00000000000000pry-0.10.3/spec/regression/readline_spec.rb000066400000000000000000000020521260757071700206540ustar00rootroot00000000000000# These specs ensure that Pry doesn't require readline until the first time a # REPL is started. require "helper" require "shellwords" describe "Readline" do before do @ruby = RbConfig.ruby.shellescape @pry_dir = File.expand_path(File.join(__FILE__, '../../../lib')).shellescape end it "is not loaded on requiring 'pry'" do code = <<-RUBY require "pry" p defined?(Readline) RUBY `#@ruby -I #@pry_dir -e '#{code}'`.should == "nil\n" end it "is loaded on invoking 'pry'" do code = <<-RUBY require "pry" Pry.start self, input: StringIO.new("exit-all"), output: StringIO.new puts defined?(Readline) RUBY `#@ruby -I #@pry_dir -e '#{code}'`.end_with?("constant\n").should == true end it "is not loaded on invoking 'pry' if Pry.input is set" do code = <<-RUBY require "pry" Pry.input = StringIO.new("exit-all") Pry.start self, output: StringIO.new p defined?(Readline) RUBY `#@ruby -I #@pry_dir -e '#{code}'`.end_with?("nil\n").should == true end end pry-0.10.3/spec/run_command_spec.rb000066400000000000000000000011471260757071700172170ustar00rootroot00000000000000require_relative 'helper' describe "Pry.run_command" do before do o = Object.new def o.drum "roken is dodelijk" end @context = Pry.binding_for(o) end it 'performs a simple ls' do @context.eval("hokey_pokey = 10") Pry.run_command "ls", :context => @context, :output => out = StringIO.new out.string.should =~ /hokey_pokey/ end # This is a regression test as 0.9.11 broke this behaviour it 'can perform a show-source' do Pry.run_command "show-source drum", :context => @context, :output => out = StringIO.new out.string.should =~ /roken is dodelijk/ end end pry-0.10.3/spec/spec_helpers/000077500000000000000000000000001260757071700160275ustar00rootroot00000000000000pry-0.10.3/spec/spec_helpers/mock_pry.rb000066400000000000000000000014771260757071700202100ustar00rootroot00000000000000def mock_pry(*args) args.flatten! binding = args.first.is_a?(Binding) ? args.shift : binding() options = args.last.is_a?(Hash) ? args.pop : {} input = InputTester.new(*args) output = StringIO.new redirect_pry_io(input, output) do binding.pry(options) end output.string end # Set I/O streams. Out defaults to an anonymous StringIO. def redirect_pry_io(new_in, new_out = StringIO.new) old_in = Pry.config.input old_out = Pry.config.output Pry.config.input = new_in Pry.config.output = new_out begin yield ensure Pry.config.input = old_in Pry.config.output = old_out end end class InputTester def initialize(*actions) @orig_actions = actions.dup @actions = actions end def readline(*) @actions.shift end def rewind @actions = @orig_actions.dup end end pry-0.10.3/spec/spec_helpers/repl_tester.rb000066400000000000000000000045011260757071700207040ustar00rootroot00000000000000# This is for super-high-level integration testing. require 'thread' require 'delegate' class ReplTester class Input def initialize(tester_mailbox) @tester_mailbox = tester_mailbox end def readline(prompt) @tester_mailbox.push prompt mailbox.pop end def mailbox Thread.current[:mailbox] end end class Output < SimpleDelegator def clear __setobj__(StringIO.new) end end def self.start(options = {}, &block) Thread.current[:mailbox] = Queue.new instance = nil input = Input.new(Thread.current[:mailbox]) output = Output.new(StringIO.new) redirect_pry_io input, output do instance = new(options) instance.instance_eval(&block) instance.ensure_exit end ensure if instance && instance.thread && instance.thread.alive? instance.thread.kill end end attr_accessor :thread, :mailbox, :last_prompt def initialize(options = {}) @pry = Pry.new(options) @repl = Pry::REPL.new(@pry) @mailbox = Thread.current[:mailbox] @thread = Thread.new do begin Thread.current[:mailbox] = Queue.new @repl.start ensure Thread.current[:session_ended] = true mailbox.push nil end end wait # wait until the instance reaches its first readline end # Accept a line of input, as if entered by a user. def input(input) reset_output repl_mailbox.push input wait @pry.output.string end # Assert that the current prompt matches the given string or regex. def prompt(match) match.should === last_prompt end # Assert that the most recent output (since the last time input was called) # matches the given string or regex. def output(match) match.should === @pry.output.string.chomp end # Assert that the Pry session ended naturally after the last input. def assert_exited @should_exit_naturally = true end # @private def ensure_exit if @should_exit_naturally raise "Session was not ended!" unless @thread[:session_ended].equal?(true) else input "exit-all" raise "REPL didn't die" unless @thread[:session_ended] end end private def reset_output @pry.output.clear end def repl_mailbox @thread[:mailbox] end def wait @last_prompt = mailbox.pop end end pry-0.10.3/spec/sticky_locals_spec.rb000066400000000000000000000125641260757071700175650ustar00rootroot00000000000000require_relative 'helper' describe "Sticky locals (_file_ and friends)" do it 'locals should all exist upon initialization' do expect { pry_eval '_file_', '_dir_', '_ex_', '_pry_', '_' }.to_not raise_error end it 'locals should still exist after cd-ing into a new context' do expect { pry_eval 'cd 0', '_file_', '_dir_', '_ex_', '_pry_', '_' }.to_not raise_error end it 'locals should keep value after cd-ing (_pry_)' do pry_tester.tap do |t| pry = t.eval '_pry_' t.eval 'cd 0' t.eval('_pry_').should == pry end end describe '_ex_' do it 'returns the last exception without wrapping it in a LastException' do ReplTester.start do input 'raise "halp"' input '_ex_.message == "halp"' output '=> true' input 'Kernel.instance_method(:class).bind(_ex_).call' output '=> RuntimeError' end end it 'keeps its value after cd-ing' do ReplTester.start do input 'error blah' input '$x = _ex_' input 'cd 0' input '_ex_ == $x' output '=> true' end end end it 'locals should keep value after cd-ing (_file_ and _dir_)' do Pry.config.commands.command "file-and-dir-test" do set_file_and_dir_locals("/blah/ostrich.rb") end pry_eval('file-and-dir-test', 'cd 0', '_file_'). should =~ /\/blah\/ostrich\.rb/ pry_eval('file-and-dir-test', 'cd 0', '_dir_'). should =~ /\/blah/ Pry.config.commands.delete "file-and-dir-test" end it 'locals should return last result (_)' do pry_tester.tap do |t| lam = t.eval 'lambda { |foo| }' t.eval('_').should == lam end end it 'locals should return second last result (__)' do pry_tester.tap do |t| lam = t.eval 'lambda { |foo| }' t.eval 'num = 1' t.eval('__').should == lam end end describe "User defined sticky locals" do describe "setting as Pry.config option" do it 'should define a new sticky local for the session (normal value)' do Pry.config.extra_sticky_locals[:test_local] = :john o = Object.new redirect_pry_io(InputTester.new("@value = test_local", "exit-all")) do Pry.start(o) end o.instance_variable_get(:@value).should == :john Pry.config.extra_sticky_locals = {} end it 'should define a new sticky local for the session (proc)' do Pry.config.extra_sticky_locals[:test_local] = proc { :john } o = Object.new redirect_pry_io(InputTester.new("@value = test_local", "exit-all")) do Pry.start(o) end o.instance_variable_get(:@value).should == :john Pry.config.extra_sticky_locals = {} end end describe "passing in as hash option when creating pry instance" do it 'should define a new sticky local for the session (normal value)' do o = Object.new redirect_pry_io(InputTester.new("@value = test_local", "exit-all")) do Pry.start(o, :extra_sticky_locals => { :test_local => :john } ) end o.instance_variable_get(:@value).should == :john end it 'should define multiple sticky locals' do o = Object.new redirect_pry_io(InputTester.new("@value1 = test_local1", "@value2 = test_local2", "exit-all")) do Pry.start(o, :extra_sticky_locals => { :test_local1 => :john , :test_local2 => :carl} ) end o.instance_variable_get(:@value1).should == :john o.instance_variable_get(:@value2).should == :carl end it 'should define a new sticky local for the session (as Proc)' do o = Object.new redirect_pry_io(InputTester.new("@value = test_local", "exit-all")) do Pry.start(o, :extra_sticky_locals => { :test_local => proc { :john }} ) end o.instance_variable_get(:@value).should == :john end end describe "hash option value should override config value" do it 'should define a new sticky local for the session (normal value)' do Pry.config.extra_sticky_locals[:test_local] = :john o = Object.new redirect_pry_io(InputTester.new("@value = test_local", "exit-all")) do Pry.start(o, :extra_sticky_locals => { :test_local => :carl }) end o.instance_variable_get(:@value).should == :carl Pry.config.extra_sticky_locals = {} end end it 'should create a new sticky local' do t = pry_tester t.eval "_pry_.add_sticky_local(:test_local){ :test_value }" t.eval("test_local").should == :test_value end it 'should still exist after cd-ing into new binding' do t = pry_tester t.eval "_pry_.add_sticky_local(:test_local){ :test_value }" t.eval "cd Object.new" t.eval("test_local").should == :test_value end it 'should provide different values for successive block invocations' do pry = Pry.new pry.push_binding binding pry.add_sticky_local(:test_local) { rand } value1 = pry.evaluate_ruby 'test_local' value2 = pry.evaluate_ruby 'test_local' value1.should_not == value2 end end end pry-0.10.3/spec/syntax_checking_spec.rb000066400000000000000000000046101260757071700200740ustar00rootroot00000000000000require_relative 'helper' describe Pry do before do @str_output = StringIO.new end [ ["p = '", "'"], ["def", "a", "(); end"], ["p = < true/m end it "should allow whitespace delimeted strings" do mock_pry('"%s" %% foo ').should =~ /"foo"/ end it "should allow newline delimeted strings" do mock_pry('"%s" %%','foo').should =~ /"foo"/ end it "should allow whitespace delimeted strings ending on the first char of a line" do mock_pry('"%s" %% ', ' #done!').should =~ /"\\n"/ end end pry-0.10.3/spec/wrapped_module_spec.rb000066400000000000000000000211701260757071700177220ustar00rootroot00000000000000require_relative 'helper' describe Pry::WrappedModule do describe "#initialize" do it "should raise an exception when a non-module is passed" do expect { Pry::WrappedModule.new(nil) }.to raise_error ArgumentError end end describe "candidates" do class Host %w(spec/fixtures/candidate_helper1.rb spec/fixtures/candidate_helper2.rb).each do |file| binding.eval File.read(file), file, 1 end # rank 2 class CandidateTest def test6 end end class PitifullyBlank DEFAULT_TEST = CandidateTest end FOREVER_ALONE_LINE = __LINE__ + 1 class ForeverAlone class DoublyNested # nested docs class TriplyNested def nested_method end end end end end describe "number_of_candidates" do it 'should return the correct number of candidates' do Pry::WrappedModule(Host::CandidateTest).number_of_candidates.should == 3 end it 'should return 0 candidates for a class with no nested modules or methods' do Pry::WrappedModule(Host::PitifullyBlank).number_of_candidates.should == 0 end it 'should return 1 candidate for a class with a nested module with methods' do Pry::WrappedModule(Host::ForeverAlone).number_of_candidates.should == 1 end end describe "ordering of candidates" do it 'should return class with largest number of methods as primary candidate' do Pry::WrappedModule(Host::CandidateTest).candidate(0).file.should =~ /helper1/ end it 'should return class with second largest number of methods as second ranked candidate' do Pry::WrappedModule(Host::CandidateTest).candidate(1).file.should =~ /helper2/ end it 'should return class with third largest number of methods as third ranked candidate' do Pry::WrappedModule(Host::CandidateTest).candidate(2).file.should =~ /#{__FILE__}/ end it 'should raise when trying to access non-existent candidate' do expect { Pry::WrappedModule(Host::CandidateTest).candidate(3) }.to raise_error Pry::CommandError end end describe "source_location" do it 'should return primary candidates source_location by default' do wm = Pry::WrappedModule(Host::CandidateTest) wm.source_location.should == wm.candidate(0).source_location end it 'should return the location of the outer module if an inner module has methods' do wm = Pry::WrappedModule(Host::ForeverAlone) File.expand_path(wm.source_location.first).should == File.expand_path(__FILE__) wm.source_location.last.should == Host::FOREVER_ALONE_LINE end it 'should return nil if no source_location can be found' do Pry::WrappedModule(Host::PitifullyBlank).source_location.should == nil end end describe "source" do it 'should return primary candidates source by default' do wm = Pry::WrappedModule(Host::CandidateTest) wm.source.should == wm.candidate(0).source end it 'should return source for highest ranked candidate' do Pry::WrappedModule(Host::CandidateTest).candidate(0).source.should =~ /test1/ end it 'should return source for second ranked candidate' do Pry::WrappedModule(Host::CandidateTest).candidate(1).source.should =~ /test4/ end it 'should return source for third ranked candidate' do Pry::WrappedModule(Host::CandidateTest).candidate(2).source.should =~ /test6/ end it 'should return source for deeply nested class' do Pry::WrappedModule(Host::ForeverAlone::DoublyNested::TriplyNested).source.should =~ /nested_method/ Pry::WrappedModule(Host::ForeverAlone::DoublyNested::TriplyNested).source.lines.count.should == 4 end end describe "doc" do it 'should return primary candidates doc by default' do wm = Pry::WrappedModule(Host::CandidateTest) wm.doc.should == wm.candidate(0).doc end it 'should return doc for highest ranked candidate' do Pry::WrappedModule(Host::CandidateTest).candidate(0).doc.should =~ /rank 0/ end it 'should return doc for second ranked candidate' do Pry::WrappedModule(Host::CandidateTest).candidate(1).doc.should =~ /rank 1/ end it 'should return doc for third ranked candidate' do Pry::WrappedModule(Host::CandidateTest).candidate(2).doc.should =~ /rank 2/ end it 'should return docs for deeply nested class' do Pry::WrappedModule(Host::ForeverAlone::DoublyNested::TriplyNested).doc.should =~ /nested docs/ end end end describe ".method_prefix" do before do Foo = Class.new @foo = Foo.new end after do Object.remove_const(:Foo) end it "should return Foo# for normal classes" do Pry::WrappedModule.new(Foo).method_prefix.should == "Foo#" end it "should return Bar# for modules" do Pry::WrappedModule.new(Kernel).method_prefix.should == "Kernel#" end it "should return Foo. for singleton classes of classes" do Pry::WrappedModule.new(class << Foo; self; end).method_prefix.should == "Foo." end example "of singleton classes of objects" do Pry::WrappedModule.new(class << @foo; self; end).method_prefix.should == "self." end example "of anonymous classes should not be empty" do Pry::WrappedModule.new(Class.new).method_prefix.should =~ /##/ end example "of singleton classes of anonymous classes should not be empty" do Pry::WrappedModule.new(class << Class.new; self; end).method_prefix.should =~ /#./ end end describe ".singleton_class?" do it "should be true for singleton classes" do Pry::WrappedModule.new(class << ""; self; end).singleton_class?.should == true end it "should be false for normal classes" do Pry::WrappedModule.new(Class.new).singleton_class?.should == false end it "should be false for modules" do Pry::WrappedModule.new(Module.new).singleton_class?.should == false end end describe ".singleton_instance" do it "should raise an exception when called on a non-singleton-class" do expect { Pry::WrappedModule.new(Class).singleton_instance }.to raise_error ArgumentError end it "should return the attached object" do Pry::WrappedModule.new(class << "hi"; self; end).singleton_instance.should == "hi" Pry::WrappedModule.new(class << Object; self; end).singleton_instance.should.equal?(Object) end end describe ".super" do describe "receiver is a class" do before do @a = Class.new @m = Module.new @b = Class.new(@a) @b.send(:include, @m) @c = Class.new(@b) end it 'should return superclass for a wrapped class' do Pry::WrappedModule(@c).super.wrapped.should == @b end it 'should return nth superclass for a wrapped class' do d = Class.new(@c) Pry::WrappedModule(d).super(2).wrapped.should == @b end it 'should ignore modules when retrieving nth superclass' do Pry::WrappedModule(@c).super(2).wrapped.should == @a end it 'should return nil when no nth superclass exists' do Pry::WrappedModule(@c).super(10).should == nil end it 'should return self when .super(0) is used' do c = Pry::WrappedModule(@c) c.super(0).should == c end end describe "receiver is a module" do before do @m1 = Module.new @m2 = Module.new.tap { |v| v.send(:include, @m1) } @m3 = Module.new.tap { |v| v.send(:include, @m2) } end it 'should not ignore modules when retrieving supers' do Pry::WrappedModule(@m3).super.wrapped.should == @m2 end it 'should retrieve nth super' do Pry::WrappedModule(@m3).super(2).wrapped.should == @m1 end it 'should return self when .super(0) is used' do m = Pry::WrappedModule(@m1) m.super(0).should == m end end end describe ".from_str" do before do class Namespace Value = Class.new end end it 'should lookup a constant' do m = Pry::WrappedModule.from_str("Namespace::Value", binding) m.wrapped.should == Namespace::Value end it 'should lookup a local' do local = Namespace::Value m = Pry::WrappedModule.from_str("local", binding) m.wrapped.should == Namespace::Value end it 'should lookup an ivar' do @ivar = Namespace::Value m = Pry::WrappedModule.from_str("@ivar", binding) m.wrapped.should == Namespace::Value end end end