attribute_extras 0.1.4 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,50 +1,54 @@
1
- require 'attribute_extras/extra_builder'
2
- require 'attribute_extras/hook_builder'
3
- require 'attribute_extras/modifier'
4
- require 'logger'
1
+ # frozen_string_literal: true
5
2
 
6
- # Used for automatic attribute manipulation
3
+ require 'attribute_extras/version'
4
+
5
+ # Extra macros for auto attribute manipulation.
7
6
  module AttributeExtras
7
+ # Parent class of the various extras.
8
+ class AttributeExtra < Module
9
+ attr_reader :name
10
+
11
+ def initialize(name, attributes, perform)
12
+ @name = name
13
+ define_extra(name, attributes, perform)
14
+ end
15
+
16
+ def included(clazz)
17
+ clazz.before_validation(name)
18
+ end
19
+
20
+ private
21
+
22
+ def define_extra(name, attributes, perform)
23
+ define_method(name) do
24
+ attributes.each do |attribute|
25
+ value = public_send(attribute)
26
+ public_send(:"#{attribute}=", perform[self, attribute, value])
27
+ end
28
+ end
29
+ end
30
+ end
8
31
 
9
- # the registered extras
10
- mattr_accessor :extras
11
- self.extras = []
32
+ def self.define_extra(name, &perform)
33
+ extra = Class.new(AttributeExtra)
34
+ extra_name = name.to_s.gsub(/(?:\A|_)([a-z])/i) { $1.upcase }.to_sym
12
35
 
13
- # wrap up configuration options into one block
14
- def self.configure(&block)
15
- yield self
36
+ AttributeExtras.const_set(extra_name, extra)
37
+ ActiveRecord::Base.define_singleton_method(name) do |*attributes|
38
+ include extra.new(name, attributes, perform)
39
+ end
16
40
  end
17
41
 
18
- # the logger for attribute extras
19
- def self.logger
20
- @logger ||= Logger.new($stderr)
42
+ define_extra :nullify_attributes do |*, value|
43
+ value.presence
21
44
  end
22
45
 
23
- # register the extra and build the functions
24
- def self.register_extra(verb, function, past:, validator:, options: nil)
25
- past ||= verb
26
- compiled_validator = validator.is_a?(Proc) ? validator : ->(options){ validator }
27
- options ||= ->(attribute){ {} }
28
-
29
- extra = ExtraBuilder.new(verb, past, function, compiled_validator, options).build
30
- hook = HookBuilder.new(verb, past).build
31
-
32
- self.const_set(:"#{verb.capitalize}Attributes", extra)
33
- self.extras << extra
34
- ActiveRecord::Base.extend(hook)
46
+ define_extra :strip_attributes do |*, value|
47
+ value.is_a?(String) ? value.strip : value
35
48
  end
36
49
 
37
- self.register_extra :nullify, ->(value, options){ value.presence },
38
- past: :nullified,
39
- validator: { format: { allow_nil: true, without: /\A\s*\z/ } }
40
-
41
- self.register_extra :strip, ->(value, options){ value.is_a?(String) ? value.strip : value },
42
- past: :stripped,
43
- validator: { format: { without: /\A\s+|\s+\z/ } }
44
-
45
- self.register_extra :truncate, ->(value, options){ value.is_a?(String) ? value[0...options[:limit]] : value },
46
- past: :truncated,
47
- validator: ->(options){ { length: { maximum: options[:limit] } } },
48
- options: ->(attribute){ { limit: self.columns_hash[attribute.to_s].limit } }
49
-
50
+ define_extra :truncate_attributes do |record, attribute, value|
51
+ limit = record.class.columns_hash[attribute.to_s].limit
52
+ value.is_a?(String) ? value[0...limit] : value
53
+ end
50
54
  end
metadata CHANGED
@@ -1,116 +1,163 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attribute_extras
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
5
- prerelease:
4
+ version: 1.0.1
6
5
  platform: ruby
7
6
  authors:
8
- - Kevin Deisz
9
- autorequire:
10
- bindir: bin
7
+ - Kevin Newton
8
+ autorequire:
9
+ bindir: exe
11
10
  cert_chain: []
12
- date: 2016-02-08 00:00:00.000000000 Z
11
+ date: 2021-11-17 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activerecord
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>'
17
+ - - ">"
20
18
  - !ruby/object:Gem::Version
21
19
  version: '3'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>'
24
+ - - ">"
28
25
  - !ruby/object:Gem::Version
29
26
  version: '3'
30
27
  - !ruby/object:Gem::Dependency
