Pry使用教程

一、pry是什么

Pry是一个非常强大的可以替代Ruby自带irb的控制台。
它有非常多的先进的功能。

  • 源代码查看(安装 pry-doc gem 还可以查看C语言源代码)
  • 文档浏览
  • 在线帮助系统
  • 可以在编辑器中编辑方法(edit Class#method)
  • 语法高亮
  • 各种命令集成(启动编辑器,运行git,执行rake)
  • linux命令集成(可以使用 cd, ls 等)
  • 能够查看和回放历史

二、根据实例介绍Pry

Pry关联的几个gem

pry (0.9.12.6)
pry-debugger (0.2.2)
pry-doc (0.6.0)
pry-rails (0.3.1)

一个小例子

    require 'active_record'
require 'arel'

class TestCount
  PUBLIC_STATUS = 4

  def initialize
    ActiveRecord::Base.establish_connection(
      :adapter => 'mysql2',
      :host    => 'localhost',
      :username => 'root',
      :database => 'tao800_test8'
    )

    Arel::Table.engine = ActiveRecord::Base

    @x = 123
  end

  def self.my_to_sql
    binding.pry
    id = ::Arel::Nodes::SqlLiteral.new("id")
    id.count.to_sql
  end

  def say_hello_to_pry
    binding.pry
    p "Fine, pry"
  end
end

aa = TestCount.new
aa.say_hello_to_pry

TestCount.my_to_sql

-ls 命令

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. 

  -m, --methods               Show public methods defined on the Object (default)
  -M, --instance-methods      Show methods defined in a Module or Class
  -p, --ppp                   Show public, protected (in yellow) and private (in green) methods
  -G, --grep                  Filter output by regular expression

-cd 命令

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 -

-whereami 命令

Describe the current location. If you use `binding.pry` inside a method then
whereami will print out the source for that method.

-nesting 命令

Show nesting information.

-step 命令

Step execution forward. By default, moves a single step.

Examples:

    step                           Move a single step forward.
    step 5                         Execute the next 5 steps.

-jump-to 命令

Jump to a binding further up the stack, popping all bindings below. 

实战

arel (master) $ pry my_test/test_count.rb

From: (pry) @ line 9 TestCount#initialize:

     8: def initialize
 =>  9:   binding.pry
    10:   ActiveRecord::Base.establish_connection(
    11:     :adapter => 'mysql2',
    12:     :host    => 'localhost',
    13:     :username => 'root',
    14:     :database => 'tao800_test8'
    15:   )
    16:
    17:   Arel::Table.engine = ActiveRecord::Base
    18:
    19:   binding.pry
    20:   @x = 123
    21: end

[1] pry(#)> step

From: (pry) @ line 10 TestCount#initialize:

     8: def initialize
     9:   binding.pry
 => 10:   ActiveRecord::Base.establish_connection(
    11:     :adapter => 'mysql2',
    12:     :host    => 'localhost',
    13:     :username => 'root',
    14:     :database => 'tao800_test8'
    15:   )
    16:
    17:   Arel::Table.engine = ActiveRecord::Base
    18:
    19:   binding.pry
    20:   @x = 123
    21: end

[1] pry(#)> step

From: /Users/wanghao/.rvm/gems/ruby-2.1.1@others/gems/activerecord-4.2.1/lib/active_record/base.rb @ line 1 :

 => 1: require 'yaml'
    2: require 'set'
    3: require 'active_support/benchmarkable'
    4: require 'active_support/dependencies'
    5: require 'active_support/descendants_tracker'
    6: require 'active_support/time'

[1] pry(main)> step

From: /Users/wanghao/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb @ line 39 Kernel#require:

    34:   #
    35:   # The normal require functionality of returning false if
    36:   # that file has already been loaded is preserved.
    37:
    38:   def require path
 => 39:     RUBYGEMS_ACTIVATION_MONITOR.enter
    40:
    41:     path = path.to_path if path.respond_to? :to_path
    42:
    43:     spec = Gem.find_unresolved_default_spec(path)
    44:     if spec

[1] pry(main)> step

From: /Users/wanghao/.rvm/rubies/ruby-2.1.1/lib/ruby/2.1.0/monitor.rb @ line 184 MonitorMixin#mon_enter:

    183: def mon_enter
 => 184:   if @mon_owner != Thread.current
    185:     @mon_mutex.lock
    186:     @mon_owner = Thread.current
    187:   end
    188:   @mon_count += 1
    189: end

[1] pry(#)> nesting
Nesting status:
--
0. # (Pry top level)
[2] pry(#)> @mon_owner
=> nil
[3] pry(#)> c

From: (pry) @ line 19 TestCount#initialize:

     8: def initialize
     9:   binding.pry
    10:   ActiveRecord::Base.establish_connection(
    11:     :adapter => 'mysql2',
    12:     :host    => 'localhost',
    13:     :username => 'root',
    14:     :database => 'tao800_test8'
    15:   )
    16:
    17:   Arel::Table.engine = ActiveRecord::Base
    18:
 => 19:   binding.pry
    20:   @x = 123
    21: end

[1] pry(#)> Arel::Table.engine
=> ActiveRecord::Base
[2] pry(#)> ls
TestCount#methods: say_hello_to_pry
locals: _  __  _dir_  _ex_  _file_  _in_  _out_  _pry_
[3] pry(#)> ls -i

[4] pry(#)> ls -m
TestCount#methods: say_hello_to_pry
[5] pry(#)> cd Arel::Table
[6] pry(Arel::Table):1> show-source

From: /Users/wanghao/Project/arel/lib/arel/table.rb @ line 2:
Class name: Arel::Table
Number of lines: 123

class Table
  include Arel::Crud
  include Arel::FactoryMethods

  @engine = nil
  class << self; attr_accessor :engine; end

  attr_accessor :name, :aliases, :table_alias

  # TableAlias and Table both have a #table_name which is the name of the underlying table
  alias :table_name :name

  def initialize(name, as: nil, type_caster: nil)
    @name    = name.to_s
    @columns = nil
    @aliases = []
    @type_caster = type_caster

    # Sometime AR sends an :as parameter to table, to let the table know
    # that it is an Alias.  We may want to override new, and return a
    # TableAlias node?
    if as.to_s == @name
      as = nil
    end
    @table_alias = as
  end

  def alias name = "#{self.name}_2"
    Nodes::TableAlias.new(self, name).tap do |node|
      @aliases << node
    end
  end

  def from
    SelectManager.new(self)
  end

  def join relation, klass = Nodes::InnerJoin
    return from unless relation

    case relation
    when String, Nodes::SqlLiteral
      raise if relation.empty?
      klass = Nodes::StringJoin
    end

    from.join(relation, klass)
  end

  def outer_join relation
    join(relation, Nodes::OuterJoin)
  end

  def group *columns
    from.group(*columns)
  end

  def order *expr
    from.order(*expr)
  end

  def where condition
    from.where condition
  end

  def project *things
    from.project(*things)
  end

  def take amount
    from.take amount
  end

  def skip amount
    from.skip amount
  end

  def having expr
    from.having expr
  end

  def [] name
    ::Arel::Attribute.new self, name
  end

  def hash
    # Perf note: aliases and table alias is excluded from the hash
    #  aliases can have a loop back to this table breaking hashes in parent
    #  relations, for the vast majority of cases @name is unique to a query
    @name.hash
  end

  def eql? other
    self.class == other.class &&
      self.name == other.name &&
      self.aliases == other.aliases &&
      self.table_alias == other.table_alias
  end
  alias :== :eql?

  def type_cast_for_database(attribute_name, value)
    type_caster.type_cast_for_database(attribute_name, value)
  end

  def able_to_type_cast?
    !type_caster.nil?
  end

  protected

  attr_reader :type_caster

  private

  def attributes_for columns
    return nil unless columns

    columns.map do |column|
      Attributes.for(column).new self, column.name.to_sym
    end
  end

end
[7] pry(Arel::Table):1> show-source -l

From: /Users/wanghao/Project/arel/lib/arel/table.rb @ line 2:
Class name: Arel::Table
Number of lines: 123

  2: class Table
  3:   include Arel::Crud
  4:   include Arel::FactoryMethods
  5:
  6:   @engine = nil
  7:   class << self; attr_accessor :engine; end
  8:
  9:   attr_accessor :name, :aliases, :table_alias
 10:
 11:   # TableAlias and Table both have a #table_name which is the name of the underlying table
 12:   alias :table_name :name
 13:
 14:   def initialize(name, as: nil, type_caster: nil)
 15:     @name    = name.to_s
 16:     @columns = nil
 17:     @aliases = []
 18:     @type_caster = type_caster
 19:
 20:     # Sometime AR sends an :as parameter to table, to let the table know
 21:     # that it is an Alias.  We may want to override new, and return a
 22:     # TableAlias node?
 23:     if as.to_s == @name
 24:       as = nil
 25:     end
 26:     @table_alias = as
 27:   end
 28:
 29:   def alias name = "#{self.name}_2"
 30:     Nodes::TableAlias.new(self, name).tap do |node|
 31:       @aliases << node
 32:     end
 33:   end
 34:
 35:   def from
 36:     SelectManager.new(self)
 37:   end
 38:
 39:   def join relation, klass = Nodes::InnerJoin
 40:     return from unless relation
 41:
 42:     case relation
 43:     when String, Nodes::SqlLiteral
 44:       raise if relation.empty?
 45:       klass = Nodes::StringJoin
 46:     end
 47:
 48:     from.join(relation, klass)
 49:   end
 50:
 51:   def outer_join relation
 52:     join(relation, Nodes::OuterJoin)
 53:   end
 54:
 55:   def group *columns
 56:     from.group(*columns)
 57:   end
 58:
 59:   def order *expr
 60:     from.order(*expr)
 61:   end
 62:
 63:   def where condition
 64:     from.where condition
 65:   end
 66:
 67:   def project *things
 68:     from.project(*things)
 69:   end
 70:
 71:   def take amount
 72:     from.take amount
 73:   end
 74:
 75:   def skip amount
 76:     from.skip amount
 77:   end
 78:
 79:   def having expr
 80:     from.having expr
 81:   end
 82:
 83:   def [] name
 84:     ::Arel::Attribute.new self, name
 85:   end
 86:
[8] pry(Arel::Table):1> whereami
Inside Arel::Table.
[9] pry(Arel::Table):1> nesting
Nesting status:
--
0. # (Pry top level)
1. Arel::Table
[10] pry(Arel::Table):1> jump-to 0
[11] pry(#)> whereami

From: (pry) @ line 19 TestCount#initialize:

     8: def initialize
     9:   binding.pry
    10:   ActiveRecord::Base.establish_connection(
    11:     :adapter => 'mysql2',
    12:     :host    => 'localhost',
    13:     :username => 'root',
    14:     :database => 'tao800_test8'
    15:   )
    16:
    17:   Arel::Table.engine = ActiveRecord::Base
    18:
 => 19:   binding.pry
    20:   @x = 123
    21: end

[12] pry(#)> next

From: (pry) @ line 20 TestCount#initialize:

     8: def initialize
     9:   binding.pry
    10:   ActiveRecord::Base.establish_connection(
    11:     :adapter => 'mysql2',
    12:     :host    => 'localhost',
    13:     :username => 'root',
    14:     :database => 'tao800_test8'
    15:   )
    16:
    17:   Arel::Table.engine = ActiveRecord::Base
    18:
    19:   binding.pry
 => 20:   @x = 123
    21: end

[12] pry(#)> next

From: /Users/wanghao/.rvm/gems/ruby-2.1.1@others/gems/pry-0.10.1/lib/pry/pry_instance.rb @ line 356 Pry#evaluate_ruby:

    351: def evaluate_ruby(code)
    352:   inject_sticky_locals!
    353:   exec_hook :before_eval, code, self
    354:
    355:   result = current_binding.eval(code, Pry.eval_path, Pry.current_line)
 => 356:   set_last_result(result, code)
    357: ensure
    358:   update_input_history(code)
    359:   exec_hook :after_eval, result, self
    360: end

[12] pry(#)> continue

From: (pry) @ line 29 TestCount#say_hello_to_pry:

    28: def say_hello_to_pry
 => 29:   binding.pry
    30:   puts "Fine, pry"
    31:   id = ::Arel::Nodes::SqlLiteral.new("id")
    32:   binding.pry
    33:   id.count.to_sql
    34: end

[1] pry(#)> step

From: (pry) @ line 30 TestCount#say_hello_to_pry:

    28: def say_hello_to_pry
    29:   binding.pry
 => 30:   puts "Fine, pry"
    31:   id = ::Arel::Nodes::SqlLiteral.new("id")
    32:   binding.pry
    33:   id.count.to_sql
    34: end

[1] pry(#)> step
Fine, pry

From: (pry) @ line 31 TestCount#say_hello_to_pry:

    28: def say_hello_to_pry
    29:   binding.pry
    30:   puts "Fine, pry"
 => 31:   id = ::Arel::Nodes::SqlLiteral.new("id")
    32:   binding.pry
    33:   id.count.to_sql
    34: end

[1] pry(#)> id
=> nil
[2] pry(#)> cd ::Arel::Nodes::SqlLiteral
[3] pry(Arel::Nodes::SqlLiteral):1> show-source

From: /Users/wanghao/Project/arel/lib/arel/nodes/sql_literal.rb @ line 3:
Class name: Arel::Nodes::SqlLiteral
Number of lines: 10

class SqlLiteral < String
  include Arel::Expressions
  include Arel::Predications
  include Arel::AliasPredication
  include Arel::OrderPredications

  def encode_with(coder)
    coder.scalar = self.to_s
  end
end
[4] pry(Arel::Nodes::SqlLiteral):1> nesting
Nesting status:
--
0. # (Pry top level)
1. Arel::Nodes::SqlLiteral
[5] pry(Arel::Nodes::SqlLiteral):1> jump-to 0
[6] pry(#)> step

From: (pry) @ line 32 TestCount#say_hello_to_pry:

    28: def say_hello_to_pry
    29:   binding.pry
    30:   puts "Fine, pry"
    31:   id = ::Arel::Nodes::SqlLiteral.new("id")
 => 32:   binding.pry
    33:   id.count.to_sql
    34: end

[6] pry(#)> id
=> "id"
[7] pry(#)> step

From: /Users/wanghao/.rvm/gems/ruby-2.1.1@others/gems/pry-0.10.1/lib/pry/core_extensions.rb @ line 42 Object#pry:

    41: def pry(object=nil, hash={})
 => 42:   if object.nil? || Hash === object
    43:     Pry.start(self, object || {})
    44:   else
    45:     Pry.start(object, hash)
    46:   end
    47: end

[7] pry(#)> cd ..
[8] pry(#)> nesting
Nesting status:
--
0. # (Pry top level)
[9] pry(#)> jump-to -1
Invalid nest level. Must be between 0 and -1. Got -1.
[10] pry(#)> continue

From: (pry) @ line 32 TestCount#say_hello_to_pry:

    28: def say_hello_to_pry
    29:   binding.pry
    30:   puts "Fine, pry"
    31:   id = ::Arel::Nodes::SqlLiteral.new("id")
 => 32:   binding.pry
    33:   id.count.to_sql
    34: end

[1] pry(#)> id
=> "id"
[2] pry(#)> id.class
=> Arel::Nodes::SqlLiteral
[3] pry(#)> id.count

From: /Users/wanghao/Project/arel/lib/arel/expressions.rb @ line 4 Arel::Expressions#count:

    3: def count distinct = false
 => 4:   binding.pry
    5:   Nodes::Count.new [self], distinct
    6: end

[1] pry("id")> whereami
whereami
[1] pry("id")> whereami
whereami
[1] pry("id")> whereami -l

From: /Users/wanghao/Project/arel/lib/arel/expressions.rb @ line 4 Arel::Expressions#count:

 => 4:       binding.pry

[2] pry("id")> whereami -l 20

From: /Users/wanghao/Project/arel/lib/arel/expressions.rb @ line 4 Arel::Expressions#count:

 => 4:       binding.pry

[3] pry("id")> whereami 20

From: /Users/wanghao/Project/arel/lib/arel/expressions.rb @ line 4 Arel::Expressions#count:

     1: module Arel
     2:   module Expressions
     3:     def count distinct = false
 =>  4:       binding.pry
     5:       Nodes::Count.new [self], distinct
     6:     end
     7:
     8:     def sum
     9:       Nodes::Sum.new [self]
    10:     end
    11:
    12:     def maximum
    13:       Nodes::Max.new [self]
    14:     end
    15:
    16:     def minimum
    17:       Nodes::Min.new [self]
    18:     end
    19:
    20:     def average
    21:       Nodes::Avg.new [self]
    22:     end
    23:
    24:     def extract field

[4] pry("id")> self
=> "id"
[5] pry("id")> distinct
=> false
[6] pry("id")> cd Nodes::Count
[7] pry(Arel::Nodes::Count):1> whereami
Inside Arel::Nodes::Count.
[8] pry(Arel::Nodes::Count):1> show-source

From: /Users/wanghao/Project/arel/lib/arel/nodes/count.rb @ line 3:
Class name: Arel::Nodes::Count
Number of lines: 6

class Count < Arel::Nodes::Function
  def initialize expr, distinct = false, aliaz = nil
    super(expr, aliaz)
    @distinct = distinct
  end
end
[9] pry(Arel::Nodes::Count):1> cd Arel::Nodes::Function
[10] pry(Arel::Nodes::Function):2> show-source

From: /Users/wanghao/Project/arel/lib/arel/nodes/function.rb @ line 3:
Class name: Arel::Nodes::Function
Number of lines: 28

class Function < Arel::Nodes::Node
  include Arel::Predications
  include Arel::WindowPredications
  attr_accessor :expressions, :alias, :distinct

  def initialize expr, aliaz = nil
    super()
    @expressions = expr
    @alias       = aliaz && SqlLiteral.new(aliaz)
    @distinct    = false
  end

  def as aliaz
    self.alias = SqlLiteral.new(aliaz)
    self
  end

  def hash
    [@expressions, @alias, @distinct].hash
  end

  def eql? other
    self.class == other.class &&
      self.expressions == other.expressions &&
      self.alias == other.alias &&
      self.distinct == other.distinct
  end
end
[11] pry(Arel::Nodes::Function):2> cd Arel::Nodes::Node
[12] pry(Arel::Nodes::Node):3> show-source

From: /Users/wanghao/Project/arel/lib/arel/nodes/node.rb @ line 7:
Class name: Arel::Nodes::Node
Number of lines: 52

class Node
  include Arel::FactoryMethods
  include Enumerable

  if $DEBUG
    def _caller
      @caller
    end

    def initialize
      @caller = caller.dup
    end
  end

From: /Users/wanghao/Project/arel/lib/arel/nodes/node.rb @ line 7:
Class name: Arel::Nodes::Node
Number of lines: 52

class Node
  include Arel::FactoryMethods
  include Enumerable

  if $DEBUG
    def _caller
      @caller
    end

    def initialize
      @caller = caller.dup
    end
  end

  ###
  # Factory method to create a Nodes::Not node that has the recipient of
  # the caller as a child.
  def not
    Nodes::Not.new self
  end

From: /Users/wanghao/Project/arel/lib/arel/nodes/node.rb @ line 7:
Class name: Arel::Nodes::Node
Number of lines: 52

class Node
  include Arel::FactoryMethods
  include Enumerable

  if $DEBUG
    def _caller
      @caller
    end

    def initialize
      @caller = caller.dup
    end
  end

  ###
  # Factory method to create a Nodes::Not node that has the recipient of
  # the caller as a child.
  def not
    Nodes::Not.new self
  end

  ###
  # Factory method to create a Nodes::Grouping node that has an Nodes::Or
  # node as a child.
  def or right
    Nodes::Grouping.new Nodes::Or.new(self, right)
  end
[13] pry(Arel::Nodes::Node):3> nesting
Nesting status:
--
0. "id" (Pry top level)
1. Arel::Nodes::Count
2. Arel::Nodes::Function
3. Arel::Nodes::Node
[14] pry(Arel::Nodes::Node):3> jump-to 2
[15] pry(Arel::Nodes::Function):2> show-source

From: /Users/wanghao/Project/arel/lib/arel/nodes/function.rb @ line 3:
Class name: Arel::Nodes::Function
Number of lines: 28

class Function < Arel::Nodes::Node
  include Arel::Predications
  include Arel::WindowPredications
  attr_accessor :expressions, :alias, :distinct

  def initialize expr, aliaz = nil
    super()
    @expressions = expr
    @alias       = aliaz && SqlLiteral.new(aliaz)
    @distinct    = false
  end

  def as aliaz
    self.alias = SqlLiteral.new(aliaz)
    self
  end

  def hash
    [@expressions, @alias, @distinct].hash
  end

  def eql? other
    self.class == other.class &&
      self.expressions == other.expressions &&
      self.alias == other.alias &&
      self.distinct == other.distinct
  end
end
[16] pry(Arel::Nodes::Function):2> nesting
Nesting status:
--
0. "id" (Pry top level)
1. Arel::Nodes::Count
2. Arel::Nodes::Function
[17] pry(Arel::Nodes::Function):2> jump to 1
NoMethodError: undefined method `to' for Arel::Nodes::Function:Class
from (pry):46:in `__binding__'
[18] pry(Arel::Nodes::Function):2> jump-to 1
[19] pry(Arel::Nodes::Count):1> whereami
Inside Arel::Nodes::Count.
[20] pry(Arel::Nodes::Count):1> show-source

From: /Users/wanghao/Project/arel/lib/arel/nodes/count.rb @ line 3:
Class name: Arel::Nodes::Count
Number of lines: 6

class Count < Arel::Nodes::Function
  def initialize expr, distinct = false, aliaz = nil
    super(expr, aliaz)
    @distinct = distinct
  end
end
[21] pry(Arel::Nodes::Count):1> continue
Error: Cannot find local context. Did you use `binding.pry`?
[22] pry(Arel::Nodes::Count):1> jump-to 0
[23] pry("id")> whereami

From: /Users/wanghao/Project/arel/lib/arel/expressions.rb @ line 4 Arel::Expressions#count:

    3: def count distinct = false
 => 4:   binding.pry
    5:   Nodes::Count.new [self], distinct
    6: end

[24] pry("id")> Nodes::Count.new("name")
=> #
[25] pry("id")> Nodes::Count.new("name").to_sql
NoMethodError: undefined method `each_with_index' for "name":String
from /Users/wanghao/Project/arel/lib/arel/visitors/to_sql.rb:790:in `inject_join'
[26] pry("id")> Nodes::Count.new("name").class
=> Arel::Nodes::Count
[27] pry("id")> continue
=> #
[4] pry(#)> continue

From: /Users/wanghao/Project/arel/lib/arel/expressions.rb @ line 4 Arel::Expressions#count:

    3: def count distinct = false
 => 4:   binding.pry
    5:   Nodes::Count.new [self], distinct
    6: end

[1] pry("id")> continue
heihei
self.my_to_sql
You have new mail in /var/mail/wanghao
参考

https://github.com/pry/pry

你可能感兴趣的:(Pry使用教程)