devver-germinate 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,13 @@
1
+ == 1.1.0 / 2009-07-12
2
+
3
+ * 1 major enhancement
4
+ * Added post-pipeline excerpting, e.g. $SOURCE|ruby:/def foo/../end/
5
+ Post-pipeline excerpting executes the process against the entire sample and
6
+ then excerpts the output.
7
+ * 1 minor enhancement
8
+ * Processes applied to $SOURCE will be given the actual source path instead of
9
+ a temp file
10
+
1
11
  == 1.0.0 / 2009-07-06
2
12
 
3
13
  * 1 major enhancement
data/TODO ADDED
@@ -0,0 +1,71 @@
1
+ # -*- mode: org -*-
2
+ #+SEQ_TODO: TODO | DONE INVALID
3
+
4
+ * INVALID Fix bug in `germ select` :bug:
5
+ CLOSED: [2009-07-12 Sun 18:25]
6
+ : germ select -s "$SOURCE|ruby" ruby_subprocesses_part_2.rb
7
+ : F, [2009-07-12T17:41:17.331337 #19506] FATAL -- : No code sample named 'SECTION0'. Known samples: helpers, SECTION3, open_with_pipe, open_with_pipe_dash, popen, popen_with_dash, SECTION8 (IndexError)
8
+
9
+ <2009-07-12 Sun> My mistake... the shell was interpreting the $SOURCE directive.
10
+
11
+ * DONE Make $SOURCE use the actual source file path in processes
12
+ CLOSED: [2009-07-12 Sun 19:46]
13
+
14
+ * TODO Improve error message for non-matching regexen in selectors :usability:
15
+
16
+ * TODO Output line numbers for Reader errors :usability:
17
+
18
+ * TODO Gist uploads :feature:
19
+
20
+ * TODO Publishing to WordPress blogs (Atompub) :feature:
21
+
22
+ * TODO Alternate directive syntax :usability:
23
+ one that doesn't conflict with RDoc
24
+
25
+ * TODO Anonymous processes :feature:
26
+ A process that doesn't match a predefined process name should be interpreted
27
+ as a shell command.
28
+
29
+ * TODO Code indent :feature:
30
+ Define an indent (either N spaces or a string) to be applied to code sections.
31
+
32
+ Should first de-indent code.
33
+
34
+ * TODO Shorthand for matching whitespace in selectors :feature:
35
+ e.g. "@mysample:/def foo/..._"
36
+
37
+ * TODO Format Pipelines :feature:
38
+ Define a pipeline to be run on the entire article after formatting
39
+
40
+ * TODO ERB Substitution :feature:
41
+ Should be run on TEXT sections.
42
+
43
+ * TODO Line# Helper :feature:
44
+ A helper for ERB subtitution which inserts the line# of a given selector.
45
+
46
+ * TODO Plugin API :feature:
47
+ Should use gems to discover plugins.
48
+
49
+ * TODO User-global preference file :feature:
50
+
51
+ * TODO Multiple file support :feature:
52
+
53
+ * TODO Output line numbers for errors at any point :usability:
54
+ This will require giving Hunks the knowledge of their source offset.
55
+
56
+ * TODO Nested samples :feature:
57
+ Might want to wait this on the implementation of nested states in AlterEgo.
58
+
59
+ * TODO Optionally capture STDERR from processes :feature:
60
+
61
+ Workaround: Authors can just include 2>&1 in their process definitions.
62
+
63
+ * DONE Syntax for post-process excerpting
64
+ CLOSED: [2009-07-12 Sun 20:50]
65
+ E.g. "$SOURCE|ruby:/---/../---/"
66
+
67
+ This would cause the process to be run on $SOURCE and then a subset of the
68
+ output to be excerpted.
69
+
70
+ * TODO Named Styles
71
+ A way to group together a bunch of style attributes in a reusable way.
data/bin/germ CHANGED
@@ -44,9 +44,9 @@ Main do
44
44
  source_argument
45
45
  def run
46
46
  Germinate.logger = self
47
- with_source_file do |source|
47
+ with_source_file do |source, path|
48
48
  application = Germinate::Application.new
49
- application.format(source, $stdout, $stderr)
49
+ application.format(source, path, $stdout, $stderr)
50
50
  end
51
51
  end
52
52
  end
@@ -67,9 +67,9 @@ Main do
67
67
  COLLECTIONS.each do |collection|
68
68
  things_to_list << collection if params[collection].value
69
69
  end
70
- with_source_file do |source|
70
+ with_source_file do |source, path|
71
71
  application = Germinate::Application.new
72
- application.list(source, things_to_list, $stdout)
72
+ application.list(source, path, things_to_list, $stdout)
73
73
  end
74
74
  end
75
75
  end
@@ -90,9 +90,9 @@ Main do
90
90
  sel[type] = params[type].values
91
91
  sel
92
92
  }
