##// END OF EJS Templates
link_to in Redmine::Hook::ViewListener omits relative url root (#19024)....
Jean-Philippe Lang -
r13578:d347fd4d39ff
parent child
Show More
@@ -1,175 +1,175
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module Redmine
18 module Redmine
19 module Hook
19 module Hook
20 @@listener_classes = []
20 @@listener_classes = []
21 @@listeners = nil
21 @@listeners = nil
22 @@hook_listeners = {}
22 @@hook_listeners = {}
23
23
24 class << self
24 class << self
25 # Adds a listener class.
25 # Adds a listener class.
26 # Automatically called when a class inherits from Redmine::Hook::Listener.
26 # Automatically called when a class inherits from Redmine::Hook::Listener.
27 def add_listener(klass)
27 def add_listener(klass)
28 raise "Hooks must include Singleton module." unless klass.included_modules.include?(Singleton)
28 raise "Hooks must include Singleton module." unless klass.included_modules.include?(Singleton)
29 @@listener_classes << klass
29 @@listener_classes << klass
30 clear_listeners_instances
30 clear_listeners_instances
31 end
31 end
32
32
33 # Returns all the listener instances.
33 # Returns all the listener instances.
34 def listeners
34 def listeners
35 @@listeners ||= @@listener_classes.collect {|listener| listener.instance}
35 @@listeners ||= @@listener_classes.collect {|listener| listener.instance}
36 end
36 end
37
37
38 # Returns the listener instances for the given hook.
38 # Returns the listener instances for the given hook.
39 def hook_listeners(hook)
39 def hook_listeners(hook)
40 @@hook_listeners[hook] ||= listeners.select {|listener| listener.respond_to?(hook)}
40 @@hook_listeners[hook] ||= listeners.select {|listener| listener.respond_to?(hook)}
41 end
41 end
42
42
43 # Clears all the listeners.
43 # Clears all the listeners.
44 def clear_listeners
44 def clear_listeners
45 @@listener_classes = []
45 @@listener_classes = []
46 clear_listeners_instances
46 clear_listeners_instances
47 end
47 end
48
48
49 # Clears all the listeners instances.
49 # Clears all the listeners instances.
50 def clear_listeners_instances
50 def clear_listeners_instances
51 @@listeners = nil
51 @@listeners = nil
52 @@hook_listeners = {}
52 @@hook_listeners = {}
53 end
53 end
54
54
55 # Calls a hook.
55 # Calls a hook.
56 # Returns the listeners response.
56 # Returns the listeners response.
57 def call_hook(hook, context={})
57 def call_hook(hook, context={})
58 [].tap do |response|
58 [].tap do |response|
59 hls = hook_listeners(hook)
59 hls = hook_listeners(hook)
60 if hls.any?
60 if hls.any?
61 hls.each {|listener| response << listener.send(hook, context)}
61 hls.each {|listener| response << listener.send(hook, context)}
62 end
62 end
63 end
63 end
64 end
64 end
65 end
65 end
66
66
67 # Base class for hook listeners.
67 # Base class for hook listeners.
68 class Listener
68 class Listener
69 include Singleton
69 include Singleton
70 include Redmine::I18n
70 include Redmine::I18n
71
71
72 # Registers the listener
72 # Registers the listener
73 def self.inherited(child)
73 def self.inherited(child)
74 Redmine::Hook.add_listener(child)
74 Redmine::Hook.add_listener(child)
75 super
75 super
76 end
76 end
77
77
78 end
78 end
79
79
80 # Listener class used for views hooks.
80 # Listener class used for views hooks.
81 # Listeners that inherit this class will include various helpers by default.
81 # Listeners that inherit this class will include various helpers by default.
82 class ViewListener < Listener
82 class ViewListener < Listener
83 include ERB::Util
83 include ERB::Util
84 include ActionView::Helpers::TagHelper
84 include ActionView::Helpers::TagHelper
85 include ActionView::Helpers::FormHelper
85 include ActionView::Helpers::FormHelper
86 include ActionView::Helpers::FormTagHelper
86 include ActionView::Helpers::FormTagHelper
87 include ActionView::Helpers::FormOptionsHelper
87 include ActionView::Helpers::FormOptionsHelper
88 include ActionView::Helpers::JavaScriptHelper
88 include ActionView::Helpers::JavaScriptHelper
89 include ActionView::Helpers::NumberHelper
89 include ActionView::Helpers::NumberHelper
90 include ActionView::Helpers::UrlHelper
90 include ActionView::Helpers::UrlHelper
91 include ActionView::Helpers::AssetTagHelper
91 include ActionView::Helpers::AssetTagHelper
92 include ActionView::Helpers::TextHelper
92 include ActionView::Helpers::TextHelper
93 include Rails.application.routes.url_helpers
93 include Rails.application.routes.url_helpers
94 include ApplicationHelper
94 include ApplicationHelper
95
95
96 # Default to creating links using only the path. Subclasses can
96 # Default to creating links using only the path. Subclasses can
97 # change this default as needed
97 # change this default as needed
98 def self.default_url_options
98 def self.default_url_options
99 {:only_path => true }
99 {:only_path => true, :script_name => Redmine::Utils.relative_url_root}
100 end
100 end
101
101
102 # Helper method to directly render using the context,
102 # Helper method to directly render using the context,
103 # render_options must be valid #render options.
103 # render_options must be valid #render options.
104 #
104 #
105 # class MyHook < Redmine::Hook::ViewListener
105 # class MyHook < Redmine::Hook::ViewListener
106 # render_on :view_issues_show_details_bottom, :partial => "show_more_data"
106 # render_on :view_issues_show_details_bottom, :partial => "show_more_data"
107 # end
107 # end
108 #
108 #
109 # class MultipleHook < Redmine::Hook::ViewListener
109 # class MultipleHook < Redmine::Hook::ViewListener
110 # render_on :view_issues_show_details_bottom,
110 # render_on :view_issues_show_details_bottom,
111 # {:partial => "show_more_data"},
111 # {:partial => "show_more_data"},
112 # {:partial => "show_even_more_data"}
112 # {:partial => "show_even_more_data"}
113 # end
113 # end
114 #
114 #
115 def self.render_on(hook, *render_options)
115 def self.render_on(hook, *render_options)
116 define_method hook do |context|
116 define_method hook do |context|
117 render_options.map do |options|
117 render_options.map do |options|
118 if context[:hook_caller].respond_to?(:render)
118 if context[:hook_caller].respond_to?(:render)
119 context[:hook_caller].send(:render, {:locals => context}.merge(options))
119 context[:hook_caller].send(:render, {:locals => context}.merge(options))
120 elsif context[:controller].is_a?(ActionController::Base)
120 elsif context[:controller].is_a?(ActionController::Base)
121 context[:controller].send(:render_to_string, {:locals => context}.merge(options))
121 context[:controller].send(:render_to_string, {:locals => context}.merge(options))
122 else
122 else
123 raise "Cannot render #{self.name} hook from #{context[:hook_caller].class.name}"
123 raise "Cannot render #{self.name} hook from #{context[:hook_caller].class.name}"
124 end
124 end
125 end
125 end
126 end
126 end
127 end
127 end
128
128
129 def controller
129 def controller
130 nil
130 nil
131 end
131 end
132
132
133 def config
133 def config
134 ActionController::Base.config
134 ActionController::Base.config
135 end
135 end
136 end
136 end
137
137
138 # Helper module included in ApplicationHelper and ActionController so that
138 # Helper module included in ApplicationHelper and ActionController so that
139 # hooks can be called in views like this:
139 # hooks can be called in views like this:
140 #
140 #
141 # <%= call_hook(:some_hook) %>
141 # <%= call_hook(:some_hook) %>
142 # <%= call_hook(:another_hook, :foo => 'bar') %>
142 # <%= call_hook(:another_hook, :foo => 'bar') %>
143 #
143 #
144 # Or in controllers like:
144 # Or in controllers like:
145 # call_hook(:some_hook)
145 # call_hook(:some_hook)
146 # call_hook(:another_hook, :foo => 'bar')
146 # call_hook(:another_hook, :foo => 'bar')
147 #
147 #
148 # Hooks added to views will be concatenated into a string. Hooks added to
148 # Hooks added to views will be concatenated into a string. Hooks added to
149 # controllers will return an array of results.
149 # controllers will return an array of results.
150 #
150 #
151 # Several objects are automatically added to the call context:
151 # Several objects are automatically added to the call context:
152 #
152 #
153 # * project => current project
153 # * project => current project
154 # * request => Request instance
154 # * request => Request instance
155 # * controller => current Controller instance
155 # * controller => current Controller instance
156 # * hook_caller => object that called the hook
156 # * hook_caller => object that called the hook
157 #
157 #
158 module Helper
158 module Helper
159 def call_hook(hook, context={})
159 def call_hook(hook, context={})
160 if is_a?(ActionController::Base)
160 if is_a?(ActionController::Base)
161 default_context = {:controller => self, :project => @project, :request => request, :hook_caller => self}
161 default_context = {:controller => self, :project => @project, :request => request, :hook_caller => self}
162 Redmine::Hook.call_hook(hook, default_context.merge(context))
162 Redmine::Hook.call_hook(hook, default_context.merge(context))
163 else
163 else
164 default_context = { :project => @project, :hook_caller => self }
164 default_context = { :project => @project, :hook_caller => self }
165 default_context[:controller] = controller if respond_to?(:controller)
165 default_context[:controller] = controller if respond_to?(:controller)
166 default_context[:request] = request if respond_to?(:request)
166 default_context[:request] = request if respond_to?(:request)
167 Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ').html_safe
167 Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ').html_safe
168 end
168 end
169 end
169 end
170 end
170 end
171 end
171 end
172 end
172 end
173
173
174 ApplicationHelper.send(:include, Redmine::Hook::Helper)
174 ApplicationHelper.send(:include, Redmine::Hook::Helper)
175 ActionController::Base.send(:include, Redmine::Hook::Helper)
175 ActionController::Base.send(:include, Redmine::Hook::Helper)
@@ -1,180 +1,189
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../test_helper', __FILE__)
19
19
20 class Redmine::Hook::ManagerTest < ActionView::TestCase
20 class Redmine::Hook::ManagerTest < ActionView::TestCase
21 fixtures :projects, :users, :members, :member_roles, :roles,
21 fixtures :projects, :users, :members, :member_roles, :roles,
22 :groups_users,
22 :groups_users,
23 :email_addresses,
23 :email_addresses,
24 :trackers, :projects_trackers,
24 :trackers, :projects_trackers,
25 :enabled_modules,
25 :enabled_modules,
26 :versions,
26 :versions,
27 :issue_statuses, :issue_categories, :issue_relations,
27 :issue_statuses, :issue_categories, :issue_relations,
28 :enumerations,
28 :enumerations,
29 :issues
29 :issues
30
30
31 # Some hooks that are manually registered in these tests
31 # Some hooks that are manually registered in these tests
32 class TestHook < Redmine::Hook::ViewListener; end
32 class TestHook < Redmine::Hook::ViewListener; end
33
33
34 class TestHook1 < TestHook
34 class TestHook1 < TestHook
35 def view_layouts_base_html_head(context)
35 def view_layouts_base_html_head(context)
36 'Test hook 1 listener.'
36 'Test hook 1 listener.'
37 end
37 end
38 end
38 end
39
39
40 class TestHook2 < TestHook
40 class TestHook2 < TestHook
41 def view_layouts_base_html_head(context)
41 def view_layouts_base_html_head(context)
42 'Test hook 2 listener.'
42 'Test hook 2 listener.'
43 end
43 end
44 end
44 end
45
45
46 class TestHook3 < TestHook
46 class TestHook3 < TestHook
47 def view_layouts_base_html_head(context)
47 def view_layouts_base_html_head(context)
48 "Context keys: #{context.keys.collect(&:to_s).sort.join(', ')}."
48 "Context keys: #{context.keys.collect(&:to_s).sort.join(', ')}."
49 end
49 end
50 end
50 end
51
51
52 class TestLinkToHook < TestHook
52 class TestLinkToHook < TestHook
53 def view_layouts_base_html_head(context)
53 def view_layouts_base_html_head(context)
54 link_to('Issues', :controller => 'issues')
54 link_to('Issues', :controller => 'issues')
55 end
55 end
56 end
56 end
57
57
58 class TestHookHelperController < ActionController::Base
58 class TestHookHelperController < ActionController::Base
59 include Redmine::Hook::Helper
59 include Redmine::Hook::Helper
60 end
60 end
61
61
62 class TestHookHelperView < ActionView::Base
62 class TestHookHelperView < ActionView::Base
63 include Redmine::Hook::Helper
63 include Redmine::Hook::Helper
64 end
64 end
65
65
66 Redmine::Hook.clear_listeners
66 Redmine::Hook.clear_listeners
67
67
68 def setup
68 def setup
69 @hook_module = Redmine::Hook
69 @hook_module = Redmine::Hook
70 @hook_module.clear_listeners
70 @hook_module.clear_listeners
71 end
71 end
72
72
73 def teardown
73 def teardown
74 @hook_module.clear_listeners
74 @hook_module.clear_listeners
75 end
75 end
76
76
77 def test_clear_listeners
77 def test_clear_listeners
78 assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size
78 assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size
79 @hook_module.add_listener(TestHook1)
79 @hook_module.add_listener(TestHook1)
80 @hook_module.add_listener(TestHook2)
80 @hook_module.add_listener(TestHook2)
81 assert_equal 2, @hook_module.hook_listeners(:view_layouts_base_html_head).size
81 assert_equal 2, @hook_module.hook_listeners(:view_layouts_base_html_head).size
82
82
83 @hook_module.clear_listeners
83 @hook_module.clear_listeners
84 assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size
84 assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size
85 end
85 end
86
86
87 def test_add_listener
87 def test_add_listener
88 assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size
88 assert_equal 0, @hook_module.hook_listeners(:view_layouts_base_html_head).size
89 @hook_module.add_listener(TestHook1)
89 @hook_module.add_listener(TestHook1)
90 assert_equal 1, @hook_module.hook_listeners(:view_layouts_base_html_head).size
90 assert_equal 1, @hook_module.hook_listeners(:view_layouts_base_html_head).size
91 end
91 end
92
92
93 def test_call_hook
93 def test_call_hook
94 @hook_module.add_listener(TestHook1)
94 @hook_module.add_listener(TestHook1)
95 assert_equal ['Test hook 1 listener.'], hook_helper.call_hook(:view_layouts_base_html_head)
95 assert_equal ['Test hook 1 listener.'], hook_helper.call_hook(:view_layouts_base_html_head)
96 end
96 end
97
97
98 def test_call_hook_with_context
98 def test_call_hook_with_context
99 @hook_module.add_listener(TestHook3)
99 @hook_module.add_listener(TestHook3)
100 assert_equal ['Context keys: bar, controller, foo, hook_caller, project, request.'],
100 assert_equal ['Context keys: bar, controller, foo, hook_caller, project, request.'],
101 hook_helper.call_hook(:view_layouts_base_html_head, :foo => 1, :bar => 'a')
101 hook_helper.call_hook(:view_layouts_base_html_head, :foo => 1, :bar => 'a')
102 end
102 end
103
103
104 def test_call_hook_with_multiple_listeners
104 def test_call_hook_with_multiple_listeners
105 @hook_module.add_listener(TestHook1)
105 @hook_module.add_listener(TestHook1)
106 @hook_module.add_listener(TestHook2)
106 @hook_module.add_listener(TestHook2)
107 assert_equal ['Test hook 1 listener.', 'Test hook 2 listener.'], hook_helper.call_hook(:view_layouts_base_html_head)
107 assert_equal ['Test hook 1 listener.', 'Test hook 2 listener.'], hook_helper.call_hook(:view_layouts_base_html_head)
108 end
108 end
109
109
110 # Context: Redmine::Hook::Helper.call_hook default_url
110 # Context: Redmine::Hook::Helper.call_hook default_url
111 def test_call_hook_default_url_options
111 def test_call_hook_default_url_options
112 @hook_module.add_listener(TestLinkToHook)
112 @hook_module.add_listener(TestLinkToHook)
113
113
114 assert_equal ['<a href="/issues">Issues</a>'], hook_helper.call_hook(:view_layouts_base_html_head)
114 assert_equal ['<a href="/issues">Issues</a>'], hook_helper.call_hook(:view_layouts_base_html_head)
115 end
115 end
116
116
117 def test_view_hook_should_generate_links_with_relative_url_root
118 Redmine::Utils.relative_url_root = '/foo'
119 @hook_module.add_listener(TestLinkToHook)
120
121 assert_equal ['<a href="/foo/issues">Issues</a>'], hook_helper.call_hook(:view_layouts_base_html_head)
122 ensure
123 Redmine::Utils.relative_url_root = ''
124 end
125
117 # Context: Redmine::Hook::Helper.call_hook
126 # Context: Redmine::Hook::Helper.call_hook
118 def test_call_hook_with_project_added_to_context
127 def test_call_hook_with_project_added_to_context
119 @hook_module.add_listener(TestHook3)
128 @hook_module.add_listener(TestHook3)
120 assert_match /project/i, hook_helper.call_hook(:view_layouts_base_html_head)[0]
129 assert_match /project/i, hook_helper.call_hook(:view_layouts_base_html_head)[0]
121 end
130 end
122
131
123 def test_call_hook_from_controller_with_controller_added_to_context
132 def test_call_hook_from_controller_with_controller_added_to_context
124 @hook_module.add_listener(TestHook3)
133 @hook_module.add_listener(TestHook3)
125 assert_match /controller/i, hook_helper.call_hook(:view_layouts_base_html_head)[0]
134 assert_match /controller/i, hook_helper.call_hook(:view_layouts_base_html_head)[0]
126 end
135 end
127
136
128 def test_call_hook_from_controller_with_request_added_to_context
137 def test_call_hook_from_controller_with_request_added_to_context
129 @hook_module.add_listener(TestHook3)
138 @hook_module.add_listener(TestHook3)
130 assert_match /request/i, hook_helper.call_hook(:view_layouts_base_html_head)[0]
139 assert_match /request/i, hook_helper.call_hook(:view_layouts_base_html_head)[0]
131 end
140 end
132
141
133 def test_call_hook_from_view_with_project_added_to_context
142 def test_call_hook_from_view_with_project_added_to_context
134 @hook_module.add_listener(TestHook3)
143 @hook_module.add_listener(TestHook3)
135 assert_match /project/i, view_hook_helper.call_hook(:view_layouts_base_html_head)
144 assert_match /project/i, view_hook_helper.call_hook(:view_layouts_base_html_head)
136 end
145 end
137
146
138 def test_call_hook_from_view_with_controller_added_to_context
147 def test_call_hook_from_view_with_controller_added_to_context
139 @hook_module.add_listener(TestHook3)
148 @hook_module.add_listener(TestHook3)
140 assert_match /controller/i, view_hook_helper.call_hook(:view_layouts_base_html_head)
149 assert_match /controller/i, view_hook_helper.call_hook(:view_layouts_base_html_head)
141 end
150 end
142
151
143 def test_call_hook_from_view_with_request_added_to_context
152 def test_call_hook_from_view_with_request_added_to_context
144 @hook_module.add_listener(TestHook3)
153 @hook_module.add_listener(TestHook3)
145 assert_match /request/i, view_hook_helper.call_hook(:view_layouts_base_html_head)
154 assert_match /request/i, view_hook_helper.call_hook(:view_layouts_base_html_head)
146 end
155 end
147
156
148 def test_call_hook_from_view_should_join_responses_with_a_space
157 def test_call_hook_from_view_should_join_responses_with_a_space
149 @hook_module.add_listener(TestHook1)
158 @hook_module.add_listener(TestHook1)
150 @hook_module.add_listener(TestHook2)
159 @hook_module.add_listener(TestHook2)
151 assert_equal 'Test hook 1 listener. Test hook 2 listener.',
160 assert_equal 'Test hook 1 listener. Test hook 2 listener.',
152 view_hook_helper.call_hook(:view_layouts_base_html_head)
161 view_hook_helper.call_hook(:view_layouts_base_html_head)
153 end
162 end
154
163
155 def test_call_hook_should_not_change_the_default_url_for_email_notifications
164 def test_call_hook_should_not_change_the_default_url_for_email_notifications
156 issue = Issue.find(1)
165 issue = Issue.find(1)
157
166
158 ActionMailer::Base.deliveries.clear
167 ActionMailer::Base.deliveries.clear
159 Mailer.deliver_issue_add(issue)
168 Mailer.deliver_issue_add(issue)
160 mail = ActionMailer::Base.deliveries.last
169 mail = ActionMailer::Base.deliveries.last
161
170
162 @hook_module.add_listener(TestLinkToHook)
171 @hook_module.add_listener(TestLinkToHook)
163 hook_helper.call_hook(:view_layouts_base_html_head)
172 hook_helper.call_hook(:view_layouts_base_html_head)
164
173
165 ActionMailer::Base.deliveries.clear
174 ActionMailer::Base.deliveries.clear
166 Mailer.deliver_issue_add(issue)
175 Mailer.deliver_issue_add(issue)
167 mail2 = ActionMailer::Base.deliveries.last
176 mail2 = ActionMailer::Base.deliveries.last
168
177
169 assert_equal mail_body(mail), mail_body(mail2)
178 assert_equal mail_body(mail), mail_body(mail2)
170 end
179 end
171
180
172 def hook_helper
181 def hook_helper
173 @hook_helper ||= TestHookHelperController.new
182 @hook_helper ||= TestHookHelperController.new
174 end
183 end
175
184
176 def view_hook_helper
185 def view_hook_helper
177 @view_hook_helper ||= TestHookHelperView.new(Rails.root.to_s + '/app/views')
186 @view_hook_helper ||= TestHookHelperView.new(Rails.root.to_s + '/app/views')
178 end
187 end
179 end
188 end
180
189
General Comments 0
You need to be logged in to leave comments. Login now