racket-registry 0.2.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d0ba35e3b8ae749a231ddfb8ebc8c1be932123fc
4
- data.tar.gz: dd77a4e59f964f4f23cddad580d3942ec5fc8096
3
+ metadata.gz: efdb66903525e8c25d4c9254fabeec1ba8171650
4
+ data.tar.gz: 30839afe56b0fd154c0cb1b99b4baa1e026055be
5
5
  SHA512:
6
- metadata.gz: 61e50e05a2981477850b0f431d8dcfd6c50440829f6b2dd89e78bfe2e3367b38930a0ca7d1404b8fb29d9062aa6bd45da1d728bd4b1b685961843707b4da7413
7
- data.tar.gz: 585da05068ae97d15b38247fdfe8c1625f97b18eddb8a4cdec8f3fd97cd310f4eccc06683a3dca703882189c0fb3d5449e597870213eee4a3649b4b18f69594f
6
+ metadata.gz: 6c1f7bf54264adcbb648b9c3c322a7cce347caea3d9c84d14b6a880c6636d16b6e11c398cb5eb3cc9ca980fede07c638e2c8518ddaaf66ec70975e97b4c94de6
7
+ data.tar.gz: 76634886929c092c1f44c412a2443c94f7fafe63e925ef20501e6bb501ec79cff0573fba5445faa2a348a5ecc05edfe6ecdc5cb3963ae2cd429d76f650c8beb3
data/README.md CHANGED
@@ -8,7 +8,7 @@ Racket Registry was originally intended for use in my home-made web framework, [
8
8
  The intention of the this library is to provide a very simple dependency injection container. Although not as useful in ruby as in less dynamic languages, I still think using a service container has its uses.
9
9
 
10
10
  ## How?
11
- Racket Registry allows you to register two kinds of procs, non-singletons and singletons. Registering also means that the container gets a new public method corresponding to the key used when registering the proc.
11
+ Racket Registry allows you to register two kinds of callbacks, non-singletons and singletons. Registering also means that the container gets a new public method corresponding to the key used when registering the callback.
12
12
 
13
13
  ```ruby
14
14
  require 'racket/registry'
@@ -83,5 +83,10 @@ registry.register(:foo, lambda { Object.new })
83
83
  registry.register(:foo) { Object.new }
84
84
  ```
85
85
 
86
+ ## "Unregistering" callbacks
87
+
88
+ If you want to "unregister" a specific callback, you can use `registry.forget(key)`. If you want to unregister all callbacks,
89
+ you can use `registry.forget_all`.
90
+
86
91
  ## Limitations
87
- When registering a proc, you must use a string/symbol as key. Since the registry is also defining a new public method, the key must not collide with any public method in Object or Racket::Registry.
92
+ When registering a callback, you must use a string/symbol as key. Since the registry is also defining a new public method, the key must represent a valid method name and also not collide with any public method in the registry.
@@ -20,79 +20,167 @@
20
20
  module Racket
21
21
  # Racket Registry namespace
22
22
  class Registry
23
- def initialize
24
- @resolved = {}
23
+ # Removes the callback specified by +key+ from the registry.
24
+ #
25
+ # @param [String|Symbol] key
26
+ # @return [nil]
27
+ def forget(key)
28
+ self.class.forget(obj: self, key: key)
25
29
  end
26
30
 
27
- # Registers a new proc in the registry. This will add a new method
31
+ # Removes all callbacks from the registry.
32
+ def forget_all
33
+ self.class.forget_all(obj: self)
34
+ end
35
+
36
+ # Registers a new callback in the registry. This will add a new method
28
37
  # matching +key+ to the registry that can be used both outside the
29
- # registry and when registering other procs dependant of the
30
- # current entry. Results from the proc will not be cached, meaning
31
- # that the proc may return a different object every time.
38
+ # registry and when registering other callbacks dependant of the
39
+ # current entry. Results from the callback will not be cached, meaning
40
+ # that the callback may return a different object every time.
32
41
  #
33
42
  # @param [String|Symbol] key
34
43
  # @param [Proc|nil] proc
35
44
  # @return [nil]
36
45
  def register(key, proc = nil, &block)
37
- key, proc, proc_args, =
38
- ClassMethods.validate_usable([key, self, proc, block, @resolved])
39
- singleton_class.instance_eval do
40
- define_method(key) { proc.call(*proc_args) }
41
- end && nil
46
+ self.class.register(
47
+ obj: self, key: key, proc: proc, block: block
48
+ )
42
49
  end
43
50
 
44
- # Registers a new proc in the registry. This will add a new method
51
+ # Registers a new callback in the registry. This will add a new method
45
52
  # matching +key+ to the registry that can be used both outside the
46
- # registry and when registering other procs dependant of the
47
- # current entry. Results from the proc will be cached, meaning
48
- # that the proc will return the same object every time.
53
+ # registry and when registering other callbacks dependant of the
54
+ # current entry. Results from the callnack will be cached, meaning
55
+ # that the callback will return the same object every time.
49
56
  #
50
57
  # @param [String|Symbol] key
51
58
  # @param [Proc|nil] proc
52
59
  # @return [nil]
53
60
  def register_singleton(key, proc = nil, &block)
54
- key, proc, proc_args, resolved =
55
- ClassMethods.validate_usable([key, self, proc, block, @resolved])
56
- singleton_class.instance_eval do
57
- define_method(key) do
58
- return resolved[key] if resolved.key?(key)
59
- resolved[key] = proc.call(*proc_args)
60
- end
61
- end && nil
61
+ self.class.register_singleton(
62
+ obj: self, key: key, proc: proc, block: block
63
+ )
62
64
  end
63
65
 
64
66
  alias singleton register_singleton
65
67
 
66
- # Racket Registry class methods
67
- module ClassMethods
68
- # Validates that the parameters sent to the registry is usable.
69
- #
70
- # @param [Array] args
71
- # @return [Array]
72
- def self.validate_usable(args)
73
- key, obj, proc, block, resolved = args
74
- key = validate_key(key, obj)
75
- proc = validate_proc(proc, block)
76
- [key, proc, proc.arity.zero? ? [] : [obj], resolved]
77
- end
78
-
79
- def self.validate_key(key, obj)
80
- sym = key.to_sym
81
- insp = key.inspect
82
- raise "Invalid key #{insp}" if
83
- Racket::Registry.public_methods.include?(sym) ||
84
- /^[a-z\_]{1}[\d\w\_]*$/ !~ sym
85
- raise "Key #{insp} already registered" if obj.respond_to?(key)
86
- sym
87
- end
88
-
89
- def self.validate_proc(proc, block)
90
- return proc if proc.respond_to?(:call)
91
- return block if block.respond_to?(:call)
92
- raise 'No proc/block given'
93
- end
94
-
95
- private_class_method :validate_key, :validate_proc
68
+ # Removes a callback from a registry.
69
+ #
70
+ # @param [Hash] options
71
+ # @return [nil]
72
+ def self.forget(options)
73
+ obj, methods, key = validate_existing(options)
74
+ raise KeyNotRegisteredError,
75
+ "Key #{key} is not registered" unless methods.include?(key)
76
+ obj.singleton_class.instance_eval do
77
+ @resolved.delete(key) if defined?(@resolved)
78
+ remove_method(key)
79
+ end && nil
80
+ end
81
+
82
+ # Removes all callbacks from a registry.
83
+ #
84
+ # @param [Hash] options
85
+ # @return [nil]
86
+ def self.forget_all(options)
87
+ obj, methods, = validate_existing(options)
88
+ obj.singleton_class.instance_eval do
89
+ @resolved.clear if defined?(@resolved)
90
+ methods.each { |meth| remove_method(meth) }
91
+ end && nil
92
+ end
93
+
94
+ # Registers a new callback to a registry. This will add a new method
95
+ # matching +key+ to the registry that can be used both outside the
96
+ # registry and when registering other callbacks dependant of the
97
+ # current entry. Results from the callback will not be cached, meaning
98
+ # that the callback may return a different object every time.
99
+ #
100
+ # @param [Hash] options
101
+ # @return [nil]
102
+ def self.register(options)
103
+ key, proc, proc_args, obj = validate_usable(options)
104
+ obj.define_singleton_method(key) do
105
+ proc.call(*proc_args)
106
+ end && nil
107
+ end
108
+
109
+ # Registers a new callback to a registry. This will add a new method
110
+ # matching +key+ to the registry that can be used both outside the
111
+ # registry and when registering other callbacks dependant of the
112
+ # current entry. Results from the callback will be cached, meaning
113
+ # that the callback will return the same object every time.
114
+ #
115
+ # @param [Hash] options
116
+ # @return [nil]
117
+ def self.register_singleton(options)
118
+ key, proc, proc_args, obj = validate_usable(options)
119
+ resolved = resolved(options[:obj])
120
+ obj.define_singleton_method(key) do
121
+ return resolved[key] if resolved.key?(key)
122
+ resolved[key] = proc.call(*proc_args)
123
+ end && nil
124
+ end
125
+
126
+ def self.resolved(obj)
127
+ obj.singleton_class.instance_eval { @resolved ||= {} }
128
+ end
129
+
130
+ def self.validate_existing(options)
131
+ result = [options[:obj]]
132
+ result << result.first.singleton_methods
133
+ key = options.fetch(:key, nil)
134
+ result << key.to_sym if key
135
+ result
136
+ end
137
+
138
+ def self.validate_key(key, obj)
139
+ sym = key.to_sym
140
+ insp = key.inspect
141
+ raise KeyAlreadyRegisteredError, "Key #{insp} already registered" if
142
+ obj.singleton_methods.include?(sym)
143
+ raise InvalidKeyError, "Invalid key #{insp}" if
144
+ obj.public_methods.include?(sym) ||
145
+ /^[a-z\_]{1}[\d\w\_]*$/ !~ sym
146
+ sym
147
+ end
148
+
149
+ def self.validate_callback(proc, block)
150
+ return proc if proc.respond_to?(:call)
151
+ return block if block.respond_to?(:call)
152
+ raise InvalidCallbackError, 'Invalid callback'
153
+ end
154
+
155
+ def self.validate_usable(options)
156
+ obj = options[:obj]
157
+ key = validate_key(options[:key], obj)
158
+ proc = validate_callback(options[:proc], options[:block])
159
+ [key, proc, proc.arity.zero? ? [] : [obj], obj]
160
+ end
161
+
162
+ private_class_method :resolved, :validate_callback,
163
+ :validate_existing, :validate_key,
164
+ :validate_usable
165
+
166
+ # Exception class used when a user tries to register an
167
+ # invalid callback.
168
+ class InvalidCallbackError < ArgumentError
169
+ end
170
+
171
+ # Exception class used when a user tries to register an
172
+ # invalid key.
173
+ class InvalidKeyError < ArgumentError
174
+ end
175
+
176
+ # Exception class used when a user tries to register a key
177
+ # that is already registered.
178
+ class KeyAlreadyRegisteredError < ArgumentError
179
+ end
180
+
181
+ # Exception class used when a user is requesting to forget
182
+ # a key that is not registered.
183
+ class KeyNotRegisteredError < ArgumentError
96
184
  end
97
185
  end
98
186
  end
@@ -67,24 +67,25 @@ describe 'Racket::Registry registration' do
67
67
 
68
68
  it 'should block invalid keys' do
69
69
  -> { registry.register('inspect') }
70
- .should.raise(RuntimeError)
70
+ .should.raise(Racket::Registry::InvalidKeyError)
71
71
  .message.should.equal('Invalid key "inspect"')
72
72
  end
73
73
 
74
74
  it 'should block already registered keys' do
75
75
  -> { registry.register('one', -> { Object.new }) }
76
- .should.raise(RuntimeError)
76
+ .should.raise(Racket::Registry::KeyAlreadyRegisteredError)
77
77
  .message.should.equal('Key "one" already registered')
78
78
  end
79
79
 
80
80
  it 'should block invalid block/procs' do
81
81
  -> { registry.register('invalid') }
82
- .should.raise(RuntimeError)
83
- .message.should.equal('No proc/block given')
82
+ .should.raise(Racket::Registry::InvalidCallbackError)
83
+ .message.should.equal('Invalid callback')
84
84
  end
85
85
  end
86
86
 
87
87
  describe 'Racket::Registry dependency handling' do
88
+ # A very simple class
88
89
  class Simple
89
90
  attr_reader :text
90
91
 
@@ -93,6 +94,7 @@ describe 'Racket::Registry dependency handling' do
93
94
  end
94
95
  end
95
96
 
97
+ # A somewhat complex class
96
98
  class NotSoSimple
97
99
  attr_reader :text, :simple_first, :simple_second
98
100
 
@@ -103,7 +105,8 @@ describe 'Racket::Registry dependency handling' do
103
105
  end
104
106
  end
105
107
 
106
- it 'should be able to resolve dependencies regardless of registration order' do
108
+ it 'should be able to resolve dependencies regardless of ' \
109
+ 'registration order' do
107
110
  registry = Racket::Registry.new
108
111
 
109
112
  foo = Simple.new('foo')
@@ -111,10 +114,10 @@ describe 'Racket::Registry dependency handling' do
111
114
 
112
115
  registry.singleton(
113
116
  :baz,
114
- lambda { |r| NotSoSimple.new('baz', r.foo, r.bar) }
117
+ ->(r) { NotSoSimple.new('baz', r.foo, r.bar) }
115
118
  )
116
- registry.singleton(:bar, lambda { |r| bar })
117
- registry.singleton(:foo, lambda { |r| foo })
119
+ registry.singleton(:bar, -> { bar })
120
+ registry.singleton(:foo, -> { foo })
118
121
 
119
122
  baz = registry.baz
120
123
  baz.simple_first.object_id.should.equal(foo.object_id)
@@ -123,3 +126,32 @@ describe 'Racket::Registry dependency handling' do
123
126
  registry.bar.object_id.should.equal(bar.object_id)
124
127
  end
125
128
  end
129
+
130
+ describe 'Racket::Registry entry removal' do
131
+ registry = Racket::Registry.new
132
+
133
+ it 'should be able to forget a single entry' do
134
+ obj = Object.new
135
+ registry.register(:foo) { obj }
136
+ registry.foo.object_id.should.equal(obj.object_id)
137
+ registry.forget(:foo)
138
+ -> { registry.foo }.should.raise(NoMethodError)
139
+ end
140
+
141
+ it 'should be able to forget all entries' do
142
+ obj = Object.new
143
+ registry.register(:foo) { obj }
144
+ registry.register(:bar) { obj }
145
+ registry.foo.object_id.should.equal(obj.object_id)
146
+ registry.bar.object_id.should.equal(obj.object_id)
147
+ registry.forget_all
148
+ -> { registry.foo }.should.raise(NoMethodError)
149
+ -> { registry.bar }.should.raise(NoMethodError)
150
+ end
151
+
152
+ it 'should fail to forget non-existing entries' do
153
+ -> { registry.forget(:baz) }
154
+ .should.raise(Racket::Registry::KeyNotRegisteredError)
155
+ .message.should.equal('Key baz is not registered')
156
+ end
157
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: racket-registry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lars Olsson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-22 00:00:00.000000000 Z
11
+ date: 2016-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bacon