Skip to content

Commit

Permalink
Merge branch 'v3'
Browse files Browse the repository at this point in the history
  • Loading branch information
beerlington committed Jul 20, 2012
2 parents 2ad4f40 + b7b9ed1 commit 16ed8da
Show file tree
Hide file tree
Showing 29 changed files with 709 additions and 773 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ spec/reports
test/tmp
test/version_tmp
tmp
.DS_Store
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# ClassyEnum Changelog

## 3.0.0

* Removing ClassyEnum::Base.enum_classes in favor of using enum
inheritance to setup classes
* Removing ClassyEnum::Base.valid_options
* Removing ClassyEnum::Base.find
* Removing ClassyEnum::Base#name
* Removing :suffix option from classy_enum_attr
* Enforce use of namespacing for subclasses (Parent::Child < Parent)
* Use require instead of autoload
* Lots of code refactoring

## 2.3.0

* Deprecating ClassyEnum::Base#name (use to_s.titleize instead). `name` is
Expand Down
80 changes: 22 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,22 @@ ClassyEnum is a Ruby on Rails gem that adds class-based enumerator functionality

## Rails & Ruby Versions Supported

*Rails:*
*Rails:* 3.0.x - 3.2.x

* 3.0.x - 3.2.x: Fully tested in a production application.
* 2.3.x: If you need support for Rails 2.3.x, please install [version 0.9.1](https://rubygems.org/gems/classy_enum/versions/0.9.1)
*Ruby:* 1.8.7, 1.9.2 and 1.9.3

*Ruby:* Ruby 1.8.7, 1.9.2, and 1.9.3 are tested and supported
If you need support for Rails 2.3.x, please install [version 0.9.1](https://rubygems.org/gems/classy_enum/versions/0.9.1).
Note: This branch is no longer maintained and will not get bug fixes or new features.

## Installation

The gem is hosted at [rubygems.org](https://rubygems.org/gems/classy_enum)

You will also need to add `app/enums` as an autoloadable path. This configuration will depend on which version of rails you are using.

## Upgrading to 2.0
## Upgrading?

Prior to 2.0, enum classes were implicity defined and were only required
when overriding methods or properties. As of 2.0, all enum classes must
explicity subclass a child of ClassyEnum::Base. If you used the
generator, there are no changes to the existing structure.

Built-in Formtastic support has been removed. See the note at the
bottom of this readme for more information how how to enable it.
See the [wiki](https://github.com/beerlington/classy_enum/wiki/Upgrading) for notes about upgrading from previous versions.

## Example Usage

Expand All @@ -45,20 +39,19 @@ A new enum template file will be created at app/enums/priority.rb that will look

```ruby
class Priority < ClassyEnum::Base
enum_classes :low, :medium, :high
end

class PriorityLow < Priority
class Priority::Low < Priority
end

class PriorityMedium < Priority
class Priority::Medium < Priority
end

class PriorityHigh < Priority
class Priority::High < Priority
end
```

The `enum_classes` class macro will define the enum member order as well as additional ClassyEnum behavior, which is described further down in this document.
The class order will define the enum member order as well as additional ClassyEnum behavior, which is described further down in this document.

### 2. Customize the Enum

Expand All @@ -70,20 +63,18 @@ I would like to add a method called `send_email?` that all member subclasses res

```ruby
class Priority < ClassyEnum::Base
enum_classes :low, :medium, :high

def send_email?
false
end
end

class PriorityLow < Priority
class Priority::Low < Priority
end

class PriorityMedium < Priority
class Priority::Medium < Priority
end

class PriorityHigh < Priority
class Priority::High < Priority
def send_email?
true
end
Expand Down Expand Up @@ -119,11 +110,10 @@ With this setup, I can now do the following:
```ruby
@alarm = Alarm.create(:priority => :medium)

@alarm.priority # => PriorityMedium
@alarm.priority # => Priority::Medium
@alarm.priority.medium? # => true
@alarm.priority.high? # => false
@alarm.priority.to_s # => 'medium'
@alarm.priority.name # => 'Medium'

# Should this alarm send an email?
@alarm.send_email? # => false
Expand All @@ -137,7 +127,7 @@ The enum field works like any other model attribute. It can be mass-assigned usi

In some cases you may want an enum class to reference the owning object
(an instance of the active record model). Think of it as a `belongs_to`
relationship, where the enum can reference its owning object.
relationship, where the enum belongs to the model.

By default, the back reference can be called using `owner`.
If you want to refer to the owner by a different name, you must explicitly declare
Expand All @@ -147,14 +137,11 @@ Example using the default `owner` method:

```ruby
class Priority < ClassyEnum::Base
enum_classes :low, :medium, :high
end

...
# low and medium subclasses omitted
...

class PriorityHigh < Priority
class Priority::High < Priority
def send_email?
owner.enabled?
end
Expand All @@ -165,15 +152,12 @@ Example where the owner reference is explicitly declared:

```ruby
class Priority < ClassyEnum::Base
enum_classes :low, :medium, :high
owner :alarm
end

...
# low and medium subclasses omitted
...

class PriorityHigh < Priority
class Priority::High < Priority
def send_email?
alarm.enabled?
end
Expand Down Expand Up @@ -213,28 +197,15 @@ end

## Special Cases

What if your enum class name is not the same as your model's attribute name? No problem! Just use a second arugment in `classy_enum_attr` to declare the attribute name. In this case, the model's attribute is called *alarm_priority*.
What if your enum class name is not the same as your model's attribute name? No problem! Just use a second argument in `classy_enum_attr` to declare the attribute name. In this case, the model's attribute is called *alarm_priority*.

```ruby
class Alarm < ActiveRecord::Base
classy_enum_attr :alarm_priority, :enum => :priority
classy_enum_attr :alarm_priority, :enum => 'Priority'
end

@alarm = Alarm.create(:alarm_priority => :medium)
@alarm.alarm_priority # => PriorityMedium
```

If you would like the default getter method to return a string, you can
use the optional *:suffix* option for the enum getter:

```ruby
class Alarm < ActiveRecord::Base
classy_enum_attr :priority, :suffix => 'type'
end

alarm = Alarm.create(:priority => :high)
alarm.priority # => 'high'
alarm.priority_type # instance of PriorityHigh enum
@alarm.alarm_priority # => Priority::Medium
```

## Model Validation
Expand Down Expand Up @@ -265,20 +236,13 @@ end

While ClassyEnum was designed to be used directly with ActiveRecord, it can also be used outside of it. Here are some examples based on the enum class defined earlier in this document.

Instantiate an enum member subclass *PriorityLow*
Instantiate an enum member subclass *Priority::Low*

```ruby
# These statements are all equivalent
low = Priority.build(:low)
low = Priority.build('low')
low = Priority.find(:low)
low = PriorityLow.new
```

Get a list of the valid enum options

```ruby
Priority.valid_options # => low, medium, high
low = Priority::Low.new
```

## Formtastic Support
Expand Down
2 changes: 1 addition & 1 deletion classy_enum.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Gem::Specification.new do |gem|

gem.add_dependency('rails', '>= 3.0')

gem.add_development_dependency('rspec-rails', '~> 2.10.0')
gem.add_development_dependency('rspec-rails', '~> 2.11.0')
gem.add_development_dependency('sqlite3', '~> 1.3.6')
gem.add_development_dependency('json', '~> 1.6.5')

Expand Down
6 changes: 2 additions & 4 deletions gemfiles/Gemfile.rails-3.0.x
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
source :rubygems

gem 'rails', '~> 3.0.0'
gem 'rspec-rails', '~> 2.8.1'
gem 'formtastic', '~> 1.2.4'
gem 'rspec-rails', '~> 2.11.0'
gem 'sqlite3-ruby', :require => 'sqlite3'
gem 'json', '~> 1.6.5'
gem "jeweler", "~> 1.6.2"
gem 'json', '~> 1.6.5'
6 changes: 2 additions & 4 deletions gemfiles/Gemfile.rails-3.1.x
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
source :rubygems

gem 'rails', '~> 3.1.0'
gem 'rspec-rails', '~> 2.8.1'
gem 'formtastic', '~> 1.2.4'
gem 'rspec-rails', '~> 2.11.0'
gem 'sqlite3'
gem 'json', '~> 1.6.5'
gem "jeweler", "~> 1.6.2"
gem 'json', '~> 1.6.5'
6 changes: 2 additions & 4 deletions gemfiles/Gemfile.rails-3.2.x
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
source :rubygems

gem 'rails', '~> 3.2.0'
gem 'rspec-rails', '~> 2.8.1'
gem 'formtastic', '~> 1.2.4'
gem 'rspec-rails', '~> 2.11.0'
gem 'sqlite3'
gem 'json', '~> 1.6.5'
gem "jeweler", "~> 1.6.2"
gem 'json', '~> 1.6.5'
13 changes: 5 additions & 8 deletions lib/classy_enum.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
module ClassyEnum
autoload :Base, 'classy_enum/base'
autoload :InstanceMethods, 'classy_enum/instance_methods'
autoload :ClassMethods, 'classy_enum/class_methods'
autoload :Attributes, 'classy_enum/attributes'
end

ActiveRecord::Base.send :extend, ClassyEnum::Attributes
require 'classy_enum/collection'
require 'classy_enum/conversion'
require 'classy_enum/predicate'
require 'classy_enum/base'
require 'classy_enum/active_record'
58 changes: 58 additions & 0 deletions lib/classy_enum/active_record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
module ClassyEnum
module ActiveRecord

# Class macro used to associate an enum with an attribute on an ActiveRecord model.
# This method is automatically added to all ActiveRecord models when the classy_enum gem
# is installed. Accepts an argument for the enum class to be associated with
# the model. ActiveRecord validation is automatically added to ensure
# that a value is one of its pre-defined enum members.
#
# ==== Example
# # Associate an enum Priority with Alarm model's priority attribute
# class Alarm < ActiveRecord::Base
# classy_enum_attr :priority
# end
#
# # Associate an enum Priority with Alarm model's alarm_priority attribute
# classy_enum_attr :alarm_priority, :enum => 'Priority'
#
# # Allow enum value to be nil
# classy_enum_attr :priority, :allow_nil => true
#
# # Allow enum value to be blank
# classy_enum_attr :priority, :allow_blank => true
def classy_enum_attr(attribute, options={})
enum = (options[:enum] || attribute).to_s.camelize.constantize
allow_blank = options[:allow_blank] || false
allow_nil = options[:allow_nil] || false
serialize_as_json = options[:serialize_as_json] || false

error_message = "must be #{enum.all.to_sentence(:two_words_connector => ' or ', :last_word_connector => ', or ')}"

# Add ActiveRecord validation to ensure it won't be saved unless it's an option
validates_inclusion_of attribute,
:in => enum.all,
:message => error_message,
:allow_blank => allow_blank,
:allow_nil => allow_nil

# Define getter method that returns a ClassyEnum instance
define_method attribute do
enum.build(read_attribute(attribute),
:owner => self,
:serialize_as_json => serialize_as_json,
:allow_blank => (allow_blank || allow_nil)
)
end

# Define setter method that accepts either string or symbol for member
define_method "#{attribute}=" do |value|
value = value.to_s unless value.nil?
super(value)
end
end

end
end

ActiveRecord::Base.send :extend, ClassyEnum::ActiveRecord
Loading

0 comments on commit 16ed8da

Please sign in to comment.