Commit a52a26ff456cdbdd13af893969328451a161e469

Initial.

Commit diff

Rakefile

 
1require 'rubygems'
2Gem.clear_paths
3Gem.path.unshift(File.join(File.dirname(__FILE__), "gems"))
4
5require 'rake'
6require 'rake/rdoctask'
7require 'rake/testtask'
8require 'spec/rake/spectask'
9require 'fileutils'
10require 'merb-core'
11require 'rubigen'
12include FileUtils
13
14# Load the basic runtime dependencies; this will include
15# any plugins and therefore plugin rake tasks.
16init_env = ENV['MERB_ENV'] || 'rake'
17Merb.load_dependencies(:environment => init_env)
18
19# Get Merb plugins and dependencies
20Merb::Plugins.rakefiles.each { |r| require r }
21
22desc "start runner environment"
23task :merb_env do
24 Merb.start_environment(:environment => init_env, :adapter => 'runner')
25end
26
27##############################################################################
28# ADD YOUR CUSTOM TASKS BELOW
29##############################################################################
30
31desc "Add new files to subversion"
32task :svn_add do
33 system "svn status | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\ /g' | xargs svn add"
34end
toggle raw diff

app/controllers/application.rb

 
1class Application < Merb::Controller
2end
toggle raw diff

app/controllers/exceptions.rb

 
1class Exceptions < Application
2
3 # handle NotFound exceptions (404)
4 def not_found
5 render :format => :html
6 end
7
8 # handle NotAcceptable exceptions (406)
9 def not_acceptable
10 render :format => :html
11 end
12
13end
toggle raw diff

app/helpers/global_helpers.rb

 
1module Merb
2 module GlobalHelpers
3 # helpers defined here available to all views.
4 end
5end
toggle raw diff

app/views/exceptions/internal_server_error.html.erb

 
1<html>
2<head>
3 <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
4 <title><%= @exception_name %></title>
5 <style type="text/css" media="screen">
6 body {
7 font-family:arial;
8 font-size:11px;
9 }
10 h1 {
11 font-size:48px;
12 letter-spacing:-4px;
13 margin:0;
14 line-height:36px;
15 color:#333;
16 }
17 h1 sup {
18 font-size: 0.5em;
19 }
20 h1 sup.error_500, h1 sup.error_400 {
21 color:#990E05;
22 }
23 h1 sup.error_100, h1 sup.error_200 {
24 color:#00BF10;
25 }
26 h1 sup.error_300 {
27 /* pretty sure you cant 'see' status 300
28 errors but if you could I think they
29 would be blue */
30 color:#1B2099;
31 }
32 h2 {
33 font-size:36px;
34 letter-spacing:-3px;
35 margin:0;
36 line-height:28px;
37 color:#444;
38 }
39 a, a:visited {
40 color:#00BF10;
41 }
42 .internalError {
43 width:800px;
44 margin:50px auto;
45 }
46 .header {
47 border-bottom:10px solid #333;
48 margin-bottom:1px;
49 background-image: url("data:image/gif;base64,R0lGODlhAwADAIAAAP///8zMzCH5BAAAAAAALAAAAAADAAMAAAIEBHIJBQA7");
50 padding:20px;
51 }
52 table.trace {
53 width:100%;
54 font-family:courier, monospace;
55 letter-spacing:-1px;
56 border-collapse: collapse;
57 border-spacing:0;
58 }
59 table.trace tr td{
60 padding:0;
61 height:26px;
62 font-size:13px;
63 vertical-align:middle;
64 }
65 table.trace tr.file{
66 border-top:2px solid #fff;
67 background-color:#F3F3F3;
68 }
69 table.trace tr.source {
70 background-color:#F8F8F8;
71 display:none;
72 }
73 table.trace .open tr.source {
74 display:table-row;
75 }
76 table.trace tr.file td.expand {
77 width:23px;
78 background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAIAAABvSEP3AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdVJREFUeNqMVL+TwUAYxaRIOlEhlZHGDAUzzOQ61+AqXMV1lJSU7q/QRqm8KFUcJTNn5qJkaPyoKKVz7y4mF8na5Kt29tt9+/Z97/u81+vVQ4r9frdarS6Xi7ETDIZisRjxMGPfmk4niNPpZE+xLAugbPaZ53nzvtfMBe/3+/3dbuehBrAKhZdUKkVAWa9Xsiybv0CPZDJZLr/qa5/BwgwRjYqOKIvFYjQa/aNommZh0Ww2K5UqzwfoQOPxaLPZ3FAmk0+7lplMpt1u53J5OpBOR0eZEE9wHJfP5zud93g88QhluwWbjW+5VOmKBgKBer3eaDTDYeGBQF8+x7rqIYoiPgixWJazpA6HA+MSxRArkUgMh0M409g8Ho8+9wYxxCqVSq1W26EDHGM2m4HOHQrEc38f/Yn7cLmlIRhBENzcx8cVRZnPZ/YUep2BWkjTIfA+PKVpZAXR5QxsjiqCKvGEqqp443w+0dvy17swqD0HB3S73V5PpkNg1qBqt8kwGCjmPkinM0QJbIoEa7U6UG6ToVgs4V9G2g0ESoP5Aoi7KYX5oCgf8IKbkvn9/mr1LRQKESamzgJy0g0tSZIuB3nuGqRU9Vv9C4sKkUhEkp4soxvxI8AAhWrrtXa3X8EAAAAASUVORK5CYII=);
79 background-position:top left;
80 background-repeat:no-repeat;
81 }
82 table.trace .open tr.file td.expand {
83 width:19px;
84 background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAB1CAIAAAAqdO2mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXZJREFUeNrslK1ywkAUhcMOBomEOiSdqLxEBJX0NaijOsjyHGGmCGyQQYaiiiw4gktkcOmZbpsuuzQ/M5XnqJ2d3S/n3nM3rTzPLUP7/Tt0+pLcGQwG3W53OLyHzPMtjYL7q9UqSRLrD4E1Gj1orCvKYuFHUWTVkOM44/HjDcp8/lL4r6NerzeZPMm1KFw0QkDn83m5fP2lHA4fNQvRtNvtjsfDd0WzmSfb2e/fdTqdOvdh/HLJZLOn0+d2HJ+KRGzbdl23EpFlmed5cp2maRzHQq1lvQ5KMi6EUZBGfup6E1pTfd+vrGW7jbQ2C9hTt9BpqNyIWaAwAy6xg2eBz5iRC/NomiZhGN5sqmnkauo0BUGgVQoBjQ80oCACgNQdZHfTYBkF2mxCtWWAqunWpahxIDUt3QYUxIFQpJHyIWpXjinabKbbwItMHT+NyjchrP8QKaSQQgoppJBCCimkkEIKKaSQQgoppJBCCimkkEIKKaSo+hRgAEFD17X08O2NAAAAAElFTkSuQmCC);
85 background-position:top left;
86 background-repeat:no-repeat;
87 }
88 table.trace tr.source td.collapse {
89 width:19px;
90 background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAB1CAIAAAAqdO2mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVxJREFUeNrs0zFygkAUBmBlUkgJHdABlQwVkVJKKUxBYWbkALTxMJwhltyDFkss03IF8pudIcwaDaDl/6pd2P327b7d+eHwMXs4lNkzggoVKlSoUKFChQoVKlSoUKFChQoVKlSoUKFChQqVEYqm6ft9+qiSJEkYho7jTlcw2fd9NOI4nq4gEdFwXXe1Cqco63VkWVbXRTqLhTpOwQRpF7quR1E0TgGhqvLKUFCyoQqG/rks3O6kZKW/eRFpevOCoGTXVTcMQ5EyxyDEkML1c5RzuZOICIyXqn7JBVez6282MWrx731HOv2qB8Hri2lamNk0DfpVVdV1Peodappmmua8bdvzuc7zfNprzrLMth1FnGh/X8MjCAIQv/cFz/+65PcDh7rbvYv2ZUfdj+PxsyzLgVl0hKwgTqeqKApx2LeOc7t98zyv/1FWOgvx9RPii23bmL9cetJ8Ed8CDAC6aFW8bCzFhwAAAABJRU5ErkJggg==);
91 background-position:bottom left;
92 background-repeat:no-repeat;
93 background-color:#6F706F;
94 }
95 table.trace tr td.path {
96 padding-left:10px;
97 }
98 table.trace tr td.code {
99 padding-left:35px;
100 white-space: pre;
101 line-height:9px;
102 padding-bottom:10px;
103 }
104 table.trace tr td.code em {
105 font-weight:bold;
106 color:#00BF10;
107 }
108 table.trace tr td.code a {
109 width: 20px;
110 float: left;
111 }
112 table.trace tr td.code .more {
113 color:#666;
114 }
115 table.trace tr td.line {
116 width:30px;
117 text-align:right;
118 padding-right:4px;
119 }
120 .footer {
121 margin-top:5px;
122 font-size:11px;
123 color:#444;
124 text-align:right;
125 }
126 </style>
127</head>
128<body>
129 <div class="internalError">
130
131 <div class="header">
132 <h1><%= @exception_name %> <sup class="error_<%= @exception.class::STATUS %>"><%= @exception.class::STATUS %></sup></h1>
133 <% if show_details = ::Merb::Config[:exception_details] -%>
134 <h2><%= @exception.message %></h2>
135 <% else -%>
136 <h2>Sorry about that...</h2>
137 <% end -%>
138 <h3>Parameters</h3>
139 <ul>
140 <% params[:original_params].each do |param, value| %>
141 <li><strong><%= param %>:</strong> <%= value.inspect %></li>
142 <% end %>
143 <%= "<li>None</li>" if params[:original_params].empty? %>
144 </ul>
145
146 <h3>Session</h3>
147 <ul>
148 <% params[:original_session].each do |param, value| %>
149 <li><strong><%= param %>:</strong> <%= value.inspect %></li>
150 <% end %>
151 <%= "<li>None</li>" if params[:original_session].empty? %>
152 </ul>
153
154 <h3>Cookies</h3>
155 <ul>
156 <% params[:original_cookies].each do |param, value| %>
157 <li><strong><%= param %>:</strong> <%= value.inspect %></li>
158 <% end %>
159 <%= "<li>None</li>" if params[:original_cookies].empty? %>
160 </ul>
161 </div>
162
163 <% if show_details %>
164 <table class="trace">
165 <% @exception.backtrace.each_with_index do |line, index| %>
166 <tbody class="close">
167 <tr class="file">
168 <td class="expand">
169 </td>
170 <td class="path">
171 <%= (line.match(/^([^:]+)/)[1] rescue 'unknown').sub(/\/((opt|usr)\/local\/lib\/(ruby\/)?(gems\/)?(1.8\/)?(gems\/)?|.+\/app\/)/, '') %>
172 <% unless line.match(/\.erb:/) %>
173 in "<strong><%= line.match(/:in `(.+)'$/)[1] rescue '?' %></strong>"
174 <% else %>
175 (<strong>ERB Template</strong>)
176 <% end %>
177 </td>
178 <td class="line">
179 <a href="txmt://open?url=file://<%=file = (line.match(/^([^:]+)/)[1] rescue 'unknown')%>&amp;line=<%= lineno = line.match(/:([0-9]+):/)[1] rescue '?' %>"><%=lineno%></a>&nbsp;
180 </td>
181 </tr>
182 <tr class="source">
183 <td class="collapse">
184 </td>
185 <td class="code" colspan="2"><% (__caller_lines__(file, lineno, 5) rescue []).each do |llineno, lcode, lcurrent| %>
186<a href="txmt://open?url=file://<%=file%>&amp;line=<%=llineno%>"><%= llineno %></a><%='<em>' if llineno==lineno.to_i %><%= lcode.size > 90 ? CGI.escapeHTML(lcode[0..90])+'<span class="more">......</span>' : CGI.escapeHTML(lcode) %><%='</em>' if llineno==lineno.to_i %>
187<% end %>
188
189</td>
190 </tr>
191 </tbody>
192 <% end %>
193 </table>
194 <script type="text/javascript" charset="utf-8">
195 // swop the open & closed classes
196 els = document.getElementsByTagName('td');
197 for(i=0; i<els.length; i++){
198 if(els[i].className=='expand' || els[i].className=='collapse'){
199 els[i].onclick = function(e){
200 tbody = this.parentNode.parentNode;
201 if(tbody.className=='open'){
202 tbody.className='closed';
203 }else{
204 tbody.className='open';
205 }
206 }
207 }
208 }
209 </script>
210 <% end %>
211 <div class="footer">
212 lots of love, from <a href="#">merb</a>
213 </div>
214 </div>
215</body>
216</html>
toggle raw diff

