devver-germinate 1.0.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 (86) hide show
  1. data/.gitignore +2 -0
  2. data/History.txt +4 -0
  3. data/README.rdoc +132 -0
  4. data/Rakefile +43 -0
  5. data/bin/germ +133 -0
  6. data/cucumber.yml +2 -0
  7. data/examples/basic.rb +118 -0
  8. data/examples/short.rb +17 -0
  9. data/features/author-formats-article.feature +108 -0
  10. data/features/author-lists-info.feature +45 -0
  11. data/features/author-publishes-article-source.feature +5 -0
  12. data/features/author-publishes-article.feature +5 -0
  13. data/features/author-republishes-article.feature +5 -0
  14. data/features/author-selects-hunks.feature +26 -0
  15. data/features/author-updates-article-source.feature +5 -0
  16. data/features/author-views-stuff.feature +48 -0
  17. data/features/bin/quoter +6 -0
  18. data/features/bin/sorter +4 -0
  19. data/features/example_articles/code_samples.rb +89 -0
  20. data/features/example_articles/escaping.txt +12 -0
  21. data/features/example_articles/hello.rb +9 -0
  22. data/features/example_articles/pipelines.txt +25 -0
  23. data/features/example_articles/regexen.rb +24 -0
  24. data/features/example_articles/sample_offsets.rb +18 -0
  25. data/features/example_articles/specials.rb +19 -0
  26. data/features/example_articles/wrapping.rb +8 -0
  27. data/features/example_output/code_samples.txt +186 -0
  28. data/features/example_output/escaping.out +5 -0
  29. data/features/example_output/hello.txt +1 -0
  30. data/features/example_output/pipelines.out +28 -0
  31. data/features/example_output/regexen.txt +22 -0
  32. data/features/example_output/sample_offsets.txt +15 -0
  33. data/features/example_output/specials.txt +36 -0
  34. data/features/example_output/wrapping.txt +3 -0
  35. data/features/step_definitions/germinate.rb +30 -0
  36. data/features/support/env.rb +18 -0
  37. data/germinate.gemspec +55 -0
  38. data/lib/germinate.rb +54 -0
  39. data/lib/germinate/application.rb +62 -0
  40. data/lib/germinate/article_editor.rb +20 -0
  41. data/lib/germinate/article_formatter.rb +75 -0
  42. data/lib/germinate/formatter.rb +119 -0
  43. data/lib/germinate/hunk.rb +149 -0
  44. data/lib/germinate/implicit_insertion.rb +9 -0
  45. data/lib/germinate/insertion.rb +15 -0
  46. data/lib/germinate/librarian.rb +179 -0
  47. data/lib/germinate/pipeline.rb +11 -0
  48. data/lib/germinate/process.rb +67 -0
  49. data/lib/germinate/reader.rb +212 -0
  50. data/lib/germinate/selector.rb +95 -0
  51. data/lib/germinate/shared_style_attributes.rb +23 -0
  52. data/lib/germinate/text_transforms.rb +90 -0
  53. data/spec/germinate/application_spec.rb +14 -0
  54. data/spec/germinate/article_editor_spec.rb +97 -0
  55. data/spec/germinate/article_formatter_spec.rb +153 -0
  56. data/spec/germinate/code_hunk_spec.rb +45 -0
  57. data/spec/germinate/formatter_spec.rb +160 -0
  58. data/spec/germinate/hunk_spec.rb +77 -0
  59. data/spec/germinate/implicit_insertion_spec.rb +33 -0
  60. data/spec/germinate/insertion_spec.rb +18 -0
  61. data/spec/germinate/librarian_spec.rb +336 -0
  62. data/spec/germinate/pipeline_spec.rb +24 -0
  63. data/spec/germinate/process_spec.rb +64 -0
  64. data/spec/germinate/reader_spec.rb +306 -0
  65. data/spec/germinate/selector_spec.rb +65 -0
  66. data/spec/germinate/text_hunk_spec.rb +53 -0
  67. data/spec/germinate/text_transforms_spec.rb +154 -0
  68. data/spec/germinate_spec.rb +8 -0
  69. data/spec/spec.opts +1 -0
  70. data/spec/spec_helper.rb +16 -0
  71. data/tasks/ann.rake +80 -0
  72. data/tasks/bones.rake +20 -0
  73. data/tasks/cucumber.rake +5 -0
  74. data/tasks/gem.rake +201 -0
  75. data/tasks/git.rake +40 -0
  76. data/tasks/notes.rake +27 -0
  77. data/tasks/post_load.rake +34 -0
  78. data/tasks/rdoc.rake +51 -0
  79. data/tasks/rubyforge.rake +55 -0
  80. data/tasks/setup.rb +292 -0
  81. data/tasks/spec.rake +54 -0
  82. data/tasks/svn.rake +47 -0
  83. data/tasks/test.rake +40 -0
  84. data/tasks/zentest.rake +36 -0
  85. data/test/test_germinate.rb +0 -0
  86. metadata +209 -0
