Array#select returns a new array with all the elements that returned true from the block. It does this by iterating over each element, passing it to the block, running the block if the block returns true it puts the element in the new array if not it will skip it and once done it will return a new array.
With that said there are a few other things we should know first before delving into the problem you're having.
1) In Ruby there's a concept called Truthiness. That means that every element except for nil and false evaluates to true. Take for example if I ran this conditional
if 'happy puppy'
puts "I'm the happiest puppy"
end
You'd see that I'm the happiest puppy is output. That's because the string, not being false or nil, will evaluate to true. Conversely if ran this code
if nil
puts "Truthiness means all things evaluate to true except nil and false"
end
In this example, the conditional wouldn't output the string because nil doesn't evaluate to true.
2) Pay careful attention to what a method outputs and returns. In the case of Kernel#Puts it outputs n and returns nil. When the block being passed to Array#select is invoked it runs each line of code in the block including puts. That's why we see each number output. Then, this is the important part, it returns nil. Now remember the rules of Truthiness? Because this is the last line of code in the block it's the implicit return of the entire block. That means the block will return nil which evaluates to false.
3) Now on to Array#select, it works by iterating over each element in an array and invoking the block on it. Based on the return value of the block it'll decide whether or not the element belongs in the return array. In your first example, puts is used on the last line and returns nil which means that the block will always evaluate to false. That's why it outputs the element but then returns an empty array. In the second example, the last line in the block is n+2 which will evaluate to an integer. This is where truthiness comes in to play, an integer (or anything besides false or nil) will always evaluate to true. This means the block always returns true. That's why all the elements are returned in the array.