devver-germinate 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -23,5 +23,6 @@ module Germinate
23
23
  @it.format_with(@formatter)
24
24
  end
25
25
  end
26
+
26
27
  end
27
28
  end
@@ -33,6 +33,7 @@ module Germinate
33
33
  @it.send(attribute).should == "test"
34
34
  end
35
35
  end
36
+
36
37
  end
37
38
 
38
39
  describe Hunk do
@@ -11,7 +11,8 @@ module Germinate
11
11
  end
12
12
 
13
13
  it "should use the library to resolve itself" do
14
- @library.should_receive(:[]).with(@selector).and_return(@hunk)
14
+ @library.should_receive(:[]).
15
+ with(@selector, anything, anything).and_return(@hunk)
15
16
  @it.resolve.should == @hunk
16
17
  end
17
18
  end
@@ -17,6 +17,10 @@ module Germinate
17
17
  end
18
18
 
19
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
+
20
24
  it "should not have a comment prefix" do
21
25
  @it.comment_prefix.should == nil
22
26
  @it.comment_prefix_known?.should be_false
@@ -88,7 +92,9 @@ module Germinate
88
92
 
89
93
  context "given an insertion in my_section with selector @my_selector" do
90
94
  before :each do
91
- @it.add_insertion!("my_section", "@my_selector", { :comment_prefix => "@" })
95
+ @it.disable_all_transforms!
96
+ @it.add_code!("my_sample", "line 1\n")
97
+ @it.add_insertion!("my_section", "@my_sample", { :comment_prefix => "@" })
92
98
  end
93
99
 
94
100
  it "should add an Insertion to the named section" do
@@ -96,7 +102,7 @@ module Germinate
96
102
  end
97
103
 
98
104
  it "should give the insertion the selector @my_selector" do
99
- @it.section("my_section").last.selector.to_s.should == "@my_selector"
105
+ @it.section("my_section").last.selector.to_s.should == "@my_sample"
100
106
  end
101
107
 
102
108
  it "should give the insertion a reference to the library" do
@@ -106,6 +112,11 @@ module Germinate
106
112
  it "should apply any passed attributes to the insertion" do
107
113
  @it.section("my_section").last.comment_prefix.should == "@"
108
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
109
120
  end
110
121
 
111
122
  context "given a process to file" do
@@ -113,8 +124,8 @@ module Germinate
113
124
  @it.add_process!("myproc", "cowsay")
114
125
  end
115
126
 
116
- it "should make the process available as a Process object" do
117
- @it.process("myproc").should be_a_kind_of(Germinate::Process)
127
+ it "should make the process available as a ShellProcess object" do
128
+ @it.process("myproc").should be_a_kind_of(Germinate::ShellProcess)
118
129
  end
119
130
 
120
131
  it "should store the process name" do
@@ -128,19 +139,29 @@ module Germinate
128
139
  it "should include the process when listing known processes" do
129
140
  @it.process_names.should include("myproc")
130
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
131
146
  end
132
147
 
133
148
  context "given a code sample and some processes" do
134
149
  before :each do
135
- @output_a = ["line 1a", "line 2a"]
136
- @output_b = ["line 1b", "line 2b"]
137
- @process_a = stub("Process A", :call => @output_a)
138
- @process_b = stub("Process B", :call => @output_b)
139
- Germinate::Process.stub!(:new).
140
- with("foo", "aaa").
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", {}).
141
162
  and_return(@process_a)
142
- Germinate::Process.stub!(:new).
143
- with("bar", "bbb").
163
+ Germinate::ShellProcess.stub!(:new).
164
+ with("bar", "bbb", {}).
144
165
  and_return(@process_b)
145
166
 
146
167
  @it.add_code!("A", "line 1")
@@ -155,7 +176,7 @@ module Germinate
155
176
  end
156
177
 
157
178
  it "should call the processes on the selected text" do
158
- @process_a.should_receive(:call).with(["line 1", "line 2"]).
179
+ @process_a.should_receive(:call).with(["line 1\n", "line 2\n"]).
159
180
  and_return(@output_a)
160
181
  @process_b.should_receive(:call).with(@output_a).
161
182
  and_return(@output_b)
@@ -163,6 +184,184 @@ module Germinate
163
184
  @it[@selector].should == ["line 1b", "line 2b"]
164
185
  end
165
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
166
365
  end
167
366
 
168
367
  context "given an assortment of lines" do
@@ -185,69 +384,69 @@ module Germinate
185
384
 
186
385
  it "should be able to retrieve all the lines in order" do
187
386
  @it.lines.should == [
188
- "FM 1",
189
- "FM 2",
190
- "CONTROL 1",
191
- "TEXT 1",
192
- "TEXT 2",
193
- "CONTROL 2",
194
- "CODE 1",
195
- "CONTROL 3",
196
- "TEXT 3",
197
- "TEXT 4",
198
- "CODE 2",
199
- "CODE 2l2",
200
- "CODE 2l3",
201
- "CODE 2l4",
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",
202
401
  ]
203
402
  end
204
403
 
205
404
  it "should be able to retrieve text lines" do
206
405
  @it.text_lines.should == [
207
- "TEXT 1",
208
- "TEXT 2",
209
- "TEXT 3",
210
- "TEXT 4"
406
+ "TEXT 1\n",
407
+ "TEXT 2\n",
408
+ "TEXT 3\n",
409
+ "TEXT 4\n"
211
410
  ]
