pharrell 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 +4 -4
- data/Gemfile.lock +8 -8
- data/README.md +102 -8
- data/lib/pharrell.rb +7 -28
- data/lib/pharrell/errors.rb +23 -0
- data/lib/pharrell/injectable.rb +6 -1
- data/pharrell.gemspec +1 -1
- data/spec/injectable_spec.rb +27 -4
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c591314692d9690e8940b3f0b72b8dc1cc3926c
|
|
4
|
+
data.tar.gz: e7e948670a4f517771e7bdcf4207579e1557706f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e893aea8b98ef7bf417db1006d2879ff3d567fe9f4dd4ebbd0d9361cdf5a2663c9db3e976d1be745e8ca07a5552291d83fd51afc2f169f95732fbb453c85b390
|
|
7
|
+
data.tar.gz: 658f2f56202b8e1a2b277ed37e075ee59763cd0d9d9456e47085b87c2d0dc7a41a5db24e054bedd6bca6fc895e243dae87d35d99bce83d4add5ef9baccb55840
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
pharrell (0.
|
|
4
|
+
pharrell (0.8.0)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
@@ -12,10 +12,10 @@ GEM
|
|
|
12
12
|
simplecov (>= 0.7)
|
|
13
13
|
term-ansicolor
|
|
14
14
|
thor
|
|
15
|
-
docile (1.1.
|
|
16
|
-
mime-types (2.
|
|
17
|
-
multi_json (1.
|
|
18
|
-
rake (10.1.
|
|
15
|
+
docile (1.1.3)
|
|
16
|
+
mime-types (2.2)
|
|
17
|
+
multi_json (1.9.2)
|
|
18
|
+
rake (10.1.1)
|
|
19
19
|
rest-client (1.6.7)
|
|
20
20
|
mime-types (>= 1.16)
|
|
21
21
|
simplecov (0.8.2)
|
|
@@ -23,10 +23,10 @@ GEM
|
|
|
23
23
|
multi_json
|
|
24
24
|
simplecov-html (~> 0.8.0)
|
|
25
25
|
simplecov-html (0.8.0)
|
|
26
|
-
term-ansicolor (1.
|
|
27
|
-
tins (~> 0
|
|
26
|
+
term-ansicolor (1.3.0)
|
|
27
|
+
tins (~> 1.0)
|
|
28
28
|
thor (0.18.1)
|
|
29
|
-
tins (0.
|
|
29
|
+
tins (1.0.1)
|
|
30
30
|
|
|
31
31
|
PLATFORMS
|
|
32
32
|
ruby
|
data/README.md
CHANGED
|
@@ -24,7 +24,7 @@ Or, install for your system:
|
|
|
24
24
|
You can inject dependencies into classes like so:
|
|
25
25
|
|
|
26
26
|
```ruby
|
|
27
|
-
class
|
|
27
|
+
class BlackBox
|
|
28
28
|
include Pharrell::Injectible
|
|
29
29
|
|
|
30
30
|
injected :current_time, Time
|
|
@@ -57,17 +57,92 @@ Pharrell.config(:test) do |config|
|
|
|
57
57
|
config.bind(Time, Time.at(0))
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
describe
|
|
60
|
+
describe BlackBox do
|
|
61
61
|
before do
|
|
62
62
|
Pharrell.use_config(:test)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
it "displays the time of day" do
|
|
66
|
-
assert_equal(
|
|
66
|
+
assert_equal(BlackBox.new.to_s, "The time is 12 o'clock")
|
|
67
67
|
end
|
|
68
68
|
end
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
### Constructor Injection
|
|
72
|
+
|
|
73
|
+
When you're working with objects that have to be a black box
|
|
74
|
+
(like a Rails controller for instance) you will need to inject dependencies
|
|
75
|
+
like in the basic example before. It's a lot nicer to be able to design your
|
|
76
|
+
other objects so their dependencies are injected directly into their constructor i.e.
|
|
77
|
+
they do not cheat. This will make your components easier reason about and easier to test.
|
|
78
|
+
|
|
79
|
+
We can break the previous time code into into its object to achieve this:
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
class PrettyTime
|
|
83
|
+
def initialize(current_time)
|
|
84
|
+
@current_time = current_time
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def to_s
|
|
88
|
+
hour = @current_time.hour % 12
|
|
89
|
+
"The time is #{hour == 0 ? 12 : hour} o'clock"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This is great but what if we want to construct `PrettyTime` of these in the
|
|
95
|
+
`BlackBox` class?
|
|
96
|
+
|
|
97
|
+
For this we can use constructor injection:
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
class PrettyTime
|
|
101
|
+
include Pharrell::Constructor
|
|
102
|
+
|
|
103
|
+
constructor Time
|
|
104
|
+
|
|
105
|
+
def initialize(current_time)
|
|
106
|
+
@current_time = current_time
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def to_s
|
|
110
|
+
hour = @current_time.hour % 12
|
|
111
|
+
"The time is #{hour == 0 ? 12 : hour} o'clock"
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
We can then inject `PrettyTime` straight into `BlackBox`:
|
|
117
|
+
|
|
118
|
+
```ruby
|
|
119
|
+
class BlackBox
|
|
120
|
+
include Pharrell::Injectible
|
|
121
|
+
|
|
122
|
+
injected :pretty_time, PrettyTime
|
|
123
|
+
|
|
124
|
+
def to_s
|
|
125
|
+
pretty_time.to_s
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Our binding would then look like this:
|
|
131
|
+
|
|
132
|
+
```ruby
|
|
133
|
+
Pharrell.config(:base) do |config|
|
|
134
|
+
config.bind(Time) { Time.now }
|
|
135
|
+
config.bind(PrettyTime, PrettyTime)
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Because we marked `PrettyTime` as having constructor injection
|
|
140
|
+
pharrell will build `PrettyTime` with the bound instance of `Time`.
|
|
141
|
+
|
|
142
|
+
This approach may seem more complex but it allows you to move most of your application's logic
|
|
143
|
+
into more responsible components and should free you from using
|
|
144
|
+
magic dependency injection (DI frameworks, stubbing factories etc) anywhere but at the top level.
|
|
145
|
+
|
|
71
146
|
### Bindings
|
|
72
147
|
|
|
73
148
|
When building configurations in pharrell you can bind instances to
|
|
@@ -113,15 +188,34 @@ Pharrell is really easy to set up with Rails. Here's an example similar to the `
|
|
|
113
188
|
```ruby
|
|
114
189
|
class Application < Rails::Application
|
|
115
190
|
config.to_prepare do
|
|
116
|
-
Pharrell.config do |config|
|
|
191
|
+
Pharrell.config(:base) do |config|
|
|
117
192
|
config.bind(Time, Time)
|
|
118
193
|
end
|
|
119
|
-
|
|
120
|
-
|
|
194
|
+
|
|
195
|
+
# make sure you have one config for each of your environments!
|
|
196
|
+
Pharrell.config(:development, :extends => :base) {}
|
|
197
|
+
Pharrell.config(:production, :extends => :base) {}
|
|
198
|
+
|
|
199
|
+
Pharrell.use_config(:test, :extends => :base) do
|
|
200
|
+
config.bind(Time, FakeTime.new)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
Pharrell.use_config(Rails.env.to_sym)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**spec/spec_helper.rb**
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
RSpec.configure do |config|
|
|
212
|
+
config.include Pharrell::Injectable
|
|
213
|
+
|
|
214
|
+
config.before(:each) do
|
|
215
|
+
Pharrell.use_config(:test)
|
|
121
216
|
end
|
|
122
217
|
end
|
|
123
218
|
```
|
|
124
219
|
|
|
125
220
|
Pharrell should be configured in the Rails Application's `#to_prepare` method as this runs at startup
|
|
126
|
-
in production and before each request in development.
|
|
127
|
-
whatever test framework you use (exactly as in the first example).
|
|
221
|
+
in production and before each request in development.
|
data/lib/pharrell.rb
CHANGED
|
@@ -1,36 +1,15 @@
|
|
|
1
1
|
require 'pharrell/config'
|
|
2
2
|
require 'pharrell/injectable'
|
|
3
3
|
require 'pharrell/constructor'
|
|
4
|
+
require 'pharrell/errors'
|
|
4
5
|
|
|
5
6
|
module Pharrell
|
|
6
|
-
class BindingNotFoundError < Exception
|
|
7
|
-
def message
|
|
8
|
-
"Binding could not be found!"
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
class ConfigNotDefinedError < Exception
|
|
13
|
-
def message
|
|
14
|
-
"Config has not been defined!"
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
class InvalidOptionsError < Exception
|
|
19
|
-
def initialize(opts)
|
|
20
|
-
@opts = opts
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def message
|
|
24
|
-
"Invalid options: #{@opts.join(" ")}"
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
7
|
@@configs = {}
|
|
29
8
|
@@config = nil
|
|
30
9
|
|
|
31
10
|
def self.config(name, opts = {}, &blk)
|
|
32
11
|
check_options([:extends], opts)
|
|
33
|
-
|
|
12
|
+
|
|
34
13
|
if opts[:extends]
|
|
35
14
|
@@configs[name] = fetch_config(opts[:extends]).extend(blk)
|
|
36
15
|
else
|
|
@@ -50,7 +29,7 @@ module Pharrell
|
|
|
50
29
|
def self.rebuild!
|
|
51
30
|
current_config.rebuild!
|
|
52
31
|
end
|
|
53
|
-
|
|
32
|
+
|
|
54
33
|
def self.reset!
|
|
55
34
|
@@configs = {}
|
|
56
35
|
@@config = nil
|
|
@@ -61,20 +40,20 @@ module Pharrell
|
|
|
61
40
|
def self.current_config
|
|
62
41
|
fetch_config(@@config)
|
|
63
42
|
end
|
|
64
|
-
|
|
43
|
+
|
|
65
44
|
def self.fetch_config(name)
|
|
66
45
|
config = @@configs[name]
|
|
67
|
-
|
|
46
|
+
|
|
68
47
|
if config
|
|
69
48
|
config
|
|
70
49
|
else
|
|
71
50
|
raise ConfigNotDefinedError
|
|
72
51
|
end
|
|
73
52
|
end
|
|
74
|
-
|
|
53
|
+
|
|
75
54
|
def self.check_options(opts, opt_hash)
|
|
76
55
|
extra_keys = opt_hash.keys.reject { |key| opts.include?(key) }
|
|
77
|
-
|
|
56
|
+
|
|
78
57
|
if extra_keys.empty?
|
|
79
58
|
true
|
|
80
59
|
else
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Pharrell
|
|
2
|
+
class BindingNotFoundError < Exception
|
|
3
|
+
def message
|
|
4
|
+
"Binding could not be found!"
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class ConfigNotDefinedError < Exception
|
|
9
|
+
def message
|
|
10
|
+
"Config has not been defined!"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class InvalidOptionsError < Exception
|
|
15
|
+
def initialize(opts)
|
|
16
|
+
@opts = opts
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def message
|
|
20
|
+
"Invalid options: #{@opts.join(" ")}"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/pharrell/injectable.rb
CHANGED
|
@@ -5,7 +5,12 @@ module Pharrell
|
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
module ClassMethods
|
|
8
|
-
def injected(name, klass)
|
|
8
|
+
def injected(name, klass=nil)
|
|
9
|
+
if klass.nil?
|
|
10
|
+
klass_name = name.to_s.split("_").map(&:capitalize).join
|
|
11
|
+
klass = Kernel.const_get(klass_name)
|
|
12
|
+
end
|
|
13
|
+
|
|
9
14
|
define_method(name) do
|
|
10
15
|
@__pharrell_cache__ ||= {}
|
|
11
16
|
@__pharrell_cache__[klass] ||= Pharrell.instance_for(klass)
|
data/pharrell.gemspec
CHANGED
data/spec/injectable_spec.rb
CHANGED
|
@@ -6,7 +6,7 @@ describe "Injectable" do
|
|
|
6
6
|
before do
|
|
7
7
|
Pharrell.reset!
|
|
8
8
|
end
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
describe ".injected" do
|
|
11
11
|
it "defines a method to retrieve that class from Pharrell" do
|
|
12
12
|
Pharrell.config(:base) { |c| c.bind(String, "Injected") }
|
|
@@ -14,13 +14,36 @@ describe "Injectable" do
|
|
|
14
14
|
|
|
15
15
|
klass = Class.new {
|
|
16
16
|
include Pharrell::Injectable
|
|
17
|
-
|
|
18
17
|
injected :string, String
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
assert_equal(klass.new.send(:string), "Injected")
|
|
22
21
|
end
|
|
23
|
-
|
|
22
|
+
|
|
23
|
+
describe 'simpler injection' do
|
|
24
|
+
before do
|
|
25
|
+
Pharrell.config(:base) do |c|
|
|
26
|
+
c.bind(String, "Injected")
|
|
27
|
+
c.bind(SecureRandom, "Also Injected")
|
|
28
|
+
end
|
|
29
|
+
Pharrell.use_config(:base)
|
|
30
|
+
|
|
31
|
+
@klass = Class.new {
|
|
32
|
+
include Pharrell::Injectable
|
|
33
|
+
injected :string
|
|
34
|
+
injected :secure_random
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "allows simpler injection with a symbol" do
|
|
39
|
+
assert_equal(@klass.new.send(:string), "Injected")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'allows more complex binding' do
|
|
43
|
+
assert_equal(@klass.new.send(:secure_random), "Also Injected")
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
24
47
|
it "caches lazy bindings on the instance" do
|
|
25
48
|
i = 0
|
|
26
49
|
Pharrell.config(:base) { |c| c.bind(Object) { i = i + 1 } }
|
|
@@ -31,7 +54,7 @@ describe "Injectable" do
|
|
|
31
54
|
|
|
32
55
|
injected :injected_ob, Object
|
|
33
56
|
}
|
|
34
|
-
|
|
57
|
+
|
|
35
58
|
object = klass.new
|
|
36
59
|
assert_equal(object.send(:injected_ob), object.send(:injected_ob))
|
|
37
60
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pharrell
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Callum Stott
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-
|
|
11
|
+
date: 2014-03-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description:
|
|
14
14
|
email:
|
|
@@ -27,6 +27,7 @@ files:
|
|
|
27
27
|
- lib/pharrell.rb
|
|
28
28
|
- lib/pharrell/config.rb
|
|
29
29
|
- lib/pharrell/constructor.rb
|
|
30
|
+
- lib/pharrell/errors.rb
|
|
30
31
|
- lib/pharrell/injectable.rb
|
|
31
32
|
- media/pharrell.jpg
|
|
32
33
|
- pharrell.gemspec
|