trailblazer-context 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 278837bbeb41d58a08abe15cfa239e7c2d0030cf4d4d7de19e98f0982fd70ea1
4
- data.tar.gz: 1dffd41a315387722858cf987a4289211cc8ea537664c98b5042539fcee11e6a
3
+ metadata.gz: 68c328cb817dbf1889d8e4619afa0b950786a839d8685c145ac9cda543b63c5b
4
+ data.tar.gz: 3bbe468cf341ebb429715983c3ea284b02251eedfe0084b6225252fbf5240e4b
5
5
  SHA512:
6
- metadata.gz: 553c3dd7b3d9ff2ed9493c4a0d44369d1f6f4442ab9b53679e6e1147f7e052d98974273fa38466056e377e2de03fdd662f8e12d28b99cfde99d1074c5d4aa9e3
7
- data.tar.gz: abfddac36f7d1a789f45018d3a79e98f5443e4934a29513f80d728453e5c12cf10e85bd8f061eead6b96006c3f0df85a26a2a80c9184524255b9e7b7a197504c
6
+ metadata.gz: 0001ec043007eec13ac0ce4c836f406a4fbfcfee8c759fb85c2059d0fffce774423d8986f504a9b0fc36c31e4d0bd75673a02f2d1e9f92b1229f95af3115f029
7
+ data.tar.gz: 85848da20e2f7639183f4cefc2095294f183f3217927b8ed573ba307ed122871549f1a5409d3369e767a896f8a64c18af598e30fbf10bc33de3918e546e2c6dd
data/.travis.yml CHANGED
@@ -3,6 +3,7 @@ before_install: gem install bundler
3
3
  cache: bundler
4
4
  rvm:
5
5
  - ruby-head
6
+ - 3.0
6
7
  - 2.7
7
8
  - 2.6
8
9
  - 2.5
data/CHANGES.md CHANGED
@@ -1,3 +1,22 @@
1
+ # 0.4.0
2
+
3
+ * Ready for Ruby 3.0. :heart:
4
+ * Remove `Option::KW`, after many years it's been superseded by the original `Trailblazer::Option`.
5
+
6
+ To achieve an invocation such as
7
+
8
+ ```ruby
9
+ Option::KW(proc).(ctx, another_positional_arg, **circuit_options)
10
+ ```
11
+
12
+ you can use the new `:keyword_arguments` options.
13
+
14
+ ```ruby
15
+ Option(proc).(ctx, another_positional_arg, keyword_arguments: ctx.to_hash, **circuit_options)
16
+ ```
17
+
18
+ This way, no more guessing is happening about what positional arg is the actual `circuit_options`.
19
+
1
20
  # 0.3.3
2
21
 
3
22
  * Remove an unsolicited `puts`.
data/Gemfile CHANGED
@@ -1,5 +1,4 @@
1
1
  source "https://rubygems.org"
2
2
  gemspec
3
3
 
4
- gem "benchmark-ips"
5
4
  gem "minitest-line"
@@ -18,16 +18,16 @@ module Trailblazer
18
18
  module_function
19
19
 
20
20
  def for_circuit(wrapped_options, mutable_options, (_, flow_options), **)
21
- build(wrapped_options, mutable_options, flow_options.fetch(:context_options))
21
+ build(wrapped_options, mutable_options, **flow_options.fetch(:context_options))
22
22
  end
23
23
 
24
24
  def build(wrapped_options, mutable_options, container_class:, **context_options)
25
- container_class.new(wrapped_options, mutable_options, context_options)
25
+ container_class.new(wrapped_options, mutable_options, **context_options)
26
26
  end
27
27
  end
28
28
 
29
29
  def self.Context(wrapped_options, mutable_options = {}, context_options = nil)
30
30
  defaults = { container_class: Context::Container, replica_class: Context::Store::IndifferentAccess }
31
- Context.build(wrapped_options, mutable_options, defaults.merge( Hash(context_options) ))
31
+ Context.build(wrapped_options, mutable_options, **defaults.merge( Hash(context_options) ))
32
32
  end
33
33
  end
@@ -1,5 +1,5 @@
1
1
  module Trailblazer
2
2
  module Context