app/views/exceptions/not_acceptable.html.erb

 
1<div id="container">
2 <div id="header-container">
3 <img src="/images/merb.jpg" />
4 <!-- <h1>Mongrel + Erb</h1> -->
5 <h2>pocket rocket web framework</h2>
6 <hr />
7 </div>
8
9 <div id="left-container">
10 <h3>Exception:</h3>
11 <p><%= params[:exception] %></p>
12 </div>
13
14 <div id="main-container">
15 <h3>Why am I seeing this page?</h3>
16 <p>Merb couldn't find an appropriate content_type to return,
17 based on what you said was available via provides() and
18 what the client requested.</p>
19
20 <h3>How to add a mime-type</h3>
21 <pre><code>
22 Merb.add_mime_type :pdf, :to_pdf, %w[application/pdf], &quot;Content-Encoding&quot; =&gt; &quot;gzip&quot;
23 </code></pre>
24 <h3>What this means is:</h3>
25 <ul>
26 <li>Add a mime-type for :pdf</li>
27 <li>Register the method for converting objects to PDF as <code>#to_pdf</code>.</li>
28 <li>Register the incoming mime-type "Accept" header as <code>application/pdf</code>.</li>
29 <li>Specify a new header for PDF types so it will set <code>Content-Encoding</code> to gzip.</li>
30 </ul>
31
32 <h3>You can then do:</h3>
33 <pre><code>
34 class Foo &lt; Application
35 provides :pdf
36 end
37 </code></pre>
38
39 <h3>Where can I find help?</h3>
40 <p>If you have any questions or if you can't figure something out, please take a
41 look at our <a href="http://merb.devjavu.com/"> project development page</a> or,
42 feel free to come chat at irc.freenode.net, channel #merb.</p>
43
44 <h3>How do I edit this page?</h3>
45 <p>You can change what people see when this happens byy editing <tt>app/views/exceptions/not_found.html.erb</tt>.</p>
46
47 </div>
48
49 <div id="footer-container">
50 <hr />
51 <div class="left"></div>
52 <div class="right">&copy; 2007 the merb dev team</div>
53 <p>&nbsp;</p>
54 </div>
55</div>
toggle raw diff