@@ -0,0 +1,24 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe Pipeline, "given a set of processes" do
6
+ before :each do
7
+ @intput = stub("Input")
8
+ @output1 = stub("Output 1")
9
+ @output2 = stub("Output 2")
10
+ @output3 = stub("Output 3")
11
+ @process1 = stub("Process 1", :call => @output1)
12
+ @process2 = stub("Process 2", :call => @output2)
13
+ @process3 = stub("Process 3", :call => @output3)
14
+ @it = Germinate::Pipeline.new([@process1, @process2, @process3])
15
+ end
16
+
17
+ it "should compose the processes into a pipeline" do
18
+ @process1.should_receive(:call).with(@input).and_return(@output1)
19
+ @process2.should_receive(:call).with(@output1).and_return(@output2)
20
+ @process3.should_receive(:call).with(@output2).and_return(@output3)
21
+ @it.call(@input).should == @output3
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,64 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe Process do
6
+ before :each do
7
+ @input = Germinate::Hunk.new(
8
+ ["line 1\n", "line 2\n"],
9
+ :comment_prefix => "//")
10
+ @output = ["1 enil\n", "2 enil\n"]
11
+ @command = stub("Command", :readlines => @output).as_null_object
12
+ IO.stub!(:popen).and_yield(@command)
13
+ end
14
+
15
+ context "given a command 'mycommand'" do
16
+ before :each do
17
+ @it = Germinate::Process.new("myproc", "mycommand")
18
+ end
19
+
20
+ context "when called on a hunk of text" do
21
+ it "should pipe the input through the command" do
22
+ @command.should_receive(:<<).with("line 1\n").ordered
23
+ @command.should_receive(:<<).with("line 2\n").ordered
24
+ @command.should_receive(:close_write).ordered
25
+ @command.should_receive(:readlines).ordered.
26
+ and_return(["a\n", "b\n"])
27
+ IO.should_receive(:popen).with("mycommand", "r+").and_yield(@command)
28
+ output = @it.call(@input)
29
+ output.should == ["a\n", "b\n"]
30
+ end
31
+
32
+ it "should preserve hunk attributes" do
33
+ output = @it.call(@input)
34
+ output.comment_prefix.should == "//"
35
+ end
36
+ end
37
+ end
38
+
39
+ context "given a command 'mycommand %f' and called on some text" do
40
+ before :each do
41
+ @it = Germinate::Process.new("myproc", "mycommand %f")
42
+ end
43
+
44
+ it "should create a temporary file and pass the name to the command" do
45
+ @tempfile = stub("Temp File", :path => "TEMP_PATH")
46
+ Tempfile.should_receive(:open).with("germinate_hunk").and_yield(@tempfile)
47
+ @tempfile.should_receive(:<<).with("line 1\n").ordered
48
+ @tempfile.should_receive(:<<).with("line 2\n").ordered
49
+ @tempfile.should_receive(:close).ordered
50
+ IO.should_receive(:popen).
51
+ with("mycommand 'TEMP_PATH'", "r").
52
+ and_yield(@command)
53
+
54
+ @it.call(@input).should == @output
55
+ end
56
+
57
+ it "should preserve hunk attributes" do
58
+ output = @it.call(@input)
59
+ output.comment_prefix.should == "//"
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,306 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe Reader do
6
+ before :each do
7
+ @librarian = stub("Librarian", :comment_prefix_known? => false).
8
+ as_null_object
9
+ @it = Reader.new(@librarian)
10
+ end
11
+
12
+ it "should start in the :initial state" do
13
+ @it.state.should == :initial
14
+ end
15
+
16
+ it "should start out with a section count of 0" do
17
+ @it.section_count.should == 0
18
+ end
19
+
20
+ it "should start out with current section SECTION0" do
21
+ @it.current_section.should == "SECTION0"
22
+ end
23
+
24
+ context "when section count is incremented" do
25
+
26
+ before :each do
27
+ @it.increment_section_count!
28
+ end
29
+
30
+ it "should increment section count by one" do
31
+ @it.section_count.should == 1
32
+ end
33
+
34
+ it "should update current section" do
35
+ @it.current_section.should == "SECTION1"
36
+ end
37
+
38
+ end
39
+
40
+ CONTROL_LINES = [
41
+ # Line Comment Args
42
+ [":TEXT:\n", nil, []],
43
+ ["# :CUT: \n", "#", []],
44
+ [" ; :TEXT: foo\n", ";", ["foo"]],
45
+ ["//:SAMPLE:\n", "//", []],
46
+ ["$>:END: ", "$>", []],
47
+ [":SAMPLE: bar, { a: 1, b: 2 }", nil, ["bar", {"a"=>1, "b"=>2}]],
48
+ [':BRACKET_CODE:', nil, []],
49
+ [':INSERT: @sel', nil, ["@sel"]],
50
+ [':PROCESS: foo, bar', nil, ["foo", "bar"]],
51
+ ]
52
+
53
+ CONTROL_LINES.each do |(line, comment, args)|
54
+ context "when given the line #{line}" do
55
+ if comment
56
+ it "should set the comment character to '#{comment}'" do
57
+ @librarian.should_receive(:comment_prefix=).with(comment)
58
+ @it << line
59
+ end
60
+ else
61
+ it "should not set a comment prefix" do
62
+ @librarian.should_not_receive(:comment_prefix=)
63
+ @it << line
64
+ end
65
+ end
66
+
67
+ it "should store the line as a control line" do
68
+ @librarian.should_receive(:add_control!).with(line)
69
+ @it << line
70
+ end
71
+ end
72
+ end
73
+
74
+ context "given a BRACKET_CODE control line" do
75
+ before :each do
76
+ @line = ':BRACKET_CODE: "<<<", ">>>"'
77
+ end
78
+
79
+ it "should store the brackets" do
80
+ @librarian.should_receive(:code_open_bracket=).with("<<<")
81
+ @librarian.should_receive(:code_close_bracket=).with(">>>")
82
+ @it << @line
83
+ end
84
+
85
+ end
86
+
87
+ context "before the first line of text" do
88
+ it "should treat non-keyword lines as front matter" do
89
+ @librarian.should_receive(:add_front_matter!, "TEST")
90
+ @it << "TEST"
91
+ end
92
+ end
93
+
94
+ context "after an initial line of text" do
95
+ before :each do
96
+ @it << "\n"
97
+ end
98
+
99
+ it "should be in the :front_matter state" do
100
+ @it.state.should == :front_matter
101
+ end
102
+
103
+ it "should record non-keyword lines as more front matter" do
104
+ @librarian.should_receive(:add_front_matter!, "TEST")
105
+ @it << "TEST"
106
+ end
107
+ end
108
+
109
+ context "after the :TEXT: keyword" do
110
+ before :each do
111
+ @it << ":TEXT:\n"
112
+ end
113
+
114
+ it "should be in the :text state" do
115
+ @it.state.should == :text
116
+ end
117
+
118
+ it "should place following text lines into a section" do
119
+ @librarian.should_receive(:add_text!).with("SECTION1", "blah blah blah")
120
+ @it << "blah blah blah"
121
+ end
122
+
123
+ context "given an escaped directive" do
124
+ it "should add the directive line as text" do
125
+ @librarian.should_receive(:add_text!).with("SECTION1", ":TEXT: abc")
126
+ @it << "\\:TEXT: abc"
127
+ end
128
+ end
129
+ end
130
+
131
+ context "after two anonymous :TEXT: sections" do
132
+ before :each do
133
+ @it << ":TEXT:\n"
134
+ @it << ":TEXT:\n"
135
+ end
136
+
137
+ it "should be in SECTION2" do
138
+ @it.current_section.should == "SECTION2"
139
+ end
140
+ end
141
+
142
+ context "after a named :TEXT: keyword" do
143
+ before :each do
144
+ @it << ":TEXT: foo\n"
145
+ end
146
+
147
+ it "should be in the :text state" do
148
+ @it.state.should == :text
149
+ end
150
+
151
+ it "should place following text lines into the named section" do
152
+ @librarian.should_receive(:add_text!).with("foo", "yadda yadda")
153
+ @it << "yadda yadda"
154
+ end
155
+
156
+ it "should name following code lines after the section" do
157
+ @librarian.should_receive(:add_code!).with("foo", "this is code")
158
+ @it << "yadda yadda\n"
159
+ @it << ":SAMPLE:\n"
160
+ @it << "this is code"
161
+ end
162
+ end
163
+
164
+ context "after text is ended by a :CUT:" do
165
+ before :each do
166
+ @it << ":TEXT:\n"
167
+ @it << ":CUT:\n"
168
+ end
169
+
170
+ it "should be in the :code state" do
171
+ @it.state.should == :code
172
+ end
173
+
174
+ it "should add following lines to a code sample" do
175
+ @librarian.should_receive(:add_code!).with("SECTION2", "this is code")
176
+ @it << "this is code"
177
+ end
178
+ end
179
+
180
+ context "after a :TEXT: keyword prefixed with '#'" do
181
+ before :each do
182
+ @it << "# :TEXT:\n"
183
+ end
184
+
185
+ it "should be in the :text state" do
186
+ @it.state.should == :text
187
+ end
188
+
189
+ end
190
+
191
+ context "after a :TEXT: keyword prefixed with ';'" do
192
+ before :each do
193
+ @it << " ; :TEXT:\n"
194
+ end
195
+
196
+ it "should be in the :text state" do
197
+ @it.state.should == :text
198
+ end
199
+
200
+ end
201
+
202
+ context "given a :SAMPLE: keyword with a name" do
203
+ before :each do
204
+ @it << ":SAMPLE: foobar"
205
+ end
206
+
207
+ it "should file following code lines under the given name" do
208
+ @librarian.should_receive(:add_code!).with("foobar", "line 1")
209
+ @librarian.should_receive(:add_code!).with("foobar", "line 2")
210
+
211
+ @it << "line 1"
212
+ @it << "line 2"
213
+ end
214
+
215
+ context "given an escaped directive" do
216
+ it "should add the directive line as code" do
217
+ @librarian.should_receive(:add_code!).with("foobar", " # :TEXT: abc")
218
+ @it << " # \\:TEXT: abc"
219
+ end
220
+ end
221
+ end
222
+
223
+ context "given a :SAMPLE: keyword with custom brackets" do
224
+ before :each do
225
+ @line = ':SAMPLE: foobar, { brackets: ["<<", ">>"] }'
226
+ end
227
+
228
+ it "should assign custom bracket attributes to the sample" do
229
+ @librarian.should_receive(:set_code_attributes!).
230
+ with("foobar",
231
+ {
232
+ :code_open_bracket => "<<",
233
+ :code_close_bracket => ">>"
234
+ })
235
+
236
+ @it << @line
237
+ end
238
+ end
239
+
240
+ context "in text section with comment set" do
241
+ before :each do
242
+ @librarian.stub!(:comment_prefix_known?).and_return(true)
243
+ @librarian.stub!(:comment_prefix).and_return("#")
244
+ @it << "# :TEXT:\n"
245
+ @section = @it.current_section
246
+ end
247
+
248
+ it "should treat a commented line as more of the same section" do
249
+ @librarian.should_receive(:add_text!).
250
+ with(@section, "# commented text\n")
251
+ @it << "# commented text\n"
252
+ end
253
+
254
+ it "should treat a commented blank line as more of the same section" do
255
+ @librarian.should_receive(:add_text!).
256
+ with(@section, "# \n")
257
+ @it << "# \n"
258
+ end
259
+
260
+ it "should treat an uncommented blank line as more of the same section" do
261
+ @librarian.should_receive(:add_text!).
262
+ with(@section, " \n")
263
+ @it << " \n"
264
+ end
265
+
266
+ it "should treat an uncommented line as the start of code" do
267
+ @librarian.should_receive(:add_code!).
268
+ with(@section, "uncommented text\n")
269
+ @it << "uncommented text\n"
270
+ end
271
+ end
272
+
273
+ context "given an insertion with an explicit selector" do
274
+ before :each do
275
+ @it << ":TEXT: mysection"
276
+ @line = ":INSERT: foo"
277
+ end
278
+
279
+ it "should add an insertion to the current section" do
280
+ @librarian.should_receive(:add_insertion!).with("mysection", anything)
281
+ @it << @line
282
+ end
283
+
284
+ it "should pass a selector object to the librarian" do
285
+ @librarian.should_receive(:add_insertion!) do |section, selector|
286
+ selector.should be_a_kind_of(Selector)
287
+ selector.string.should == "foo"
288
+ selector.default_key.should == "mysection"
289
+ end
290
+ @it << @line
291
+ end
292
+ end
293
+
294
+ context "given a process directive" do
295
+ before :each do
296
+ @line = ' # :PROCESS: sortail, "sort | tail"'
297
+ end
298
+
299
+ it "should add the process to the library" do
300
+ @librarian.should_receive(:add_process!).with("sortail", "sort | tail")
301
+ @it << @line
302
+ end
303
+ end
304
+
305
+ end
306
+ end
@@ -0,0 +1,65 @@
1
+ require File.expand_path(
2
+ File.join(File.dirname(__FILE__), %w[.. .. lib germinate]))
3
+
4
+ module Germinate
5
+ describe Selector do
6
+ EXAMPLE_SELECTORS = [
7
+ # selector type key delim start end length pipeline
8
+ [ "@A", :code, "A", '..', 1, -1, nil, [] ],
9
+ [ "@A:1", :code, "A", nil, 1, 1, nil, [] ],
10
+ [ "", :code, "DEFAULT", '..', 1, -1, nil, [] ],
11
+ [ nil, :code, "DEFAULT", '..', 1, -1, nil, [] ],
12
+ [ ":2..4", :code, "DEFAULT", '..', 2, 4, nil, [] ],
13
+ [ ":2...4", :code, "DEFAULT", '...', 2, 4, nil, [] ],
14
+ [ "@B:2,5", :code, "B", ',', 2, nil,5, [] ],
15
+ [ "@B:/z/,6", :code, "B", ',', /z/, nil,6, [] ],
16
+ [ "@_:/z/../x/", :code, "_", '..', /z/, /x/,nil, [] ],
17
+ [ "@B:2,4|fnord",:code, "B", ',', 2, nil,4, ["fnord"]],
18
+ [ "$FOO", :special, "FOO", '..', 1, -1, nil, [] ],
19
+ [ "@A|foo|bar", :code, "A", '..', 1, -1, nil, ["foo", "bar"]],
20
+ ]
21
+
22
+ EXAMPLE_SELECTORS.each do |selector_attributes|
23
+ selector_string = selector_attributes[0]
24
+ type = selector_attributes[1]
25
+ key = selector_attributes[2]
26
+ delimiter = selector_attributes[3]
27
+ start = selector_attributes[4]
28
+ end_offset = selector_attributes[5]
29
+ length = selector_attributes[6]
30
+ pipeline = selector_attributes[7]
31
+
32
+ context "given selector '#{selector_attributes[0]}'" do
33
+ before :each do
34
+ @it = Germinate::Selector.new(selector_string, "DEFAULT")
35
+ end
36
+
37
+ it "should have string #{selector_string}" do
38
+ @it.string.should == selector_string
39
+ end
40
+
41
+ it "should have type #{type.inspect}" do
42
+ @it.selector_type.should == type
43
+ end
44
+ it "should have key #{key.inspect}" do
45
+ @it.key.should == key
46
+ end
47
+ it "should start at #{start.inspect}" do
48
+ @it.start_offset.should == start
49
+ end
50
+ it "should end at #{end_offset.inspect}" do
51
+ @it.end_offset.should == end_offset
52
+ end
53
+ it "should have length #{length.inspect}" do
54
+ @it.length.should == length
55
+ end
56
+ it "should have pipeline #{pipeline.inspect}" do
57
+ @it.pipeline.should == pipeline
58
+ end
59
+ it "should have delimiter #{delimiter.inspect}" do
60
+ @it.delimiter.should == delimiter
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end