enum_id 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/Gemfile +8 -0
- data/Gemfile.lock +27 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +82 -0
- data/Rakefile +46 -0
- data/TODO +1 -0
- data/VERSION +1 -0
- data/init.rb +5 -0
- data/lib/enum_id.rb +99 -0
- metadata +124 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.8.3)
|
6
|
+
bundler (~> 1.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
rdoc
|
10
|
+
json (1.6.6)
|
11
|
+
rake (0.9.2.2)
|
12
|
+
rdoc (3.12)
|
13
|
+
json (~> 1.4)
|
14
|
+
shoulda (3.0.1)
|
15
|
+
shoulda-context (~> 1.0.0)
|
16
|
+
shoulda-matchers (~> 1.0.0)
|
17
|
+
shoulda-context (1.0.0)
|
18
|
+
shoulda-matchers (1.0.0)
|
19
|
+
|
20
|
+
PLATFORMS
|
21
|
+
ruby
|
22
|
+
|
23
|
+
DEPENDENCIES
|
24
|
+
bundler (~> 1)
|
25
|
+
jeweler (~> 1.8.3)
|
26
|
+
rdoc (~> 3.12)
|
27
|
+
shoulda
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Javier Goizueta
|
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
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
=enum_id
|
2
|
+
|
3
|
+
Defines an enumerated field (stored as an integral id).
|
4
|
+
The field is defined by its name (which must be the column name without the _id suffix),
|
5
|
+
and a hash which maps the id valid values of the field to symbolic constants.
|
6
|
+
The hash can also contain options with symbolic keys; currently the only valid option is
|
7
|
+
:required which checks for non-nil values at validation; if a value other than true is
|
8
|
+
assigned to it, it should be a hash with options that will be relayed to validates_presence_of
|
9
|
+
|
10
|
+
Example: (we assume that the table for X has an integer column named 'status_id')
|
11
|
+
|
12
|
+
class X < ActiveRecord::Base
|
13
|
+
enum_id :status, 1=>:first, 2=>:second, 3=>:third, :required=>true
|
14
|
+
end
|
15
|
+
|
16
|
+
This is equivalent to:
|
17
|
+
|
18
|
+
class X < ActiveRecord::Base
|
19
|
+
# Return the symbolic status value
|
20
|
+
def status
|
21
|
+
X.status(status_id)
|
22
|
+
end
|
23
|
+
# Assigns the symbolic status value and also accepts status ids
|
24
|
+
def status=(st)
|
25
|
+
self.status_id = X.status_id(st)
|
26
|
+
end
|
27
|
+
# Returns the status description (must be provided as a translation)
|
28
|
+
def status_name
|
29
|
+
X.status_name(status_id)
|
30
|
+
end
|
31
|
+
ENUM_ID_status_SYMBOLS = {1=>:first, 2=>:second, 3=>:third}
|
32
|
+
ENUM_ID_status_IDS = {:first=>1, :second=>2, :third=>3}
|
33
|
+
# Return the symbolic status for a status id
|
34
|
+
def X.status(id)
|
35
|
+
id && (ENUM_ID_status_SYMBOLS[id.to_i] || raise("Invalid status id: #{id}"))
|
36
|
+
end
|
37
|
+
# Return the status id for a symbolic status (or status id)
|
38
|
+
def X.status_id(st)
|
39
|
+
st && if st.kind_of?(Integer)
|
40
|
+
raise "Invalid status id: #{st}" unless X.status_ids.include?(st)
|
41
|
+
st
|
42
|
+
elsif st.kind_of?(Symbol)
|
43
|
+
ENUM_ID_status_IDS[st.to_sym] || raise("Invalid status: #{st.inspect}")
|
44
|
+
else
|
45
|
+
raise TypeError,"Integer or Symbol argument expected (got a #{st.class.name})."
|
46
|
+
end
|
47
|
+
end
|
48
|
+
# Return the symbolic status given a status symbol or id
|
49
|
+
def X.status_symbol(st)
|
50
|
+
st && (st.kind_of?(Integer) ? status(st) : st.to_sym)
|
51
|
+
end
|
52
|
+
# Return the description of a status symbol or id
|
53
|
+
def X.status_name(st)
|
54
|
+
st = status_symbol(st)
|
55
|
+
st && I18n.t("enum_id.x.status.#{st}")
|
56
|
+
end
|
57
|
+
# Return all the valid status ids in an Array [1,2,3]
|
58
|
+
def X.status_ids
|
59
|
+
ENUM_ID_status_SYMBOLS.keys.sort
|
60
|
+
end
|
61
|
+
# Return all the valid status symbols in an Array: [:first, :second, :third]
|
62
|
+
def X.status_symbols
|
63
|
+
status_ids.map{|id| status_symbol(id)}
|
64
|
+
end
|
65
|
+
# Define accessors for all status values: first?, second?, third?
|
66
|
+
X.status_symbols.each do |stat|
|
67
|
+
define_method :"#{stat}?" do
|
68
|
+
status == :"#{stat}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
# Define validations
|
72
|
+
validates_inclusion_of :status_id, :in=>X.status_ids
|
73
|
+
end
|
74
|
+
|
75
|
+
To use the _name methods we'd need to add this to config/locales/en.yml (and any other required languages):
|
76
|
+
|
77
|
+
enum_id:
|
78
|
+
x:
|
79
|
+
status:
|
80
|
+
first: "Description of first status"
|
81
|
+
second: "Description of second status"
|
82
|
+
third: "Description of third status"
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "enum_id"
|
18
|
+
gem.homepage = "http://github.com/jgoizueta/enum_id"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Enumerated ActiveRecord fields }
|
21
|
+
gem.description = %Q{Enumerated ActiveRecord fields }
|
22
|
+
gem.email = "jgoizueta@gmail.com"
|
23
|
+
gem.authors = ["Javier Goizueta"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
task :default => :test
|
37
|
+
|
38
|
+
require 'rdoc/task'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "enum_id #{version}"
|
44
|
+
rdoc.rdoc_files.include('README*')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/init.rb
ADDED
data/lib/enum_id.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# Defines an enumerated field (stored as an integral id).
|
2
|
+
# The field is defined by its name (which must be the column name without the _id suffix),
|
3
|
+
# and a hash which maps the id valid values of the field to symbolic constants.
|
4
|
+
# The hash can also contain options with symbolic keys; currently the only valid option is
|
5
|
+
# :required which checks for non-nil values at validation; if a value other than true is
|
6
|
+
# assigned to it, it should be a hash with options that will be relayed to validates_presence_of
|
7
|
+
module EnumId
|
8
|
+
|
9
|
+
def enum_id(name, options_and_enum_values)
|
10
|
+
options_and_enum_values = options_and_enum_values.group_by{|k,v| k.kind_of?(Integer) ? :values : :options}
|
11
|
+
options = (options_and_enum_values[:options]||[]).to_h
|
12
|
+
symbols_map = (options_and_enum_values[:values]||[]).to_h
|
13
|
+
ids_map = symbols_map.invert
|
14
|
+
|
15
|
+
required = options[:required]
|
16
|
+
|
17
|
+
name_id = :"#{name}_id"
|
18
|
+
symbols_const = :"ENUM_ID_#{name}_SYMBOLS"
|
19
|
+
ids_const = :"ENUM_ID_#{name}_IDS"
|
20
|
+
|
21
|
+
const_set symbols_const, symbols_map
|
22
|
+
const_set ids_const, ids_map
|
23
|
+
|
24
|
+
model_class = self
|
25
|
+
|
26
|
+
# Instance methods
|
27
|
+
|
28
|
+
# Access the enumerated value as a symbol.
|
29
|
+
define_method name do
|
30
|
+
# #{model_class.name}.#{name}(#{name}_id)
|
31
|
+
model_class.send name, self.send(name_id)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Assigns the enumerated value as a symbol or id (integer)
|
35
|
+
define_method :"#{name}=" do |st|
|
36
|
+
# self.#{name}_id = #{model_class.name}.#{name}_id(st)
|
37
|
+
self.send :"#{name_id}=", model_class.send(name_id, st)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Access the human-name of the (symbolic or integral id) value (translated)
|
41
|
+
define_method :"#{name}_name" do
|
42
|
+
# #{model_class.name}.#{name}_name(#{name}_id)
|
43
|
+
model_class.send :"#{name}_name", self.send(name_id)
|
44
|
+
end
|
45
|
+
|
46
|
+
symbols_map.values.each do |stat|
|
47
|
+
define_method :"#{stat}?" do
|
48
|
+
send(name) == stat
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Class methods
|
53
|
+
|
54
|
+
model_metaclass = class << model_class; self; end
|
55
|
+
model_metaclass.instance_eval do
|
56
|
+
define_method name do |id|
|
57
|
+
# id && (#{symbols_const}[id.to_i] || raise("Invalid status id: #{id}"))
|
58
|
+
id && (symbols_map[id.to_i] || raise("Invalid #{name} id: #{id}"))
|
59
|
+
end
|
60
|
+
|
61
|
+
define_method name_id do |st|
|
62
|
+
st && if st.kind_of?(Integer)
|
63
|
+
raise "Invalid #{name} id: #{st}" unless send(:"#{name}_ids").include?(st)
|
64
|
+
st
|
65
|
+
elsif st.kind_of?(Symbol)
|
66
|
+
ids_map[st.to_sym] || raise("Invalid #{name}: #{st.inspect}")
|
67
|
+
else
|
68
|
+
raise TypeError,"Integer or Symbol argument expected (got a #{st.class.name})."
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
define_method :"#{name}_symbol" do |st|
|
73
|
+
st && (st.kind_of?(Integer) ? send(name, st) : st.to_sym)
|
74
|
+
end
|
75
|
+
|
76
|
+
define_method :"#{name}_name" do |st|
|
77
|
+
st = send(:"#{name}_symbol", st)
|
78
|
+
st && I18n.t("enum_id.#{model_class.name.underscore}.#{name}.#{st}")
|
79
|
+
end
|
80
|
+
|
81
|
+
define_method :"#{name}_ids" do
|
82
|
+
symbols_map.keys.sort
|
83
|
+
end
|
84
|
+
|
85
|
+
define_method :"#{name}_symbols" do
|
86
|
+
send(:"#{name}_ids").map{|id| send(:"#{name}_symbol", id)}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Define validations
|
91
|
+
if required == true
|
92
|
+
validates_inclusion_of name_id, :in=>model_class.send(:"#{name}_ids")
|
93
|
+
else
|
94
|
+
validates_inclusion_of name_id, :in=>model_class.send(:"#{name}_ids")+[nil]
|
95
|
+
validates_presence_of name_id, required if required
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: enum_id
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Javier Goizueta
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: shoulda
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
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: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rdoc
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '3.12'
|
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.12'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: bundler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1'
|
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'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: jeweler
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.8.3
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.8.3
|
78
|
+
description: ! 'Enumerated ActiveRecord fields '
|
79
|
+
email: jgoizueta@gmail.com
|
80
|
+
executables: []
|
81
|
+
extensions: []
|
82
|
+
extra_rdoc_files:
|
83
|
+
- LICENSE.txt
|
84
|
+
- README.rdoc
|
85
|
+
- TODO
|
86
|
+
files:
|
87
|
+
- Gemfile
|
88
|
+
- Gemfile.lock
|
89
|
+
- LICENSE.txt
|
90
|
+
- README.rdoc
|
91
|
+
- Rakefile
|
92
|
+
- TODO
|
93
|
+
- VERSION
|
94
|
+
- init.rb
|
95
|
+
- lib/enum_id.rb
|
96
|
+
homepage: http://github.com/jgoizueta/enum_id
|
97
|
+
licenses:
|
98
|
+
- MIT
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
segments:
|
110
|
+
- 0
|
111
|
+
hash: 2693429870970939883
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
requirements: []
|
119
|
+
rubyforge_project:
|
120
|
+
rubygems_version: 1.8.21
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: Enumerated ActiveRecord fields
|
124
|
+
test_files: []
|