Question

In Nokogiri 1.6.1, I'm observing the following behavior:

require 'nokogiri'

xml1 = Nokogiri::XML::Builder.new do |xml|
  xml.p
end
xml1.to_xml #=> <?xml version="1.0"?>\n<p/>

xml2 = Nokogiri::XML::Builder.new do |xml|
  xml.send(:p)
end
xml2.to_xml #=> <?xml version="1.0"?>

So, .p produces a <p/> element, while .send(:p) produces nothing. What's going on here? This behavior seems to contradict everything I've read about Nokogiri's API. It also seems illogical in terms of Ruby's semantics, unless that class overrides #send.

The same also happens with .send("p").

For reference:

How do I create XML using Nokogiri::XML::Builder with a hyphen in the element name?

https://www.ruby-forum.com/topic/4406393

Was it helpful?

Solution

Ruby’s send method will invoke private methods as well as public ones. In this case it ends up calling the Kernel#p method, which is a private method on all objects. You can see this by passing another argument to p that will be printed:

xml.send(:p, "A message that will be printed")

Another way to demonstrate this would be to use public_send, which doesn’t look at private methods and so will trigger method_missing and generate the tag.

xml.public_send(:p)

Of course you don’t really need to use public_send, since p doesn’t use any special characters and you can use it directly as a method:

xml.p
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top