31
- name: activesupport
28
+ name: bundler
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>'
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
- version: '3'
38
- type: :runtime
33
+ version: '2.0'
34
+ type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>'
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
- version: '3'
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '13.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.12'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.12'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.17'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.17'
46
97
  - !ruby/object:Gem::Dependency
47
98
  name: sqlite3
48
99
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
100
  requirements:
51
- - - ! '>='
101
+ - - "~>"
52
102
  - !ruby/object:Gem::Version
53
- version: '0'
103
+ version: '1.4'
54
104
  type: :development
55
105
  prerelease: false
56
106
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
107
  requirements:
59
- - - ! '>='
108
+ - - "~>"
60
109
  - !ruby/object:Gem::Version
61
- version: '0'
62
- description: Builds macros to automatically manipulate your models' attributes.
110
+ version: '1.4'
111
+ description: 'Builds macros to automatically manipulate your models'' attributes.
112
+
113
+ '
63
114
  email:
64
- - info@trialnetworks.com
115
+ - kddnewton@gmail.com
65
116
  executables: []
66
117
  extensions: []
67
118
  extra_rdoc_files: []
68
119
  files:
69
- - lib/attribute_extras/extra_builder.rb
70
- - lib/attribute_extras/hook_builder.rb
71
- - lib/attribute_extras/modifier.rb
72
- - lib/attribute_extras/version.rb
73
- - lib/attribute_extras.rb
74
- - MIT-LICENSE
75
- - Rakefile
120
+ - ".github/dependabot.yml"
121
+ - ".github/workflows/main.yml"
122
+ - ".gitignore"
123
+ - ".rubocop.yml"
124
+ - CHANGELOG.md
125
+ - CODE_OF_CONDUCT.md
126
+ - Gemfile
127
+ - Gemfile.lock
128
+ - LICENSE
76
129
  - README.md
77
- - test/base_extensions_test.rb
78
- - test/modifier_test.rb
79
- - test/nullify_attributes_test.rb
80
- - test/strip_attributes_test.rb
81
- - test/test_classes.rb
82
- - test/test_helper.rb
83
- - test/truncate_attributes_test.rb
84
- homepage: https://github.com/drugdev/attribute_extras
130
+ - Rakefile
131
+ - attribute_extras.gemspec
132
+ - bin/console
133
+ - bin/setup
134
+ - lib/attribute_extras.rb
135
+ - lib/attribute_extras/version.rb
136
+ homepage: https://github.com/kddnewton/attribute_extras
85
137
  licenses:
86
138
  - MIT
87
- post_install_message:
139
+ metadata:
140
+ bug_tracker_uri: https://github.com/kddnewton/attribute_extras/issues
141
+ changelog_uri: https://github.com/kddnewton/attribute_extras/blob/v1.0.1/CHANGELOG.md
142
+ source_code_uri: https://github.com/kddnewton/attribute_extras
143
+ rubygems_mfa_required: 'true'
144
+ post_install_message:
88
145
  rdoc_options: []
89
146
  require_paths:
90
147
  - lib
91
148
  required_ruby_version: !ruby/object:Gem::Requirement
92
- none: false
93
149
  requirements:
94
- - - ! '>='
150
+ - - ">="
95
151
  - !ruby/object:Gem::Version
96
152
  version: '0'
97
153
  required_rubygems_version: !ruby/object:Gem::Requirement
98
- none: false
99
154
  requirements:
100
- - - ! '>='
155
+ - - ">="
101
156
  - !ruby/object:Gem::Version
102
157
  version: '0'
103
158
  requirements: []
104
- rubyforge_project:
105
- rubygems_version: 1.8.23
106
- signing_key:
107
- specification_version: 3
159
+ rubygems_version: 3.2.3
160
+ signing_key:
161
+ specification_version: 4
108
162
  summary: Extra macros for auto attribute manipulation.
109
- test_files:
110
- - test/base_extensions_test.rb
111
- - test/modifier_test.rb
112
- - test/nullify_attributes_test.rb
113
- - test/strip_attributes_test.rb
114
- - test/test_classes.rb
115
- - test/test_helper.rb
116
- - test/truncate_attributes_test.rb
163
+ test_files: []
data/MIT-LICENSE DELETED
@@ -1,20 +0,0 @@
1
- Copyright 2015 DrugDev, Inc.
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,83 +0,0 @@
1
- module AttributeExtras
2
-
3
- # Builds a concern that will be included into classes when they call
4
- # the macro corresponding to the given verb. For instance, for the verb
5
- # :nullify it will build out AttributeExtras::NullifyAttributes, which
6
- # can be included into classes to get all of the utility functions.
7
- class ExtraBuilder
8
-
9
- # store the given options
10
- def initialize(verb, past, function, validator, options)
11
- @verb = verb
12
- @past = past
13
- @function = function
14
- @validator = validator
15
- @options = options
16
- end
17
-
18
- # build the extra
19
- def build
20
- concern = Module.new
21
- concern.module_eval(concern_definition)
22
- concern::ClassMethods.module_eval(&utilities_definition)
23
- concern
24
- end
25
-
26
- private
27
-
28
- # the module definition for the concern
29
- def concern_definition
30
- <<-RUBY
31
- extend ActiveSupport::Concern
32
-
33
- module ClassMethods
34
- def inherited_#{@past}_attributes
35
- @inherited_#{@past}_attributes ||= begin
36
- modifiers = []
37
- self.ancestors.each do |ancestor|
38
- break if ancestor == ActiveRecord::Base
39
- if ancestor.respond_to?(:#{@past}_attributes)
40
- modifiers += ancestor.#{@past}_attributes
41
- end
42
- end
43
- modifiers
44
- end
45
- end
46
-
47
- def #{@past}_attributes
48
- @#{@past}_attributes ||= []
49
- end
50
- end
51
-
52
- def #{@verb}_attributes
53
- set_#{@past}_attributes
54
- self.changed? ? self.save : true
55
- end
56
-
57
- def #{@verb}_attributes!
58
- set_#{@past}_attributes
59
- self.changed? ? self.save : true
60
- end
61
-
62
- private
63
-
64
- def set_#{@past}_attributes
65
- self.class.inherited_#{@past}_attributes.each do |modifier|
66
- attribute = modifier.attribute
67
- self.send(:\"\#{attribute}=\", self.class.#{@verb}_attribute_extra(self.send(attribute), modifier.options))
68
- end
69
- end
70
- RUBY
71
- end
72
-
73
- # the module definition for the utilities
74
- def utilities_definition
75
- verb, function, validator, options = @verb, @function, @validator, @options
76
- proc do
77
- define_method(:"#{verb}_attribute_extra", function)
78
- define_method(:"#{verb}_validator_for", validator)
79
- define_method(:"#{verb}_options_for", options)
80
- end
81
- end
82
- end
83
- end
@@ -1,56 +0,0 @@
1
- module AttributeExtras
2
-
3
- # Builds a module that extends ActiveRecord::Base to build the macro
4
- # corresponding to the given verb. For instance, for the verb :nullify,
5
- # it will build a module that extends AR::Base with the method
6
- # :nullify_attributes, which is then used to include the concern from
7
- # the ExtraBuilder.
8
- class HookBuilder
9
-
10
- # store the given options
11
- def initialize(verb, past)
12
- @verb = verb
13
- @past = past
14
- end
15
-
16
- # build the hook
17
- def build
18
- hook = Module.new
19
- hook.module_eval(module_definition)
20
- hook
21
- end
22
-
23
- private
24
-
25
- # the module definition for the extra
26
- def module_definition
27
- <<-RUBY
28
- def #{@verb}_attributes(*attributes, validator: true, writer: true)
29
- if self.table_exists? && (non_attributes = attributes.map(&:to_s) - self.column_names).any?
30
- AttributeExtras.logger.warn("Invalid attributes passed to #{@verb}_attributes: \#{non_attributes.join(', ')}")
31
- return
32
- end
33
-
34
- include ::AttributeExtras::#{@verb.capitalize}Attributes
35
-
36
- attributes.each do |attribute|
37
- options = self.#{@verb}_options_for(attribute)
38
- modifier = Modifier.new(attribute, options)
39
-
40
- if validator
41
- validates attribute, self.#{@verb}_validator_for(modifier.options)
42
- end
43
-
44
- if writer
45
- define_method("\#{attribute}=") do |value|
46
- write_attribute(attribute, self.class.#{@verb}_attribute_extra(value, modifier.options))
47
- end
48
- end
49
-
50
- #{@past}_attributes << modifier
51
- end
52
- end
53
- RUBY
54
- end
55
- end
56
- end
@@ -1,19 +0,0 @@
1
- module AttributeExtras
2
-
3
- # a container for an attribute that has been modified
4
- class Modifier
5
-
6
- # the attribute this modifier represents
7
- attr_reader :attribute
8
-
9
- # the set of options generated for this attribute
10
- attr_reader :options
11
-
12
- # store the given options
13
- def initialize(attribute, options = {})
14
- @attribute = attribute
15
- @options = options
16
- end
17
-
18
- end
19
- end
@@ -1,52 +0,0 @@
1
- require 'test_helper'
2
-
3
- class BaseExtensionsTest < ActiveSupport::TestCase
4
-
5
- def test_nullify_attributes_warns
6
- assert_output_matches 'Invalid attributes' do
7
- address_class(:nullify_attributes, :first_line, :second_line, :third_line)
8
- end
9
- end
10
-
11
- def test_nullify_attributes_success
12
- klass = address_class(:nullify_attributes, :first_line, :second_line)
13
- assert_equal klass.nullified_attributes.map(&:attribute), [:first_line, :second_line]
14
- end
15
-
16
- def test_strip_attributes_warns
17
- assert_output_matches 'Invalid attributes' do
18
- address_class(:strip_attributes, :first_line, :second_line, :third_line)
19
- end
20
- end
21
-
22
- def test_strip_attributes_success
23
- klass = address_class(:strip_attributes, :first_line, :second_line)
24
- assert_equal klass.stripped_attributes.map(&:attribute), [:first_line, :second_line]
25
- end
26
-
27
- def test_truncate_attributes_success
28
- klass = address_class(:truncate_attributes, :first_line, :second_line)
29
- assert_equal klass.truncated_attributes.map(&:attribute), [:first_line, :second_line]
30
- end
31
-
32
- private
33
-
34
- # returns a newly created address class
35
- def address_class(macro, *arguments)
36
- Class.new(ActiveRecord::Base) do
37
- self.table_name = 'addresses'
38
- send(macro, *arguments)
39
- end
40
- end
41
-
42
- # assert that the output to $stderr matches the expected
43
- def assert_output_matches(expected)
44
- stderr = $stderr
45
- $stderr = StringIO.new
46
- AttributeExtras.instance_variable_set(:@logger, Logger.new($stderr))
47
- yield
48
- assert_match expected, $stderr.string
49
- ensure
50
- $stderr = stderr
51
- end
52
- end
@@ -1,9 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ModifierTest < ActiveSupport::TestCase
4
- def test_modifiers
5
- modifier = AttributeExtras::Modifier.new(:name, limit: 255)
6
- assert_equal modifier.attribute, :name
7
- assert_equal modifier.options, { limit: 255 }
8
- end
9
- end
@@ -1,57 +0,0 @@
1
- require 'test_helper'
2
-
3
- class NullifyAttributesTest < ActiveSupport::TestCase
4
- def test_nullify_attributes
5
- person = Person.new
6
- person.set_blank_attributes
7
-
8
- assert person.nullify_attributes
9
- person_attributes.each do |attribute|
10
- assert_nil person.send(attribute)
11
- end
12
- end
13
-
14
- def test_nullify_attributes!
15
- person = Person.new
16
- person.set_blank_attributes
17
-
18
- assert person.nullify_attributes!
19
- person_attributes.each do |attribute|
20
- assert_nil person.send(attribute)
21
- end
22
- end
23
-
24
- def test_nullified_attributes_inheritance
25
- architect = Architect.new
26
- architect.set_blank_attributes
27
-
28
- assert architect.nullify_attributes
29
- architect_attributes.each do |attribute|
30
- assert_nil architect.send(attribute)
31
- end
32
- end
33
-
34
- def test_nullified_attributes
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)
38
- end
39
-
40
- def test_inherited_nullified_attributes
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)
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
- end
@@ -1,57 +0,0 @@
1
- require 'test_helper'
2
-
3
- class StripAttributesTest < ActiveSupport::TestCase
4
- def test_strip_attributes
5
- person = Person.new
6
- person.set_padded_attributes
7
-
8
- assert person.strip_attributes
9
- person_attributes.each do |attribute|
10
- assert_equal Person.stripped_value, person.send(attribute)
11
- end
12
- end
13
-
14
- def test_strip_attributes!
15
- person = Person.new
16
- person.set_padded_attributes
17
-
18
- assert person.strip_attributes!
19
- person_attributes.each do |attribute|
20
- assert_equal Person.stripped_value, person.send(attribute)
21
- end
22
- end
23
-
24
- def test_stripped_attributes_inheritance
25
- architect = Architect.new
26
- architect.set_padded_attributes
27
-
28
- assert architect.strip_attributes
29
- architect_attributes.each do |attribute|
30
- assert_equal Architect.stripped_value, architect.send(attribute)
31
- end
32
- end
33
-
34
- def test_stripped_attributes
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)
38
- end
39
-
40
- def test_inherited_stripped_attributes
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)
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
- end