rellampec
rellampec

Reputation: 752

Method returning different type if block_given?

Would it be bad practice to have a method that returns self on block_given? and a different type if a block was not provided?

The example:

Config#item will return the item if a block is not given, and will return Config if it is given.

class Item
  :attr_reader :key

  def initialize(key)
    @key = key
  end

  def do_stuff
    puts "#{key} doing some stuff"
    self
  end
end

class Config
  attr_reader :items

  def initialize
    @items = {}
  end

  def item(key)
    itm = @items[key] ||= Item.new(key)
    if block_given?
      yield(itm)
      self
    else
      itm
    end
  end
end

Usage:

cnf = Config.new
cnf.item("foo") do |itm|
  itm.do_stuff
end

.item("bar") do |itm|
  itm.do_stuff
end

foo = .item("foo").do_stuff
cnf.item("baz").do_stuff
foo.do_stuff

The model is meant to use the same method item as a getter and as a way to refer to an item that needs to be configured or which configuration needs to be reopened.

Upvotes: 0

Views: 254

Answers (2)

Michael Gaskill
Michael Gaskill

Reputation: 8042

Not at all, as long as the users of your method have adequate understanding of this. Documentation helps quite significantly in these situations.

Consider the Ruby Standard Library. Many methods return different types based on their inputs and block_given?, such as Enumerable#map, Hash#each, and Range#step.

Like the standard library authors, you have to decide whether you prefer a compact interface to your class/model or consistent behavior from your methods. There are always tradeoffs to make, and you have numerous strong examples of each of these to draw from within the Ruby Standard Library.

Upvotes: 2

Jörg W Mittag
Jörg W Mittag

Reputation: 369624

Would it be bad practice to have a method that returns self on block_given? and a different type if a block was not provided?

No. In fact, there is an extremely well-known example of a method that has this exact signature: each. each returns self if a block is given, and an Enumerator when no block is given. In fact, many methods in Enumerable return an Enumerator when no block is given and something else if there is a block.

(I am actually surprised that you haven't encountered each or Enumerable so far.)

Upvotes: 2

Related Questions