activerecord-null 0.1.4 → 0.1.5
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/CHANGELOG.md +18 -4
- data/README.md +75 -0
- data/lib/activerecord/null/mimic.rb +1 -1
- data/lib/activerecord/null/version.rb +1 -1
- data/lib/activerecord/null.rb +140 -41
- data/test/activerecord/test_void.rb +245 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a56f2bfbaf5d498a54f2698e96dc1d460b6a9036ed1c6946e54bcbf724a782c9
|
|
4
|
+
data.tar.gz: 4575ab2f7ffabae11b05bf8429acb57c0810840fd7e996902691f4758d63ce81
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5f737ae853ffbdf31b4ef323e313f9a844f7b549d2bb3a7aa8d5547af94bfb0779b5d2f099a47b11f6ff4b3a48f163e842d68e8c3efb8b52e519a08ae30dc620
|
|
7
|
+
data.tar.gz: e0af61bf86c190fb5e5ccf05eb7d8ec13f0cbb51e59b48e36eb3e0be1b29f3925ea69e778e391c2b0b700d7e1e053ab801db4840fe4e1ae91a130772b98c3132
|
data/CHANGELOG.md
CHANGED
|
@@ -5,14 +5,28 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [0.1.
|
|
8
|
+
## [0.1.5] - 2025-11-19
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Void() method for defining non-singleton null objects (0e89194)
|
|
13
|
+
- Model.void(attributes) for creating instances with attribute overrides (0e89194)
|
|
9
14
|
|
|
10
15
|
### Changed
|
|
11
16
|
|
|
12
|
-
-
|
|
17
|
+
- Mimic module now delegates table_name to parent model (c6f3956)
|
|
18
|
+
- Extracted create_null_class, setup_singleton_attributes, setup_instance_attributes helpers (b0a77f8)
|
|
19
|
+
- Pass class_name to the Null() or Void() methods with an alternative class name. (d3284c4)
|
|
20
|
+
|
|
21
|
+
## [0.1.5] - 2025-11-19
|
|
22
|
+
|
|
23
|
+
### Added
|
|
13
24
|
|
|
14
|
-
|
|
25
|
+
- Void() method for defining non-singleton null objects (0e89194)
|
|
26
|
+
- Model.void(attributes) for creating instances with attribute overrides (0e89194)
|
|
15
27
|
|
|
16
28
|
### Changed
|
|
17
29
|
|
|
18
|
-
-
|
|
30
|
+
- Mimic module now delegates table_name to parent model (c6f3956)
|
|
31
|
+
- Extracted create_null_class, setup_singleton_attributes, setup_instance_attributes helpers (b0a77f8)
|
|
32
|
+
- Pass class_name to the Null() or Void() methods with an alternative class name. (d3284c4)
|
data/README.md
CHANGED
|
@@ -68,6 +68,81 @@ class User < ApplicationRecord
|
|
|
68
68
|
end
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
Customize the null class name:
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
class User < ApplicationRecord
|
|
75
|
+
Null(class_name: "Guest")
|
|
76
|
+
class << self
|
|
77
|
+
alias_method :null, :guest
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
User.guest # returns a User::Guest instance
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Void Objects
|
|
85
|
+
|
|
86
|
+
While `Null` objects are singletons (one instance per model), `Void` objects are instantiable null objects that allow creating multiple instances with different attribute values.
|
|
87
|
+
|
|
88
|
+
Define a void object for the model:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
class Product < ApplicationRecord
|
|
92
|
+
Void([:name] => "Unknown Product") do
|
|
93
|
+
def display_name
|
|
94
|
+
"Product: #{name}"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Create instances with custom attributes:
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
product1 = Product.void(name: "Widget")
|
|
104
|
+
product2 = Product.void(name: "Gadget")
|
|
105
|
+
|
|
106
|
+
product1.name # => "Widget"
|
|
107
|
+
product2.name # => "Gadget"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Each call to `.void` returns a new instance:
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
Product.void.object_id != Product.void.object_id # => true
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Instance attributes override defaults:
|
|
117
|
+
|
|
118
|
+
```ruby
|
|
119
|
+
product = Product.void(name: "Custom")
|
|
120
|
+
product.name # => "Custom" (overrides default "Unknown Product")
|
|
121
|
+
|
|
122
|
+
default_product = Product.void
|
|
123
|
+
default_product.name # => "Unknown Product" (uses default)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Void objects support the same features as Null objects:
|
|
127
|
+
- Callable defaults (lambdas/procs)
|
|
128
|
+
- Custom methods via block syntax
|
|
129
|
+
- Association handling
|
|
130
|
+
- All ActiveRecord query methods (`null?`, `persisted?`, etc.)
|
|
131
|
+
- Custom class names via `class_name:` parameter
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
class Product < ApplicationRecord
|
|
135
|
+
Void(class_name: "Placeholder")
|
|
136
|
+
class << self
|
|
137
|
+
alias_method :void, :placeholder
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
Product.placeholder # returns a Product::Placeholder instance
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Use `Null` when you need a single shared null object instance. Use `Void` when you need multiple null object instances with different attribute values.
|
|
145
|
+
|
|
71
146
|
## Development
|
|
72
147
|
|
|
73
148
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/activerecord/null.rb
CHANGED
|
@@ -12,44 +12,20 @@ module ActiveRecord
|
|
|
12
12
|
# extend ActiveRecord::Null
|
|
13
13
|
# end
|
|
14
14
|
module Null
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
# Null do
|
|
20
|
-
# def name = "None"
|
|
21
|
-
# end
|
|
22
|
-
# end
|
|
23
|
-
#
|
|
24
|
-
# Business.null # => #<Business::Null:0x0000000000000000>
|
|
25
|
-
# Business.null.name # => "None"
|
|
26
|
-
#
|
|
27
|
-
# class User < ApplicationRecord
|
|
28
|
-
# Null([:name, :team_name] => "Unknown")
|
|
29
|
-
# end
|
|
30
|
-
#
|
|
31
|
-
# User.null.name # => "Unknown"
|
|
32
|
-
# User.null.team_name # => "Unknown"
|
|
33
|
-
#
|
|
34
|
-
# @param inherit [Class] The class from which the Null object inherits attributes
|
|
35
|
-
# @param assignments [Array] The attributes to assign to the null object
|
|
36
|
-
def Null(inherit = self, assignments = {}, &)
|
|
37
|
-
if inherit.is_a?(Hash)
|
|
38
|
-
assignments = inherit
|
|
39
|
-
inherit = self
|
|
40
|
-
end
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
# Shared method to create Null or Void classes
|
|
18
|
+
def create_null_class(inherit, assignments, singleton:)
|
|
41
19
|
null_class = Class.new do
|
|
42
20
|
include ::ActiveRecord::Null::Mimic
|
|
43
21
|
|
|
44
22
|
mimics inherit
|
|
45
23
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
# Store assignments for lazy initialization
|
|
49
|
-
@_null_assignments = assignments
|
|
24
|
+
# Store assignments
|
|
25
|
+
instance_variable_set(:@_assignments, assignments)
|
|
50
26
|
|
|
51
27
|
class << self
|
|
52
|
-
attr_reader :
|
|
28
|
+
attr_reader :_assignments
|
|
53
29
|
|
|
54
30
|
def method_missing(method, ...)
|
|
55
31
|
mimic_model_class.respond_to?(method) ? mimic_model_class.send(method, ...) : super
|
|
@@ -58,7 +34,22 @@ module ActiveRecord
|
|
|
58
34
|
def respond_to_missing?(method, include_private = false)
|
|
59
35
|
mimic_model_class.respond_to?(method, include_private) || super
|
|
60
36
|
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if singleton
|
|
41
|
+
null_class.include(Singleton)
|
|
42
|
+
setup_singleton_attributes(null_class)
|
|
43
|
+
else
|
|
44
|
+
setup_instance_attributes(null_class)
|
|
45
|
+
end
|
|
61
46
|
|
|
47
|
+
null_class
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def setup_singleton_attributes(null_class)
|
|
51
|
+
null_class.class_eval do
|
|
52
|
+
class << self
|
|
62
53
|
# Override instance to initialize attributes lazily
|
|
63
54
|
def instance
|
|
64
55
|
initialize_attribute_methods unless @_attributes_initialized
|
|
@@ -68,21 +59,17 @@ module ActiveRecord
|
|
|
68
59
|
private
|
|
69
60
|
|
|
70
61
|
def initialize_attribute_methods
|
|
71
|
-
# Only initialize if table exists
|
|
72
62
|
return unless mimic_model_class.table_exists?
|
|
73
63
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
_null_assignments.each do |attributes, value|
|
|
64
|
+
if _assignments.any?
|
|
65
|
+
_assignments.each do |attributes, value|
|
|
77
66
|
define_attribute_methods(attributes, value:)
|
|
78
67
|
end
|
|
79
68
|
end
|
|
80
69
|
|
|
81
|
-
# Then define database attributes
|
|
82
70
|
nil_assignments = mimic_model_class.attribute_names
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
_null_assignments.each do |attributes, _|
|
|
71
|
+
if _assignments.any?
|
|
72
|
+
_assignments.each do |attributes, _|
|
|
86
73
|
nil_assignments -= attributes
|
|
87
74
|
end
|
|
88
75
|
end
|
|
@@ -92,13 +79,125 @@ module ActiveRecord
|
|
|
92
79
|
end
|
|
93
80
|
end
|
|
94
81
|
end
|
|
95
|
-
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def setup_instance_attributes(null_class)
|
|
85
|
+
null_class.class_eval do
|
|
86
|
+
def initialize(attributes = {})
|
|
87
|
+
@_instance_attributes = attributes
|
|
88
|
+
initialize_attribute_methods
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def initialize_attribute_methods
|
|
94
|
+
return unless self.class.mimic_model_class.table_exists?
|
|
95
|
+
|
|
96
|
+
assignments = self.class._assignments
|
|
97
|
+
|
|
98
|
+
if assignments.any?
|
|
99
|
+
assignments.each do |attributes, default_value|
|
|
100
|
+
attributes.each do |attr|
|
|
101
|
+
attr_sym = attr.to_sym
|
|
102
|
+
next if respond_to?(attr_sym)
|
|
103
|
+
|
|
104
|
+
define_singleton_method(attr_sym) do
|
|
105
|
+
if @_instance_attributes.key?(attr_sym)
|
|
106
|
+
@_instance_attributes[attr_sym]
|
|
107
|
+
elsif default_value.is_a?(Proc)
|
|
108
|
+
instance_exec(&default_value)
|
|
109
|
+
else
|
|
110
|
+
default_value
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
nil_assignments = self.class.mimic_model_class.attribute_names
|
|
118
|
+
if assignments.any?
|
|
119
|
+
assignments.each do |attributes, _|
|
|
120
|
+
nil_assignments -= attributes.map(&:to_s)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
96
123
|
|
|
97
|
-
|
|
124
|
+
nil_assignments.each do |attr|
|
|
125
|
+
attr_sym = attr.to_sym
|
|
126
|
+
next if respond_to?(attr_sym)
|
|
98
127
|
|
|
128
|
+
define_singleton_method(attr_sym) do
|
|
129
|
+
@_instance_attributes.key?(attr_sym) ? @_instance_attributes[attr_sym] : nil
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
public
|
|
137
|
+
|
|
138
|
+
# Define a Null class for the given class.
|
|
139
|
+
#
|
|
140
|
+
# @example
|
|
141
|
+
# class Business < ApplicationRecord
|
|
142
|
+
# Null do
|
|
143
|
+
# def name = "None"
|
|
144
|
+
# end
|
|
145
|
+
# end
|
|
146
|
+
#
|
|
147
|
+
# Business.null # => #<Business::Null:0x0000000000000000>
|
|
148
|
+
# Business.null.name # => "None"
|
|
149
|
+
#
|
|
150
|
+
# class User < ApplicationRecord
|
|
151
|
+
# Null([:name, :team_name] => "Unknown")
|
|
152
|
+
# end
|
|
153
|
+
#
|
|
154
|
+
# User.null.name # => "Unknown"
|
|
155
|
+
# User.null.team_name # => "Unknown"
|
|
156
|
+
#
|
|
157
|
+
# @param inherit [Class] The class from which the Null object inherits attributes
|
|
158
|
+
# @param assignments [Array] The attributes to assign to the null object
|
|
159
|
+
def Null(inherit = self, class_name: :Null, **assignments, &)
|
|
160
|
+
if inherit.is_a?(Hash)
|
|
161
|
+
assignments = inherit
|
|
162
|
+
inherit = self
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
null_class = create_null_class(inherit, assignments, singleton: true)
|
|
166
|
+
null_class.class_eval(&) if block_given?
|
|
167
|
+
|
|
168
|
+
inherit.const_set(class_name, null_class)
|
|
99
169
|
inherit.define_singleton_method(:null) { null_class.instance }
|
|
100
170
|
end
|
|
101
171
|
|
|
172
|
+
# Define a Void class for the given class.
|
|
173
|
+
# Unlike Null, Void objects are not singletons and can be instantiated
|
|
174
|
+
# multiple times with different attribute values.
|
|
175
|
+
#
|
|
176
|
+
# @example
|
|
177
|
+
# class Product < ApplicationRecord
|
|
178
|
+
# Void do
|
|
179
|
+
# def display_name = "Product: #{name}"
|
|
180
|
+
# end
|
|
181
|
+
# end
|
|
182
|
+
#
|
|
183
|
+
# product1 = Product.void(name: "Widget")
|
|
184
|
+
# product2 = Product.void(name: "Gadget")
|
|
185
|
+
#
|
|
186
|
+
# @param inherit [Class] The class from which the Void object inherits attributes
|
|
187
|
+
# @param assignments [Hash] The default attributes to assign to void objects
|
|
188
|
+
def Void(inherit = self, class_name: :Void, **assignments, &)
|
|
189
|
+
if inherit.is_a?(Hash)
|
|
190
|
+
assignments = inherit
|
|
191
|
+
inherit = self
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
void_class = create_null_class(inherit, assignments, singleton: false)
|
|
195
|
+
void_class.class_eval(&) if block_given?
|
|
196
|
+
|
|
197
|
+
inherit.const_set(class_name, void_class)
|
|
198
|
+
inherit.define_singleton_method(:void) { |attributes = {}| void_class.new(attributes) }
|
|
199
|
+
end
|
|
200
|
+
|
|
102
201
|
def self.extended(base)
|
|
103
202
|
base.define_method(:null?) { false }
|
|
104
203
|
end
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class ApplicationRecord < ActiveRecord::Base
|
|
6
|
+
primary_abstract_class
|
|
7
|
+
extend ActiveRecord::Null
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Product < ApplicationRecord
|
|
11
|
+
self.table_name = "businesses" # Reuse existing table
|
|
12
|
+
|
|
13
|
+
Void([:name] => "Unknown Product") do
|
|
14
|
+
def display_name
|
|
15
|
+
"Product: #{name}"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class Comment < ApplicationRecord
|
|
21
|
+
self.table_name = "posts" # Reuse existing table
|
|
22
|
+
|
|
23
|
+
Void()
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class ActiveRecord::TestVoid < Minitest::Spec
|
|
27
|
+
describe "Void class definition" do
|
|
28
|
+
it "creates Void constant on model" do
|
|
29
|
+
assert Product.const_defined?(:Void)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "Void class includes Mimic" do
|
|
33
|
+
assert Product::Void.include?(ActiveRecord::Null::Mimic)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "Void class does not include Singleton" do
|
|
37
|
+
refute Product::Void.include?(Singleton)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "defines .void method on model" do
|
|
41
|
+
assert Product.respond_to?(:void)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "Void can be defined without arguments" do
|
|
45
|
+
assert Comment.const_defined?(:Void)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe ".void instantiation" do
|
|
50
|
+
it "returns new instance each time" do
|
|
51
|
+
void1 = Product.void
|
|
52
|
+
void2 = Product.void
|
|
53
|
+
|
|
54
|
+
assert_instance_of Product::Void, void1
|
|
55
|
+
assert_instance_of Product::Void, void2
|
|
56
|
+
refute_equal void1.object_id, void2.object_id
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "creates instance with no arguments" do
|
|
60
|
+
void_obj = Product.void
|
|
61
|
+
|
|
62
|
+
assert_instance_of Product::Void, void_obj
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "creates instance with empty hash" do
|
|
66
|
+
void_obj = Product.void({})
|
|
67
|
+
|
|
68
|
+
assert_instance_of Product::Void, void_obj
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe "attribute handling" do
|
|
73
|
+
it "returns default value from hash syntax" do
|
|
74
|
+
void_obj = Product.void
|
|
75
|
+
|
|
76
|
+
assert_equal "Unknown Product", void_obj.name
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "allows instance attributes to override defaults" do
|
|
80
|
+
void_obj = Product.void(name: "Custom Product")
|
|
81
|
+
|
|
82
|
+
assert_equal "Custom Product", void_obj.name
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "database attributes default to nil" do
|
|
86
|
+
# Assuming businesses table doesn't have a 'price' column
|
|
87
|
+
void_obj = Product.void
|
|
88
|
+
|
|
89
|
+
# Name has a default, so it should return that
|
|
90
|
+
assert_equal "Unknown Product", void_obj.name
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "supports multiple instances with different attributes" do
|
|
94
|
+
void1 = Product.void(name: "Product A")
|
|
95
|
+
void2 = Product.void(name: "Product B")
|
|
96
|
+
|
|
97
|
+
assert_equal "Product A", void1.name
|
|
98
|
+
assert_equal "Product B", void2.name
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "instance attributes don't affect class defaults" do
|
|
102
|
+
void1 = Product.void(name: "Modified")
|
|
103
|
+
void2 = Product.void
|
|
104
|
+
|
|
105
|
+
assert_equal "Modified", void1.name
|
|
106
|
+
assert_equal "Unknown Product", void2.name
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe "custom methods from block" do
|
|
111
|
+
it "block-defined methods are accessible" do
|
|
112
|
+
void_obj = Product.void
|
|
113
|
+
|
|
114
|
+
assert_respond_to void_obj, :display_name
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "block methods can access attributes" do
|
|
118
|
+
void_obj = Product.void(name: "Special")
|
|
119
|
+
|
|
120
|
+
assert_equal "Product: Special", void_obj.display_name
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "block methods work with defaults" do
|
|
124
|
+
void_obj = Product.void
|
|
125
|
+
|
|
126
|
+
assert_equal "Product: Unknown Product", void_obj.display_name
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
describe "type checking" do
|
|
131
|
+
it "is_a?(Model) returns true" do
|
|
132
|
+
void_obj = Product.void
|
|
133
|
+
|
|
134
|
+
assert void_obj.is_a?(Product)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "is_a?(Model::Void) returns true" do
|
|
138
|
+
void_obj = Product.void
|
|
139
|
+
|
|
140
|
+
assert void_obj.is_a?(Product::Void)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "null? returns true" do
|
|
144
|
+
void_obj = Product.void
|
|
145
|
+
|
|
146
|
+
assert void_obj.null?
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "persisted? returns false" do
|
|
150
|
+
void_obj = Product.void
|
|
151
|
+
|
|
152
|
+
refute void_obj.persisted?
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "new_record? returns false" do
|
|
156
|
+
void_obj = Product.void
|
|
157
|
+
|
|
158
|
+
refute void_obj.new_record?
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it "destroyed? returns false" do
|
|
162
|
+
void_obj = Product.void
|
|
163
|
+
|
|
164
|
+
refute void_obj.destroyed?
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe "callable attribute values" do
|
|
169
|
+
it "supports callable defaults" do
|
|
170
|
+
test_class = Class.new(ApplicationRecord) do
|
|
171
|
+
def self.name
|
|
172
|
+
"CallableTest"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
self.table_name = "users"
|
|
176
|
+
|
|
177
|
+
Void([:name] => -> { "Computed Name" })
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
void_obj = test_class.void
|
|
181
|
+
|
|
182
|
+
assert_equal "Computed Name", void_obj.name
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it "callable defaults can access instance context" do
|
|
186
|
+
test_class = Class.new(ApplicationRecord) do
|
|
187
|
+
def self.name
|
|
188
|
+
"ContextTest"
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
self.table_name = "users"
|
|
192
|
+
|
|
193
|
+
Void([:name] => -> { "Hello" })
|
|
194
|
+
|
|
195
|
+
def greeting
|
|
196
|
+
"Welcome"
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
void_obj = test_class.void
|
|
201
|
+
|
|
202
|
+
assert_equal "Hello", void_obj.name
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
describe "integration with Null" do
|
|
207
|
+
it "Null and Void can coexist on same model" do
|
|
208
|
+
# Define both on a test class
|
|
209
|
+
test_class = Class.new(ApplicationRecord) do
|
|
210
|
+
def self.name
|
|
211
|
+
"TestModel"
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
self.table_name = "users"
|
|
215
|
+
|
|
216
|
+
Null([:name] => "Null Default")
|
|
217
|
+
Void([:name] => "Void Default")
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
null_obj = test_class.null
|
|
221
|
+
void_obj = test_class.void
|
|
222
|
+
|
|
223
|
+
assert_equal "Null Default", null_obj.name
|
|
224
|
+
assert_equal "Void Default", void_obj.name
|
|
225
|
+
assert_equal null_obj.object_id, test_class.null.object_id # Singleton
|
|
226
|
+
refute_equal void_obj.object_id, test_class.void.object_id # Not singleton
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
describe "model integration" do
|
|
231
|
+
it "respects table_name from parent model" do
|
|
232
|
+
assert_equal Product.table_name, Product::Void.table_name
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it "respects primary_key from parent model" do
|
|
236
|
+
assert_equal "id", Product::Void.primary_key
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it "has mimic_model_class reference" do
|
|
240
|
+
void_obj = Product.void
|
|
241
|
+
|
|
242
|
+
assert_equal Product, void_obj.mimic_model_class
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-null
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jim Gay
|
|
@@ -41,6 +41,7 @@ files:
|
|
|
41
41
|
- lib/activerecord/null/version.rb
|
|
42
42
|
- test/activerecord/test_lazy_loading.rb
|
|
43
43
|
- test/activerecord/test_null.rb
|
|
44
|
+
- test/activerecord/test_void.rb
|
|
44
45
|
- test/support/schema.rb
|
|
45
46
|
- test/test_helper.rb
|
|
46
47
|
homepage: https://github.com/SOFware/activerecord-null
|