interaktor 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a783c3017cd4cb48ee61f7d68869a1b7b2e3a716657c3c1bc8ca230b8e7f483
4
- data.tar.gz: d5966a7b86cbfe7af7892002e8eee10cc10872743717b7501fee850a30ebc9a5
3
+ metadata.gz: 99cf1e62638c0d275243c18799d225ec5f6e44eb6e75ac0cb12418775f8d2ebe
4
+ data.tar.gz: 8e53e5c94af31544e37222810b123bf7817db54a3667f94e01a10c64d9536ba3
5
5
  SHA512:
6
- metadata.gz: 1f0df7c0eb75c1a3594c5f9e2c53fa7561fa8349c2cec2408f7d2a38be4e9c8ab80403fc63d6dee36f8f9e449c27fd9842912569bb80a30cf302ab398ccc5ddd
7
- data.tar.gz: f6333614072980b7bee34734ba34f8ee0d1881dc6aa756eaaa42e2ba4058cfcc85580fe2d2c83188a060dd185b1b322c62be188ae137acb9b38adbebcc9b7762
6
+ metadata.gz: 7fcd8dfeabdbacd828471bac5d80e57582e98f02c9ecf31188c2300aa24e19e2dde04453aeb82b439b8f048a4c10bb00147f2b7e9927d028aa4adbcfa22ebcf0
7
+ data.tar.gz: 1ddb2a5b49de3269b02b1c1264991ae126385ed2c22fd7f9fb953361820d9f373620fee434be064310e3aaaabe394bf3cab2d2085a9c37ac43619b8f04f92313
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "interaktor"
3
- spec.version = "0.1.4"
3
+ spec.version = "0.1.5"
4
4
 
5
5
  spec.author = "Taylor Thurlow"
6
6
  spec.email = "taylorthurlow@me.com"
@@ -33,6 +33,13 @@ module Interaktor
33
33
  @optional_attributes ||= []
34
34
  end
35
35
 
36
+ # A list of optional attributes and their default values.
37
+ #
38
+ # @return [Array<Symbol>]
39
+ def optional_defaults
40
+ @optional_defaults ||= {}
41
+ end
42
+
36
43
  # The list of attributes which are required to be passed in when calling
37
44
  # `#fail!` from within the interaktor.
38
45
  #
@@ -52,29 +59,39 @@ module Interaktor
52
59
  # A DSL method for documenting required interaktor attributes.
53
60
  #
54
61
  # @param attributes [Symbol, Array<Symbol>] the list of attribute names
62
+ # @param options [Hash]
55
63
  #
56
64
  # @return [void]
57
- def required(*attributes)
65
+ def required(*attributes, **options)
58
66
  required_attributes.concat attributes
59
67
 
60
68
  attributes.each do |attribute|
69
+ # Define getter
61
70
  define_method(attribute) { @context.send(attribute) }
71
+
72
+ # Define setter
62
73
  define_method("#{attribute}=".to_sym) do |value|
63
74
  @context.send("#{attribute}=".to_sym, value)
64
75
  end
76
+
77
+ raise "Unknown option(s): #{options.keys.join(", ")}" if options.any?
65
78
  end
66
79
  end
67
80
 
68
81
  # A DSL method for documenting optional interaktor attributes.
69
82
  #
70
83
  # @param attributes [Symbol, Array<Symbol>] the list of attribute names
84
+ # @param options [Hash]
71
85
  #
72
86
  # @return [void]
73
- def optional(*attributes)
87
+ def optional(*attributes, **options)
74
88
  optional_attributes.concat attributes
75
89
 
76
90
  attributes.each do |attribute|
91
+ # Define getter
77
92
  define_method(attribute) { @context.send(attribute) }
93
+
94
+ # Define setter
78
95
  define_method("#{attribute}=".to_sym) do |value|
79
96
  unless @context.to_h.key?(attribute)
80
97
  raise <<~ERROR
@@ -86,6 +103,12 @@ module Interaktor
86
103
 
87
104
  @context.send("#{attribute}=".to_sym, value)
88
105
  end
106
+
107
+ # Handle options
108
+ optional_defaults[attribute] = options[:default] if options[:default]
109
+ options.delete(:default)
110
+
111
+ raise "Unknown option(s): #{options.keys.join(", ")}" if options.any?
89
112
  end
