sequel_notnaughty 0.6.1
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/CHANGELOG.rdoc +4 -0
- data/COPYING +18 -0
- data/README.rdoc +0 -0
- data/Rakefile +119 -0
- data/lib/sequel_notnaughty.rb +72 -0
- data/lib/validations/uniqueness_validation.rb +47 -0
- data/spec/rcov.opts +4 -0
- data/spec/sequel_spec_helper.rb +16 -0
- data/spec/sequel_validated_spec.rb +92 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/validations_spec.rb +42 -0
- metadata +76 -0
data/CHANGELOG.rdoc
ADDED
data/COPYING
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2007-2008 Florian Aßmann
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
require "rake"
|
2
|
+
require "rake/clean"
|
3
|
+
require "rake/gempackagetask"
|
4
|
+
require "rake/rdoctask"
|
5
|
+
require "fileutils"
|
6
|
+
include FileUtils
|
7
|
+
|
8
|
+
##############################################################################
|
9
|
+
# Configuration
|
10
|
+
##############################################################################
|
11
|
+
NAME = "sequel_notnaughty"
|
12
|
+
VERS = "0.6.1"
|
13
|
+
CLEAN.include %w[ pkg doc coverage ]
|
14
|
+
RDOC_OPTS = [
|
15
|
+
"--quiet",
|
16
|
+
"--title", "Ruby Sequel adapater for NotNaughty: The Validation Framework",
|
17
|
+
"--opname", "index.html",
|
18
|
+
"--inline-source",
|
19
|
+
"--line-numbers",
|
20
|
+
"--main", "README.rdoc",
|
21
|
+
"--inline-source",
|
22
|
+
"--charset", "utf-8"
|
23
|
+
]
|
24
|
+
|
25
|
+
##############################################################################
|
26
|
+
# RDoc
|
27
|
+
##############################################################################
|
28
|
+
task :doc => [:rdoc]
|
29
|
+
|
30
|
+
Rake::RDocTask.new do |rdoc|
|
31
|
+
rdoc.rdoc_dir = "doc"
|
32
|
+
rdoc.options += RDOC_OPTS
|
33
|
+
rdoc.main = "README.rdoc"
|
34
|
+
rdoc.title = "Ruby Sequel adapater for NotNaughty: The Validation Framework"
|
35
|
+
rdoc.rdoc_files.add %w[README.rdoc COPYING CHANGELOG.rdoc lib/**/*.rb]
|
36
|
+
end
|
37
|
+
|
38
|
+
##############################################################################
|
39
|
+
# specs
|
40
|
+
##############################################################################
|
41
|
+
require "spec/rake/spectask"
|
42
|
+
|
43
|
+
desc "Run specs with coverage"
|
44
|
+
Spec::Rake::SpecTask.new("spec") do |t|
|
45
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
46
|
+
t.spec_opts = File.read("spec/spec.opts").split("\n")
|
47
|
+
t.rcov_opts = File.read("spec/rcov.opts").split("\n")
|
48
|
+
t.rcov = true
|
49
|
+
end
|
50
|
+
|
51
|
+
desc "Run specs without coverage"
|
52
|
+
Spec::Rake::SpecTask.new("spec_no_cov") do |t|
|
53
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
54
|
+
t.spec_opts = File.read("spec/spec.opts").split("\n")
|
55
|
+
end
|
56
|
+
|
57
|
+
desc "check documentation coverage"
|
58
|
+
task :dcov do
|
59
|
+
sh "find lib -name '*.rb' | xargs dcov"
|
60
|
+
end
|
61
|
+
|
62
|
+
##############################################################################
|
63
|
+
# Gem packaging
|
64
|
+
##############################################################################
|
65
|
+
desc "Packages up Ruby Sequel adapter for NotNaughty."
|
66
|
+
task :default => [:package]
|
67
|
+
task :package => [:clean]
|
68
|
+
|
69
|
+
spec = Gem::Specification.new do |s|
|
70
|
+
s.name = NAME
|
71
|
+
s.rubyforge_project = NAME
|
72
|
+
s.version = VERS
|
73
|
+
s.platform = Gem::Platform::RUBY
|
74
|
+
s.has_rdoc = true
|
75
|
+
s.extra_rdoc_files = ["README.rdoc", "CHANGELOG.rdoc", "COPYING"]
|
76
|
+
s.summary = "Gifts Ruby Sequel with heavily armed validations."
|
77
|
+
s.description = s.summary
|
78
|
+
s.author = "Florian Aßmann"
|
79
|
+
s.email = "boof@monkey-patch.me"
|
80
|
+
s.homepage = "http://monkey-patch.me/p/not-naughty"
|
81
|
+
s.required_ruby_version = ">= 1.8.6"
|
82
|
+
s.add_dependency("not-naughty", "= #{ VERS }")
|
83
|
+
|
84
|
+
s.files = %w(COPYING README.rdoc Rakefile) + Dir.glob("{spec,lib}/**/*")
|
85
|
+
|
86
|
+
s.require_path = "lib"
|
87
|
+
end
|
88
|
+
|
89
|
+
Rake::GemPackageTask.new(spec) do |p|
|
90
|
+
p.need_tar = true
|
91
|
+
p.gem_spec = spec
|
92
|
+
end
|
93
|
+
|
94
|
+
##############################################################################
|
95
|
+
# installation & removal
|
96
|
+
##############################################################################
|
97
|
+
task :install do
|
98
|
+
sh %{rake package}
|
99
|
+
sh %{sudo gem install pkg/#{NAME}-#{VERS}}
|
100
|
+
end
|
101
|
+
|
102
|
+
task :install_no_docs do
|
103
|
+
sh %{rake package}
|
104
|
+
sh %{sudo gem install pkg/#{NAME}-#{VERS} --no-rdoc --no-ri}
|
105
|
+
end
|
106
|
+
|
107
|
+
task :uninstall => [:clean] do
|
108
|
+
sh %{sudo gem uninstall #{NAME}}
|
109
|
+
end
|
110
|
+
|
111
|
+
##############################################################################
|
112
|
+
# gem and rdoc release
|
113
|
+
##############################################################################
|
114
|
+
task :release => [:package] do
|
115
|
+
sh %{rubyforge login}
|
116
|
+
sh %{rubyforge add_release not-naughty not-naughty #{VERS} pkg/#{NAME}-#{VERS}.tgz}
|
117
|
+
sh %{rubyforge add_file not-naughty not-naughty #{VERS} pkg/#{NAME}-#{VERS}.gem}
|
118
|
+
end
|
119
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
gem 'sequel', '>= 2.5.0'
|
4
|
+
require 'sequel'
|
5
|
+
|
6
|
+
#gem 'not-naughty', '0.6.1'
|
7
|
+
require 'not_naughty'
|
8
|
+
|
9
|
+
::NotNaughty::Validation.load(:acceptance, :confirmation, :format, :length, :numericality, :presence)
|
10
|
+
require "#{ File.dirname __FILE__ }/validations/uniqueness_validation.rb"
|
11
|
+
|
12
|
+
module Sequel #:nodoc:
|
13
|
+
module Plugins #:nodoc:
|
14
|
+
# == Adapter for Ruby Sequel
|
15
|
+
#
|
16
|
+
# Validate all your Ruby Sequel models with NotNaughty:
|
17
|
+
#
|
18
|
+
# class Sequel::Model
|
19
|
+
# is :notnaughty
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# Validate just specific models:
|
23
|
+
#
|
24
|
+
# class YourModel < Sequel::Model
|
25
|
+
# is :notnaughty
|
26
|
+
# end
|
27
|
+
class NotNaughty < NotNaughty::Validator
|
28
|
+
|
29
|
+
# Hook called by plugin api.
|
30
|
+
def self.apply(receiver, *args)
|
31
|
+
receiver.extend ::NotNaughty
|
32
|
+
receiver.validator self, :create, :update
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns state for given instance.
|
36
|
+
def get_state(instance)
|
37
|
+
if instance.new? then @states[:create] else @states[:update] end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Ensures API compatibility.
|
41
|
+
module InstanceMethods
|
42
|
+
def validate #:nodoc:
|
43
|
+
errors.clear
|
44
|
+
return false if before_validation == false
|
45
|
+
self.class.validator.invoke self
|
46
|
+
after_validation
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
# Ensures API compatibility.
|
51
|
+
module ClassMethods
|
52
|
+
|
53
|
+
def validations #:nodoc:
|
54
|
+
validator.states.
|
55
|
+
inject({}) do |validations, state_with_name|
|
56
|
+
validations.merge(state_with_name[1].validations) {|k,o,n| o|n}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
def has_validations?() #:nodoc:
|
60
|
+
validator.has_validations?
|
61
|
+
end
|
62
|
+
def validate(instance) #:nodoc:
|
63
|
+
validator.invoke instance
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
# this isn't a one-liner...
|
70
|
+
Notnaughty = NotNaughty
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module NotNaughty
|
2
|
+
|
3
|
+
# Validates only if the fields in the model (specified by atts) are
|
4
|
+
# unique in the database. You should also add a unique index in the
|
5
|
+
# database, as this suffers from a fairly obvious race condition.
|
6
|
+
#
|
7
|
+
# Possible Options:
|
8
|
+
# <tt>:in</tt>:: scope could be a single or multiple attributes
|
9
|
+
# <tt>:message</tt>:: see NotNaughty::Errors for details
|
10
|
+
# <tt>:if</tt>:: see NotNaughty::Validation::Condition for details
|
11
|
+
# <tt>:unless</tt>:: see NotNaughty::Validation::Condition for details
|
12
|
+
class UniquenessValidation < Validation
|
13
|
+
|
14
|
+
def initialize(valid, attributes) #:nodoc:
|
15
|
+
valid[:message] ||= '%s is already taken.'
|
16
|
+
valid[:in] = case valid[:in]
|
17
|
+
when Array; valid[:in].map { |scp| scp.to_sym }
|
18
|
+
when String, String; [ valid[:in].to_sym ]
|
19
|
+
else
|
20
|
+
[]
|
21
|
+
end
|
22
|
+
|
23
|
+
if valid[:allow_blank] or valid[:allow_nil]
|
24
|
+
valid[:allow] = valid[:allow_blank] ? :blank? : :nil?
|
25
|
+
|
26
|
+
super valid, attributes do |obj, attr, value|
|
27
|
+
scope_values = obj.values.values_at(*valid[:in])
|
28
|
+
scope = Hash[*valid[:in].zip(scope_values).flatten]
|
29
|
+
|
30
|
+
value.send valid[:allow] or
|
31
|
+
obj.model.find(scope.merge(attr => value)).nil? or
|
32
|
+
obj.errors.add attr, valid[:message]
|
33
|
+
end
|
34
|
+
else
|
35
|
+
|
36
|
+
super valid, attributes do |obj, attr, value|
|
37
|
+
scope_values = obj.values.values_at(*valid[:in])
|
38
|
+
scope = Hash[*valid[:in].zip(scope_values).flatten]
|
39
|
+
|
40
|
+
obj.model.find(scope.merge(attr => value)).nil? or
|
41
|
+
obj.errors.add attr, valid[:message]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/spec/rcov.opts
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "#{ File.dirname __FILE__ }/spec_helper.rb"
|
2
|
+
|
3
|
+
DB = Sequel::Model.db = Sequel.sqlite
|
4
|
+
|
5
|
+
Sequel::Model.instance_eval do
|
6
|
+
%w[validate valid?].
|
7
|
+
each {|m| undef_method m.to_sym}
|
8
|
+
end
|
9
|
+
|
10
|
+
(class << Sequel::Model; self; end).module_eval do
|
11
|
+
%w[validate validates validates_acceptance_of validates_confirmation_of
|
12
|
+
validates_each validates_format_of validates_length_of
|
13
|
+
validates_numericality_of validates_presence_of validations
|
14
|
+
has_validations?].
|
15
|
+
each {|m| undef_method m.to_sym}
|
16
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require "#{ File.dirname __FILE__ }/sequel_spec_helper.rb"
|
2
|
+
|
3
|
+
describe Sequel::Plugins::NotNaughty do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@obj = Class.new(Sequel::Model) { is :notnaughty }
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should delegate validation methods in receiver" do
|
10
|
+
@instance = @obj.new
|
11
|
+
|
12
|
+
@obj.validator.should be_an_instance_of(Sequel::Plugins::NotNaughty)
|
13
|
+
@obj.validator.should_receive(:states).and_return({})
|
14
|
+
@obj.validator.should_receive(:has_validations?)
|
15
|
+
@obj.validator.should_receive(:invoke).with(@instance)
|
16
|
+
|
17
|
+
@instance.errors.should be_an_instance_of(subject::Violation)
|
18
|
+
@instance.should respond_to(:validate)
|
19
|
+
@instance.should respond_to(:valid?)
|
20
|
+
|
21
|
+
@obj.validations
|
22
|
+
@obj.has_validations?
|
23
|
+
@obj.validate @instance
|
24
|
+
end
|
25
|
+
it "should return validations" do
|
26
|
+
@obj.validations.should be_an_instance_of(Hash)
|
27
|
+
end
|
28
|
+
it "should not have validations" do
|
29
|
+
@obj.has_validations?.should == false
|
30
|
+
end
|
31
|
+
it "should add_validation instance of validation" do
|
32
|
+
validation = Class.new(subject::Validation)
|
33
|
+
|
34
|
+
@obj.validator.add_validation validation, :attribute
|
35
|
+
|
36
|
+
validations = @obj.validator.states[:create][:attribute]
|
37
|
+
validations.length.should == 1
|
38
|
+
validations.first.should be_an_instance_of(validation)
|
39
|
+
|
40
|
+
validations = @obj.validator.states[:update][:attribute]
|
41
|
+
validations.length.should == 1
|
42
|
+
validations.first.should be_an_instance_of(validation)
|
43
|
+
|
44
|
+
@obj.validator.add_validation validation, :attribute, :on => :create
|
45
|
+
|
46
|
+
validations = @obj.validator.states[:create][:attribute]
|
47
|
+
validations.length.should == 2
|
48
|
+
validations[0].should be_an_instance_of(validation)
|
49
|
+
validations[1].should be_an_instance_of(validation)
|
50
|
+
|
51
|
+
validations = @obj.validator.states[:update][:attribute]
|
52
|
+
validations.length.should == 1
|
53
|
+
validations.first.should be_an_instance_of(validation)
|
54
|
+
end
|
55
|
+
it "should have validations" do
|
56
|
+
validation = Class.new(subject::Validation)
|
57
|
+
@obj.validator.add_validation validation, :attribute
|
58
|
+
|
59
|
+
@obj.has_validations?.should == true
|
60
|
+
end
|
61
|
+
it "should add_validation blocks as Validation" do
|
62
|
+
@obj.validator.add_validation(:attribute) { |o, a, v| }
|
63
|
+
|
64
|
+
@obj.validator.states[:create][:attribute].first.
|
65
|
+
should be_kind_of(subject::Validation)
|
66
|
+
@obj.validator.states[:update][:attribute].first.
|
67
|
+
should be_kind_of(subject::Validation)
|
68
|
+
end
|
69
|
+
it "should run validations on object when it's invoked" do
|
70
|
+
probe = mock 'Probe', :new? => true
|
71
|
+
probe.should_receive(:attribute).and_return(1)
|
72
|
+
probe.should_receive(:test).with(:attribute, 1)
|
73
|
+
|
74
|
+
@obj.validator.add_validation(:attribute) { |o, a, v| o.test a, v }
|
75
|
+
@obj.validate probe
|
76
|
+
end
|
77
|
+
it "should validate if saved" do
|
78
|
+
x = rand
|
79
|
+
instance = @obj.new
|
80
|
+
instance.stub!(:save!).and_return(x)
|
81
|
+
@obj.validator.should_receive(:invoke).with(instance)
|
82
|
+
instance.save.should be(x)
|
83
|
+
end
|
84
|
+
it "should run hooks if validated" do
|
85
|
+
instance = @obj.new
|
86
|
+
instance.should_receive(:before_validation)
|
87
|
+
instance.should_receive(:after_validation)
|
88
|
+
instance.stub!(:save!)
|
89
|
+
instance.save
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require "#{ File.dirname __FILE__ }/sequel_spec_helper.rb"
|
2
|
+
|
3
|
+
Sequel.sqlite
|
4
|
+
|
5
|
+
class Item < Sequel::Model
|
6
|
+
is :notnaughty
|
7
|
+
validates_uniqueness_of :name, :in => [:category, :domain]
|
8
|
+
|
9
|
+
set_schema :items do
|
10
|
+
primary_key :id
|
11
|
+
column :name, :text
|
12
|
+
column :category, :text
|
13
|
+
column :domain, :text
|
14
|
+
end
|
15
|
+
create_table
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Sequel::Plugins::NotNaughty do
|
20
|
+
|
21
|
+
before(:each) { Item.delete_all }
|
22
|
+
|
23
|
+
it "should not be valid when valid isn't unique" do
|
24
|
+
item = Item.new :name => 'abc'
|
25
|
+
proc { item.save }.should_not raise_error
|
26
|
+
|
27
|
+
item = Item.new :name => 'abc'
|
28
|
+
proc { item.save }.should raise_error(Sequel::Error)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should honor scopes" do
|
32
|
+
item = Item.new :name => 'abc', :category => 'efg'
|
33
|
+
proc { item.save }.should_not raise_error
|
34
|
+
|
35
|
+
item = Item.new :name => 'abc', :category => 'efg'
|
36
|
+
proc { item.save }.should raise_error(Sequel::Error)
|
37
|
+
|
38
|
+
item = Item.new :name => 'abc', :category => 'efg', :domain => 'hij'
|
39
|
+
proc { item.save }.should_not raise_error
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sequel_notnaughty
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Florian A\xC3\x9Fmann"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-10-10 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: not-naughty
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - "="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.6.1
|
24
|
+
version:
|
25
|
+
description: Gifts Ruby Sequel with heavily armed validations.
|
26
|
+
email: boof@monkey-patch.me
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README.rdoc
|
33
|
+
- CHANGELOG.rdoc
|
34
|
+
- COPYING
|
35
|
+
files:
|
36
|
+
- COPYING
|
37
|
+
- README.rdoc
|
38
|
+
- Rakefile
|
39
|
+
- spec/rcov.opts
|
40
|
+
- spec/sequel_spec_helper.rb
|
41
|
+
- spec/sequel_validated_spec.rb
|
42
|
+
- spec/spec.opts
|
43
|
+
- spec/spec_helper.rb
|
44
|
+
- spec/validations_spec.rb
|
45
|
+
- lib/sequel_notnaughty.rb
|
46
|
+
- lib/validations
|
47
|
+
- lib/validations/uniqueness_validation.rb
|
48
|
+
- CHANGELOG.rdoc
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: http://monkey-patch.me/p/not-naughty
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 1.8.6
|
61
|
+
version:
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
version:
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
rubyforge_project: sequel_notnaughty
|
71
|
+
rubygems_version: 1.3.0
|
72
|
+
signing_key:
|
73
|
+
specification_version: 2
|
74
|
+
summary: Gifts Ruby Sequel with heavily armed validations.
|
75
|
+
test_files: []
|
76
|
+
|