git-commit-notifier 0.8.0 → 0.8.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/LICENSE +1 -1
- data/README.textile +20 -5
- data/Rakefile +40 -20
- data/VERSION +1 -1
- data/bin/git-commit-notifier +8 -1
- data/config/git-notifier-config.yml.sample +41 -15
- data/git-commit-notifier.gemspec +50 -24
- data/lib/commit_hook.rb +104 -74
- data/lib/diff_to_html.rb +120 -52
- data/lib/emailer.rb +43 -22
- data/lib/git.rb +36 -26
- data/lib/logger.rb +48 -0
- data/lib/result_processor.rb +9 -5
- data/{test → spec}/fixtures/existing_file_one_line.txt +0 -0
- data/{test → spec}/fixtures/git-notifier-group-email-by-push.yml +2 -0
- data/{test → spec}/fixtures/git-notifier-ignore-merge.yml +0 -0
- data/{test → spec}/fixtures/git-notifier-with-merge.yml +0 -0
- data/{test → spec}/fixtures/git_log +0 -0
- data/{test → spec}/fixtures/git_show_055850e7d925110322b8db4e17c3b840d76e144c +0 -0
- data/{test → spec}/fixtures/git_show_51b986619d88f7ba98be7d271188785cbbb541a0 +0 -0
- data/{test → spec}/fixtures/git_show_a4629e707d80a5769f7a71ca6ed9471015e14dc9 +0 -0
- data/{test → spec}/fixtures/git_show_dce6ade4cdc2833b53bd600ef10f9bce83c7102d +0 -0
- data/{test → spec}/fixtures/git_show_e28ad77bba0574241e6eb64dfd0c1291b221effe +0 -0
- data/spec/fixtures/git_show_ff037a73fc1094455e7bbf506171a3f3cf873ae6 +18 -0
- data/{test → spec}/fixtures/new_file_one_line.txt +0 -0
- data/spec/lib/commit_hook_spec.rb +88 -0
- data/spec/lib/diff_to_html_spec.rb +168 -0
- data/spec/lib/emailer_spec.rb +102 -0
- data/spec/lib/git_spec.rb +93 -0
- data/spec/lib/logger_spec.rb +63 -0
- data/spec/lib/result_processor_spec.rb +102 -0
- data/{test/test_helper.rb → spec/spec_helper.rb} +14 -12
- data/template/email.html.erb +2 -2
- data/template/styles.css +2 -1
- metadata +110 -31
- data/test/unit/test_commit_hook.rb +0 -43
- data/test/unit/test_diff_to_html.rb +0 -160
- data/test/unit/test_result_processor.rb +0 -95
data/lib/logger.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
class Logger
|
4
|
+
DEFAULT_LOG_DIRECTORY = Dir.tmpdir.freeze
|
5
|
+
LOG_NAME = 'git-commit-notifier.log'.freeze
|
6
|
+
|
7
|
+
attr_reader :log_directory
|
8
|
+
|
9
|
+
def initialize(config)
|
10
|
+
@enabled = !!(config['debug'] && config['debug']['enabled'])
|
11
|
+
@log_directory = debug? ? (config['debug']['log_directory'] || DEFAULT_LOG_DIRECTORY) : nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def debug?
|
15
|
+
@enabled
|
16
|
+
end
|
17
|
+
|
18
|
+
def log_path
|
19
|
+
return nil unless debug?
|
20
|
+
File.join(log_directory, LOG_NAME)
|
21
|
+
end
|
22
|
+
|
23
|
+
def debug(msg)
|
24
|
+
return unless debug?
|
25
|
+
File.open(log_path, 'a') do |f|
|
26
|
+
f.puts msg
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def file(file_path)
|
31
|
+
return unless debug?
|
32
|
+
orig_dest_name = File.join(log_directory, File.basename(file_path))
|
33
|
+
dest_name = orig_dest_name
|
34
|
+
counter = 1
|
35
|
+
while File.exists?(dest_name)
|
36
|
+
counter += 1
|
37
|
+
dest_name = "#{orig_dest_name}.#{counter}"
|
38
|
+
end
|
39
|
+
debug("Save file #{file_path} for debugging purposes to #{dest_name}")
|
40
|
+
File.copy(file_path, dest_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
__END__
|
46
|
+
|
47
|
+
vim: tabstop=2:expandtab:shiftwidth=2
|
48
|
+
|
data/lib/result_processor.rb
CHANGED
@@ -12,6 +12,14 @@ class ResultProcessor
|
|
12
12
|
[array_of_lines(@result[:removal]), array_of_lines(@result[:addition])]
|
13
13
|
end
|
14
14
|
|
15
|
+
def length_in_chars(diff)
|
16
|
+
diff.inject(0) do |length, s|
|
17
|
+
token = s[:token]
|
18
|
+
token_length = token.respond_to?(:jlength) ? token.jlength : token.length
|
19
|
+
length + token_length
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
15
23
|
private
|
16
24
|
|
17
25
|
def initialize(diff)
|
@@ -46,15 +54,11 @@ class ResultProcessor
|
|
46
54
|
@diff.insert(position, { :action => :discard_b, :token => token} )
|
47
55
|
end
|
48
56
|
|
49
|
-
def length_in_chars(diff)
|
50
|
-
diff.inject(0) { |length, s| length + s[:token].size}
|
51
|
-
end
|
52
|
-
|
53
57
|
def filter_replaced_lines
|
54
58
|
# if a block is replaced by an other one, lcs-diff will find even the single common word between the old and the new content
|
55
59
|
# no need for intelligent diff in this case, simply show the removed and the added block with no highlighting
|
56
60
|
# rule: if less than 33% of a block is not a match, we don't need intelligent diff for that block
|
57
|
-
match_length = length_in_chars(@diff.select { |d| d[:action] == :match})
|
61
|
+
match_length = length_in_chars(@diff.select { |d| d[:action] == :match })
|
58
62
|
total_length = length_in_chars(@diff)
|
59
63
|
|
60
64
|
if total_length.to_f / match_length > 3.3
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
commit ff037a73fc1094455e7bbf506171a3f3cf873ae6
|
2
|
+
Author: Mokevnin Kirill <mokevnin@gmail.com>
|
3
|
+
Date: Tue Oct 26 15:31:13 2010 +0400
|
4
|
+
|
5
|
+
remove debug put
|
6
|
+
|
7
|
+
diff --git a/app/models/user.rb b/app/models/user.rb
|
8
|
+
index ac9399f..ea2e351 100644
|
9
|
+
--- a/app/models/user.rb
|
10
|
+
+++ b/app/models/user.rb
|
11
|
+
@@ -226,7 +226,6 @@ class User < ActiveRecord::Base
|
12
|
+
all_stats.keys.each do |type|
|
13
|
+
all_stats[type].each do |st|
|
14
|
+
stat_line = {type => st[:value]}
|
15
|
+
- puts "type #{type} st #{st}"
|
16
|
+
if results[st[:shift]]
|
17
|
+
results[st[:shift]].merge!(stat_line)
|
18
|
+
else
|
File without changes
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
require 'commit_hook'
|
3
|
+
|
4
|
+
describe CommitHook do
|
5
|
+
|
6
|
+
it "should ignore merge" do
|
7
|
+
# 4 commits, one email for each of them, without merge
|
8
|
+
run_with_config('spec/fixtures/git-notifier-ignore-merge.yml', 4)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should hook with merge" do
|
12
|
+
# 5 commits, one email for each of them, with merge mail
|
13
|
+
run_with_config('spec/fixtures/git-notifier-with-merge.yml', 5)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should hook group email by push" do
|
17
|
+
# 1 commit for the push, all commits in the one message
|
18
|
+
run_with_config('spec/fixtures/git-notifier-group-email-by-push.yml', 1)
|
19
|
+
end
|
20
|
+
|
21
|
+
def run_with_config(config, times)
|
22
|
+
expect_repository_access
|
23
|
+
|
24
|
+
emailer = mock!.send.times(times).subject
|
25
|
+
mock(Emailer).new(anything, anything) { emailer }.times(times)
|
26
|
+
|
27
|
+
mock(CommitHook).info(/Sending mail/)
|
28
|
+
|
29
|
+
any_instance_of(DiffToHtml, :check_handled_commits => lambda { |commits, branch| commits })
|
30
|
+
CommitHook.run config, REVISIONS.first, REVISIONS.last, 'refs/heads/master'
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_commit_from
|
34
|
+
# 1 commit with a from: adress
|
35
|
+
expect_repository_access
|
36
|
+
emailer = mock!.send.subject
|
37
|
+
mock(Emailer).new(anything, hash_including(:from_address => "max@example.com")) { emailer }
|
38
|
+
|
39
|
+
CommitHook.run 'spec/fixtures/git-notifier-group-email-by-push.yml', REVISIONS.first, REVISIONS.last, 'refs/heads/master'
|
40
|
+
end
|
41
|
+
|
42
|
+
def expect_repository_access
|
43
|
+
mock(Git).log(REVISIONS.first, REVISIONS.last) { IO.read(FIXTURES_PATH + 'git_log') }
|
44
|
+
mock(Git).mailing_list_address { 'recipient@test.com' }
|
45
|
+
REVISIONS.each do |rev|
|
46
|
+
mock(Git).show(rev) { IO.read(FIXTURES_PATH + "git_show_#{rev}") }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe :logger do
|
51
|
+
it "should be nstance of logger" do
|
52
|
+
stub(CommitHook).config { {} }
|
53
|
+
CommitHook.logger.should be_kind_of(Logger)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe :show_error do
|
58
|
+
it "should write error to stderr" do
|
59
|
+
mock($stderr).puts("\n").times(2)
|
60
|
+
mock($stderr).puts(/GIT\sNOTIFIER\sPROBLEM/).times(2)
|
61
|
+
mock($stderr).puts('yes')
|
62
|
+
CommitHook.show_error('yes')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe :info do
|
67
|
+
it "should write to and flush stdout" do
|
68
|
+
mock($stdout).puts('msg')
|
69
|
+
mock($stdout).flush
|
70
|
+
CommitHook.info('msg')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe :run do
|
75
|
+
it "should report error when no recipients specified" do
|
76
|
+
mock(File).exists?(:noconfig) { false }
|
77
|
+
mock(Git).mailing_list_address { nil }
|
78
|
+
mock(CommitHook).show_error(/recipient/)
|
79
|
+
CommitHook.run(:noconfig, :rev1, :rev2, 'master')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
__END__
|
86
|
+
|
87
|
+
vim: tabstop=2 expandtab shiftwidth=2
|
88
|
+
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
require 'diff_to_html'
|
3
|
+
require 'git'
|
4
|
+
require 'hpricot'
|
5
|
+
|
6
|
+
describe DiffToHtml do
|
7
|
+
|
8
|
+
|
9
|
+
describe :lines_are_sequential? do
|
10
|
+
before(:all) do
|
11
|
+
@diff_to_html = DiffToHtml.new
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should be true if left line numbers are sequential" do
|
15
|
+
@diff_to_html.lines_are_sequential?({
|
16
|
+
:added => 2,
|
17
|
+
:removed => 2
|
18
|
+
}, {
|
19
|
+
:added => 3,
|
20
|
+
:removed => 6
|
21
|
+
}).should be_true
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be true if right line numbers are sequential" do
|
25
|
+
@diff_to_html.lines_are_sequential?({
|
26
|
+
:added => 2,
|
27
|
+
:removed => 2
|
28
|
+
}, {
|
29
|
+
:added => 7,
|
30
|
+
:removed => 3
|
31
|
+
}).should be_true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should be false unless line numbers are sequential" do
|
35
|
+
@diff_to_html.lines_are_sequential?({
|
36
|
+
:added => 2,
|
37
|
+
:removed => 2
|
38
|
+
}, {
|
39
|
+
:added => 4,
|
40
|
+
:removed => 6
|
41
|
+
}).should be_false
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should be true if left line numbers are sequential (right are nil)" do
|
45
|
+
@diff_to_html.lines_are_sequential?({
|
46
|
+
:added => 2,
|
47
|
+
:removed => 2
|
48
|
+
}, {
|
49
|
+
:added => 3,
|
50
|
+
:removed => nil
|
51
|
+
}).should be_true
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should be true if right line numbers are sequential (left are nil)" do
|
55
|
+
@diff_to_html.lines_are_sequential?({
|
56
|
+
:added => nil,
|
57
|
+
:removed => 2
|
58
|
+
}, {
|
59
|
+
:added => 7,
|
60
|
+
:removed => 3
|
61
|
+
}).should be_true
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should be false unless line numbers are sequential (nils)" do
|
65
|
+
@diff_to_html.lines_are_sequential?({
|
66
|
+
:added => nil,
|
67
|
+
:removed => nil
|
68
|
+
}, {
|
69
|
+
:added => 4,
|
70
|
+
:removed => 6
|
71
|
+
}).should be_false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe :unique_commits_per_branch? do
|
76
|
+
it "should be false unless specified in config" do
|
77
|
+
diff = DiffToHtml.new(nil, {})
|
78
|
+
diff.should_not be_unique_commits_per_branch
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should be false if specified as false in config" do
|
82
|
+
diff = DiffToHtml.new(nil, { 'unique_commits_per_branch' => false })
|
83
|
+
diff.should_not be_unique_commits_per_branch
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should be true if specified as true in config" do
|
87
|
+
diff = DiffToHtml.new(nil, { 'unique_commits_per_branch' => true })
|
88
|
+
diff.should be_unique_commits_per_branch
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe :get_previous_commits do
|
93
|
+
it "should read and parse previous file if it exists" do
|
94
|
+
fn = DiffToHtml::HANDLED_COMMITS_FILE
|
95
|
+
diff = DiffToHtml.new
|
96
|
+
mock(File).exists?(fn) { true }
|
97
|
+
mock(IO).read(fn) { "a\nb" }
|
98
|
+
diff.get_previous_commits(fn).should == %w[a b]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "multiple commits" do
|
103
|
+
mock(Git).log(REVISIONS.first, REVISIONS.last) { IO.read(FIXTURES_PATH + 'git_log') }
|
104
|
+
REVISIONS.each do |rev|
|
105
|
+
mock(Git).show(rev) { IO.read(FIXTURES_PATH + 'git_show_' + rev) }
|
106
|
+
end
|
107
|
+
|
108
|
+
diff = DiffToHtml.new
|
109
|
+
mock(diff).check_handled_commits(anything, 'master') { |commits, branch| commits }
|
110
|
+
diff.diff_between_revisions REVISIONS.first, REVISIONS.last, 'testproject', 'master'
|
111
|
+
|
112
|
+
diff.result.should have(5).commits # one result for each of the commits
|
113
|
+
|
114
|
+
diff.result.each do |html|
|
115
|
+
html.should_not be_include('@@') # diff correctly processed
|
116
|
+
end
|
117
|
+
|
118
|
+
# first commit
|
119
|
+
hp = Hpricot diff.result.first[:html_content]
|
120
|
+
(hp/"table").should have(2).tables # 2 files updated - one table for each of the files
|
121
|
+
(hp/"table/tr/").each do |td|
|
122
|
+
if td.inner_html == "require 'iconv'"
|
123
|
+
# first added line in changeset a4629e707d80a5769f7a71ca6ed9471015e14dc9
|
124
|
+
td.parent.search('td')[0].inner_text.should == '' # left
|
125
|
+
td.parent.search('td')[1].inner_text.should == '2' # right
|
126
|
+
td.parent.search('td')[2].inner_html.should == "require 'iconv'" # change
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# second commit
|
131
|
+
hp = Hpricot diff.result[1][:html_content]
|
132
|
+
(hp/"table").should have(1).table # 1 file updated
|
133
|
+
|
134
|
+
# third commit - dce6ade4cdc2833b53bd600ef10f9bce83c7102d
|
135
|
+
hp = Hpricot diff.result[2][:html_content]
|
136
|
+
(hp/"table").should have(6).tables # 6 files updated
|
137
|
+
(hp/"h2")[1].inner_text.should == 'Added binary file railties/doc/guides/source/images/icons/callouts/11.png'
|
138
|
+
(hp/"h2")[2].inner_text.should == 'Deleted binary file railties/doc/guides/source/icons/up.png'
|
139
|
+
(hp/"h2")[3].inner_text.should == 'Deleted file railties/doc/guides/source/icons/README'
|
140
|
+
(hp/"h2")[4].inner_text.should == 'Added file railties/doc/guides/source/images/icons/README'
|
141
|
+
|
142
|
+
# fourth commit - 51b986619d88f7ba98be7d271188785cbbb541a0
|
143
|
+
hp = Hpricot diff.result[3][:html_content]
|
144
|
+
(hp/"table").should have(3).tables # 3 files updated
|
145
|
+
(hp/"table/tr/").each do |td|
|
146
|
+
if td.inner_html =~ /create_btn/
|
147
|
+
cols = td.parent.search('td')
|
148
|
+
['405', '408', ''].should be_include(cols[0].inner_text) # line 405 changed
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should get good diff when new branch created" do
|
154
|
+
first_rev, last_rev = %w[ 0000000000000000000000000000000000000000 9b15cebcc5434e27c00a4a2acea43509f9faea21 ]
|
155
|
+
mock(Git).branch_commits('rvm') { %w[ ff037a73fc1094455e7bbf506171a3f3cf873ae6 ] }
|
156
|
+
%w[ ff037a73fc1094455e7bbf506171a3f3cf873ae6 ].each do |rev|
|
157
|
+
mock(Git).show(rev) { IO.read(FIXTURES_PATH + 'git_show_' + rev) }
|
158
|
+
end
|
159
|
+
diff = DiffToHtml.new
|
160
|
+
mock(diff).check_handled_commits(anything, 'rvm') { |commits, branch| commits }
|
161
|
+
diff.diff_between_revisions(first_rev, last_rev, 'tm-admin', 'rvm')
|
162
|
+
diff.result.should have(1).commit
|
163
|
+
hp = Hpricot diff.result.first[:html_content]
|
164
|
+
(hp/"table").should have(1).table
|
165
|
+
(hp/"tr.r").should have(1).row
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
require 'emailer'
|
5
|
+
|
6
|
+
describe Emailer do
|
7
|
+
|
8
|
+
describe :new do
|
9
|
+
it "should assign config if given" do
|
10
|
+
Emailer.new({:a => :b}).config[:a].should == :b
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should use empty hash unless config given" do
|
14
|
+
cfg = Emailer.new(false).config
|
15
|
+
cfg.should be_kind_of(Hash)
|
16
|
+
cfg.should be_empty
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should not generate message from template" do
|
20
|
+
any_instance_of(Emailer) do |emailer|
|
21
|
+
dont_allow(emailer).generate_message
|
22
|
+
end
|
23
|
+
Emailer.new({})
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should assign parameters from options" do
|
27
|
+
options = {}
|
28
|
+
Emailer::PARAMETERS.each do |name|
|
29
|
+
options[name.to_sym] = Faker::Lorem.sentence
|
30
|
+
end
|
31
|
+
emailer = Emailer.new({}, options)
|
32
|
+
options.each_pair do |key, value|
|
33
|
+
emailer.instance_variable_get("@#{key}").should == value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe :stylesheet_string do
|
39
|
+
it "should return default stylesheet if custom is not provided" do
|
40
|
+
emailer = Emailer.new({})
|
41
|
+
mock(IO).read(Emailer::DEFAULT_STYLESHEET_PATH) { 'ok' }
|
42
|
+
emailer.stylesheet_string.should == 'ok'
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return custom stylesheet if custom is provided" do
|
46
|
+
emailer = Emailer.new({'stylesheet' => '/path/to/custom/stylesheet'})
|
47
|
+
mock(IO).read('/path/to/custom/stylesheet') { 'ok' }
|
48
|
+
dont_allow(IO).read(Emailer::DEFAULT_STYLESHEET_PATH)
|
49
|
+
emailer.stylesheet_string.should == 'ok'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe :generate_message do
|
54
|
+
it "should generate html" do
|
55
|
+
options = {}
|
56
|
+
Emailer::PARAMETERS.each do |name|
|
57
|
+
options[name.to_sym] = Faker::Lorem.sentence
|
58
|
+
end
|
59
|
+
emailer = Emailer.new({}, options)
|
60
|
+
emailer.generate_message
|
61
|
+
emailer.instance_variable_get(:@html).should match(/html/)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe :template do
|
66
|
+
before(:each) do
|
67
|
+
Emailer.reset_template
|
68
|
+
mock(IO).read(Emailer::TEMPLATE) { 'erb' }
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should respond to result" do
|
72
|
+
Emailer.template.should respond_to(:result)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should return Erubis template if Erubis installed" do
|
76
|
+
mock(Emailer).require('erubis')
|
77
|
+
dont_allow(Emailer).require('erb')
|
78
|
+
unless defined?(Erubis)
|
79
|
+
module Erubis
|
80
|
+
class Eruby
|
81
|
+
def initialize(erb)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
mock.proxy(Erubis::Eruby).new('erb')
|
87
|
+
Emailer.template.should be_kind_of(Erubis::Eruby)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should return ERB template unless Erubis installed" do
|
91
|
+
mock(Emailer).require('erubis') { raise LoadError.new('erubis') }
|
92
|
+
mock(Emailer).require('erb')
|
93
|
+
mock.proxy(ERB).new('erb')
|
94
|
+
Emailer.template.should be_kind_of(ERB)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
__END__
|
100
|
+
|
101
|
+
vim: tabstop=2 expandtab shiftwidth=2
|
102
|
+
|