activerecord_null_object 0.2.0 → 0.3.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/.gitignore +3 -2
- data/.travis.yml +13 -0
- data/Gemfile +2 -0
- data/README.md +13 -0
- data/Rakefile +11 -18
- data/activerecord_null_object.gemspec +22 -48
- data/gemfiles/rails3.gemfile +8 -0
- data/gemfiles/rails4.gemfile +8 -0
- data/lib/activerecord_null_object/null_object.rb +29 -0
- data/lib/activerecord_null_object/null_object_support.rb +67 -0
- data/lib/activerecord_null_object.rb +4 -56
- data/spec/belongs_to_spec.rb +45 -77
- data/spec/has_one_spec.rb +70 -0
- data/spec/null_object_spec.rb +35 -67
- data/spec/spec_helper.rb +50 -8
- metadata +193 -43
- data/README +0 -5
- data/init.rb +0 -5
- data/lib/null_object.rb +0 -21
- data/spec/database.yml +0 -3
data/.gitignore
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- 2.0.0
|
5
|
+
- 2.1
|
6
|
+
script: "bundle exec rake coverage"
|
7
|
+
gemfile:
|
8
|
+
- gemfiles/rails3.gemfile
|
9
|
+
- gemfiles/rails4.gemfile
|
10
|
+
notifications:
|
11
|
+
email:
|
12
|
+
- support@travellink.com.au
|
13
|
+
flowdock: e69dcafad1fea15c6b8c76e9ced965af
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
ActiveRecord Null Object
|
2
|
+
========================
|
3
|
+
|
4
|
+
[](https://travis-ci.org/sealink/activerecord_null_object)
|
5
|
+
[](https://coveralls.io/r/sealink/activerecord_null_object)
|
6
|
+
[](https://gemnasium.com/sealink/activerecord_null_object)
|
7
|
+
[](https://codeclimate.com/github/sealink/activerecord_null_object)
|
8
|
+
|
9
|
+
# DESCRIPTION
|
10
|
+
|
11
|
+
Implements the Null Object Pattern for nil values in ActiveRecord associations.
|
12
|
+
|
13
|
+
Copyright (c) 2009 West Arete Computing, Inc., released under the MIT license
|
data/Rakefile
CHANGED
@@ -1,25 +1,18 @@
|
|
1
|
-
require
|
2
|
-
require 'spec/rake/spectask'
|
3
|
-
require 'init'
|
1
|
+
require "bundler/gem_tasks"
|
4
2
|
|
5
3
|
desc 'Default: run specs.'
|
6
4
|
task :default => :spec
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
|
8
|
+
desc "Run specs"
|
9
|
+
RSpec::Core::RakeTask.new do |t|
|
10
|
+
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
11
|
+
# Put spec opts in a file named .rspec in root
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
s.summary = %q{Implements the Null Object Pattern for nil values in ActiveRecord associations.}
|
18
|
-
s.email = %q{info@westarete.com}
|
19
|
-
s.homepage = %q{http://github.com/westarete/activerecord_null_object/}
|
20
|
-
s.description = ""
|
21
|
-
s.authors = ["Scott Woods"]
|
22
|
-
end
|
23
|
-
rescue LoadError
|
24
|
-
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
14
|
+
desc "Generate SimpleCov test coverage and open in your browser"
|
15
|
+
task :coverage do
|
16
|
+
ENV['COVERAGE'] = 'true'
|
17
|
+
Rake::Task['spec'].invoke
|
25
18
|
end
|
@@ -1,54 +1,28 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
-
Gem::Specification.new do |
|
4
|
-
|
5
|
-
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "activerecord_null_object"
|
5
|
+
spec.version = "0.3.0"
|
6
|
+
spec.authors = ["Scott Woods", "Alessandro Berardi"]
|
7
|
+
spec.email = ["support@travellink.com.au"]
|
8
|
+
spec.description = %q{Implements the Null Object Pattern for nil values in ActiveRecord associations.}
|
9
|
+
spec.summary = %q{Implements the Null Object Pattern for nil values in ActiveRecord associations.}
|
10
|
+
spec.homepage = 'http://github.com/sealink/activerecord_null_object'
|
6
11
|
|
7
|
-
|
8
|
-
s.authors = ["Scott Woods"]
|
9
|
-
s.date = %q{2009-09-02}
|
10
|
-
s.description = %q{}
|
11
|
-
s.email = %q{info@westarete.com}
|
12
|
-
s.extra_rdoc_files = [
|
13
|
-
"README"
|
14
|
-
]
|
15
|
-
s.files = [
|
16
|
-
".gitignore",
|
17
|
-
"MIT-LICENSE",
|
18
|
-
"README",
|
19
|
-
"Rakefile",
|
20
|
-
"VERSION",
|
21
|
-
"activerecord_null_object.gemspec",
|
22
|
-
"init.rb",
|
23
|
-
"lib/activerecord_null_object.rb",
|
24
|
-
"lib/null_object.rb",
|
25
|
-
"spec/belongs_to_spec.rb",
|
26
|
-
"spec/database.yml",
|
27
|
-
"spec/null_object_spec.rb",
|
28
|
-
"spec/schema.rb",
|
29
|
-
"spec/spec.opts",
|
30
|
-
"spec/spec_helper.rb"
|
31
|
-
]
|
32
|
-
s.has_rdoc = true
|
33
|
-
s.homepage = %q{http://github.com/westarete/activerecord_null_object/}
|
34
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
35
|
-
s.require_paths = ["lib"]
|
36
|
-
s.rubygems_version = %q{1.3.1}
|
37
|
-
s.summary = %q{Implements the Null Object Pattern for nil values in ActiveRecord associations.}
|
38
|
-
s.test_files = [
|
39
|
-
"spec/belongs_to_spec.rb",
|
40
|
-
"spec/null_object_spec.rb",
|
41
|
-
"spec/schema.rb",
|
42
|
-
"spec/spec_helper.rb"
|
43
|
-
]
|
12
|
+
spec.license = "MIT"
|
44
13
|
|
45
|
-
|
46
|
-
|
47
|
-
|
14
|
+
spec.files = `git ls-files`.split($/)
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
17
|
+
spec.require_paths = ["lib"]
|
48
18
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
19
|
+
spec.add_runtime_dependency "activesupport", ">= 3.0"
|
20
|
+
spec.add_runtime_dependency "activerecord", ">= 3.0"
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "rspec-its"
|
25
|
+
spec.add_development_dependency "simplecov"
|
26
|
+
spec.add_development_dependency "coveralls"
|
27
|
+
spec.add_development_dependency 'sqlite3'
|
54
28
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module ActiveRecordNullObject
|
4
|
+
module NullObject
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
validate :unsavable
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def id
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def nil?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def empty?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
def unsavable
|
25
|
+
errors.add(:base, "is a null object and can't be saved")
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module ActiveRecordNullObject
|
4
|
+
module NullObjectSupport
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
|
9
|
+
# Add null object support to the given accessor method.
|
10
|
+
def add_null_object_support(name, options = {}) #:nodoc:
|
11
|
+
# Determine the class of the association.
|
12
|
+
association_class_name = options[:class_name] || name.to_s.classify
|
13
|
+
association_class = association_class_name.constantize
|
14
|
+
null_class_name = "Null" + association_class_name
|
15
|
+
|
16
|
+
# Determine the null class for this association.
|
17
|
+
null_class = options[:null_object].to_s.classify.safe_constantize || null_class_name.safe_constantize
|
18
|
+
|
19
|
+
unless null_class
|
20
|
+
# Define the null class as an ancestor of the association class.
|
21
|
+
null_class = Object.const_set(null_class_name, Class.new(association_class))
|
22
|
+
null_class.class_eval do
|
23
|
+
include ::Singleton
|
24
|
+
include ::ActiveRecordNullObject::NullObject
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Modify the "getter" of the relationship to return an
|
29
|
+
# instance of the association's null object instead of returning nil.
|
30
|
+
class_eval do
|
31
|
+
define_method("#{name}".to_sym) do |*args|
|
32
|
+
super(*args) || null_class.instance
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Add a :null_object option to belongs_to.
|
38
|
+
def belongs_to(*args)
|
39
|
+
options = args.extract_options!
|
40
|
+
name, scope = *args
|
41
|
+
args << options.except(:null_object)
|
42
|
+
# Call the real belongs_to so that the association gets defined.
|
43
|
+
super(*args)
|
44
|
+
|
45
|
+
# Modify the association if need be.
|
46
|
+
if options[:null_object]
|
47
|
+
add_null_object_support(name, options)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Add a :null_object option to has_one.
|
52
|
+
def has_one(*args)
|
53
|
+
options = args.extract_options!
|
54
|
+
name, scope = *args
|
55
|
+
args << options.except(:null_object)
|
56
|
+
# Call the real belongs_to so that the association gets defined.
|
57
|
+
super(*args)
|
58
|
+
|
59
|
+
# Modify the association if need be.
|
60
|
+
if options[:null_object]
|
61
|
+
add_null_object_support(name, options)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,58 +1,6 @@
|
|
1
|
-
|
2
|
-
module Associations
|
3
|
-
module ClassMethods
|
4
|
-
|
5
|
-
# Add null object support to the given accessor method.
|
6
|
-
def add_null_object_support(association_id, options = {}) #:nodoc:
|
7
|
-
# Determine the class of the association.
|
8
|
-
association_class_name = options[:class_name] || association_id.to_s.classify
|
9
|
-
association_class = association_class_name.constantize
|
1
|
+
require 'active_record'
|
10
2
|
|
11
|
-
|
12
|
-
|
13
|
-
if Object.const_defined?(null_class_name)
|
14
|
-
null_class = Object.const_get(null_class_name.to_sym)
|
15
|
-
else
|
16
|
-
# Define the null class as an ancestor of the association class.
|
17
|
-
null_class = Object.const_set(null_class_name, Class.new(association_class))
|
18
|
-
null_class.class_eval do
|
19
|
-
include Singleton
|
20
|
-
include ActiveRecordNullObject::NullObject
|
21
|
-
end
|
22
|
-
end
|
3
|
+
require 'activerecord_null_object/null_object'
|
4
|
+
require 'activerecord_null_object/null_object_support'
|
23
5
|
|
24
|
-
|
25
|
-
# instance of the association's null object instead of returning nil.
|
26
|
-
class_eval do
|
27
|
-
define_method("#{association_id}_with_null_object".to_sym) do
|
28
|
-
send("#{association_id}_without_null_object".to_sym) || null_class.instance
|
29
|
-
end
|
30
|
-
alias_method_chain association_id, :null_object
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# Add a boolean :null_object option to belongs_to.
|
35
|
-
def belongs_to_with_null_object(association_id, options = {}) #:nodoc:
|
36
|
-
# Extract our custom option.
|
37
|
-
use_null_object = options.delete(:null_object)
|
38
|
-
# Call the real belongs_to so that the association gets defined.
|
39
|
-
belongs_to_without_null_object(association_id, options)
|
40
|
-
# Modify the association if need be.
|
41
|
-
add_null_object_support(association_id, options) if use_null_object
|
42
|
-
end
|
43
|
-
alias_method_chain :belongs_to, :null_object
|
44
|
-
|
45
|
-
# Add a boolean :null_object option to has_one.
|
46
|
-
def has_one_with_null_object(association_id, options = {}) #:nodoc:
|
47
|
-
# Extract our custom option.
|
48
|
-
use_null_object = options.delete(:null_object)
|
49
|
-
# Call the real has_one so that the association gets defined.
|
50
|
-
has_one_without_null_object(association_id, options)
|
51
|
-
# Modify the association if need be.
|
52
|
-
add_null_object_support(association_id, options) if use_null_object
|
53
|
-
end
|
54
|
-
alias_method_chain :has_one, :null_object
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
6
|
+
ActiveRecord::Base.send :include, ActiveRecordNullObject::NullObjectSupport
|
data/spec/belongs_to_spec.rb
CHANGED
@@ -1,93 +1,61 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
|
3
3
|
describe Comment do
|
4
|
-
|
5
|
-
@comment = Comment.create!(:body => 'The body.')
|
6
|
-
end
|
7
|
-
|
8
|
-
it "should contain a body" do
|
9
|
-
@comment.body.should == 'The body.'
|
10
|
-
end
|
4
|
+
subject(:comment) { Comment.create!(:body => 'The body.') }
|
11
5
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
@comment.author.nil?.should be_true
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should return false for comment.author.present?" do
|
26
|
-
@comment.author.present?.should be_false
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should return nil for the author's name" do
|
30
|
-
@comment.author.name.should be_nil
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
describe "with an author" do
|
35
|
-
before(:each) do
|
36
|
-
@comment.author = Author.create!(:name => 'James Baker')
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should return the author object" do
|
40
|
-
@comment.author.kind_of?(Author).should be_true
|
41
|
-
@comment.author.kind_of?(NullAuthor).should_not be_true
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should return false for comment.author.nil?" do
|
45
|
-
@comment.author.nil?.should be_false
|
46
|
-
end
|
47
|
-
|
48
|
-
it "should return true for comment.author.present?" do
|
49
|
-
@comment.author.present?.should be_true
|
50
|
-
end
|
51
|
-
|
52
|
-
it "should return the author's name" do
|
53
|
-
@comment.author.name.should == 'James Baker'
|
6
|
+
its(:body) { should == 'The body.' }
|
7
|
+
|
8
|
+
context "its author" do
|
9
|
+
subject(:author) { comment.author }
|
10
|
+
|
11
|
+
context "when not present" do
|
12
|
+
it { should be_kind_of NullAuthor }
|
13
|
+
it { should be_nil }
|
14
|
+
it { should_not be_present }
|
15
|
+
its(:name) { should be_nil }
|
54
16
|
end
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
17
|
+
|
18
|
+
context "when present" do
|
19
|
+
before { comment.create_author!(:name => 'James Baker') }
|
20
|
+
|
21
|
+
it { should be_kind_of Author }
|
22
|
+
it { should_not be_kind_of NullAuthor }
|
23
|
+
it { should_not be_nil }
|
24
|
+
it { should be_present }
|
25
|
+
its(:name) { should == 'James Baker' }
|
26
|
+
|
27
|
+
context "when removed" do
|
28
|
+
before { comment.author = nil }
|
29
|
+
its(:name) { should be_nil }
|
30
|
+
end
|
59
31
|
end
|
60
32
|
end
|
61
33
|
end
|
62
34
|
|
63
35
|
describe Post do
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
@post.author.kind_of?(Author).should be_false
|
75
|
-
@post.author.respond_to?(:name).should be_false
|
36
|
+
subject(:post) { Post.create!(:body => 'The body.') }
|
37
|
+
|
38
|
+
its(:body) { should == 'The body.' }
|
39
|
+
|
40
|
+
context "without null object support for the author" do
|
41
|
+
subject(:author) { post.author }
|
42
|
+
|
43
|
+
it { should be_nil }
|
44
|
+
it { should_not be_kind_of Author }
|
45
|
+
it { should_not respond_to :name }
|
76
46
|
end
|
77
47
|
end
|
78
48
|
|
79
49
|
describe Session do
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
@session.author.kind_of?(Author).should be_false
|
91
|
-
@session.author.respond_to?(:name).should be_false
|
50
|
+
subject(:session) { Session.create!(:description => 'The description.') }
|
51
|
+
|
52
|
+
its(:description) { should == 'The description.' }
|
53
|
+
|
54
|
+
context "without null object support for the author" do
|
55
|
+
subject(:author) { session.author }
|
56
|
+
|
57
|
+
it { should be_nil }
|
58
|
+
it { should_not be_kind_of Author }
|
59
|
+
it { should_not respond_to :name }
|
92
60
|
end
|
93
61
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Author do
|
4
|
+
subject(:author) { Author.create!(:name => 'James Madison') }
|
5
|
+
|
6
|
+
context "its profile" do
|
7
|
+
subject(:profile) { author.profile }
|
8
|
+
|
9
|
+
context "when not present" do
|
10
|
+
context "without null object support for the profile" do
|
11
|
+
it { should be_nil }
|
12
|
+
it { should_not be_kind_of Profile }
|
13
|
+
it { should_not respond_to :age }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when present" do
|
18
|
+
before { author.create_profile!(:age => 56) }
|
19
|
+
|
20
|
+
its(:age) { should == 56 }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "its account" do
|
25
|
+
subject(:account) { author.account }
|
26
|
+
|
27
|
+
context "when not present" do
|
28
|
+
context "without null object support for the account" do
|
29
|
+
it { should be_nil }
|
30
|
+
it { should_not be_kind_of Account }
|
31
|
+
it { should_not respond_to :password }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when present" do
|
36
|
+
before { author.create_account!(:password => 'secret') }
|
37
|
+
|
38
|
+
its(:password) { should == 'secret' }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
context "its address" do
|
44
|
+
subject(:address) { author.address }
|
45
|
+
|
46
|
+
context "when not present" do
|
47
|
+
it { should be_kind_of NullAddress }
|
48
|
+
it { should be_nil }
|
49
|
+
it { should_not be_present }
|
50
|
+
its(:street) { should be_nil }
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when present" do
|
54
|
+
before { author.create_address!(:street => '1600 Pennsylvania Ave') }
|
55
|
+
|
56
|
+
it { should be_kind_of Address }
|
57
|
+
it { should_not be_kind_of NullAddress }
|
58
|
+
it { should_not be_nil }
|
59
|
+
it { should be_present }
|
60
|
+
its(:street) { should == '1600 Pennsylvania Ave' }
|
61
|
+
|
62
|
+
context "when the address is removed" do
|
63
|
+
before { author.address = nil }
|
64
|
+
its(:street) { should be_nil }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/spec/null_object_spec.rb
CHANGED
@@ -1,99 +1,67 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
|
3
3
|
describe NullAuthor do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
it "should be a kind of Author" do
|
10
|
-
@null_author.kind_of?(Author).should be_true
|
11
|
-
end
|
4
|
+
|
5
|
+
subject(:null_author) { Comment.new.author }
|
6
|
+
|
7
|
+
it { should be_kind_of Author }
|
12
8
|
|
13
9
|
it "should be a singleton" do
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should be nil" do
|
18
|
-
@null_author.nil?.should be_true
|
19
|
-
@null_author.should be_nil
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should be empty" do
|
23
|
-
@null_author.empty?.should be_true
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should be blank" do
|
27
|
-
@null_author.blank?.should be_true
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should not be present" do
|
31
|
-
@null_author.present?.should be_false
|
10
|
+
expect { NullAuthor.new }.to raise_error(NoMethodError)
|
32
11
|
end
|
33
12
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
describe "#save" do
|
47
|
-
it "should return false" do
|
48
|
-
@null_author.save.should be_false
|
49
|
-
end
|
50
|
-
|
13
|
+
it { should be_nil }
|
14
|
+
it { should be_empty }
|
15
|
+
it { should be_blank }
|
16
|
+
it { should_not be_present }
|
17
|
+
its(:id) { should be_nil }
|
18
|
+
it { should be_new_record }
|
19
|
+
|
20
|
+
context "when saving with save" do
|
21
|
+
its(:save) { should be false }
|
22
|
+
|
51
23
|
it "should not create a new record" do
|
52
|
-
|
24
|
+
expect { null_author.save }.to_not change { NullAuthor.count }
|
53
25
|
end
|
54
|
-
|
26
|
+
|
55
27
|
it "should add an error" do
|
56
|
-
|
28
|
+
expect(null_author.errors[:base]).to eq ["is a null object and can't be saved"]
|
57
29
|
end
|
58
30
|
end
|
59
|
-
|
60
|
-
|
31
|
+
|
32
|
+
context "when saving with save!" do
|
61
33
|
it "should raise an exception" do
|
62
|
-
|
34
|
+
expect { null_author.save! }.to raise_error(ActiveRecord::RecordInvalid)
|
63
35
|
end
|
64
|
-
|
36
|
+
|
65
37
|
it "should not create a new record" do
|
66
|
-
|
38
|
+
expect {
|
67
39
|
begin
|
68
|
-
|
40
|
+
null_author.save!
|
69
41
|
rescue ActiveRecord::RecordInvalid
|
70
42
|
end
|
71
|
-
}.
|
43
|
+
}.to_not change { NullAuthor.count }
|
72
44
|
end
|
73
45
|
|
74
46
|
it "should add an error" do
|
75
|
-
|
47
|
+
expect(null_author.errors[:base]).to eq ["is a null object and can't be saved"]
|
76
48
|
end
|
77
49
|
end
|
78
50
|
|
79
|
-
|
51
|
+
context "when updating attributes" do
|
80
52
|
it "should return false" do
|
81
|
-
|
53
|
+
expect(null_author.update_attributes({})).to be false
|
82
54
|
end
|
83
|
-
|
55
|
+
|
84
56
|
it "should not create a new record" do
|
85
|
-
|
57
|
+
expect { null_author.update_attributes({}) }.to_not change { NullAuthor.count }
|
86
58
|
end
|
87
59
|
|
88
60
|
it "should add an error" do
|
89
|
-
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
describe "#name" do
|
94
|
-
it "should return nil" do
|
95
|
-
@null_author.name.should be_nil
|
61
|
+
expect(null_author.errors[:base]).to eq ["is a null object and can't be saved"]
|
96
62
|
end
|
97
63
|
end
|
98
|
-
|
99
|
-
|
64
|
+
|
65
|
+
its(:name) { should be_nil }
|
66
|
+
|
67
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,19 +1,50 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
2
3
|
require 'active_record'
|
3
4
|
require 'yaml'
|
4
|
-
require '
|
5
|
-
require
|
5
|
+
require 'rspec'
|
6
|
+
require 'rspec/its'
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
I18n.enforce_available_locales = true if I18n.respond_to? :enforce_available_locales=
|
9
|
+
|
10
|
+
MINIMUM_COVERAGE = 100
|
11
|
+
|
12
|
+
if ENV['COVERAGE']
|
13
|
+
require 'simplecov'
|
14
|
+
require 'coveralls'
|
15
|
+
Coveralls.wear!
|
16
|
+
|
17
|
+
SimpleCov.formatter = Coveralls::SimpleCov::Formatter
|
18
|
+
SimpleCov.start do
|
19
|
+
add_filter '/vendor/'
|
20
|
+
add_filter '/spec/'
|
21
|
+
add_group 'lib', 'lib'
|
22
|
+
end
|
23
|
+
SimpleCov.at_exit do
|
24
|
+
SimpleCov.result.format!
|
25
|
+
percent = SimpleCov.result.covered_percent
|
26
|
+
unless percent >= MINIMUM_COVERAGE
|
27
|
+
puts "Coverage must be above #{MINIMUM_COVERAGE}%. It is #{"%.2f" % percent}%"
|
28
|
+
Kernel.exit(1)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
require 'activerecord_null_object'
|
11
34
|
|
12
35
|
# Fixes 'address'.singularize # => 'addres'
|
13
36
|
ActiveSupport::Inflector.inflections do |inflect|
|
14
37
|
inflect.singular(/ess$/i, 'ess')
|
15
38
|
end
|
16
39
|
|
40
|
+
DB_FILE = 'tmp/test_db'
|
41
|
+
FileUtils.mkdir_p File.dirname(DB_FILE)
|
42
|
+
FileUtils.rm_f DB_FILE
|
43
|
+
|
44
|
+
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => DB_FILE
|
45
|
+
|
46
|
+
load('spec/schema.rb')
|
47
|
+
|
17
48
|
class Account < ActiveRecord::Base
|
18
49
|
end
|
19
50
|
|
@@ -29,12 +60,20 @@ class Author < ActiveRecord::Base
|
|
29
60
|
has_many :comments
|
30
61
|
has_many :sessions
|
31
62
|
has_one :profile
|
32
|
-
|
63
|
+
if ::ActiveRecord::VERSION::MAJOR == 4
|
64
|
+
has_one :account, -> {order :created_at}, :null_object => false
|
65
|
+
else
|
66
|
+
has_one :account, :null_object => false
|
67
|
+
end
|
33
68
|
has_one :address, :null_object => true
|
34
69
|
end
|
35
70
|
|
36
71
|
class Comment < ActiveRecord::Base
|
37
|
-
|
72
|
+
if ::ActiveRecord::VERSION::MAJOR == 4
|
73
|
+
belongs_to :author, -> {order :name}, :null_object => true
|
74
|
+
else
|
75
|
+
belongs_to :author, :null_object => true
|
76
|
+
end
|
38
77
|
end
|
39
78
|
|
40
79
|
class Post < ActiveRecord::Base
|
@@ -45,3 +84,6 @@ class Session < ActiveRecord::Base
|
|
45
84
|
belongs_to :author
|
46
85
|
end
|
47
86
|
|
87
|
+
RSpec.configure do |config|
|
88
|
+
config.raise_errors_for_deprecations!
|
89
|
+
end
|
metadata
CHANGED
@@ -1,72 +1,222 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord_null_object
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
|
-
authors:
|
7
|
+
authors:
|
7
8
|
- Scott Woods
|
9
|
+
- Alessandro Berardi
|
8
10
|
autorequire:
|
9
11
|
bindir: bin
|
10
12
|
cert_chain: []
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
date: 2014-08-29 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '3.0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: activerecord
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '3.0'
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '3.0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: bundler
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '1.3'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: rake
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: rspec
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: rspec-its
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: coveralls
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
none: false
|
131
|
+
requirements:
|
132
|
+
- - ! '>='
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
type: :development
|
136
|
+
prerelease: false
|
137
|
+
version_requirements: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
- !ruby/object:Gem::Dependency
|
144
|
+
name: sqlite3
|
145
|
+
requirement: !ruby/object:Gem::Requirement
|
146
|
+
none: false
|
147
|
+
requirements:
|
148
|
+
- - ! '>='
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
type: :development
|
152
|
+
prerelease: false
|
153
|
+
version_requirements: !ruby/object:Gem::Requirement
|
154
|
+
none: false
|
155
|
+
requirements:
|
156
|
+
- - ! '>='
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
159
|
+
description: Implements the Null Object Pattern for nil values in ActiveRecord associations.
|
160
|
+
email:
|
161
|
+
- support@travellink.com.au
|
18
162
|
executables: []
|
19
|
-
|
20
163
|
extensions: []
|
21
|
-
|
22
|
-
|
23
|
-
- README
|
24
|
-
files:
|
164
|
+
extra_rdoc_files: []
|
165
|
+
files:
|
25
166
|
- .gitignore
|
167
|
+
- .travis.yml
|
168
|
+
- Gemfile
|
26
169
|
- MIT-LICENSE
|
27
|
-
- README
|
170
|
+
- README.md
|
28
171
|
- Rakefile
|
29
172
|
- VERSION
|
30
173
|
- activerecord_null_object.gemspec
|
31
|
-
-
|
174
|
+
- gemfiles/rails3.gemfile
|
175
|
+
- gemfiles/rails4.gemfile
|
32
176
|
- lib/activerecord_null_object.rb
|
33
|
-
- lib/null_object.rb
|
177
|
+
- lib/activerecord_null_object/null_object.rb
|
178
|
+
- lib/activerecord_null_object/null_object_support.rb
|
34
179
|
- spec/belongs_to_spec.rb
|
35
|
-
- spec/
|
180
|
+
- spec/has_one_spec.rb
|
36
181
|
- spec/null_object_spec.rb
|
37
182
|
- spec/schema.rb
|
38
183
|
- spec/spec.opts
|
39
184
|
- spec/spec_helper.rb
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
185
|
+
homepage: http://github.com/sealink/activerecord_null_object
|
186
|
+
licenses:
|
187
|
+
- MIT
|
44
188
|
post_install_message:
|
45
|
-
rdoc_options:
|
46
|
-
|
47
|
-
require_paths:
|
189
|
+
rdoc_options: []
|
190
|
+
require_paths:
|
48
191
|
- lib
|
49
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
192
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
193
|
+
none: false
|
194
|
+
requirements:
|
195
|
+
- - ! '>='
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '0'
|
198
|
+
segments:
|
199
|
+
- 0
|
200
|
+
hash: 1262034008497264332
|
201
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
202
|
+
none: false
|
203
|
+
requirements:
|
204
|
+
- - ! '>='
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '0'
|
207
|
+
segments:
|
208
|
+
- 0
|
209
|
+
hash: 1262034008497264332
|
61
210
|
requirements: []
|
62
|
-
|
63
211
|
rubyforge_project:
|
64
|
-
rubygems_version: 1.
|
212
|
+
rubygems_version: 1.8.25
|
65
213
|
signing_key:
|
66
|
-
specification_version:
|
214
|
+
specification_version: 3
|
67
215
|
summary: Implements the Null Object Pattern for nil values in ActiveRecord associations.
|
68
|
-
test_files:
|
216
|
+
test_files:
|
69
217
|
- spec/belongs_to_spec.rb
|
218
|
+
- spec/has_one_spec.rb
|
70
219
|
- spec/null_object_spec.rb
|
71
220
|
- spec/schema.rb
|
221
|
+
- spec/spec.opts
|
72
222
|
- spec/spec_helper.rb
|
data/README
DELETED
data/init.rb
DELETED
data/lib/null_object.rb
DELETED
data/spec/database.yml
DELETED