midas-dynamic_validations 0.0.3

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.
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,16 @@
1
+ History.txt
2
+ Manifest.txt
3
+ PostInstall.txt
4
+ README.rdoc
5
+ Rakefile
6
+ lib/dynamic_validations.rb
7
+ lib/dynamic_validations/act_methods.rb
8
+ lib/dynamic_validations/validation_rule.rb
9
+ lib/dynamic_validations/validations.rb
10
+ script/console
11
+ script/destroy
12
+ script/generate
13
+ spec/dynamic_validations_spec.rb
14
+ spec/spec.opts
15
+ spec/spec_helper.rb
16
+ tasks/rspec.rake
@@ -0,0 +1,7 @@
1
+
2
+ For more information on dynamic_validations, see http://dynamic_validations.rubyforge.org
3
+
4
+ NOTE: Change this information in PostInstall.txt
5
+ You can also delete it if you don't want it.
6
+
7
+
@@ -0,0 +1,75 @@
1
+ = dynamic_validations
2
+
3
+ http://github.com/midas/dynamic_validations/tree/master
4
+
5
+
6
+ == DESCRIPTION:
7
+
8
+ Easily make your rails app's validation configurable by the end user by storing the validation rules in the database.
9
+
10
+
11
+ == FEATURES:
12
+
13
+ * Generates the necessary validation rule table migration
14
+ * Provides a validation rule ActiveRecord model
15
+ * Overrides validation method for models with has_dynamic_validations macro
16
+
17
+
18
+ == PROBLEMS:
19
+
20
+
21
+
22
+ == REQUIREMENTS:
23
+
24
+
25
+
26
+ == INSTALL:
27
+
28
+ sudo gem install midas-dynamic_validations
29
+
30
+
31
+ == USAGE:
32
+
33
+ Add to environment file:
34
+
35
+ config.gem "midas-dynamic_validations", :version => '00.2'
36
+
37
+
38
+ In an environment initializer:
39
+
40
+ DYNAMIC_VALIDATIONS_CONFIG = {
41
+ :messages => {
42
+ :presence => "cannot be blank"
43
+ }
44
+ }
45
+
46
+
47
+ In an ActiveRecord model:
48
+
49
+ has_dynamic_valdiations
50
+
51
+
52
+ == LICENSE:
53
+
54
+ (The MIT License)
55
+
56
+ Copyright (c) 2009 C. Jason Harrelson (midas)
57
+
58
+ Permission is hereby granted, free of charge, to any person obtaining
59
+ a copy of this software and associated documentation files (the
60
+ 'Software'), to deal in the Software without restriction, including
61
+ without limitation the rights to use, copy, modify, merge, publish,
62
+ distribute, sublicense, and/or sell copies of the Software, and to
63
+ permit persons to whom the Software is furnished to do so, subject to
64
+ the following conditions:
65
+
66
+ The above copyright notice and this permission notice shall be
67
+ included in all copies or substantial portions of the Software.
68
+
69
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
70
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
71
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
72
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
73
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
74
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
75
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/dynamic_validations'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('dynamic_validations', DynamicValidations::VERSION) do |p|
7
+ p.developer('C. Jason Harrelson', 'jason@lookforwardenterprises.com')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
10
+ p.rubyforge_name = p.name # TODO this is default value
11
+ # p.extra_deps = [
12
+ # ['activesupport','>= 2.0.2'],
13
+ # ]
14
+ p.extra_dev_deps = [
15
+ ['newgem', ">= #{::Newgem::VERSION}"]
16
+ ]
17
+
18
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
19
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
20
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
21
+ p.rsync_args = '-av --delete --ignore-errors'
22
+ end
23
+
24
+ require 'newgem/tasks' # load /tasks/*.rake
25
+ Dir['tasks/**/*.rake'].each { |t| load t }
26
+
27
+ # TODO - want other tests/tasks run by default? Add them to the list
28
+ # task :default => [:spec, :features]
@@ -0,0 +1,12 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'dynamic_validations/act_methods'
5
+ require 'dynamic_validations/validations'
6
+ #require 'dynamic_validations/validation_rule'
7
+
8
+ module DynamicValidations
9
+ VERSION = '0.0.3'
10
+ end
11
+
12
+ ActiveRecord::Base.send( :extend, DynamicValidations::ActMethods ) if defined?( ActiveRecord::Base )
@@ -0,0 +1,11 @@
1
+ module DynamicValidations
2
+ module ActMethods
3
+
4
+ def has_dynamic_validations
5
+ unless included_modules.include? Validations
6
+ include Validations
7
+ end
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module DynamicValidations
2
+ if defined?( ActiveRecord::Base )
3
+
4
+ class ValidationRule < ActiveRecord::Base
5
+ named_scope :for_account, lambda { |*args| { :conditions => { :account_id => args.first } } }
6
+ named_scope :for_type, lambda { |*args| { :conditions => { :type => args.first } } }
7
+ named_scope :for_attribute, lambda { |*args| { :conditions => { :attribute => args.first } } }
8
+
9
+ def to_s
10
+ "#{self.attribute} - #{self.validation}"
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,158 @@
1
+ module DynamicValidations
2
+ module Validations
3
+ DEFAULT_VALIDATION_OPTIONS = {
4
+ :on => :save,
5
+ :allow_nil => false,
6
+ :allow_blank => false,
7
+ :message => nil
8
+ }.freeze
9
+
10
+ ALL_RANGE_OPTIONS = [ :is, :within, :in, :minimum, :maximum ].freeze
11
+ ALL_NUMERICALITY_CHECKS = { :greater_than => '>', :greater_than_or_equal_to => '>=',
12
+ :equal_to => '==', :less_than => '<', :less_than_or_equal_to => '<=',
13
+ :odd => 'odd?', :even => 'even?' }.freeze
14
+
15
+ def validate
16
+ validation_rules = ValidationRule.find( :all, :conditions => { :is_active => true, :account_id => self.account_id,
17
+ :entity_type => self.class.name }, :order => "attribute, validation", :select => "id, attribute, validation, description, message" )
18
+
19
+ #validation_rules.group_by(&:validation).each do |validation, validation_rules|
20
+ validation_rules.each do |validation_rule|
21
+ desc = YAML.load( validation_rule.description ) unless validation_rule.description.nil?
22
+ if desc.nil?
23
+ self.send( "validate_#{validation_rule.validation}".to_sym, validation_rule.attribute )
24
+ else
25
+ self.send( "validate_#{validation_rule.validation}".to_sym, validation_rule.attribute, desc )
26
+ end
27
+ #self.send( "validate_#{validation}".to_sym, *(validation_rules.map { |rule| rule.attribute }) )
28
+ end
29
+ end
30
+
31
+ def validate_presence( *args )
32
+ options = args.extract_options!
33
+ attrs = args
34
+ self.errors.add_on_blank( attrs, DYNAMIC_VALIDATIONS_CONFIG[:messages][:presence] || "cannot be blank" )
35
+ end
36
+
37
+ def validate_length( *args )
38
+ # Merge given options with defaults.
39
+ options = {
40
+ :tokenizer => lambda {|value| value.split(//)}
41
+ }.merge(DEFAULT_VALIDATION_OPTIONS)
42
+ options.update(args.extract_options!.symbolize_keys)
43
+ attr = args[0]
44
+
45
+ # Ensure that one and only one range option is specified.
46
+ range_options = ALL_RANGE_OPTIONS & options.keys
47
+ case range_options.size
48
+ when 0
49
+ raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
50
+ when 1
51
+ # Valid number of options; do nothing.
52
+ else
53
+ raise ArgumentError, 'Too many range options specified. Choose only one.'
54
+ end
55
+
56
+ # Get range option and value.
57
+ option = range_options.first
58
+ option_value = options[range_options.first]
59
+ key = {:is => :wrong_length, :minimum => :too_short, :maximum => :too_long}[option]
60
+ custom_message = options[:message] || options[key]
61
+ value = self.send( "#{attr}".to_sym )
62
+
63
+ case option
64
+ when :within, :in
65
+ raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?( Range )
66
+
67
+ #self.class.validates_each(attrs, options) do |record, attr, value|
68
+ value = options[:tokenizer].call( value ) if value.kind_of?( String )
69
+ if value.nil? or value.size < option_value.begin.to_i
70
+ self.errors.add( attr, :too_short, :default => custom_message || options[:too_short], :count => option_value.begin )
71
+ elsif value.size > option_value.end.to_i
72
+ self.errors.add( attr, :too_long, :default => custom_message || options[:too_long], :count => option_value.end )
73
+ end
74
+ #end
75
+ when :is, :minimum, :maximum
76
+ raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?( Integer ) and option_value >= 0
77
+
78
+ # Declare different validations per option.
79
+ validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" }
80
+
81
+ #self.class.validates_each(attrs, options) do |record, attr, value|
82
+ value = options[:tokenizer].call( value ) if value.kind_of?( String )
83
+ unless !value.nil? and value.size.method( validity_checks[option] )[option_value]
84
+ record.errors.add( attr, key, :default => custom_message, :count => option_value )
85
+ end
86
+ #end
87
+ end
88
+ end #def valiate_length
89
+
90
+ def validate_numericality( *args )
91
+ configuration = { :on => :save, :only_integer => false, :allow_nil => false }
92
+ configuration.update( args.extract_options!.symbolize_keys )
93
+ attr_name = args[0]
94
+
95
+ numericality_options = ALL_NUMERICALITY_CHECKS.keys & configuration.keys
96
+
97
+ (numericality_options - [ :odd, :even ]).each do |option|
98
+ raise ArgumentError, ":#{option} must be a number" unless configuration[option].is_a?( Numeric )
99
+ end
100
+
101
+ raw_value = self.send( "#{attr_name}_before_type_cast" ) || value
102
+
103
+ return if configuration[:allow_nil] and raw_value.nil?
104
+
105
+ if configuration[:only_integer]
106
+ unless raw_value.to_s =~ /\A[+-]?\d+\Z/
107
+ msg = DYNAMIC_VALIDATIONS_CONFIG[:messages][:numericality][:not_an_integer] || configuration[:message] || "must be an integer"
108
+ self.errors.add( attr_name, :not_a_number, :value => raw_value, :default => msg )
109
+ return
110
+ end
111
+ raw_value = raw_value.to_i
112
+ else
113
+ begin
114
+ raw_value = Kernel.Float( raw_value )
115
+ rescue ArgumentError, TypeError
116
+ msg = DYNAMIC_VALIDATIONS_CONFIG[:messages][:numericality][:not_a_number] || configuration[:message] || "must be a number"
117
+ self.errors.add( attr_name, :not_a_number, :value => raw_value, :default => msg )
118
+ return
119
+ end
120
+ end
121
+
122
+ numericality_options.each do |option|
123
+ case option
124
+ when :odd
125
+ unless raw_value.to_i.method( ALL_NUMERICALITY_CHECKS[option] )[]
126
+ msg = DYNAMIC_VALIDATIONS_CONFIG[:messages][:numericality][:even_number] || configuration[:message] || "must be an odd number"
127
+ self.errors.add( attr_name, option, :value => raw_value, :default => msg )
128
+ end
129
+ when :even
130
+ unless raw_value.to_i.method( ALL_NUMERICALITY_CHECKS[option] )[]
131
+ msg = DYNAMIC_VALIDATIONS_CONFIG[:messages][:numericality][:odd_number] || configuration[:message] || "must be an even number"
132
+ self.errors.add( attr_name, option, :value => raw_value, :default => msg )
133
+ end
134
+ when :greater_than
135
+ unless raw_value.to_i > configuration[:greater_than]
136
+ self.errors.add( attr_name, option, :value => raw_value, :default => "must be a number greater than #{configuration[:greater_than].to_s}" )
137
+ end
138
+ when :greater_than_or_equal_to
139
+ unless raw_value.to_i >= configuration[:greater_than_or_equal_to]
140
+ self.errors.add( attr_name, option, :value => raw_value, :default => "must be a number greater than #{configuration[:greater_than_or_equal_to].to_s}" )
141
+ end
142
+ when :less_than
143
+ unless raw_value.to_i < configuration[:less_than]
144
+ self.errors.add( attr_name, option, :value => raw_value, :default => "must be a number less than #{configuration[:less_than].to_s}" )
145
+ end
146
+ when :less_than_or_equal_to
147
+ unless raw_value.to_i <= configuration[:less_than_or_equal_to]
148
+ self.errors.add( attr_name, option, :value => raw_value, :default => "must be a number less than #{configuration[:less_than_or_equal_to].to_s}" )
149
+ end
150
+ else
151
+ msg = DYNAMIC_VALIDATIONS_CONFIG[:messages][:numericality][:not_a_number] || configuration[:message] || "must be a number"
152
+ self.errors.add( attr_name, option, :default => configuration[:message], :value => raw_value, :count => configuration[option] ) unless raw_value.method( ALL_NUMERICALITY_CHECKS[option] )[configuration[option]]
153
+ end
154
+ end
155
+ end #def validate_numericality
156
+
157
+ end #module Validations
158
+ end #module DynamcValidations
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/dynamic_validations.rb'}"
9
+ puts "Loading dynamic_validations gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ # Time to add your specs!
4
+ # http://rspec.info/
5
+ describe "Place your specs here" do
6
+
7
+ it "find this spec in spec directory" do
8
+ violated "Be sure to write your specs"
9
+ end
10
+
11
+ end
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'dynamic_validations'
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: midas-dynamic_validations
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - C. Jason Harrelson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-10 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: newgem
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.3.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.0
34
+ version:
35
+ description: Easily make your rails app's validation configurable by the end user by storing the validation rules in the database.
36
+ email:
37
+ - jason@lookforwardenterprises.com
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - PostInstall.txt
46
+ - README.rdoc
47
+ files:
48
+ - History.txt
49
+ - Manifest.txt
50
+ - PostInstall.txt
51
+ - README.rdoc
52
+ - Rakefile
53
+ - lib/dynamic_validations.rb
54
+ - lib/dynamic_validations/act_methods.rb
55
+ - lib/dynamic_validations/validation_rule.rb
56
+ - lib/dynamic_validations/validations.rb
57
+ - script/console
58
+ - script/destroy
59
+ - script/generate
60
+ - spec/dynamic_validations_spec.rb
61
+ - spec/spec.opts
62
+ - spec/spec_helper.rb
63
+ - tasks/rspec.rake
64
+ has_rdoc: true
65
+ homepage: http://github.com/midas/dynamic_validations/tree/master
66
+ post_install_message: PostInstall.txt
67
+ rdoc_options:
68
+ - --main
69
+ - README.rdoc
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: "0"
77
+ version:
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: "0"
83
+ version:
84
+ requirements: []
85
+
86
+ rubyforge_project: dynamic_validations
87
+ rubygems_version: 1.2.0
88
+ signing_key:
89
+ specification_version: 2
90
+ summary: Easily make your rails app's validation configurable by the end user by storing the validation rules in the database.
91
+ test_files: []
92
+