deject 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/Readme.md +103 -51
  2. data/lib/deject/version.rb +1 -1
  3. metadata +6 -6
data/Readme.md CHANGED
@@ -16,85 +16,135 @@ On some systems:
16
16
 
17
17
  If you have to use sudo and you don't know why, it's because you need to set your GEM_HOME environment variable.
18
18
 
19
- Example
20
- =======
19
+ Examples
20
+ ========
21
+
22
+ Add Deject to your class.
21
23
 
22
24
  ```ruby
23
- require 'deject'
25
+ class Game
26
+ Deject self
27
+ end
28
+ ```
24
29
 
25
- class HumanPlayer
26
- def type
27
- 'human player'
28
- end
30
+ Declare a dependency with a default.
31
+
32
+ ```ruby
33
+ ComputerPlayer = Class.new
34
+
35
+ class Game
36
+ Deject self
37
+ dependency(:player) { ComputerPlayer.new }
29
38
  end
30
39
 
31
- class ComputerPlayer
32
- def type
33
- 'computer player'
34
- end
40
+ Game.new.player # => #<ComputerPlayer:0x007fb504945f28>
41
+ ```
42
+
43
+ Override the dependency for the class.
44
+
45
+ ```ruby
46
+ ComputerPlayer = Class.new
47
+ HumanPlayer = Class.new
48
+
49
+ class Game
50
+ Deject self
51
+ dependency(:player) { ComputerPlayer.new }
35
52
  end
36
53
 
37
- class MockPlayer
38
- def type
39
- 'mock player'
40
- end
54
+ Game.override(:player) { HumanPlayer.new } # in some initialization file
55
+
56
+ Game.new.player # => #<HumanPlayer:0x007fde2d8ac880>
57
+ ```
58
+
59
+ Override the dependency for an instance by using `#with_<dependency>`. You can
60
+ pass a specific object, or a block for lazy initialization. This method returns
61
+ the instance.
62
+
63
+ ```ruby
64
+ ComputerPlayer = Class.new
65
+ HumanPlayer = Class.new
66
+ MockPlayer = Class.new
67
+
68
+ class Game
69
+ Deject self
70
+ dependency(:player) { ComputerPlayer.new }
41
71
  end
42
72
 
73
+ Game.new.with_player(HumanPlayer.new).player # => #<HumanPlayer:0x007fb2a1015e40>
74
+ Game.new.with_player { MockPlayer.new }.player # => #<MockPlayer:0x007fb2a10155f8>
75
+ ```
76
+
77
+ Set a global default value to be used when a value isn't explicitly provided.
78
+ If you are worried about clobbering a previously registered value, invoke with `:player2, safe: true`
79
+ this is turned off by default because I found that code reloading was horking everything up.
80
+
81
+ ```ruby
82
+ ComputerPlayer = Class.new
83
+ HumanPlayer = Class.new
84
+
85
+ # these would go in some initialization file
86
+ Deject.register(:player1) { ComputerPlayer.new }
87
+ Deject.register(:player2) { ComputerPlayer.new }
88
+
43
89
  class Game
44
90
  Deject self
45
- dependency(:player1) { ComputerPlayer.new }
91
+ dependency(:player1) { HumanPlayer.new }
46
92
  dependency :player2
47
-
48
- def name
49
- 'poker'
50
- end
51
93
  end
52
94
 
53
- # register a global value (put this into an initializer or dependency injection file)
54
- # if you are worried about clobbering a previously set value, invoke with `:player2, safe: true`
55
- # this is turned off by default because I found that code reloading was horking everything up
56
- Deject.register(:player2) { HumanPlayer.new }
95
+ Game.new.player1 # => #<HumanPlayer:0x007fed8212d7d0>
96
+ Game.new.player2 # => #<ComputerPlayer:0x007fed8212d348>
97
+ ```
57
98
 
58
- # declared with a block, so will default to block value
59
- Game.new.player1.type # => "computer player"
99
+ Dependencies without a default block can passed to the Deject function.
60
100
 
61
- # declared without a block, so will default to the global definition for player1
62
- Game.new.player2.type # => "human player"
101
+ ```ruby
102
+ ComputerPlayer = Class.new
63
103
 
64
- # we can override for this entire class
65
- Game.override(:player2) { MockPlayer.new }
66
- Game.new.player2.type # => "mock player"
104
+ class Game
105
+ Deject self, :player
106
+ end
67
107
 
68
- # we can override for some specific instance using either a block or a value
69
- # instance level overriding is done using method with_<dependnecy_name>, which returns the instance
70
- Game.new.with_player2 { HumanPlayer.new }.player2.type # => "human player"
71
- Game.new.with_player2(ComputerPlayer.new).player2.type # => "computer player"
108
+ Game.new.with_player(ComputerPlayer.new).player # => #<ComputerPlayer:0x007fac2393a248>
109
+ ```
72
110
 
