germinate 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 (105) hide show
  1. data/.gitignore +2 -0
  2. data/History.txt +26 -0
  3. data/README.rdoc +152 -0
  4. data/Rakefile +43 -0
  5. data/TODO +140 -0
  6. data/bin/germ +260 -0
  7. data/cucumber.yml +2 -0
  8. data/examples/basic.rb +123 -0
  9. data/examples/short.rb +19 -0
  10. data/features/author-formats-article.feature +111 -0
  11. data/features/author-lists-info.pending_feature +48 -0
  12. data/features/author-publishes-article-source.feature +5 -0
  13. data/features/author-publishes-article.feature +57 -0
  14. data/features/author-republishes-article.feature +5 -0
  15. data/features/author-selects-hunks.feature +26 -0
  16. data/features/author-sets-variables.feature +88 -0
  17. data/features/author-updates-article-source.feature +5 -0
  18. data/features/author-views-stuff.pending_feature +52 -0
  19. data/features/bin/quoter +6 -0
  20. data/features/bin/sorter +4 -0
  21. data/features/example_articles/bracketing.rb +27 -0
  22. data/features/example_articles/escaping.txt +13 -0
  23. data/features/example_articles/excerpt_output.rb +16 -0
  24. data/features/example_articles/hello.rb +9 -0
  25. data/features/example_articles/pipelines.txt +25 -0
  26. data/features/example_articles/regexen.rb +24 -0
  27. data/features/example_articles/sample_offsets.rb +18 -0
  28. data/features/example_articles/specials.rb +19 -0
  29. data/features/example_articles/stderr.rb +10 -0
  30. data/features/example_articles/wrapping.rb +8 -0
  31. data/features/example_output/bracketing.out +23 -0
  32. data/features/example_output/code_samples.txt +186 -0
  33. data/features/example_output/escaping.out +5 -0
  34. data/features/example_output/excerpt_output.out +6 -0
  35. data/features/example_output/hello.txt +1 -0
  36. data/features/example_output/pipelines.out +28 -0
  37. data/features/example_output/regexen.txt +22 -0
  38. data/features/example_output/sample_offsets.txt +15 -0
  39. data/features/example_output/specials.txt +40 -0
  40. data/features/example_output/stderr.out +3 -0
  41. data/features/example_output/wrapping.txt +3 -0
  42. data/features/step_definitions/germinate.rb +42 -0
  43. data/features/support/env.rb +20 -0
  44. data/germinate.gemspec +55 -0
  45. data/lib/germinate.rb +54 -0
  46. data/lib/germinate/application.rb +113 -0
  47. data/lib/germinate/article_editor.rb +20 -0
  48. data/lib/germinate/formatter.rb +119 -0
  49. data/lib/germinate/hunk.rb +183 -0
  50. data/lib/germinate/implicit_insertion.rb +9 -0
  51. data/lib/germinate/insertion.rb +29 -0
  52. data/lib/germinate/librarian.rb +293 -0
  53. data/lib/germinate/origin.rb +5 -0
  54. data/lib/germinate/pipeline.rb +13 -0
  55. data/lib/germinate/publisher.rb +57 -0
  56. data/lib/germinate/reader.rb +266 -0
  57. data/lib/germinate/selector.rb +136 -0
  58. data/lib/germinate/shared_style_attributes.rb +54 -0
  59. data/lib/germinate/shell_process.rb +94 -0
  60. data/lib/germinate/shell_publisher.rb +19 -0
  61. data/lib/germinate/simple_publisher.rb +7 -0
  62. data/lib/germinate/source_file.rb +41 -0
  63. data/lib/germinate/text_transforms.rb +119 -0
  64. data/lib/germinate/transform_process.rb +25 -0
  65. data/lib/germinate/variable.rb +23 -0
  66. data/sample.rb +14 -0
  67. data/spec/germinate/application_spec.rb +31 -0
  68. data/spec/germinate/article_editor_spec.rb +97 -0
  69. data/spec/germinate/code_hunk_spec.rb +73 -0
  70. data/spec/germinate/file_hunk_spec.rb +28 -0
  71. data/spec/germinate/formatter_spec.rb +160 -0
  72. data/spec/germinate/hunk_spec.rb +84 -0
  73. data/spec/germinate/implicit_insertion_spec.rb +33 -0
  74. data/spec/germinate/insertion_spec.rb +19 -0
  75. data/spec/germinate/librarian_spec.rb +555 -0
  76. data/spec/germinate/pipeline_spec.rb +34 -0
  77. data/spec/germinate/process_spec.rb +105 -0
  78. data/spec/germinate/publisher_spec.rb +130 -0
  79. data/spec/germinate/reader_spec.rb +385 -0
  80. data/spec/germinate/selector_spec.rb +121 -0
  81. data/spec/germinate/shell_publisher_spec.rb +61 -0
  82. data/spec/germinate/source_file_spec.rb +99 -0
  83. data/spec/germinate/text_hunk_spec.rb +98 -0
  84. data/spec/germinate/text_transforms_spec.rb +242 -0
  85. data/spec/germinate/transform_process_spec.rb +50 -0
  86. data/spec/germinate/variable_spec.rb +14 -0
  87. data/spec/germinate_spec.rb +8 -0
  88. data/spec/spec.opts +1 -0
  89. data/spec/spec_helper.rb +16 -0
  90. data/tasks/ann.rake +80 -0
  91. data/tasks/bones.rake +20 -0
  92. data/tasks/cucumber.rake +5 -0
  93. data/tasks/gem.rake +201 -0
  94. data/tasks/git.rake +40 -0
  95. data/tasks/notes.rake +27 -0
  96. data/tasks/post_load.rake +34 -0
  97. data/tasks/rdoc.rake +51 -0
  98. data/tasks/rubyforge.rake +55 -0
  99. data/tasks/setup.rb +292 -0
  100. data/tasks/spec.rake +54 -0
  101. data/tasks/svn.rake +47 -0
  102. data/tasks/test.rake +40 -0
  103. data/tasks/zentest.rake +36 -0
  104. data/test/test_germinate.rb +0 -0
  105. metadata +228 -0
@@ -0,0 +1,73 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe CodeHunk do
6
+ before :each do
7
+ @it = CodeHunk.new(["foo", "bar"])
8
+ end
9
+
10
+ it "should disable line joining" do
11
+ @it.should_not be_join_lines
12
+ end
13
+
14
+ it "should enable blank stripping" do
15
+ @it.should be_strip_blanks
16
+ end
17
+
18
+ it "should disable comment erasure" do
19
+ @it.should_not be_erase_comments
20
+ end
21
+
22
+ it "should disable uncommenting" do
23
+ @it.should_not be_uncomment
24
+ end
25
+
26
+ it "should disable stripping right-side whitespace" do
27
+ @it.should_not be_rstrip_lines
28
+ end
29
+
30
+ it "should enable bracketing" do
31
+ @it.should be_bracket
32
+ end
33
+
34
+ it "should enable pipeline processing" do
35
+ @it.should be_pipeline
36
+ end
37
+
38
+ context "when visited by a formatter" do
39
+ before :each do
40
+ @formatter = stub("Formatter")
41
+ end
42
+
43
+ it "should call #formate_code! for self" do
44
+ @formatter.should_receive(:format_code!).with(@it, anything)
45
+ @it.format_with(@formatter)
46
+ end
47
+ end
48
+
49
+ describe "with a nested hunk" do
50
+ before :each do
51
+ @formatter = stub("Formatter")
52
+ @comment_prefix = ">>"
53
+ @nested_hunk = stub("Nested Hunk", :empty? => false)
54
+ contents = [
55
+ "foo",
56
+ "bar",
57
+ @nested_hunk,
58
+ "baz"
59
+ ]
60
+ @it = CodeHunk.new(contents,
61
+ :comment_prefix => @comment_prefix)
62
+ end
63
+
64
+ it "should pass formatter on to nested hunks" do
65
+ @formatter.should_receive(:format_code!).with(["foo", "bar"], ">>").ordered
66
+ @nested_hunk.should_receive(:format_with).with(@formatter).ordered
67
+ @formatter.should_receive(:format_code!).with(["baz"], ">>").ordered
68
+ @it.format_with(@formatter)
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe FileHunk do
6
+ before :each do
7
+ @it = FileHunk.new(["foo", "bar"], {:source_path => "SOURCE_PATH"})
8
+ end
9
+
10
+ it "should know its source path" do
11
+ @it.source_path.to_s.should == "SOURCE_PATH"
12
+ end
13
+
14
+ specify { @it.should be_whole_file }
15
+
16
+ context "when visited by a formatter" do
17
+ before :each do
18
+ @formatter = stub("Formatter")
19
+ end
20
+
21
+ it "should call #formate_code! for self" do
22
+ @formatter.should_receive(:format_code!).with(@it, anything)
23
+ @it.format_with(@formatter)
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,160 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe Formatter do
6
+ before :each do
7
+ @output = StringIO.new
8
+ @it = Formatter.new(@output)
9
+ end
10
+
11
+ it "should start in the :initial state" do
12
+ @it.state.should == :initial
13
+ end
14
+
15
+
16
+ def output_string
17
+ @output.rewind
18
+ @output.string
19
+ end
20
+
21
+ context "which has been started" do
22
+ before :each do
23
+ @it.start!
24
+ end
25
+
26
+ it "should be in the :code state" do
27
+ @it.state.should == :code
28
+ end
29
+
30
+ it "should ignore initial lines" do
31
+ @it.add_line!("TEST")
32
+ output_string.should == ""
33
+ end
34
+
35
+ end
36
+
37
+ context "after the :TEXT: keyword" do
38
+ before :each do
39
+ @it.start!
40
+ @it.add_line!(":TEXT:\n")
41
+ end
42
+
43
+ it "should be in the :paragraph state" do
44
+ @it.state.should == :paragraph
45
+ end
46
+
47
+ it "should start outputting text" do
48
+ @it.add_line!("check 1 2 3\n")
49
+ @it.add_line!("\n")
50
+ output_string.should == "check 1 2 3\n"
51
+ end
52
+ end
53
+
54
+ context "after the :TEXT: keyword followed by :CUT:" do
55
+ before :each do
56
+ @it.start!
57
+ @it.add_line!(":TEXT:\n")
58
+ @it.add_line!(":CUT:\n")
59
+ end
60
+
61
+ it "should be in the :code state" do
62
+ @it.state.should == :code
63
+ end
64
+
65
+ it "should stop outputting text" do
66
+ @it.add_line!("check 1 2 3\n")
67
+ output_string.should == ""
68
+ end
69
+ end
70
+
71
+ context "after a :TEXT: keyword prefixed with '#'" do
72
+ before :each do
73
+ @it.start!
74
+ @it.add_line!("# :TEXT:\n")
75
+ end
76
+
77
+ it "should be in the :paragraph state" do
78
+ @it.state.should == :paragraph
79
+ end
80
+
81
+ it "should have a comment prefix of '#'" do
82
+ @it.comment_prefix.should == '#'
83
+ end
84
+
85
+ it "should strip '#' prefixes from text" do
86
+ @it.add_line!("# Line 1\n")
87
+ @it.add_line!(" ## Line 2\n")
88
+ @it.add_line!("\n")
89
+ output_string.should == "Line 1 Line 2\n"
90
+ end
91
+
92
+ it "should ignore uncommented lines" do
93
+ @it.add_line!("; Not a comment #")
94
+ output_string.should == ""
95
+ end
96
+
97
+ it "should ignore blank lines" do
98
+ @it.add_line!(" \t\n")
99
+ output_string.should == ""
100
+ end
101
+
102
+ it "should ignore commented blank lines" do
103
+ @it.add_line!("# \t\n")
104
+ output_string.should == ""
105
+ end
106
+ end
107
+
108
+ context "after a :TEXT: keyword prefixed with ';'" do
109
+ before :each do
110
+ @it.start!
111
+ @it.add_line!(" ; :TEXT:\n")
112
+ end
113
+
114
+ it "should have a comment prefix of ';'" do
115
+ @it.comment_prefix.should == ';'
116
+ end
117
+
118
+ it "should strip ';' prefixes from text" do
119
+ @it.add_line!("; Line 1\n")
120
+ @it.add_line!(" ;; Line 2\n")
121
+ @it.add_line!(";\n")
122
+ output_string.should == "Line 1 Line 2\n"
123
+ end
124
+
125
+ it "should ignore lines with '#' prefixes" do
126
+ @it.add_line!("# Line 1\n")
127
+ output_string.should == ""
128
+ end
129
+ end
130
+
131
+ context "in a text section " do
132
+ before :each do
133
+ @it.start!
134
+ @it.add_line!("# :TEXT:\n")
135
+ end
136
+
137
+ it "should join adjacent lines" do
138
+ @it.add_line!("# foo\n")
139
+ @it.add_line!("# bar\n")
140
+ @it.add_line!("\n")
141
+ output_string.should == "foo bar\n"
142
+ end
143
+ end
144
+
145
+ context "in a linebreak section" do
146
+ before :each do
147
+ @it.start!
148
+ @it.add_line!("# :TEXT:\n")
149
+ @it.add_line!("# P1\n")
150
+ @it.add_line!("\n")
151
+ end
152
+
153
+ it "should finish the section with a double newline" do
154
+ @it.add_line!("# P2\n")
155
+ @it.add_line!("\n")
156
+ output_string.should == "P1\n\nP2\n"
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,84 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe Hunk, "(attributes)" do
6
+ Germinate::SharedStyleAttributes.fattrs.each do |attribute|
7
+ it "should support the #{attribute} style attribute" do
8
+ @it = Germinate::Hunk.new([], attribute => "test")
9
+ @it.send(attribute).should == "test"
10
+ end
11
+
12
+ it "should pass the #{attribute} attribute on to duplicates" do
13
+ @it = Germinate::Hunk.new([], attribute => "test")
14
+ @it.dup.send(attribute).should == "test"
15
+ end
16
+
17
+ it "should pass the #{attribute} attribute on to clones" do
18
+ @it = Germinate::Hunk.new([], attribute => "test")
19
+ @it.clone.send(attribute).should == "test"
20
+ end
21
+
22
+ it "should pass the #{attribute} attribute on to slices" do
23
+ @it = Germinate::Hunk.new([], attribute => "test")
24
+ @it[0..-1].send(attribute).should == "test"
25
+ @it.slice(0..-1).send(attribute).should == "test"
26
+ end
27
+
28
+ it "should copy #{attribute} from given template" do
29
+ @template = Object.new
30
+ @template.extend SharedStyleAttributes
31
+ @template.send(attribute, "test")
32
+ @it = Germinate::Hunk.new([], @template)
33
+ @it.send(attribute).should == "test"
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ describe Hunk do
40
+ before :each do
41
+ @it = Hunk.new
42
+ end
43
+
44
+ it "should not have a source path" do
45
+ @it.source_path.should be_nil
46
+ end
47
+
48
+ specify { @it.should_not be_whole_file }
49
+
50
+ context "with an insertion" do
51
+ before :each do
52
+ @nested_hunk = stub("Nested Hunk")
53
+ @insertion = stub("Insertion", :resolve => @nested_hunk)
54
+ @it << "line 1"
55
+ @it << @insertion
56
+ @it << "line 2"
57
+ end
58
+
59
+ it "should be able to resolve the insertion" do
60
+ @it.resolve_insertions.should == [
61
+ "line 1",
62
+ @nested_hunk,
63
+ "line 2"
64
+ ]
65
+ end
66
+ end
67
+
68
+ describe "with some content" do
69
+ before :each do
70
+ @it.push("foo", "bar", "foo", "baz")
71
+ end
72
+
73
+ it "should be able to find indexes of elements matching a regex" do
74
+ @it.index_matching(/ba/).should == 1
75
+ @it.index_matching(/fo/).should == 0
76
+ @it.index_matching(/fo/, 1).should == 2
77
+ @it.index_matching(/fo/, 2).should == 2
78
+ @it.index_matching(/fo/, 3).should be_nil
79
+ @it.index_matching(/za/, 3).should be_nil
80
+ end
81
+ end
82
+ end
83
+
84
+ end
@@ -0,0 +1,33 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe ImplicitInsertion do
6
+ before :each do
7
+ @hunk = stub("Hunk").as_null_object
8
+ @library = stub("Library")
9
+ @selector = stub("Selector")
10
+ @it = Germinate::ImplicitInsertion.new(@selector, @library)
11
+ end
12
+
13
+ context "when the librarian can find the selection" do
14
+ before :each do
15
+ @library.stub!(:[]).and_return(@hunk)
16
+ end
17
+
18
+ it "should resolve to the hunk the librarian returns" do
19
+ @it.resolve.should equal(@hunk)
20
+ end
21
+ end
22
+
23
+ context "when the librarian cannot find the selection" do
24
+ before :each do
25
+ @library.stub!(:[]).and_raise(IndexError.new)
26
+ end
27
+
28
+ it "should resolve to a null hunk" do
29
+ @it.resolve.should be_a_kind_of(NullHunk)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe Insertion, "given a library and a selector" do
6
+ before :each do
7
+ @hunk = stub("Hunk").as_null_object
8
+ @library = stub("Library", :[] => @hunk)
9
+ @selector = stub("Selector")
10
+ @it = Germinate::Insertion.new(@selector, @library, {})
11
+ end
12
+
13
+ it "should use the library to resolve itself" do
14
+ @library.should_receive(:[]).
15
+ with(@selector, anything, anything).and_return(@hunk)
16
+ @it.resolve.should == @hunk
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,555 @@
1
+ require 'rubygems'
2
+ require 'arrayfields'
3
+
4
+ require File.expand_path(
5
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
6
+
7
+
8
+ module Germinate
9
+ describe Librarian do
10
+ before :each do
11
+ @it = Librarian.new
12
+ @it.source_path = "SOURCE_PATH"
13
+ end
14
+
15
+ it "should know its source path if given" do
16
+ @it.source_path.should == "SOURCE_PATH"
17
+ end
18
+
19
+ context "by default" do
20
+ it "should have access to the special _transform process" do
21
+ @it.process('_transform').should be_a_kind_of(TransformProcess)
22
+ end
23
+
24
+ it "should not have a comment prefix" do
25
+ @it.comment_prefix.should == nil
26
+ @it.comment_prefix_known?.should be_false
27
+ end
28
+
29
+ it "should not have code brackets" do
30
+ @it.code_open_bracket.should be_nil
31
+ @it.code_close_bracket.should be_nil
32
+ end
33
+ end
34
+
35
+ Germinate::SharedStyleAttributes.fattrs.each do |attribute|
36
+ it "should pass the #{attribute} attribute on to text hunks" do
37
+ @it.send(attribute, "#{attribute}_test")
38
+ @it.add_text!("first", "hello")
39
+ @it.section("first").send(attribute).should == "#{attribute}_test"
40
+ end
41
+
42
+ it "should pass the #{attribute} attribute on to code hunks" do
43
+ @it.send(attribute, "#{attribute}_test")
44
+ @it.add_code!("first", "hello")
45
+ @it.sample("first").send(attribute).should == "#{attribute}_test"
46
+ end
47
+ end
48
+
49
+ context "given a comment prefix" do
50
+ before :each do
51
+ @it.comment_prefix = "||"
52
+ end
53
+
54
+ it "should remember the comment prefix" do
55
+ @it.comment_prefix.should == "||"
56
+ end
57
+
58
+ it "should know it has a comment prefix" do
59
+ @it.comment_prefix_known?.should be_true
60
+ end
61
+ end
62
+
63
+ context "given code brackets" do
64
+ before :each do
65
+ @it.code_open_bracket = "{"
66
+ @it.code_close_bracket = "}"
67
+ end
68
+
69
+ it "should remember the open bracket" do
70
+ @it.code_open_bracket.should == "{"
71
+ end
72
+
73
+ it "should remember the close bracket" do
74
+ @it.code_close_bracket.should == "}"
75
+ end
76
+
77
+ end
78
+
79
+ context "given custom code attributes" do
80
+ before :each do
81
+ @it.set_code_attributes!(
82
+ "sample1",
83
+ :code_open_bracket => "<<",
84
+ :code_close_bracket => ">>")
85
+ end
86
+
87
+ it "should create the sample (if needed) and assign the attributes" do
88
+ @it.sample("sample1").code_open_bracket.should == "<<"
89
+ @it.sample("sample1").code_close_bracket.should == ">>"
90
+ end
91
+ end
92
+
93
+ context "given an insertion in my_section with selector @my_selector" do
94
+ before :each do
95
+ @it.disable_all_transforms!
96
+ @it.add_code!("my_sample", "line 1\n")
97
+ @it.add_insertion!("my_section", "@my_sample", { :comment_prefix => "@" })
98
+ end
99
+
100
+ it "should add an Insertion to the named section" do
101
+ @it.section("my_section").last.should be_a_kind_of(Insertion)
102
+ end
103
+
104
+ it "should give the insertion the selector @my_selector" do
105
+ @it.section("my_section").last.selector.to_s.should == "@my_sample"
106
+ end
107
+
108
+ it "should give the insertion a reference to the library" do
109
+ @it.section("my_section").last.library.should == @it
110
+ end
111
+
112
+ it "should apply any passed attributes to the insertion" do
113
+ @it.section("my_section").last.comment_prefix.should == "@"
114
+ end
115
+
116
+ it "should include the insertion in the $TEXT hunk" do
117
+ @it['$TEXT'].first.should be_a_kind_of(Insertion)
118
+ @it['$TEXT'].first.selector.should == "@my_sample"
119
+ end
120
+ end
121
+
122
+ context "given a process to file" do
123
+ before :each do
124
+ @it.add_process!("myproc", "cowsay")
125
+ end
126
+
127
+ it "should make the process available as a ShellProcess object" do
128
+ @it.process("myproc").should be_a_kind_of(Germinate::ShellProcess)
129
+ end
130
+
131
+ it "should store the process name" do
132
+ @it.process("myproc").name.should == "myproc"
133
+ end
134
+
135
+ it "should store the process command" do
136
+ @it.process("myproc").command.should == "cowsay"
137
+ end
138
+
139
+ it "should include the process when listing known processes" do
140
+ @it.process_names.should include("myproc")
141
+ end
142
+
143
+ it "should give the process a reference to the librarians variables" do
144
+ @it.process("myproc").variables.should equal(@it.variables)
145
+ end
146
+ end
147
+
148
+ context "given a code sample and some processes" do
149
+ before :each do
150
+ @output_a = Hunk.new(["line 1a", "line 2a"])
151
+ @output_b = Hunk.new(["line 1b", "line 2b"])
152
+ @process_a = stub("ShellProcess A",
153
+ :call => @output_a,
154
+ :name => "foo",
155
+ :command => "aaa")
156
+ @process_b = stub("ShellProcess B",
157
+ :call => @output_b,
158
+ :name => "bar",
159
+ :command => "bbb")
160
+ Germinate::ShellProcess.stub!(:new).
161
+ with("foo", "aaa", {}).
162
+ and_return(@process_a)
163
+ Germinate::ShellProcess.stub!(:new).
164
+ with("bar", "bbb", {}).
165
+ and_return(@process_b)
166
+
167
+ @it.add_code!("A", "line 1")
168
+ @it.add_code!("A", "line 2")
169
+ @it.add_process!("foo", "aaa")
170
+ @it.add_process!("bar", "bbb")
171
+ end
172
+
173
+ context "when the processes are included in a selection" do
174
+ before :each do
175
+ @selector = "@A|foo|bar"
176
+ end
177
+
178
+ it "should call the processes on the selected text" do
179
+ @process_a.should_receive(:call).with(["line 1\n", "line 2\n"]).
180
+ and_return(@output_a)
181
+ @process_b.should_receive(:call).with(@output_a).
182
+ and_return(@output_b)
183
+
184
+ @it[@selector].should == ["line 1b", "line 2b"]
185
+ end
186
+ end
187
+
188
+ context "when asked to make a pipeline of the two processes" do
189
+ before :each do
190
+ @pipeline = @it.make_pipeline("bar|foo")
191
+ end
192
+
193
+ it "should return a Pipeline object" do
194
+ @pipeline.should be_a_kind_of(Germinate::Pipeline)
195
+ end
196
+
197
+ it "should return a two-process pipeline" do
198
+ @pipeline.should have(2).processes
199
+ end
200
+
201
+ it "should include the named processes in the pipeline" do
202
+ @pipeline.processes[0].name.should == "bar"
203
+ @pipeline.processes[0].command.should == "bbb"
204
+ @pipeline.processes[1].name.should == "foo"
205
+ @pipeline.processes[1].command.should == "aaa"
206
+ end
207
+ end
208
+
209
+ context "when asked to make an empty pipeline" do
210
+ before :each do
211
+ @pipeline = @it.make_pipeline("")
212
+ end
213
+
214
+ it "should return an empty pipeline" do
215
+ @pipeline.should have(0).processes
216
+ end
217
+ end
218
+ end
219
+
220
+ context "given a new publisher" do
221
+ before :each do
222
+ @publisher_name = "MyPub"
223
+ @publisher_type = "shell"
224
+ @publisher_options = {'foo' => 'bar'}
225
+ @publisher = stub("Publisher")
226
+ Germinate::Publisher.stub!(:make).and_return(@publisher)
227
+ end
228
+
229
+ it "should construct a new publisher object" do
230
+ Germinate::Publisher.should_receive(:make).
231
+ with(@publisher_name, @publisher_type, @it, @publisher_options).
232
+ and_return(@publisher)
233
+ @it.add_publisher!(@publisher_name, @publisher_type, @publisher_options)
234
+ end
235
+
236
+ it "should make the new publisher available by name" do
237
+ @it.add_publisher!(@publisher_name, @publisher_type, @publisher_options)
238
+ @it.publisher(@publisher_name).should equal(@publisher)
239
+ end
240
+
241
+ it "should raise an error when an unknown publisher is requested" do
242
+ @it.add_publisher!(@publisher_name, @publisher_type, @publisher_options)
243
+ lambda do
244
+ @it.publisher("foo")
245
+ end.should raise_error(IndexError)
246
+ end
247
+ end
248
+
249
+ context "given a variable directive" do
250
+ before :each do
251
+ @line = " :SET: FOO, 123"
252
+ @it.set_variable!(@line, 111, "FOO", "123")
253
+ end
254
+
255
+ it "should add a variable with the given name and value" do
256
+ @it.variables["FOO"].should == "123"
257
+ end
258
+
259
+ it "should set the variables line to the given value" do
260
+ @it.variables["FOO"].line.should equal(@line)
261
+ end
262
+
263
+ it "should set the variables line_number to the given value" do
264
+ @it.variables["FOO"].origin.line_number.should == 111
265
+ end
266
+
267
+ it "should set the variables source path to its own source path" do
268
+ @it.variables["FOO"].origin.source_path.to_s.should == "SOURCE_PATH"
269
+ end
270
+ end
271
+
272
+ context "given a variable setting when the variable already has a value" do
273
+ before :each do
274
+ @it.set_variable!(" :SET: FOO, 123", 1, "FOO", "123")
275
+ @it.set_variable!(" :SET: FOO, 456", 1, "FOO", "456")
276
+ end
277
+
278
+ it "should replace the old variable value with the new one" do
279
+ @it.variables["FOO"].should == "456"
280
+ end
281
+ end
282
+
283
+ context "setting a new variable" do
284
+ before :each do
285
+ @it.add_text!("a", " # some text")
286
+ @it.comment_prefix = " # "
287
+ @it.variables["FOO"] = 123
288
+ end
289
+
290
+ it "should add a new line" do
291
+ @it.lines.last.should == " # :SET: 'FOO', '123'\n"
292
+ end
293
+
294
+ it "should set the variable to reference the new line" do
295
+ @it.variables["FOO"].line.should equal(@it.lines.last)
296
+ end
297
+
298
+ it "should set the line number for the new line" do
299
+ @it.variables["FOO"].origin.line_number.should == 2
300
+ end
301
+
302
+ it "should set the variable's source file to its own" do
303
+ @it.variables["FOO"].origin.source_path.should == "SOURCE_PATH"
304
+ end
305
+
306
+ it "should set the variable's value as a string" do
307
+ @it.variables["FOO"].should == "123"
308
+ end
309
+
310
+ it "should set the updatad flag" do
311
+ @it.should be_updated
312
+ end
313
+ end
314
+
315
+ context "setting an existing variable" do
316
+ before :each do
317
+ @it.comment_prefix = " # "
318
+ @it.variables["FOO"] = 123
319
+ @it.add_text!("a", " # some text")
320
+ @it.updated = false
321
+ @it.variables["FOO"] = 456
322
+ end
323
+
324
+ it "should not add a new line" do
325
+ @it.should have(2).lines
326
+ end
327
+
328
+ it "should point to an already existing line" do
329
+ @it.variables["FOO"].line.should equal(@it.lines.first)
330
+ end
331
+
332
+ it "should keep variable line number" do
333
+ @it.variables["FOO"].origin.line_number.should == 1
334
+ end
335
+
336
+ it "should keep variable source path" do
337
+ @it.variables["FOO"].origin.source_path.should == "SOURCE_PATH"
338
+ end
339
+
340
+ it "should update the variable's value" do
341
+ @it.variables["FOO"].should == "456"
342
+ end
343
+
344
+ it "should set the updatad flag" do
345
+ @it.should be_updated
346
+ end
347
+
348
+ it "should update the source line with a new directive" do
349
+ @it.lines.first.should == " # :SET: 'FOO', '456'\n"
350
+ end
351
+ end
352
+
353
+ context "storing changes" do
354
+ before :each do
355
+ @it.add_text!("A", "Line 1")
356
+ @it.add_text!("B", "Line 2")
357
+ @source_file = stub("Source File")
358
+ @it.source_file = @source_file
359
+ end
360
+
361
+ it "should send all lines to the source file object to be written" do
362
+ @source_file.should_receive(:write!).with(["Line 1\n", "Line 2\n"])
363
+ @it.store_changes!
364
+ end
365
+ end
366
+
367
+ context "given an assortment of lines" do
368
+ before :each do
369
+ @it.add_front_matter!("FM 1")
370
+ @it.add_front_matter!("FM 2")
371
+ @it.add_control!("CONTROL 1")
372
+ @it.add_text!("SECTION1", "TEXT 1")
373
+ @it.add_text!("SECTION1", "TEXT 2")
374
+ @it.add_control!("CONTROL 2")
375
+ @it.add_code!("SECTION1", "CODE 1")
376
+ @it.add_control!("CONTROL 3")
377
+ @it.add_text!("SECTION2", "TEXT 3")
378
+ @it.add_text!("SECTION2", "TEXT 4")
379
+ @it.add_code!("SECTION2", "CODE 2")
380
+ @it.add_code!("SECTION2", "CODE 2l2")
381
+ @it.add_code!("SECTION2", "CODE 2l3")
382
+ @it.add_code!("SECTION2", "CODE 2l4")
383
+ end
384
+
385
+ it "should be able to retrieve all the lines in order" do
386
+ @it.lines.should == [
387
+ "FM 1\n",
388
+ "FM 2\n",
389
+ "CONTROL 1\n",
390
+ "TEXT 1\n",
391
+ "TEXT 2\n",
392
+ "CONTROL 2\n",
393
+ "CODE 1\n",
394
+ "CONTROL 3\n",
395
+ "TEXT 3\n",
396
+ "TEXT 4\n",
397
+ "CODE 2\n",
398
+ "CODE 2l2\n",
399
+ "CODE 2l3\n",
400
+ "CODE 2l4\n",
401
+ ]
402
+ end
403
+
404
+ it "should be able to retrieve text lines" do
405
+ @it.text_lines.should == [
406
+ "TEXT 1\n",
407
+ "TEXT 2\n",
408
+ "TEXT 3\n",
409
+ "TEXT 4\n"
410
+ ]
411
+ end
412
+
413
+ it "should be able to retrieve code lines" do
414
+ @it.code_lines.should == [
415
+ "CODE 1\n",
416
+ "CODE 2\n",
417
+ "CODE 2l2\n",
418
+ "CODE 2l3\n",
419
+ "CODE 2l4\n",
420
+ ]
421
+ end
422
+
423
+ it "should be able to retrieve front matter" do
424
+ @it.front_matter_lines.should == [
425
+ "FM 1\n",
426
+ "FM 2\n",
427
+ ]
428
+ end
429
+
430
+ it "should be able to retrieve text by section" do
431
+ @it.section("SECTION1").should == [
432
+ "TEXT 1\n",
433
+ "TEXT 2\n"
434
+ ]
435
+ @it.section("SECTION2").should == [
436
+ "TEXT 3\n",
437
+ "TEXT 4\n"
438
+ ]
439
+ end
440
+
441
+ it "should be able to retrieve code by sample name" do
442
+ @it.sample("SECTION1").should == [
443
+ "CODE 1\n"
444
+ ]
445
+ @it.sample("SECTION2").should == [
446
+ "CODE 2\n",
447
+ "CODE 2l2\n",
448
+ "CODE 2l3\n",
449
+ "CODE 2l4\n",
450
+ ]
451
+ end
452
+
453
+ it "should be able to return a list of section names" do
454
+ @it.section_names.should == [
455
+ "SECTION1",
456
+ "SECTION2"
457
+ ]
458
+ end
459
+
460
+ it "should be able to return a list of sample names" do
461
+ @it.sample_names.should == [
462
+ "SECTION1",
463
+ "SECTION2"
464
+ ]
465
+ end
466
+
467
+ it "should be able to tell if a section exists" do
468
+ @it.should have_section("SECTION1")
469
+ @it.should_not have_section("SECTION5")
470
+ end
471
+
472
+ it "should be able to tell if a sample exists" do
473
+ @it.should have_sample("SECTION1")
474
+ @it.should_not have_sample("SECTION5")
475
+ end
476
+
477
+ it "should be able to retrieve lines using a selector" do
478
+ @it[Selector.new("@SECTION1", nil)].should == ["CODE 1\n"]
479
+ @it["@SECTION1"].should == ["CODE 1\n"]
480
+ end
481
+
482
+ context "given the $SOURCE selector with no subscripts" do
483
+ before :each do
484
+ @hunk = @it["$SOURCE"]
485
+ end
486
+
487
+ it "should return a FileHunk" do
488
+ @hunk.should be_a_kind_of(FileHunk)
489
+ end
490
+
491
+ it "should return a FileHunk with the source file path set" do
492
+ @hunk.source_path.should == "SOURCE_PATH"
493
+ end
494
+
495
+ end
496
+
497
+ SELECTOR_EXAMPLES = [
498
+ # Selector Expected Excerpt Expected Type
499
+ [ "@SECTION1", ["CODE 1\n"], CodeHunk ],
500
+ [ "@SECTION2:1", ["CODE 2\n"], CodeHunk ],
501
+ [ "@SECTION2:2..3", ["CODE 2l2\n", "CODE 2l3\n"], CodeHunk ],
502
+ [ "@SECTION2:2,2", ["CODE 2l2\n", "CODE 2l3\n"], CodeHunk ],
503
+ [ "@SECTION2:/l2/../l3/", ["CODE 2l2\n", "CODE 2l3\n"], CodeHunk ],
504
+ [ "@SECTION2:/l2/.../l3/", ["CODE 2l2\n"], CodeHunk ],
505
+ [ "@SECTION2:/2/,3", [
506
+ "CODE 2\n",
507
+ "CODE 2l2\n",
508
+ "CODE 2l3\n"], CodeHunk ],
509
+ [ "@SECTION2:/l2/..-1", [
510
+ "CODE 2l2\n",
511
+ "CODE 2l3\n",
512
+ "CODE 2l4\n"], CodeHunk ],
513
+ [ "$CODE", [
514
+ "CODE 1\n",
515
+ "CODE 2\n",
516
+ "CODE 2l2\n",
517
+ "CODE 2l3\n",
518
+ "CODE 2l4\n", ], CodeHunk
519
+ ],
520
+ [ "$SOURCE", [
521
+ "FM 1\n",
522
+ "FM 2\n",
523
+ "CONTROL 1\n",
524
+ "TEXT 1\n",
525
+ "TEXT 2\n",
526
+ "CONTROL 2\n",
527
+ "CODE 1\n",
528
+ "CONTROL 3\n",
529
+ "TEXT 3\n",
530
+ "TEXT 4\n",
531
+ "CODE 2\n",
532
+ "CODE 2l2\n",
533
+ "CODE 2l3\n",
534
+ "CODE 2l4\n",
535
+ ], FileHunk
536
+ ],
537
+ [ "$TEXT", [
538
+ "TEXT 1 TEXT 2 TEXT 3 TEXT 4" ], TextHunk
539
+ ],
540
+
541
+ ]
542
+
543
+ SELECTOR_EXAMPLES.each do |example|
544
+ example.fields = [:selector, :hunk, :type]
545
+ it "should be able to locate #{example[:selector]}" do
546
+ @it[example[:selector]].should == example[:hunk]
547
+ end
548
+
549
+ it "should return #{example[:selector]} as #{example[:type]}" do
550
+ @it[example[:selector]].should be_a_kind_of(example[:type])
551
+ end
552
+ end
553
+ end
554
+ end
555
+ end