93
- with_source_file do |source|
93
+ with_source_file do |source, path|
94
94
  application = Germinate::Application.new
95
- application.show(source, selection, $stdout)
95
+ application.show(source, path, selection, $stdout)
96
96
  end
97
97
  end
98
98
  end
@@ -108,9 +108,9 @@ Main do
108
108
  end
109
109
 
110
110
  def run
111
- with_source_file do |source|
111
+ with_source_file do |source, path|
112
112
  application = Germinate::Application.new
113
- application.select(source, params[:selector].value, $stdout)
113
+ application.select(source, path, params[:selector].value, $stdout)
114
114
  end
115
115
  end
116
116
  end
@@ -125,8 +125,11 @@ Main do
125
125
  end
126
126
  end
127
127
 
128
- def with_source_file(&block)
129
- File.open(params['source'].value, &block)
128
+ def with_source_file
129
+ path = params['source'].value
130
+ File.open(path) do |file|
131
+ yield file, path
132
+ end
130
133
  end
131
134
  end
132
135
 
@@ -106,4 +106,6 @@ Feature: author formats article
106
106
  | pipelines.txt | pipelines.out |
107
107
  | escaping.txt | escaping.out |
108
108
  | bracketing.rb | bracketing.out |
109
+ | stderr.rb | stderr.out |
110
+ | excerpt_output.rb | excerpt_output.out |
109
111
 
@@ -0,0 +1,16 @@
1
+ # We can excerpt the output of a command instead of running the command on an
2
+ # excerpt.
3
+ # :PROCESS: ruby, "ruby %f"
4
+ # :SAMPLE:
5
+
6
+ puts "-" * 3
7
+ puts "line 1"
8
+ puts "-" * 5
9
+
10
+ puts "=" * 3
11
+ puts "line 2"
12
+ puts "=" * 5
13
+
14
+ # :TEXT:
15
+ # :INSERT: $SOURCE|ruby:/===/../=====/
16
+ # :INSERT: $SOURCE|ruby:/---/../-----/
@@ -0,0 +1,10 @@
1
+ # We can capture both STDOUT and STDERR by using shell modifiers
2
+ # :PROCESS: ruby, "ruby %f 2>&1"
3
+ # :SAMPLE: output
4
+ $stdout.sync = true
5
+ $stdout.puts "Hello, STDOUT"
6
+ $stderr.puts "Hello, STDERR"
7
+ $stdout.puts "Hello again, STDOUT"
8
+
9
+ # :TEXT:
10
+ # :INSERT: $SOURCE|ruby
@@ -0,0 +1,6 @@
1
+ ===
2
+ line 2
3
+ =====
4
+ ---
5
+ line 1
6
+ -----
@@ -0,0 +1,3 @@
1
+ Hello, STDOUT
2
+ Hello, STDERR
3
+ Hello again, STDOUT
@@ -19,10 +19,13 @@ Then /^the output should look like "([^\"]*)"$/ do |output_file|
19
19
  end
20
20
 
21
21
  Given /^an article with the contents:$/ do |contents|
22
- Tempfile.open("germinate_example_article") do |file|
23
- file.write(contents)
24
- @filename = Pathname(file.path)
22
+ file = Tempfile.open("germinate_example_article")
23
+ file.write(contents)
24
+ file.close
25
+ at_exit do
26
+ file.delete
25
27
  end
28
+ @filename = Pathname(file.path)
26
29
  end
27
30
 
28
31
  Then /^the output should be as follows:$/ do |example_output|
@@ -16,3 +16,5 @@ def run_germinate(arguments, permit_failure=false)
16
16
  @result = $CHILD_STATUS
17
17
  raise "Command `#{command}` failed" unless @result.success? or permit_failure
18
18
  end
19
+
20
+
data/germinate.gemspec CHANGED
@@ -2,17 +2,17 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{germinate}
5
- s.version = "1.0.1"
5
+ s.version = "1.1.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Avdi Grimm"]
9
- s.date = %q{2009-07-10}
9
+ s.date = %q{2009-07-13}
10
10
  s.default_executable = %q{germ}
