You almost had it. So, your problem is that the condition is evaluated only once? Well, what design do we know that we can evaluate as often as we want? That's right: features! So let condition function (or a Proc in Ruby lingo):
def custom_while(condition) loop do break unless condition.() yield end end i = 0 custom_while -> { i < 5 } do puts i i += 1 end
This, unfortunately, does not look as good as in other languages. Ruby's syntax and semantics are aggressively optimized for methods that take exactly 1 "function" as an argument. To do this, Ruby has a special syntactically and semantically lightweight construction, namely blocks. Once you have more than one, you're out of luck.
Compare this with languages ββthat have matching block literals, such as Smalltalk. In Smalltalk, you can write a while:do: method and call it like this:
i := 0. while: [i < 5] do: [Transcript write: i. i := i + 1].
In fact, in Smalltalk, the syntax for blocks is so small that it has no control structures. if / then / else is just a Boolean instance method, for example:
i % 2 == 0 ifTrue: [Transcript write: "even"] ifFalse: [Transcript write: "odd"].
And while is actually a Block instance method, so in fact your example will look like this:
i := 0. [i < 5] whileTrue: [Transcript write: i. i := i + 1]
Note. I do not guarantee Smalltalk code, I have not tested it.
source share