rails-and-solid 0.9.0 → 0.9.1

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.
data/README CHANGED
@@ -1,3 +1,8 @@
1
+ # What is this?
2
+
3
+ This is a gem that changes Rails behavior to allow you to code more freely, without coupling
4
+ yourself to inheritance issues. Take a look at the examples to see what it changes.
5
+
1
6
  # Installing
2
7
 
3
8
  Configure the gem in your Gemfile:
@@ -11,22 +16,194 @@ and make it believe you have the controller he wants, just trick him:
11
16
 
12
17
  class ApplicationController < ActionController::Base
13
18
 
14
- protect_from_forgery
15
- include RailsAndSolid::TrickHim
19
+ solidify
20
+
21
+ end
22
+
23
+ # Inheritance coupling in controllers
24
+
25
+ Ok. Time for some goodies. First example, let's unpimp :
26
+
27
+ [code]
28
+ RailsAndSolid.pimp :clients
29
+
30
+ class ClientsControl
31
+
32
+ def show(id)
33
+ @client = Client.find(id)
34
+ end
35
+
36
+ end
37
+ [/code]
38
+
39
+ Notice that *id* is the parameter *id* from your http request. No inheritance required.
40
+ Same old behavior. No http params appeared. You can unit test for real, without all
41
+ its inherited behavior.
42
+
43
+ Why? Am I really coupled to something when inheriting?
44
+
45
+ [code]
46
+ rails console
47
+ > ActionController::Base.instance_methods.size
48
+ 374
49
+ > (ActionController::Base.instance_methods + ActionController::Base.instance_methods - Object.instance_methods - Object.private_instance_methods).size
50
+ 560
51
+ > ActionController::Base.methods.size
52
+ 353
53
+ > ActionController::Base.ancestors.size
54
+ 36
55
+ [/code]
56
+
57
+ By default, when creating a new controller in Rails, you are coupled
58
+ with 374 public methods (*542 in total*), inheriting behavior from *36 different* sources.
59
+
60
+ # Session parameters
61
+
62
+ [code]
63
+ class ClientsControl
64
+
65
+ def show(current_user, id)
66
+ # if session[:current_user] exists, guess who is here?
67
+ end
68
+
69
+ end
70
+ [/code]
71
+
72
+ Again, unit testable. Non-http intrusive.
73
+
74
+ # Session parameters
75
+
76
+ [code]
77
+ class ClientsControl
78
+
79
+ def show(current_user, id)
80
+ # if session[:current_user] exists, guess who is here?
81
+ end
82
+
83
+ end
84
+ [/code]
85
+
86
+ # What about creating a client?
87
+
88
+ Well, just create it:
89
+
90
+ [code]
91
+ class ClientsControl
16
92
 
93
+ def create(client)
94
+ client.save
17
95
  end
96
+
97
+ end
98
+ [/code]
99
+
100
+ # But you can't load, right?
101
+
102
+ I don't think so:
103
+
104
+ [code]
105
+ class ClientsControl
106
+
107
+ def show(loaded_client)
108
+ @client = loaded_client
109
+ end
110
+
111
+ end
112
+ [/code]
18
113
 
19
- # Using
114
+ # But what about responses? Sessions? Http stuff?
20
115
 
21
- NO INHERITANCE
116
+ Just bind to what you need, nothing more than that:
117
+
118
+ [code]
119
+ def logout(session, redirect_to, flash)
120
+ session[:current_user] = nil
121
+ flash[:message] = "Logged out..."
122
+ redirect_to.root_path
123
+ end
124
+ [/code]
125
+
126
+ # Internally: Helpers
127
+
128
+ Helpers are the classes that help passing parameters to those
129
+ methods by using a key based lookup algorithm. For example
130
+ if a 'json' parameter is received, one will use the Json helper
131
+ to return it:
132
+
133
+ [code]
134
+ class ApplicationController < ActionController::Base
135
+
136
+ protect_from_forgery
137
+ solidify
138
+
139
+ class JsonHelper
140
+ def initialize(controller)
141
+ @controller = controller
142
+ end
143
+ def message(x)
144
+ @controller.render :json => {'message' => x}
145
+ end
146
+ end
22
147
 
