模块 PP::PPMethods

定义漂亮打印的辅助方法的模块。

公共实例方法

check_inspect_key(id) 点击以切换源代码

检查 object_id id 是否在当前要进行漂亮打印的对象缓冲区中。用于在要漂亮打印的对象链中打破循环。

# File pp.rb, line 169
def check_inspect_key(id)
  Thread.current[:__recursive_key__] &&
  Thread.current[:__recursive_key__][:inspect] &&
  Thread.current[:__recursive_key__][:inspect].include?(id)
end
comma_breakable() 点击以切换源代码

一个方便的方法,与以下内容相同

text ','
breakable
# File pp.rb, line 232
def comma_breakable
  text ','
  breakable
end
guard_inspect_key() { || ... } 点击以切换源代码

产生一个块,并保留先前正在打印的对象集合。

# File pp.rb, line 147
def guard_inspect_key
  if Thread.current[:__recursive_key__] == nil
    Thread.current[:__recursive_key__] = {}.compare_by_identity
  end

  if Thread.current[:__recursive_key__][:inspect] == nil
    Thread.current[:__recursive_key__][:inspect] = {}.compare_by_identity
  end

  save = Thread.current[:__recursive_key__][:inspect]

  begin
    Thread.current[:__recursive_key__][:inspect] = {}.compare_by_identity
    yield
  ensure
    Thread.current[:__recursive_key__][:inspect] = save
  end
end
object_address_group(obj, &block) 点击以切换源代码

一个方便的方法,类似于 object_group,但也重新格式化了 Object 的 object_id。

# File pp.rb, line 222
def object_address_group(obj, &block)
  str = Kernel.instance_method(:to_s).bind_call(obj)
  str.chomp!('>')
  group(1, str, '>', &block)
end
object_group(obj) { || ... } 点击以切换源代码

一个方便的方法,与以下内容相同

group(1, '#<' + obj.class.name, '>') { ... }
# File pp.rb, line 216
def object_group(obj, &block) # :yield:
  group(1, '#<' + obj.class.name, '>', &block)
end
pop_inspect_key(id) 点击以切换源代码

从正在进行漂亮打印的对象集合中删除一个对象。

# File pp.rb, line 182
def pop_inspect_key(id)
  Thread.current[:__recursive_key__][:inspect].delete id
end
pp(obj) 点击以切换源代码

使用 Object#pretty_print 或 Object#pretty_print_cycle 将 obj 添加到漂亮打印缓冲区。

obj 已经打印过时,即对象引用链存在循环时,会使用 Object#pretty_print_cycle。

# File pp.rb, line 191
def pp(obj)
  # If obj is a Delegator then use the object being delegated to for cycle
  # detection
  obj = obj.__getobj__ if defined?(::Delegator) and ::Delegator === obj

  if check_inspect_key(obj)
    group {obj.pretty_print_cycle self}
    return
  end

  begin
    push_inspect_key(obj)
    group do
      obj.pretty_print self
    rescue NoMethodError
      text Kernel.instance_method(:inspect).bind_call(obj)
    end
  ensure
    pop_inspect_key(obj) unless PP.sharing_detection
  end
end
pp_hash(obj) 点击以切换源代码

用于哈希的漂亮打印

# File pp.rb, line 291
def pp_hash(obj)
  group(1, '{', '}') {
    seplist(obj, nil, :each_pair) {|k, v|
      group {
        pp_hash_pair k, v
      }
    }
  }
end
pp_hash_pair(k, v) 点击以切换源代码

用于哈希对的漂亮打印

# File pp.rb, line 303
def pp_hash_pair(k, v)
  if Symbol === k
    sym_s = k.inspect
    if sym_s[1].match?(/["$@!]/) || sym_s[-1].match?(/[%&*+\-\/<=>@\]^`|~]/)
      text "#{k.to_s.inspect}:"
    else
      text "#{k}:"
    end
  else
    pp k
    text ' '
    text '=>'
  end
  group(1) {
    breakable
    pp v
  }
end
pp_object(obj) 点击以切换源代码

为任何给定的 Object 提供标准的漂亮打印安全措施

# File pp.rb, line 275
def pp_object(obj)
  object_address_group(obj) {
    seplist(obj.pretty_print_instance_variables, lambda { text ',' }) {|v|
      breakable
      v = v.to_s if Symbol === v
      text v
      text '='
      group(1) {
        breakable ''
        pp(obj.instance_eval(v))
      }
    }
  }
end
push_inspect_key(id) 点击以切换源代码

将 object_id id 添加到正在进行漂亮打印的对象集合中,以避免重复对象。

# File pp.rb, line 177
def push_inspect_key(id)
  Thread.current[:__recursive_key__][:inspect][id] = true
end
seplist(list, sep=nil, iter_method=:each) { |element| ... } 点击以切换源代码

添加一个分隔的列表。默认情况下,列表由逗号和可中断的空格分隔。

seplist 使用 iter_method 迭代 list。它将每个对象传递给为 seplist 提供的块。在每次 yield 之间调用过程 separator_proc

如果迭代次数为零,则根本不调用 separator_proc

如果 separator_proc 为 nil 或未给定,则使用 +lambda { comma_breakable }+。如果未给定 iter_method,则使用 :each。

例如,以下 3 个代码片段具有相似的效果。

q.seplist([1,2,3]) {|v| xxx v }

q.seplist([1,2,3], lambda { q.comma_breakable }, :each) {|v| xxx v }

xxx 1
q.comma_breakable
xxx 2
q.comma_breakable
xxx 3
# File pp.rb, line 261
def seplist(list, sep=nil, iter_method=:each) # :yield: element
  sep ||= lambda { comma_breakable }
  first = true
  list.__send__(iter_method) {|*v|
    if first
      first = false
    else
      sep.call
    end
    RUBY_VERSION >= "3.0" ? yield(*v, **{}) : yield(*v)
  }
end