Những công dụng "ẩn" của pry không phải ai cũng biết
Pry là một công cụ nổi tiếng mà bất cứ lập trình viên Ruby nào cũng biết. Cách sử dụng rất đơn giản, chỉ cần thêm dòng lệnh binding.pry vào bất cứ đoạn code nào, chương trình sẽ dừng lại khi đọc đến đoạn code đó, và ta có thể sử dụng pry console như sau: From: lib/dry/types/hash/schema.rb @ line ...
Pry là một công cụ nổi tiếng mà bất cứ lập trình viên Ruby nào cũng biết. Cách sử dụng rất đơn giản, chỉ cần thêm dòng lệnh binding.pry vào bất cứ đoạn code nào, chương trình sẽ dừng lại khi đọc đến đoạn code đó, và ta có thể sử dụng pry console như sau:
From: lib/dry/types/hash/schema.rb @ line 58 Dry::Types::Hash::Schema#try: 40: def try(hash, &block) 41: success = true 42: output = {} 43: 44: begin 45: result = try_coerce(hash) do |key, member_result| 46: success &&= member_result.success? 47: output[key] = member_result.input 48: 49: member_result 50: end 51: rescue ConstraintError, UnknownKeysError, SchemaError => e 52: success = false 53: result = e 54: end 55: 56: binding.pry 57: => 58: if success 59: success(output) 60: else 61: failure = failure(output, result) 62: block ? yield(failure) : failure 63: end 64: end > (#<Dry::Types::Hash::Weak>)
Nhưng pry không chỉ có vậy, nó còn cung cấp những công cụ khác giúp cho việc tìm hiểu về code được chủ động và hiệu quả hơn. Dưới đây là một số tính năng hỗ trợ của pry mà một lập trình viên nên biết:
Liệt kê các method khả dụng
Pry console cung cấp một lệnh ls có khả năng liệt kê các hàm và biến khả dụng trong scope hiện tại. Ví dụ với pry console hiện lên ở ví dụ trên, lệnh ls sẽ in ra:
> (#<Dry::Types::Hash::Weak>) ls #<Dry::Equalizer:0x007fafd29f2b88>#methods: hash inspect Dry::Equalizer::Methods#methods: == eql? Dry::Types::Options#methods: meta pristine with Dry::Types::Builder#methods: constrained constrained_type constructor default enum optional safe | Dry::Types::Definition#methods: === default? name options primitive? success constrained? failure optional? primitive result valid? Dry::Types::Hash#methods: permissive schema strict strict_with_defaults symbolized weak Dry::Types::Hash::Schema#methods: [] call member_types Dry::Types::Hash::Weak#methods: try instance variables: @__args__ @member_types @meta @options @primitive locals: block e failure hash output result success
Đây là một danh sách liệt kê các hàm khả dụng trong scope hiện tại, được nhóm theo các class và module định nghĩa hàm đó. Ở phía dưới là danh sách các biến instance và local. Nhờ đó ta có thể nắm được sơ bộ vai trò và nhiệm vụ của đoạn code đang debug.
Lệnh ls còn cho phép ta đào sâu vào các phần khác của scope. Ta có thể thêm tùy chọn -locals, hay viết tắt -l để xem tên của các biến local cùng với giá trị hiện tại của chúng:
> (#<Dry::Types::Hash::Weak>) ls -l result = { :name=> #<Dry::Types::Result::Failure input=nil error=#<Dry::Logic::Result:0x007fafd2cb98d0 @success=false, @id=nil, @serializer=#<Proc:0x01@lib/dry/logic/rule.rb:47>>>} hash = {:name=>nil} output = {:name=>nil} success = false block = nil e = nil failure = nil
Tìm hiểu về code khi không có documentation
Pry cung cấp công cụ hỗ trợ việc tìm kiếm và liệt kê các hàm của một namespace bất kỳ. Ví dụ, nếu muốn tìm các hàm liên quan đến xử lý xpath của Nokogiri, ta dùng lệnh find-method:
> find-method xpath Nokogiri Nokogiri::CSS.xpath_for Nokogiri::CSS::Node Nokogiri::CSS::Node#to_xpath Nokogiri::CSS::Parser Nokogiri::CSS::Parser#xpath_for Nokogiri::XML::Document Nokogiri::XML::Document#implied_xpath_contexts Nokogiri::XML::Node Nokogiri::XML::Node#implied_xpath_contexts Nokogiri::XML::NodeSet Nokogiri::XML::NodeSet#xpath Nokogiri::XML::NodeSet#implied_xpath_contexts Nokogiri::XML::Searchable Nokogiri::XML::Searchable#xpath Nokogiri::XML::Searchable#xpath_at Nokogiri::XML::Searchable#xpath_query_from_css_rule
Từ kết quả tìm kiếm ta có thể học được một số điều khá thú vị:
- Ta có thể convert một CSS selector thành XPath
- Ta có thể search trên một XML document với hàm #xpath và #xpath_at...
Nếu muốn tìm hiểu thêm và nắm được chính xác cách sử dụng một hàm ta có thể sử dụng lệnh stat:
> stat Nokogiri::CSS.xpath_for Method Information: -- Name: xpath_for Alias: None. Owner: #<Class:Nokogiri::CSS> Visibility: public Type: Bound Arity: -2 Method Signature: xpath_for(selector, options=?) Source Location: /dev/gems/ruby/2.4.1/gems/nokogiri-1.7.2/lib/nokogiri/css.rb:22
Thậm chí ta có thể thấy rõ được phương thức hoạt động của hàm với lệnh show-source:
> show-source Nokogiri::CSS.xpath_for From: /dev/gems/ruby/2.4.1/gems/nokogiri-1.7.2/lib/nokogiri/css.rb @ line 22: Owner: #<Class:Nokogiri::CSS> Visibility: public Number of lines: 3 def xpath_for(selector, options={}) Parser.new(options[:ns] || {}).xpath_for selector, options end
Hoặc ta có thể xem doc của hàm nếu có với lệnh show-doc:
> show-doc Nokogiri::XML::Searchable#xpath From: /dev/gems/ruby/2.4.1/gems/nokogiri-1.7.2/lib/nokogiri/xml/searchable.rb @ line 122: Owner: Nokogiri::XML::Searchable Visibility: public Signature: xpath(*args) Number of lines: 29 call-seq: xpath *paths, [namespace-bindings, variable-bindings, custom-handle-class] Search this node for XPath paths. paths must be one or more XPath queries. node.xpath('.//title') A hash of namespace bindings may be appended. For example: node.xpath('.//foo:name', {'foo' => 'http://example.org'}) node.xpath('.//xmlns:name', node.root.namespace) A hash of variable bindingd may also be appended to namespace bindings. For example: node.xpath('.//address[@domestic=$value]', nil, {:value => 'Yes'}) Custom XPath functions may also be defined. To define custom functions create a class and implement the function you want to define. The first argument to the method will be the current matching NodeSet. Any other arguments are ones that you pass in. Note that this class may appear anywhere in the argument list. For example: node.xpath('.//title[regex(., "w+")]', Class.new { def regex node_set, regex node_set.find_all { |node| node['some_attribute'] =~ /#{regex}/ } end }.new) >
Phía trên là những lệnh đơn giản và hữu ích khi debug với pry. Hy vọng bài viết này sẽ giúp ích được cho bạn trong công việc. Xin cảm ơn.