attribute_extras 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +28 -7
- data/lib/attribute_extras/base_extensions.rb +8 -42
- data/lib/attribute_extras/extra_builder.rb +78 -0
- data/lib/attribute_extras/hook_builder.rb +49 -0
- data/lib/attribute_extras/version.rb +1 -1
- data/lib/attribute_extras.rb +35 -4
- data/test/base_extensions_test.rb +0 -12
- data/test/nullify_attributes_test.rb +27 -27
- data/test/strip_attributes_test.rb +27 -27
- data/test/test_classes.rb +38 -32
- data/test/truncate_attributes_test.rb +27 -39
- metadata +7 -9
- data/lib/attribute_extras/nullify_attributes.rb +0 -49
- data/lib/attribute_extras/strip_attributes.rb +0 -49
- data/lib/attribute_extras/truncate_attributes.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbe2cf428824264839a52d09fe981d4212785d06
|
4
|
+
data.tar.gz: f34788ebc3efdef5db35eea0c7951e3698732d8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81b22a9c17b95bbcde17c18ef0e38a329630e38cad3a054459e9b24cda64fe4ebcb11f13b75126fc40b572f2f32c2700375dc63ab819ebfba2b639f92f5eefdf
|
7
|
+
data.tar.gz: 023a5250dccab5535a615529e8dfdb3bff2940286ece963ce721272e6898c08adb6f3e445885d4c50d0b32cfe8c6fa4e7ec1ba6af7a19c532b93ef0bc553423d
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
## AttributeExtras
|
2
2
|
|
3
|
-
Use this gem for automatic behavior on attributes. It provides three class macros that can be used for managing attributes.
|
3
|
+
Use this gem for automatic behavior on attributes. It by default provides three class macros that can be used for managing attributes. You can also build your own macros that will automatically become available to you within your ActiveRecord models. By default each macro gets the options `:validator` and `:writer` and both are set to true. If you do not want the macros to validate or overwrite the attribute writers, you can pass false to those options.
|
4
4
|
|
5
5
|
### nullify_attributes
|
6
6
|
|
@@ -30,17 +30,15 @@ p.name # => 'value'
|
|
30
30
|
|
31
31
|
### truncate_attributes
|
32
32
|
|
33
|
-
Causes string attribute assignment to be truncated down to the maximum allowed value for that column.
|
33
|
+
Causes string attribute assignment to be truncated down to the maximum allowed value for that column.
|
34
34
|
|
35
35
|
```ruby
|
36
36
|
class Person < ActiveRecord::Base
|
37
|
-
truncate_attributes :
|
38
|
-
truncate_attributes :last_name, whiny: true
|
37
|
+
truncate_attributes :name
|
39
38
|
end
|
40
39
|
|
41
|
-
p = Person.new(
|
42
|
-
p.
|
43
|
-
p.save! # => ActiveRecord::RecordInvalid: Validation failed
|
40
|
+
p = Person.new(name: 'a' * 500)
|
41
|
+
p.name # => 'a' * limit
|
44
42
|
```
|
45
43
|
|
46
44
|
### Inheritance
|
@@ -69,6 +67,29 @@ Developer.nullified_attributes.map(&:attribute) # => [:email]
|
|
69
67
|
Developer.inherited_nullified_attributes.map(&:attribute) # => [:email, :name]
|
70
68
|
```
|
71
69
|
|
70
|
+
## Internals
|
71
|
+
|
72
|
+
If you want to register your own macros, you can do so with `AttributeExtras.register_extra`. Internally `attribute_extras` does this for the three macros listed above.
|
73
|
+
|
74
|
+
### `:nullify` Example
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
self.register_extra :nullify, ->(value, options){ value.presence },
|
78
|
+
past: :nullified,
|
79
|
+
validator: { format: { allow_nil: true, without: /\A\s*\z/ } }
|
80
|
+
```
|
81
|
+
|
82
|
+
### `:truncate` Example
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
self.register_extra :truncate, ->(value, options){ value.is_a?(String) ? value[0...options[:limit]] : value },
|
86
|
+
past: :truncated,
|
87
|
+
validator: ->(options){ { length: { maximum: options[:limit] } } },
|
88
|
+
options: ->(attribute){ { limit: self.columns_hash[attribute.to_s].limit } }
|
89
|
+
```
|
90
|
+
|
91
|
+
In this case the options is needed to build a hash of metadata about the attribute in question so that the validator option can change. The options hash is also passed in to the `truncate_attribute_extra` method so that you have access to that metadata.
|
92
|
+
|
72
93
|
## Additional information
|
73
94
|
|
74
95
|
### Contributing
|
@@ -1,44 +1,8 @@
|
|
1
1
|
module AttributeExtras
|
2
2
|
module BaseExtensions
|
3
3
|
|
4
|
-
# overrides the writer to set to nil if that value is blank
|
5
|
-
def nullify_attributes(*attributes)
|
6
|
-
if self.table_exists? and (non_attributes = attributes.map(&:to_s) - self.column_names).any?
|
7
|
-
raise ArgumentError, "Invalid attributes passed to nullify_attributes: #{non_attributes.join(', ')}"
|
8
|
-
end
|
9
|
-
|
10
|
-
include ::AttributeExtras::NullifyAttributes
|
11
|
-
|
12
|
-
attributes.each do |attribute|
|
13
|
-
define_method("#{attribute}=") do |value|
|
14
|
-
write_attribute(attribute, value.presence)
|
15
|
-
end
|
16
|
-
nullified_attributes << Modifier.new(attribute)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# overrides the writer to strip the value
|
21
|
-
def strip_attributes(*attributes)
|
22
|
-
string_columns = self.columns.select { |column| column.type == :string }.map(&:name)
|
23
|
-
if self.table_exists? and (non_attributes = attributes.map(&:to_s) - string_columns).any?
|
24
|
-
raise ArgumentError, <<-MSG.squish
|
25
|
-
Invalid attributes passed to strip_attributes: #{non_attributes.join(', ')};
|
26
|
-
attributes must be string columns
|
27
|
-
MSG
|
28
|
-
end
|
29
|
-
|
30
|
-
include ::AttributeExtras::StripAttributes
|
31
|
-
|
32
|
-
attributes.each do |attribute|
|
33
|
-
define_method("#{attribute}=") do |value|
|
34
|
-
write_attribute(attribute, value.is_a?(String) ? value.strip : value)
|
35
|
-
end
|
36
|
-
stripped_attributes << Modifier.new(attribute)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
4
|
# overrides the writer to truncate if that value is blank
|
41
|
-
def truncate_attributes(*attributes,
|
5
|
+
def truncate_attributes(*attributes, validator: false, writer: true)
|
42
6
|
string_columns = self.columns.select { |column| column.type == :string && !column.limit.nil? }.map(&:name)
|
43
7
|
if self.table_exists? and (non_attributes = attributes.map(&:to_s) - string_columns).any?
|
44
8
|
raise ArgumentError, <<-MSG.squish
|
@@ -53,15 +17,17 @@ module AttributeExtras
|
|
53
17
|
attributes.each do |attribute|
|
54
18
|
limit = self.columns_hash[attribute.to_s].limit
|
55
19
|
|
56
|
-
if
|
20
|
+
if validator
|
57
21
|
validates attribute, length: { maximum: limit }
|
58
|
-
|
59
|
-
|
22
|
+
end
|
23
|
+
|
24
|
+
if writer
|
60
25
|
define_method("#{attribute}=") do |value|
|
61
|
-
write_attribute(attribute, value
|
26
|
+
write_attribute(attribute, ::AttributeExtras::TruncateAttributes::FUNCTION[value, limit: limit])
|
62
27
|
end
|
63
|
-
@truncated_attributes << Modifier.new(attribute)
|
64
28
|
end
|
29
|
+
|
30
|
+
truncated_attributes << Modifier.new(attribute, limit: limit)
|
65
31
|
end
|
66
32
|
end
|
67
33
|
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module AttributeExtras
|
2
|
+
class ExtraBuilder
|
3
|
+
|
4
|
+
# store the given options
|
5
|
+
def initialize(verb, past, function, validator, options)
|
6
|
+
@verb = verb
|
7
|
+
@past = past
|
8
|
+
@function = function
|
9
|
+
@validator = validator
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
# build the extra
|
14
|
+
def build
|
15
|
+
concern = Module.new
|
16
|
+
concern.module_eval(concern_definition)
|
17
|
+
concern::ClassMethods.module_eval(&utilities_definition)
|
18
|
+
concern
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# the module definition for the concern
|
24
|
+
def concern_definition
|
25
|
+
<<-RUBY
|
26
|
+
extend ActiveSupport::Concern
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
def inherited_#{@past}_attributes
|
30
|
+
@inherited_#{@past}_attributes ||= begin
|
31
|
+
modifiers = []
|
32
|
+
self.ancestors.each do |ancestor|
|
33
|
+
break if ancestor == ActiveRecord::Base
|
34
|
+
if ancestor.respond_to?(:#{@past}_attributes)
|
35
|
+
modifiers += ancestor.#{@past}_attributes
|
36
|
+
end
|
37
|
+
end
|
38
|
+
modifiers
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def #{@past}_attributes
|
43
|
+
@#{@past}_attributes ||= []
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def #{@verb}_attributes
|
48
|
+
set_#{@past}_attributes
|
49
|
+
self.changed? ? self.save : true
|
50
|
+
end
|
51
|
+
|
52
|
+
def #{@verb}_attributes!
|
53
|
+
set_#{@past}_attributes
|
54
|
+
self.changed? ? self.save : true
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def set_#{@past}_attributes
|
60
|
+
self.class.inherited_#{@past}_attributes.each do |modifier|
|
61
|
+
attribute = modifier.attribute
|
62
|
+
self.send(:\"\#{attribute}=\", self.class.#{@verb}_attribute_extra(self.send(attribute), modifier.options))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
RUBY
|
66
|
+
end
|
67
|
+
|
68
|
+
# the module definition for the utilities
|
69
|
+
def utilities_definition
|
70
|
+
verb, function, validator, options = @verb, @function, @validator, @options
|
71
|
+
proc do
|
72
|
+
define_method(:"#{verb}_attribute_extra", function)
|
73
|
+
define_method(:"#{verb}_validator_for", validator)
|
74
|
+
define_method(:"#{verb}_options_for", options)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module AttributeExtras
|
2
|
+
class HookBuilder
|
3
|
+
|
4
|
+
# store the given options
|
5
|
+
def initialize(verb, past)
|
6
|
+
@verb = verb
|
7
|
+
@past = past
|
8
|
+
end
|
9
|
+
|
10
|
+
# build the hook
|
11
|
+
def build
|
12
|
+
hook = Module.new
|
13
|
+
hook.module_eval(module_definition)
|
14
|
+
hook
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# the module definition for the extra
|
20
|
+
def module_definition
|
21
|
+
<<-RUBY
|
22
|
+
def #{@verb}_attributes(*attributes, validator: true, writer: true)
|
23
|
+
if self.table_exists? && (non_attributes = attributes.map(&:to_s) - self.column_names).any?
|
24
|
+
raise ArgumentError, "Invalid attributes passed to #{@verb}_attributes: \#{non_attributes.join(', ')}"
|
25
|
+
end
|
26
|
+
|
27
|
+
include ::AttributeExtras::#{@verb.capitalize}Attributes
|
28
|
+
|
29
|
+
attributes.each do |attribute|
|
30
|
+
options = self.#{@verb}_options_for(attribute)
|
31
|
+
modifier = Modifier.new(attribute, options)
|
32
|
+
|
33
|
+
if validator
|
34
|
+
validates attribute, self.#{@verb}_validator_for(modifier.options)
|
35
|
+
end
|
36
|
+
|
37
|
+
if writer
|
38
|
+
define_method("\#{attribute}=") do |value|
|
39
|
+
write_attribute(attribute, self.class.#{@verb}_attribute_extra(value, modifier.options))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#{@past}_attributes << modifier
|
44
|
+
end
|
45
|
+
end
|
46
|
+
RUBY
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/attribute_extras.rb
CHANGED
@@ -1,8 +1,39 @@
|
|
1
1
|
require 'attribute_extras/base_extensions'
|
2
|
+
require 'attribute_extras/extra_builder'
|
3
|
+
require 'attribute_extras/hook_builder'
|
4
|
+
require 'attribute_extras/modifier'
|
2
5
|
|
3
6
|
module AttributeExtras
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
7
|
+
|
8
|
+
# the registered extras
|
9
|
+
mattr_accessor :extras
|
10
|
+
self.extras = []
|
11
|
+
|
12
|
+
# register the extra and build the functions
|
13
|
+
def self.register_extra(verb, function, past:, validator:, options: nil)
|
14
|
+
past ||= verb
|
15
|
+
compiled_validator = validator.is_a?(Proc) ? validator : ->(options){ validator }
|
16
|
+
options ||= ->(attribute){ {} }
|
17
|
+
|
18
|
+
extra = ExtraBuilder.new(verb, past, function, compiled_validator, options).build
|
19
|
+
hook = HookBuilder.new(verb, past).build
|
20
|
+
|
21
|
+
self.const_set(:"#{verb.capitalize}Attributes", extra)
|
22
|
+
self.extras << extra
|
23
|
+
ActiveRecord::Base.extend(hook)
|
24
|
+
end
|
25
|
+
|
26
|
+
self.register_extra :nullify, ->(value, options){ value.presence },
|
27
|
+
past: :nullified,
|
28
|
+
validator: { format: { allow_nil: true, without: /\A\s*\z/ } }
|
29
|
+
|
30
|
+
self.register_extra :strip, ->(value, options){ value.is_a?(String) ? value.strip : value },
|
31
|
+
past: :stripped,
|
32
|
+
validator: { format: { without: /\A\s+|\s+\z/ } }
|
33
|
+
|
34
|
+
self.register_extra :truncate, ->(value, options){ value.is_a?(String) ? value[0...options[:limit]] : value },
|
35
|
+
past: :truncated,
|
36
|
+
validator: ->(options){ { length: { maximum: options[:limit] } } },
|
37
|
+
options: ->(attribute){ { limit: self.columns_hash[attribute.to_s].limit } }
|
38
|
+
|
8
39
|
end
|
@@ -12,7 +12,6 @@ class BaseExtensionsTest < ActiveSupport::TestCase
|
|
12
12
|
def test_nullify_attributes_success
|
13
13
|
klass = address_class(:nullify_attributes, :first_line, :second_line)
|
14
14
|
assert_equal klass.nullified_attributes.map(&:attribute), [:first_line, :second_line]
|
15
|
-
assert_includes klass.instance_method(:first_line=).source_location.first, 'attribute_extras/base_extensions'
|
16
15
|
end
|
17
16
|
|
18
17
|
def test_strip_attributes_failure
|
@@ -25,7 +24,6 @@ class BaseExtensionsTest < ActiveSupport::TestCase
|
|
25
24
|
def test_strip_attributes_success
|
26
25
|
klass = address_class(:strip_attributes, :first_line, :second_line)
|
27
26
|
assert_equal klass.stripped_attributes.map(&:attribute), [:first_line, :second_line]
|
28
|
-
assert_includes klass.instance_method(:first_line=).source_location.first, 'attribute_extras/base_extensions'
|
29
27
|
end
|
30
28
|
|
31
29
|
def test_truncate_attributes_failure
|
@@ -38,16 +36,6 @@ class BaseExtensionsTest < ActiveSupport::TestCase
|
|
38
36
|
def test_truncate_attributes_success
|
39
37
|
klass = address_class(:truncate_attributes, :first_line, :second_line)
|
40
38
|
assert_equal klass.truncated_attributes.map(&:attribute), [:first_line, :second_line]
|
41
|
-
assert_includes klass.instance_method(:first_line=).source_location.first, 'attribute_extras/base_extensions'
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_truncate_attributes_success_whiny
|
45
|
-
klass = address_class(:truncate_attributes, :first_line, :second_line, whiny: true)
|
46
|
-
assert_equal klass.truncated_attributes.map(&:attribute), [:first_line, :second_line]
|
47
|
-
|
48
|
-
validator = klass.validators_on(:first_line).first
|
49
|
-
assert_kind_of ActiveModel::Validations::LengthValidator, validator
|
50
|
-
assert_equal validator.options[:maximum], COLUMN_LIMIT
|
51
39
|
end
|
52
40
|
|
53
41
|
private
|
@@ -1,24 +1,14 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class NullifyAttributesTest < ActiveSupport::TestCase
|
4
|
-
def test_nullified_name=
|
5
|
-
person = Person.new
|
6
|
-
person.nullified_name = ' '
|
7
|
-
assert_nil person.nullified_name
|
8
|
-
|
9
|
-
person.nullified_name = nil
|
10
|
-
assert_nil person.nullified_name
|
11
|
-
|
12
|
-
person.nullified_name = 'test_value'
|
13
|
-
assert_equal 'test_value', person.nullified_name
|
14
|
-
end
|
15
|
-
|
16
4
|
def test_nullify_attributes
|
17
5
|
person = Person.new
|
18
6
|
person.set_blank_attributes
|
19
7
|
|
20
8
|
assert person.nullify_attributes
|
21
|
-
|
9
|
+
person_attributes.each do |attribute|
|
10
|
+
assert_nil person.send(attribute)
|
11
|
+
end
|
22
12
|
end
|
23
13
|
|
24
14
|
def test_nullify_attributes!
|
@@ -26,7 +16,9 @@ class NullifyAttributesTest < ActiveSupport::TestCase
|
|
26
16
|
person.set_blank_attributes
|
27
17
|
|
28
18
|
assert person.nullify_attributes!
|
29
|
-
|
19
|
+
person_attributes.each do |attribute|
|
20
|
+
assert_nil person.send(attribute)
|
21
|
+
end
|
30
22
|
end
|
31
23
|
|
32
24
|
def test_nullified_attributes_inheritance
|
@@ -34,24 +26,32 @@ class NullifyAttributesTest < ActiveSupport::TestCase
|
|
34
26
|
architect.set_blank_attributes
|
35
27
|
|
36
28
|
assert architect.nullify_attributes
|
37
|
-
|
38
|
-
|
29
|
+
architect_attributes.each do |attribute|
|
30
|
+
assert_nil architect.send(attribute)
|
31
|
+
end
|
39
32
|
end
|
40
33
|
|
41
34
|
def test_nullified_attributes
|
42
|
-
assert_equal Person.nullified_attributes.map(&:attribute)
|
43
|
-
|
44
|
-
assert_equal
|
45
|
-
assert_equal Architect.nullified_attributes.map(&:attribute),
|
46
|
-
[:other_nullified_name]
|
35
|
+
assert_equal person_attributes, Person.nullified_attributes.map(&:attribute)
|
36
|
+
assert_empty Developer.nullified_attributes.map(&:attribute)
|
37
|
+
assert_equal [:architect_nullified], Architect.nullified_attributes.map(&:attribute)
|
47
38
|
end
|
48
39
|
|
49
40
|
def test_inherited_nullified_attributes
|
50
|
-
assert_equal Person.inherited_nullified_attributes.map(&:attribute)
|
51
|
-
|
52
|
-
assert_equal
|
53
|
-
[:nullified_name]
|
54
|
-
assert_equal Architect.inherited_nullified_attributes.map(&:attribute),
|
55
|
-
[:other_nullified_name, :nullified_name]
|
41
|
+
assert_equal person_attributes, Person.inherited_nullified_attributes.map(&:attribute)
|
42
|
+
assert_equal person_attributes, Developer.inherited_nullified_attributes.map(&:attribute)
|
43
|
+
assert_equal architect_attributes, Architect.inherited_nullified_attributes.map(&:attribute)
|
56
44
|
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# a list of the attributes that are nullified on the architect class
|
49
|
+
def architect_attributes
|
50
|
+
@architect_attributes ||= ([:architect_nullified] + person_attributes)
|
51
|
+
end
|
52
|
+
|
53
|
+
# a list of the attributes that are nullified on the person class
|
54
|
+
def person_attributes
|
55
|
+
@person_attributes ||= [:person_nullified_one, :person_nullified_two, :person_nullified_three, :person_nullified_four]
|
56
|
+
end
|
57
57
|
end
|
@@ -1,24 +1,14 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class StripAttributesTest < ActiveSupport::TestCase
|
4
|
-
def test_stripped_name=
|
5
|
-
person = Person.new
|
6
|
-
person.stripped_name = ' test value '
|
7
|
-
assert_equal 'test value', person.stripped_name
|
8
|
-
|
9
|
-
person.stripped_name = nil
|
10
|
-
assert_nil person.stripped_name
|
11
|
-
|
12
|
-
person.stripped_name = 'test value'
|
13
|
-
assert_equal 'test value', person.stripped_name
|
14
|
-
end
|
15
|
-
|
16
4
|
def test_strip_attributes
|
17
5
|
person = Person.new
|
18
6
|
person.set_padded_attributes
|
19
7
|
|
20
8
|
assert person.strip_attributes
|
21
|
-
|
9
|
+
person_attributes.each do |attribute|
|
10
|
+
assert_equal Person.stripped_value, person.send(attribute)
|
11
|
+
end
|
22
12
|
end
|
23
13
|
|
24
14
|
def test_strip_attributes!
|
@@ -26,7 +16,9 @@ class StripAttributesTest < ActiveSupport::TestCase
|
|
26
16
|
person.set_padded_attributes
|
27
17
|
|
28
18
|
assert person.strip_attributes!
|
29
|
-
|
19
|
+
person_attributes.each do |attribute|
|
20
|
+
assert_equal Person.stripped_value, person.send(attribute)
|
21
|
+
end
|
30
22
|
end
|
31
23
|
|
32
24
|
def test_stripped_attributes_inheritance
|
@@ -34,24 +26,32 @@ class StripAttributesTest < ActiveSupport::TestCase
|
|
34
26
|
architect.set_padded_attributes
|
35
27
|
|
36
28
|
assert architect.strip_attributes
|
37
|
-
|
38
|
-
|
29
|
+
architect_attributes.each do |attribute|
|
30
|
+
assert_equal Architect.stripped_value, architect.send(attribute)
|
31
|
+
end
|
39
32
|
end
|
40
33
|
|
41
34
|
def test_stripped_attributes
|
42
|
-
assert_equal Person.stripped_attributes.map(&:attribute)
|
43
|
-
|
44
|
-
assert_equal
|
45
|
-
assert_equal Architect.stripped_attributes.map(&:attribute),
|
46
|
-
[:other_stripped_name]
|
35
|
+
assert_equal person_attributes, Person.stripped_attributes.map(&:attribute)
|
36
|
+
assert_empty Developer.stripped_attributes.map(&:attribute)
|
37
|
+
assert_equal [:architect_stripped], Architect.stripped_attributes.map(&:attribute)
|
47
38
|
end
|
48
39
|
|
49
40
|
def test_inherited_stripped_attributes
|
50
|
-
assert_equal Person.inherited_stripped_attributes.map(&:attribute)
|
51
|
-
|
52
|
-
assert_equal
|
53
|
-
[:stripped_name]
|
54
|
-
assert_equal Architect.inherited_stripped_attributes.map(&:attribute),
|
55
|
-
[:other_stripped_name, :stripped_name]
|
41
|
+
assert_equal person_attributes, Person.inherited_stripped_attributes.map(&:attribute)
|
42
|
+
assert_equal person_attributes, Developer.inherited_stripped_attributes.map(&:attribute)
|
43
|
+
assert_equal architect_attributes, Architect.inherited_stripped_attributes.map(&:attribute)
|
56
44
|
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# a list of the attributes that are stripped on the architect class
|
49
|
+
def architect_attributes
|
50
|
+
@architect_attributes ||= ([:architect_stripped] + person_attributes)
|
51
|
+
end
|
52
|
+
|
53
|
+
# a list of the attributes that are stripped on the person class
|
54
|
+
def person_attributes
|
55
|
+
@person_attributes ||= [:person_stripped_one, :person_stripped_two, :person_stripped_three, :person_stripped_four]
|
56
|
+
end
|
57
57
|
end
|
data/test/test_classes.rb
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
COLUMN_LIMIT = 255
|
2
|
+
NUMBERS = %w[one two three four]
|
2
3
|
|
3
4
|
ActiveRecord::Schema.define do
|
4
5
|
create_table :people, force: true do |t|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
t.string :truncated_whiny_name, limit: COLUMN_LIMIT
|
13
|
-
t.string :other_truncated_name, limit: COLUMN_LIMIT
|
6
|
+
%w[nullified stripped truncated].each do |prefix|
|
7
|
+
options = (prefix == 'truncated') ? { limit: COLUMN_LIMIT } : {}
|
8
|
+
NUMBERS.each do |number|
|
9
|
+
t.string "person_#{prefix}_#{number}", options
|
10
|
+
end
|
11
|
+
t.string "architect_#{prefix}", options
|
12
|
+
end
|
14
13
|
end
|
15
14
|
|
16
15
|
create_table :addresses, force: true do |t|
|
@@ -20,25 +19,32 @@ ActiveRecord::Schema.define do
|
|
20
19
|
end
|
21
20
|
|
22
21
|
class Person < ActiveRecord::Base
|
23
|
-
|
24
|
-
strip_attributes :
|
25
|
-
|
26
|
-
|
22
|
+
|
23
|
+
{ nullified: :nullify_attributes, stripped: :strip_attributes, truncated: :truncate_attributes }.each do |prefix, macro|
|
24
|
+
NUMBERS.each_with_index do |number, index|
|
25
|
+
send(macro, "person_#{prefix}_#{number}".to_sym, validator: (index / 2).even?, writer: (index % 2))
|
26
|
+
end
|
27
|
+
end
|
27
28
|
|
28
29
|
def set_blank_attributes
|
29
|
-
|
30
|
-
|
30
|
+
NUMBERS.each do |number|
|
31
|
+
write_attribute("person_nullified_#{number}", ' ')
|
32
|
+
end
|
33
|
+
save(validate: false)
|
31
34
|
end
|
32
35
|
|
33
36
|
def set_long_attributes
|
34
|
-
|
35
|
-
|
37
|
+
NUMBERS.each do |number|
|
38
|
+
write_attribute("person_truncated_#{number}", self.class.long_value)
|
39
|
+
end
|
36
40
|
save(validate: false)
|
37
41
|
end
|
38
42
|
|
39
43
|
def set_padded_attributes
|
40
|
-
|
41
|
-
|
44
|
+
NUMBERS.each do |number|
|
45
|
+
write_attribute("person_stripped_#{number}", ' test value ')
|
46
|
+
end
|
47
|
+
save(validate: false)
|
42
48
|
end
|
43
49
|
|
44
50
|
class << self
|
@@ -46,6 +52,10 @@ class Person < ActiveRecord::Base
|
|
46
52
|
@short_value ||= ('a' * COLUMN_LIMIT)
|
47
53
|
end
|
48
54
|
|
55
|
+
def stripped_value
|
56
|
+
@stripped_value ||= 'test value'
|
57
|
+
end
|
58
|
+
|
49
59
|
def long_value
|
50
60
|
@long_value ||= ('a' * 500)
|
51
61
|
end
|
@@ -55,26 +65,22 @@ end
|
|
55
65
|
class Developer < Person; end
|
56
66
|
|
57
67
|
class Architect < Developer
|
58
|
-
nullify_attributes :
|
59
|
-
strip_attributes :
|
60
|
-
truncate_attributes :
|
68
|
+
nullify_attributes :architect_nullified
|
69
|
+
strip_attributes :architect_stripped
|
70
|
+
truncate_attributes :architect_truncated
|
61
71
|
|
62
72
|
def set_blank_attributes
|
63
|
-
write_attribute(:
|
64
|
-
|
65
|
-
save
|
73
|
+
write_attribute(:architect_nullified, ' ')
|
74
|
+
super
|
66
75
|
end
|
67
76
|
|
68
77
|
def set_long_attributes
|
69
|
-
write_attribute(:
|
70
|
-
|
71
|
-
write_attribute(:other_truncated_name, self.class.long_value)
|
72
|
-
save
|
78
|
+
write_attribute(:architect_truncated, self.class.long_value)
|
79
|
+
super
|
73
80
|
end
|
74
81
|
|
75
82
|
def set_padded_attributes
|
76
|
-
write_attribute(:
|
77
|
-
|
78
|
-
save
|
83
|
+
write_attribute(:architect_stripped, ' test value ')
|
84
|
+
super
|
79
85
|
end
|
80
86
|
end
|
@@ -1,34 +1,14 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class TruncateAttributesTest < ActiveSupport::TestCase
|
4
|
-
def test_truncated_name=
|
5
|
-
person = Person.new
|
6
|
-
person.truncated_name = Person.long_value
|
7
|
-
assert_equal Person.short_value, person.truncated_name
|
8
|
-
|
9
|
-
person.truncated_name = nil
|
10
|
-
assert_equal nil, person.truncated_name
|
11
|
-
|
12
|
-
person.truncated_name = 'test_value'
|
13
|
-
assert_equal 'test_value', person.truncated_name
|
14
|
-
end
|
15
|
-
|
16
|
-
def test_truncated_whiny_name_validation
|
17
|
-
person = Person.new
|
18
|
-
person.truncated_whiny_name = Person.long_value
|
19
|
-
|
20
|
-
assert_not person.save
|
21
|
-
assert_equal ["is too long (maximum is #{COLUMN_LIMIT} characters)"],
|
22
|
-
person.errors[:truncated_whiny_name]
|
23
|
-
end
|
24
|
-
|
25
4
|
def test_truncate_attributes
|
26
5
|
person = Person.new
|
27
6
|
person.set_long_attributes
|
28
7
|
|
29
8
|
assert person.truncate_attributes
|
30
|
-
|
31
|
-
|
9
|
+
person_attributes.each do |attribute|
|
10
|
+
assert_equal Person.short_value, person.send(attribute)
|
11
|
+
end
|
32
12
|
end
|
33
13
|
|
34
14
|
def test_truncate_attributes!
|
@@ -36,8 +16,9 @@ class TruncateAttributesTest < ActiveSupport::TestCase
|
|
36
16
|
person.set_long_attributes
|
37
17
|
|
38
18
|
assert person.truncate_attributes!
|
39
|
-
|
40
|
-
|
19
|
+
person_attributes.each do |attribute|
|
20
|
+
assert_equal Person.short_value, person.send(attribute)
|
21
|
+
end
|
41
22
|
end
|
42
23
|
|
43
24
|
def test_truncated_attributes_inheritance
|
@@ -45,25 +26,32 @@ class TruncateAttributesTest < ActiveSupport::TestCase
|
|
45
26
|
architect.set_long_attributes
|
46
27
|
|
47
28
|
assert architect.truncate_attributes
|
48
|
-
|
49
|
-
|
50
|
-
|
29
|
+
architect_attributes.each do |attribute|
|
30
|
+
assert_equal Architect.short_value, architect.send(attribute)
|
31
|
+
end
|
51
32
|
end
|
52
33
|
|
53
34
|
def test_truncated_attributes
|
54
|
-
assert_equal Person.truncated_attributes.map(&:attribute)
|
55
|
-
|
56
|
-
assert_equal
|
57
|
-
assert_equal Architect.truncated_attributes.map(&:attribute),
|
58
|
-
[:other_truncated_name]
|
35
|
+
assert_equal person_attributes, Person.truncated_attributes.map(&:attribute)
|
36
|
+
assert_empty Developer.truncated_attributes.map(&:attribute)
|
37
|
+
assert_equal [:architect_truncated], Architect.truncated_attributes.map(&:attribute)
|
59
38
|
end
|
60
39
|
|
61
40
|
def test_inherited_truncated_attributes
|
62
|
-
assert_equal Person.inherited_truncated_attributes.map(&:attribute)
|
63
|
-
|
64
|
-
assert_equal
|
65
|
-
[:truncated_name, :truncated_whiny_name]
|
66
|
-
assert_equal Architect.inherited_truncated_attributes.map(&:attribute),
|
67
|
-
[:other_truncated_name, :truncated_name, :truncated_whiny_name]
|
41
|
+
assert_equal person_attributes, Person.inherited_truncated_attributes.map(&:attribute)
|
42
|
+
assert_equal person_attributes, Developer.inherited_truncated_attributes.map(&:attribute)
|
43
|
+
assert_equal architect_attributes, Architect.inherited_truncated_attributes.map(&:attribute)
|
68
44
|
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
# a list of the attributes that are truncated on the architect class
|
49
|
+
def architect_attributes
|
50
|
+
@architect_attributes ||= ([:architect_truncated] + person_attributes)
|
51
|
+
end
|
52
|
+
|
53
|
+
# a list of the attributes that are truncated on the person class
|
54
|
+
def person_attributes
|
55
|
+
@person_attributes ||= [:person_truncated_one, :person_truncated_two, :person_truncated_three, :person_truncated_four]
|
56
|
+
end
|
69
57
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attribute_extras
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kevin Deisz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -38,10 +38,9 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
description:
|
42
|
-
behavior such as nullifying, stripping, and truncating.
|
41
|
+
description: Builds macros to automatically manipulate your models' attributes.
|
43
42
|
email:
|
44
|
-
-
|
43
|
+
- info@trialnetworks.com
|
45
44
|
executables: []
|
46
45
|
extensions: []
|
47
46
|
extra_rdoc_files: []
|
@@ -51,10 +50,9 @@ files:
|
|
51
50
|
- Rakefile
|
52
51
|
- lib/attribute_extras.rb
|
53
52
|
- lib/attribute_extras/base_extensions.rb
|
53
|
+
- lib/attribute_extras/extra_builder.rb
|
54
|
+
- lib/attribute_extras/hook_builder.rb
|
54
55
|
- lib/attribute_extras/modifier.rb
|
55
|
-
- lib/attribute_extras/nullify_attributes.rb
|
56
|
-
- lib/attribute_extras/strip_attributes.rb
|
57
|
-
- lib/attribute_extras/truncate_attributes.rb
|
58
56
|
- lib/attribute_extras/version.rb
|
59
57
|
- test/base_extensions_test.rb
|
60
58
|
- test/modifier_test.rb
|
@@ -63,7 +61,7 @@ files:
|
|
63
61
|
- test/test_classes.rb
|
64
62
|
- test/test_helper.rb
|
65
63
|
- test/truncate_attributes_test.rb
|
66
|
-
homepage: https://github.com/
|
64
|
+
homepage: https://github.com/drugdev/attribute_extras
|
67
65
|
licenses:
|
68
66
|
- MIT
|
69
67
|
metadata: {}
|
@@ -1,49 +0,0 @@
|
|
1
|
-
module AttributeExtras
|
2
|
-
module NullifyAttributes
|
3
|
-
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
module ClassMethods
|
7
|
-
# inherited and current nullified attributes
|
8
|
-
def inherited_nullified_attributes
|
9
|
-
@inherited_nullified_attributes ||= begin
|
10
|
-
modifiers = []
|
11
|
-
self.ancestors.each_with_object([]) do |ancestor|
|
12
|
-
break if ancestor == ActiveRecord::Base
|
13
|
-
if ancestor.respond_to?(:nullified_attributes)
|
14
|
-
modifiers += ancestor.nullified_attributes
|
15
|
-
end
|
16
|
-
end
|
17
|
-
modifiers
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# the nullified attributes for this class
|
22
|
-
def nullified_attributes
|
23
|
-
@nullified_attributes ||= []
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# calls set_nullified_attributes then save
|
28
|
-
def nullify_attributes
|
29
|
-
set_nullified_attributes
|
30
|
-
self.save if self.changed?
|
31
|
-
end
|
32
|
-
|
33
|
-
# calls set_nullified_attributes then save!
|
34
|
-
def nullify_attributes!
|
35
|
-
set_nullified_attributes
|
36
|
-
self.save! if self.changed?
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
# apply the nullification to each specified nullified attribute
|
42
|
-
def set_nullified_attributes
|
43
|
-
self.class.inherited_nullified_attributes.each do |modifier|
|
44
|
-
attribute = modifier.attribute
|
45
|
-
self.send("#{attribute}=", self.send(attribute))
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
module AttributeExtras
|
2
|
-
module StripAttributes
|
3
|
-
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
module ClassMethods
|
7
|
-
# inherited and current stripped attributes
|
8
|
-
def inherited_stripped_attributes
|
9
|
-
@inherited_stripped_attributes ||= begin
|
10
|
-
modifiers = []
|
11
|
-
self.ancestors.each_with_object([]) do |ancestor|
|
12
|
-
break if ancestor == ActiveRecord::Base
|
13
|
-
if ancestor.respond_to?(:stripped_attributes)
|
14
|
-
modifiers += ancestor.stripped_attributes
|
15
|
-
end
|
16
|
-
end
|
17
|
-
modifiers
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# the stripped attributes for this class
|
22
|
-
def stripped_attributes
|
23
|
-
@stripped_attributes ||= []
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# calls set_stripped_attributes then save
|
28
|
-
def strip_attributes
|
29
|
-
set_stripped_attributes
|
30
|
-
self.save if self.changed?
|
31
|
-
end
|
32
|
-
|
33
|
-
# calls set_stripped_attributes then save!
|
34
|
-
def strip_attributes!
|
35
|
-
set_stripped_attributes
|
36
|
-
self.save! if self.changed?
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
# apply the strip to each specified stripped attribute
|
42
|
-
def set_stripped_attributes
|
43
|
-
self.class.inherited_stripped_attributes.each do |modifier|
|
44
|
-
attribute = modifier.attribute
|
45
|
-
self.send("#{attribute}=", self.send(attribute))
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module AttributeExtras
|
2
|
-
module TruncateAttributes
|
3
|
-
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
module ClassMethods
|
7
|
-
# inherited and current truncated attributes
|
8
|
-
def inherited_truncated_attributes
|
9
|
-
@inherited_truncated_attributes ||= begin
|
10
|
-
modifiers = []
|
11
|
-
self.ancestors.each_with_object([]) do |ancestor|
|
12
|
-
break if ancestor == ActiveRecord::Base
|
13
|
-
if ancestor.respond_to?(:truncated_attributes)
|
14
|
-
modifiers += ancestor.truncated_attributes
|
15
|
-
end
|
16
|
-
end
|
17
|
-
modifiers
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# the truncated attributes for this class
|
22
|
-
def truncated_attributes
|
23
|
-
@truncated_attributes ||= []
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# calls set_truncated_attributes then save
|
28
|
-
def truncate_attributes
|
29
|
-
set_truncated_attributes
|
30
|
-
self.save if self.changed?
|
31
|
-
end
|
32
|
-
|
33
|
-
# calls set_truncated_attributes then save!
|
34
|
-
def truncate_attributes!
|
35
|
-
set_truncated_attributes
|
36
|
-
self.save! if self.changed?
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
# apply the truncation to each specified truncated attribute
|
42
|
-
def set_truncated_attributes
|
43
|
-
self.class.inherited_truncated_attributes.each do |modifier|
|
44
|
-
attribute = modifier.attribute
|
45
|
-
if modifier.options[:limit]
|
46
|
-
self.send("#{attribute}=", self.send(attribute)[0...modifier.options[:limit]])
|
47
|
-
else
|
48
|
-
self.send("#{attribute}=", self.send(attribute))
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|