active_helper 0.2.0 → 0.2.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.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!
|