active_null 0.0.6 → 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.
- checksums.yaml +4 -4
- data/README.md +15 -2
- data/active_null.gemspec +3 -2
- data/circle.yml +3 -0
- data/lib/active_null/null_model_builder.rb +13 -3
- data/lib/active_null/version.rb +1 -1
- data/lib/active_null.rb +20 -2
- data/spec/active_null_spec.rb +8 -1
- data/spec/models.rb +7 -3
- data/spec/null_spec.rb +67 -0
- data/spec/schema.rb +9 -3
- data/spec/spec_helper.rb +3 -0
- metadata +24 -8
- data/.travis.yml +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 34802b6bb45c168b836473546d630a125fe6b116
|
4
|
+
data.tar.gz: db5beef0d960320f86938d4a04cc38b22d9be4bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53077a09ae14ecb32e5ef97df52b7178580fabde3cb0f9e5136219e9e6fdabae7eefa200986d95c899a76c76ec682d237a222ebcac9f978422979d82377c6d9d
|
7
|
+
data.tar.gz: d9a9dbf632553cf2eaa5ec794b17a1fd83b3f510cd77d81eeaa94d47c1cd5960fb3c2ca2b88f641f83279b48ada6168af5fbf1d28c1b1fbd52d0218c317e0011
|
data/README.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
[](https://circleci.com/gh/Originate/active_null)
|
2
|
+
[](https://coveralls.io/github/Originate/active_null?branch=master)
|
3
|
+
[](https://codeclimate.com/github/Originate/active_null)
|
4
|
+
|
1
5
|
# ActiveNull
|
2
6
|
|
3
7
|
Using Null Objects can make life a lot easier and avoid having excessive `nil?` checks.
|
@@ -34,13 +38,11 @@ For each model you would like to be null aware, `extend ActiveNull`.
|
|
34
38
|
class Post < ActiveRecord::Base
|
35
39
|
extend ActiveNull
|
36
40
|
has_many :comments
|
37
|
-
null_model
|
38
41
|
end
|
39
42
|
|
40
43
|
class Comment < ActiveRecord::Base
|
41
44
|
extend ActiveNull
|
42
45
|
belongs_to :post
|
43
|
-
null_model
|
44
46
|
end
|
45
47
|
```
|
46
48
|
|
@@ -74,6 +76,17 @@ class Post < ActiveRecord::Base
|
|
74
76
|
end
|
75
77
|
```
|
76
78
|
|
79
|
+
When using polymorphic relationships, ActiveNull must be told a default
|
80
|
+
model to use for the Null Object representation.
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
class Post < ActiveRecord::Base
|
84
|
+
extend ActiveNull
|
85
|
+
belongs_to :author, polymorphic: true
|
86
|
+
null_defaults_for_polymorphic author: 'User'
|
87
|
+
end
|
88
|
+
```
|
89
|
+
|
77
90
|
If you have `Draper` included in your project, the Null Object versions of
|
78
91
|
your model will respond as expected to `decorate`.
|
79
92
|
|
data/active_null.gemspec
CHANGED
@@ -23,7 +23,8 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
24
24
|
spec.add_development_dependency 'rake'
|
25
25
|
spec.add_development_dependency 'rspec'
|
26
|
-
spec.add_development_dependency 'activerecord', '~> 4.
|
26
|
+
spec.add_development_dependency 'activerecord', '~> 4.2'
|
27
27
|
spec.add_development_dependency 'sqlite3'
|
28
|
-
spec.add_development_dependency 'draper', '~> 1
|
28
|
+
spec.add_development_dependency 'draper', '~> 2.1'
|
29
|
+
spec.add_development_dependency 'coveralls'
|
29
30
|
end
|
data/circle.yml
ADDED
@@ -15,12 +15,22 @@ module ActiveNull
|
|
15
15
|
config.impersonate model
|
16
16
|
|
17
17
|
model.reflect_on_all_associations.each do |relation|
|
18
|
+
klass = begin
|
19
|
+
if relation.options[:polymorphic]
|
20
|
+
model.polymorphic_null_defaults[relation.name].constantize
|
21
|
+
else
|
22
|
+
relation.klass
|
23
|
+
end
|
24
|
+
rescue
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
next unless klass
|
18
28
|
if relation.collection?
|
19
|
-
define_method(relation.name) {
|
29
|
+
define_method(relation.name) { klass.none }
|
20
30
|
else
|
21
31
|
define_method(relation.name) do
|
22
|
-
return unless
|
23
|
-
|
32
|
+
return unless klass.respond_to? :null
|
33
|
+
klass.null
|
24
34
|
end
|
25
35
|
end
|
26
36
|
end
|
data/lib/active_null/version.rb
CHANGED
data/lib/active_null.rb
CHANGED
@@ -6,6 +6,14 @@ module ActiveNull
|
|
6
6
|
null_class.get
|
7
7
|
end
|
8
8
|
|
9
|
+
def null_defaults_for_polymorphic mappings
|
10
|
+
@polymorphic_null_defaults = mappings
|
11
|
+
end
|
12
|
+
|
13
|
+
def polymorphic_null_defaults
|
14
|
+
@polymorphic_null_defaults || {}
|
15
|
+
end
|
16
|
+
|
9
17
|
def null_model(&block)
|
10
18
|
@null_model_overrides = if block_given?
|
11
19
|
Module.new.tap { |m| m.module_eval(&block) }
|
@@ -19,11 +27,21 @@ module ActiveNull
|
|
19
27
|
def null_associations
|
20
28
|
self.reflect_on_all_associations.each do |relation|
|
21
29
|
unless relation.collection?
|
30
|
+
klass = begin
|
31
|
+
if relation.options[:polymorphic]
|
32
|
+
polymorphic_null_defaults[relation.name]
|
33
|
+
elsif relation.klass
|
34
|
+
relation.klass.name
|
35
|
+
end
|
36
|
+
rescue
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
next unless klass
|
22
40
|
class_eval <<-CODE
|
23
41
|
def #{relation.name}(*args)
|
24
42
|
result = association(:#{relation.name}).reader(*args)
|
25
|
-
return result if result || !#{
|
26
|
-
#{
|
43
|
+
return result if result || !#{klass}.respond_to?(:null)
|
44
|
+
#{klass}.null
|
27
45
|
end
|
28
46
|
CODE
|
29
47
|
end
|
data/spec/active_null_spec.rb
CHANGED
@@ -4,10 +4,11 @@ describe ActiveNull do
|
|
4
4
|
it 'defines the null class only when accessing it for the first time (ie: with a .null or .null_class call)' do
|
5
5
|
expect(Object.const_defined? 'NullPost').to be_falsey
|
6
6
|
expect(Object.const_defined? 'NullMicroPost').to be_falsey
|
7
|
-
expect(Post.null).to be_instance_of
|
7
|
+
expect(Post.null).to be_instance_of NullPost
|
8
8
|
expect(MicroPost.null_class).to eq NullMicroPost
|
9
9
|
expect(Object.const_defined? 'NullPost').to be_truthy
|
10
10
|
expect(Object.const_defined? 'NullMicroPost').to be_truthy
|
11
|
+
expect(Test::TestModel.null).to be_instance_of Test::NullTestModel
|
11
12
|
end
|
12
13
|
|
13
14
|
describe '.null_class' do
|
@@ -24,6 +25,10 @@ describe ActiveNull do
|
|
24
25
|
specify { expect(Post.null.override).to eq 'I am an override.' }
|
25
26
|
end
|
26
27
|
|
28
|
+
describe '.find_by' do
|
29
|
+
specify { expect(Test::TestModel.find_by(id: 42)).to be_instance_of(Test::NullTestModel) }
|
30
|
+
end
|
31
|
+
|
27
32
|
describe 'a has many' do
|
28
33
|
specify { expect(Post.null.comments).to eq [] }
|
29
34
|
specify { expect(Post.null.comments).to be_instance_of(Comment::ActiveRecord_Relation) }
|
@@ -34,6 +39,8 @@ describe ActiveNull do
|
|
34
39
|
describe 'a belongs to' do
|
35
40
|
specify { expect(Comment.null.post).to be_instance_of(NullPost) }
|
36
41
|
specify { expect(Comment.new.post).to be_instance_of(NullPost) }
|
42
|
+
specify { expect(Comment.null.author).to be_instance_of(NullUser) }
|
43
|
+
specify { expect(Comment.new.author).to be_instance_of(NullUser) }
|
37
44
|
end
|
38
45
|
|
39
46
|
it 'supports draper' do
|
data/spec/models.rb
CHANGED
@@ -10,13 +10,18 @@ end
|
|
10
10
|
|
11
11
|
class MicroPost < Post
|
12
12
|
extend ActiveNull
|
13
|
-
|
13
|
+
end
|
14
|
+
|
15
|
+
class User < ActiveRecord::Base
|
16
|
+
extend ActiveNull
|
17
|
+
has_many :comments, as: :author
|
14
18
|
end
|
15
19
|
|
16
20
|
class Comment < ActiveRecord::Base
|
17
21
|
extend ActiveNull
|
18
22
|
belongs_to :post
|
19
|
-
|
23
|
+
belongs_to :author, polymorphic: true
|
24
|
+
null_defaults_for_polymorphic author: 'User'
|
20
25
|
end
|
21
26
|
|
22
27
|
class NullPostDecorator < Draper::Decorator
|
@@ -30,6 +35,5 @@ end
|
|
30
35
|
module Test
|
31
36
|
class TestModel < ActiveRecord::Base
|
32
37
|
extend ActiveNull
|
33
|
-
null_model
|
34
38
|
end
|
35
39
|
end
|
data/spec/null_spec.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Null Models' do
|
4
|
+
subject(:null_model) { Test::TestModel.null }
|
5
|
+
|
6
|
+
describe '#nil?' do
|
7
|
+
specify { expect(null_model.nil?).to be_truthy }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#present?' do
|
11
|
+
specify { expect(null_model.present?).to be_falsey }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#blank?' do
|
15
|
+
specify { expect(null_model.blank?).to be_truthy }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#to_json' do
|
19
|
+
specify { expect(null_model.to_json).to eq '{}' }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'Decoratable Null Models' do
|
23
|
+
subject(:null_model) { Post.null }
|
24
|
+
|
25
|
+
describe '#decorate' do
|
26
|
+
specify { expect(null_model.decorate).to be_decorated_with(null_model.decorator_class) }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#decorator_class?' do
|
30
|
+
specify { expect(null_model.decorator_class?).to eq NullPostDecorator }
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#decorator_class' do
|
34
|
+
specify { expect(null_model.decorator_class).to eq NullPostDecorator }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when not yet decorated' do
|
38
|
+
describe '#decorated?' do
|
39
|
+
specify { expect(null_model.decorated?).to be_falsey }
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#decorated_with?' do
|
43
|
+
specify { expect(null_model.decorated_with?(null_model.decorator_class)).to be_falsey }
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#applied_decorators' do
|
47
|
+
specify { expect(null_model.applied_decorators).to eq [] }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when decorated' do
|
52
|
+
subject(:null_model) { Post.null.decorate }
|
53
|
+
|
54
|
+
describe '#decorated?' do
|
55
|
+
specify { expect(null_model.decorated?).to be_truthy }
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#decorated_with?' do
|
59
|
+
specify { expect(null_model.decorated_with?(null_model.decorator_class)).to be_truthy }
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#applied_decorators' do
|
63
|
+
specify { expect(null_model.applied_decorators).to eq [NullPostDecorator] }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/spec/schema.rb
CHANGED
@@ -4,16 +4,22 @@ ActiveRecord::Schema.define do
|
|
4
4
|
create_table :posts, force: true do |t|
|
5
5
|
t.string :title
|
6
6
|
t.string :_type
|
7
|
-
t.timestamps
|
7
|
+
t.timestamps null: true
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table :users, force: true do |t|
|
11
|
+
t.string :name
|
12
|
+
t.timestamps null: true
|
8
13
|
end
|
9
14
|
|
10
15
|
create_table :comments, force: true do |t|
|
11
16
|
t.string :content
|
12
17
|
t.references :post
|
13
|
-
t.
|
18
|
+
t.references :author, polymorphic: true
|
19
|
+
t.timestamps null: true
|
14
20
|
end
|
15
21
|
|
16
22
|
create_table :test_models, force: true do |t|
|
17
|
-
t.timestamps
|
23
|
+
t.timestamps null: true
|
18
24
|
end
|
19
25
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_null
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- alexpeachey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: naught
|
@@ -72,14 +72,14 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '4.
|
75
|
+
version: '4.2'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '4.
|
82
|
+
version: '4.2'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: sqlite3
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,14 +100,28 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '1
|
103
|
+
version: '2.1'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '1
|
110
|
+
version: '2.1'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: coveralls
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
111
125
|
description: Make ActiveRecord null model aware.
|
112
126
|
email:
|
113
127
|
- alex.peachey@originate.com
|
@@ -117,17 +131,18 @@ extra_rdoc_files: []
|
|
117
131
|
files:
|
118
132
|
- ".gitignore"
|
119
133
|
- ".rspec"
|
120
|
-
- ".travis.yml"
|
121
134
|
- Gemfile
|
122
135
|
- LICENSE.txt
|
123
136
|
- README.md
|
124
137
|
- Rakefile
|
125
138
|
- active_null.gemspec
|
139
|
+
- circle.yml
|
126
140
|
- lib/active_null.rb
|
127
141
|
- lib/active_null/null_model_builder.rb
|
128
142
|
- lib/active_null/version.rb
|
129
143
|
- spec/active_null_spec.rb
|
130
144
|
- spec/models.rb
|
145
|
+
- spec/null_spec.rb
|
131
146
|
- spec/schema.rb
|
132
147
|
- spec/spec_helper.rb
|
133
148
|
homepage: https://github.com/Originate/active_null
|
@@ -150,12 +165,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
165
|
version: '0'
|
151
166
|
requirements: []
|
152
167
|
rubyforge_project:
|
153
|
-
rubygems_version: 2.4.
|
168
|
+
rubygems_version: 2.4.6
|
154
169
|
signing_key:
|
155
170
|
specification_version: 4
|
156
171
|
summary: Make ActiveRecord null model aware.
|
157
172
|
test_files:
|
158
173
|
- spec/active_null_spec.rb
|
159
174
|
- spec/models.rb
|
175
|
+
- spec/null_spec.rb
|
160
176
|
- spec/schema.rb
|
161
177
|
- spec/spec_helper.rb
|
data/.travis.yml
DELETED