devver-germinate 1.1.0 → 1.2.0

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.
Files changed (57) hide show
  1. data/History.txt +12 -0
  2. data/README.rdoc +26 -4
  3. data/TODO +80 -8
  4. data/bin/germ +162 -38
  5. data/examples/basic.rb +14 -9
  6. data/examples/short.rb +2 -0
  7. data/features/author-formats-article.feature +3 -3
  8. data/features/{author-lists-info.feature → author-lists-info.pending_feature} +3 -0
  9. data/features/author-publishes-article.feature +52 -0
  10. data/features/author-selects-hunks.feature +1 -1
  11. data/features/author-sets-variables.feature +88 -0
  12. data/features/{author-views-stuff.feature → author-views-stuff.pending_feature} +4 -0
  13. data/features/example_articles/escaping.txt +1 -0
  14. data/features/example_articles/specials.rb +3 -3
  15. data/features/example_output/specials.txt +9 -5
  16. data/features/step_definitions/germinate.rb +9 -0
  17. data/germinate.gemspec +3 -3
  18. data/lib/germinate.rb +1 -1
  19. data/lib/germinate/application.rb +82 -31
  20. data/lib/germinate/hunk.rb +20 -0
  21. data/lib/germinate/insertion.rb +10 -2
  22. data/lib/germinate/librarian.rb +129 -31
  23. data/lib/germinate/origin.rb +5 -0
  24. data/lib/germinate/pipeline.rb +2 -0
  25. data/lib/germinate/publisher.rb +57 -0
  26. data/lib/germinate/reader.rb +51 -8
  27. data/lib/germinate/selector.rb +18 -6
  28. data/lib/germinate/shared_style_attributes.rb +18 -1
  29. data/lib/germinate/{process.rb → shell_process.rb} +27 -8
  30. data/lib/germinate/shell_publisher.rb +19 -0
  31. data/lib/germinate/simple_publisher.rb +7 -0
  32. data/lib/germinate/source_file.rb +41 -0
  33. data/lib/germinate/text_transforms.rb +38 -9
  34. data/lib/germinate/transform_process.rb +25 -0
  35. data/lib/germinate/variable.rb +23 -0
  36. data/sample.rb +14 -0
  37. data/spec/germinate/application_spec.rb +18 -1
  38. data/spec/germinate/article_editor_spec.rb +3 -3
  39. data/spec/germinate/code_hunk_spec.rb +28 -0
  40. data/spec/germinate/file_hunk_spec.rb +1 -0
  41. data/spec/germinate/hunk_spec.rb +1 -0
  42. data/spec/germinate/insertion_spec.rb +2 -1
  43. data/spec/germinate/librarian_spec.rb +280 -85
  44. data/spec/germinate/pipeline_spec.rb +10 -0
  45. data/spec/germinate/process_spec.rb +31 -6
  46. data/spec/germinate/publisher_spec.rb +130 -0
  47. data/spec/germinate/reader_spec.rb +58 -2
  48. data/spec/germinate/selector_spec.rb +34 -14
  49. data/spec/germinate/shell_publisher_spec.rb +61 -0
  50. data/spec/germinate/source_file_spec.rb +99 -0
  51. data/spec/germinate/text_hunk_spec.rb +45 -0
  52. data/spec/germinate/text_transforms_spec.rb +90 -2
  53. data/spec/germinate/transform_process_spec.rb +50 -0
  54. data/spec/germinate/variable_spec.rb +14 -0
  55. metadata +19 -7
  56. data/lib/germinate/article_formatter.rb +0 -75
  57. data/spec/germinate/article_formatter_spec.rb +0 -153
@@ -21,4 +21,14 @@ module Germinate
21
21
  @it.call(@input).should == @output3
22
22
  end
23
23
  end
24
+
25
+ describe Pipeline, "given no processes" do
26
+ before :each do
27
+ @it = Pipeline.new([])
28
+ end
29
+
30
+ it "should pass input through unchanged" do
31
+ @it.call(["foo", "bar"]).should == ["foo", "bar"]
32
+ end
33
+ end
24
34
  end
