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 +4 -4
- data/README.md +7 -2
- data/lib/racket/registry.rb +141 -53
- data/spec/racket_registry.rb +40 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: efdb66903525e8c25d4c9254fabeec1ba8171650
|
4
|
+
data.tar.gz: 30839afe56b0fd154c0cb1b99b4baa1e026055be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
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.
|
data/lib/racket/registry.rb
CHANGED
@@ -20,79 +20,167 @@
|
|
20
20
|
module Racket
|
21
21
|
# Racket Registry namespace
|
22
22
|
class Registry
|
23
|
-
|
24
|
-
|
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
|
-
#
|
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
|
30
|
-
# current entry. Results from the
|
31
|
-
# that the
|
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
|
-
|
38
|
-
|
39
|
-
|
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
|
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
|
47
|
-
# current entry. Results from the
|
48
|
-
# that the
|
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
|
-
|
55
|
-
|
56
|
-
|
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
|
-
#
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
data/spec/racket_registry.rb
CHANGED
@@ -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(
|
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(
|
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(
|
83
|
-
.message.should.equal('
|
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
|
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
|
-
|
117
|
+
->(r) { NotSoSimple.new('baz', r.foo, r.bar) }
|
115
118
|
)
|
116
|
-
registry.singleton(:bar,
|
117
|
-
registry.singleton(: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.
|
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-
|
11
|
+
date: 2016-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bacon
|