enumerated_attribute 0.2.7
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/.gitignore +16 -0
- data/CHANGELOG.rdoc +49 -0
- data/LICENSE +20 -0
- data/README.rdoc +555 -0
- data/Rakefile +104 -0
- data/init.rb +1 -0
- data/lib/enumerated_attribute.rb +24 -0
- data/lib/enumerated_attribute/attribute.rb +78 -0
- data/lib/enumerated_attribute/attribute/arguments.rb +48 -0
- data/lib/enumerated_attribute/attribute/attribute_descriptor.rb +51 -0
- data/lib/enumerated_attribute/attribute/class_methods.rb +42 -0
- data/lib/enumerated_attribute/attribute/instance_methods.rb +96 -0
- data/lib/enumerated_attribute/integrations.rb +33 -0
- data/lib/enumerated_attribute/integrations/active_record.rb +109 -0
- data/lib/enumerated_attribute/integrations/datamapper.rb +6 -0
- data/lib/enumerated_attribute/integrations/default.rb +25 -0
- data/lib/enumerated_attribute/integrations/object.rb +47 -0
- data/lib/enumerated_attribute/method_definition_dsl.rb +142 -0
- data/lib/enumerated_attribute/rails_helpers.rb +97 -0
- data/lib/jeffp-enumerated_attribute.rb +1 -0
- data/spec/active_record/active_record_spec.rb +363 -0
- data/spec/active_record/association_test_classes.rb +40 -0
- data/spec/active_record/associations_spec.rb +130 -0
- data/spec/active_record/cfg.rb +6 -0
- data/spec/active_record/inheritance_classes.rb +19 -0
- data/spec/active_record/inheritance_spec.rb +60 -0
- data/spec/active_record/race_car.rb +15 -0
- data/spec/active_record/single_table_inheritance_spec.rb +0 -0
- data/spec/active_record/sti_classes.rb +10 -0
- data/spec/active_record/sti_spec.rb +41 -0
- data/spec/active_record/test_in_memory.rb +71 -0
- data/spec/car.rb +67 -0
- data/spec/cfg.rb +8 -0
- data/spec/inheritance_classes.rb +16 -0
- data/spec/inheritance_spec.rb +80 -0
- data/spec/new_and_method_missing_spec.rb +73 -0
- data/spec/plural.rb +8 -0
- data/spec/poro_spec.rb +397 -0
- data/spec/rails/README +243 -0
- data/spec/rails/Rakefile +10 -0
- data/spec/rails/app/controllers/application_controller.rb +10 -0
- data/spec/rails/app/controllers/form_test_controller.rb +38 -0
- data/spec/rails/app/helpers/application_helper.rb +3 -0
- data/spec/rails/app/helpers/form_test_helper.rb +2 -0
- data/spec/rails/app/models/user.rb +9 -0
- data/spec/rails/app/views/form_test/form.html.erb +1 -0
- data/spec/rails/app/views/form_test/form_for.html.erb +10 -0
- data/spec/rails/app/views/form_test/form_tag.html.erb +9 -0
- data/spec/rails/app/views/form_test/index.html.erb +6 -0
- data/spec/rails/app/views/layouts/application.html.erb +11 -0
- data/spec/rails/config/boot.rb +110 -0
- data/spec/rails/config/database.yml +22 -0
- data/spec/rails/config/environment.rb +45 -0
- data/spec/rails/config/environments/development.rb +17 -0
- data/spec/rails/config/environments/production.rb +28 -0
- data/spec/rails/config/environments/test.rb +28 -0
- data/spec/rails/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails/config/initializers/inflections.rb +10 -0
- data/spec/rails/config/initializers/mime_types.rb +5 -0
- data/spec/rails/config/initializers/new_rails_defaults.rb +19 -0
- data/spec/rails/config/initializers/session_store.rb +15 -0
- data/spec/rails/config/locales/en.yml +5 -0
- data/spec/rails/config/routes.rb +43 -0
- data/spec/rails/db/development.sqlite3 +0 -0
- data/spec/rails/db/migrate/20090804230221_create_sessions.rb +16 -0
- data/spec/rails/db/migrate/20090804230546_create_users.rb +21 -0
- data/spec/rails/db/schema.rb +35 -0
- data/spec/rails/db/test.sqlite3 +0 -0
- data/spec/rails/public/404.html +30 -0
- data/spec/rails/public/422.html +30 -0
- data/spec/rails/public/500.html +30 -0
- data/spec/rails/public/favicon.ico +0 -0
- data/spec/rails/public/images/rails.png +0 -0
- data/spec/rails/public/index.html +275 -0
- data/spec/rails/public/javascripts/application.js +2 -0
- data/spec/rails/public/javascripts/controls.js +963 -0
- data/spec/rails/public/javascripts/dragdrop.js +973 -0
- data/spec/rails/public/javascripts/effects.js +1128 -0
- data/spec/rails/public/javascripts/prototype.js +4320 -0
- data/spec/rails/public/robots.txt +5 -0
- data/spec/rails/public/stylesheets/scaffold.css +54 -0
- data/spec/rails/script/about +4 -0
- data/spec/rails/script/autospec +6 -0
- data/spec/rails/script/console +3 -0
- data/spec/rails/script/dbconsole +3 -0
- data/spec/rails/script/destroy +3 -0
- data/spec/rails/script/generate +3 -0
- data/spec/rails/script/performance/benchmarker +3 -0
- data/spec/rails/script/performance/profiler +3 -0
- data/spec/rails/script/plugin +3 -0
- data/spec/rails/script/runner +3 -0
- data/spec/rails/script/server +3 -0
- data/spec/rails/script/spec +10 -0
- data/spec/rails/script/spec_server +9 -0
- data/spec/rails/spec/controllers/form_test_controller_spec.rb +41 -0
- data/spec/rails/spec/integrations/enum_select_spec.rb +75 -0
- data/spec/rails/spec/matchers.rb +12 -0
- data/spec/rails/spec/rcov.opts +2 -0
- data/spec/rails/spec/spec.opts +4 -0
- data/spec/rails/spec/spec_helper.rb +40 -0
- data/spec/rails/spec/views/form_test/form.html.erb_spec.rb +12 -0
- data/spec/rails/spec/views/form_test/form_for.html.erb_spec.rb +12 -0
- data/spec/rails/spec/views/form_test/form_tag.html.erb_spec.rb +12 -0
- data/spec/rcov.opts +2 -0
- data/spec/spec.opts +4 -0
- data/spec/tractor.rb +48 -0
- metadata +182 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#require 'rake/testtask'
|
|
2
|
+
require 'rake/rdoctask'
|
|
3
|
+
require 'rake/gempackagetask'
|
|
4
|
+
require 'rake/contrib/sshpublisher'
|
|
5
|
+
require 'gem_version'
|
|
6
|
+
|
|
7
|
+
spec = Gem::Specification.new do |s|
|
|
8
|
+
s.name = 'enumerated_attribute'
|
|
9
|
+
s.version = GemVersion.next_version
|
|
10
|
+
s.platform = Gem::Platform::RUBY
|
|
11
|
+
s.description = 'Enumerated model attributes and view helpers'
|
|
12
|
+
s.summary = 'Add enumerated attributes to your models and expose them in drop-down lists in your views'
|
|
13
|
+
|
|
14
|
+
s.add_dependency('meta_programming', '>= 0.2.1')
|
|
15
|
+
|
|
16
|
+
exclude_folders = 'spec/rails/{doc,lib,log,nbproject,tmp,vendor,test}'
|
|
17
|
+
exclude_files = FileList['**/*.log'] + FileList[exclude_folders+'/**/*'] + FileList[exclude_folders]
|
|
18
|
+
s.files = FileList['{examples,lib,tasks,spec}/**/*'] + %w(CHANGELOG.rdoc init.rb LICENSE Rakefile README.rdoc .gitignore) - exclude_files
|
|
19
|
+
s.require_path = 'lib'
|
|
20
|
+
s.has_rdoc = true
|
|
21
|
+
s.test_files = Dir['spec/*_spec.rb']
|
|
22
|
+
|
|
23
|
+
s.author = 'Jeff Patmon'
|
|
24
|
+
s.email = 'jpatmon@gmail.com'
|
|
25
|
+
s.homepage = 'http://github.com/jeffp/enumerated_attribute/tree/master'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
require 'spec/version'
|
|
29
|
+
require 'spec/rake/spectask'
|
|
30
|
+
|
|
31
|
+
desc "Run specs"
|
|
32
|
+
|
|
33
|
+
namespace :spec do
|
|
34
|
+
task :default=>:all
|
|
35
|
+
Spec::Rake::SpecTask.new(:object) do |t|
|
|
36
|
+
t.spec_files = FileList['spec/*_spec.rb']
|
|
37
|
+
t.libs << 'lib' << 'spec'
|
|
38
|
+
t.rcov = false
|
|
39
|
+
t.spec_opts = ['--options', 'spec/spec.opts']
|
|
40
|
+
#t.rcov_dir = 'coverage'
|
|
41
|
+
#t.rcov_opts = ['--exclude', "kernel,load-diff-lcs\.rb,instance_exec\.rb,lib/spec.rb,lib/spec/runner.rb,^spec/*,bin/spec,examples,/gems,/Library/Ruby,\.autotest,#{ENV['GEM_HOME']}"]
|
|
42
|
+
end
|
|
43
|
+
=begin
|
|
44
|
+
Spec::Rake::SpecTask.new(:sub) do |t|
|
|
45
|
+
t.spec_files = FileList['spec/inheritance_spec.rb']
|
|
46
|
+
t.libs << 'lib' << 'spec'
|
|
47
|
+
t.rcov = false
|
|
48
|
+
t.spec_opts = ['--options', 'spec/spec.opts']
|
|
49
|
+
end
|
|
50
|
+
Spec::Rake::SpecTask.new(:poro) do |t|
|
|
51
|
+
t.spec_files = FileList['spec/poro_spec.rb']
|
|
52
|
+
t.libs << 'lib' << 'spec'
|
|
53
|
+
t.rcov = false
|
|
54
|
+
t.spec_opts = ['--options', 'spec/spec.opts']
|
|
55
|
+
end
|
|
56
|
+
=end
|
|
57
|
+
desc "Run ActiveRecord integration specs"
|
|
58
|
+
Spec::Rake::SpecTask.new(:ar) do |t|
|
|
59
|
+
t.spec_files = FileList['spec/active_record/*_spec.rb']
|
|
60
|
+
t.libs << 'lib' << 'spec/active_record'
|
|
61
|
+
t.spec_opts = ['--options', 'spec/spec.opts']
|
|
62
|
+
t.rcov = false
|
|
63
|
+
end
|
|
64
|
+
Spec::Rake::SpecTask.new(:forms) do |t|
|
|
65
|
+
t.spec_files = FileList['spec/rails/spec/integrations/*_spec.rb']
|
|
66
|
+
t.libs << 'lib' << 'spec/rails/spec'
|
|
67
|
+
t.spec_opts = ['--options', 'spec/spec.opts']
|
|
68
|
+
t.rcov = false
|
|
69
|
+
end
|
|
70
|
+
# Spec::Rake::SpecTask.new(:associations) do |t|
|
|
71
|
+
# t.spec_files = FileList['spec/active_record/associations_spec.rb']
|
|
72
|
+
# t.libs << 'lib' << 'spec/active_record'
|
|
73
|
+
# t.rcov = false
|
|
74
|
+
# end
|
|
75
|
+
desc "Run all specs"
|
|
76
|
+
task :all=>[:object, :ar, :forms]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
desc "Generate documentation for the #{spec.name} plugin."
|
|
81
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
82
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
83
|
+
rdoc.title = spec.name
|
|
84
|
+
#rdoc.template = '../rdoc_template.rb'
|
|
85
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
|
86
|
+
rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'LICENSE', 'lib/**/*.rb')
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
desc 'Generate a gemspec file.'
|
|
90
|
+
task :gemspec do
|
|
91
|
+
File.open("#{spec.name}.gemspec", 'w') do |f|
|
|
92
|
+
f.write spec.to_ruby
|
|
93
|
+
end
|
|
94
|
+
GemVersion.increment_version
|
|
95
|
+
GemVersion.commit_and_push
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
Rake::GemPackageTask.new(spec) do |p|
|
|
99
|
+
p.gem_spec = spec
|
|
100
|
+
p.need_tar = RUBY_PLATFORM =~ /mswin/ ? false : true
|
|
101
|
+
p.need_zip = true
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
Dir['tasks/**/*.rake'].each {|rake| load rake}
|
data/init.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'enumerated_attribute'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
gem 'meta_programming', '>= 0.2.0'
|
|
2
|
+
require 'meta_programming'
|
|
3
|
+
require 'enumerated_attribute/attribute'
|
|
4
|
+
|
|
5
|
+
module EnumeratedAttribute
|
|
6
|
+
|
|
7
|
+
module MacroMethods
|
|
8
|
+
|
|
9
|
+
def enumerated_attribute(*args, &block)
|
|
10
|
+
class << self
|
|
11
|
+
include EnumeratedAttribute::Attribute
|
|
12
|
+
end
|
|
13
|
+
create_enumerated_attribute(*args, &block)
|
|
14
|
+
end
|
|
15
|
+
alias_method :enum_attr, :enumerated_attribute
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Class.class_eval do
|
|
22
|
+
include EnumeratedAttribute::MacroMethods
|
|
23
|
+
end
|
|
24
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'enumerated_attribute/attribute/attribute_descriptor'
|
|
2
|
+
require 'enumerated_attribute/attribute/arguments'
|
|
3
|
+
require 'enumerated_attribute/attribute/instance_methods'
|
|
4
|
+
require 'enumerated_attribute/attribute/class_methods'
|
|
5
|
+
require 'enumerated_attribute/method_definition_dsl'
|
|
6
|
+
require 'enumerated_attribute/integrations'
|
|
7
|
+
require 'enumerated_attribute/rails_helpers'
|
|
8
|
+
require 'ostruct'
|
|
9
|
+
|
|
10
|
+
module EnumeratedAttribute
|
|
11
|
+
|
|
12
|
+
class EnumeratedAttributeError < StandardError; end
|
|
13
|
+
class IntegrationError < EnumeratedAttributeError; end
|
|
14
|
+
class InvalidEnumeration < EnumeratedAttributeError; end
|
|
15
|
+
class InvalidDefinition < EnumeratedAttributeError; end
|
|
16
|
+
class AmbiguousMethod < EnumeratedAttributeError; end
|
|
17
|
+
|
|
18
|
+
module Attribute
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def create_enumerated_attribute(*args, &block)
|
|
22
|
+
return if args.empty?
|
|
23
|
+
config = Arguments.parse_enum_attr_arguments(args)
|
|
24
|
+
|
|
25
|
+
class_eval do
|
|
26
|
+
@enumerated_attributes ||= {}
|
|
27
|
+
@enumerated_attributes[config.attr_symbol] = AttributeDescriptor.new(config.attr_symbol, config.enums, config.opts)
|
|
28
|
+
|
|
29
|
+
unless @integration_map
|
|
30
|
+
@integration_map = Integrations.find_integration_map(self)
|
|
31
|
+
@integration_map[:aliasing].each do |p|
|
|
32
|
+
alias_method(p.first, p.last)
|
|
33
|
+
end
|
|
34
|
+
include(EnumeratedAttribute::Integrations::Default)
|
|
35
|
+
include(@integration_map[:module]) if @integration_map[:module]
|
|
36
|
+
|
|
37
|
+
self.extend ClassMethods
|
|
38
|
+
include InstanceMethods
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
#create accessors
|
|
43
|
+
define_enumerated_attribute_reader_method(config.attr_symbol) unless (config.opts.key?(:reader) && !config.opts[:reader])
|
|
44
|
+
define_enumerated_attribute_writer_method(config.attr_symbol) unless (config.opts.key?(:writer) && !config.opts[:writer])
|
|
45
|
+
define_enumerated_attribute_new_method
|
|
46
|
+
|
|
47
|
+
#create state and action methods from block
|
|
48
|
+
config.initial_value = config.opts[:init] || config.initial_value
|
|
49
|
+
if block_given?
|
|
50
|
+
m = EnumeratedAttribute::MethodDefinitionDSL.new(self, self.enumerated_attributes(false)[config.attr_symbol]) #attr_name, enums)
|
|
51
|
+
m.instance_eval(&block)
|
|
52
|
+
config.initial_value = m.initial_value || config.initial_value
|
|
53
|
+
config.plural_name = m.pluralized_name || config.plural_name
|
|
54
|
+
config.decrementor = m.decrementor_name || config.decrementor
|
|
55
|
+
config.incrementor = m.incrementor_name || config.incrementor
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#define the enum values accessor
|
|
59
|
+
class_eval do
|
|
60
|
+
@enumerated_attributes ||={}
|
|
61
|
+
@enumerated_attributes[config.attr_symbol].init_value = config.initial_value if config.initial_value
|
|
62
|
+
|
|
63
|
+
define_method(config.plural_name.to_sym) { self.class.enumerated_attributes[config.attr_symbol]}
|
|
64
|
+
define_method(config.incrementor.to_sym) do
|
|
65
|
+
z = self.class.enumerated_attributes[config.attr_symbol].enums
|
|
66
|
+
index = z.index(read_enumerated_attribute(config.attr_symbol))
|
|
67
|
+
write_enumerated_attribute(config.attr_symbol, z[index >= z.size-1 ? 0 : index+1])
|
|
68
|
+
end
|
|
69
|
+
define_method(config.decrementor.to_sym) do
|
|
70
|
+
z = self.class.enumerated_attributes[config.attr_symbol].enums
|
|
71
|
+
index = z.index(read_enumerated_attribute(config.attr_symbol))
|
|
72
|
+
write_enumerated_attribute(config.attr_symbol, z[index > 0 ? index-1 : z.size-1])
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module EnumeratedAttribute
|
|
2
|
+
module Attribute
|
|
3
|
+
module Arguments
|
|
4
|
+
def self.validate_enum_attr_arguments(config)
|
|
5
|
+
raise(InvalidDefinition, 'second argument of enumerated_attribute/enum_attr is not an array of symbols or strings representing the enum values', caller) if config.enums.empty?
|
|
6
|
+
end
|
|
7
|
+
def self.init_incrementor_decrementor_method_names(config)
|
|
8
|
+
config.incrementor = config.opts[:incrementor] || config.opts[:inc] || "#{config.attr_name}_next"
|
|
9
|
+
config.decrementor = config.opts[:decrementor] || config.opts[:dec] || "#{config.attr_name}_previous"
|
|
10
|
+
end
|
|
11
|
+
def self.init_plural_name(config)
|
|
12
|
+
config.plural_name = config.opts[:plural] || config.opts[:enums_accessor] || config.opts[:enums] || begin
|
|
13
|
+
case
|
|
14
|
+
when config.attr_name =~ /[aeiou]y$/
|
|
15
|
+
"#{config.attr_name}s"
|
|
16
|
+
when config.attr_name =~ /y$/
|
|
17
|
+
config.attr_name.sub(/y$/, 'ies')
|
|
18
|
+
when config.attr_name =~ /(sh|ch|x|s)$/
|
|
19
|
+
"#{config.attr_name}es"
|
|
20
|
+
else
|
|
21
|
+
"#{config.attr_name}s"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
def self.process_enums_for_initial_value(config)
|
|
26
|
+
config.initial_value = nil
|
|
27
|
+
config.enums = config.enums.map{|v| (v =~ /^\^/ ? (config.initial_value ||= v[1, v.length-1].to_sym) : v.to_sym )}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.parse_enum_attr_arguments(args)
|
|
31
|
+
config = OpenStruct.new
|
|
32
|
+
config.attr_name = args[0].to_s
|
|
33
|
+
config.attr_symbol = config.attr_name.to_sym
|
|
34
|
+
config.enums = (args[1] && args[1].is_a?(Array) ? args[1] : [])
|
|
35
|
+
index = config.enums.empty? ? 1 : 2
|
|
36
|
+
config.opts = (args[index] && args[index].is_a?(Hash) ? args[index] : {})
|
|
37
|
+
|
|
38
|
+
validate_enum_attr_arguments(config)
|
|
39
|
+
init_plural_name(config)
|
|
40
|
+
init_incrementor_decrementor_method_names(config)
|
|
41
|
+
process_enums_for_initial_value(config)
|
|
42
|
+
|
|
43
|
+
config
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
|
|
2
|
+
module EnumeratedAttribute
|
|
3
|
+
module Attribute
|
|
4
|
+
class AttributeDescriptor < Array
|
|
5
|
+
attr_reader :name
|
|
6
|
+
attr_accessor :init_value
|
|
7
|
+
|
|
8
|
+
def initialize(name, enums=[], opts={})
|
|
9
|
+
super enums
|
|
10
|
+
@name = name
|
|
11
|
+
@options = opts
|
|
12
|
+
@labels_hash = Hash[*self.collect{|e| [e, e.to_s.gsub(/_/, ' ').squeeze(' ').capitalize]}.flatten]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def allows_nil?
|
|
16
|
+
@options.key?(:nil) ? @options[:nil] : true
|
|
17
|
+
end
|
|
18
|
+
def allows_value?(value)
|
|
19
|
+
self.include?(value.to_sym)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def enums
|
|
23
|
+
self
|
|
24
|
+
end
|
|
25
|
+
def label(value)
|
|
26
|
+
@labels_hash[value]
|
|
27
|
+
end
|
|
28
|
+
def labels
|
|
29
|
+
@labels_array ||= self.map{|e| @labels_hash[e]}
|
|
30
|
+
end
|
|
31
|
+
def hash
|
|
32
|
+
@labels_hash
|
|
33
|
+
end
|
|
34
|
+
def select_options
|
|
35
|
+
@select_options ||= self.map{|e| [@labels_hash[e], e.to_s]}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def set_label(enum_value, label_string)
|
|
39
|
+
reset_labels
|
|
40
|
+
@labels_hash[enum_value.to_sym] = label_string
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
protected
|
|
44
|
+
def reset_labels
|
|
45
|
+
@labels_array = nil
|
|
46
|
+
@select_options = nil
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module EnumeratedAttribute
|
|
2
|
+
module Attribute
|
|
3
|
+
module ClassMethods
|
|
4
|
+
def enumerated_attributes(all=true)
|
|
5
|
+
return @enumerated_attributes unless all
|
|
6
|
+
return @all_enumerated_attributes_cache if @all_enumerated_attributes_cache
|
|
7
|
+
@all_enumerated_attributes_cache = @enumerated_attributes ? @enumerated_attributes.dup : {}
|
|
8
|
+
klass = self.superclass
|
|
9
|
+
while (klass)
|
|
10
|
+
if (klass.respond_to?(:enumerated_attributes))
|
|
11
|
+
if (sub_enums = klass.enumerated_attributes)
|
|
12
|
+
@all_enumerated_attributes_cache = sub_enums.merge @all_enumerated_attributes_cache
|
|
13
|
+
break
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
klass = klass.superclass
|
|
17
|
+
end
|
|
18
|
+
@all_enumerated_attributes_cache
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def has_enumerated_attribute?(name)
|
|
22
|
+
!name.nil? && !!self.enumerated_attributes.key?(name.to_sym)
|
|
23
|
+
end
|
|
24
|
+
def enumerated_attribute_allows_nil?(name)
|
|
25
|
+
(descriptor = self.enumerated_attributes[name.to_sym]) && descriptor.allows_nil?
|
|
26
|
+
end
|
|
27
|
+
def enumerated_attribute_allows_value?(name, value)
|
|
28
|
+
return (false) unless (descriptor = self.enumerated_attributes[name.to_sym])
|
|
29
|
+
return descriptor.allows_nil? if (value == nil || value == '')
|
|
30
|
+
descriptor.allows_value?(value)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def define_enumerated_attribute_custom_method(symbol, attr_name, value, negated)
|
|
34
|
+
define_method symbol do
|
|
35
|
+
ival = read_enumerated_attribute(attr_name)
|
|
36
|
+
negated ? ival != value : ival == value
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
module EnumeratedAttribute
|
|
2
|
+
module Attribute
|
|
3
|
+
module InstanceMethods
|
|
4
|
+
def self.included(base)
|
|
5
|
+
|
|
6
|
+
method_missing_suffix = "enumerated_attribute_#{base.name}_#{base.hash}".to_sym
|
|
7
|
+
define_method("method_missing_with_#{method_missing_suffix}") do |methId, *args|
|
|
8
|
+
return self.__send__(methId) if define_enumerated_attribute_dynamic_method(methId)
|
|
9
|
+
self.__send__("method_missing_without_#{method_missing_suffix}", methId, *args)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
respond_to_suffix = "enumerated_attribute_#{base.name}_#{base.hash}".to_sym
|
|
13
|
+
base.class_eval %{
|
|
14
|
+
def respond_to_with_#{respond_to_suffix}?(method, include_private=false)
|
|
15
|
+
self.respond_to_without_#{respond_to_suffix}?(method, include_private) ||
|
|
16
|
+
(!!parse_dynamic_method_parts!(method.to_s) rescue false)
|
|
17
|
+
end
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
base.safe_alias_method_chain :method_missing, method_missing_suffix
|
|
21
|
+
base.safe_alias_method_chain :respond_to?, respond_to_suffix
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def enums(attr)
|
|
26
|
+
self.class.enumerated_attributes[attr.to_sym]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def initialize_enumerated_attributes(only_if_nil = false)
|
|
31
|
+
self.class.enumerated_attributes.each do |k,v|
|
|
32
|
+
self.write_enumerated_attribute(k, v.init_value) unless (only_if_nil && read_enumerated_attribute(k) != nil)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def parse_dynamic_method_parts!(meth_name)
|
|
39
|
+
return(nil) unless meth_name[-1, 1] == '?'
|
|
40
|
+
|
|
41
|
+
middle = meth_name.chop #remove the ?
|
|
42
|
+
|
|
43
|
+
attr = nil
|
|
44
|
+
self.class.enumerated_attributes.keys.each do |name|
|
|
45
|
+
if middle.sub!(Regexp.new("^"+name.to_s), "")
|
|
46
|
+
attr = name; break
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
value = nil
|
|
51
|
+
attr_sym = attr ? attr.to_sym : nil
|
|
52
|
+
if (descriptor = self.class.enumerated_attributes[attr_sym])
|
|
53
|
+
descriptor.enums.each do |v|
|
|
54
|
+
if middle.sub!(Regexp.new(v.to_s+"$"), "")
|
|
55
|
+
value = v; break
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
else
|
|
59
|
+
#search through enum values one at time and identify any ambiguities
|
|
60
|
+
self.class.enumerated_attributes.each do |attr_key,descriptor|
|
|
61
|
+
descriptor.enums.each do|v|
|
|
62
|
+
if middle.match(v.to_s+"$")
|
|
63
|
+
raise(AmbiguousMethod, meth_name+" is ambiguous, use something like "+attr_sym.to_s+(middle[0,1]=='_'? '' : '_')+middle+"? or "+attr_key.to_s+(middle[0,1]=='_'? '' : '_')+middle+"?", caller) if attr_sym
|
|
64
|
+
attr_sym = attr_key
|
|
65
|
+
value = v
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
return (nil) unless attr_sym
|
|
70
|
+
attr = attr_sym.to_s
|
|
71
|
+
middle.sub!(Regexp.new(value.to_s+"$"), "")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
unless value #check for nil?
|
|
75
|
+
return (nil) unless middle.sub!(Regexp.new('nil$'), "")
|
|
76
|
+
value = nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
[attr, middle, value]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def define_enumerated_attribute_dynamic_method(methId)
|
|
83
|
+
meth_name = methId.id2name
|
|
84
|
+
parts = parse_dynamic_method_parts!(meth_name)
|
|
85
|
+
return(false) unless parts
|
|
86
|
+
|
|
87
|
+
negated = !!parts[1].downcase.match(/(^|_)not_/)
|
|
88
|
+
value = parts[2] ? parts[2].to_sym : nil
|
|
89
|
+
self.class.define_enumerated_attribute_custom_method(methId, parts[0], value, negated)
|
|
90
|
+
|
|
91
|
+
true
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|