3
- VERSION = "0.3.3"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
@@ -3,75 +3,45 @@ module Trailblazer
3
3
  # A call implementation invoking `proc.(*args)` and plainly forwarding all arguments.
4
4
  # Override this for your own step strategy (see KW#call!).
5
5
  # @private
6
- def self.call!(proc, *args, &block)
7
- proc.(*args, &block)
6
+ def self.call!(proc, *args, keyword_arguments: {}, **, &block)
7
+ # {**keyword_arguments} gets removed automatically if it's an empty hash.
8
+ # DISCUSS: is this a good practice?
9
+ proc.(*args, **keyword_arguments, &block)
8
10
  end
9
11
 
10
12
  # Note that both #evaluate_callable and #evaluate_method drop most of the args.
11
13
  # If you need those, override this class.
12
14
  # @private
13
- def self.evaluate_callable(proc, *args, **, &block)
14
- call!(proc, *args, &block)
15
+ def self.evaluate_callable(proc, *args, **options, &block)
16
+ call!(proc, *args, **options, &block)
15
17
  end
16
18
 
17
19
  # Make the context's instance method a "lambda" and reuse #call!.
18
20
  # @private
19
- def self.evaluate_method(proc, *args, exec_context: raise("No :exec_context given."), **, &block)
20
- call!(exec_context.method(proc), *args, &block)
21
+ def self.evaluate_method(proc, *args, exec_context: raise("No :exec_context given."), **options, &block)
22
+ call!(exec_context.method(proc), *args, **options, &block)
21
23
  end
22
24
 
23
25
  # Generic builder for a callable "option".
24
26
  # @param call_implementation [Class, Module] implements the process of calling the proc
25
27
  # while passing arguments/options to it in a specific style (e.g. kw args, step interface).
26
28
  # @return [Proc] when called, this proc will evaluate its option (at run-time).
27
- def self.build(call_implementation, proc)
29
+ def self.build(proc)
28
30
  if proc.is_a? Symbol
29
- ->(*args, &block) { call_implementation.evaluate_method(proc, *args, &block) }
31
+ ->(*args, **kws, &block) { Option.evaluate_method(proc, *args, **kws, &block) }
30
32
  else
31
- ->(*args, &block) { call_implementation.evaluate_callable(proc, *args, &block) }
33
+ ->(*args, **kws, &block) {
34
+ Option.evaluate_callable(proc, *args, **kws, &block) }
32
35
  end
33
36
  end
34
37
 
35
- # Returns a {Proc} that, when called, invokes the `proc` argument with keyword arguments.
36
- # This is known as "step (call) interface".
37
- #
38
- # This is commonly used by `Operation::step` to wrap the argument and make it
39
- # callable in the circuit.
40
- #
41
- # my_proc = ->(options, **kws) { options["i got called"] = true }
42
- # task = Trailblazer::Option::KW(my_proc)
43
- # task.(options = {})
44
- # options["i got called"] #=> true
45
- #
46
- # Alternatively, you can pass a symbol and an `:exec_context`.
47
- #
48
- # my_proc = :some_method
49
- # task = Trailblazer::Option::KW(my_proc)
50
- #
51
- # class A
52
- # def some_method(options, **kws)
53
- # options["i got called"] = true
54
- # end
55
- # end
56
- #
57
- # task.(options = {}, exec_context: A.new)
58
- # options["i got called"] #=> true
59
38
  def self.KW(proc)
60
- Option.build(KW, proc)
61
- end
62
-
63
- # TODO: It would be cool if call! was typed and had `options SymbolizedHash` or something.
64
- class KW < Option
65
- # A different call implementation that calls `proc` with a "step interface".
66
- # your_code.(options, **options)
67
- # @private
68
- def self.call!(proc, options, *)
69
- proc.(options, **options.to_hash) # Step interface: (options, **)
70
- end
39
+ raise "The `Option::KW()` method has been removed in trailblazer-context-0.4.
40
+ Please use `Option(task, keyword_arguments: {...})` instead. Check https://trailblazer.to/2.1/docs/trailblazer.html#trailblazer-context-option"
71
41
  end
72
42
  end
73
43
  # @note This might go to trailblazer-args along with `Context` at some point.
74
44
  def self.Option(proc)
