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
@@ -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
  ]