iron-enum 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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: []
|