23
- GIVE A SIMPLE EXAMPLE
148
+ KEYS["json"] = JsonHelper
149
+
150
+ end
151
+ [/code]
24
152
 
25
- GIVE A LOAD EXAMPLE
153
+ Now you can receive json and use the message:
26
154
 
27
- GIVE AN AMAZING EXAMPLE
155
+ [code]
156
+ def some_action(json)
157
+ json.message("Well done!")
158
+ end
159
+ [/code]
28
160
 
29
- # Helpers
161
+ You can use those auxiliary objects to compose any kind of behavior (not just rendering)
162
+ by just receiving the expected coupled semantic value instead of inheriting everything.
30
163
 
31
164
  # Handlers
32
165
 
166
+ Handlers are not key-fixed parameter providers. For instance, the param lookup:
167
+
168
+ [code]
169
+ module RailsAndSolid
170
+ module Handler
171
+ class Param
172
+ def extract(controller, name)
173
+ controller.params[name]
174
+ end
175
+ def handles?(controller, name)
176
+ controller.params[name]
177
+ end
178
+ end
179
+ end
180
+ end[/code]
181
+
182
+ It will be asked whether it can handle this parameter and the provide it.
183
+
184
+ # TODO List
185
+
186
+ Help?
187
+
188
+ First, simple unit tests.
189
+
190
+ Units are split and behavior is composed. This was only to
191
+ show that its possible to achieve the same (and better results) with less coupling and a different
192
+ OO design approach. So what about start unit testing, providing new handlers, new helpers or
193
+ just doing a blog post on it? Refactoring trick_him would also be nice. Removing the
194
+ pimp method would be even better but that requires more refactoring on Rails internals,
195
+ not just tricking it.
196
+
197
+ Results from handlers "handles?" could be cached.
198
+
199
+ You can also implement DI support by correctly implementing di_instantiate(type) at TrickHim.
200
+
201
+ Finally, feel you can support named parameters in 1.8.7+ if not yet supported.
202
+
203
+ Everything is quite simple so far as this is just a concept
204
+
205
+ # Why not changing Rails internally?
206
+
207
+ One needs to know how all the mixin of Rails interact with each other (i.e. the 36 ancestors
208
+ of ActionController) in order to make safe changes. That is the coupling this proof of concept
209
+ is trying show how to avoid.
@@ -4,4 +4,15 @@ module RailsAndSolid
4
4
  autoload :TrickHim, 'rails-and-solid/trick_him'
5
5
  autoload :Handler, 'rails-and-solid/handler'
6
6
 
7
+ # Shortcut to hack rails.
8
+ def self.pimp(what)
9
+ Object.module_eval "class #{what.to_s.camelize}Controller < ApplicationController; end"
10
+ end
11
+
12
+ end
13
+
14
+ class ActionController::Base
15
+ def self.solidify
16
+ include RailsAndSolid::TrickHim
17
+ end
7
18
  end
@@ -1,9 +1,9 @@
1
1
  module RailsAndSolid
2
2
  module Handler
3
3
  class Instantiate
4
- def extract(controller, var)
5
- val = var.camelize.constantize.new(controller.params[p])
6
- controller.send :instance_variable_set ,"@#{var}", val
4
+ def extract(controller, name)
5
+ val = name.camelize.constantize.new(controller.params[p])
6
+ controller.send :instance_variable_set ,"@#{name}", val
7
7
  return val
8
8
  end
9
9
  def handles?(controller, name)
@@ -1,3 +1,3 @@
1
1
  module RailsAndSolid
2
- VERSION = "0.9.0"
2
+ VERSION = "0.9.1"
3
3
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 9
8
- - 0
9
- version: 0.9.0
8
+ - 1
9
+ version: 0.9.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Guilherme Silveira
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-03-08 00:00:00 -03:00
17
+ date: 2011-03-18 00:00:00 -03:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency