Code review for newbie

I’m learning Ruby. There are so many ways to do things with Ruby, but is there a usual way how to implement something? I wrote this code, comments are welcome:

For example I don’t know if it is good practice to add a method to the built-in Integer class.

Like most languages, it is generally a Really Bad IdeaTM to inherit from standard classes in case they get changed or deprecated in the next version. Unless it is a class that is designed to be extended, of course, like ActiveRecord.

Aside from that there isn’t much wrong with the rest of it, apart from changing a few things to make them more idiomatic.

class Integer
  def happy?
    n = self
    n = n.to_s.chars.map { |x| x.to_i**2 }.sum while n > 6
    n == 1
  end
end
  1. Ruby methods that return booleans don’t use the Java Bean isSomething() pattern, they use something? instead. It’s like the code equivalent of a high rising terminal…
  2. Replaced split('') with chars which has the same effect but more closely describes the intent of the action
  3. Single line blocks can be replaced by statement modifiers such as if, unless, while and until to make the code more succinct. If you’ve ever written any perl you will have seen them before
  4. In your n == 1 you’ve already realised that you don’t need a return statement if it is the last expression in a block because Ruby always returns the value of the last expression evaluated

Thanks, looks nice. I guess it is unlikely that “Integer” gets changed, but maybe better to use a normal function. This would work then for other number types as well. I tried it now like this:

# returns true, if the number is happy
def happy?(n)
   n = n.to_s.chars.map { |x| x.to_i**2 }.sum while n > 6
   n == 1
end

# filter all numbers <= 100 for happiness and print the list
puts (1..100).select { |x| happy? x }

Is there a way to write the block argument to the select shorter, like with the previous code? Looks like the “&:” calls the argument as a method on the numbers. I would need some way to create a block which calls the function with the elements as an argument instead. I couldn’t find an explanation for “&:” and if there are more of such operators.

But I don’t know if this would be very Ruby idiomatic. Looks like method calls are used often in Ruby programs, so maybe extending the Integer class would be better in this case?

The &: construct is syntactic sugar. Without going into too much gory detail, it allows you to call a method on each item, the result of which becomes an element in the output stream. But it doesn’t allow you to pass a parameter to the method, so there is no simple shortcut in this case, you have to use a block.

On sites like this there always seems to be a bit of competition to shrink something down to a sparse, elegant one-liner, but sometimes it helps to be able to see what’s going on, too…

You are right, I started learning Ruby for code golf, but this is not always that best code to read.

But in a chat someone also suggested that I don’t need the extra filter, because sum can accept a filter block, and Integer has the digits method. This is the new version now, I think it looks perfect now, and even if it is a one liner, it is still easy to read and understand :grinning:

#!/usr/bin/env ruby

# prints all happy numbers <= 100
# https://en.wikipedia.org/wiki/Happy_number

# returns true, if the number is happy
def happy?(n)
   n = n.digits.sum { |x| x * x } while n > 6
   n == 1
end

# filter all numbers <= 100 for happiness and print the list
puts (1..100).select { |x| happy? x }

Looks good. Better stop before we cross the line from refactoring to obsession… :joy: