active_helper 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +42 -9
- data/Rakefile +1 -1
- data/lib/active_helper.rb +30 -1
- data/lib/active_helper/base.rb +2 -1
- data/lib/active_helper/rails.rb +1 -1
- data/test/active_helper_test.rb +31 -37
- data/test/rails_test.rb +1 -0
- metadata +9 -21
- data/lib/active_helper/version.rb +0 -5
data/README.textile
CHANGED
@@ -10,10 +10,10 @@ Helpers suck. They've always sucked, and they will suck on if we keep them in mo
|
|
10
10
|
ActiveHelper is an attempt to pack helpers into *classes*. This brings us a few benefits
|
11
11
|
|
12
12
|
* *inheritance* helpers can be derived other helpers
|
13
|
-
* *delegation* helpers are no longer mixed into a target- the targets @
|
13
|
+
* *delegation* helpers are no longer mixed into a target- the targets @import@ the helper, where the new
|
14
14
|
methods are _delegated_ to the helper instances
|
15
15
|
* *proper encapsulation* helpers don't rely blindly on instance variables - a helper defines its @needs@, the target has to provide readers
|
16
|
-
* *interfaces* a helper clearly @provides@ methods and might @
|
16
|
+
* *interfaces* a helper clearly @provides@ methods and might @import@ additional helpers
|
17
17
|
|
18
18
|
Note that ActiveHelper is a generic helper framework. Not coupled to anything like Rails or Merb. Not providing any concrete helpers. Feel free to use clean helpers in _any_ framework (including Rails and friends)!
|
19
19
|
|
@@ -38,12 +38,14 @@ The view wants to render tags using the TagHelper.
|
|
38
38
|
<pre>
|
39
39
|
class View
|
40
40
|
include ActiveHelper
|
41
|
+
import TagHelper
|
41
42
|
end
|
42
43
|
|
43
|
-
> view.use TagHelper
|
44
44
|
</pre>
|
45
45
|
|
46
|
-
To pull-in
|
46
|
+
To pull-in a helper we invoke @import@ in the target class.
|
47
|
+
|
48
|
+
Note that you can also use @import@ on an object to limit the helper's scope to that instance, only.
|
47
49
|
|
48
50
|
|
49
51
|
h3. Interfaces
|
@@ -84,7 +86,7 @@ end
|
|
84
86
|
That's _a bit_ cleaner than blindly including 30 helper modules in another helper in another helper, isn't it?
|
85
87
|
|
86
88
|
<pre>
|
87
|
-
> view.
|
89
|
+
> view.import FormHelper
|
88
90
|
> view.tag(:form) # => "<form>"
|
89
91
|
> view.form('apotomo.de') # => "<form action=apotomo.de>"
|
90
92
|
</pre>
|
@@ -109,7 +111,7 @@ In ActiveHelper this is slightly different.
|
|
109
111
|
<pre>
|
110
112
|
class FormHelper < TagHelper
|
111
113
|
provides :form_tag
|
112
|
-
|
114
|
+
import UrlHelper
|
113
115
|
|
114
116
|
def form_tag(destination)
|
115
117
|
destination = url_for(destination) # in UrlHelper.
|
@@ -120,9 +122,9 @@ end
|
|
120
122
|
|
121
123
|
Hmm, our _FormHelper_ is already derived from _ActiveHelper_, how do we import additional methods?
|
122
124
|
|
123
|
-
Easy as well, the helper class @
|
125
|
+
Easy as well, the helper class @import@s it.
|
124
126
|
|
125
|
-
So we have to know _#url_for_ is located in the _UrlHelper_ and we even have to
|
127
|
+
So we have to know _#url_for_ is located in the _UrlHelper_ and we even have to @import@ that one.
|
126
128
|
That's a good thing for a) *code tidiness*, b) *good architecture* and c) *debugging*.
|
127
129
|
|
128
130
|
How would the _UrlHelper_ look like?
|
@@ -183,10 +185,41 @@ Now, does it work?
|
|
183
185
|
|
184
186
|
Yeah.
|
185
187
|
|
188
|
+
h2. Rails Bindings
|
189
|
+
|
190
|
+
Use ActiveHelper in your Rails app! Assuming you'd be writing a helper for text munging, you would
|
191
|
+
|
192
|
+
1. Write your helper and put it in @app/active_helpers/text_munging_helper.rb@.
|
193
|
+
|
194
|
+
<pre>
|
195
|
+
class TextMungingHelper < ActiveHelper::Base
|
196
|
+
provides :munge
|
197
|
+
|
198
|
+
def munge(text)
|
199
|
+
text.rot13
|
200
|
+
end
|
201
|
+
end
|
202
|
+
</pre>
|
203
|
+
|
204
|
+
2. Prepare your controller.
|
205
|
+
|
206
|
+
<pre>
|
207
|
+
class StupidController < ActionController::Base
|
208
|
+
active_helper TextMungingHelper
|
209
|
+
</pre>
|
210
|
+
|
211
|
+
3. Use the imported methods in your views, just as you know it from other helpers.
|
212
|
+
|
213
|
+
<pre>
|
214
|
+
<p>
|
215
|
+
Your Email is <%= munge @user.email %>.
|
216
|
+
</p>
|
217
|
+
</pre>
|
218
|
+
|
219
|
+
|
186
220
|
h2. Concepts
|
187
221
|
* Helpers are instances, when accessing a raw @@ivar@ it refers to their own instance variables
|
188
222
|
* Dependencies between different helpers and between the target (e.g. a _View_ instance) are modelled with OOP strategies: Inheritance and the declarative @#needs@.
|
189
|
-
* Naturally helpers can @use@ other helpers on instance level, a helper class @uses@ supporting helpers.
|
190
223
|
|
191
224
|
h2. License
|
192
225
|
|
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
require 'rake'
|
3
3
|
require 'rake/testtask'
|
4
4
|
require 'rake/rdoctask'
|
5
|
-
require File.join(File.dirname(__FILE__), 'lib', 'active_helper'
|
5
|
+
require File.join(File.dirname(__FILE__), 'lib', 'active_helper')
|
6
6
|
|
7
7
|
desc 'Default: run unit tests.'
|
8
8
|
task :default => :test
|
data/lib/active_helper.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
gem 'activesupport', '~>2.3'
|
1
2
|
require 'active_support'
|
2
3
|
require 'forwardable'
|
3
4
|
|
4
5
|
|
5
6
|
module ActiveHelper
|
7
|
+
VERSION = '0.2.1'
|
8
|
+
|
6
9
|
module GenericMethods
|
7
10
|
def use_for(classes, target)
|
8
11
|
classes.each do |helper_class|
|
@@ -44,10 +47,36 @@ module ActiveHelper
|
|
44
47
|
#
|
45
48
|
# view = View.new
|
46
49
|
# view.use UrlHelper, DataMapperHelper
|
47
|
-
def
|
50
|
+
def import(*classes)
|
48
51
|
setup_delegator_strategy!
|
49
52
|
use_for(classes, self)
|
50
53
|
end
|
54
|
+
alias_method :use, :import
|
55
|
+
|
56
|
+
module ClassMethods
|
57
|
+
include GenericMethods
|
58
|
+
|
59
|
+
# Imports the provided methods from +classes+ into the target (the receiver).
|
60
|
+
# All imported helper methods in the target will be delegated back to the helpers.
|
61
|
+
#
|
62
|
+
# Example:
|
63
|
+
# class View
|
64
|
+
# uses UrlHelper, DataMapperHelper
|
65
|
+
# end
|
66
|
+
def import(*classes)
|
67
|
+
setup_delegator_strategy!
|
68
|
+
use_for(classes, self)
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
def setup_delegator_strategy!
|
73
|
+
extend Forwardable
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.included(base)
|
78
|
+
base.extend ClassMethods
|
79
|
+
end
|
51
80
|
end
|
52
81
|
|
53
82
|
require 'active_helper/base'
|
data/lib/active_helper/base.rb
CHANGED
@@ -60,9 +60,10 @@ module ActiveHelper
|
|
60
60
|
use_class_helpers!
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
63
|
+
def import(*classes)
|
64
64
|
use_for(classes, parent) # in GenericMethods.
|
65
65
|
end
|
66
|
+
alias_method :use, :import
|
66
67
|
|
67
68
|
protected
|
68
69
|
# Delegates methods declared with #needs back to parent.
|
data/lib/active_helper/rails.rb
CHANGED
@@ -19,7 +19,7 @@ class ActionController::Base
|
|
19
19
|
|
20
20
|
def initialize_template_class_with_active_helper(response)
|
21
21
|
initialize_template_class_without_active_helper(response)
|
22
|
-
response.template.
|
22
|
+
response.template.import *self.class.active_helpers
|
23
23
|
end
|
24
24
|
|
25
25
|
alias_method_chain :initialize_template_class, :active_helper
|
data/test/active_helper_test.rb
CHANGED
@@ -39,12 +39,12 @@ class ActiveHelperTest < Test::Unit::TestCase
|
|
39
39
|
should "delegate the method to the parent when called" do
|
40
40
|
@helper_class.instance_eval { needs :bottle }
|
41
41
|
@helper = @helper_class.new(@target)
|
42
|
-
@target.
|
42
|
+
@target.import @helper.class
|
43
43
|
|
44
44
|
assert_equal "cheers!", @helper.bottle
|
45
45
|
end
|
46
46
|
|
47
|
-
# DiningHelper.
|
47
|
+
# DiningHelper.import GreedyHelper
|
48
48
|
#
|
49
49
|
# GreedyHelper
|
50
50
|
# needs :bottle
|
@@ -56,14 +56,14 @@ class ActiveHelperTest < Test::Unit::TestCase
|
|
56
56
|
@greedy_class.instance_eval { needs :bottle }
|
57
57
|
|
58
58
|
@dining = helper_mock(@target)
|
59
|
-
@dining.
|
59
|
+
@dining.import @greedy_class
|
60
60
|
|
61
61
|
assert_equal 'cheers!', helper_in(@greedy_class, @dining).bottle
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
context "With #parent_readers and #
|
66
|
+
context "With #parent_readers and #import," do
|
67
67
|
setup do
|
68
68
|
@target = Object.new
|
69
69
|
@target.class.instance_eval { include ::ActiveHelper }
|
@@ -131,29 +131,29 @@ class ActiveHelperTest < Test::Unit::TestCase
|
|
131
131
|
|
132
132
|
context "On a Helper" do
|
133
133
|
setup do
|
134
|
-
assert_respond_to ::ActiveHelper::Base, :
|
134
|
+
assert_respond_to ::ActiveHelper::Base, :import
|
135
135
|
@helper = Class.new(::ActiveHelper::Base).new
|
136
|
-
assert_respond_to @helper.class, :
|
136
|
+
assert_respond_to @helper.class, :import
|
137
137
|
assert ! @helper.respond_to?(:eat)
|
138
138
|
|
139
139
|
|
140
140
|
end
|
141
141
|
|
142
|
-
context "#
|
142
|
+
context "#import" do
|
143
143
|
should "delegate the new Helper methods" do
|
144
|
-
@helper.
|
144
|
+
@helper.import GreedyHelper
|
145
145
|
assert_respond_to @helper, :eat
|
146
146
|
end
|
147
147
|
|
148
148
|
should "set @parent => @target in the used Helper" do
|
149
149
|
@target = Object.new
|
150
150
|
@helper = Class.new(::ActiveHelper::Base).new(@target)
|
151
|
-
@helper.
|
151
|
+
@helper.import GreedyHelper
|
152
152
|
assert_equal @target, helper_in(GreedyHelper, @helper).parent # parent of used handler is target, not the using handler!
|
153
153
|
end
|
154
154
|
|
155
155
|
should "accept multiple helper classes" do
|
156
|
-
@helper.
|
156
|
+
@helper.import GreedyHelper, ThirstyHelper
|
157
157
|
assert_respond_to @helper, :eat
|
158
158
|
assert_respond_to @helper, :drink
|
159
159
|
assert_respond_to @helper, :booze
|
@@ -161,7 +161,7 @@ class ActiveHelperTest < Test::Unit::TestCase
|
|
161
161
|
|
162
162
|
should "accept empty helpers with no methods" do
|
163
163
|
@empty_helper = helper_mock
|
164
|
-
@helper.
|
164
|
+
@helper.import @empty_helper.class
|
165
165
|
assert helper_in(@empty_helper.class, @helper)
|
166
166
|
end
|
167
167
|
|
@@ -196,14 +196,14 @@ class ActiveHelperTest < Test::Unit::TestCase
|
|
196
196
|
end
|
197
197
|
|
198
198
|
should "respond to the new delegated Helper methods" do
|
199
|
-
@helper.class.
|
199
|
+
@helper.class.import GreedyHelper
|
200
200
|
assert_respond_to @helper.class.new, :eat
|
201
201
|
end
|
202
202
|
|
203
203
|
should "inherit helper methods to ancestors" do
|
204
204
|
class DiningHelper < ::ActiveHelper::Base
|
205
205
|
provides :drink
|
206
|
-
|
206
|
+
import GreedyHelper
|
207
207
|
|
208
208
|
def drink;end
|
209
209
|
end
|
@@ -219,50 +219,44 @@ class ActiveHelperTest < Test::Unit::TestCase
|
|
219
219
|
setup do
|
220
220
|
@target_class = Class.new(Object) # don't pollute Object directly.
|
221
221
|
@target_class.instance_eval { include ::ActiveHelper }
|
222
|
-
assert_respond_to @target_class, :
|
222
|
+
assert_respond_to @target_class, :import
|
223
223
|
|
224
224
|
@target = @target_class.new
|
225
225
|
assert ! @target.respond_to?(:eat)
|
226
226
|
end
|
227
227
|
|
228
|
-
context "#
|
228
|
+
context "#import" do
|
229
229
|
should "delegate new delegated helper methods" do
|
230
|
-
@target.
|
230
|
+
@target.import GreedyHelper
|
231
231
|
assert_respond_to @target, :eat
|
232
232
|
end
|
233
233
|
|
234
234
|
should "set @parent => @target in the used Helper" do
|
235
|
-
@target.
|
235
|
+
@target.import GreedyHelper
|
236
236
|
assert_equal @target, helper_in(GreedyHelper, @target).parent
|
237
237
|
end
|
238
238
|
|
239
239
|
should "accept multiple helper classes" do
|
240
|
-
@target.
|
240
|
+
@target.import GreedyHelper, ThirstyHelper
|
241
241
|
assert_respond_to @target, :eat
|
242
242
|
assert_respond_to @target, :drink
|
243
243
|
assert_respond_to @target, :booze
|
244
244
|
end
|
245
245
|
end
|
246
246
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
#
|
261
|
-
# @helper = Class.new(DiningHelper).new
|
262
|
-
# assert_respond_to @helper, :eat # from uses GreedyHelper.
|
263
|
-
# assert_respond_to @helper, :drink # from DiningHelper inheritance.
|
264
|
-
# end
|
265
|
-
#end
|
247
|
+
context "Class#import" do
|
248
|
+
should "delegate helper methods" do
|
249
|
+
@target.class.import GreedyHelper
|
250
|
+
assert_respond_to @target, :eat
|
251
|
+
end
|
252
|
+
|
253
|
+
should "accept multiple helper classes" do
|
254
|
+
@target.class.import GreedyHelper, ThirstyHelper
|
255
|
+
assert_respond_to @target, :eat
|
256
|
+
assert_respond_to @target, :drink
|
257
|
+
assert_respond_to @target, :booze
|
258
|
+
end
|
259
|
+
end
|
266
260
|
end
|
267
261
|
|
268
262
|
context "#ivar_name_for" do
|
data/test/rails_test.rb
CHANGED
metadata
CHANGED
@@ -1,12 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_helper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 0
|
7
|
-
- 2
|
8
|
-
- 0
|
9
|
-
version: 0.2.0
|
4
|
+
version: 0.2.1
|
10
5
|
platform: ruby
|
11
6
|
authors:
|
12
7
|
- Nick Sutterer
|
@@ -14,23 +9,19 @@ autorequire:
|
|
14
9
|
bindir: bin
|
15
10
|
cert_chain: []
|
16
11
|
|
17
|
-
date: 2010-
|
12
|
+
date: 2010-06-17 00:00:00 +02:00
|
18
13
|
default_executable:
|
19
14
|
dependencies:
|
20
15
|
- !ruby/object:Gem::Dependency
|
21
16
|
name: activesupport
|
22
|
-
|
23
|
-
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
20
|
requirements:
|
25
21
|
- - ">="
|
26
22
|
- !ruby/object:Gem::Version
|
27
|
-
segments:
|
28
|
-
- 2
|
29
|
-
- 3
|
30
|
-
- 0
|
31
23
|
version: 2.3.0
|
32
|
-
|
33
|
-
version_requirements: *id001
|
24
|
+
version:
|
34
25
|
description: Finally - helpers with proper encapsulation, delegation, interfaces and inheritance!
|
35
26
|
email: apotonick@gmail.com
|
36
27
|
executables: []
|
@@ -45,7 +36,6 @@ files:
|
|
45
36
|
- lib/active_helper.rb
|
46
37
|
- lib/active_helper/base.rb
|
47
38
|
- lib/active_helper/rails.rb
|
48
|
-
- lib/active_helper/version.rb
|
49
39
|
- rails/init.rb
|
50
40
|
- test/active_helper_test.rb
|
51
41
|
- test/helpers/helpers.rb
|
@@ -64,20 +54,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
64
54
|
requirements:
|
65
55
|
- - ">="
|
66
56
|
- !ruby/object:Gem::Version
|
67
|
-
segments:
|
68
|
-
- 0
|
69
57
|
version: "0"
|
58
|
+
version:
|
70
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
60
|
requirements:
|
72
61
|
- - ">="
|
73
62
|
- !ruby/object:Gem::Version
|
74
|
-
segments:
|
75
|
-
- 0
|
76
63
|
version: "0"
|
64
|
+
version:
|
77
65
|
requirements: []
|
78
66
|
|
79
67
|
rubyforge_project:
|
80
|
-
rubygems_version: 1.3.
|
68
|
+
rubygems_version: 1.3.5
|
81
69
|
signing_key:
|
82
70
|
specification_version: 3
|
83
71
|
summary: Finally - helpers with proper encapsulation, delegation, interfaces and inheritance!
|