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 +10 -0
- data/TODO +71 -0
- data/bin/germ +13 -10
- data/features/author-formats-article.feature +2 -0
- data/features/example_articles/excerpt_output.rb +16 -0
- data/features/example_articles/stderr.rb +10 -0
- data/features/example_output/excerpt_output.out +6 -0
- data/features/example_output/stderr.out +3 -0
- data/features/step_definitions/germinate.rb +6 -3
- data/features/support/env.rb +2 -0
- data/germinate.gemspec +3 -3
- data/lib/germinate.rb +1 -1
- data/lib/germinate/application.rb +10 -10
- data/lib/germinate/hunk.rb +23 -3
- data/lib/germinate/insertion.rb +2 -2
- data/lib/germinate/librarian.rb +19 -3
- data/lib/germinate/process.rb +8 -0
- data/lib/germinate/reader.rb +3 -1
- data/lib/germinate/selector.rb +34 -5
- data/lib/germinate/shared_style_attributes.rb +2 -1
- data/spec/germinate/file_hunk_spec.rb +27 -0
- data/spec/germinate/hunk_spec.rb +6 -0
- data/spec/germinate/librarian_spec.rb +21 -1
- data/spec/germinate/process_spec.rb +16 -0
- data/spec/germinate/reader_spec.rb +6 -1
- data/spec/germinate/selector_spec.rb +49 -13
- metadata +8 -2
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
|
129
|
-
|
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
|
|
@@ -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
|
@@ -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")
|
23
|
-
|
24
|
-
|
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|
|
data/features/support/env.rb
CHANGED
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
|
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-
|
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
@@ -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
|
data/lib/germinate/hunk.rb
CHANGED
@@ -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
|
-
|
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.
|
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.
|
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
|
+
|
data/lib/germinate/insertion.rb
CHANGED
@@ -8,14 +8,14 @@ class Germinate::Insertion
|
|
8
8
|
attr_reader :selector
|
9
9
|
|
10
10
|
def initialize(selector, library, template={})
|
11
|
-
|
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.
|
18
|
+
hunk.copy_shared_style_attributes_from(self, false)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
data/lib/germinate/librarian.rb
CHANGED
@@ -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"
|
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
|
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
|
data/lib/germinate/process.rb
CHANGED
@@ -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
|
data/lib/germinate/reader.rb
CHANGED
@@ -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
|
data/lib/germinate/selector.rb
CHANGED
@@ -9,7 +9,8 @@ class Germinate::Selector
|
|
9
9
|
attr_reader :pipeline
|
10
10
|
attr_reader :default_key
|
11
11
|
|
12
|
-
PATTERN =
|
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
|
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[
|
31
|
-
|
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[
|
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
|
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
|
data/spec/germinate/hunk_spec.rb
CHANGED
@@ -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
|
-
],
|
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
|
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-
|
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
|