73
- # anywhere a block is used, the instance will be passed into it
74
- generic_player = Struct.new :type
111
+ Anywhere a block is used, the instance is passed to it.
75
112
 
76
- game = Game.new.with_player1 { |game| generic_player.new "#{game.name} player1" }
77
- game.player1.type # => "poker player1"
113
+ ```ruby
114
+ ChattyPlayer = Struct.new :message
78
115
 
79
- Game.override(:player2) { |game| generic_player.new "#{game.name} player2" }
80
- game.player2.type # => "poker player2"
81
- ```
116
+ class Game < Struct.new(:name)
117
+ Deject self
118
+ dependency(:player) { |game| ChattyPlayer.new "You're good at #{game.name}" }
119
+ end
120
+
121
+ player = Game.new('Monopoly').player
122
+ player.message # => "You're good at Monopoly"
82
123
 
124
+ player = Game.new('Monopoly').with_player { |game| ChattyPlayer.new "You're terrible at #{game.name}" }.player
125
+ player.message # => "You're terrible at Monopoly"
126
+ ```
83
127
 
84
- Note that dependencies using the defaults can be declared when dejecting the class:
128
+ Results are memoized.
85
129
 
86
130
  ```ruby
87
- class Game
88
- # this
131
+ NamedPlayer = Struct.new :name
132
+
133
+ class Game < Struct.new(:name)
89
134
  Deject self
90
- dependency :player1
91
- dependency :player2
92
135
 
93
- # is the same as this
94
- Deject self, :player1, :player2
136
+ i = 0
137
+ dependency(:player) { NamedPlayer.new "Player#{i+=1}" }
95
138
  end
139
+
140
+ game = Game.new
141
+ game.player.name # => "Player1"
142
+ game.player.name # => "Player1"
143
+
144
+ Game.new.player.name # => "Player2"
96
145
  ```
97
146
 
147
+
98
148
  Reasons
99
149
  =======
100
150
 
@@ -198,7 +248,7 @@ end
198
248
  # or the changes that happened to it.
199
249
  ```
200
250
 
201
- Compare to Deject
251
+ Compare the above examples to Deject
202
252
 
203
253
  ```ruby
204
254
  class SomeClass
@@ -207,6 +257,7 @@ class SomeClass
207
257
  end
208
258
 
209
259
  # straightforward (no one will be surprised when this changes),
260
+ # declarative so easy to understand
210
261
  # convenient to override for all instances or any specific instance.
211
262
  ```
212
263
 
@@ -225,11 +276,12 @@ But I couldn't think of a good one. But wait, do I _really_ need a verb? I went
225
276
  and decided I was okay with having a method named after the class that applies it, hence `Deject SomeClass`. Not a usual practice
226
277
  but not unheard of, and I don't think it makes sense to force an OO like interface where it doesn't fit well.
227
278
 
228
- We use `with_<dependency>` instead of `dependency=` because taking blocks is grotesque with assignment methods. Further, I have a general
279
+ We use `with_<dependency>` instead of `dependency=` because taking blocks is grotesque with assignment methods. I have a general
229
280
  disdain for assignment methods as they encourage a mindset that doesn't appreciate the advantages of OO.
230
281
  _"When you have a 'setter' on an object, you have turned an object back into a data structure" -- Alan Kay_.
231
282
  Furthermore, I nearly always want to be able to override the result inline, which you can't easily do with assignment methods
232
283
  as the interpreter guarantees they return the RHS (best solution would be to `tap` the object).
284
+ The `with_<name>` pattern is a common pattern in [IO](http://iolanguage.com/).
233
285
 
234
286
  In general, all variables are stored as locals in closures rather than instance variables on the object. This is
235
287
  partially due to the implementation (alternative implementations used ivars), and partially because I wanted to
@@ -1,3 +1,3 @@
1
1
  module Deject
2
- VERSION = '0.2.1'
2
+ VERSION = '0.2.2'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deject
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-29 00:00:00.000000000 Z
12
+ date: 2012-05-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70118660588240 !ruby/object:Gem::Requirement
16
+ requirement: &70127720072140 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70118660588240
24
+ version_requirements: *70127720072140
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: pry
27
- requirement: &70118660586140 !ruby/object:Gem::Requirement
27
+ requirement: &70127720071620 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70118660586140
35
+ version_requirements: *70127720071620
36
36
  description: Provides a super simple API for dependency injection
37
37
  email:
38
38
  - josh.cheek@gmail.com