germinate 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 (105) hide show
  1. data/.gitignore +2 -0
  2. data/History.txt +26 -0
  3. data/README.rdoc +152 -0
  4. data/Rakefile +43 -0
  5. data/TODO +140 -0
  6. data/bin/germ +260 -0
  7. data/cucumber.yml +2 -0
  8. data/examples/basic.rb +123 -0
  9. data/examples/short.rb +19 -0
  10. data/features/author-formats-article.feature +111 -0
  11. data/features/author-lists-info.pending_feature +48 -0
  12. data/features/author-publishes-article-source.feature +5 -0
  13. data/features/author-publishes-article.feature +57 -0
  14. data/features/author-republishes-article.feature +5 -0
  15. data/features/author-selects-hunks.feature +26 -0
  16. data/features/author-sets-variables.feature +88 -0
  17. data/features/author-updates-article-source.feature +5 -0
  18. data/features/author-views-stuff.pending_feature +52 -0
  19. data/features/bin/quoter +6 -0
  20. data/features/bin/sorter +4 -0
  21. data/features/example_articles/bracketing.rb +27 -0
  22. data/features/example_articles/escaping.txt +13 -0
  23. data/features/example_articles/excerpt_output.rb +16 -0
  24. data/features/example_articles/hello.rb +9 -0
  25. data/features/example_articles/pipelines.txt +25 -0
  26. data/features/example_articles/regexen.rb +24 -0
  27. data/features/example_articles/sample_offsets.rb +18 -0
  28. data/features/example_articles/specials.rb +19 -0
  29. data/features/example_articles/stderr.rb +10 -0
  30. data/features/example_articles/wrapping.rb +8 -0
  31. data/features/example_output/bracketing.out +23 -0
  32. data/features/example_output/code_samples.txt +186 -0
  33. data/features/example_output/escaping.out +5 -0
  34. data/features/example_output/excerpt_output.out +6 -0
  35. data/features/example_output/hello.txt +1 -0
  36. data/features/example_output/pipelines.out +28 -0
  37. data/features/example_output/regexen.txt +22 -0
  38. data/features/example_output/sample_offsets.txt +15 -0
  39. data/features/example_output/specials.txt +40 -0
  40. data/features/example_output/stderr.out +3 -0
  41. data/features/example_output/wrapping.txt +3 -0
  42. data/features/step_definitions/germinate.rb +42 -0
  43. data/features/support/env.rb +20 -0
  44. data/germinate.gemspec +55 -0
  45. data/lib/germinate.rb +54 -0
  46. data/lib/germinate/application.rb +113 -0
  47. data/lib/germinate/article_editor.rb +20 -0
  48. data/lib/germinate/formatter.rb +119 -0
  49. data/lib/germinate/hunk.rb +183 -0
  50. data/lib/germinate/implicit_insertion.rb +9 -0
  51. data/lib/germinate/insertion.rb +29 -0
  52. data/lib/germinate/librarian.rb +293 -0
  53. data/lib/germinate/origin.rb +5 -0
  54. data/lib/germinate/pipeline.rb +13 -0
  55. data/lib/germinate/publisher.rb +57 -0
  56. data/lib/germinate/reader.rb +266 -0
  57. data/lib/germinate/selector.rb +136 -0
  58. data/lib/germinate/shared_style_attributes.rb +54 -0
  59. data/lib/germinate/shell_process.rb +94 -0
  60. data/lib/germinate/shell_publisher.rb +19 -0
  61. data/lib/germinate/simple_publisher.rb +7 -0
  62. data/lib/germinate/source_file.rb +41 -0
  63. data/lib/germinate/text_transforms.rb +119 -0
  64. data/lib/germinate/transform_process.rb +25 -0
  65. data/lib/germinate/variable.rb +23 -0
  66. data/sample.rb +14 -0
  67. data/spec/germinate/application_spec.rb +31 -0
  68. data/spec/germinate/article_editor_spec.rb +97 -0
  69. data/spec/germinate/code_hunk_spec.rb +73 -0
  70. data/spec/germinate/file_hunk_spec.rb +28 -0
  71. data/spec/germinate/formatter_spec.rb +160 -0
  72. data/spec/germinate/hunk_spec.rb +84 -0
  73. data/spec/germinate/implicit_insertion_spec.rb +33 -0
  74. data/spec/germinate/insertion_spec.rb +19 -0
  75. data/spec/germinate/librarian_spec.rb +555 -0
  76. data/spec/germinate/pipeline_spec.rb +34 -0
  77. data/spec/germinate/process_spec.rb +105 -0
  78. data/spec/germinate/publisher_spec.rb +130 -0
  79. data/spec/germinate/reader_spec.rb +385 -0
  80. data/spec/germinate/selector_spec.rb +121 -0
  81. data/spec/germinate/shell_publisher_spec.rb +61 -0
  82. data/spec/germinate/source_file_spec.rb +99 -0
  83. data/spec/germinate/text_hunk_spec.rb +98 -0
  84. data/spec/germinate/text_transforms_spec.rb +242 -0
  85. data/spec/germinate/transform_process_spec.rb +50 -0
  86. data/spec/germinate/variable_spec.rb +14 -0
  87. data/spec/germinate_spec.rb +8 -0
  88. data/spec/spec.opts +1 -0
  89. data/spec/spec_helper.rb +16 -0
  90. data/tasks/ann.rake +80 -0
  91. data/tasks/bones.rake +20 -0
  92. data/tasks/cucumber.rake +5 -0
  93. data/tasks/gem.rake +201 -0
  94. data/tasks/git.rake +40 -0
  95. data/tasks/notes.rake +27 -0
  96. data/tasks/post_load.rake +34 -0
  97. data/tasks/rdoc.rake +51 -0
  98. data/tasks/rubyforge.rake +55 -0
  99. data/tasks/setup.rb +292 -0
  100. data/tasks/spec.rake +54 -0
  101. data/tasks/svn.rake +47 -0
  102. data/tasks/test.rake +40 -0
  103. data/tasks/zentest.rake +36 -0
  104. data/test/test_germinate.rb +0 -0
  105. metadata +228 -0
