I don't programme much any more but the whole beauty of Ruby that it pretty much heavily relies on #respond_to? / duck typing and thus you don't rely on types or class checking at all.
Most ruby code isn't written like that - it's written like most static languages, where objects conform to interfaces / traits / type classes / pick your poison. The community is shifting towards explicitly specifying and statically checking types now. rbs and sorbet are a testament to this.
I wouldn't say it's really a beauty of the language, it may have been the original design intent but time has shown what's actually maintainable.
I don’t think the existence of a library to do something is evidence of the community shifting. For me the complete absence of types from any Ruby I see IRL or in examples from conference talks, readmes etc is evidence that the community is uninterested despite tons of effort from big players.
I think there's some real sample bias in that definition of "the community" though, because people who are passionate Ruby programmers giving conference talks, running meetups, etc are often a distinctly different group than the regular-old programmers making business software go 'round every day. The big players writing tools for bringing various flavors of type safety into Ruby are doing it because they're experiencing the pain of having lots of programmers working on large, complex software over years-long periods with the tools that Ruby gives you out of the box. They often employ some of those community fixtures, but thats not the majority of an engineering organization.
The reality is that there certainly are enthusiast programmers who can thrive with the lightweight elegance of stock Ruby, but most people writing code professionally aren't enthusiast programmers under ideal conditions. Everything is always a little more distracted, a little less well-defined, and a little more coupled to legacy than anyone would want. And those are the conditions where I want my tools working as hard as possible, automatically, for me / my teams.
Using #respond_to? is normally a code smell. The point of duck typing is exactly that it allows you to avoid checking the type of a class. As long as the object responds to the correct messages, the type does not matter.
#respond_to? is fine, it's really more #is_a? that is a code smell, in my opinion. As long as you're dispatching based on #respond_to? (i.e. "does this respond to each") by calling the method you're checking, when it does respond, you're fine as far as duck typing goes. It's when you check #is_a? and then dispatch based on type where things get weird.
An example I always used to use was something like a method that could take a single item or a collection:
def unpicky(something)
if something.respond_to?(:each)
# unpack using each or recurse to something.each do |item| unpicky(item) end
else
# main body
end
end
I don't think you're really losing the ability to check if an object responds to a message ie a_car.respond_to?(:color) just because theres type annotations. And I assume the type checker doesnt yell if you do a_car.color after that -- or if it does there's surely an equivalent to Typescript's `any` to accomplish it.
As for authoring classes, respond_to_missing?/method_missing should be rare, usually in a situation where its the only way to accomplish something. There's never been a reason to write something like:
class Car
def respond_to_missing?(name, priv)
[:color, :color=].include?(name)
end
def method_missing(name, *args, &block)
if name == :color
@color
elsif name == :color=
@color = args.first
end
end
end
Instead of
class Car
def color; @color; end
def color=(value); @color = value; end
end
Or, more idiomatically
class Car
attr_accessor :color
end
And for that last case, T-Ruby apparently covers it with: