Skip to content

Instantly share code, notes, and snippets.

@markjlorenz
Last active August 29, 2015 14:03
Show Gist options
  • Save markjlorenz/3ee0194095ba84bee77f to your computer and use it in GitHub Desktop.
Save markjlorenz/3ee0194095ba84bee77f to your computer and use it in GitHub Desktop.
First and only
module Enumerable
def first_and_only!
fail(FirstAndOnly::LengthNotOne, count) if first(2).count != 1
first
end
module FirstAndOnly
LengthNotOne = Class.new(StandardError)
end
end

FirstAndOnly

One Thing

require first_and_only

[:thing].first_and_only! # => :thing

Too Many Things

require first_and_only

[1,2].first_and_only!
# => Enumerable::FirstAndOnly::LengthNotOne: 2

Not Enough Things

require first_and_only

[].first_and_only!
# => Enumerable::FirstAndOnly::LengthNotOne: 0

Works With ActiveRecord

require first_and_only

MyModel.count  # => 0

MyModel.where(some: "query").first_and_only!
# => Enumerable::FirstAndOnly::LengthNotOne: 0
@mikegee
Copy link

mikegee commented Jun 28, 2014

Two different errors seems like an overkill.

def first_and_only!
  fail FirstAndOnly::LengthNotOne, length unless length == 1
  first
end

@mikegee
Copy link

mikegee commented Jun 28, 2014

I think its best practice to define your method in a module then make Enumerable include it.

module FirstAndOnly
  def first_and_only!
    ...
  end
  LengthNotOne = Class.new StandardError
end

Enumerable.send :include, FirstAndOnly

That way, pry or other tools will see that the method is from your module.

@mikegee
Copy link

mikegee commented Jun 28, 2014

Enumerable doesn't define length, just count.

Calling count on a huge or infinite Range would be problematic. Perhaps you should only extend Array.

@markjlorenz
Copy link
Author

I think its best practice to define your method in a module then make Enumerable include it.

Totally agree, that's what I wanted to do... All the ways I tried to include a module into a module I kept getting undefined method when calling #first_and_only! (including the way you pointed out)

Two different errors seems like an overkill.

Good point.

Enumerable doesn't define length, just count....Perhaps you should only extend Array.

That's what I get for going on memory. Better than "extending array", I've modified the implementation to take #first(2) in the size check. This should be a nice middle ground.

@markjlorenz
Copy link
Author

All the ways I tried to include a module into a module...

The eigen class strikes again: https://www.ruby-forum.com/topic/109820. That explains why I couldn't get it to work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment