Remix.run Logo
kace91 19 hours ago

That is interesting! I haven't explored Procs much, since I use ruby for a shared codebase at work and I was originally a bit afraid of trying to push unidiomatic ideas in the codebase.

In your experience, is it ok to use Procs for example for extraction of block methods for cleanliness in refactors? or would I hit any major roadblocks if I treated them too much like first-class functions?

Also, is there any particular Rails convention to place collections of useful procs? Or does that go a bit against the general model?

vinceguidry 16 hours ago | parent | next [-]

You shouldn't have much difficulty, Ruby converts blocks to Procs whenever it needs an actual object. Their semantics are intentionally kept the same. This is unlike lambdas, whose semantics are closer to methods.

Pass the wrong number of of arguments to a Proc or block, it will pass nil for missing args and omit extras. Pass the wrong number of arguments for a method or lambda and you get an ArgumentError. Use the return keyword in a lambda, it returns from the lambda, just like if you call return in a method. In a block or Proc, it returns from the calling method.

So I would feel comfortable leaning on them for refactoring as it's as Ruby intended. Just use lambdas when you want to turn methods into objects and Procs when you want to objectify blocks.

You should get ahold of a copy of Metaprogramming Ruby 2 if you find yourself refactoring a lot of Ruby. It's out of print, but ebooks are available.

vidarh 16 hours ago | parent [-]

Just to clarify here: Both lambdas and procs are Proc objects. Blocks gets turned into Proc objects when you take their value.

So just be clear about whether you're talking about a proc or a Proc...

> In a block or Proc, it returns from the calling method

No, in block or a Proc it returns from the scope where it was defined.

Usually this is the same, and so it doesn't usually matter much, but if you pass a proc or a block down to another method, then a return within the block will still return from the method where it was defined.

This can occasionally be useful, as you can use it to pass in a predicate to a method that can control if/when you want to return, irrespective of how deeply nested.

vidarh 10 hours ago | parent [-]

Too late to edit now, and this is what I get for quibbling about casing:

> No, in block or a Proc it returns from the scope where it was defined.

Should of course read:

> No, in a block or a proc it returns from the scope where it was defined.

Mystery-Machine 16 hours ago | parent | prev [-]

This sounds like a really innovative idea. I haven't seen a dedicated place for "collection of useful procs", but one emerging pattern is to use `app/services` and then have a bunch of single-responsibility service classes that each have call or perform method and then you use the service when you need some shared functionality. It's like a proc, but instead it's a class with `#call` method.

vidarh 10 hours ago | parent [-]

> It's like a proc, but instead it's a class with `#call` method.

It's called the "callable" pattern.