212
411
  end
213
412
 
214
413
  it "should be able to retrieve code lines" do
215
414
  @it.code_lines.should == [
216
- "CODE 1",
217
- "CODE 2",
218
- "CODE 2l2",
219
- "CODE 2l3",
220
- "CODE 2l4",
415
+ "CODE 1\n",
416
+ "CODE 2\n",
417
+ "CODE 2l2\n",
418
+ "CODE 2l3\n",
419
+ "CODE 2l4\n",
221
420
  ]
222
421
  end
223
422
 
224
423
  it "should be able to retrieve front matter" do
225
424
  @it.front_matter_lines.should == [
226
- "FM 1",
227
- "FM 2",
425
+ "FM 1\n",
426
+ "FM 2\n",
228
427
  ]
229
428
  end
230
429
 
231
430
  it "should be able to retrieve text by section" do
232
431
  @it.section("SECTION1").should == [
233
- "TEXT 1",
234
- "TEXT 2"
432
+ "TEXT 1\n",
433
+ "TEXT 2\n"
235
434
  ]
236
435
  @it.section("SECTION2").should == [
237
- "TEXT 3",
238
- "TEXT 4"
436
+ "TEXT 3\n",
437
+ "TEXT 4\n"
239
438
  ]
240
439
  end
241
440
 
242
441
  it "should be able to retrieve code by sample name" do
243
442
  @it.sample("SECTION1").should == [
244
- "CODE 1"
443
+ "CODE 1\n"
245
444
  ]
246
445
  @it.sample("SECTION2").should == [
247
- "CODE 2",
248
- "CODE 2l2",
249
- "CODE 2l3",
250
- "CODE 2l4",
446
+ "CODE 2\n",
447
+ "CODE 2l2\n",
448
+ "CODE 2l3\n",
449
+ "CODE 2l4\n",
251
450
  ]
252
451
  end
253
452
 
@@ -276,8 +475,8 @@ module Germinate
276
475
  end
277
476
 
278
477
  it "should be able to retrieve lines using a selector" do
279
- @it[Selector.new("@SECTION1", nil)].should == ["CODE 1"]
280
- @it["@SECTION1"].should == ["CODE 1"]
478
+ @it[Selector.new("@SECTION1", nil)].should == ["CODE 1\n"]
479
+ @it["@SECTION1"].should == ["CODE 1\n"]
281
480
  end
282
481
 
283
482
  context "given the $SOURCE selector with no subscripts" do
@@ -297,50 +496,46 @@ module Germinate
297
496
 
298
497
  SELECTOR_EXAMPLES = [
299
498
  # Selector Expected Excerpt Expected Type
300
- [ "@SECTION1", ["CODE 1"], CodeHunk ],
301
- [ "@SECTION2:1", ["CODE 2"], CodeHunk ],
302
- [ "@SECTION2:2..3", ["CODE 2l2", "CODE 2l3"], CodeHunk ],
303
- [ "@SECTION2:2,2", ["CODE 2l2", "CODE 2l3"], CodeHunk ],
304
- [ "@SECTION2:/l2/../l3/", ["CODE 2l2", "CODE 2l3"], CodeHunk ],
305
- [ "@SECTION2:/l2/.../l3/", ["CODE 2l2"], CodeHunk ],
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 ],
306
505
  [ "@SECTION2:/2/,3", [
307
- "CODE 2",
308
- "CODE 2l2",
309
- "CODE 2l3"], CodeHunk ],
506
+ "CODE 2\n",
507
+ "CODE 2l2\n",
508
+ "CODE 2l3\n"], CodeHunk ],
310
509
  [ "@SECTION2:/l2/..-1", [
311
- "CODE 2l2",
312
- "CODE 2l3",
313
- "CODE 2l4"], CodeHunk ],
510
+ "CODE 2l2\n",
511
+ "CODE 2l3\n",
512
+ "CODE 2l4\n"], CodeHunk ],
314
513
  [ "$CODE", [
315
- "CODE 1",
316
- "CODE 2",
317
- "CODE 2l2",
318
- "CODE 2l3",
319
- "CODE 2l4", ], CodeHunk
514
+ "CODE 1\n",
515
+ "CODE 2\n",
516
+ "CODE 2l2\n",
517
+ "CODE 2l3\n",
518
+ "CODE 2l4\n", ], CodeHunk
320
519
  ],
321
520
  [ "$SOURCE", [
322
- "FM 1",
323
- "FM 2",
324
- "CONTROL 1",
325
- "TEXT 1",
326
- "TEXT 2",
327
- "CONTROL 2",
328
- "CODE 1",
329
- "CONTROL 3",
330
- "TEXT 3",
331
- "TEXT 4",
332
- "CODE 2",
333
- "CODE 2l2",
334
- "CODE 2l3",
335
- "CODE 2l4",
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",
336
535
  ], FileHunk
337
536
  ],
338
537
  [ "$TEXT", [
339
- "TEXT 1",
340
- "TEXT 2",
341
- "TEXT 3",
342
- "TEXT 4"
343
- ], CodeHunk
538
+ "TEXT 1 TEXT 2 TEXT 3 TEXT 4" ], TextHunk
344
539
  ],
345
540
 
346
541
  ]