Why does Dir.glob("*.txt").sort also need .each?

The second one fails because sort {|f| p f} really doesn't make sense. The block you use with sort is supposed to "return -1, 0, or +1" and take two arguments (the elements to be compared) but your block takes one argument and returns that argument because p str returns str.

The third one is fine because sort's default comparator block is equivalent to saying:

sort { |a, b| a <=> b }

so .sort.each makes perfect sense.

If you use the sort of block that sort expects in the second example:

Dir.glob("*.txt").sort {|a, b| a <=> b }

then things will work better. Or you could just leave out the block if you want to sorting things in ascending lexical order:

Dir.glob('*.txt').sort

The other answer is correct, but I think there is a deeper explanation. When you have a block after a method call, like Dir.glob("*.txt") {|f| p f}, the block is an (optional) argument to the method. In the definition of Dir.glob, there is a yield statement that runs the block.

When you chain the methods, like in Dir.glob("*.txt").sort {|f| p f}, the block becomes an argument to the sort method instead of the glob method. sort can also take a block to define a comparison, but this block doesn't make sense in that context.

Chaining each to get Dir.glob("*.txt").sort.each {|f| p f} makes the block an argument to the each method, which uses it like glob does (running the block for each argument).