@@ -2,21 +2,46 @@ require File.expand_path(
2
2
  File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
3
 
4
4
  module Germinate
5
- describe Process do
5
+ describe ShellProcess do
6
6
  before :each do
7
7
  @input = Germinate::Hunk.new(
8
8
  ["line 1\n", "line 2\n"],
9
9
  :comment_prefix => "//")
10
10
  @output = ["1 enil\n", "2 enil\n"]
11
11
  @command = stub("Command", :readlines => @output).as_null_object
12
+ @tempfile = stub("Temp File", :path => "TEMP_PATH").as_null_object
13
+ @status = stub("Child Status", :success => true)
12
14
  IO.stub!(:popen).and_yield(@command)
15
+ Tempfile.stub!(:open).and_yield(@tempfile)
16
+ end
17
+
18
+ context "given a command and some variables" do
19
+ before :each do
20
+ @it = Germinate::ShellProcess.new(
21
+ "myproc", "mycommand", { "FOO" => 123, "BAR" => 456 })
22
+ ENV["FOO"] = "xxx"
23
+ end
24
+
25
+ it "should set the variables in the environment before execution" do
26
+ IO.should_receive(:popen) do
27
+ ENV["FOO"].should == "123"
28
+ ENV["BAR"].should == "456"
29
+ end
30
+ @it.call(@input)
31
+ end
32
+
33
+ it "should reset the environment after execution" do
34
+ @it.call(@input)
35
+ ENV["FOO"].should == "xxx"
36
+ ENV["BAR"].should be_nil
37
+ end
13
38
  end
14
39
 
15
40
  context "given a command 'mycommand'" do
16
41
  before :each do
17
- @it = Germinate::Process.new("myproc", "mycommand")
42
+ @it = Germinate::ShellProcess.new("myproc", "mycommand")
18
43
  end
19
-
44
+
20
45
  context "when called on a hunk of text" do
21
46
  it "should pipe the input through the command" do
22
47
  @command.should_receive(:<<).with("line 1\n").ordered
@@ -33,16 +58,16 @@ module Germinate
33
58
  output = @it.call(@input)
34
59
  output.comment_prefix.should == "//"
35
60
  end
61
+
36
62
  end
37
63
  end
38
64
 
39
65
  context "given a command 'mycommand %f' and called on some text" do
40
66
  before :each do
41
- @it = Germinate::Process.new("myproc", "mycommand %f")
67
+ @it = Germinate::ShellProcess.new("myproc", "mycommand %f")
42
68
  end
43
69
 
44
70
  it "should create a temporary file and pass the name to the command" do
45
- @tempfile = stub("Temp File", :path => "TEMP_PATH")
46
71
  Tempfile.should_receive(:open).with("germinate_hunk").and_yield(@tempfile)
47
72
  @tempfile.should_receive(:<<).with("line 1\n").ordered
48
73
  @tempfile.should_receive(:<<).with("line 2\n").ordered
@@ -66,7 +91,7 @@ module Germinate
66
91
  @input = Germinate::FileHunk.new(
67
92
  ["line 1\n", "line 2\n"],
68
93
  {:source_path => "SOURCE_PATH"})
69
- @it = Germinate::Process.new("myproc", "mycommand %f")
94
+ @it = Germinate::ShellProcess.new("myproc", "mycommand %f")
70
95
  end
71
96
 
72
97
  it "should pass the source file path to the command" do
@@ -0,0 +1,130 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe Publisher do
6
+ before :each do
7
+ @name = "my_pub"
8
+ @hunk = stub("Input Hunk")
9
+ @output = stub("Pipeline Output")
10
+ @pipeline = stub("Pipeline", :call => @output)
11
+ @librarian = stub("Librarian",
12
+ :make_pipeline => @pipeline,
13
+ :[] => @hunk ).as_null_object
14
+ @options = {:a => 'b'}
15
+ end
16
+
17
+ context "when a new publisher type 'foo' is defined" do
18
+ before :each do
19
+ @it = Germinate::Publisher
20
+ @subclass = Class.new(Publisher) do
21
+ identifier "foo"
22
+ end
23
+ end
24
+
25
+ it "should be able to make 'foo' publishers" do
26
+ @publisher = stub("Publisher")
27
+ @subclass.should_receive(:new).with(@name, @librarian, @options).
28
+ and_return(@publisher)
29
+
30
+ @it.make(@name, "foo", @librarian, @options)
31
+ end
32
+
33
+ end
34
+
35
+ context "when an anonymous publisher subclass is defined" do
36
+ before :each do
37
+ @it = Germinate::Publisher
38
+ @subclass = Class.new(Publisher) do
39
+ self.identifier = nil
40
+ end
41
+ end
42
+
43
+ it "should not make the publisher available as an instantiable type" do
44
+ @librarian = stub("Librarian")
45
+ @options = {:a => 'b'}
46
+ @publisher = stub("Publisher")
47
+
48
+ lambda do
49
+ @it.make("mypub", nil, @librarian, @options)
50
+ end.should raise_error(IndexError)
51
+ end
52
+
53
+ end
54
+
55
+ context "given name, librarian, and options" do
56
+ before :each do
57
+ @name = "frank"
58
+ @librarian = stub("Librarian").as_null_object
59
+ @options = {:foo => "bar"}
60
+ @it = Publisher.new(@name, @librarian, @options)
61
+ end
62
+
63
+ it "should know its name" do
64
+ @it.name.should == @name
65
+ end
66
+
67
+ it "should know its librarian" do
68
+ @it.librarian.should == @librarian
69
+ end
70
+
71
+ it "should know its options" do
72
+ @it.options.should == @options
73
+ end
74
+ end
75
+
76
+ context "given a pipeline option" do
77
+ before :each do
78
+ @name = "frank"
79
+ @librarian = stub("Librarian").as_null_object
80
+ @options = {:pipeline => "foo|bar"}
81
+ end
82
+
83
+ it "should have a pipeline" do
84
+ @it = Publisher.new(@name, @librarian, @options)
85
+ @it.pipeline.should_not be_nil
86
+ end
87
+
88
+ it "should use the librarian to construct a pipeline" do
89
+ @librarian.should_receive(:make_pipeline).with("foo|bar")
90
+ @it = Publisher.new(@name, @librarian, @options)
91
+ end
92
+ end
93
+
94
+ context "with no selector specified" do
95
+ before :each do
96
+ @it = Publisher.new(@name, @librarian, @options)
97
+ end
98
+
99
+ it "should select $TEXT|_transform" do
100
+ @it.selector.should == "$TEXT|_transform"
101
+ end
102
+
103
+ end
104
+
105
+ context "with a custom selector specified" do
106
+ before :each do
107
+ @it = Publisher.new(@name, @librarian, { :selector => "@sec1|myproc" })
108
+ end
109
+
110
+ it "should have the specified selector" do
111
+ @it.selector.should == "@sec1|myproc"
112
+ end
113
+
114
+ it "should use the selector to get a hunk to process" do
115
+ @librarian.should_receive(:[]).
116
+ with("@sec1|myproc", anything)
117
+ @it.input
118
+ end
119
+
120
+ it "should pass the selected hunk through the pipeline to get input" do
121
+ @pipeline.should_receive(:call).with(@hunk)
122
+ @it.input
123
+ end
124
+
125
+ it "should use pipeline output as input to publisher process" do
126
+ @it.input.should == @output
127
+ end
128
+ end
129
+ end
130
+ end
@@ -45,8 +45,8 @@ module Germinate
45
45
  CONTROL_LINES = [
46
46
  # Line Comment Args
47
47
  [":TEXT:\n", nil, []],
48
- ["# :CUT: \n", "#", []],
49
- [" ; :TEXT: foo\n", ";", ["foo"]],
48
+ ["# :CUT: \n", "# ", []],
49
+ [" ; :TEXT: foo\n", " ; ", ["foo"]],
50
50
  ["//:SAMPLE:\n", "//", []],
51
51
  ["$>:END: ", "$>", []],
52
52
  [":SAMPLE: bar, { a: 1, b: 2 }", nil, ["bar", {"a"=>1, "b"=>2}]],
@@ -225,6 +225,19 @@ module Germinate
225
225
  end
226
226
  end
227
227
 
228
+ context "given a :SAMPLE: after a TEXT section with the same name" do
229
+ before :each do
230
+ @it << ":TEXT: foobar\n"
231
+ @it << "This is the text\n"
232
+ end
233
+
234
+ it "should add an implicit insertion to the TEXT section" do
235
+ @librarian.should_receive(:add_insertion!).with("foobar", "@foobar", {})
236
+ @it << ":SAMPLE: foobar\n"
237
+ end
238
+
239
+ end
240
+
228
241
  context "given a :SAMPLE: keyword with custom brackets" do
229
242
  before :each do
230
243
  @line = ':SAMPLE: foobar, { brackets: ["<<", ">>"] }'
@@ -314,6 +327,25 @@ module Germinate
314
327
 
315
328
  end
316
329
 
330
+ context "given an insertion with the special disable_transforms attr" do
331
+ before :each do
332
+ @it << ":TEXT: mysection"
333
+ @line = ":INSERT: foo, { disable_transforms: true } "
334
+ end
335
+
336
+ it "should disable all transforms in the options" do
337
+ @librarian.should_receive(:add_insertion!) do
338
+ |section, selector, options|
339
+
340
+ TextTransforms.singleton_methods.each do |transform|
341
+ options[transform.to_sym].should be_false
342
+ end
343
+ end
344
+ @it << @line
345
+ end
346
+
347
+ end
348
+
317
349
  context "given a process directive" do
318
350
  before :each do
319
351
  @line = ' # :PROCESS: sortail, "sort | tail"'
@@ -325,5 +357,29 @@ module Germinate
325
357
  end
326
358
  end
327
359
 
360
+ context "given a publisher directive" do
361
+ before :each do
362
+ @line = ' # :PUBLISHER: source, shell, { command: "cat %f" }'
363
+ end
364
+
365
+ it "should add the publisher to the librarian" do
366
+ @librarian.should_receive(:add_publisher!).
367
+ with("source", "shell", { :command => "cat %f" })
368
+ @it << @line
369
+ end
370
+ end
371
+
372
+ context "given a set directive" do
373
+ before :each do
374
+ @line = ' # :SET: name, value'
375
+ end
376
+
377
+ it "should set a variable on the librarian" do
378
+ @librarian.should_receive(:set_variable!).
379
+ with(@line, 1, "name", "value")
380
+ @it << @line
381
+ end
382
+ end
383
+
328
384
  end
329
385
  end
@@ -3,6 +3,11 @@ require File.expand_path(
3
3
 
4
4
  module Germinate
5
5
  describe Selector do
6
+
7
+ it "should be comparable to a string" do
8
+ Selector.new("@A:1..5").should be == "@A:1..5"
9
+ Selector.new("@A:1..5").should_not be == "@A:1..6"
10
+ end
6
11
 
7
12
  context "given a subscript" do
8
13
  before :each do
@@ -31,21 +36,36 @@ module Germinate
31
36
  specify { @it.should be_whole }
32
37
  end
33
38
 
39
+ context "given no type sigil or key" do
40
+ before :each do
41
+ @it = Selector.new(":2..5")
42
+ end
43
+
44
+ it "should have type code" do
45
+ @it.selector_type.should == :special
46
+ end
47
+
48
+ it "should have key SOURCE" do
49
+ @it.key.should == "SOURCE"
50
+ end
51
+ end
52
+
34
53
  EXAMPLE_SELECTORS = [
35
- # selector type key delim start end length pipeline excerpt_output?
36
- [ "@A", :code, "A", '..', 1, -1, nil, [] ,false],
37
- [ "@A:1", :code, "A", nil, 1, 1, nil, [] ,false],
38
- [ "", :code, "DEFAULT", '..', 1, -1, nil, [] ,false],
39
- [ nil, :code, "DEFAULT", '..', 1, -1, nil, [] ,false],
40
- [ ":2..4", :code, "DEFAULT", '..', 2, 4, nil, [] ,false],
41
- [ ":2...4", :code, "DEFAULT", '...', 2, 4, nil, [] ,false],
42
- [ "@B:2,5", :code, "B", ',', 2, nil,5, [] ,false],
43
- [ "@B:/z/,6", :code, "B", ',', /z/, nil,6, [] ,false],
44
- [ "@_:/z/../x/", :code, "_", '..', /z/, /x/,nil, [] ,false],
45
- [ "@B:2,4|fnord",:code, "B", ',', 2, nil,4, ["fnord"],false],
46
- [ "$FOO", :special, "FOO", '..', 1, -1, nil, [] ,false],
47
- [ "@A|foo|bar", :code, "A", '..', 1, -1, nil, ["foo", "bar"],false],
48
- [ "@B|fnord:2,4",:code, "B", ',', 2, nil,4, ["fnord"],true],
54
+ # selector type key delim start end length pipeline excerpt_output?
55
+ [ "@A", :code, "A", '..', 1, -1, nil, %w[_transform] ,false],
56
+ [ "@A:1", :code, "A", nil, 1, 1, nil, %w[_transform] ,false],
57
+ [ "", :code, "DEFAULT", '..', 1, -1, nil, %w[_transform] ,false],
58
+ [ nil, :code, "DEFAULT", '..', 1, -1, nil, %w[_transform] ,false],
59
+ [ ":2..4", :code, "DEFAULT", '..', 2, 4, nil, %w[_transform] ,false],
60
+ [ ":2...4", :code, "DEFAULT", '...', 2, 4, nil, %w[_transform] ,false],
61
+ [ "@B:2,5", :code, "B", ',', 2, nil,5, %w[_transform] ,false],
62
+ [ "@B:/z/,6", :code, "B", ',', /z/, nil,6, %w[_transform] ,false],
63
+ [ "@_:/z/../x/", :code, "_", '..', /z/, /x/,nil, %w[_transform] ,false],
64
+ [ "@B:2,4|fnord",:code, "B", ',', 2, nil,4, %w[_transform fnord] ,false],
65
+ [ "$FOO", :special, "FOO", '..', 1, -1, nil, %w[_transform] ,false],
66
+ [ "@A|foo|bar", :code, "A", '..', 1, -1, nil, %w[_transform foo bar],false],
67
+ [ "@B|fnord:2,4",:code, "B", ',', 2, nil,4, %w[_transform fnord],true],
68
+ [ "@B|_transform",:code, "B", '..', 1, -1, nil, %w[_transform], false]
49
69
  ]
50
70
 
51
71
  EXAMPLE_SELECTORS.each do |selector_attributes|
@@ -0,0 +1,61 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe ShellPublisher do
6
+ before :each do
7
+ @name = "frank"
8
+ @pipeline_output = ["* line 1\n", "* line 2\n"]
9
+ @pipeline = stub("Pipeline", :call => @pipeline_output)
10
+ @variables = stub("Variables")
11
+ @librarian = stub("Librarian",
12
+ :make_pipeline => @pipeline,
13
+ :variables => @variables)
14
+ @command = "cat %f"
15
+ @options = {:command => @command}
16
+ @it = ShellPublisher.new(@name, @librarian, @options)
17
+ end
18
+
19
+ it "should have identifier 'shell'" do
20
+ ShellPublisher.identifier.should == "shell"
21
+ end
22
+
23
+ context "on publish" do
24
+ before :each do
25
+ @result = ["line 1\n", "line 2\n"]
26
+ @output = StringIO.new
27
+ @process = stub("ShellProcess", :call => @result).as_null_object
28
+ @source = stub("Source").as_null_object
29
+ @librarian.stub!(:[]).and_return(@source)
30
+ ShellProcess.stub!(:new).and_return(@process)
31
+ end
32
+
33
+ it "should create a new process" do
34
+ ShellProcess.should_receive(:new).with(@name, @command, @variables)
35
+ @it.publish!(@output)
36
+ end
37
+
38
+ it "should execute the created process" do
39
+ @process.should_receive(:call).with(anything).and_return(@result)
40
+ @it.publish!(@output)
41
+ end
42
+
43
+ it "should pass the pipeline output to the created process" do
44
+ @process.should_receive(:call).with(@pipeline_output).and_return(@result)
45
+ @it.publish!(@output)
46
+ end
47
+
48
+ it "should ask the librarian for the source file" do
49
+ @librarian.should_receive(:[]).with("$TEXT|_transform", anything)
50
+ @it.publish!(@output)
51
+ end
52
+
53
+ it "should write process output to given output stream" do
54
+ @it.publish!(@output)
55
+ @output.rewind
56
+ @output.read.should == "line 1\nline 2\n"
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,99 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe SourceFile do
6
+ before :each do
7
+ @it = SourceFile.new("DIR/SOURCE_PATH.EXT")
8
+ @file = stub("File", :flock => 0)
9
+ @lines = ["Line 1\n", "Line 2\n"]
10
+ File.stub!(:new).and_return(@file)
11
+ FileUtils.stub!(:cp)
12
+ end
13
+
14
+ it "should have a source path" do
15
+ @it.path.to_s.should == "DIR/SOURCE_PATH.EXT"
16
+ end
17
+
18
+ it "should append .germ.back for the backup path" do
19
+ @it.backup_path.to_s.should == "DIR/SOURCE_PATH.EXT.germ.bak"
20
+ end
21
+
22
+ context "when writing" do
23
+ before :each do
24
+ @open_file = stub("Open File", :write => nil)
25
+ @path = stub("Source Path", :read => "...")
26
+ @path.stub!(:open).and_yield(@open_file)
27
+ @backup_path = stub("BACKUP_PATH", :read => "...")
28
+ @it.backup_path = @backup_path
29
+ @it.path = @path
30
+ end
31
+
32
+ it "should lock and unlock the source path" do
33
+ File.should_receive(:new).with(@it.path).and_return(@file)
34
+ @file.should_receive(:flock).with(File::LOCK_EX).ordered.and_return(0)
35
+ @file.should_receive(:flock).with(File::LOCK_UN).ordered
36
+ @it.write!(@lines)
37
+ end
38
+
39
+ it "should raise error if locking fails" do
40
+ @file.should_receive(:flock).with(File::LOCK_EX).ordered.and_return(1)
41
+ @file.should_receive(:flock).with(File::LOCK_UN).ordered
42
+
43
+ lambda do
44
+ @it.write!(@lines)
45
+ end.should raise_error(RuntimeError)
46
+ end
47
+
48
+ it "should make a backup copy after locking the file" do
49
+ @file.should_receive(:flock).with(File::LOCK_EX).ordered.and_return(0)
50
+ FileUtils.should_receive(:cp).with(@it.path, @backup_path).ordered
51
+ @it.write!(@lines)
52
+ end
53
+
54
+ it "should make no backup if locking fails" do
55
+ @file.should_receive(:flock).with(File::LOCK_EX).ordered.and_return(1)
56
+ FileUtils.should_not_receive(:cp)
57
+ @it.write!(@lines) rescue nil
58
+ end
59
+
60
+ it "should unlock the file if backup fails" do
61
+ FileUtils.should_receive(:cp).and_raise("Some Error")
62
+ @file.should_receive(:flock).with(File::LOCK_UN)
63
+ @it.write!(@lines) rescue nil
64
+ end
65
+
66
+ it "should raise error if source file and backup are not equal" do
67
+ @path.should_receive(:read).and_return("...")
68
+ @backup_path.should_receive(:read).and_return("....")
69
+ lambda do @it.write!(@lines) end.should raise_error(RuntimeError)
70
+ end
71
+
72
+ it "should not open the source file if comparison fails" do
73
+ @path.should_receive(:read).and_return("...")
74
+ @backup_path.should_receive(:read).and_return("....")
75
+ @path.should_not_receive(:open)
76
+ lambda do @it.write!(@lines) end.should raise_error(RuntimeError)
77
+ end
78
+
79
+ it "should open the source file for overwriting after backing up" do
80
+ FileUtils.should_receive(:cp).ordered
81
+ @path.should_receive(:open).with('w+').ordered
82
+ @it.write!(@lines)
83
+ end
84
+
85
+ it "should write lines to the source file" do
86
+ @open_file.should_receive(:write).with("Line 1\n").ordered
87
+ @open_file.should_receive(:write).with("Line 2\n").ordered
88
+ @it.write!(@lines)
89
+ end
90
+
91
+ it "should restore backup if write fails" do
92
+ @open_file.should_receive(:write).and_raise("Some Failure")
93
+ FileUtils.should_receive(:cp).with(@backup_path, @path)
94
+ lambda do @it.write!(@lines) end.should raise_error(RuntimeError)
95
+ end
96
+
97
+ end
98
+ end
99
+ end