@@ -0,0 +1,2 @@
1
+ pkg
2
+ doc
@@ -0,0 +1,26 @@
1
+ == 1.2.0 / 2009-07-21
2
+
3
+ * 4 major enhancements
4
+ * Added "publish" command and pluggable publishers
5
+ * Added builtin publisher "shell" for publishing via shell command
6
+ * Added variables, settable with the :SET: directive
7
+ * Added the ability for commands to write changes back to the source file
8
+ (with backups)
9
+ * 2 minor enhancements
10
+ * Refactored standard text transforms to be just another process
11
+ * Made the list/show/select command arguments easier to use
12
+
13
+ == 1.1.0 / 2009-07-12
14
+
15
+ * 1 major enhancement
16
+ * Added post-pipeline excerpting, e.g. $SOURCE|ruby:/def foo/../end/
17
+ Post-pipeline excerpting executes the process against the entire sample and
18
+ then excerpts the output.
19
+ * 1 minor enhancement
20
+ * Processes applied to $SOURCE will be given the actual source path instead of
21
+ a temp file
22
+
23
+ == 1.0.0 / 2009-07-06
24
+
25
+ * 1 major enhancement
26
+ * Birthday!
@@ -0,0 +1,152 @@
1
+ = germinate
2
+
3
+ by Avdi Grimm
4
+
5
+ http://github.com/devver/germinate/
6
+
7
+ == SYNOPSIS
8
+
9
+ germ generate > my_article.rb
10
+ germ format my_article.rb > my_article.txt
11
+
12
+ == DESCRIPTION
13
+
14
+ Germinate is a tool for writing about code. With Germinate, the source code IS
15
+ the article.
16
+
17
+ For example, given the following source code:
18
+
19
+ # #!/usr/bin/env ruby
20
+ # :BRACKET_CODE: <pre>, </pre>
21
+ # :PROCESS: ruby, "ruby %f"
22
+
23
+ # :SAMPLE: hello
24
+ def hello(who)
25
+ puts "Hello, #{who}"
26
+ end
27
+
28
+ hello("World")
29
+
30
+ # :TEXT:
31
+ # Check out my amazing program! Here's the hello method:
32
+ # :INSERT: @hello:/def/../end/
33
+
34
+ # And here's the output:
35
+ # :INSERT: @hello|ruby
36
+
37
+ When we run the <tt>germ format</tt> command the following output is generated:
38
+
39
+ Check out my amazing program! Here's the hello method:
40
+ <pre>
41
+ def hello(who)
42
+ puts "Hello, #{who}"
43
+ end
44
+ </pre>
45
+ And here's the output:
46
+ <pre>
47
+ Hello, World
48
+ </pre>
49
+
50
+ To get a better idea of how this works, please take a look at
51
+ link:examples/basic.rb, or run:
52
+
53
+ germ generate > basic.rb
54
+
55
+ To generate an example article to play with.
56
+
57
+ Germinate is particularly useful for writing articles, such as blog posts, which
58
+ contain code excerpts. Instead of forcing you to keep a source code file and an
59
+ article document in sync throughout the editing process, the Germinate motto is
60
+ "The source code IS the article". Specially marked comment sections in your
61
+ code file become the article text. Wherever you need to reference the source
62
+ code in the article, use insertion directives to tell Germinate what parts of
63
+ the code to excerpt. An advanced selector syntax enables you to be very
64
+ specific about which lines of code you want to insert.
65
+
66
+ If you also want to show the output of your code, Germinate has you covered.
67
+ Special "process" directives enable you to define arbitrary commands which can
68
+ be run on your code. The output of the command then becomes the excerpt text.
69
+ You can define an arbitrary number of processes and have different excerpts
70
+ showing the same code as processed by different commands. You can even string
71
+ processes together into pipelines.
72
+
73
+ Development of Germinate is graciously sponsored by Devver, purveyor of fine
74
+ cloud-based services to busy Ruby developers. If you like this tool please
75
+ check them out at http://devver.net.
76
+
77
+ == WHAT GERMINATE IS NOT
78
+
79
+ Germinate is not a markup language like HTML, Textile, or Markdown. It is
80
+ completely markup-agnostic, although it can be configured to automatically
81
+ pre-process your articles with markup tools before publishing. Germinate
82
+ concerns itslf strictly with bringing together your words and your code, and
83
+ with automating the process of publishing the finished product.
84
+
85
+ Germinate is not a code documentation tool. While it facilitates the process of
86
+ writing *about* code, it has no understanding of the code itself. Germinate is
87
+ orthogonal to tools such as RDoc or Doxygen.
88
+
89
+ Germinate is not a blogging engine. It is designed to integrate with your
90
+ favorite blogging engine through publisher plugins.
91
+
92
+ Germinate is none of these things, but it is designed to complement all of
93
+ them.
94
+
95
+ == FEATURES
96
+
97
+ * Language and markup agnostic
98
+ * Advanced selector syntax for excerpting code
99
+ * Define arbitrary command pipelines to preprocess excerpts
100
+ * Article text is reformatted to be more compatible with popular blogging
101
+ engines, e.g. WordPress.
102
+ * Extensable with plugins for publishing to Gist, WordPress, etc.
103
+ * Introspection commands make it easy to experiment
104
+
105
+ == KNOWN ISSUES
106
+
107
+ * Directive syntax conflicts with RDoc. Doh!
108
+ * Focus is currently on features. Documentation is lacking. Have a look at the
109
+ features/ directory to get a better idea of various Germinate features.
110
+
111
+ == FUTURE
112
+
113
+ * Integration with blogging platforms, e.g. WordPress
114
+
115
+ == REQUIREMENTS
116
+
117
+ * Ruby 1.8
118
+ * main
119
+ * fattr
120
+ * ick
121
+ * orderedhash
122
+ * arrayfields
123
+ * alter-ego
124
+
125
+ == INSTALL:
126
+
127
+ gem install --source http://gems.rubyforge.org devver-germinate
128
+
129
+ == LICENSE:
130
+
131
+ (The MIT License)
132
+
133
+ Copyright (c) 2009
134
+
135
+ Permission is hereby granted, free of charge, to any person obtaining
136
+ a copy of this software and associated documentation files (the
137
+ 'Software'), to deal in the Software without restriction, including
138
+ without limitation the rights to use, copy, modify, merge, publish,
139
+ distribute, sublicense, and/or sell copies of the Software, and to
140
+ permit persons to whom the Software is furnished to do so, subject to
141
+ the following conditions:
142
+
143
+ The above copyright notice and this permission notice shall be
144
+ included in all copies or substantial portions of the Software.
145
+
146
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
147
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
148
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
149
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
150
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
151
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
152
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,43 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ begin
6
+ require 'bones'
7
+ Bones.setup
8
+ rescue LoadError
9
+ begin
10
+ load 'tasks/setup.rb'
11
+ rescue LoadError
12
+ raise RuntimeError, '### please install the "bones" gem ###'
13
+ end
14
+ end
15
+
16
+ ensure_in_path 'lib'
17
+ require 'germinate'
18
+
19
+ task :default => 'spec:run'
20
+
21
+ PROJ.name = 'germinate'
22
+ PROJ.authors = 'Avdi Grimm'
23
+ PROJ.email = 'avdi@avdi.org'
24
+ PROJ.url = 'http://github.com/devver/germinate/'
25
+ PROJ.version = Germinate::VERSION
26
+ PROJ.rubyforge.name = 'germinate'
27
+
28
+ PROJ.spec.opts << '--color'
29
+
30
+ PROJ.ruby_opts = []
31
+
32
+ PROJ.readme_file = "README.rdoc"
33
+ PROJ.rdoc.main = "README.rdoc"
34
+ PROJ.rdoc.exclude << "features"
35
+
36
+ depend_on "ick", "~> 0.3.0"
37
+ depend_on "fattr", "~> 1.0.3"
38
+ depend_on "arrayfields", "~> 4.7.3"
39
+ depend_on "orderedhash", "~> 0.0.6"
40
+ depend_on "alter-ego", "~> 1.0.0"
41
+ depend_on "main", "~> 2.8.3"
42
+
43
+ # EOF
data/TODO ADDED
@@ -0,0 +1,140 @@
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
+ * DONE Improve error message for non-matching regexen in selectors :usability:
15
+ CLOSED: [2009-07-13 Mon 02:17]
16
+ * DONE Make text transforms just another process for pipelines :techdebt:
17
+ CLOSED: [2009-07-19 Sun 16:33]
18
+ This should help make [[*Make%20it%20possible%20for%20publishers%20to%20use%20formatted%20text%20as%20input][this item]] possible.
19
+ * DONE Add standard "select" option to publishers
20
+ CLOSED: [2009-07-19 Sun 16:33]
21
+ The select option would define a selector to be used to get the input for the
22
+ publisher. Another step towards [[*Make%20it%20possible%20for%20publishers%20to%20use%20formatted%20text%20as%20input][this]].
23
+
24
+ This MAY make the current "pipeline" option redundant.
25
+ * DONE Make it possible for publishers to use formatted text as input :feature:
26
+ CLOSED: [2009-07-19 Sun 16:33]
27
+ Pretty useless without this...
28
+
29
+ * TODO Refactor format command into a null publisher :techdebt:
30
+ This just needs one last step of pre-loading a "stdout publisher" and then we
31
+ can do e.g.:
32
+
33
+ : germ publish stdout my_article.c
34
+ * TODO Output line numbers for Reader errors :usability:
35
+
36
+ * DONE Gist uploads :feature:
37
+ CLOSED: [2009-07-21 Tue 10:54]
38
+
39
+ * DONE Publishing to WordPress blogs (Atompub) :feature:
40
+ CLOSED: [2009-07-21 Tue 10:54]
41
+
42
+ * TODO Alternate directive syntax :usability:
43
+ one that doesn't conflict with RDoc
44
+
45
+ * TODO Anonymous processes :feature:
46
+ A process that doesn't match a predefined process name should be interpreted
47
+ as a shell command.
48
+
49
+ * TODO Code indent :feature:
50
+ Define an indent (either N spaces or a string) to be applied to code sections.
51
+
52
+ Should first de-indent code.
53
+
54
+ * TODO Shorthand for matching whitespace in selectors :feature:
55
+ e.g. "@mysample:/def foo/..._"
56
+
57
+ * TODO Format Pipelines :feature:
58
+ Define a pipeline to be run on the entire article after formatting
59
+
60
+ Or maybe just demote "format" to be a built-in publisher.
61
+ * TODO ERB Substitution :feature:
62
+ Should be run on TEXT sections.
63
+
64
+ * TODO Line# Helper :feature:
65
+ A helper for ERB subtitution which inserts the line# of a given selector.
66
+
67
+ * TODO Plugin API :feature:
68
+ * TODO User-global preference file :feature:
69
+
70
+ * TODO Multiple file support :feature:
71
+
72
+ * TODO Output line numbers for errors at any point :usability:
73
+ This will require giving Hunks the knowledge of their source offset.
74
+
75
+ * TODO Nested samples :feature:
76
+ Might want to wait this on the implementation of nested states in AlterEgo.
77
+
78
+ * TODO Optionally capture STDERR from processes :feature:
79
+
80
+ Workaround: Authors can just include 2>&1 in their process definitions.
81
+
82
+ * DONE Syntax for post-process excerpting :feature:
83
+ CLOSED: [2009-07-12 Sun 20:50]
84
+ E.g. "$SOURCE|ruby:/---/../---/"
85
+
86
+ This would cause the process to be run on $SOURCE and then a subset of the
87
+ output to be excerpted.
88
+
89
+ * TODO Named Styles :feature:
90
+ A way to group together a bunch of style attributes in a reusable way.
91
+ * DONE A way to set arbitrary variables for later substitution :feature:
92
+ CLOSED: [2009-07-16 Thu 11:51]
93
+ * DONE Standard "pipeline" option for publishers :feature:
94
+ CLOSED: [2009-07-15 Wed 01:32]
95
+ Defines a pipeline which will be run on $SOURCE before publishing.
96
+ * TODO Plugin discovery :feature:
97
+ Should use gems to discover plugins.
98
+
99
+ * TODO Line continuations for directives :usability:
100
+ After some thought I think what I really want is a second syntax for long-form
101
+ directives, wherein the YAML arguments go in between directive opening and
102
+ closing lines. E.g.
103
+
104
+ : # :PUBLISHER: ---
105
+ : # - source
106
+ : # - shell
107
+ : # -
108
+ : # command: cat
109
+ : # pipeline: markdown
110
+ : # :END:
111
+ * DONE Variables
112
+ CLOSED: [2009-07-16 Thu 19:47]
113
+ Syntax:
114
+ : :SET: foo, 123
115
+ *** Reader records what line they were set on
116
+ *** SourceFile class which can set and re-set variables
117
+ - Backs the file up first
118
+ - Verifies the backup
119
+ - Locks the file and the backup
120
+ - Removes the old line
121
+ - Replaces it with a new :SET: line
122
+ - Or adds a new :SET: line to the end
123
+ - Re-reads and verifies value
124
+ - Restores the backup if there is a problem
125
+
126
+ *** Variables are available to processes as environment vars
127
+ * TODO Add processing/style options to TEXT sections :feature:
128
+ * TODO Add console modes :feature:
129
+ *** TODO Shell console
130
+ In this version we just exec $SHELL with some custom environment. A
131
+ GERMINATE_SOURCE variable should point to the source file, and all germ
132
+ commands should use it if no explicit source is specified.
133
+
134
+ In addition, aliases for all the common germ modes should be installed -
135
+ publish, format, list, etc.
136
+ *** TODO Debug console
137
+ An IRB session with Germinate preloaded.
138
+
139
+ * TODO Clean up output during tests :techdebt:
140
+ * TODO Add a dry-run mode :feature:
@@ -0,0 +1,260 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib germinate]))
5
+
6
+ require 'English'
7
+ require 'main'
8
+
9
+ Main do
10
+ description <<-END
11
+ Germinate - A tool for writing about code.
12
+
13
+ With Germinate, your source code is also your article text. Special
14
+ directives tell Germinate which parts to format as article text and
15
+ where to insert source code excerpts and program output.
16
+
17
+ To get started, execute:
18
+
19
+ germ generate > my_article.rb
20
+
21
+ to have Germinate generate a basic example article.
22
+
23
+ For more information, see the project homepage at
24
+ http://github.com/devver/germinate/
25
+
26
+ Development of Germinate is graciously sponsored by Devver, purveyor
27
+ of fine cloud-based services to busy Ruby developers. If you like
28
+ this tool please check them out at http://devver.net.
29
+ END
30
+
31
+ author "Avdi Grimm <avdi@avdi.org>"
32
+
33
+ version Germinate::VERSION
34
+
35
+ def self.source_argument
36
+ argument :source do
37
+ arity 1
38
+ validate{|source| Pathname(source).readable?}
39
+ description "Source file"
40
+ end
41
+ end
42
+
43
+ option(:debug, :d) do
44
+ cast :bool
45
+ end
46
+
47
+ def run
48
+ help!
49
+ end
50
+
51
+ mode :format do
52
+ description "Format an article for publishing"
53
+ source_argument
54
+ def run
55
+ with_source_file do |source, path|
56
+ @application.format(source, path)
57
+ end
58
+ end
59
+ end
60
+
61
+ mode :list do
62
+ description "List info about the source file"
63
+ argument :collection do
64
+ arity 1
65
+ required
66
+ argument_required
67
+ description "One of: sections, samples, processes, publishers, variables"
68
+ end
69
+ source_argument
70
+
71
+ def run
72
+ with_source_file do |source, path|
73
+ @application.list(source, path, params[:collection].value)
74
+ end
75
+ end
76
+ end
77
+
78
+ mode :show do
79
+ description "Show details about various article components"
80
+ argument :type do
81
+ arity 1
82
+ required
83
+ argument_required
84
+ description "One of: section, sample, process, publisher, variable"
85
+ end
86
+ argument :item do
87
+ arity 1
88
+ required
89
+ argument_required
90
+ description "The specific item to show details about"
91
+ end
92
+ source_argument
93
+
94
+ def run
95
+ with_source_file do |source, path|
96
+ @application.show(source, path, params['type'].value, params['item'].value)
97
+ end
98
+ end
99
+ end
100
+
101
+ mode :select do
102
+ description "Test out a selector"
103
+ argument :selector do
104
+ arity 1
105
+ required
106
+ argument_required
107
+ description "The selector to retrieve"
108
+ end
109
+ source_argument
110
+
111
+ Germinate::TextTransforms.singleton_methods.each do |transform|
112
+ option(transform) do
113
+ description "Enable/disable the '#{transform}' text transform"
114
+ cast :bool
115
+ end
116
+ end
117
+
118
+ def run
119
+ options = Germinate::TextTransforms.singleton_methods.inject({}) do
120
+ |opts, transform|
121
+ if params[transform].given?
122
+ opts[transform] = params[transform].value
123
+ logger.info "Text transform '#{transform}' " +
124
+ (params[transform].value ? "enabled" : "disabled")
125
+ end
126
+ opts
127
+ end
128
+ with_source_file do |source, path|
129
+ @application.select(source, path, params[:selector].value, options)
130
+ end
131
+ end
132
+ end
133
+
134
+ mode :generate do
135
+ description "Generate a sample article"
136
+
137
+ def run
138
+ example = File.expand_path("../doc/examples/basic.rb",
139
+ File.dirname(__FILE__))
140
+ stdout.write(File.read(example))
141
+ end
142
+ end
143
+
144
+ mode :publish do
145
+ description "Publish the article using the named publisher"
146
+ argument :publisher
147
+ source_argument
148
+ option 'publish-options' do
149
+ arity 1
150
+ end
151
+
152
+ def run
153
+ with_source_file do |source, path|
154
+ options = YAML.load(params['publish-options'].value || "{}")
155
+ @application.publish(source, path, params[:publisher].value, options)
156
+ end
157
+ end
158
+ end
159
+
160
+ mode :set do
161
+ description "Set a named value in the article"
162
+ argument :name do
163
+ description "Variable name"
164
+ cast :string
165
+ end
166
+ argument :value do
167
+ description "Variable value"
168
+ cast :string
169
+ end
170
+ source_argument
171
+
172
+ def run
173
+ with_source_file do |source, path|
174
+ @application.set(
175
+ source,
176
+ path,
177
+ params[:name].value,
178
+ params[:value].value)
179
+ end
180
+ end
181
+ end
182
+
183
+ def initialize
184
+ @command = "#{$PROGRAM_NAME} #{ARGV.join(' ')}"
185
+ Germinate.logger = logger
186
+ logger.progname = "germinate"
187
+ logger.formatter = lambda { |severity, time, progname, message|
188
+ lines = case message
189
+ when ::String then message.split("\n")
190
+ when ::Exception then
191
+ Array(message.message) + Array(message.backtrace)
192
+ else
193
+ message.inspect
194
+ end
195
+ lines.map{|l| "#{severity} -- #{progname}: #{l}"}.join("\n") + "\n"
196
+ }
197
+ @application = Germinate::Application.new(stdout, stderr)
198
+ @application.load_plugins!
199
+ end
200
+
201
+ def pre_parse_parameters
202
+ end
203
+
204
+ def pre_run
205
+ logger.level = params['debug'].value ? Logger::DEBUG : Logger::INFO
206
+ end
207
+
208
+ def with_source_file
209
+ rescue_errors do
210
+ path = params['source'].value
211
+ File.open(path) do |file|
212
+ yield file, path
213
+ end
214
+ end
215
+ end
216
+
217
+ def rescue_errors
218
+ yield
219
+ rescue RuntimeError => error
220
+ raise if params['debug'].value
221
+ log_user_error(error)
222
+ rescue Exception => error
223
+ raise if params['debug'].value
224
+ log_program_error(error)
225
+ end
226
+
227
+ def log_user_error(error)
228
+ log_fatal_error <<-END
229
+ Germinate could not complete your command.
230
+ Please check your command and article for proper syntax.
231
+ #{command_report}
232
+ #{error_report(error)}
233
+ For more information, re-run the command with the --debug flag.
234
+ END
235
+ end
236
+
237
+ def log_program_error(error)
238
+ log_fatal_error <<-END
239
+ Germinate encountered an error while executing your command.
240
+ #{command_report}
241
+ #{error_report(error)}
242
+ Please re-run the command with the --debug flag, and file a problem report at
243
+ http://github.com/devver/germinate/
244
+ END
245
+ end
246
+
247
+ def command_report
248
+ "The command was: '#{@command}'"
249
+ end
250
+
251
+ def error_report(error)
252
+ "The error was: '#{error.message}'"
253
+ end
254
+
255
+ def log_fatal_error(error)
256
+ logger.fatal(error)
257
+ end
258
+ end
259
+
260
+ # EOF