75
- Option.build(Option, proc)
45
+ Option.build(proc)
76
46
  end
77
47
  end
data/test/context_test.rb CHANGED
@@ -250,7 +250,7 @@ class ContextWithIndifferentAccessTest < Minitest::Spec
250
250
  immutable = { model: Object }
251
251
  options = { container_class: MyContainer, replica_class: Trailblazer::Context::Store::IndifferentAccess }
252
252
 
253
- ctx = Trailblazer::Context.build(immutable, {}, options)
253
+ ctx = Trailblazer::Context.build(immutable, {}, **options)
254
254
  _(ctx.class).must_equal(MyContainer)
255
255
  _(ctx.inspect).must_equal("#<MyContainer wrapped=#{immutable} mutable={}>")
256
256
 
@@ -277,7 +277,7 @@ class ContextWithIndifferentAccessTest < Minitest::Spec
277
277
  immutable = { model: Object }
278
278
  options = { container_class: Trailblazer::Context::Container, replica_class: MyReplica }
279
279
 
280
- ctx = Trailblazer::Context.build(immutable, {}, options)
280
+ ctx = Trailblazer::Context.build(immutable, {}, **options)
281
281
  ctx[:integer] = Integer
282
282
 
283
283
  _(ctx[:integer]).must_equal(Integer)
data/test/option_test.rb CHANGED
@@ -8,6 +8,22 @@ class OptionTest < Minitest::Spec
8
8
  _(keywords.inspect).must_equal %({:a=>2, :b=>3})
9
9
  end
10
10
 
11
+ # it "what" do
12
+ # ctx = {params: 1}
13
+ # tmp_options = {constant: Object, model: Module}
14
+
15
+ # builder = Class.new do
16
+ # def builder(ctx, constant:, model:, **)
17
+ # raise model.inspect
18
+ # end
19
+ # end.new
20
+
21
+ # circuit_options = {exec_context: builder}
22
+
23
+ # # Trailblazer::Option(:builder, ).(ctx, tmp_options, **circuit_options.merge(keyword_arguments: tmp_options)) # calls {def default_contract!(options, constant:, model:, **)}
24
+ # Trailblazer::Option(:builder, ).(ctx, **circuit_options.merge(keyword_arguments: tmp_options)) # calls {def default_contract!(options, constant:, model:, **)}
25
+ # end
26
+
11
27
  describe "positional and kws" do
12
28
  class Step
13
29
  def with_positional_and_keywords(options, a: nil, **more_options, &block)
@@ -38,13 +54,13 @@ class OptionTest < Minitest::Spec
38
54
 
39
55
  # positional = { a: 1 }
40
56
  # keywords = { a: 2, b: 3 }
41
- assert_result option.(positional, keywords, exec_context: step)
57
+ assert_result option.(positional, keyword_arguments: keywords, exec_context: step)
42
58
  end
43
59
 
44
60
  it "allows passing a block, too" do
45
61
  step = Step.new
46
62
 
47
- assert_result option.(positional, keywords, {exec_context: step}, &block), block
63
+ assert_result option.(positional, keyword_arguments: keywords, exec_context: step, &block), block
48
64
  end
49
65
  end
50
66
 
@@ -52,15 +68,15 @@ class OptionTest < Minitest::Spec
52
68
  let(:option) { Trailblazer::Option(WITH_POSITIONAL_AND_KEYWORDS) }
53
69
 
54
70
  it "-> {} lambda" do
55
- assert_result option.(positional, keywords, {})
71
+ assert_result option.(positional, **{keyword_arguments: keywords})
56
72
  end
57
73
 
58
74
  it "allows passing a block, too" do
59
- assert_result option.(positional, keywords, {}, &block), block
75
+ assert_result option.(positional, **{keyword_arguments: keywords}, &block), block
60
76
  end
61
77
 
62
78
  it "doesn't mind :exec_context" do
63
- assert_result option.(positional, keywords, exec_context: "bogus")
79
+ assert_result option.(positional, keyword_arguments: keywords, exec_context: "bogus")
64
80
  end
65
81
  end
66
82
 
@@ -68,21 +84,27 @@ class OptionTest < Minitest::Spec
68
84
  let(:option) { Trailblazer::Option(WithPositionalAndKeywords) }
