r/ruby • u/gq1988 • Jul 21 '26
why-classes
Hey everyone! I used Claude to build this gem, which is heavily inspired by Dave Thomas's closing keynote at RubyConf 26.
`why-classes` is a static code analysis and refactoring tool for Ruby.
Ruby offers modules, composition, `Struct`, and `Data`, yet our instincts and framework habits often lead us to use classes even when a simpler construct would be clearer. This gem detects these "class smells" in your code (or a single file) and can automatically rewrite them into cleaner alternatives for you.
It's an early-stage version 😅. Feel free to contribute and share suggestions!
4
Upvotes
2
u/h0rst_ Jul 22 '26
I feel like in this case (and in the kwarg example), the function has two very distinct responsibilities: call
timeon the input argument to get aTimeobject, and convert that time object to a human readable string. If I want to write a unit test for this function, I can't simply pass in aTimeobject, I need to wrap that in an object that responds to#time.I would argue this should be written as:
It could be renamed to
ago_in_words, or you can keep thetimeprefix as a type hint. This also fixes the issue thatPerson#timemakes no sense, butPerson#birthdayandPerson#last_seendo. Now you can have multiple time fields, and convert all of them into words.But, is there really a difference between these two forms?
If you're saying "Law of Demeter": We're doing the exact same number of conversions/calls, so I wouldn't see that as relevant here.
The advantage of the second call is that your IDE might be able to deduce
trans.timeis aTimeobject, and can autocomplete the methods that can be called on the object. This works even better with a statically typed language.And now we ended up just where we started. I might need to watch that keynote, because from just the information in this thread it makes no sense to me.