dry-behaviour 0.7.0 → 0.8.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
  SHA1:
3
- metadata.gz: 68e9909166c5283d9505f7be6f541334aea5d161
4
- data.tar.gz: 2319fcbbb2da7b56aff3825e44788d44da99a688
3
+ metadata.gz: c9950cb0ec4cecfed71f7cae1cd777a0693ed8b5
4
+ data.tar.gz: a77cc845e72319b08e222e3ab7c820f87359e6a2
5
5
  SHA512:
6
- metadata.gz: cd3f037341b4f6f2e28d9e4478d763fc6bd554d09e5be20be2ac08c2fad405be3a2ce8e45a273cdd0c6bbbf26efd8ee0abaf4edb6d48e4760c933ebaf54d1397
7
- data.tar.gz: cea7c3a4b77dbc7cc4215e38b853c92d96670fe8677c771a2d1914b6e60293d163fc00d9bd3a60b97966849e5a7f025cb3b39c0b30afb933c62e25dfdafb4497
6
+ metadata.gz: d7f410dc7fb586256831916469d2d7bdcd74361235a74c891ac90ea8609bc69e343d9585d211a8b91abd9f88b443a60509bb9418df4201917fc01e170815346a
7
+ data.tar.gz: f4d1c1116169906a8efc11ea289c45d150cd920a3dcc2cbbc2c0f73870f449b2f102478e3a5aa54d6fb5a8c9e1d87031532f57a147d322d9d41d6ba885be75cc
data/README.md CHANGED
@@ -100,9 +100,41 @@ end
100
100
 
101
101
  ## Changelog
102
102
 
103
+ ### `0.8.0` :: Implicit Inheritance
104
+
105
+ - deprecate implicit delegation to the target instance; error message saying “it’ll be removed in 1.0”
106
+ - `implicit_inheritance: true` flag in call to `defprotocol` makes the implementation implicitly inherit the behaviour declared in the core protocol module itself, without the necessity to explicitly call `super`:
107
+
108
+ ```diff
109
+ module ParentOKImplicit
110
+ include Dry::Protocol
111
+
112
+ - defprotocol do
113
+ + defprotocol implicit_inheritance: true do
114
+ defmethod :foo
115
+
116
+ def foo(this)
117
+ :ok
118
+ end
119
+
120
+ defimpl target: String do
121
+ - def foo(this)
122
+ - super(this)
123
+ - end
124
+ end
125
+ end
126
+ end
127
+ ```
128
+
129
+ ### `0.7.0` :: Handling Errors
130
+
131
+ - better error messages (very descriptive, with whys and howtos)
132
+ - the whole stacktrace is carefully saved with `cause`
133
+ - internal exceptions related to wrong implementation do now point to the proper lines in the client code (internal trace lines are removed)
134
+
103
135
  ### `0.6.0` :: Bugfix
104
136
 
105
- - Implementation for classes responding to **`to_a`** is handled properly
137
+ - implementation for classes responding to **`to_a`** is handled properly
106
138
 
107
139
  ### `0.5.0` :: Guards
108
140
 
@@ -15,12 +15,14 @@ module Dry
15
15
  end
16
16
  end
17
17
 
18
- def defprotocol
19
- raise if BlackTie.protocols.key?(self) # DUPLICATE DEF
20
- raise unless block_given?
18
+ def defprotocol(implicit_inheritance: false, &λ)
19
+ raise ::Dry::Protocol::DuplicateDefinition.new(self) if BlackTie.protocols.key?(self)
20
+ raise ::Dry::Protocol::MalformedDefinition.new(self) unless block_given?
21
+
22
+ BlackTie.protocols[self][:__implicit_inheritance__] = !!implicit_inheritance
21
23
 
22
24
  ims = instance_methods(false)
23
- class_eval(&Proc.new)
25
+ class_eval()
24
26
  (instance_methods(false) - ims).each { |m| class_eval { module_function m } }
25
27
 
26
28
  singleton_class.send :define_method, :method_missing do |method, *_args|
@@ -55,7 +57,7 @@ module Dry
55
57
  end
56
58
 
57
59
  singleton_class.send :define_method, :respond_to? do |method|
58
- BlackTie.protocols[self].keys.include? method
60
+ NORMALIZE_KEYS.(self).include? method
59
61
  end
60
62
  end
61
63
 
@@ -78,21 +80,42 @@ module Dry
78
80
  end.enable
79
81
  end
80
82
 
