sleeping_king_studios-tools 0.8.0 → 1.0.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,196 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'sleeping_king_studios/tools/core_tools'
4
- require 'sleeping_king_studios/tools/toolbox'
5
-
6
- # rubocop:disable Metrics/AbcSize
7
- # rubocop:disable Metrics/CyclomaticComplexity
8
- # rubocop:disable Metrics/MethodLength
9
- # rubocop:disable Metrics/PerceivedComplexity
10
- module SleepingKingStudios::Tools::Toolbox
11
- # Module for extending classes with basic delegation. Supports passing
12
- # arguments, keywords, and blocks to the delegated method.
13
- #
14
- # @example
15
- # class MyClass
16
- # extend SleepingKingStudios::Tools::Delegator
17
- #
18
- # delegate :my_method, :to => MyService
19
- # end # class
20
- module Delegator
21
- def self.extended(_module)
22
- super
23
-
24
- SleepingKingStudios::Tools::CoreTools.deprecate(
25
- 'SleepingKingStudios::Tools::Toolbox::Delegator',
26
- message: 'Use Ruby stdlib Forwardable instead.'
27
- )
28
- end
29
-
30
- # Defines a wrapper method to delegate implementation of the specified
31
- # method or methods to an object, to the object at another specified method,
32
- # or to the object at a specified instance variable.
33
- #
34
- # @example Delegate to an object
35
- # class MyModule
36
- # extend SleepingKingStudios::Tools::Toolbox::Delegator
37
- #
38
- # delegate :my_method, :to => MyService
39
- # end # class
40
- #
41
- # @example Delegate to a method
42
- # class MyModule
43
- # extend SleepingKingStudios::Tools::Toolbox::Delegator
44
- #
45
- # def my_service
46
- # MyService.new
47
- # end # method my_service
48
- #
49
- # delegate :my_method, :to => :my_service
50
- # end # class
51
- #
52
- # @example Delegate to an instance variable
53
- # class MyModule
54
- # extend SleepingKingStudios::Tools::Toolbox::Delegator
55
- #
56
- # def initialize
57
- # @my_service = MyService.new
58
- # end # constructor
59
- #
60
- # delegate :my_method, :to => :@my_service
61
- # end # class
62
- #
63
- # @param method_names [Array<String, Symbol>] The names of the methods to
64
- # delegate.
65
- # @param to [Object, String, Symbol] The object, method, or instance
66
- # variable to delegate to. If the object is not a string or symbol, the
67
- # generated method will call `method_name` on the object. If the object is
68
- # a string or symbol, but does not start with an `@`, the generated method
69
- # will call the method of that name on the instance, and then call
70
- # `method_name` on the result. If the object is a string or symbol and
71
- # does start with an `@`, the generated method will get the instance
72
- # variable of that name and call `method_name` on the result.
73
- #
74
- # @raise ArgumentError if no delegate is specified.
75
- def delegate(*method_names, to: nil, allow_nil: false)
76
- raise ArgumentError, 'must specify a delegate' if to.nil? && !allow_nil
77
-
78
- method_names.each do |method_name|
79
- delegate_method method_name, to, { allow_nil: !!allow_nil }
80
- end
81
- end
82
-
83
- # Wraps a delegate object by automatically delegating each method that is
84
- # defined on the delegate class from the instance to the delegate. The
85
- # delegate can be specified with an object literal or with the name of an
86
- # instance method or instance variable.
87
- #
88
- # Only methods that are defined at the time #wrap_delegate is called will be
89
- # delegated, so make sure to call #wrap_delegate after loading any gems or
90
- # libraries that extend your delegate class, such as ActiveSupport.
91
- #
92
- # @example Create a class that wraps a Hash
93
- # class Errors
94
- # extend SleepingKingStudios::Tools::Delegator
95
- #
96
- # wrap_delegate(
97
- # Hash.new { |hsh, key| hsh[key] = Errors.new },
98
- # :klass => Hash
99
- # )
100
- #
101
- # def messages
102
- # @messages ||= []
103
- # end # method messages
104
- # end # class
105
- #
106
- # errors = Errors.new
107
- # errors[:post].messages << "title can't be blank"
108
- #
109
- # @param target [Object, String, Symbol] The object, method, or instance
110
- # variable to delegate to. If the object is not a string or symbol, the
111
- # generated method will call each method on the object. If the object is
112
- # a string or symbol, but does not start with an `@`, the generated method
113
- # will call the method of that name on the instance, and then call
114
- # each method on the result. If the object is a string or symbol and
115
- # does start with an `@`, the generated method will get the instance
116
- # variable of that name and call each method on the result.
117
- # @param klass [Module] The class or module whose methods are delegated to
118
- # the target. If target is the name of an instance variable or an instance
119
- # method, the klass must be specified. If target is an object literal, the
120
- # klass is optional, in which case all methods from the target will be
121
- # delegated to the target.
122
- # @param except [Array<String, Symbol>] An optional list of method names.
123
- # Any names on the list will not be delegated, even if the method is
124
- # defined by the klass or defined on the target literal.
125
- # @param only [Array<String, Symbol>] An optional list of method names.
126
- # Only names on the list will be delegated, and only if the method is
127
- # defined by the klass or defined on the target literal.
128
- #
129
- # @raise ArgumentError if no delegate is specified.
130
- # @raise ArgumentError if the target is the name of an instance method or an
131
- # instance variable and no klass is specified.
132
- # @raise ArgumentError if the target is an object literal that does not
133
- # belong to the specified klass.
134
- #
135
- # @see #delegate
136
- def wrap_delegate(target, klass: nil, except: [], only: [])
137
- if klass.is_a?(Module)
138
- unless target.is_a?(String) ||
139
- target.is_a?(Symbol) ||
140
- target.is_a?(klass)
141
- raise ArgumentError, "expected delegate to be a #{klass.name}"
142
- end
143
-
144
- method_names = klass.instance_methods - Object.instance_methods
145
- elsif target.is_a?(String) || target.is_a?(Symbol)
146
- raise ArgumentError, 'must specify a delegate class'
147
- else
148
- method_names = target.methods - Object.new.methods
149
- end
150
-
151
- if except.is_a?(Array) && !except.empty?
152
- method_names -= except.map(&:intern)
153
- end
154
-
155
- method_names &= only.map(&:intern) if only.is_a?(Array) && !only.empty?
156
-
157
- delegate(*method_names, to: target)
158
- end
159
-
160
- private
161
-
162
- def delegate_method(method_name, target, options = {})
163
- if target.is_a?(String) || target.is_a?(Symbol)
164
- target = target.intern
165
-
166
- if target.to_s =~ /\A@/
167
- define_method method_name do |*args, &block|
168
- receiver = instance_variable_get(target)
169
-
170
- return nil if receiver.nil? && options[:allow_nil]
171
-
172
- receiver.send(method_name, *args, &block)
173
- end
174
- else
175
- define_method method_name do |*args, &block|
176
- receiver = send(target)
177
-
178
- return nil if receiver.nil? && options[:allow_nil]
179
-
180
- receiver.send(method_name, *args, &block)
181
- end
182
- end
183
- else
184
- define_method method_name do |*args, &block|
185
- return nil if target.nil? && options[:allow_nil]
186
-
187
- target.send(method_name, *args, &block)
188
- end
189
- end
190
- end
191
- end
192
- end
193
- # rubocop:enable Metrics/AbcSize
194
- # rubocop:enable Metrics/CyclomaticComplexity
195
- # rubocop:enable Metrics/MethodLength
196
- # rubocop:enable Metrics/PerceivedComplexity