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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a03c1e8f8cd9196d0a71b9068554a24d088d47dd
4
- data.tar.gz: fce0a06653f61e7fde4a1387e3eb944a76d08547
3
+ metadata.gz: 3c591314692d9690e8940b3f0b72b8dc1cc3926c
4
+ data.tar.gz: e7e948670a4f517771e7bdcf4207579e1557706f
5
5
  SHA512:
6
- metadata.gz: 93ebb87549b3c51756a79c5ce31b8f4bd42c8aeb6000d195214089f041e7f356734b696e9d09bba599fc1ede330bae3dda21bdbca5516db704f3f6e02e76fae4
7
- data.tar.gz: a9b6b448c29fc48fa1600b4b13c5a7ec99343d7e8cec8cdb3c70dc7f35ee5948aeedddbb66df3ce080577f99a2defc04ef0af3a50e4e2f329d7c83ecd87ba5d5
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.7.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.0)
16
- mime-types (2.0)
17
- multi_json (1.8.2)
18
- rake (10.1.0)
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.2.2)
27
- tins (~> 0.8)
26
+ term-ansicolor (1.3.0)
27
+ tins (~> 1.0)
28
28
  thor (0.18.1)
29
- tins (0.13.1)
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 CurrentTime
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 "CurrentTime" do
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(CurrentTime.new.to_s, "The time is 12 o'clock")
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
- Pharrell.use_config(:base)
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. You can then attach your test configuration for Pharrell to
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
@@ -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
@@ -3,7 +3,7 @@ $:.unshift lib unless $:.include?(lib)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "pharrell"
6
- s.version = "0.7.0"
6
+ s.version = "0.8.0"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Callum Stott"]
9
9
  s.email = ["callum@seadowg.com"]
@@ -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.7.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-01-18 00:00:00.000000000 Z
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