=begin
It seems impossible to implement without fundamentally changing the feel of writing ruby.
Due to enumerators, currently your example results in a SyntaxError:
$ pbpaste | ruby20
-:7: syntax error, unexpected keyword_end, expecting $end
How do we disambiguate between existing uses of (({&block})) and your proposal?
Currently a method with (({&block})) accepts an optional block argument that is captured to the local variable (({block})). Since a named block argument is always optional it can be used by methods that return Enumerators (such as creating an enumerator from an Enumerable internal to the object). Changing this to mean "a block argument is required" breaks such usage.
After solving the problem of specifying a method's signature to enable your special parsing, how do we look up this information at runtime if the method is dynamically defined or method_missing is involved?
How do we parse this example?
class C
def method
do_three_times
puts "Hi"
end
end
def initialize
# defines the do_three_times method in a manner that enables "do"-less syntax
require 'c/do_three_times'
end
end
C.new.do_three_times
The definition of (({do_three_times})) is ambiguous when the call is encountered, so the number of (({end}))s to consume is impossible to determine. Ruby can't look in (({c/do_three_times.rb})) to determine how to parse (({do_three_times})) since it is dynamic.
If the parser assumes (({do_three_times})) is a do-less block then (({C.new})) will require (({c/do_three_times.rb})). However, if that file defines (({do_three_times})) to be a method that returns an Enumerator (not a do-less block) then the file was required at the wrong spot (as the second (({end})) after (({puts})) closed C and #initialize was not part of class C so the require should not have happened.
I'm unsure how you are going to resolve ambiguity due to the dynamic nature of ruby absent a (({do})) or introduction of some other discriminator (such as python's significant whitespace).
=end