dry-behaviour 0.11.2 → 0.12.1
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 +5 -5
- data/.github/workflows/ci.yml +15 -11
- data/.github/workflows/gempush.yml +3 -3
- data/.tool-versions +1 -0
- data/README.md +39 -0
- data/lib/dry/behaviour/black_tie.rb +55 -29
- data/lib/dry/behaviour/version.rb +1 -1
- metadata +5 -4
- data/.travis.yml +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e6de5e26b1d3d57039660055f9248c1a3df5431d
|
4
|
+
data.tar.gz: 17404270b966673dd7d7c56d6966d1a93cf58cfd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb1ddcc3af289266d79dfd8c38b33fd47f4db8f3d2533e4aec395ff353490876bbf2554e241b23c5e56b45b81bec623f79baa97eede969071ab07c7ab7e24eba
|
7
|
+
data.tar.gz: 02e81fe058128b1ebdbb4fe34ed5811c9bd6da01ab91742235bb57f87b29adfc3824d33885e507137e724fffac7d793d3a33da7882b4dc766de8601a7df43c0e
|
data/.github/workflows/ci.yml
CHANGED
@@ -3,18 +3,22 @@ name: Ruby
|
|
3
3
|
on: [push]
|
4
4
|
|
5
5
|
jobs:
|
6
|
-
|
6
|
+
test:
|
7
7
|
|
8
8
|
runs-on: ubuntu-latest
|
9
9
|
|
10
|
+
strategy:
|
11
|
+
fail-fast: false
|
12
|
+
matrix:
|
13
|
+
ruby-version: ['head', '3.1', '3.0', '2.7']
|
14
|
+
|
10
15
|
steps:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
bundle
|
20
|
-
bundle exec rake
|
16
|
+
- uses: actions/checkout@v3
|
17
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
18
|
+
uses: ruby/setup-ruby@359bebbc29cbe6c87da6bc9ea3bc930432750108
|
19
|
+
with:
|
20
|
+
ruby-version: ${{ matrix.ruby-version }}
|
21
|
+
- name: Install dependencies
|
22
|
+
run: bundle install --jobs 4 --retry 3
|
23
|
+
- name: Run tests
|
24
|
+
run: bundle exec rspec
|
@@ -15,10 +15,10 @@ jobs:
|
|
15
15
|
|
16
16
|
steps:
|
17
17
|
- uses: actions/checkout@master
|
18
|
-
- name: Set up Ruby 2.
|
19
|
-
uses:
|
18
|
+
- name: Set up Ruby 2.3.8
|
19
|
+
uses: ruby/setup-ruby@v1
|
20
20
|
with:
|
21
|
-
version: 2.
|
21
|
+
version: 2.3.8
|
22
22
|
|
23
23
|
- name: Publish to GPR
|
24
24
|
run: |
|
data/.tool-versions
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby 2.3.8
|
data/README.md
CHANGED
@@ -60,6 +60,45 @@ expect(Protocols::Adder.add(nil, 10)).to eq(10)
|
|
60
60
|
expect(Protocols::Adder.add_default(1)).to eq(6)
|
61
61
|
```
|
62
62
|
|
63
|
+
### Arguments types
|
64
|
+
|
65
|
+
Normally, one would use a simple notation to declare a method. It includes `:this` receiver
|
66
|
+
in te very first position and some optional required arguments afterward.
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
defmethod :add, :this, :addend
|
70
|
+
...
|
71
|
+
defimpl ... do
|
72
|
+
def add(this, addend); this + addend; end
|
73
|
+
end
|
74
|
+
```
|
75
|
+
|
76
|
+
If the argument is not generic (optional, or splatted, or keyword,) its type must be explicitly
|
77
|
+
specified in the protocol definition as shown below.
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
defprotocol implicit_inheritance: true do
|
81
|
+
defmethod :with_def_argument, :this, [:foo_opt, :opt]
|
82
|
+
defmethod :with_def_keyword_argument, :this, [:foo_key, :key]
|
83
|
+
defmethod :with_req_keyword_argument, :this, [:foo_key, :keyreq]
|
84
|
+
|
85
|
+
def with_def_argument(this, foo_opt = :super); foo_opt; end
|
86
|
+
def with_def_keyword_argument(this, foo_key: :super); foo_key; end
|
87
|
+
def with_req_keyword_argument(this, foo_key:); foo_key; end
|
88
|
+
...
|
89
|
+
```
|
90
|
+
|
91
|
+
That said, `:addend` argument declaration is a syntactic sugar for `[:addend, :req]`.
|
92
|
+
Possible values for the type are:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
PARAM_TYPES = %i[req opt rest key keyrest keyreq block]
|
96
|
+
```
|
97
|
+
|
98
|
+
Please note, that the signature of the method and its implementation must exactly match.
|
99
|
+
One cannot declare a method to have a `keyreq` argument and then make it defaulted in the
|
100
|
+
implementation. That is done by design.
|
101
|
+
|
63
102
|
## Guards
|
64
103
|
|
65
104
|
Starting with `v0.5.0` we support multiple function clauses and guards.
|
@@ -8,7 +8,7 @@ module Dry
|
|
8
8
|
class << self
|
9
9
|
def proto_caller
|
10
10
|
caller.drop_while do |line|
|
11
|
-
line =~ %r
|
11
|
+
line =~ %r{dry-behaviour/lib/dry/behaviour}
|
12
12
|
end.first
|
13
13
|
end
|
14
14
|
|
@@ -20,7 +20,7 @@ module Dry
|
|
20
20
|
require 'logger'
|
21
21
|
Logger.new($stdout)
|
22
22
|
end
|
23
|
-
@logger
|
23
|
+
@logger || Class.new { def warn(*); end }.new
|
24
24
|
end
|
25
25
|
|
26
26
|
def protocols
|
@@ -33,8 +33,8 @@ module Dry
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def defprotocol(implicit_inheritance: false, &λ)
|
36
|
-
raise ::Dry::Protocol::DuplicateDefinition
|
37
|
-
raise ::Dry::Protocol::MalformedDefinition
|
36
|
+
raise ::Dry::Protocol::DuplicateDefinition, self if BlackTie.protocols.key?(self)
|
37
|
+
raise ::Dry::Protocol::MalformedDefinition, self unless block_given?
|
38
38
|
|
39
39
|
BlackTie.protocols[self][:__implicit_inheritance__] = !!implicit_inheritance
|
40
40
|
|
@@ -54,21 +54,38 @@ module Dry
|
|
54
54
|
end.reject(&:nil?).first
|
55
55
|
end
|
56
56
|
|
57
|
-
BlackTie.protocols[self].each do |method, *
|
58
|
-
singleton_class.send :define_method, method do |receiver
|
57
|
+
BlackTie.protocols[self].each do |method, *_m_args, **_m_kwargs| # FIXME: CHECK ARITY HERE
|
58
|
+
# singleton_class.send :define_method, method do |receiver, *args, **kwargs|
|
59
|
+
singleton_class.send :define_method, method do |*args, **kwargs|
|
60
|
+
if args == []
|
61
|
+
receiver = kwargs
|
62
|
+
kwargs = {}
|
63
|
+
else
|
64
|
+
receiver, *args = args
|
65
|
+
end
|
66
|
+
|
59
67
|
impl = implementation_for(receiver)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
68
|
+
|
69
|
+
unless impl
|
70
|
+
raise Dry::Protocol::NotImplemented.new(
|
71
|
+
:protocol, inspect,
|
72
|
+
method: method, receiver: receiver, args: args, self: self
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
64
76
|
begin
|
65
|
-
|
66
|
-
|
77
|
+
# [AM] [v1] [FIXME] for modern rubies `if` is redundant
|
78
|
+
if kwargs.empty?
|
79
|
+
impl[method].(*args.unshift(receiver))
|
80
|
+
else
|
81
|
+
impl[method].(*args.unshift(receiver), **kwargs)
|
82
|
+
end
|
83
|
+
rescue StandardError => e
|
67
84
|
raise Dry::Protocol::NotImplemented.new(
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
85
|
+
:nested, inspect,
|
86
|
+
cause: e,
|
87
|
+
method: method, receiver: receiver, args: args, impl: impl, self: self
|
88
|
+
)
|
72
89
|
end
|
73
90
|
end
|
74
91
|
end
|
@@ -80,16 +97,16 @@ module Dry
|
|
80
97
|
|
81
98
|
def defmethod(name, *params)
|
82
99
|
if params.size.zero? || params.first.is_a?(Array) && params.first.last != :req
|
83
|
-
BlackTie.Logger.warn(IMPLICIT_RECEIVER_DECLARATION
|
100
|
+
BlackTie.Logger.warn(format(IMPLICIT_RECEIVER_DECLARATION, Dry::BlackTie.proto_caller, inspect, name))
|
84
101
|
params.unshift(:this)
|
85
102
|
end
|
86
103
|
params =
|
87
104
|
params.map do |p, type|
|
88
105
|
if type && !PARAM_TYPES.include?(type)
|
89
|
-
BlackTie.Logger.warn(UNKNOWN_TYPE_DECLARATION
|
106
|
+
BlackTie.Logger.warn(format(UNKNOWN_TYPE_DECLARATION, Dry::BlackTie.proto_caller, type, inspect, name))
|
90
107
|
type = nil
|
91
108
|
end
|
92
|
-
[type || PARAM_TYPES.include?(p) ? p : :req, p]
|
109
|
+
[type || (PARAM_TYPES.include?(p) ? p : :req), p]
|
93
110
|
end
|
94
111
|
BlackTie.protocols[self][name] = params
|
95
112
|
end
|
@@ -109,13 +126,18 @@ module Dry
|
|
109
126
|
(NORMALIZE_KEYS.(protocol) - meths).each_with_object(meths) do |m, acc|
|
110
127
|
if BlackTie.protocols[protocol][:__implicit_inheritance__]
|
111
128
|
mod.singleton_class.class_eval do
|
112
|
-
define_method m do |this, *♿_args, &♿_λ|
|
113
|
-
|
129
|
+
define_method m do |this, *♿_args, **♿_kwargs, &♿_λ|
|
130
|
+
# [AM] [v1] [FIXME] for modern rubies `if` is redundant
|
131
|
+
if ♿_kwargs.empty?
|
132
|
+
super(this, *♿_args, &♿_λ)
|
133
|
+
else
|
134
|
+
super(this, *♿_args, **♿_kwargs, &♿_λ)
|
135
|
+
end
|
114
136
|
end
|
115
137
|
end
|
116
138
|
else
|
117
139
|
BlackTie.Logger.warn(
|
118
|
-
IMPLICIT_DELEGATE_DEPRECATION
|
140
|
+
format(IMPLICIT_DELEGATE_DEPRECATION, Dry::BlackTie.proto_caller, protocol.inspect, m, target)
|
119
141
|
)
|
120
142
|
DELEGATE_METHOD.(mod.singleton_class, [m] * 2)
|
121
143
|
end
|
@@ -128,13 +150,17 @@ module Dry
|
|
128
150
|
proto = BlackTie.protocols[protocol]
|
129
151
|
ok =
|
130
152
|
mds.map(&:first).include?(m) ||
|
131
|
-
((proto[m] == {} || proto[:__implicit_inheritance__]) && [[:req],
|
153
|
+
((proto[m] == {} || proto[:__implicit_inheritance__]) && [[:req],
|
154
|
+
[:rest]].include?(params.map(&:first))) ||
|
132
155
|
[proto[m], params].map { |args| args.map(&:first) }.reduce(:==)
|
133
156
|
|
134
157
|
# TODO[1.0] raise NotImplemented(:arity)
|
135
|
-
|
136
|
-
|
137
|
-
|
158
|
+
unless ok
|
159
|
+
BlackTie.Logger.warn(
|
160
|
+
format(WRONG_PARAMETER_DECLARATION, Dry::BlackTie.proto_caller, protocol.inspect, m, target,
|
161
|
+
BlackTie.protocols[protocol][m].map(&:first))
|
162
|
+
)
|
163
|
+
end
|
138
164
|
|
139
165
|
BlackTie.implementations[protocol][tgt][m] = mod.method(m).to_proc
|
140
166
|
end
|
@@ -143,7 +169,7 @@ module Dry
|
|
143
169
|
end
|
144
170
|
module_function :defimpl
|
145
171
|
|
146
|
-
PARAM_TYPES = %i[req opt rest keyrest block]
|
172
|
+
PARAM_TYPES = %i[req opt rest key keyrest keyreq block]
|
147
173
|
|
148
174
|
DELEGATE_METHOD = lambda do |klazz, (source, target)|
|
149
175
|
klazz.class_eval do
|
@@ -176,7 +202,7 @@ module Dry
|
|
176
202
|
"\n⚠️ TOO IMPLICIT → %s\n" \
|
177
203
|
" ⮩ Implicit declaration of `this' parameter in `defmethod'.\n" \
|
178
204
|
" ⮩ Whilst it’s allowed, we strongly encourage to explicitly declare it\n" \
|
179
|
-
|
205
|
+
' ⮩ in call to %s#defmethod(%s).'.freeze
|
180
206
|
|
181
207
|
UNKNOWN_TYPE_DECLARATION =
|
182
208
|
"\n⚠️ UNKNOWN TYPE → %s\n" \
|
@@ -189,7 +215,7 @@ module Dry
|
|
189
215
|
" ⮩ Wrong parameters declaration will be removed in 1.0\n" \
|
190
216
|
" ⮩ %s#%s was implemented for %s with unexpected parameters.\n" \
|
191
217
|
" ⮩ Consider implementing interfaces exactly as they were declared.\n" \
|
192
|
-
|
218
|
+
' ⮩ Expected: %s'.freeze
|
193
219
|
|
194
220
|
private
|
195
221
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-behaviour
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aleksei Matiushkin
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2023-02-01 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -111,7 +111,7 @@ files:
|
|
111
111
|
- ".rspec"
|
112
112
|
- ".rubocop.yml"
|
113
113
|
- ".rubocop_todo.yml"
|
114
|
-
- ".
|
114
|
+
- ".tool-versions"
|
115
115
|
- CODE_OF_CONDUCT.md
|
116
116
|
- Gemfile
|
117
117
|
- LICENSE.txt
|
@@ -149,7 +149,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
149
149
|
- !ruby/object:Gem::Version
|
150
150
|
version: '0'
|
151
151
|
requirements: []
|
152
|
-
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 2.5.2.3
|
153
154
|
signing_key:
|
154
155
|
specification_version: 4
|
155
156
|
summary: Tiny library inspired by Elixir protocol pattern.
|