serega 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/VERSION +1 -0
  3. data/lib/serega/attribute.rb +130 -0
  4. data/lib/serega/config.rb +48 -0
  5. data/lib/serega/convert.rb +45 -0
  6. data/lib/serega/convert_item.rb +37 -0
  7. data/lib/serega/helpers/serializer_class_helper.rb +11 -0
  8. data/lib/serega/map.rb +49 -0
  9. data/lib/serega/plugins/activerecord_preloads/activerecord_preloads.rb +61 -0
  10. data/lib/serega/plugins/activerecord_preloads/lib/preloader.rb +95 -0
  11. data/lib/serega/plugins/context_metadata/context_metadata.rb +74 -0
  12. data/lib/serega/plugins/formatters/formatters.rb +49 -0
  13. data/lib/serega/plugins/hide_nil/hide_nil.rb +80 -0
  14. data/lib/serega/plugins/metadata/meta_attribute.rb +74 -0
  15. data/lib/serega/plugins/metadata/metadata.rb +123 -0
  16. data/lib/serega/plugins/metadata/validations/check_block.rb +45 -0
  17. data/lib/serega/plugins/metadata/validations/check_opt_hide_empty.rb +31 -0
  18. data/lib/serega/plugins/metadata/validations/check_opt_hide_nil.rb +31 -0
  19. data/lib/serega/plugins/metadata/validations/check_opts.rb +41 -0
  20. data/lib/serega/plugins/metadata/validations/check_path.rb +53 -0
  21. data/lib/serega/plugins/preloads/lib/enum_deep_freeze.rb +17 -0
  22. data/lib/serega/plugins/preloads/lib/format_user_preloads.rb +53 -0
  23. data/lib/serega/plugins/preloads/lib/main_preload_path.rb +40 -0
  24. data/lib/serega/plugins/preloads/lib/preloads_constructor.rb +60 -0
  25. data/lib/serega/plugins/preloads/preloads.rb +100 -0
  26. data/lib/serega/plugins/preloads/validations/check_opt_preload_path.rb +38 -0
  27. data/lib/serega/plugins/presenter/presenter.rb +111 -0
  28. data/lib/serega/plugins/root/root.rb +65 -0
  29. data/lib/serega/plugins/string_modifiers/parse_string_modifiers.rb +64 -0
  30. data/lib/serega/plugins/string_modifiers/string_modifiers.rb +32 -0
  31. data/lib/serega/plugins/validate_modifiers/validate.rb +51 -0
  32. data/lib/serega/plugins/validate_modifiers/validate_modifiers.rb +44 -0
  33. data/lib/serega/plugins.rb +51 -0
  34. data/lib/serega/utils/as_json.rb +35 -0
  35. data/lib/serega/utils/enum_deep_dup.rb +43 -0
  36. data/lib/serega/utils/to_hash.rb +52 -0
  37. data/lib/serega/utils/to_json.rb +22 -0
  38. data/lib/serega/validations/attribute/check_block.rb +81 -0
  39. data/lib/serega/validations/attribute/check_name.rb +45 -0
  40. data/lib/serega/validations/attribute/check_opt_hide.rb +20 -0
  41. data/lib/serega/validations/attribute/check_opt_many.rb +20 -0
  42. data/lib/serega/validations/attribute/check_opt_method.rb +25 -0
  43. data/lib/serega/validations/attribute/check_opt_serializer.rb +36 -0
  44. data/lib/serega/validations/attribute/check_opts.rb +36 -0
  45. data/lib/serega/validations/check_allowed_keys.rb +13 -0
  46. data/lib/serega/validations/check_opt_is_bool.rb +14 -0
  47. data/lib/serega/validations/check_opt_is_hash.rb +14 -0
  48. data/lib/serega/version.rb +5 -0
  49. data/lib/serega.rb +265 -0
  50. metadata +94 -0
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ module Metadata
6
+ #
7
+ # Stores Attribute data
8
+ #
9
+ class MetaAttribute
10
+ #
11
+ # Stores Attribute instance methods
12
+ #
13
+ module InstanceMethods
14
+ # @return [Symbol] Meta attribute name
15
+ attr_reader :name
16
+
17
+ # @return [Symbol] Meta attribute full path
18
+ attr_reader :path
19
+
20
+ # @return [Proc] Meta attribute options
21
+ attr_reader :opts
22
+
23
+ # @return [Proc] Meta attribute originally added block
24
+ attr_reader :block
25
+
26
+ #
27
+ # Initializes new meta attribute
28
+ #
29
+ # @param path [Array<Symbol, String>] Path for metadata of attribute
30
+ #
31
+ # @param opts [Hash] metadata attribute options
32
+ #
33
+ # @param block [Proc] Proc that receives object(s) and context and finds value
34
+ #
35
+ def initialize(path:, opts:, block:)
36
+ check(path, opts, block)
37
+
38
+ @name = path.join(".").to_sym
39
+ @path = Utils::EnumDeepDup.call(path)
40
+ @opts = Utils::EnumDeepDup.call(opts)
41
+ @block = block
42
+ end
43
+
44
+ #
45
+ # Finds attribute value
46
+ #
47
+ # @param object [Object] Serialized object(s)
48
+ # @param context [Hash, nil] Serialization context
49
+ #
50
+ # @return [Object] Serialized meta attribute value
51
+ #
52
+ def value(object, context)
53
+ block.call(object, context)
54
+ end
55
+
56
+ def hide?(value)
57
+ (opts[:hide_nil] && value.nil?) || (opts[:hide_empty] && value.empty?)
58
+ end
59
+
60
+ private
61
+
62
+ def check(path, opts, block)
63
+ CheckPath.call(path)
64
+ CheckOpts.call(opts, self.class.serializer_class.config[:metadata][:attribute_keys])
65
+ CheckBlock.call(block)
66
+ end
67
+ end
68
+
69
+ extend Serega::Helpers::SerializerClassHelper
70
+ include InstanceMethods
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ module Metadata
6
+ def self.plugin_name
7
+ :metadata
8
+ end
9
+
10
+ def self.before_load_plugin(serializer_class, **opts)
11
+ serializer_class.plugin(:root, **opts) unless serializer_class.plugin_used?(:root)
12
+ end
13
+
14
+ def self.load_plugin(serializer_class, **_opts)
15
+ serializer_class.extend(ClassMethods)
16
+ serializer_class::Convert.include(ConvertInstanceMethods)
17
+
18
+ require_relative "./meta_attribute"
19
+ require_relative "./validations/check_block"
20
+ require_relative "./validations/check_opt_hide_nil"
21
+ require_relative "./validations/check_opt_hide_empty"
22
+ require_relative "./validations/check_opts"
23
+ require_relative "./validations/check_path"
24
+
25
+ meta_attribute_class = Class.new(MetaAttribute)
26
+ meta_attribute_class.serializer_class = serializer_class
27
+ serializer_class.const_set(:MetaAttribute, meta_attribute_class)
28
+ end
29
+
30
+ def self.after_load_plugin(serializer_class, **_opts)
31
+ serializer_class.config[plugin_name] = {attribute_keys: %i[path hide_nil hide_empty]}
32
+ end
33
+
34
+ module ClassMethods
35
+ private def inherited(subclass)
36
+ super
37
+
38
+ meta_attribute_class = Class.new(self::MetaAttribute)
39
+ meta_attribute_class.serializer_class = subclass
40
+ subclass.const_set(:MetaAttribute, meta_attribute_class)
41
+
42
+ # Assign same metadata attributes
43
+ meta_attributes.each_value do |attr|
44
+ subclass.meta_attribute(*attr.path, **attr.opts, &attr.block)
45
+ end
46
+ end
47
+
48
+ #
49
+ # List of added metadata attributes
50
+ #
51
+ # @return [Array] Added metadata attributes
52
+ #
53
+ def meta_attributes
54
+ @meta_attributes ||= {}
55
+ end
56
+
57
+ #
58
+ # Adds metadata to response
59
+ #
60
+ # @example
61
+ # class AppSerializer < Serega
62
+ #
63
+ # meta_attribute(:version) { '1.2.3' }
64
+ #
65
+ # meta_attribute(:meta, :paging, hide_nil: true, hide_empty: true) do |scope, ctx|
66
+ # { page: scope.page, per_page: scope.per_page, total_count: scope.total_count }
67
+ # end
68
+ # end
69
+ #
70
+ # @param *path [Array<String, Symbol>] Metadata attribute path keys
71
+ # @param **opts [Hash] Metadata attribute options
72
+ # @param &block [Proc] Metadata attribute value
73
+ #
74
+ # @return [MetadataAttribute] Added metadata attribute
75
+ #
76
+ def meta_attribute(*path, **opts, &block)
77
+ attribute = self::MetaAttribute.new(path: path, opts: opts, block: block)
78
+ meta_attributes[attribute.name] = attribute
79
+ end
80
+ end
81
+
82
+ module ConvertInstanceMethods
83
+ def to_h
84
+ hash = super
85
+ add_metadata(hash)
86
+ hash
87
+ end
88
+
89
+ private
90
+
91
+ def add_metadata(hash)
92
+ self.class.serializer_class.meta_attributes.each_value do |meta_attribute|
93
+ metadata = meta_attribute_value(meta_attribute)
94
+ next unless metadata
95
+
96
+ deep_merge_metadata(hash, metadata)
97
+ end
98
+ end
99
+
100
+ def meta_attribute_value(meta_attribute)
101
+ value = meta_attribute.value(object, opts[:context])
102
+ return if meta_attribute.hide?(value)
103
+
104
+ # Example:
105
+ # [:foo, :bar].reverse_each.inject(:bazz) { |val, key| { key => val } } # => { foo: { bar: :bazz } }
106
+ meta_attribute.path.reverse_each.inject(value) { |val, key| {key => val} }
107
+ end
108
+
109
+ def deep_merge_metadata(hash, metadata)
110
+ hash.merge!(metadata) do |_key, this_val, other_val|
111
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
112
+ deep_merge_metadata(this_val, other_val)
113
+ else
114
+ other_val
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ register_plugin(Metadata.plugin_name, Metadata)
122
+ end
123
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ module Metadata
6
+ class MetaAttribute
7
+ class CheckBlock
8
+ ALLOWED_PARAM_TYPES = %i[opt req]
9
+ private_constant :ALLOWED_PARAM_TYPES
10
+
11
+ class << self
12
+ #
13
+ # Checks block provided with attribute
14
+ # Block must have up to two arguments - object and context.
15
+ # It should not have any *rest or **key arguments
16
+ #
17
+ # @example without arguments
18
+ # metadata(:version) { CONSTANT_VERSION }
19
+ #
20
+ # @example with one argument
21
+ # metadata(:paging) { |scope| { { page: scope.page, per_page: scope.per_page, total_count: scope.total_count } }
22
+ #
23
+ # @example with two arguments
24
+ # metadata(:paging) { |scope, context| { { ... } if context[:with_paging] }
25
+ #
26
+ # @param block [Proc] Block that returns serialized meta attribute value
27
+ #
28
+ # @raise [Error] Error that block has invalid arguments
29
+ #
30
+ # @return [void]
31
+ #
32
+ def call(block)
33
+ raise Error, "Block must be provided when defining meta attribute" unless block
34
+
35
+ params = block.parameters
36
+ return if (params.count <= 2) && params.all? { |par| ALLOWED_PARAM_TYPES.include?(par[0]) }
37
+
38
+ raise Error, "Block can have maximum 2 regular parameters (no **keyword or *array args)"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ module Metadata
6
+ class MetaAttribute
7
+ class CheckOptHideEmpty
8
+ class << self
9
+ #
10
+ # Checks attribute :after_hide_if option
11
+ #
12
+ # @param opts [Hash] Attribute options
13
+ #
14
+ # @raise [Error] Error that option has invalid value
15
+ #
16
+ # @return [void]
17
+ #
18
+ def call(opts)
19
+ return unless opts.key?(:hide_empty)
20
+
21
+ value = opts[:hide_empty]
22
+ return if value == true
23
+
24
+ raise Error, "Invalid option :hide_empty => #{value.inspect}. Must be true"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ module Metadata
6
+ class MetaAttribute
7
+ class CheckOptHideNil
8
+ class << self
9
+ #
10
+ # Checks attribute :after_hide_if option
11
+ #
12
+ # @param opts [Hash] Attribute options
13
+ #
14
+ # @raise [Error] Error that option has invalid value
15
+ #
16
+ # @return [void]
17
+ #
18
+ def call(opts)
19
+ return unless opts.key?(:hide_nil)
20
+
21
+ value = opts[:hide_nil]
22
+ return if value == true
23
+
24
+ raise Error, "Invalid option :hide_nil => #{value.inspect}. Must be true"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ module Metadata
6
+ class MetaAttribute
7
+ class CheckOpts
8
+ class << self
9
+ #
10
+ # Validates attribute options
11
+ # Checks used options are allowed and then checks options values.
12
+ #
13
+ # @param opts [Hash] Attribute options
14
+ # @param attribute_keys [Array<Symbol>] Allowed options keys
15
+ #
16
+ # @raise [Error] when attribute has invalid options
17
+ #
18
+ # @return [void]
19
+ #
20
+ def call(opts, attribute_keys)
21
+ opts.each_key do |key|
22
+ next if attribute_keys.include?(key.to_sym)
23
+
24
+ raise Error, "Invalid option #{key.inspect}. Allowed options are: #{attribute_keys.map(&:inspect).join(", ")}"
25
+ end
26
+
27
+ check_each_opt(opts)
28
+ end
29
+
30
+ private
31
+
32
+ def check_each_opt(opts)
33
+ CheckOptHideEmpty.call(opts)
34
+ CheckOptHideNil.call(opts)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ module Metadata
6
+ class MetaAttribute
7
+ class CheckPath
8
+ FORMAT_ONE_CHAR = /\A[a-zA-Z0-9]\z/
9
+ FORMAT_MANY_CHARS = /\A[a-zA-Z0-9][a-zA-Z0-9_-]*?[a-zA-Z0-9]\z/ # allow '-' and '_' in the middle
10
+
11
+ private_constant :FORMAT_ONE_CHAR, :FORMAT_MANY_CHARS
12
+
13
+ class << self
14
+ #
15
+ # Checks allowed characters in specified metadata path parts.
16
+ # Globally allowed characters: "a-z", "A-Z", "0-9".
17
+ # Minus and low line "-", "_" also allowed except as the first or last character.
18
+ #
19
+ # @param path [Array<String, Symbol>] Metadata attribute path names
20
+ #
21
+ # @raise [Error] when metadata attribute name has invalid format
22
+ # @return [void]
23
+ #
24
+ def call(path)
25
+ path.each { |attr_name| check_name(attr_name) }
26
+ end
27
+
28
+ private
29
+
30
+ def check_name(name)
31
+ name = name.to_s
32
+
33
+ valid =
34
+ case name.size
35
+ when 0 then false
36
+ when 1 then name.match?(FORMAT_ONE_CHAR)
37
+ else name.match?(FORMAT_MANY_CHARS)
38
+ end
39
+
40
+ return if valid
41
+
42
+ raise Error, message(name)
43
+ end
44
+
45
+ def message(name)
46
+ %(Invalid metadata path #{name.inspect}, globally allowed characters: "a-z", "A-Z", "0-9". Minus and low line "-", "_" also allowed except as the first or last character)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ module Preloads
6
+ # Freezes nested enumerable data
7
+ class EnumDeepFreeze
8
+ class << self
9
+ def call(data)
10
+ data.each_entry { |entry| call(entry) } if data.is_a?(Enumerable)
11
+ data.freeze
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ module Preloads
6
+ # Transforms user provided preloads to hash
7
+ class FormatUserPreloads
8
+ METHODS = {
9
+ Array => :array_to_hash,
10
+ FalseClass => :nil_to_hash,
11
+ Hash => :hash_to_hash,
12
+ NilClass => :nil_to_hash,
13
+ String => :string_to_hash,
14
+ Symbol => :symbol_to_hash
15
+ }.freeze
16
+
17
+ module ClassMethods
18
+ def call(value)
19
+ send(METHODS.fetch(value.class), value)
20
+ end
21
+
22
+ private
23
+
24
+ def array_to_hash(values)
25
+ values.each_with_object({}) do |value, obj|
26
+ obj.merge!(call(value))
27
+ end
28
+ end
29
+
30
+ def hash_to_hash(values)
31
+ values.each_with_object({}) do |(key, value), obj|
32
+ obj[key.to_sym] = call(value)
33
+ end
34
+ end
35
+
36
+ def nil_to_hash(_value)
37
+ {}
38
+ end
39
+
40
+ def string_to_hash(value)
41
+ symbol_to_hash(value.to_sym)
42
+ end
43
+
44
+ def symbol_to_hash(value)
45
+ {value => {}}
46
+ end
47
+ end
48
+
49
+ extend ClassMethods
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ module Preloads
6
+ class MainPreloadPath
7
+ module ClassMethods
8
+ # @param preloads [Hash] Formatted user provided preloads hash
9
+ def call(preloads)
10
+ return FROZEN_EMPTY_ARRAY if preloads.empty?
11
+
12
+ main_path(preloads)
13
+ end
14
+
15
+ private
16
+
17
+ # Generates path (Array) to the last included resource.
18
+ # We need to know this path to include nested associations.
19
+ #
20
+ # main_path(a: { b: { c: {} }, d: {} }) # => [:a, :d]
21
+ #
22
+ def main_path(hash, path = [])
23
+ current_level = path.size
24
+
25
+ hash.each do |key, data|
26
+ path.pop(path.size - current_level)
27
+ path << key
28
+
29
+ main_path(data, path)
30
+ end
31
+
32
+ path
33
+ end
34
+ end
35
+
36
+ extend ClassMethods
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ module Preloads
6
+ #
7
+ # Finds relations to preload for provided serializer
8
+ #
9
+ class PreloadsConstructor
10
+ module ClassMethods
11
+ #
12
+ # Constructs preloads hash for given serializer
13
+ #
14
+ # @param serializer [Serega] Instance of Serega serializer
15
+ #
16
+ # @return [Hash]
17
+ #
18
+ def call(map)
19
+ preloads = {}
20
+ append_many(preloads, map)
21
+ preloads
22
+ end
23
+
24
+ private
25
+
26
+ def append_many(preloads, map)
27
+ map.each do |attribute, nested_map|
28
+ current_preloads = attribute.preloads
29
+ next unless current_preloads
30
+
31
+ has_nested = nested_map.any?
32
+ current_preloads = Utils::EnumDeepDup.call(current_preloads) if has_nested
33
+ append_current(preloads, current_preloads)
34
+ next unless has_nested
35
+
36
+ nested_preloads = nested(preloads, attribute.preloads_path)
37
+ append_many(nested_preloads, nested_map)
38
+ end
39
+ end
40
+
41
+ def append_current(preloads, current_preloads)
42
+ merge(preloads, current_preloads) unless current_preloads.empty?
43
+ end
44
+
45
+ def merge(preloads, current_preloads)
46
+ preloads.merge!(current_preloads) do |_key, value_one, value_two|
47
+ merge(value_one, value_two)
48
+ end
49
+ end
50
+
51
+ def nested(preloads, path)
52
+ !path || path.empty? ? preloads : preloads.dig(*path)
53
+ end
54
+ end
55
+
56
+ extend ClassMethods
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Serega
4
+ module Plugins
5
+ #
6
+ # Plugin adds `.preloads` method to find relations that must be preloaded
7
+ #
8
+ module Preloads
9
+ # @return [Symbol] plugin name
10
+ def self.plugin_name
11
+ :preloads
12
+ end
13
+
14
+ #
15
+ # Includes plugin modules to current serializer
16
+ #
17
+ # @param serializer_class [Class] current serializer class
18
+ # @param _opts [Hash] plugin opts
19
+ #
20
+ # @return [void]
21
+ #
22
+ def self.load_plugin(serializer_class, **_opts)
23
+ serializer_class.include(InstanceMethods)
24
+ serializer_class::Attribute.include(AttributeMethods)
25
+
26
+ serializer_class::Attribute::CheckOpts.extend(CheckOptsClassMethods)
27
+
28
+ require_relative "./lib/enum_deep_freeze"
29
+ require_relative "./lib/format_user_preloads"
30
+ require_relative "./lib/main_preload_path"
31
+ require_relative "./lib/preloads_constructor"
32
+ require_relative "./validations/check_opt_preload_path"
33
+ end
34
+
35
+ def self.after_load_plugin(serializer_class, **opts)
36
+ config = serializer_class.config
37
+ config[:attribute_keys] += [:preload, :preload_path]
38
+ config[:preloads] = {auto_preload_relations: opts.fetch(:auto_preload_relations, true)}
39
+ end
40
+
41
+ # Adds #preloads instance method
42
+ module InstanceMethods
43
+ # @return [Hash] relations that can be preloaded to omit N+1
44
+ def preloads
45
+ @preloads ||= PreloadsConstructor.call(map)
46
+ end
47
+ end
48
+
49
+ # Adds #preloads and #preloads_path Attribute instance method
50
+ module AttributeMethods
51
+ def preloads
52
+ return @preloads if defined?(@preloads)
53
+
54
+ @preloads = get_preloads
55
+ end
56
+
57
+ def preloads_path
58
+ return @preloads_path if defined?(@preloads_path)
59
+
60
+ @preloads_path = get_preloads_path
61
+ end
62
+
63
+ private
64
+
65
+ def get_preloads
66
+ preloads_provided = opts.key?(:preload)
67
+ preloads =
68
+ if preloads_provided
69
+ opts[:preload]
70
+ elsif relation? && self.class.serializer_class.config[:preloads][:auto_preload_relations]
71
+ key
72
+ end
73
+
74
+ # Nil and empty hash differs as we can preload nested results to
75
+ # empty hash, but we will skip nested preloading if nil or false provided
76
+ return if preloads_provided && !preloads
77
+
78
+ FormatUserPreloads.call(preloads)
79
+ end
80
+
81
+ def get_preloads_path
82
+ path = Array(opts[:preload_path]).map!(&:to_sym)
83
+ path = MainPreloadPath.call(preloads) if path.empty?
84
+ EnumDeepFreeze.call(path)
85
+ end
86
+ end
87
+
88
+ module CheckOptsClassMethods
89
+ private
90
+
91
+ def check_each_opt(opts)
92
+ super
93
+ CheckOptPreloadPath.call(opts)
94
+ end
95
+ end
96
+ end
97
+
98
+ register_plugin(Preloads.plugin_name, Preloads)
99
+ end
100
+ end