trailblazer-option 0.1.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 +7 -0
- data/.github/workflows/ci.yml +17 -0
- data/.gitignore +10 -0
- data/CHANGES.md +3 -0
- data/Gemfile +9 -0
- data/LICENSE +21 -0
- data/README.md +1 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/trailblazer-option.rb +2 -0
- data/lib/trailblazer/option.rb +56 -0
- data/lib/trailblazer/option/version.rb +5 -0
- data/test/option_test.rb +170 -0
- data/test/test_helper.rb +6 -0
- data/trailblazer-option.gemspec +28 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0c5d6eb7b91e88296224c9a75b28fae91a4c91d58b36f1193ed8c13068e77261
|
4
|
+
data.tar.gz: 4fb0d17ce2fbb30a2ac25c358c4a7b082e056aa406d646ac026991ba43ffe263
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 709e99594cbfb5810f6861a20294552ace31a364025e83a14709dee74e0339d8ed5e1e7ce9ac35bb18018864994a1ee81b1c8eea6115edf25f3d3d2b9febe22a
|
7
|
+
data.tar.gz: 8ac22945f47ead2bc30d143f608dbaf257605fe95bad012c7328bde2aff2acf278bd3410854fe7787c0d0d3450f8cd8a28d4edc1f0d01c7f0bcc455f12b4ff17
|
@@ -0,0 +1,17 @@
|
|
1
|
+
name: CI
|
2
|
+
on: [push, pull_request]
|
3
|
+
jobs:
|
4
|
+
test:
|
5
|
+
strategy:
|
6
|
+
fail-fast: false
|
7
|
+
matrix:
|
8
|
+
# Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0'
|
9
|
+
ruby: [2.5, 2.6, 2.7, '3.0', head, jruby, jruby-head]
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
steps:
|
12
|
+
- uses: actions/checkout@v2
|
13
|
+
- uses: ruby/setup-ruby@v1
|
14
|
+
with:
|
15
|
+
ruby-version: ${{ matrix.ruby }}
|
16
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
17
|
+
- run: bundle exec rake
|
data/.gitignore
ADDED
data/CHANGES.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017-2021 TRAILBLAZER GmbH
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# trailblazer-option
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "trailblazer/option"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require "irb"
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
class Option
|
3
|
+
# A call implementation invoking `value.(*args, **keyword_arguments)` and plainly forwarding all arguments.
|
4
|
+
# Override this for your own step strategy.
|
5
|
+
# @private
|
6
|
+
def self.call!(value, *args, signal: :call, keyword_arguments: {}, **, &block)
|
7
|
+
# {**keyword_arguments} gets removed automatically if it's an empty hash.
|
8
|
+
# DISCUSS: is this a good practice?
|
9
|
+
value.public_send(signal, *args, **keyword_arguments, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Note that #evaluate_callable, #evaluate_proc and #evaluate_method drop most of the args.
|
13
|
+
# If you need those, override this class.
|
14
|
+
#
|
15
|
+
# @private
|
16
|
+
def self.evaluate_callable(value, *args, **options, &block)
|
17
|
+
call!(value, *args, **options, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Pass given `value` as a block and evaluate it within `exec_context` binding.
|
21
|
+
# @private
|
22
|
+
def self.evaluate_proc(value, *args, signal: :instance_exec, exec_context: raise("No :exec_context given."), **options)
|
23
|
+
call!(exec_context, *args, signal: signal, **options, &value)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Make the exec_context's instance method a "lambda" and reuse #call!.
|
27
|
+
# @private
|
28
|
+
def self.evaluate_method(value, *args, exec_context: raise("No :exec_context given."), **options, &block)
|
29
|
+
call!(exec_context.method(value), *args, **options, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Choose appropriate evaluator and forward all arguments.
|
33
|
+
# @private
|
34
|
+
def self.evaluator(value, *args, **options, &block)
|
35
|
+
evaluate = case value
|
36
|
+
when Symbol then method(:evaluate_method)
|
37
|
+
when Proc then method(:evaluate_proc)
|
38
|
+
else method(:evaluate_callable)
|
39
|
+
end
|
40
|
+
|
41
|
+
evaluate.(value, *args, **options, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Generic builder for a callable "option".
|
45
|
+
# @param call_implementation [Class, Module] implements the process of calling the proc
|
46
|
+
# while passing arguments/options to it in a specific style (e.g. kw args, step interface).
|
47
|
+
# @return [Proc] when called, this proc will evaluate its option (at run-time).
|
48
|
+
def self.build(value)
|
49
|
+
->(*args, **options, &block) { evaluator(value, *args, **options, &block) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.Option(value)
|
54
|
+
Option.build(value)
|
55
|
+
end
|
56
|
+
end
|
data/test/option_test.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class OptionTest < Minitest::Spec
|
4
|
+
def assert_result(result, block = nil)
|
5
|
+
_(result).must_equal([{a: 1}, 2, {b: 3}, block])
|
6
|
+
|
7
|
+
_(positional.inspect).must_equal %({:a=>1})
|
8
|
+
_(keywords.inspect).must_equal %({:a=>2, :b=>3})
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "positional and kws" do
|
12
|
+
class Step
|
13
|
+
def with_positional_and_keywords(options, a: nil, **more_options, &block)
|
14
|
+
[options, a, more_options, block]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
WITH_POSITIONAL_AND_KEYWORDS = ->(options, a: nil, **more_options, &block) do
|
19
|
+
[options, a, more_options, block]
|
20
|
+
end
|
21
|
+
|
22
|
+
class WithPositionalAndKeywords
|
23
|
+
def self.call(options, a: nil, **more_options, &block)
|
24
|
+
[options, a, more_options, block]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
let(:positional) { {a: 1} }
|
29
|
+
let(:keywords) { {a: 2, b: 3} }
|
30
|
+
|
31
|
+
let(:block) { ->(*) { snippet } }
|
32
|
+
|
33
|
+
describe ":method" do
|
34
|
+
let(:option) { Trailblazer::Option(:with_positional_and_keywords) }
|
35
|
+
|
36
|
+
it "passes through all args" do
|
37
|
+
step = Step.new
|
38
|
+
|
39
|
+
# positional = { a: 1 }
|
40
|
+
# keywords = { a: 2, b: 3 }
|
41
|
+
assert_result option.(positional, keyword_arguments: keywords, exec_context: step)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "allows passing a block, too" do
|
45
|
+
step = Step.new
|
46
|
+
|
47
|
+
assert_result option.(positional, keyword_arguments: keywords, exec_context: step, &block), block
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "lambda" do
|
52
|
+
let(:option) { Trailblazer::Option(WITH_POSITIONAL_AND_KEYWORDS) }
|
53
|
+
|
54
|
+
it "-> {} lambda" do
|
55
|
+
step = Step.new
|
56
|
+
|
57
|
+
assert_result option.(positional, **{keyword_arguments: keywords, exec_context: step})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "Callable" do
|
62
|
+
let(:option) { Trailblazer::Option(WithPositionalAndKeywords) }
|
63
|
+
|
64
|
+
it "passes through all args" do
|
65
|
+
assert_result option.(positional, keyword_arguments: keywords, exec_context: nil)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "allows passing a block, too" do
|
69
|
+
assert_result option.(positional, keyword_arguments: keywords, exec_context: nil, &block), block
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "positionals" do
|
75
|
+
def assert_result_pos(result)
|
76
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7.0")
|
77
|
+
_(result).must_equal([1, 2, [3, 4]])
|
78
|
+
_(positionals).must_equal [1, 2, 3, 4]
|
79
|
+
else
|
80
|
+
_(result).must_equal([1, 2, [3, 4, {}]])
|
81
|
+
_(positionals).must_equal [1, 2, 3, 4]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# In Ruby < 3.0, {*args} will grab both positionals and keyword arguments.
|
86
|
+
class Step
|
87
|
+
def with_positionals(a, b, *args)
|
88
|
+
[a, b, args]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
WITH_POSITIONALS = ->(a, b, *args) do
|
93
|
+
[a, b, args]
|
94
|
+
end
|
95
|
+
|
96
|
+
class WithPositionals
|
97
|
+
def self.call(a, b, *args)
|
98
|
+
[a, b, args]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
let(:positionals) { [1, 2, 3, 4] }
|
103
|
+
|
104
|
+
it ":method" do
|
105
|
+
step = Step.new
|
106
|
+
|
107
|
+
option = Trailblazer::Option(:with_positionals)
|
108
|
+
|
109
|
+
assert_result_pos option.(*positionals, exec_context: step)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "-> {} lambda" do
|
113
|
+
option = Trailblazer::Option(WITH_POSITIONALS)
|
114
|
+
|
115
|
+
assert_result_pos option.(*positionals, exec_context: "something")
|
116
|
+
end
|
117
|
+
|
118
|
+
it "callable" do
|
119
|
+
option = Trailblazer::Option(WithPositionals)
|
120
|
+
|
121
|
+
assert_result_pos option.(*positionals, exec_context: "something")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "keywords" do
|
126
|
+
def assert_result_kws(result)
|
127
|
+
_(keywords).must_equal({ a: 1, b: 2, c: 3, d: 4 })
|
128
|
+
_(result).must_equal([1, 2, { c: 3, d: 4 }])
|
129
|
+
end
|
130
|
+
|
131
|
+
# In Ruby < 3.0, {*args} will grab both positionals and keyword arguments.
|
132
|
+
class Step
|
133
|
+
def with_keywords(a:, b:, **rest)
|
134
|
+
[a, b, rest]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
WITH_KEYWORDS = ->(a:, b:, **rest) do
|
139
|
+
[a, b, rest]
|
140
|
+
end
|
141
|
+
|
142
|
+
class WithKeywords
|
143
|
+
def self.call(a:, b:, **rest)
|
144
|
+
[a, b, rest]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
let(:keywords) { { a: 1, b: 2, c: 3, d: 4 } }
|
149
|
+
|
150
|
+
it ":method" do
|
151
|
+
step = Step.new
|
152
|
+
|
153
|
+
option = Trailblazer::Option(:with_keywords)
|
154
|
+
|
155
|
+
assert_result_kws option.(keyword_arguments: keywords, exec_context: step)
|
156
|
+
end
|
157
|
+
|
158
|
+
it "-> {} lambda" do
|
159
|
+
option = Trailblazer::Option(WITH_KEYWORDS)
|
160
|
+
|
161
|
+
assert_result_kws option.(keyword_arguments: keywords, exec_context: "something")
|
162
|
+
end
|
163
|
+
|
164
|
+
it "callable" do
|
165
|
+
option = Trailblazer::Option(WithKeywords)
|
166
|
+
|
167
|
+
assert_result_kws option.(keyword_arguments: keywords, exec_context: "something")
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "trailblazer/option/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "trailblazer-option"
|
7
|
+
spec.version = Trailblazer::Option::VERSION
|
8
|
+
spec.authors = ["Nick Sutterer"]
|
9
|
+
spec.email = ["apotonick@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Callable patterns for options in Trailblazer"
|
12
|
+
spec.description = "Wrap an option at compile-time and `call` it at runtime, which allows to have the common `-> ()`, `:method` or `Callable` pattern used for most options."
|
13
|
+
spec.homepage = "https://trailblazer.to/"
|
14
|
+
spec.licenses = ["MIT"]
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r(^test/))
|
18
|
+
end
|
19
|
+
spec.test_files = `git ls-files -z test`.split("\x0")
|
20
|
+
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
24
|
+
spec.add_development_dependency "minitest-line", "~> 0.6.5"
|
25
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
26
|
+
|
27
|
+
spec.required_ruby_version = ">= 2.1.0"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trailblazer-option
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nick Sutterer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-04-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest-line
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.6.5
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.6.5
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '13.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '13.0'
|
55
|
+
description: Wrap an option at compile-time and `call` it at runtime, which allows
|
56
|
+
to have the common `-> ()`, `:method` or `Callable` pattern used for most options.
|
57
|
+
email:
|
58
|
+
- apotonick@gmail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".github/workflows/ci.yml"
|
64
|
+
- ".gitignore"
|
65
|
+
- CHANGES.md
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- bin/console
|
71
|
+
- bin/setup
|
72
|
+
- lib/trailblazer-option.rb
|
73
|
+
- lib/trailblazer/option.rb
|
74
|
+
- lib/trailblazer/option/version.rb
|
75
|
+
- test/option_test.rb
|
76
|
+
- test/test_helper.rb
|
77
|
+
- trailblazer-option.gemspec
|
78
|
+
homepage: https://trailblazer.to/
|
79
|
+
licenses:
|
80
|
+
- MIT
|
81
|
+
metadata: {}
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 2.1.0
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
requirements: []
|
97
|
+
rubygems_version: 3.0.8
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: Callable patterns for options in Trailblazer
|
101
|
+
test_files:
|
102
|
+
- test/option_test.rb
|
103
|
+
- test/test_helper.rb
|