69
85
 
70
86
  it "passes through all args" do
71
- assert_result option.(positional, keywords, exec_context: nil)
87
+ assert_result option.(positional, keyword_arguments: keywords, exec_context: nil)
72
88
  end
73
89
 
74
90
  it "allows passing a block, too" do
75
- assert_result option.(positional, keywords, {exec_context: nil}, &block), block
91
+ assert_result option.(positional, keyword_arguments: keywords, exec_context: nil, &block), block
76
92
  end
77
93
  end
78
94
  end
79
95
 
80
96
  describe "positionals" do
81
97
  def assert_result_pos(result)
82
- _(result).must_equal([1, 2, [3, 4]])
83
- _(positionals).must_equal [1, 2, 3, 4]
98
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7.0")
99
+ _(result).must_equal([1, 2, [3, 4]])
100
+ _(positionals).must_equal [1, 2, 3, 4]
101
+ else
102
+ _(result).must_equal([1, 2, [3, 4, {}]])
103
+ _(positionals).must_equal [1, 2, 3, 4]
104
+ end
84
105
  end
85
106
 
107
+ # In Ruby < 3.0, {*args} will grab both positionals and keyword arguments.
86
108
  class Step
87
109
  def with_positionals(a, b, *args)
88
110
  [a, b, args]
@@ -122,65 +144,4 @@ class OptionTest < Minitest::Spec
122
144
  end
123
145
  end
124
146
 
125
- describe "Option::KW" do
126
- def assert_result_kws(result)
127
- _(result).must_equal([{a: 1, b: 2, c: 3}, 1, 2, {c: 3}])
128
- end
129
-
130
- class Step
131
- def with_kws(options, a: nil, b: nil, **rest)
132
- [options, a, b, rest]
133
- end
134
- end
135
-
136
- module Task
137
- def self.with_kws(options, a: nil, b: nil, **rest)
138
- [options, a, b, rest]
139
- end
140
- end
141
-
142
- WITH_KWS = ->(options, a: nil, b: nil, **rest) do
143
- [options, a, b, rest]
144
- end
145
-
146
- class WithKWs
147
- def self.call(options, a: nil, b: nil, **rest)
148
- [options, a, b, rest]
149
- end
150
- end
151
-
152
- let(:options) { {a: 1, b: 2, c: 3} }
153
-
154
- it ":method" do
155
- step = Step.new
156
-
157
- option = Trailblazer::Option::KW(:with_kws)
158
-
159
- assert_result_kws option.(options, exec_context: step)
160
- end
161
-
162
- it "Method instance" do
163
- option = Trailblazer::Option::KW(Task.method(:with_kws))
164
-
165
- assert_result_kws option.(options, {})
166
- end
167
-
168
- it "-> {} lambda" do
169
- option = Trailblazer::Option::KW(WITH_KWS)
170
-
171
- assert_result_kws option.(options, {})
172
- end
173
-
174
- it "lambda ignores :exec_context" do
175
- option = Trailblazer::Option::KW(WITH_KWS)
176
-
177
- assert_result_kws option.(options, exec_context: "something")
178
- end
179
-
180
- it "callable" do
181
- option = Trailblazer::Option::KW(WithKWs)
182
-
183
- assert_result_kws option.(options, {})
184
- end
185
- end
186
147
  end
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
 
11
11
  spec.summary = "Argument-specific data structures for Trailblazer."
12
12
  spec.description = "Argument-specific data structures for Trailblazer such as Context, Option and ContainerChain."
13
- spec.homepage = "http://trailblazer.to/gems/workflow"
13
+ spec.homepage = "https://trailblazer.to/"
14
14
  spec.licenses = ["MIT"]
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trailblazer-context
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-23 00:00:00.000000000 Z
11
+ date: 2021-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie
@@ -96,7 +96,7 @@ files:
96
96
  - test/option_test.rb
97
97
  - test/test_helper.rb
98
98
  - trailblazer-context.gemspec
99
- homepage: http://trailblazer.to/gems/workflow
99
+ homepage: https://trailblazer.to/
100
100
  licenses:
101
101
  - MIT
102
102
  metadata: {}