You can use ruby after triple backticks to get Ruby syntax highlighting instead of just white text. It helps a lot for readability.
parens and explicit return statements aren't always necessary
DRY can be overdone, everything in moderation, and premature abstraction can bite you.
Ruby comments start with # instead of //
Ruby tends towards snake_case_names over camelCaseNames
Now then, article wise.
It may be good to mention that yield is effectively the same as this:
defhello2(&block)block.callend
yield just implies it. block_given? is also a nice feature for checking if the caller actually gave a block function or not.
Functions vs Yield blocks
Point One
Not sure what you mean here? A yielded block is a function, and can be reused. You may want to clarify that function is really a method, because function can be more commonly understood to mean proc or lambda instead in Ruby.
Point Two
yielded functions are closures, which means they can see the context where they were created.
Now when you mention not being able to change Integers that's more because they're primitive values. This will work the same across Procs, blocks, lambdas, methods, and anything else in Ruby.
For Strings though, those are mutable unless you have frozen strings on:
return will end any function, whether or not a yield is involved. Now inside a function, return does some real interesting and potentially confusing things depending on what type it is:
Can't say I ever really understood that one myself, keeps catching me whenever I start using proc for some reason in my code so I tend to go for lambda / -> when possible. lambda also is more explicit about arguments and arity than a proc is, so it's easier to tell something broke.
Remember though that block functions are Procs:
testing_two{}=>Proc
Point Four
This comes back to why, for me, I prefer the explicit passing of a block. Less magic and more easily understandable from a glance. Just remember that's a stylistic choice for me, do what makes more sense for your team.
...but you got real close to something fun in Ruby in the process. Let's assume we still have an Enumerable person class out there like above.
We're going to get into some metaprogramming, so buckle up, it's a trip.
For this one we'll need Object#send, ===, to_proc, and Hash to do some fun things with kwargs. If you've ever seen ActiveRecord, this will look familiar:
Person.where(age: 18..40,occupation: 'Driver')
We can do that using === and filter in Ruby by making our own class which responds to ===:
classQuerydefinitialize(**conditions)@conditions=conditionsend# Define what it means for a value to match a querydef===(value)# Do all of our conditions match?@conditions.all?do|match_key,match_value|# We use the key of the hash as a method name to extract a value,# then `===` it against our match value. That means the match value# could be anything like a `Regexp`, `Range`, or a lot more.match_value===value.send(match_key)endend# Make `call`, like `block.call`, point to `===`alias_method:call,:===# This will make more sense in the example below, but we can treat our class# like a function by doing thisdefto_proc->value{self.call(value)}end
Why the to_procand the ===? It allows us to do both of these:
# using `to_proc` via `&` to treat our Query class as a functionPerson.select(&Query.new(age: 18..40,occupation: 'driver'))# using `===` to call our query for a case statement:casepersonwhenQuery.new(age: 18..30)# somethingwhenQuery.new(occupation: 'Driver')# something elseelse# something else againend
This pattern is super powerful, and ended up expanded in a gem I wrote called Qo. The problem is you have to do some more lifting to get it to work with Array and Hash values to match against them.
Ruby has a lot of potential for flexibility, especially when you know about === and to_proc and how to leverage them.
Other thoughts
Keep writing, it takes a bit to really get into all the fun stuff, and feel free to ask questions on any of that, I got a bit carried away in responding.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
A few asides before I get into it:
ruby
after triple backticks to get Ruby syntax highlighting instead of just white text. It helps a lot for readability.return
statements aren't always necessaryDRY
can be overdone, everything in moderation, and premature abstraction can bite you.#
instead of//
snake_case_names
overcamelCaseNames
Now then, article wise.
It may be good to mention that
yield
is effectively the same as this:yield
just implies it.block_given?
is also a nice feature for checking if the caller actually gave a block function or not.Functions vs Yield blocks
Point One
Not sure what you mean here? A
yield
ed block is a function, and can be reused. You may want to clarify thatfunction
is really amethod
, becausefunction
can be more commonly understood to meanproc
orlambda
instead in Ruby.Point Two
yield
ed functions are closures, which means they can see the context where they were created.Now when you mention not being able to change
Integer
s that's more because they're primitive values. This will work the same acrossProc
s,block
s,lambda
s,method
s, and anything else in Ruby.For Strings though, those are mutable unless you have frozen strings on:
Point Three
return
will end any function, whether or not ayield
is involved. Now inside a function,return
does some real interesting and potentially confusing things depending on what type it is:Can't say I ever really understood that one myself, keeps catching me whenever I start using
proc
for some reason in my code so I tend to go forlambda
/->
when possible.lambda
also is more explicit about arguments andarity
than aproc
is, so it's easier to tell something broke.Remember though that block functions are
Proc
s:Point Four
This comes back to why, for me, I prefer the explicit passing of a block. Less magic and more easily understandable from a glance. Just remember that's a stylistic choice for me, do what makes more sense for your team.
Using Yield with Class Iterators
Enumerable
is a very common use of this:...which gets us all of the fun
Enumerable
methods likemap
and others.Now to your example:
A few quick cleanups and we have:
filter
will return anArray
making the assignment redundant. The name for a function used to filter is a predicate.Now a more pragmatic example of this might be to use the Enumerable trick from above:
This will allow you to directly control the
People
you get back:Second Implementation
Your second implementation makes this a bit more complicated:
...but you got real close to something fun in Ruby in the process. Let's assume we still have an
Enumerable
person class out there like above.We're going to get into some metaprogramming, so buckle up, it's a trip.
For this one we'll need
Object#send
,===
,to_proc
, andHash
to do some fun things withkwargs
. If you've ever seen ActiveRecord, this will look familiar:We can do that using
===
andfilter
in Ruby by making our own class which responds to===
:Why the
to_proc
and the===
? It allows us to do both of these:This pattern is super powerful, and ended up expanded in a gem I wrote called
Qo
. The problem is you have to do some more lifting to get it to work withArray
andHash
values to match against them.Ruby has a lot of potential for flexibility, especially when you know about
===
andto_proc
and how to leverage them.Other thoughts
Keep writing, it takes a bit to really get into all the fun stuff, and feel free to ask questions on any of that, I got a bit carried away in responding.