11
11
  s.description = %q{Germinate is a tool for writing about code. With Germinate, the source code IS the article. For example, given the following source code: # #!/usr/bin/env ruby # :BRACKET_CODE: <pre>, </pre> # :PROCESS: ruby, "ruby %f" # :SAMPLE: hello def hello(who) puts "Hello, #{who}" end hello("World") # :TEXT: # Check out my amazing program! Here's the hello method: # :INSERT: @hello:/def/../end/ # And here's the output: # :INSERT: @hello|ruby When we run the <tt>germ format</tt> command the following output is generated: Check out my amazing program! Here's the hello method: <pre> def hello(who) puts "Hello, #{who}" end </pre> And here's the output: <pre> Hello, World </pre> To get a better idea of how this works, please take a look at link:examples/basic.rb, or run: germ generate > basic.rb To generate an example article to play with. Germinate is particularly useful for writing articles, such as blog posts, which contain code excerpts. Instead of forcing you to keep a source code file and an article document in sync throughout the editing process, the Germinate motto is "The source code IS the article". Specially marked comment sections in your code file become the article text. Wherever you need to reference the source code in the article, use insertion directives to tell Germinate what parts of the code to excerpt. An advanced selector syntax enables you to be very specific about which lines of code you want to insert. If you also want to show the output of your code, Germinate has you covered. Special "process" directives enable you to define arbitrary commands which can be run on your code. The output of the command then becomes the excerpt text. You can define an arbitrary number of processes and have different excerpts showing the same code as processed by different commands. You can even string processes together into pipelines. Development of Germinate is graciously sponsored by Devver, purveyor of fine cloud-based services to busy Ruby developers. If you like this tool please check them out at http://devver.net.}
12
12
  s.email = %q{avdi@avdi.org}
13
13
  s.executables = ["germ"]
14
14
  s.extra_rdoc_files = ["History.txt", "README.rdoc", "bin/germ"]
15
- s.files = [".gitignore", "History.txt", "README.rdoc", "Rakefile", "bin/germ", "cucumber.yml", "examples/basic.rb", "examples/short.rb", "features/author-formats-article.feature", "features/author-lists-info.feature", "features/author-publishes-article-source.feature", "features/author-publishes-article.feature", "features/author-republishes-article.feature", "features/author-selects-hunks.feature", "features/author-updates-article-source.feature", "features/author-views-stuff.feature", "features/bin/quoter", "features/bin/sorter", "features/example_articles/bracketing.rb", "features/example_articles/escaping.txt", "features/example_articles/hello.rb", "features/example_articles/pipelines.txt", "features/example_articles/regexen.rb", "features/example_articles/sample_offsets.rb", "features/example_articles/specials.rb", "features/example_articles/wrapping.rb", "features/example_output/bracketing.out", "features/example_output/code_samples.txt", "features/example_output/escaping.out", "features/example_output/hello.txt", "features/example_output/pipelines.out", "features/example_output/regexen.txt", "features/example_output/sample_offsets.txt", "features/example_output/specials.txt", "features/example_output/wrapping.txt", "features/step_definitions/germinate.rb", "features/support/env.rb", "germinate.gemspec", "lib/germinate.rb", "lib/germinate/application.rb", "lib/germinate/article_editor.rb", "lib/germinate/article_formatter.rb", "lib/germinate/formatter.rb", "lib/germinate/hunk.rb", "lib/germinate/implicit_insertion.rb", "lib/germinate/insertion.rb", "lib/germinate/librarian.rb", "lib/germinate/pipeline.rb", "lib/germinate/process.rb", "lib/germinate/reader.rb", "lib/germinate/selector.rb", "lib/germinate/shared_style_attributes.rb", "lib/germinate/text_transforms.rb", "spec/germinate/application_spec.rb", "spec/germinate/article_editor_spec.rb", "spec/germinate/article_formatter_spec.rb", "spec/germinate/code_hunk_spec.rb", "spec/germinate/formatter_spec.rb", "spec/germinate/hunk_spec.rb", "spec/germinate/implicit_insertion_spec.rb", "spec/germinate/insertion_spec.rb", "spec/germinate/librarian_spec.rb", "spec/germinate/pipeline_spec.rb", "spec/germinate/process_spec.rb", "spec/germinate/reader_spec.rb", "spec/germinate/selector_spec.rb", "spec/germinate/text_hunk_spec.rb", "spec/germinate/text_transforms_spec.rb", "spec/germinate_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/ann.rake", "tasks/bones.rake", "tasks/cucumber.rake", "tasks/gem.rake", "tasks/git.rake", "tasks/notes.rake", "tasks/post_load.rake", "tasks/rdoc.rake", "tasks/rubyforge.rake", "tasks/setup.rb", "tasks/spec.rake", "tasks/svn.rake", "tasks/test.rake", "tasks/zentest.rake", "test/test_germinate.rb"]
15
+ s.files = [".gitignore", "History.txt", "README.rdoc", "Rakefile", "TODO", "bin/germ", "cucumber.yml", "examples/basic.rb", "examples/short.rb", "features/author-formats-article.feature", "features/author-lists-info.feature", "features/author-publishes-article-source.feature", "features/author-publishes-article.feature", "features/author-republishes-article.feature", "features/author-selects-hunks.feature", "features/author-updates-article-source.feature", "features/author-views-stuff.feature", "features/bin/quoter", "features/bin/sorter", "features/example_articles/bracketing.rb", "features/example_articles/escaping.txt", "features/example_articles/excerpt_output.rb", "features/example_articles/hello.rb", "features/example_articles/pipelines.txt", "features/example_articles/regexen.rb", "features/example_articles/sample_offsets.rb", "features/example_articles/specials.rb", "features/example_articles/stderr.rb", "features/example_articles/wrapping.rb", "features/example_output/bracketing.out", "features/example_output/code_samples.txt", "features/example_output/escaping.out", "features/example_output/excerpt_output.out", "features/example_output/hello.txt", "features/example_output/pipelines.out", "features/example_output/regexen.txt", "features/example_output/sample_offsets.txt", "features/example_output/specials.txt", "features/example_output/stderr.out", "features/example_output/wrapping.txt", "features/step_definitions/germinate.rb", "features/support/env.rb", "germinate.gemspec", "lib/germinate.rb", "lib/germinate/application.rb", "lib/germinate/article_editor.rb", "lib/germinate/article_formatter.rb", "lib/germinate/formatter.rb", "lib/germinate/hunk.rb", "lib/germinate/implicit_insertion.rb", "lib/germinate/insertion.rb", "lib/germinate/librarian.rb", "lib/germinate/pipeline.rb", "lib/germinate/process.rb", "lib/germinate/reader.rb", "lib/germinate/selector.rb", "lib/germinate/shared_style_attributes.rb", "lib/germinate/text_transforms.rb", "spec/germinate/application_spec.rb", "spec/germinate/article_editor_spec.rb", "spec/germinate/article_formatter_spec.rb", "spec/germinate/code_hunk_spec.rb", "spec/germinate/file_hunk_spec.rb", "spec/germinate/formatter_spec.rb", "spec/germinate/hunk_spec.rb", "spec/germinate/implicit_insertion_spec.rb", "spec/germinate/insertion_spec.rb", "spec/germinate/librarian_spec.rb", "spec/germinate/pipeline_spec.rb", "spec/germinate/process_spec.rb", "spec/germinate/reader_spec.rb", "spec/germinate/selector_spec.rb", "spec/germinate/text_hunk_spec.rb", "spec/germinate/text_transforms_spec.rb", "spec/germinate_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/ann.rake", "tasks/bones.rake", "tasks/cucumber.rake", "tasks/gem.rake", "tasks/git.rake", "tasks/notes.rake", "tasks/post_load.rake", "tasks/rdoc.rake", "tasks/rubyforge.rake", "tasks/setup.rb", "tasks/spec.rake", "tasks/svn.rake", "tasks/test.rake", "tasks/zentest.rake", "test/test_germinate.rb"]
16
16
  s.has_rdoc = true
17
17
  s.homepage = %q{http://github.com/devver/germinate/}
18
18
  s.rdoc_options = ["--main", "README.rdoc"]
data/lib/germinate.rb CHANGED
@@ -5,7 +5,7 @@ require 'logger'
5
5
  module Germinate
6
6
 
7
7
  # :stopdoc:
8
- VERSION = '1.0.1'
8
+ VERSION = '1.1.0'
9
9
  LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
10
10
  PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
11
11
  # :startdoc:
@@ -3,8 +3,8 @@
3
3
  class Germinate::Application
4
4
  attr_writer :formatter
5
5
 
6
- def format(source, output=$stdout, errors=$stderr)
7
- librarian = load_librarian(source)
6
+ def format(source, path, output=$stdout, errors=$stderr)
7
+ librarian = load_librarian(source, path)
8
8
  editor = Germinate::ArticleEditor.new(librarian)
9
9
  formatter = Germinate::ArticleFormatter.new(output)
10
10
 
@@ -19,8 +19,8 @@ class Germinate::Application
19
19
  formatter.finish!
20
20
  end
21
21
 
22
- def list(source, things_to_list, output=$stdout)
23
- librarian = load_librarian(source)
22
+ def list(source, path, things_to_list, output=$stdout)
23
+ librarian = load_librarian(source, path)
24
24
  if things_to_list.include?(:sections)
25
25
  output.puts(librarian.section_names.join("\n"))
26
26
  end
@@ -32,8 +32,8 @@ class Germinate::Application
32
32
  end
33
33
  end
34
34
 
35
- def show(source, selection, output=$stdout)
36
- librarian = load_librarian(source)
35
+ def show(source, path, selection, output=$stdout)
36
+ librarian = load_librarian(source, path)
37
37
  selection.fetch(:section, []).each do |section|
38
38
  output.puts(*librarian.section(section))
39
39
  end
@@ -45,15 +45,15 @@ class Germinate::Application
45
45
  end
46
46
  end
47
47
 
48
- def select(source, selector, output=$stdout)
49
- librarian = load_librarian(source)
48
+ def select(source, path, selector, output=$stdout)
49
+ librarian = load_librarian(source, path)
50
50
  output.puts(*librarian[selector])
51
51
  end
52
52
  private
53
53
 
54
- def load_librarian(source)
54
+ def load_librarian(source, path)
55
55
  librarian = Germinate::Librarian.new
56
- reader = Germinate::Reader.new(librarian)
56
+ reader = Germinate::Reader.new(librarian, path)
57
57
  source.each_line do |line|
58
58
  reader << line
59
59
  end
@@ -1,4 +1,6 @@
1
+ require 'pathname'
1
2
  require 'ick'
3
+ require 'fattr'
2
4
  require File.expand_path("shared_style_attributes", File.dirname(__FILE__))
3
5
 
4
6
  # A Hunk represents a chunk of content. There are different types of Hunk, like
@@ -11,7 +13,7 @@ class Germinate::Hunk < ::Array
11
13
 
12
14
  def initialize(contents=[], template = {})
13
15
  super(contents)
14
- copy_shared_style_attrubutes_from(template)
16
+ copy_shared_style_attributes_from(template)
15
17
  end
16
18
 
17
19
  # return a copy with leading and trailing whitespace lines removed
@@ -51,7 +53,7 @@ class Germinate::Hunk < ::Array
51
53
  def [](*args)
52
54
  returning(super) do |slice|
53
55
  if slice.kind_of?(Germinate::Hunk)
54
- slice.copy_shared_style_attrubutes_from(self)
56
+ slice.copy_shared_style_attributes_from(self)
55
57
  end
56
58
  end
57
59
  end
@@ -59,7 +61,7 @@ class Germinate::Hunk < ::Array
59
61
  def slice(*args)
60
62
  returning(super) do |slice|
61
63
  if slice.kind_of?(Germinate::Hunk)
62
- slice.copy_shared_style_attrubutes_from(self)
64
+ slice.copy_shared_style_attributes_from(self)
63
65
  end
64
66
  end
65
67
  end
@@ -71,6 +73,10 @@ class Germinate::Hunk < ::Array
71
73
  nil
72
74
  end
73
75
 
76
+ def whole_file?
77
+ false
78
+ end
79
+
74
80
  private
75
81
 
76
82
  def resolved?
@@ -113,6 +119,7 @@ class Germinate::Hunk < ::Array
113
119
 
114
120
  end
115
121
 
122
+ # Represents a hunk of article text
116
123
  class Germinate::TextHunk < Germinate::Hunk
117
124
  def format_with(formatter)
118
125
  super(formatter) do |formatter|
@@ -121,6 +128,7 @@ class Germinate::TextHunk < Germinate::Hunk
121
128
  end
122
129
  end
123
130
 
131
+ # Represents a hunk of source code
124
132
  class Germinate::CodeHunk < Germinate::Hunk
125
133
  def code_open_bracket=(new_value)
126
134
  super
@@ -141,3 +149,15 @@ end
141
149
  class Germinate::NullHunk < Germinate::Hunk
142
150
  end
143
151
 
152
+ # Represents a the entire text of a file on disk
153
+ class Germinate::FileHunk < Germinate::CodeHunk
154
+ def initialize(lines, template)
155
+ super(lines, template)
156
+ raise ArgumentError, "Path required" if source_path.nil?
157
+ end
158
+
159
+ def whole_file?
160
+ true
161
+ end
162
+ end
163
+
@@ -8,14 +8,14 @@ class Germinate::Insertion
8
8
  attr_reader :selector
9
9
 
10
10
  def initialize(selector, library, template={})
11
- copy_shared_style_attrubutes_from(template)
11
+ copy_shared_style_attributes_from(template)
12
12
  @selector = selector
13
13
  @library = library
14
14
  end
15
15
 
16
16
  def resolve
17
17
  returning(library[selector]) do |hunk|
18
- hunk.copy_shared_style_attrubutes_from(self, false)
18
+ hunk.copy_shared_style_attributes_from(self, false)
19
19
  end
20
20
  end
21
21
  end
@@ -13,6 +13,8 @@ class Germinate::Librarian
13
13
  attr_reader :code_lines
14
14
  attr_reader :front_matter_lines
15
15
 
16
+ fattr :source_path => nil
17
+
16
18
  fattr(:log) { Germinate.logger }
17
19
 
18
20
  def initialize
@@ -114,7 +116,12 @@ class Germinate::Librarian
114
116
  when :code then sample(selector.key)
115
117
  when :special then
116
118
  case selector.key
117
- when "SOURCE" then Germinate::CodeHunk.new(lines, self)
119
+ when "SOURCE"
120
+ if selector.whole?
121
+ Germinate::FileHunk.new(lines, self)
122
+ else
123
+ Germinate::CodeHunk.new(lines, self)
124
+ end
118
125
  when "CODE" then Germinate::CodeHunk.new(code_lines, self)
119
126
  when "TEXT" then Germinate::CodeHunk.new(text_lines, self)
120
127
  else raise "Unknown special section '$#{selector.key}'"
@@ -155,7 +162,12 @@ class Germinate::Librarian
155
162
  offset = selector.start_offset_for_slice
156
163
  case offset
157
164
  when Integer then offset
158
- when Regexp then hunk.index_matching(offset)
165
+ when Regexp then
166
+ returning(hunk.index_matching(offset)) do |offset|
167
+ if offset.nil?
168
+ raise "Cannot find line matching #{offset.inspect}"
169
+ end
170
+ end
159
171
  else
160
172
  raise "Don't know how to use #{offset.inspect} as an offset"
161
173
  end
@@ -166,7 +178,11 @@ class Germinate::Librarian
166
178
  case offset
167
179
  when Integer, nil then offset
168
180
  when Regexp then
169
- hunk.index_matching(offset, start_offset)
181
+ returning(hunk.index_matching(offset, start_offset)) do |offset|
182
+ if offset.nil?
183
+ raise "Cannot find line matching #{offset.inspect}"
184
+ end
185
+ end
170
186
  else
171
187
  raise "Don't know how to use #{offset.inspect} as an offset"
172
188
  end
@@ -19,6 +19,8 @@ class Germinate::Process
19
19
  def call(input)
20
20
  if pipe?
21
21
  call_command_in_pipe(input)
22
+ elsif input.whole_file?
23
+ call_command_on_source_file(input)
22
24
  else
23
25
  call_command_on_temp_file(input)
24
26
  end
@@ -48,6 +50,12 @@ class Germinate::Process
48
50
  end
49
51
  end
50
52
 
53
+ def call_command_on_source_file(input)
54
+ log_popen(substitute_filename(command, input.source_path), 'r') do |process|
55
+ return Germinate::CodeHunk.new(process.readlines, input)
56
+ end
57
+ end
58
+
51
59
  def pipe?
52
60
  !command.include?("%f")
53
61
  end
@@ -57,11 +57,13 @@ class Germinate::Reader
57
57
 
58
58
  end
59
59
 
60
- def initialize(librarian)
60
+ def initialize(librarian, source_path=nil)
61
61
  @librarian = librarian
62
62
  @section_count = 0
63
63
  @current_section = "SECTION0"
64
64
  @line_number = 1
65
+ @source_path = source_path ? Pathname(source_path) : nil
66
+ librarian.source_path = @source_path
65
67
  end
66
68
 
67
69
  # Read a line
@@ -9,7 +9,8 @@ class Germinate::Selector
9
9
  attr_reader :pipeline
10
10
  attr_reader :default_key
11
11
 
12
- PATTERN = /([@$])?(\w+)?(:([^\s\|]+))?(\|([\w|]+))?/
12
+ PATTERN = /^([@$])?(\w+)?(:([^\s\|]+))?(\|([\w|]+))?$/
13
+ EXCERPT_OUTPUT_PATTERN = /^([@$])?(\w+)?(\|([\w|]+))?(:([^\s\|]+))?$/
13
14
  EXCERPT_PATTERN = %r{((-?\d+)|(/[^/]*/))(((\.\.\.?)|(,))((-?\d+)|(/[^/]*/)))?}
14
15
 
15
16
  def initialize(string, default_key)
@@ -17,9 +18,20 @@ class Germinate::Selector
17
18
  @default_key = default_key
18
19
  match_data = case string
19
20
  when "", nil then {}
20
- else PATTERN.match(string)
21
+ else
22
+ if data = PATTERN.match(string)
23
+ @excerpt_output = false
24
+ elsif data = EXCERPT_OUTPUT_PATTERN.match(string)
25
+ @excerpt_output = true
26
+ else
27
+ raise "Could not parse selector '#{string}'"
28
+ end
29
+ data
21
30
  end
22
31
 
32
+ subscript_index = @excerpt_output ? 6 : 3
33
+ pipeline_index = @excerpt_output ? 4 : 6
34
+
23
35
  @selector_type =
24
36
  case match_data[1]
25
37
  when "$" then :special
@@ -27,15 +39,17 @@ class Germinate::Selector
27
39
  else raise "Unknown selector type '#{match_data[1]}'"
28
40
  end
29
41
  @key = match_data[2] || default_key
30
- if match_data[3]
31
- parse_excerpt(match_data[3])
42
+ if match_data[subscript_index]
43
+ @slice = true
44
+ parse_excerpt(match_data[subscript_index])
32
45
  else
46
+ @slice = false
33
47
  @delimiter = '..'
34
48
  @start_offset = 1
35
49
  @end_offset = -1
36
50
  @length = nil
37
51
  end
38
- @pipeline = String(match_data[6]).split("|")
52
+ @pipeline = String(match_data[pipeline_index]).split("|")
39
53
  end
40
54
 
41
55
  def start_offset_for_slice
@@ -46,6 +60,21 @@ class Germinate::Selector
46
60
  offset_for_slice(end_offset)
47
61
  end
48
62
 
63
+ # Should excerpting be done on the output of the process?
64
+ def excerpt_output?
65
+ @excerpt_output
66
+ end
67
+
68
+ # Is it just a subset of the source hunk? (opposite of @whole?)
69
+ def slice?
70
+ @slice && !@excerpt_output
71
+ end
72
+
73
+ # Is it the entire hunk? (opposite of #slice?)
74
+ def whole?
75
+ !slice?
76
+ end
77
+
49
78
  private
50
79
 
51
80
  def parse_excerpt(excerpt)
@@ -5,6 +5,7 @@ module Germinate::SharedStyleAttributes
5
5
  fattr :code_open_bracket => nil
6
6
  fattr :code_close_bracket => nil
7
7
  fattr :pipeline => []
8
+ fattr :source_path => nil
8
9
 
9
10
  def shared_style_attributes
10
11
  Germinate::SharedStyleAttributes.fattrs.inject({}) {
@@ -15,7 +16,7 @@ module Germinate::SharedStyleAttributes
15
16
  }
16
17
  end
17
18
 
18
- def copy_shared_style_attrubutes_from(other, override=true)
19
+ def copy_shared_style_attributes_from(other, override=true)
19
20
  case other
20
21
  when Germinate::SharedStyleAttributes
21
22
  copy_attributes!(other.shared_style_attributes)
@@ -0,0 +1,27 @@
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
+ end
27
+ end
@@ -40,6 +40,12 @@ module Germinate
40
40
  @it = Hunk.new
41
41
  end
42
42
 
43
+ it "should not have a source path" do
44
+ @it.source_path.should be_nil
45
+ end
46
+
47
+ specify { @it.should_not be_whole_file }
48
+
43
49
  context "with an insertion" do
44
50
  before :each do
45
51
  @nested_hunk = stub("Nested Hunk")
@@ -9,6 +9,11 @@ module Germinate
9
9
  describe Librarian do
10
10
  before :each do
11
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"
12
17
  end
13
18
 
14
19
  context "by default" do
@@ -275,6 +280,21 @@ module Germinate
275
280
  @it["@SECTION1"].should == ["CODE 1"]
276
281
  end
277
282
 
283
+ context "given the $SOURCE selector with no subscripts" do
284
+ before :each do
285
+ @hunk = @it["$SOURCE"]
286
+ end
287
+
288
+ it "should return a FileHunk" do
289
+ @hunk.should be_a_kind_of(FileHunk)
290
+ end
291
+
292
+ it "should return a FileHunk with the source file path set" do
293
+ @hunk.source_path.should == "SOURCE_PATH"
294
+ end
295
+
296
+ end
297
+
278
298
  SELECTOR_EXAMPLES = [
279
299
  # Selector Expected Excerpt Expected Type
280
300
  [ "@SECTION1", ["CODE 1"], CodeHunk ],
@@ -313,7 +333,7 @@ module Germinate
313
333
  "CODE 2l2",
314
334
  "CODE 2l3",
315
335
  "CODE 2l4",
316
- ], CodeHunk
336
+ ], FileHunk
317
337
  ],