app/views/exceptions/not_found.html.erb

 
1<div id="container">
2 <div id="header-container">
3 <img src="/images/merb.jpg" />
4 <!-- <h1>Mongrel + Erb</h1> -->
5 <h2>pocket rocket web framework</h2>
6 <hr />
7 </div>
8
9 <div id="left-container">
10 <h3>Exception:</h3>
11 <p><%= params[:exception] %></p>
12 </div>
13
14 <div id="main-container">
15 <h3>Welcome to Merb!</h3>
16 <p>Merb is a light-weight MVC framework written in Ruby. We hope you enjoy it.</p>
17
18 <h3>Where can I find help?</h3>
19 <p>If you have any questions or if you can't figure something out, please take a
20 look at our <a href="http://merb.devjavu.com/"> project development page</a> or,
21 feel free to come chat at irc.freenode.net, channel #merb.</p>
22
23 <h3>How do I edit this page?</h3>
24 <p>You're seeing this page because you need to edit the following files:
25 <ul>
26 <li>config/router.rb <strong><em>(recommended)</em></strong></li>
27 <li>app/views/exceptions/not_found.html.erb <strong><em>(recommended)</em></strong></li>
28 <li>app/views/layout/application.html.erb <strong><em>(change this layout)</em></strong></li>
29 </ul>
30 </p>
31 </div>
32
33 <div id="footer-container">
34 <hr />
35 <div class="left"></div>
36 <div class="right">&copy; 2007 the merb dev team</div>
37 <p>&nbsp;</p>
38 </div>
39</div>
toggle raw diff

