git-commit-notifier 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|