90
113
  end
91
114
 
@@ -115,11 +138,10 @@ module Interaktor
115
138
  #
116
139
  # @return [Interaktor::Context] the context, following interaktor execution
117
140
  def call(context = {})
141
+ apply_default_optional_attributes(context)
118
142
  verify_attribute_presence(context)
119
143
 
120
- catch(:early_return) do
121
- new(context).tap(&:run).instance_variable_get(:@context)
122
- end
144
+ new(context).tap(&:run).instance_variable_get(:@context)
123
145
  end
124
146
 
125
147
  # Invoke an Interaktor. This method behaves identically to `#call`, with
@@ -133,18 +155,18 @@ module Interaktor
133
155
  #
134
156
  # @return [Interaktor::Context] the context, following interaktor execution
135
157
  def call!(context = {})
158
+ apply_default_optional_attributes(context)
136
159
  verify_attribute_presence(context)
137
160
 
138
- catch(:early_return) do
139
- new(context).tap(&:run!).instance_variable_get(:@context)
140
- end
161
+ new(context).tap(&:run!).instance_variable_get(:@context)
141
162
  end
142
163
 
143
164
  private
144
165
 
145
166
  # Check the provided context against the attributes defined with the DSL
146
167
  # methods, and determine if there are any attributes which are required and
147
- # have not been provided.
168
+ # have not been provided, or if there are any attributes which have been
169
+ # provided but are not listed as either required or optional.
148
170
  #
149
171
  # @param context [Interaktor::Context] the context to check
150
172
  #
@@ -157,6 +179,26 @@ module Interaktor
157
179
  Required attribute(s) were not provided when initializing #{name} interaktor:
158
180
  #{missing_attrs.join("\n ")}
159
181
  ERROR
182
+
183
+ allowed_attrs = required_attributes + optional_attributes
184
+ extra_attrs = context.to_h.keys.reject { |attr| allowed_attrs.include?(attr) }
185
+
186
+ raise <<~ERROR if extra_attrs.any?
187
+ One or more provided attributes were not recognized when initializing #{name} interaktor:
188
+ #{extra_attrs.join("\n ")}
189
+ ERROR
190
+ end
191
+
192
+ # Given the list of optional default attribute values defined by the class,
193
+ # assign those default values to the context if they were omitted.
194
+ #
195
+ # @param context [Interaktor::Context]
196
+ #
197
+ # @return [void]
198
+ def apply_default_optional_attributes(context)
199
+ optional_defaults.each do |attribute, default|
200
+ context[attribute] ||= default
201
+ end
160
202
  end
161
203
  end
162
204
 
@@ -238,7 +280,10 @@ module Interaktor
238
280
  # @return [void]
239
281
  def run!
240
282
  with_hooks do
241
- call
283
+ catch(:early_return) do
284
+ call
285
+ end
286
+
242
287
  @context.called!(self)
243
288
  end
244
289
  rescue StandardError
@@ -8,6 +8,8 @@ describe "Integration" do
8
8
  interaktor = Class.new.send(:include, Interaktor)
9
9
  interaktor.class_eval(&block) if block
10
10
  interaktor.class_eval do
11
+ optional :steps
12
+
11
13
  def unexpected_error!
12
14
  raise "foo"
13
15
  end
@@ -20,6 +22,8 @@ describe "Integration" do
20
22
  organizer.organize(options[:organize]) if options[:organize]
21
23
  organizer.class_eval(&block) if block
22
24
  organizer.class_eval do
25
+ optional :steps
26
+
23
27
  def unexpected_error!
24
28
  raise "foo"
25
29
  end
@@ -1,5 +1,12 @@
1
1
  shared_examples "lint" do
2
- let(:interaktor) { Class.new.include(described_class) }
2
+ let(:interaktor) do
3
+ klass = Class.new.include(described_class)
4
+ klass.class_eval do
5
+ optional :foo
6
+ end
7
+
8
+ klass
9
+ end
3
10
 
4
11
  describe ".call" do
5
12
  let(:context) { instance_double(Interaktor::Context) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: interaktor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Taylor Thurlow
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-24 00:00:00.000000000 Z
11
+ date: 2020-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk