def dress(dog_or_dogs) | |
dressed_dogs = Array(dog_or_dogs).map {|dog| DogSweater.new(dog) } | |
dog_or_dogs.respond_to?(:each) ? dressed_dogs : dressed_dogs.first | |
end | |
one_dog = dress(Dog.new) | |
all_my_dogs = dress([Dog.new, Dog.new, Dog.new]) |
Isn't this a little clearer?
def dress(dog)
DogSweater.new(dog)
end
def dress_all(dogs)
dogs.map { |dog| dress(dog) }
end
one_dog = dress(Dog.new)
all_my_dogs = dress_all([Dog.new, Dog.new, Dog.new])
class Dog
def dress
DogSweater.new(self)
self
end
end
class Dogs < Struct.new(:dogs)
def dress
@dogs.map { |dog| dog.dress }
end
end
dog = Dog.new
dogs = Dogs.new([Dog.new, Dog.new, Dog.new])
one_dog = dog.dress
all_my_dogs = dogs.dress
Or if you're feeling slightly risque:
class Dog
include Enumerable
def dress
DogSweater.new(self)
self
end
def each(&block)
block.call(self)
end
end
dog = Dog.new
dogs = Dogs.new([Dog.new, Dog.new, Dog.new])
one_dog = dog.map { |dog| dog.dress }
all_my_dogs = dogs.map { |dog| dog.dress }
Since the example is contrived, not sure how far to go with this 😏 With these implementations, I'm making an assumption, there's more to it than just a simple Array(...).map
could solve.
A small variation of @nakajima's example is what I have used in the past for this sort of thing:
def dress(input)
input.respond_to?(:each) ? dress_all(input) : dress_one(input)
end
def dress_one(dog)
DogSweater.new(dog)
end
def dress_all(dogs)
dogs.map { |dog| dress(dog) }
end
def dress(*dogs)
dogs.size == 1 ? dress_dog(dogs[0]) : dogs.map { |dog| dress_dog(dog) }
end
def dress_dog(dog)
DogSweater.new(dog)
end
dressed_dog = dress(Dog.new)
dressed_dogs = dress(Dog.new, Dog.new, Dog.new)
more_dressed_dogs = dress(*other_dogs)
I'm looking for a better pattern for defining a method that takes a single object or an array of objects as an argument
Don't? Why not just UTFL™?
all_my_dogs = [Dog.new, Dog.new, Dog.new].map(&:dress)
This uses core functionality of the language to handle a core function (do something to every element in this collection and return the collection) and doesn't require that I understand the meaning of different inputs to dress
. All for the modest cost of 6 additional characters.
@rjackson why call dress from within dress_all rather than dress_one. Calling dress one seems simpler to me
How about:
Or you could change the
map
block calldress(dog)
again if finding that's duplication.