318
338
  [ "$TEXT", [
319
339
  "TEXT 1",
@@ -60,5 +60,21 @@ module Germinate
60
60
  end
61
61
 
62
62
  end
63
+
64
+ context "given a command 'mycommand %f' and called on a file hunk" do
65
+ before :each do
66
+ @input = Germinate::FileHunk.new(
67
+ ["line 1\n", "line 2\n"],
68
+ {:source_path => "SOURCE_PATH"})
69
+ @it = Germinate::Process.new("myproc", "mycommand %f")
70
+ end
71
+
72
+ it "should pass the source file path to the command" do
73
+ @path = stub("Source File Path")
74
+ IO.should_receive(:popen).with("mycommand 'SOURCE_PATH'", "r").
75
+ and_yield(@command)
76
+ @it.call(@input).should == @output
77
+ end
78
+ end
63
79
  end
64
80
  end
@@ -6,7 +6,7 @@ module Germinate
6
6
  before :each do
7
7
  @librarian = stub("Librarian", :comment_prefix_known? => false).
8
8
  as_null_object
9
- @it = Reader.new(@librarian)
9
+ @it = Reader.new(@librarian, "SOURCE_PATH")
10
10
  end
11
11
 
12
12
  it "should start in the :initial state" do
@@ -21,6 +21,11 @@ module Germinate
21
21
  @it.current_section.should == "SECTION0"
22
22
  end
23
23
 
24
+ it "should set the librarian's source path" do
25
+ @librarian.should_receive(:source_path=).with(Pathname("SOURCE_PATH"))
26
+ @it = Reader.new(@librarian, "SOURCE_PATH")
27
+ end
28
+
24
29
  context "when section count is incremented" do
25
30
 
26
31
  before :each do
@@ -3,20 +3,49 @@ require File.expand_path(
3
3
 
4
4
  module Germinate
5
5
  describe Selector do
6
+
7
+ context "given a subscript" do
8
+ before :each do
9
+ @it = Germinate::Selector.new("@A:1", "DEFAULT")
10
+ end
11
+
12
+ specify { @it.should be_slice }
13
+ specify { @it.should_not be_whole }
14
+ end
15
+
16
+ context "given no subscript" do
17
+ before :each do
18
+ @it = Germinate::Selector.new("@A", "DEFAULT")
19
+ end
20
+
21
+ specify { @it.should_not be_slice }
22
+ specify { @it.should be_whole }
23
+ end
24
+
25
+ context "given a post-pipeline subscript" do
26
+ before :each do
27
+ @it = Germinate::Selector.new("@A|foo:1", "DEFAULT")
28
+ end
29
+
30
+ specify { @it.should_not be_slice }
31
+ specify { @it.should be_whole }
32
+ end
33
+
6
34
  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"]],
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],
20
49
  ]
21
50
 
22
51
  EXAMPLE_SELECTORS.each do |selector_attributes|
@@ -28,6 +57,7 @@ module Germinate
28
57
  end_offset = selector_attributes[5]
29
58
  length = selector_attributes[6]
30
59
  pipeline = selector_attributes[7]
60
+ excerpt_output = selector_attributes[8]
31
61
 
32
62
  context "given selector '#{selector_attributes[0]}'" do
33
63
  before :each do
@@ -59,6 +89,12 @@ module Germinate
59
89
  it "should have delimiter #{delimiter.inspect}" do
60
90
  @it.delimiter.should == delimiter
61
91
  end
92
+
93
+ if excerpt_output
94
+ specify { @it.should be_excerpt_output }
95
+ else
96
+ specify { @it.should_not be_excerpt_output }
97
+ end
62
98
  end
63
99
  end
64
100
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devver-germinate
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Avdi Grimm
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-10 00:00:00 -07:00
12
+ date: 2009-07-13 00:00:00 -07:00
13
13
  default_executable: germ
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -97,6 +97,7 @@ files:
97
97
  - History.txt
98
98
  - README.rdoc
99
99
  - Rakefile
100
+ - TODO
100
101
  - bin/germ
101
102
  - cucumber.yml
102
103
  - examples/basic.rb
@@ -113,20 +114,24 @@ files:
113
114
  - features/bin/sorter
114
115
  - features/example_articles/bracketing.rb
115
116
  - features/example_articles/escaping.txt
117
+ - features/example_articles/excerpt_output.rb
116
118
  - features/example_articles/hello.rb
117
119
  - features/example_articles/pipelines.txt
118
120
  - features/example_articles/regexen.rb
119
121
  - features/example_articles/sample_offsets.rb
120
122
  - features/example_articles/specials.rb
123
+ - features/example_articles/stderr.rb
121
124
  - features/example_articles/wrapping.rb
122
125
  - features/example_output/bracketing.out
123
126
  - features/example_output/code_samples.txt
124
127
  - features/example_output/escaping.out
128
+ - features/example_output/excerpt_output.out
125
129
  - features/example_output/hello.txt
126
130
  - features/example_output/pipelines.out
127
131
  - features/example_output/regexen.txt
128
132
  - features/example_output/sample_offsets.txt
129
133
  - features/example_output/specials.txt
134
+ - features/example_output/stderr.out
130
135
  - features/example_output/wrapping.txt
131
136
  - features/step_definitions/germinate.rb
132
137
  - features/support/env.rb
@@ -150,6 +155,7 @@ files:
150
155
  - spec/germinate/article_editor_spec.rb
151
156
  - spec/germinate/article_formatter_spec.rb
152
157
  - spec/germinate/code_hunk_spec.rb
158
+ - spec/germinate/file_hunk_spec.rb
153
159
  - spec/germinate/formatter_spec.rb
154
160
  - spec/germinate/hunk_spec.rb
155
161
  - spec/germinate/implicit_insertion_spec.rb