app/views/layout/application.html.erb

 
1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
3 <head>
4 <title>Fresh Merb App</title>
5 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
6 <link rel="stylesheet" href="/stylesheets/master.css" type="text/css" media="screen" charset="utf-8" />
7 </head>
8 <body>
9 <%= catch_content :for_layout %>
10 </body>
11</html>
toggle raw diff

autotest/discover.rb

 
1Autotest.add_discovery { "merb" }
toggle raw diff

autotest/merb.rb

 
1# Adapted from Autotest::Rails
2require 'autotest'
3
4class Autotest::Merb < Autotest
5
6 # +model_tests_dir+:: the directory to find model-centric tests
7 # +controller_tests_dir+:: the directory to find controller-centric tests
8 # +view_tests_dir+:: the directory to find view-centric tests
9 # +fixtures_dir+:: the directory to find fixtures in
10 attr_accessor :model_tests_dir, :controller_tests_dir, :view_tests_dir, :fixtures_dir
11
12 def initialize # :nodoc:
13 super
14
15 initialize_test_layout
16
17 # Ignore any happenings in these directories
18 add_exception %r%^\./(?:doc|log|public|tmp)%
19
20 # Ignore any mappings that Autotest may have already set up
21 clear_mappings
22
23 # Any changes to a file in the root of the 'lib' directory will run any
24 # model test with a corresponding name.
25 add_mapping %r%^lib\/.*\.rb% do |filename, _|
26 files_matching Regexp.new(["^#{model_test_for(filename)}$"])
27 end
28
29 # Any changes to a fixture will run corresponding view, controller and
30 # model tests
31 add_mapping %r%^#{fixtures_dir}/(.*)s.yml% do |_, m|
32 [
33 model_test_for(m[1]),
34 controller_test_for(m[1]),
35 view_test_for(m[1])
36 ]
37 end
38
39 # Any change to a test or test will cause it to be run
40 add_mapping %r%^test/(unit|models|integration|controllers|views|functional)/.*rb$% do |filename, _|
41 filename
42 end
43
44 # Any change to a model will cause it's corresponding test to be run
45 add_mapping %r%^app/models/(.*)\.rb$% do |_, m|
46 model_test_for(m[1])
47 end
48
49 # Any change to the global helper will result in all view and controller
50 # tests being run
51 add_mapping %r%^app/helpers/global_helpers.rb% do
52 files_matching %r%^test/(views|functional|controllers)/.*_test\.rb$%
53 end
54
55 # Any change to a helper will run it's corresponding view and controller
56 # tests, unless the helper is the global helper. Changes to the global
57 # helper run all view and controller tests.
58 add_mapping %r%^app/helpers/(.*)_helper(s)?.rb% do |_, m|
59 if m[1] == "global" then
60 files_matching %r%^test/(views|functional|controllers)/.*_test\.rb$%
61 else
62 [
63 view_test_for(m[1]),
64 controller_test_for(m[1])
65 ]
66 end
67 end
68
69 # Changes to views result in their corresponding view and controller test
70 # being run
71 add_mapping %r%^app/views/(.*)/% do |_, m|
72 [
73 view_test_for(m[1]),
74 controller_test_for(m[1])
75 ]
76 end
77
78 # Changes to a controller result in its corresponding test being run. If
79 # the controller is the exception or application controller, all
80 # controller tests are run.
81 add_mapping %r%^app/controllers/(.*)\.rb$% do |_, m|
82 if ["application", "exception"].include?(m[1])
83 files_matching %r%^test/(controllers|views|functional)/.*_test\.rb$%
84 else
85 controller_test_for(m[1])
86 end
87 end
88
89 # If a change is made to the router, run all controller and view tests
90 add_mapping %r%^config/router.rb$% do # FIX
91 files_matching %r%^test/(controllers|views|functional)/.*_test\.rb$%
92 end
93
94 # If any of the major files governing the environment are altered, run
95 # everything
96 add_mapping %r%^test/test_helper.rb|config/(init|rack|environments/test.rb|database.yml)% do # FIX
97 files_matching %r%^test/(unit|models|controllers|views|functional)/.*_test\.rb$%
98 end
99 end
100
101private
102
103 # Determines the paths we can expect tests or specs to reside, as well as
104 # corresponding fixtures.
105 def initialize_test_layout
106 self.model_tests_dir = "test/unit"
107 self.controller_tests_dir = "test/functional"
108 self.view_tests_dir = "test/views"
109 self.fixtures_dir = "test/fixtures"
110 end
111
112 # Given a filename and the test type, this method will return the
113 # corresponding test's or spec's name.
114 #
115 # ==== Arguments
116 # +filename+<String>:: the file name of the model, view, or controller
117 # +kind_of_test+<Symbol>:: the type of test we that we should run
118 #
119 # ==== Returns
120 # String:: the name of the corresponding test or spec
121 #
122 # ==== Example
123 #
124 # > test_for("user", :model)
125 # => "user_test.rb"
126 # > test_for("login", :controller)
127 # => "login_controller_test.rb"
128 # > test_for("form", :view)
129 # => "form_view_spec.rb" # If you're running a RSpec-like suite
130 def test_for(filename, kind_of_test) # :nodoc:
131 name = [filename]
132 name << kind_of_test.to_s if kind_of_test == :view
133 name << "test"
134 return name.join("_") + ".rb"
135 end
136
137 def model_test_for(filename)
138 [model_tests_dir, test_for(filename, :model)].join("/")
139 end
140
141 def controller_test_for(filename)
142 [controller_tests_dir, test_for(filename, :controller)].join("/")
143 end
144
145 def view_test_for(filename)
146 [view_tests_dir, test_for(filename, :view)].join("/")
147 end
148
149end
toggle raw diff

