behaves 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cd22ae5f7d6af9cc2a76a8d7b73d7ec25af7c759afac262731ef56c79f1d9a3b
4
- data.tar.gz: b5abbc034aa95a5067bed0ce7eb2f5472c6b3e89333d8128806499ea25d38fdc
3
+ metadata.gz: 4c594bfaa286e772150c5e2c31c24fe2b4684cd4fbd68f16341cc30b6c9ebfe0
4
+ data.tar.gz: 5aa8758aee6a60747332ac0515a73a1bc3a63d3336870237b13290b09f1cda39
5
5
  SHA512:
6
- metadata.gz: a809170ad8c43554ee5a6845ec558ce803a766ec216a088c7fb21b6b92c355dc5d618b340a48fdf5eb4cb80079d40c429622d8a344998a3a278454aa84414129
7
- data.tar.gz: 1ed4e8d27bd2171cc0e2020c1fa869ff099c887ebaeb2ef35c4d639c715d5b5e3787910e272a99b7a5c0b5fe0e31fc0af29715f1de40364652bd32bca113c4ac
6
+ metadata.gz: 87e3bf7f5c4c218c7e2cd8de1540577455cb51340bfc51f28fc6043a025315af8d07fe8802cdd750488152eb9649b219147534cc17ea08682c7b8b410312e476
7
+ data.tar.gz: 004aa2b59f31bd916b4df9380ef8d9a5bb3f6a24d88a09c549a85fbfd5b5a6cfc74d379d6c24681e19e6461aac9856be72253358ef66690da4e625f183b058c6
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- behaves (0.1.1)
4
+ behaves (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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
 
@@ -2,8 +2,15 @@ require 'behaves/version'
2
2
  require 'set'
3
3
 
4
4
  module Behaves
5
- def implements(*methods)
6
- @behaviors ||= Set.new(methods)
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 { check_for_unimplemented(klass) }
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
- implemented = Set.new(self.instance_methods - Object.instance_methods)
24
-
25
- unimplemented = required - implemented
33
+ unimplemented = required - implemented(scope)
26
34
 
27
35
  return if unimplemented.empty?
28
36
 
29
- raise NotImplementedError, "Expected `#{self}` to behave like `#{klass}`, but `#{unimplemented.to_a.join(', ')}` are not implemented."
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("@behaviors")
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."
@@ -1,3 +1,3 @@
1
1
  module Behaves
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
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.2.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-18 00:00:00.000000000 Z
11
+ date: 2019-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry