Permalink
Browse files

Using Enumerable to enhance collection functionality

After removing ClassyEum.find from 3.0, I decided to implement
it using Enumerable functionality for an API that is more consistent
with Ruby.
  • Loading branch information...
1 parent f928d39 commit 1d4803b43a64da3fd75caed81c7dab9f32408303 @beerlington beerlington committed Aug 10, 2012
Showing with 77 additions and 6 deletions.
  1. +39 −5 lib/classy_enum/collection.rb
  2. +38 −1 spec/classy_enum/collection_spec.rb
@@ -27,6 +27,9 @@ def self.included(klass)
end
module ClassMethods
+ include Enumerable
+ alias all to_a
+
def inherited(klass)
if self == ClassyEnum::Base
klass.class_attribute :enum_options
@@ -39,7 +42,7 @@ def inherited(klass)
super
end
- # Returns an array of all instantiated enums
+ # Iterates over instances of each enum in the collection
#
# ==== Example
# # Create an Enum with some elements
@@ -50,11 +53,42 @@ def inherited(klass)
# class Priority::Medium < Priority; end
# class Priority::High < Priority; end
#
- # Priority.all # => [Priority::Low.new, Priority::Medium.new, Priority::High.new]
- def all
- enum_options.map(&:new)
+ # Priority.each do |priority|
+ # puts priority # => 'Low', 'Medium', 'High'
+ # end
+ def each
+ enum_options.each {|e| yield e.new }
end
+ # Finds an enum instance by symbol, string, or block.
+ #
+ # If a block is given, it passes each entry in enum to block, and returns
+ # the first enum for which block is not false. If no enum matches, it
+ # returns nil.
+ #
+ # ==== Example
+ # # Create an Enum with some elements
+ # class Priority < ClassyEnum::Base
+ # end
+ #
+ # class Priority::Low < Priority; end
+ # class Priority::Medium < Priority; end
+ # class Priority::High < Priority; end
+ #
+ # Priority.find(:high) # => Priority::High.new
+ # Priority.find('high') # => Priority::High.new
+ # Priority.find {|e| e.to_sym == :high } # => Priority::High.new
+ def find(key=nil)
+ return super if block_given?
+
+ key = build(key)
+ return nil unless key.is_a?(ClassyEnum::Base)
+ super { |e| e == key }
+ end
+
+ alias detect find
+ alias [] find
+
# Returns a 2D array for Rails select helper options.
# Also used internally for Formtastic support
#
@@ -68,7 +102,7 @@ def all
#
# Priority.select_options # => [["Low", "low"], ["Really High", "really_high"]]
def select_options
- all.map {|e| [e.to_s.titleize, e.to_s] }
+ map {|e| [e.to_s.titleize, e.to_s] }
end
end
@@ -1,6 +1,7 @@
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
class ClassyEnumCollection < ClassyEnum::Base
+ delegate :odd?, :to => :to_i
end
class ClassyEnumCollection::One < ClassyEnumCollection
@@ -13,11 +14,47 @@ class ClassyEnumCollection::Three < ClassyEnumCollection
end
describe ClassyEnum::Collection do
- subject { ClassyEnumCollection }
+ subject(:enum) { ClassyEnumCollection }
its(:enum_options) { should == [ClassyEnumCollection::One, ClassyEnumCollection::Two, ClassyEnumCollection::Three] }
its(:all) { should == [ClassyEnumCollection::One.new, ClassyEnumCollection::Two.new, ClassyEnumCollection::Three.new] }
its(:select_options) { should == [['One', 'one'],['Two', 'two'], ['Three', 'three']] }
+
+ context '.map' do
+ it 'should behave like an enumerable' do
+ enum.map(&:to_s).should == %w(one two three)
+ end
+ end
+
+ context '.find, .detect, []' do
+ let(:expected_enum) { ClassyEnumCollection::Two.new }
+
+ [:find, :detect, :[]].each do |method|
+ it 'should return an instance when searching by symbol' do
+ enum.send(method, :two).should == expected_enum
+ end
+
+ it 'should return an instance when searching by string' do
+ enum.send(method, 'two').should == expected_enum
+ end
+
+ it 'should behave like an enumerable when using a block' do
+ enum.send(method) {|e| e.to_s == 'two'}.should == expected_enum
+ end
+
+ it 'should return nil if item cannot be found' do
+ enum.send(method, :not_found).should be_nil
+ end
+ end
+ end
+
+ context '.select' do
+ let(:expected_enum) { ClassyEnumCollection::Two.new }
+
+ it 'returns an array with each item where the block returns true' do
+ enum.select(&:odd?).should == [ClassyEnumCollection::One.new, ClassyEnumCollection::Three.new]
+ end
+ end
end
describe ClassyEnum::Collection, Comparable do

0 comments on commit 1d4803b

Please sign in to comment.