Computer >> Máy Tính >  >> Lập trình >> Ruby

Code Reading Adventures:Awesome Print Gem

Bản in tuyệt vời là một viên ngọc đẹp giúp định dạng đầu ra của bạn trong irb &pry để làm cho nó dễ đọc hơn.

Ví dụ…

Đây là những gì hiển thị một hàm băm với awesome_print trông giống như:

Code Reading Adventures:Awesome Print Gem

Nhưng điều này hoạt động như thế nào?

"Sự thật chỉ có thể được tìm thấy ở một nơi:mã." - Robert C. Martin

Hãy xem mã nguồn để tìm hiểu!

In Awesomely

Tôi muốn bắt đầu phiên đọc mã với cái nhìn tổng quan nhanh về cấu trúc dự án (tệp &thư mục), sau đó tôi muốn đặt một câu hỏi để tập trung khám phá về sau.

Vì vậy, câu hỏi đầu tiên tôi nghĩ ra là :

Làm thế nào để awesome_print thay đổi đầu ra của pry?

Bây giờ tôi đội mũ thám tử của mình và đưa ra giả thuyết :

“Đá quý này có thể thay thế cho $stdout để nó có thể nắm bắt đầu ra của pry &sau đó làm cho nó đẹp. ”

Nhưng việc triển khai này sẽ không cho phép bạn tùy chỉnh đầu ra của mình, chẳng hạn như pretty_print (từ Thư viện Chuẩn của Ruby).

Ngoài ra, chúng tôi sẽ phải phân tích cú pháp hoặc thậm chí đánh giá mã, không phải là một ý tưởng tuyệt vời!

Tiếp theo :

Tôi đã xem xét cách nạp đá quý này.

Điều này sẽ cung cấp cho chúng tôi một điểm vào mã.

Đang tải bản in tuyệt vời

Để tải awesome_print về sơ suất, bạn phải làm điều này:

require 'awesome_print'
AwesomePrint.pry!

Bây giờ chúng ta muốn tìm pry! ở đâu được xác định.

Tôi đã sử dụng tính năng “tìm kiếm trong thư mục” trong Atom để tìm nó.

Đây là mã :

def pry!
  Pry.print = proc { |output, value| output.puts value.ai } if defined?(Pry)
end

Có vẻ như Pry cho phép bạn sửa đổi đầu ra của nó bằng cách đặt giá trị của print .

Vì vậy, câu trả lời cho câu hỏi “bắt đầu từ đâu” của chúng tôi 🙂

Bạn muốn tìm hiểu thêm về điều “proc” này? Đọc “Hướng dẫn cơ bản về Blocks, Procs &Lambdas”. Đây là một chương mẫu từ cuốn sách Ruby Deep Dive của tôi.

Proc này có hai đối số :

  • đầu ra
  • giá trị

Và nó gọi hai phương thức trên các đối tượng đó.

Câu hỏi tiếp theo :

Đây là gì ai phương pháp?

Đó là một phương thức được xác định trên Kernel mô-đun:

def ai(options = {})
  ap      = AwesomePrint::Inspector.new(options)
  awesome = ap.awesome(self)

  if options[:html]
    awesome = "</pre>#{awesome}</pre>"
    awesome = awesome.html_safe if defined? ActiveSupport
  end

  awesome
end

alias :awesome_inspect :ai
# {awesome} "awesome =awesome.html_safe nếu được định nghĩa? ActiveSupport end awesomeendalias:awesome_inspect:ai

Bởi vì tất cả các đối tượng bao gồm Kernel theo mặc định, chúng sẽ có ai này phương pháp có sẵn trên chúng.

Bây giờ chúng ta hãy tìm hiểu sâu hơn một chút và xem Inspector này như thế nào hoạt động của lớp.

Lớp thanh tra

Ngay sau khi mở inspector.rb chúng tôi tìm thấy một hàm băm tùy chọn lớn bên trong initialize phương pháp.

Đây là một phần của nó :

@options = {
  indent:        4,      # Number of spaces for indenting.
  index:         true,   # Display array indices.
  html:          false,  # Use ANSI color codes rather than HTML.
  multiline:     true,   # Display in multiple lines.
  # ...
}

Sau đó, chúng tôi có thể tìm thấy mã này :

@formatter  = AwesomePrint::Formatter.new(self)
@indentator = AwesomePrint::Indentator.new(@options[:indent].abs)

Thread.current[AP] ||= []

Vì vậy, điều này thiết lập thêm hai đối tượng dường như xử lý chính việc định dạng và thụt lề của mã.

Nhưng điều gì xảy ra với Thread.current này điều gì?

Chà, điều này cho phép bạn truy cập vào chuỗi hiện tại. Ngay cả khi bạn không sử dụng các chuỗi trong ứng dụng của mình, bạn sẽ có một, chuỗi “chính”.

AP này hằng số chỉ là một hằng số được xác định ở đầu inspector.rb :

AP = :__awesome_print__

Vậy điều gì đang xảy ra ở đây?

Bản in tuyệt vời đang sử dụng Thread.current &__awesome_print__ để lưu một số dữ liệu chỉ có sẵn trên chuỗi hiện tại.

Điều này được sử dụng để tránh các vấn đề với đa luồng.

Định dạng tuyệt vời

Hãy xem mã định dạng đầu ra, điều này xảy ra bên trong AwesomePrint::Formatter lớp học.

Cách thức hoạt động là trình kiểm tra (đối tượng được tạo bởi ai phương thức) sẽ gọi định dạng format phương pháp.

def unnested(object)
  @formatter.format(object, printable(object))
end

Sau đó, format này trên Formatter lớp sẽ tìm ra cách tốt nhất để xử lý loại đối tượng này và gọi một phương thức khác bằng cách sử dụng một chút lập trình siêu hình.

Đây là phương pháp :

def format(object, type = nil)
  core_class = cast(object, type)

  awesome = if core_class != :self
    send(:"awesome_#{core_class}", object) # Core formatters.
  else
    awesome_self(object, type) # Catch all that falls back to object.inspect.
  end

  awesome
end

Để hiểu Formatter này chúng ta cũng cần xem xét cast phương pháp:

def cast(object, type)
  CORE.grep(type)[0] || :self
end

CORE hằng số là một mảng các ký hiệu đại diện cho các lớp Ruby cốt lõi &:self là một biểu tượng được sử dụng để có nghĩa là "không tìm thấy" (chỉ trong ví dụ này, không phải trong Ruby nói chung).

CORE = [:array, :bigdecimal, :class, :dir, :file, :hash, :method, :rational, :set, :struct, :unboundmethod]

Điều gì xảy ra là đây :

Nếu đối tượng đang được định dạng nằm trong danh sách "lớp lõi" thì đối tượng đó sẽ có định dạng chuyên biệt.

Nếu không, nó sẽ nhận được một cái chung chung.

Các bộ định dạng chuyên dụng được định nghĩa theo lib/awesome_print/formatters/ thư mục &bao gồm những thứ như Array , Hash &Class .

Ví dụ:đây là phương thức định dạng cho các lớp:

def format
  superclass = klass.superclass
  if superclass
    colorize("#{klass.inspect} < #{superclass}", :class)
  else
    colorize(klass.inspect, :class)
  end
end

Bạn có thể viết bộ định dạng của riêng mình nếu bạn muốn.

Tóm tắt

Bạn đã tìm hiểu về đá quý Awesome Print, cho phép bạn hiển thị các đối tượng như mảng và hàm băm một cách đẹp mắt.

Hy vọng bạn thích điều này và học được điều gì đó mới!

Hãy chia sẻ bài đăng này trên mạng xã hội yêu thích của bạn ngay bây giờ để nhiều người có thể học hỏi 🙂