What is the correct idiom for shorting a Ruby `begin ... end` block?

I often remember Ruby methods using block syntax begin ... end:

$memo = {}
def calculate(something)
  $memo[something] ||= begin
    perform_calculation(something)
  end
end

However, there is. If I return earlier from the block begin ... endusing the guard clause, the result will not be stored in memory:

$memo = {}
def calculate(something)
  $memo[something] ||= begin
    return 'foo' if something == 'bar'
    perform_calculation(something)
  end
end
# does not memoize 'bar'; method will be run each time

I can avoid this by avoiding the instructions return:

$memo = {}
def calculate(something)
  $memo[something] ||= begin
    if something == 'bar'
      'foo'
    else
      perform_calculation(something)
    end
  end
end

This works, but I do not like it because:

  • it’s easy to forget that in this case I’m not allowed to use return.
  • under many conditions, it clutters the code, unlike the security offer.

Is there a better idiom for this other than avoiding return?

+4
source share
5 answers

, ... . , procs:

$memo = {}
def calculate(something)
  $memo[something] ||= -> do
    return 'foo' if something == 'bar'
    perform_calculation(something)
  end.call
end

, , , , .

+4

:

def calculate(something)
  $memo[something] ||= _calculate(something)
end

def _calculate(something)
  return if something == 'bar'
  perform_calculation(something) # or maybe inline this then
end

, , , . .

+3

- , . :

def memoize(method_name)
  implementation = method(method_name)

  cache = Hash.new do |h, k|
    h[k] = implementation.call(*k)
  end

  define_method(method_name) do |*args|
    cache[args]
  end
end

, . , , , , , , . ! , , , x_forget x.

:

def calculate(n)
  return n if (n < 1)

  n + 2
end
memoize(:calculate)

:

10.times do |i|
  p '%d=%d' % [ i % 5, calculate(i % 5) ]
end

# => "0=0"
# => "1=3"
# => "2=4"
# => "3=5"
# => "4=6"
# => "0=0"
# => "1=3"
# => "2=4"
# => "3=5"
# => "4=6"
+2

, , , - .

$memo = {}

def calculate(something)
  $memo[something] ||= something == 'bar' ? 'foo' : perform_calculation(something)
end

.

def perform_calculation(something)
  'baz'
end

calculate('bar')
  #=> "foo" 
$memo
  #=> {"bar"=>"foo"} 
calculate('baz')
  #=> "baz" 
$memo
  #=> {"bar"=>"foo", "baz"=>"baz"} 
calculate('bar')
  #=> "foo" 
$memo
  #=> {"bar"=>"foo", "baz"=>"baz"} 
0

I do not know the solution using return, but for the sentence guard in your example I would use case.

$memo = {}
def calculate(something)
  $memo[something] ||= case something
                       when 'foo' then 'bar'
                       else perform_calculation(something)
                       end

end
0
source

Source: https://habr.com/ru/post/1672848/


All Articles