81
- def defimpl(protocol = nil, target: nil, delegate: [], map: {})
83
+ NORMALIZE_KEYS = lambda do |protocol|
84
+ BlackTie.protocols[protocol].keys.reject { |k| k.to_s =~ /\A__.*__\z/ }
85
+ end
86
+
87
+ IMPLICIT_DELEGATE_DEPRECATION =
88
+ "\n⚠️ DEPRECATED → Implicit delegation to the target class will be removed in 1.0\n" \
89
+ "  ⮩ due to the lack of the explicit implementation of %s#%s for %s\n" \
90
+ "  ⮩ it will be delegated to the target class itself.\n" \
91
+ "  ⮩ Consider using explicit `delegate:' declaration in `defimpl' or\n" \
92
+ "  ⮩ use `implicit_inheritance: true' parameter in protocol definition.".freeze
93
+
94
+ def defimpl(protocol = nil, target: nil, delegate: [], map: {}, &λ)
82
95
  raise if target.nil? || !block_given? && delegate.empty? && map.empty?
83
96
 
84
97
  mds = normalize_map_delegates(delegate, map)
85
98
 
86
99
  Module.new do
87
100
  mds.each(&DELEGATE_METHOD.curry[singleton_class])
88
- singleton_class.class_eval(&Proc.new) if block_given? # block takes precedence
101
+ singleton_class.class_eval() if block_given? # block takes precedence
89
102
  end.tap do |mod|
90
103
  protocol ? mod.extend(protocol) : POSTPONE_EXTEND.(mod, protocol = self)
91
104
 
92
105
  mod.methods(false).tap do |meths|
93
- (BlackTie.protocols[protocol].keys - meths).each_with_object(meths) do |m, acc|
94
- BlackTie.Logger.warn("Implicit delegate #{protocol.inspect}##{m} to #{target}")
95
- DELEGATE_METHOD.(mod.singleton_class, [m] * 2)
106
+ (NORMALIZE_KEYS.(protocol) - meths).each_with_object(meths) do |m, acc|
107
+ if BlackTie.protocols[protocol][:__implicit_inheritance__]
108
+ mod.singleton_class.class_eval do
109
+ define_method m do |*args, &λ|
110
+ super(*args, &λ)
111
+ end
112
+ end
113
+ else
114
+ BlackTie.Logger.warn(
115
+ IMPLICIT_DELEGATE_DEPRECATION % [protocol.inspect, m, target]
116
+ )
117
+ DELEGATE_METHOD.(mod.singleton_class, [m] * 2)
118
+ end
96
119
  acc << m
97
120
  end
98
121
  end.each do |m|
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Behaviour
3
- VERSION = '0.7.0'.freeze
3
+ VERSION = '0.8.0'.freeze
4
4
  end
5
5
  end
@@ -0,0 +1,9 @@
1
+ module Dry
2
+ module Protocol
3
+ class DuplicateDefinition < StandardError
4
+ def initialize(suspect)
5
+ super "Duplicate definition of “#{suspect.inspect}” detected."
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Dry
2
+ module Protocol
3
+ class MalformedDefinition < StandardError
4
+ def initialize(suspect)
5
+ super "Malformed definition of “#{suspect.inspect}”. Block required."
6
+ end
7
+ end
8
+ end
9
+ end
@@ -13,10 +13,11 @@ module Dry
13
13
  when :method
14
14
  "Protocol “#{@proto}” does not declare method “#{@details[:method]}”."
15
15
  when :nested
16
- "Protocol “#{@proto}” failed to invoke the implementation.\n" \
17
- " ⮩ caused by “#{cause.class}” with a message\n" \
16
+ "Protocol “#{@proto}” failed to invoke the implementation for\n" \
17
+ " ⮩ “#{@details[:receiver].class}##{@details[:method]}”.\n" \
18
+ " ⮩ Caused by “#{cause.class}” with a message\n" \
18
19
  " ⮩ “#{cause.message}”\n" \
19
- " ⮩ rescue this exception and inspect `NotImplemented#cause' for details."
20
+ " ⮩ Rescue this exception and inspect `NotImplemented#cause' for details."
20
21
  else
21
22
  "Protocol “#{proto}” is invalid."
22
23
  end
data/lib/dry/errors.rb CHANGED
@@ -1,4 +1,7 @@
1
1
  require 'dry/errors/not_implemented'
2
2
  require 'dry/errors/not_protocol'
3
+ require 'dry/errors/duplicate_definition'
4
+ require 'dry/errors/malformed_definition'
5
+
3
6
  require 'dry/errors/not_guardable'
4
7
  require 'dry/errors/not_matched'
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.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aleksei Matiushkin
@@ -124,6 +124,8 @@ files:
124
124
  - lib/dry/behaviour/cerberus.rb
125
125
  - lib/dry/behaviour/version.rb
126
126
  - lib/dry/errors.rb
127
+ - lib/dry/errors/duplicate_definition.rb
128
+ - lib/dry/errors/malformed_definition.rb
127
129
  - lib/dry/errors/not_guardable.rb
128
130
  - lib/dry/errors/not_implemented.rb
129
131
  - lib/dry/errors/not_matched.rb