behaves 0.2.0 → 0.3.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +29 -0
- data/lib/behaves.rb +61 -11
- data/lib/behaves/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c594bfaa286e772150c5e2c31c24fe2b4684cd4fbd68f16341cc30b6c9ebfe0
|
4
|
+
data.tar.gz: 5aa8758aee6a60747332ac0515a73a1bc3a63d3336870237b13290b09f1cda39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 87e3bf7f5c4c218c7e2cd8de1540577455cb51340bfc51f28fc6043a025315af8d07fe8802cdd750488152eb9649b219147534cc17ea08682c7b8b410312e476
|
7
|
+
data.tar.gz: 004aa2b59f31bd916b4df9380ef8d9a5bb3f6a24d88a09c549a85fbfd5b5a6cfc74d379d6c24681e19e6461aac9856be72253358ef66690da4e625f183b058c6
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -144,6 +144,35 @@ This extends to more than just method implementation too, you can do anything yo
|
|
144
144
|
|
145
145
|
*Do note that if you use this extensively, you might be better off using inheritance, since this will create more `Method` objects than inheritance.*
|
146
146
|
|
147
|
+
### Private Behaviors
|
148
|
+
|
149
|
+
Private behaviors can be defined like so:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
class Interface
|
153
|
+
extend Behaves
|
154
|
+
|
155
|
+
implements :foo
|
156
|
+
implements :bar, private: true
|
157
|
+
end
|
158
|
+
|
159
|
+
class Implementor
|
160
|
+
extend Behaves
|
161
|
+
|
162
|
+
behaves_like Interface
|
163
|
+
|
164
|
+
def foo
|
165
|
+
123
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
def bar
|
171
|
+
456
|
172
|
+
end
|
173
|
+
end
|
174
|
+
```
|
175
|
+
|
147
176
|
## Tips
|
148
177
|
If you do not want to type `extend Behaves` every time, you can monkey patch `Behaves` onto `Object` class, like so:
|
149
178
|
|
data/lib/behaves.rb
CHANGED
@@ -2,8 +2,15 @@ require 'behaves/version'
|
|
2
2
|
require 'set'
|
3
3
|
|
4
4
|
module Behaves
|
5
|
-
def implements(*methods)
|
6
|
-
@
|
5
|
+
def implements(*methods, **opts)
|
6
|
+
@_public_behaviors ||= Set.new
|
7
|
+
@_private_behaviors ||= Set.new
|
8
|
+
|
9
|
+
if opts[:private] == true
|
10
|
+
@_private_behaviors += Set.new(methods)
|
11
|
+
else
|
12
|
+
@_public_behaviors += Set.new(methods)
|
13
|
+
end
|
7
14
|
end
|
8
15
|
|
9
16
|
def inject_behaviors (&block)
|
@@ -12,25 +19,68 @@ module Behaves
|
|
12
19
|
|
13
20
|
def behaves_like(klass)
|
14
21
|
add_injected_behaviors(klass)
|
15
|
-
at_exit {
|
22
|
+
at_exit {
|
23
|
+
check_for_unimplemented(klass, :public)
|
24
|
+
check_for_unimplemented(klass, :private)
|
25
|
+
}
|
16
26
|
end
|
17
27
|
|
18
28
|
private
|
19
29
|
|
20
|
-
def check_for_unimplemented(klass)
|
21
|
-
required = defined_behaviors(klass)
|
30
|
+
def check_for_unimplemented(klass, scope)
|
31
|
+
required = defined_behaviors(klass, scope)
|
22
32
|
|
23
|
-
|
24
|
-
|
25
|
-
unimplemented = required - implemented
|
33
|
+
unimplemented = required - implemented(scope)
|
26
34
|
|
27
35
|
return if unimplemented.empty?
|
28
36
|
|
29
|
-
|
37
|
+
|
38
|
+
# basic "unimplemented method" error message
|
39
|
+
|
40
|
+
err = <<~ERR
|
41
|
+
\n\n Expected `#{self}` to behave like `#{klass}`, but the following #{scope} methods are unimplemented:\n
|
42
|
+
#{unimplemented.to_a.map{|method| " * `#{method}`"}.join("\n")}\n
|
43
|
+
ERR
|
44
|
+
|
45
|
+
|
46
|
+
# add "wrong scope" message
|
47
|
+
|
48
|
+
other_scopes = (scope == :public) ? [:private] : [:public]
|
49
|
+
methods_in_other_scopes = Set.new( other_scopes.map{|s| implemented(s)}.map(&:to_a).flatten.compact )
|
50
|
+
methods_in_wrong_scope = unimplemented && methods_in_other_scopes
|
51
|
+
|
52
|
+
if !methods_in_wrong_scope.empty?
|
53
|
+
err += <<~ERR
|
54
|
+
\n The following methods appear to be defined, but in the wrong scope:\n
|
55
|
+
#{methods_in_wrong_scope.to_a.map{|method| " * `#{method}`"}.join("\n")}\n\n
|
56
|
+
ERR
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
raise NotImplementedError, err
|
61
|
+
end
|
62
|
+
|
63
|
+
def implemented(scope)
|
64
|
+
lookups = {
|
65
|
+
public: :instance_methods,
|
66
|
+
private: :private_instance_methods,
|
67
|
+
}
|
68
|
+
|
69
|
+
method_lookup_sym = lookups.fetch(scope) do
|
70
|
+
raise ArgumentError.new <<~ERR
|
71
|
+
|
72
|
+
Invalid `scope`: #{scope}
|
73
|
+
Valid `scope`s include: #{lookups.keys.map{|sym| "`#{sym.inspect}`"}.join(', ')}
|
74
|
+
ERR
|
75
|
+
end
|
76
|
+
|
77
|
+
methods = self.send(method_lookup_sym, false)
|
78
|
+
|
79
|
+
Set.new(methods)
|
30
80
|
end
|
31
81
|
|
32
|
-
def defined_behaviors(klass)
|
33
|
-
if behaviors = klass.instance_variable_get("@
|
82
|
+
def defined_behaviors(klass, scope)
|
83
|
+
if behaviors = klass.instance_variable_get(:"@_#{scope}_behaviors")
|
34
84
|
behaviors
|
35
85
|
else
|
36
86
|
raise NotImplementedError, "Expected `#{klass}` to define behaviors, but none found."
|
data/lib/behaves/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: behaves
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Edison Yap
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|