There are many business requirements that we need to remember or ensure that gets done as developers which are not necessarily related to code or the behavior of the software. This could be code comments, copyright notices, or other information that are not necessarily executable, but part of the source code. For these types of requirements, we used rSpec to explicitly check whether the behavior-less requirement was met throughout our code base.
On one of the projects we have been working, our client has requested that we add a header with a copyright notice to the top of each file. The header was a few lines long, so we created a TextMate snippet to make it easy to generate when creating a new file. Unfortunately, this did not help us remember to actually add the header to each new file. After continually forgetting to add the header, we decided to create a spec which checks that all files have the appropriate header to help us remember.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
describe "copyright header" do
it "should be required on all ruby files" do
vendor = %w[ db/schema.rb lib/tasks/rspec.rake ... ]
(Dir["{app,lib,db,spec,features}/**/*.{rb,rake}"] - vendor).each do |filename|
filename.should have_ruby_copyright_header
end
end
it "should be required on all javascript files" do
vendor = %w[ public/javascripts/all.js public/javascripts/prototype.js ... ]
(Dir["public/javascripts/**/*.js"] - vendor).each do |filename|
filename.should have_javascript_copyright_header
end
end
it "should be required on all stylesheet files" do
vendor = %w[ public/stylesheets/all.css public/stylesheets/blueprint/screen.css ... ]
(Dir["public/stylesheets/**/*.css"] - vendor).each do |filename|
filename.should have_stylesheet_copyright_header
end
end
end |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
class CopyrightHeaderMatcher
def initialize(comment_line, comment_start = nil, comment_end = nil)
@header = <<-EOHEADER #{comment_start || comment_line} Copyright (c) 2008 Your Organization #{comment_line} #{comment_line} Possession of a copy of this file grants no permission or license #{comment_line} to use, modify, or create derivate works. #{comment_line} Please visit http://www.example.com/contact for further information. EOHEADER
@header << "#{comment_end}\n" if comment_end
end
def matches?(filename)
@filename = filename
File.read(filename).match(Regexp.new(Regexp.escape(@header))) ? true : false
end
def failure_message
"expected #{@filename} to have the header:\n#{@header}"
end
end
def have_ruby_copyright_header
CopyrightHeaderMatcher.new("#")
end
def have_javascript_copyright_header
CopyrightHeaderMatcher.new("//")
end
def have_stylesheet_copyright_header
CopyrightHeaderMatcher.new(" *", "/*", " */")
end |
Now when we forget to add the header, we get a nice reminder when running the specs.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
$ script/spec spec/code/header_spec.rb
F..
1)
'copyright header should be required on all ruby files' FAILED
expected app/models/user.rb to have the header:
# Copyright (c) 2008 Your Organization
#
# Possession of a copy of this file grants no permission or license
# to use, modify, or create derivate works.
# Please visit http://www.example.com/contact for further information.
Finished in 0.314035 seconds
3 examples, 1 failure |
Problem solved.