It's one thing to enshrine it as a part of the language, like C++ templates and the C preprocessor, because that forces you (hopefully!) to think about things like maintainability and concern separation.
It's quite another to ad-hoc what amounts to a language extension to paper over quick-and-dirty design. And there's not much middle ground between the two. I'll ask myself the question, "do I want to extract this into a gem and maintain it separately?" and run pretty quickly into the normal coding equivalent of "am I making a game engine or a game?" My vision has to be pretty darned awesome for the answer to be "both."
Meta-programming is great to have, having access to a credit card is way better than not having one if you have the discipline to use it properly. It's essentially why I stick with Ruby rather than move to a statically-typed language, reflection and duck typing are tremendously useful when you don't really know what it is you're building yet but need to execute quickly. You can move at the speed of thought.
But I still consider it an anti-pattern. As the system matures I refactor it into plain-old boring Ruby, easily replaceable with Go or whatever if the need presents itself. I also like to reduce dependencies on libraries whenever practical.