The consequences are always: code unmaintainable over the long term.
Unfortunately to reach this disillusioned state you need to hit some really hard walls, which doesn't happen to all ruby devs.
So in doubt no metaprogramming. Example: I never wrote a macro in a real world Elixir project.
But it's not abnormal for a rails codebase to have a Concern (rails module) that provides a class method that does something, specific to the application. Which is equivalent to a macro.
> Unfortunately to reach this disillusioned state you need to hit some really hard walls
I have seen quite a few Rails apps, some pretty old, and these were not the hard walls which were hit. One way of not hitting those specific walls (which are pretty soft IMO) is hiring decent people, decently compensated. And empowering them to make decisions.
A lot of codebases do that, and they create chain of undeclared dependencies between multiple modules being included that make impossible to determine the requirements to use such module in the first place.
The development tend also to slow down to a cripple, as well as being overstaffed to compensate.
For 'reasons', I need to add callback hooks into a particular HTTP Client library my org uses across several dozen of projects. The library we commonly use doesn't have hooks.
I've got a couple of options: switch wholesale to a different library, build a child class, build a nasty bit of monkey patching boiler plate, or build a little library which prepends some logic into the ancestors chain.
The first and second would cause eye-rolls ("I'm just calling an internal api in the way I've always done, why are you making me change it everywhere!"). The monkey patching boilerplate, well, gross. But a little bit of prepend logic packaged into a gem and I've got the behaviour I need.
One of the tremendous joys I get from ruby is never having the feeling that the language or runtime can't do something I need. Whether that thing should be done or which way it should be done is another matter.