autotest/merb_rspec.rb

 
1# Adapted from Autotest::Rails, RSpec's autotest class, as well as merb-core's.
2require 'autotest'
3
4class RspecCommandError < StandardError; end
5
6class Autotest::MerbRspec < Autotest
7
8 # +model_tests_dir+:: the directory to find model-centric tests
9 # +controller_tests_dir+:: the directory to find controller-centric tests
10 # +view_tests_dir+:: the directory to find view-centric tests
11 # +fixtures_dir+:: the directory to find fixtures in
12 attr_accessor :model_tests_dir, :controller_tests_dir, :view_tests_dir, :fixtures_dir
13
14 def initialize # :nodoc:
15 super
16
17 initialize_test_layout
18
19 # Ignore any happenings in these directories
20 add_exception %r%^\./(?:doc|log|public|tmp)%
21
22 # Ignore any mappings that Autotest may have already set up
23 clear_mappings
24
25 # Any changes to a file in the root of the 'lib' directory will run any
26 # model test with a corresponding name.
27 add_mapping %r%^lib\/.*\.rb% do |filename, _|
28 files_matching %r%#{model_test_for(filename)}$%
29 end
30
31 add_mapping %r%^spec/(spec_helper|shared/.*)\.rb$% do
32 files_matching %r%^spec/.*_spec\.rb$%
33 end
34
35 # Any changes to a fixture will run corresponding view, controller and
36 # model tests
37 add_mapping %r%^#{fixtures_dir}/(.*)s.yml% do |_, m|
38 [
39 model_test_for(m[1]),
40 controller_test_for(m[1]),
41 view_test_for(m[1])
42 ]
43 end
44
45 # Any change to a test or spec will cause it to be run
46 add_mapping %r%^spec/(unit|models|integration|controllers|views|functional)/.*rb$% do |filename, _|
47 filename
48 end
49
50 # Any change to a model will cause it's corresponding test to be run
51 add_mapping %r%^app/models/(.*)\.rb$% do |_, m|
52 model_test_for(m[1])
53 end
54
55 # Any change to the global helper will result in all view and controller
56 # tests being run
57 add_mapping %r%^app/helpers/global_helpers.rb% do
58 files_matching %r%^spec/(views|functional|controllers)/.*_spec\.rb$%
59 end
60
61 # Any change to a helper will run it's corresponding view and controller
62 # tests, unless the helper is the global helper. Changes to the global
63 # helper run all view and controller tests.
64 add_mapping %r%^app/helpers/(.*)_helper(s)?.rb% do |_, m|
65 if m[1] == "global" then
66