iron-enum 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/History.txt +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +93 -0
- data/Version.txt +1 -0
- data/lib/iron/enum/attr_support.rb +141 -0
- data/lib/iron/enum/core.rb +101 -0
- data/lib/iron/enum/model_support.rb +30 -0
- data/lib/iron/enum.rb +77 -0
- data/spec/enum/attr_spec.rb +32 -0
- data/spec/enum/enum_spec.rb +29 -0
- data/spec/enum/key_spec.rb +23 -0
- data/spec/enum/model_spec.rb +79 -0
- data/spec/enum/name_spec.rb +32 -0
- data/spec/enum/option_spec.rb +20 -0
- data/spec/enum/value_spec.rb +32 -0
- data/spec/spec_helper.rb +21 -0
- metadata +111 -0
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require <%= File.join(File.expand_path(File.dirname(__FILE__)), 'spec', 'spec_helper.rb') %>
|
data/History.txt
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Irongaze Consulting LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
'Software'), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
17
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
18
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
19
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
20
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
= GEM: iron-enum
|
2
|
+
|
3
|
+
Written by Rob Morris @ Irongaze Consulting LLC (http://irongaze.com)
|
4
|
+
|
5
|
+
== DESCRIPTION
|
6
|
+
|
7
|
+
Add support for rich enum values (enumerated constants) to Ruby/Rails.
|
8
|
+
|
9
|
+
== SYNOPSIS
|
10
|
+
|
11
|
+
Managing constants - status flags, system states, etc - is frustrating when working
|
12
|
+
with Ruby and Rails. The canonical solution is to use class constants. But doing so
|
13
|
+
leaves a lot to be desired. This gem provides a much more Ruby-like way of dealing
|
14
|
+
with magic constants, that provides symbol/key-based lookup, automatic conversion between
|
15
|
+
keys and values, user-friendly naming, Rails integration, attribute support, and more.
|
16
|
+
|
17
|
+
To use:
|
18
|
+
|
19
|
+
# Require the gem's classes (not needed if using Bundler)
|
20
|
+
require 'iron/enum'
|
21
|
+
|
22
|
+
# Declare an enum module. In this case, let's say we're working on a
|
23
|
+
# shopping cart system that tracks orders. Orders have a status - perfect
|
24
|
+
# place for an enumeration!
|
25
|
+
module OrderStatus
|
26
|
+
enum :created, 1
|
27
|
+
enum :cancelled, 2, 'No Sale'
|
28
|
+
enum :purchased, 3
|
29
|
+
enum :shipped, 4
|
30
|
+
enum :returned, 5
|
31
|
+
end
|
32
|
+
|
33
|
+
# Once you have your enum set up, there are a host of things you can do
|
34
|
+
# To start with, enums set up normal Ruby class constants
|
35
|
+
>> puts OrderStatus::PURCHASED
|
36
|
+
=> 3
|
37
|
+
|
38
|
+
# But you can also refer to them with symbolic keys
|
39
|
+
>> puts OrderStatus.value(:purchased)
|
40
|
+
=> 3
|
41
|
+
|
42
|
+
# You can convert between values, keys and text
|
43
|
+
>> OrderStatus.value(:shipped)
|
44
|
+
=> 4
|
45
|
+
>> OrderStatus.name(:shipped)
|
46
|
+
=> 'Shipped'
|
47
|
+
>> OrderStatus.key(4)
|
48
|
+
=> :shipped
|
49
|
+
|
50
|
+
# Validate values against the set of good values
|
51
|
+
>> OrderStatus.valid?(10)
|
52
|
+
=> false
|
53
|
+
|
54
|
+
# Get an array of all valid values
|
55
|
+
>> OrderStatus.values
|
56
|
+
=> [1, 2, 3, 4, 5]
|
57
|
+
# Get a selection of values by key
|
58
|
+
>> OrderStatus.values(:created, :cancelled, :returned)
|
59
|
+
=> [1, 2, 5]
|
60
|
+
|
61
|
+
# This is all handy, but where enums really shine is as declared attributes
|
62
|
+
class Order < ActiveRecord::Base
|
63
|
+
enum_attr :status => OrderStatus
|
64
|
+
end
|
65
|
+
|
66
|
+
# Now you can set a value using a key
|
67
|
+
>> @order = Order.new
|
68
|
+
>> @order.status = :shipped
|
69
|
+
=> 4
|
70
|
+
# Test for a given value with a clear syntax
|
71
|
+
>> @order.status_returned?
|
72
|
+
=> false
|
73
|
+
# Set a value
|
74
|
+
>> @order.status_returned!
|
75
|
+
=> 5
|
76
|
+
|
77
|
+
# You even get free scoping
|
78
|
+
>> Order.with_status(:shipped)
|
79
|
+
=> [...all orders with status == 4...]
|
80
|
+
|
81
|
+
== REQUIREMENTS
|
82
|
+
|
83
|
+
None, though you'll need rspec, sqlite3 and active_record gems to test and build the gem
|
84
|
+
|
85
|
+
== INSTALL
|
86
|
+
|
87
|
+
To install, simply run:
|
88
|
+
|
89
|
+
sudo gem install iron-enum
|
90
|
+
|
91
|
+
RVM users can skip the sudo:
|
92
|
+
|
93
|
+
gem install iron-enum
|
data/Version.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Enum
|
2
|
+
|
3
|
+
# Provides helper methods to integrate enumerated constants (Enum) into your model layer. Given an enum
|
4
|
+
# defined like so:
|
5
|
+
#
|
6
|
+
# module UserType
|
7
|
+
# enum :guest, 0
|
8
|
+
# enum :member, 1
|
9
|
+
# enum :admin, 2
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# To add an enumerated value to a Rails model, simply add a column of type :integer to your model, then
|
13
|
+
# declare it like so:
|
14
|
+
#
|
15
|
+
# class User < ActiveRecord::Base
|
16
|
+
# enum_attr :user_type => UserType
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# When using non-model classes, it's the same syntax:
|
20
|
+
#
|
21
|
+
# class User
|
22
|
+
# enum_attr :user_type => UserType
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# This will tell your class/model that the user_type attribute contains values from the UserType enum, and
|
26
|
+
# will add:
|
27
|
+
#
|
28
|
+
# @user.user_type => integer value or nil
|
29
|
+
# @user.user_type_admin? => true if object's user_type value == UserType::ADMIN
|
30
|
+
# @user.user_type_admin! => set the object's user_type to be UserType::ADMIN (does not save model!)
|
31
|
+
# @user.user_type_as_key => returns the key form of the current field value, eg :member
|
32
|
+
# @user.user_type_as_name => returns text name of the current field's value, eg 'Guest'
|
33
|
+
#
|
34
|
+
# In addition, you can set enum attributes via key, eg:
|
35
|
+
#
|
36
|
+
# @user.user_type = :admin
|
37
|
+
#
|
38
|
+
# and the key will be converted to a value on the fly.
|
39
|
+
#
|
40
|
+
# ActiveRecord models get a few extras. To start, each enum attribute will add a smart scope:
|
41
|
+
#
|
42
|
+
# User.with_user_type(UserType::MEMBER) => scope returning a relation selecting User instances where user_type's value == UserType::MEMBER
|
43
|
+
#
|
44
|
+
# In addition, enum attributes will show up in #inspect output as e.g. UserType::GUEST instead of 0.
|
45
|
+
module AttrSupport
|
46
|
+
|
47
|
+
# Call with enum_attr :field => Enum
|
48
|
+
def enum_attr(name_to_enum_map)
|
49
|
+
# Save off the attr map
|
50
|
+
@enum_attrs ||= {}
|
51
|
+
@enum_attrs.merge!(name_to_enum_map)
|
52
|
+
|
53
|
+
# Run each newly added enum attribute
|
54
|
+
name_to_enum_map.each_pair do |attr_name, enum|
|
55
|
+
# Convert Enum to "Enum"
|
56
|
+
enum_klass = enum.to_s
|
57
|
+
|
58
|
+
# Set up general use sugar - allows calling:
|
59
|
+
# attr_as_key to get back eg :production or :online instead of 1 or 5
|
60
|
+
# attr_as_name to get back eg "Production" or "Online"
|
61
|
+
class_eval <<-eos, __FILE__, __LINE__ + 1
|
62
|
+
def #{attr_name}_as_key
|
63
|
+
#{enum_klass}.key(self.#{attr_name})
|
64
|
+
end
|
65
|
+
|
66
|
+
def #{attr_name}_as_name
|
67
|
+
#{enum_klass}.name(self.#{attr_name})
|
68
|
+
end
|
69
|
+
eos
|
70
|
+
|
71
|
+
# Get all the possible values for this enum in :key format (ie as symbols)
|
72
|
+
enum.keys.each do |key|
|
73
|
+
# Get the value for this key (ie in integer format)
|
74
|
+
val = enum.value(key)
|
75
|
+
|
76
|
+
# Build sugar for testing and setting the attribute's enumerated value
|
77
|
+
class_eval <<-eos, __FILE__, __LINE__ + 1
|
78
|
+
def #{attr_name}_#{key}?
|
79
|
+
self.#{attr_name} == #{val}
|
80
|
+
end
|
81
|
+
|
82
|
+
def #{attr_name}_#{key}!
|
83
|
+
self.#{attr_name} = #{val}
|
84
|
+
end
|
85
|
+
eos
|
86
|
+
end
|
87
|
+
|
88
|
+
if defined?(ActiveRecord) && self < ActiveRecord::Base
|
89
|
+
|
90
|
+
# Define a finder scope
|
91
|
+
scope "with_#{attr_name}", lambda {|*vals|
|
92
|
+
vals.flatten!
|
93
|
+
if vals.empty?
|
94
|
+
where("?", false)
|
95
|
+
elsif vals.count == 1
|
96
|
+
where(attr_name => enum.value(vals.first))
|
97
|
+
else
|
98
|
+
where(attr_name => enum.values(vals))
|
99
|
+
end
|
100
|
+
}
|
101
|
+
|
102
|
+
# Override default setter to allow setting an enum attribute via key
|
103
|
+
class_eval <<-eos, __FILE__, __LINE__ + 1
|
104
|
+
def #{attr_name}=(val)
|
105
|
+
write_attribute(:#{attr_name}, #{enum_klass}.value(val))
|
106
|
+
end
|
107
|
+
eos
|
108
|
+
|
109
|
+
else
|
110
|
+
|
111
|
+
# Create getter/setter to allow setting an enum attribute via key
|
112
|
+
class_eval <<-eos, __FILE__, __LINE__ + 1
|
113
|
+
def #{attr_name}
|
114
|
+
@#{attr_name}
|
115
|
+
end
|
116
|
+
|
117
|
+
def #{attr_name}=(val)
|
118
|
+
@#{attr_name} = #{enum_klass}.value(val)
|
119
|
+
end
|
120
|
+
eos
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# True if the given symbol maps to an enum-backed attribute
|
128
|
+
def enum_attr?(name)
|
129
|
+
return false unless @enum_attrs
|
130
|
+
@enum_attrs.key?(name)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Gets the enum class for a given attribute, or nil for none
|
134
|
+
def enum_for_attr(name)
|
135
|
+
return nil unless @enum_attrs
|
136
|
+
@enum_attrs[name]
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Enum
|
2
|
+
module Core
|
3
|
+
|
4
|
+
# List of enum data used for all other enum methods
|
5
|
+
def enum_list
|
6
|
+
@enum_list ||= []
|
7
|
+
@enum_list
|
8
|
+
end
|
9
|
+
|
10
|
+
# Value for a given key or value
|
11
|
+
def value(key)
|
12
|
+
return nil if key.nil?
|
13
|
+
row_for(key)[VALUE_IDX]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Convert array of keys to an array of values
|
17
|
+
def values(*included)
|
18
|
+
rows_for(*included).collect {|row| row[VALUE_IDX]}
|
19
|
+
end
|
20
|
+
|
21
|
+
# True if a valid value (not key!), false if not
|
22
|
+
def valid_value?(val)
|
23
|
+
return values.include?(val)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Key for a given key or value
|
27
|
+
def key(key)
|
28
|
+
return nil if key.nil?
|
29
|
+
row_for(key)[KEY_IDX]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Convert an array of values into an array of keys
|
33
|
+
def keys(*included)
|
34
|
+
rows_for(*included).collect {|row| row[KEY_IDX]}
|
35
|
+
end
|
36
|
+
|
37
|
+
# Name for a given key/value
|
38
|
+
def name(key = :_no_value_)
|
39
|
+
return nil if key.nil?
|
40
|
+
return super() if key == :_no_value_
|
41
|
+
row_for(key)[NAME_IDX]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Convert arrays of keys/values into an array of names
|
45
|
+
def names(*included)
|
46
|
+
rows_for(*included).collect {|row| row[NAME_IDX]}
|
47
|
+
end
|
48
|
+
|
49
|
+
# Used for select tag options, optionally pass set of keys/ids to include, eg if there are only
|
50
|
+
# a subset that would be valid for selection in a given context.
|
51
|
+
def options(*included)
|
52
|
+
included.flatten!
|
53
|
+
if included.empty?
|
54
|
+
# All options
|
55
|
+
enum_list.collect {|row| option_for(row.first)}
|
56
|
+
else
|
57
|
+
# Only the specified ones
|
58
|
+
included.collect {|key| option_for(key)}.compact
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Array in order required by select fields
|
63
|
+
def option_for(key)
|
64
|
+
opt = [name(key), value(key)]
|
65
|
+
end
|
66
|
+
|
67
|
+
# Override inspect on the enum module to give a pretty listing
|
68
|
+
def inspect
|
69
|
+
values.collect do |v|
|
70
|
+
"#{self.to_s}::#{key(v).to_s.upcase} => #{v}"
|
71
|
+
end.join("\n")
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def to_key(id)
|
77
|
+
return id if id.is_a?(Symbol)
|
78
|
+
row = enum_list.find {|row| row[VALUE_IDX] == id}
|
79
|
+
row.nil? ? nil : row[KEY_IDX]
|
80
|
+
end
|
81
|
+
|
82
|
+
def row_for(in_key)
|
83
|
+
key = to_key(in_key)
|
84
|
+
row = enum_list.find {|r| r[KEY_IDX] == key}
|
85
|
+
raise "No information on key [#{in_key.inspect}] in enum #{self}" unless row
|
86
|
+
row
|
87
|
+
end
|
88
|
+
|
89
|
+
def rows_for(*included)
|
90
|
+
included.flatten!
|
91
|
+
if included.empty?
|
92
|
+
# All enums
|
93
|
+
enum_list
|
94
|
+
else
|
95
|
+
# Only the specified ones
|
96
|
+
included.collect {|key| row_for(key)}.compact
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Enum
|
2
|
+
|
3
|
+
# Provides ActiveRecord-specific functionality for enum attributes
|
4
|
+
module ModelSupport
|
5
|
+
|
6
|
+
# Provide pretty output of enumerated values in console, overrides
|
7
|
+
# Rails' internal method for doing the same for AR models generally.
|
8
|
+
def attribute_for_inspect(name)
|
9
|
+
# Convert to symbol and get our current value
|
10
|
+
name = name.to_sym
|
11
|
+
val = self.send(name)
|
12
|
+
|
13
|
+
# Check to see if we're non-nil and that this attribute is an enumeration attribute
|
14
|
+
if val && self.class.enum_attr?(name)
|
15
|
+
# Get the enum for this attribute
|
16
|
+
enum = self.class.enum_for_attr(name)
|
17
|
+
# Get the key version of the value
|
18
|
+
key = enum.key(val)
|
19
|
+
# Generate our pretty version in Enum::VALUE_KEY format
|
20
|
+
"#{enum.to_s}::#{key.to_s.upcase}"
|
21
|
+
|
22
|
+
else
|
23
|
+
# Not an enum attr or nil - fall back on standard implementation
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/lib/iron/enum.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# Provides enumerated value support for use as magic constants (status flags, types, etc...)
|
2
|
+
#
|
3
|
+
# Sample usage:
|
4
|
+
#
|
5
|
+
# Enum.enable_support(:all)
|
6
|
+
# module Fruit
|
7
|
+
# enum :apple, 1
|
8
|
+
# enum :pear, 2
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# Yields:
|
12
|
+
#
|
13
|
+
# Fruit::APPLE => 1
|
14
|
+
# Fruit.name(1) => 'Apple'
|
15
|
+
# Fruit.keys => [:apple, :pear]
|
16
|
+
# etc...
|
17
|
+
#
|
18
|
+
module Enum
|
19
|
+
|
20
|
+
# Indexes into our definition list
|
21
|
+
KEY_IDX = 0
|
22
|
+
VALUE_IDX = 1
|
23
|
+
NAME_IDX = 2
|
24
|
+
|
25
|
+
# Legacy method of enum creation. Call with a set of arrays, one for each desired enum. Arrays should
|
26
|
+
# contain the parameters supported by #enum, e.g. [:key, <value>, "<optional name>"]
|
27
|
+
def define_enum(*items)
|
28
|
+
items.each do |item|
|
29
|
+
enum(*item)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Add an enumerated constant to the given module/class. The key should be a symbol, the value a fixed integer
|
34
|
+
# that the symbol represents. The name is an optional user-friendly name for the enum, which will efault to
|
35
|
+
# a capitalized version of the key.
|
36
|
+
#
|
37
|
+
# Sample usage:
|
38
|
+
#
|
39
|
+
# module HTTPCode
|
40
|
+
# enum :success, 200
|
41
|
+
# enum :missing, 404
|
42
|
+
# enum :error, 500, 'Server Error'
|
43
|
+
# end
|
44
|
+
def enum(key, value, name = nil)
|
45
|
+
# Make sure we have our enum stuff in here
|
46
|
+
self.extend(Enum::Core) unless respond_to?(:enum_list)
|
47
|
+
|
48
|
+
# Validate input
|
49
|
+
raise "Invalid enum key: #{key.inspect}" unless key.is_a?(Symbol)
|
50
|
+
raise "Invalid enum value: #{value.inspect}" unless value.is_a?(Fixnum)
|
51
|
+
raise "Invalid enum name: #{name.inspect}" unless name.nil? || name.is_a?(String)
|
52
|
+
|
53
|
+
# Set our constant
|
54
|
+
const_set(key.to_s.upcase, value)
|
55
|
+
|
56
|
+
# Ensure we have a valid name
|
57
|
+
name ||= key.to_s.split('_').collect(&:capitalize).join(' ')
|
58
|
+
|
59
|
+
# Save to our list
|
60
|
+
enum_list << [key, value, name]
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
# Require additional files
|
66
|
+
require_relative './enum/core'
|
67
|
+
require_relative './enum/attr_support'
|
68
|
+
require_relative './enum/model_support'
|
69
|
+
|
70
|
+
# Bind to Module to enable #define_enum, #enum_attr and friends
|
71
|
+
Module.send(:include, Enum)
|
72
|
+
Module.send(:include, Enum::AttrSupport)
|
73
|
+
|
74
|
+
# Add our ActiveRecord extensions if we're in Rails
|
75
|
+
if defined?(ActiveRecord)
|
76
|
+
ActiveRecord::Base.send(:include, Enum::ModelSupport)
|
77
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
describe Enum do
|
2
|
+
describe 'using attributes' do
|
3
|
+
|
4
|
+
module AttrTest
|
5
|
+
enum :first, 1
|
6
|
+
enum :second, 2
|
7
|
+
end
|
8
|
+
|
9
|
+
class AttrClass
|
10
|
+
enum_attr :pos => AttrTest
|
11
|
+
end
|
12
|
+
|
13
|
+
before do
|
14
|
+
@obj = AttrClass.new
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should support declaring enum attributes' do
|
18
|
+
Module.should respond_to(:enum_attr)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should allow getting an attribute in key form' do
|
22
|
+
@obj.pos = AttrTest::SECOND
|
23
|
+
@obj.pos_as_key.should == :second
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should allow getting an attribute in name form' do
|
27
|
+
@obj.pos = 1
|
28
|
+
@obj.pos_as_name.should == 'First'
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
describe Enum do
|
2
|
+
|
3
|
+
# Sample for use below, using old declaration syntax
|
4
|
+
class EnumTest
|
5
|
+
define_enum(
|
6
|
+
[:alpha, 5],
|
7
|
+
[:beta, 10, 'A label'],
|
8
|
+
[:gamma, 2]
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should provide #define_enum and #enum on Module' do
|
13
|
+
Module.should respond_to(:define_enum)
|
14
|
+
Module.should respond_to(:enum)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should add enums to the enum list on calling #enum' do
|
18
|
+
count = EnumTest.enum_list.count
|
19
|
+
EnumTest.enum(:epsilon, 22)
|
20
|
+
EnumTest.enum_list.count.should == count + 1
|
21
|
+
EnumTest.value(:epsilon).should == 22
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should test the validity of values' do
|
25
|
+
EnumTest.valid_value?(10).should be_true
|
26
|
+
EnumTest.valid_value?(555).should be_false
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
describe Enum do
|
2
|
+
describe 'with keys' do
|
3
|
+
|
4
|
+
module KeyTest
|
5
|
+
enum :key1, 10
|
6
|
+
enum :key2, 20
|
7
|
+
enum :key3, 5000
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should set enum keys as constants' do
|
11
|
+
KeyTest::KEY1.should == 10
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should convert values to keys' do
|
15
|
+
KeyTest.key(20).should == :key2
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should return a list of all keys' do
|
19
|
+
KeyTest.keys.should == [:key1, :key2, :key3]
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
describe Enum do
|
2
|
+
describe 'model attributes' do
|
3
|
+
|
4
|
+
module AREnum
|
5
|
+
enum :one, 1
|
6
|
+
enum :two, 2
|
7
|
+
enum :thirty_three, 33
|
8
|
+
end
|
9
|
+
|
10
|
+
module AnotherEnum
|
11
|
+
enum :yo, 10
|
12
|
+
enum :bob, 20
|
13
|
+
end
|
14
|
+
|
15
|
+
class ARTest < ActiveRecord::Base
|
16
|
+
enum_attr :enum_field => AREnum, :another_enum => AnotherEnum
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
@test = ARTest.new
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should allow setting values by key' do
|
24
|
+
@test.enum_field = :two
|
25
|
+
@test.enum_field.should == 2
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should allow testing for a given value via method call' do
|
29
|
+
@test.enum_field = AREnum::ONE
|
30
|
+
@test.enum_field_one?.should be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should allow setting a field to a value via method call' do
|
34
|
+
@test.enum_field_two!
|
35
|
+
@test.enum_field.should == 2
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should show enum values in inspect as full definition' do
|
39
|
+
@test.enum_field = :two
|
40
|
+
@test.inspect.should match(/AREnum::TWO/)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should define a with_<enum field> scope' do
|
44
|
+
ARTest.should respond_to(:with_enum_field)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should find models with the provided scope' do
|
48
|
+
ARTest.delete_all
|
49
|
+
ARTest.create!(:enum_field => :two)
|
50
|
+
ARTest.create!(:enum_field => :two)
|
51
|
+
ARTest.with_enum_field(2).count.should == 2
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should support multiple values in the automatic scope' do
|
55
|
+
ARTest.delete_all
|
56
|
+
ARTest.create!(:enum_field => :two)
|
57
|
+
ARTest.create!(:enum_field => 33)
|
58
|
+
ARTest.with_enum_field(2, :thirty_three).count.should == 2
|
59
|
+
ARTest.with_enum_field([2, :thirty_three]).count.should == 2
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should return no models for empty scope' do
|
63
|
+
ARTest.delete_all
|
64
|
+
ARTest.create!(:enum_field => nil)
|
65
|
+
ARTest.create!(:enum_field => 2)
|
66
|
+
ARTest.with_enum_field([]).count.should == 0
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should return models with null values for nil scope' do
|
70
|
+
ARTest.delete_all
|
71
|
+
ARTest.with_enum_field(nil).count.should == 0
|
72
|
+
ARTest.create!(:enum_field => nil)
|
73
|
+
ARTest.create!(:enum_field => 2)
|
74
|
+
ARTest.create!(:enum_field => 2)
|
75
|
+
ARTest.with_enum_field(nil).count.should == 1
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
describe Enum do
|
2
|
+
describe 'using names' do
|
3
|
+
|
4
|
+
# Sample for use below
|
5
|
+
module NameTest
|
6
|
+
enum :a_long_key, 1
|
7
|
+
enum :custom_name, 2, 'Wahoo'
|
8
|
+
enum :singleton, 3
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should return a name from a value' do
|
12
|
+
NameTest.name(3).should == 'Singleton'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should return all names in order' do
|
16
|
+
NameTest.names.should == ['A Long Key', 'Wahoo', 'Singleton']
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should return a set of names from a set of keys or values' do
|
20
|
+
NameTest.names(2, 1, :singleton).should == ['Wahoo', 'A Long Key', 'Singleton']
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should return nil for the name of nil' do
|
24
|
+
NameTest.name(nil).should be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should keep normal Module#name behavior' do
|
28
|
+
NameTest.name.should == 'NameTest'
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
describe Enum do
|
2
|
+
describe 'using options' do
|
3
|
+
|
4
|
+
# Sample for use below
|
5
|
+
module OptionTest
|
6
|
+
enum :alpha, 5
|
7
|
+
enum :beta, 10
|
8
|
+
enum :gamma, 20, 'Monkeys'
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should return name + values as options array' do
|
12
|
+
OptionTest.options.should == [['Alpha', 5], ['Beta', 10], ['Monkeys', 20]]
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should enable getting options array subset' do
|
16
|
+
OptionTest.options(:gamma, :beta).should == [['Monkeys', 20], ['Beta', 10]]
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
describe Enum do
|
2
|
+
describe 'using values' do
|
3
|
+
|
4
|
+
# Sample for use below
|
5
|
+
module ValueTest
|
6
|
+
enum :alpha, 5
|
7
|
+
enum :beta, 10, 'a label'
|
8
|
+
enum :gamma, 2
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should return a value as that value' do
|
12
|
+
ValueTest.value(5).should == 5
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should convert keys to values' do
|
16
|
+
ValueTest.value(:beta).should == 10
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should return nil for the value of nil' do
|
20
|
+
EnumTest.value(nil).should be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should return all values' do
|
24
|
+
ValueTest.values.should == [5, 10, 2]
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should return select values' do
|
28
|
+
ValueTest.values(:alpha, :gamma).should == [5, 2]
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Set up activerecord & in-memory SQLite DB
|
2
|
+
require 'active_record'
|
3
|
+
require 'sqlite3'
|
4
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
5
|
+
|
6
|
+
# Run a migration to create our test table
|
7
|
+
ActiveRecord::Migration.create_table :ar_tests do |t|
|
8
|
+
t.integer 'enum_field'
|
9
|
+
t.integer 'another_enum'
|
10
|
+
end
|
11
|
+
|
12
|
+
# Require our library
|
13
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'iron', 'enum'))
|
14
|
+
|
15
|
+
# Config RSpec options
|
16
|
+
RSpec.configure do |config|
|
17
|
+
config.add_formatter 'documentation'
|
18
|
+
config.color = true
|
19
|
+
config.backtrace_clean_patterns = [/rspec/]
|
20
|
+
end
|
21
|
+
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: iron-enum
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Rob Morris
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.6'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.6'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: active_record
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '3.0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '3.0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: sqlite3
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.3'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
description: Adds enumerated constant value support to Ruby and Rails projects
|
63
|
+
email:
|
64
|
+
- rob@irongaze.com
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- lib/iron/enum/attr_support.rb
|
70
|
+
- lib/iron/enum/core.rb
|
71
|
+
- lib/iron/enum/model_support.rb
|
72
|
+
- lib/iron/enum.rb
|
73
|
+
- spec/enum/attr_spec.rb
|
74
|
+
- spec/enum/enum_spec.rb
|
75
|
+
- spec/enum/key_spec.rb
|
76
|
+
- spec/enum/model_spec.rb
|
77
|
+
- spec/enum/name_spec.rb
|
78
|
+
- spec/enum/option_spec.rb
|
79
|
+
- spec/enum/value_spec.rb
|
80
|
+
- spec/spec_helper.rb
|
81
|
+
- LICENSE
|
82
|
+
- History.txt
|
83
|
+
- Version.txt
|
84
|
+
- README.rdoc
|
85
|
+
- .rspec
|
86
|
+
homepage: http://irongaze.com
|
87
|
+
licenses:
|
88
|
+
- MIT
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 1.9.2
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.8.24
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: Enum support for Ruby and Rails
|
111
|
+
test_files: []
|