le1t0-whenever 0.4.2.003 → 0.6.2.001

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,12 +1,49 @@
1
- == 0.4.2.003 / Jul 5th, 2010
1
+ ### 0.6.2 / October 26th, 2010
2
2
 
3
- * fixed adding per-cronjob environment variables
3
+ * --clear-crontab option completely removes entries. #63 [Javan Makhmali]
4
4
 
5
- == 0.4.2.002 / May 18th, 2010
5
+ * Set default :environment and :path earlier in the new setup.rb (formerly job_types/default.rb). [Javan Makhmali]
6
6
 
7
- * Added setting environment variables per cron job
7
+ * Converted README and CHANGELOG to markdown. [Javan Makhmali]
8
8
 
9
- == 0.4.2 / April 26th, 2010
9
+
10
+ ### 0.6.1 / October 20th, 2010
11
+
12
+ * Detect script/rails file and change runner to Rails 3 style if found. [Javan Makhmali]
13
+
14
+ * Created a new :job_template system that can be applied to all commands. Wraps all in bash -l -c 'command..' by default now for better RVM support. Stopped automatically setting the PATH too. [Javan Makhmali]
15
+
16
+ * Added a built-in Capistrano recipe. [Javan Makhmali]
17
+
18
+
19
+ ### 0.5.3 / September 24th, 2010
20
+
21
+ * Better regexes for replacing Whenever blocks in the crontab. #45 [Javan Makhmali]
22
+
23
+ * Preserving backslashes when updating existing crontab. #82 [Javan Makhmali]
24
+
25
+
26
+ ### 0.5.2 / September 15th, 2010
27
+
28
+ * Quotes automatically escaped in jobs. [Jay Adkisson]
29
+
30
+ * Added --cut option to the command line to allow pruning of the crontab. [Peer Allan]
31
+
32
+ * Switched to aaronh-chronic which is ruby 1.9.2 compatible. [Aaron Hurley, Javan Makhmali]
33
+
34
+ * Lots of internal reorganizing; tests broken into unit and functional. [Javan Makhmali]
35
+
36
+
37
+ ### 0.5.0 / June 28th, 2010
38
+
39
+ * New job_type API for writing custom jobs. Internals use this to define command, runner, and rake. [Javan Makhmali - inspired by idlefingers (Damien)]
40
+
41
+ * Jobs < 1.hour can specify an :at. [gorenje]
42
+
43
+ * --clear option to remove crontab entries for a specific [identifier]. [mraidel (Michael Raidel)]
44
+
45
+
46
+ ### 0.4.2 / April 26th, 2010
10
47
 
11
48
  * runners now cd into the app's directory and then execute. [Michael Guterl]
12
49
 
@@ -17,49 +54,49 @@
17
54
  * bugfix: comparison Time with 0 failed. #32 [Dan Hixon]
18
55
 
19
56
 
20
- == 0.4.1 / November 30th, 2009
57
+ ### 0.4.1 / November 30th, 2009
21
58
 
22
59
  * exit(0) instead of just exit to make JRuby happy. [Elan Meng]
23
60
 
24
61
  * Fixed activesupport deprecation warning by requiring active_support. #37 [Andrew Nesbitt]
25
62
 
26
63
 
27
- == 0.4.0 / October 20th, 2009
64
+ ### 0.4.0 / October 20th, 2009
28
65
 
29
66
  * New output option replaces the old cron_log option for output redirection and is much more flexible. #31 [Peer Allan]
30
67
 
31
68
  * Reorganized the lib files (http://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices) and switched to Jeweler from Echoe.
32
69
 
33
70
 
34
- == 0.3.7 / September 4th, 2009
71
+ ### 0.3.7 / September 4th, 2009
35
72
 
36
73
  * No longer tries (and fails) to combine @shortcut jobs. #20 [Javan Makhmali]
37
74
 
38
75
 
39
- == 0.3.6 / June 15th, 2009
76
+ ### 0.3.6 / June 15th, 2009
40
77
 
41
78
  * Setting a PATH in the crontab automatically based on the user's PATH. [Javan Makhmali]
42
79
 
43
80
 
44
- == 0.3.5 / June 13th, 2009
81
+ ### 0.3.5 / June 13th, 2009
45
82
 
46
83
  * Added ability to accept lists of every's and at's and intelligently group them. (ex: every 'monday, wednesday', :at => ['3pm', '6am']). [Sam Ruby]
47
84
 
48
85
  * Fixed issue with new lines. #18 [Javan Makhmali]
49
86
 
50
- == 0.3.1 / June 25th, 2009
87
+ ### 0.3.1 / June 25th, 2009
51
88
 
52
89
  * Removed activesupport gem dependency. #1 [Javan Makhmali]
53
90
 
54
91
  * Switched to numeric days of the week for Solaris support (and probably others). #8 [Roger Ertesvåg]
55
92
 
56
93
 
57
- == 0.3.0 / June 2nd, 2009
94
+ ### 0.3.0 / June 2nd, 2009
58
95
 
59
96
  * Added ability to set variables on the fly from the command line (ex: whenever --set environment=staging). [Javan Makhmali]
60
97
 
61
98
 
62
- == 0.2.2 / April 30th, 2009
99
+ ### 0.2.2 / April 30th, 2009
63
100
 
64
101
  * Days of week jobs can now accept an :at directive (ex: every :monday, :at => '5pm'). [David Eisinger]
65
102
 
@@ -68,22 +105,22 @@
68
105
  * Raising an exception if someone tries to specify an :at with a cron shortcut (:day, :reboot, etc) so there are no false hopes. [Javan Makhmali]
69
106
 
70
107
 
71
- == 0.1.7 / March 5th, 2009
108
+ ### 0.1.7 / March 5th, 2009
72
109
 
73
110
  * Added ability to update the crontab file non-destuctively instead of only overwriting it. [Javan Makhmali -- Inspired by code submitted individually from: Tien Dung (tiendung), Tom Lea (cwninja), Kyle Maxwell (fizx), and Andrew Timberlake (andrewtimberlake) on github]
74
111
 
75
112
 
76
- == 0.1.5 / February 19th, 2009
113
+ ### 0.1.5 / February 19th, 2009
77
114
 
78
115
  * Fixed load path so Whenever's files don't conflict with anything in Rails. Thanks Ryan Koopmans. [Javan Makhmali]
79
116
 
80
117
 
81
- == 0.1.4 / February 17th, 2009
118
+ ### 0.1.4 / February 17th, 2009
82
119
 
83
120
  * Added --load-file and --user opts to whenever binary. [Javan Makhmali]
84
121
 
85
122
 
86
- == 0.1.3 / February 16th, 2009
123
+ ### 0.1.3 / February 16th, 2009
87
124
 
88
125
  * Added 'rake' helper for defining scheduled rake tasks. [Javan Makhmali]
89
126
 
@@ -96,6 +133,6 @@
96
133
  * Requiring specific gem versions: Chronic >=0.2.3 and activesupport >= 1.3.0 [Javan Makhmali]
97
134
 
98
135
 
99
- == 0.1.0 / February 15th, 2009
136
+ ### 0.1.0 / February 15th, 2009
100
137
 
101
138
  * Initial release [Javan Makhmali]
data/README.md ADDED
@@ -0,0 +1,139 @@
1
+ ### Introduction
2
+
3
+ Whenever is a Ruby gem that provides a clear syntax for writing and deploying cron jobs.
4
+
5
+ ### Installation
6
+
7
+ $ gem install whenever
8
+
9
+ Or with Bundler in your Gemfile.
10
+
11
+ gem 'whenever', :require => false
12
+
13
+ ### Getting started
14
+
15
+ $ cd /my/rails/app
16
+ $ wheneverize .
17
+
18
+ This will create an initial "config/schedule.rb" file you.
19
+
20
+ ### Example schedule.rb file
21
+
22
+ every 3.hours do
23
+ runner "MyModel.some_process"
24
+ rake "my:rake:task"
25
+ command "/usr/bin/my_great_command"
26
+ end
27
+
28
+ every 1.day, :at => '4:30 am' do
29
+ runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
30
+ end
31
+
32
+ every :hour do # Many shortcuts available: :hour, :day, :month, :year, :reboot
33
+ runner "SomeModel.ladeeda"
34
+ end
35
+
36
+ every :sunday, :at => '12pm' do # Use any day of the week or :weekend, :weekday
37
+ runner "Task.do_something_great"
38
+ end
39
+
40
+ More examples on the wiki: <http://wiki.github.com/javan/whenever/instructions-and-examples>
41
+
42
+ ### Define your own job types
43
+
44
+ Whenever ships with three pre-defined job types: command, runner, and rake. You can define your own with `job_type`.
45
+
46
+ For example:
47
+
48
+ job_type :awesome, '/usr/local/bin/awesome :task :fun_level'
49
+
50
+ every 2.hours do
51
+ awesome "party", :fun_level => "extreme"
52
+ end
53
+
54
+ Would run `/usr/local/bin/awesome party extreme` every two hours. `:task` is always replaced with the first argument, and any additional `:whatevers` are replaced with the options passed in or by variables that have been defined with `set`.
55
+
56
+ The default job types that ship with Whenever are defined like so:
57
+
58
+ job_type :command, ":task :output"
59
+ job_type :rake, "cd :path && RAILS_ENV=:environment rake :task :output"
60
+ job_type :runner, "cd :path && script/runner -e :environment ':task' :output"
61
+
62
+ If a script/rails file is detected (like in a Rails 3 app), runner will be defined to fit:
63
+
64
+ job_type :runner, "cd :path && script/rails runner -e :environment ':task' :output"
65
+
66
+ If a `:path` is not set it will default to the directory in which `whenever` was executed. `:environment` will default to 'production'. `:output` will be replaced with your output redirection settings which you can read more about here: <http://github.com/javan/whenever/wiki/Output-redirection-aka-logging-your-cron-jobs>
67
+
68
+ All jobs are by default run with `bash -l -c 'command...'`. Among other things, this allows your cron jobs to play nice with RVM by loading the entire environment instead of cron's somewhat limited environment. Read more: <http://blog.scoutapp.com/articles/2010/09/07/rvm-and-cron-in-production>
69
+
70
+ You can change this by setting your own `:job_template`.
71
+
72
+ set :job_template, "bash -l -c ':job'"
73
+
74
+ Or set the job_template to nil to have your jobs execute normally.
75
+
76
+ set :job_template, nil
77
+
78
+ And you'll see your schedule.rb converted to cron sytax. Note: running `whenever` with no options does not display your current crontab file, it simply shows you the output of converting your schedule.rb file.
79
+
80
+ ### Capistrano integration
81
+
82
+ Use the built-in Capistrano recipe for easy crontab updates with deploys.
83
+
84
+ In your "config/deploy.rb" file:
85
+
86
+ require "whenever/capistrano"
87
+
88
+ Take a look at the recipe for options you can set. <http://github.com/javan/whenever/blob/master/lib/whenever/capistrano.rb>
89
+ For example, if you're using bundler do this:
90
+
91
+ set :whenever_command, "bundle exec whenever"
92
+ require "whenever/capistrano"
93
+
94
+ ### The `whenever` command
95
+
96
+ $ cd /my/rails/app
97
+ $ whenever
98
+
99
+ This will simply show you your schedule.rb file converted to cron syntax. It does not read or write your crontab file. Run `whenever --help` for a complete list of options.
100
+
101
+ ### Credit
102
+
103
+ Whenever was created for use at Inkling (<http://inklingmarkets.com>) where I work. Their take on it: <http://blog.inklingmarkets.com/2009/02/whenever-easy-way-to-do-cron-jobs-from.html>
104
+
105
+ Thanks to all the contributors who have made it even better: <http://github.com/javan/whenever/contributors>
106
+
107
+ ### Discussion / Feedback / Issues / Bugs
108
+
109
+ For general discussion and questions, please use the google group: <http://groups.google.com/group/whenever-gem>
110
+
111
+ If you've found a genuine bug or issue, please use the Issues section on github: <http://github.com/javan/whenever/issues>
112
+
113
+ Ryan Bates created a great Railscast about Whenever: <http://railscasts.com/episodes/164-cron-in-ruby>
114
+ It's a little bit dated now, but remains a good introduction.
115
+
116
+ ### License
117
+
118
+ Copyright (c) 2009+ Javan Makhmali
119
+
120
+ Permission is hereby granted, free of charge, to any person
121
+ obtaining a copy of this software and associated documentation
122
+ files (the "Software"), to deal in the Software without
123
+ restriction, including without limitation the rights to use,
124
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
125
+ copies of the Software, and to permit persons to whom the
126
+ Software is furnished to do so, subject to the following
127
+ conditions:
128
+
129
+ The above copyright notice and this permission notice shall be
130
+ included in all copies or substantial portions of the Software.
131
+
132
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
133
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
134
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
135
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
136
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
137
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
138
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
139
+ OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
3
 
4
- require 'lib/whenever/version.rb'
4
+ require File.expand_path(File.dirname(__FILE__) + "/lib/whenever/version")
5
5
 
6
6
  begin
7
7
  require 'jeweler'
@@ -13,7 +13,10 @@ begin
13
13
  gemspec.email = "dev@ewout.to"
14
14
  gemspec.homepage = "http://github.com/le1t0/whenever"
15
15
  gemspec.authors = ["Le1t0"]
16
- gemspec.add_dependency("chronic", '>= 0.2.3')
16
+ gemspec.add_dependency 'aaronh-chronic', '>= 0.3.9'
17
+ gemspec.add_dependency 'activesupport', '>= 2.3.4'
18
+ gemspec.add_development_dependency 'shoulda', '>= 2.1.1'
19
+ gemspec.add_development_dependency 'mocha', '>= 0.9.5'
17
20
  end
18
21
  Jeweler::GemcutterTasks.new
19
22
  rescue LoadError
@@ -22,10 +25,10 @@ end
22
25
 
23
26
  require 'rake/testtask'
24
27
  Rake::TestTask.new(:test) do |test|
25
- test.libs << 'lib' << 'test'
26
- test.pattern = 'test/*.rb'
27
- test.verbose = true
28
- end
28
+ test.libs << 'lib' << 'test'
29
+ test.pattern = 'test/{functional,unit}/**/*_test.rb'
30
+ test.verbose = true
31
+ end
29
32
 
30
33
  task :test => :check_dependencies
31
34
 
data/bin/whenever CHANGED
@@ -4,25 +4,35 @@ require 'rubygems'
4
4
  require 'optparse'
5
5
  require 'whenever'
6
6
 
7
- options = Hash.new
7
+ options = {}
8
8
 
9
9
  OptionParser.new do |opts|
10
10
  opts.banner = "Usage: whenever [options]"
11
- opts.on('-v', '--version') { puts "Whenever v#{Whenever::VERSION}"; exit(0) }
12
- opts.on('-w', '--write-crontab') { options[:write] = true }
13
11
  opts.on('-i', '--update-crontab [identifier]', 'Default: full path to schedule.rb file') do |identifier|
14
12
  options[:update] = true
15
13
  options[:identifier] = identifier if identifier
16
14
  end
15
+ opts.on('-w', '--write-crontab [identifier]', 'Default: full path to schedule.rb file') do |identifier|
16
+ options[:write] = true
17
+ options[:identifier] = identifier if identifier
18
+ end
19
+ opts.on('-c', '--clear-crontab [identifier]') do |identifier|
20
+ options[:clear] = true
21
+ options[:identifier] = identifier if identifier
22
+ end
23
+ opts.on('-s', '--set [variables]', 'Example: --set environment=staging&path=/my/sweet/path') do |set|
24
+ options[:set] = set if set
25
+ end
17
26
  opts.on('-f', '--load-file [schedule file]', 'Default: config/schedule.rb') do |file|
18
27
  options[:file] = file if file
19
28
  end
20
29
  opts.on('-u', '--user [user]', 'Default: current user') do |user|
21
30
  options[:user] = user if user
22
31
  end
23
- opts.on('-s', '--set [variables]', 'Example: --set environment=staging&path=/my/sweet/path') do |set|
24
- options[:set] = set if set
32
+ opts.on('-k', '--cut [lines]', 'Cut lines from the top of the cronfile') do |lines|
33
+ options[:cut] = lines.to_i if lines
25
34
  end
35
+ opts.on('-v', '--version') { puts "Whenever v#{Whenever::VERSION}"; exit(0) }
26
36
  end.parse!
27
37
 
28
38
  Whenever::CommandLine.execute(options)
data/lib/whenever.rb CHANGED
@@ -1,31 +1,21 @@
1
1
  require 'chronic'
2
+ require 'active_support/all'
2
3
 
3
- # Hoping to load Rails' Rakefile
4
- begin
5
- load 'Rakefile'
6
- rescue LoadError
7
- nil
8
- end
9
-
10
- # If Rails' rakefile was loaded than so was active_support, but
11
- # if this is being used in a non-rails enviroment we need to require it.
12
- # It was previously defined as a dependency of this gem, but that became
13
- # problematic. See: http://github.com/javan/whenever/issues#issue/1
14
- begin
15
- require 'active_support/all'
16
- rescue LoadError
17
- warn 'To use Whenever you need the active_support gem:'
18
- warn '$ gem install activesupport'
19
- exit(1)
20
- end
21
-
22
- # Whenever files
23
- require 'whenever/base'
24
4
  require 'whenever/job_list'
25
- require 'whenever/job_types/default'
26
- require 'whenever/job_types/rake_task'
27
- require 'whenever/job_types/runner'
28
- require 'whenever/outputs/cron'
29
- require 'whenever/outputs/cron/output_redirection'
5
+ require 'whenever/job'
6
+ require 'whenever/cron'
7
+ require 'whenever/output_redirection'
30
8
  require 'whenever/command_line'
31
- require 'whenever/version'
9
+ require 'whenever/version'
10
+
11
+ module Whenever
12
+
13
+ def self.cron(options)
14
+ Whenever::JobList.new(options).generate_cron_output
15
+ end
16
+
17
+ def self.path
18
+ Dir.pwd
19
+ end
20
+
21
+ end
@@ -0,0 +1,31 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ _cset(:whenever_roles) { :db }
4
+ _cset(:whenever_command) { "whenever" }
5
+ _cset(:whenever_identifier) { application }
6
+ _cset(:whenever_update_flags) { "--update-crontab #{whenever_identifier}" }
7
+ _cset(:whenever_clear_flags) { "--clear-crontab #{whenever_identifier}" }
8
+
9
+ # Disable cron jobs at the begining of a deploy.
10
+ after "deploy:update_code", "whenever:clear_crontab"
11
+ # Write the new cron jobs near the end.
12
+ after "deploy:symlink", "whenever:update_crontab"
13
+ # If anything goes wrong, undo.
14
+ after "deploy:rollback", "whenever:update_crontab"
15
+
16
+ namespace :whenever do
17
+ desc "Update application's crontab entries using Whenever"
18
+ task :update_crontab, :roles => whenever_roles do
19
+ # Hack by Jamis to skip a task if the role has no servers defined. http://tinyurl.com/ckjgnz
20
+ next if find_servers_for_task(current_task).empty?
21
+ run "cd #{current_path} && #{whenever_command} #{whenever_update_flags}"
22
+ end
23
+
24
+ desc "Clear application's crontab entries using Whenever"
25
+ task :clear_crontab, :roles => whenever_roles do
26
+ next if find_servers_for_task(current_task).empty?
27
+ run "cd #{release_path} && #{whenever_command} #{whenever_clear_flags}"
28
+ end
29
+ end
30
+
31
+ end
@@ -12,6 +12,7 @@ module Whenever
12
12
  @options = options
13
13
 
14
14
  @options[:file] ||= 'config/schedule.rb'
15
+ @options[:cut] ||= 0
15
16
  @options[:identifier] ||= default_identifier
16
17
 
17
18
  unless File.exists?(@options[:file])
@@ -19,14 +20,20 @@ module Whenever
19
20
  exit(1)
20
21
  end
21
22
 
22
- if @options[:update] && @options[:write]
23
- warn("[fail] Can't update AND write. choose one.")
23
+ if [@options[:update], @options[:write], @options[:clear]].compact.length > 1
24
+ warn("[fail] Can only update, write or clear. Choose one.")
24
25
  exit(1)
25
26
  end
27
+
28
+ unless @options[:cut].to_s =~ /[0-9]*/
29
+ warn("[fail] Can't cut negative lines from the crontab #{options[:cut]}")
30
+ exit(1)
31
+ end
32
+ @options[:cut] = @options[:cut].to_i
26
33
  end
27
34
 
28
35
  def run
29
- if @options[:update]
36
+ if @options[:update] || @options[:clear]
30
37
  write_crontab(updated_crontab)
31
38
  elsif @options[:write]
32
39
  write_crontab(whenever_cron)
@@ -43,7 +50,8 @@ module Whenever
43
50
  end
44
51
 
45
52
  def whenever_cron
46
- @whenever_cron ||= [comment_open, Whenever.cron(@options), comment_close].join("\n") + "\n"
53
+ return '' if @options[:clear]
54
+ @whenever_cron ||= [comment_open, Whenever.cron(@options), comment_close].compact.join("\n") + "\n"
47
55
  end
48
56
 
49
57
  def read_crontab
@@ -53,7 +61,7 @@ module Whenever
53
61
  command << "-u #{@options[:user]}" if @options[:user]
54
62
 
55
63
  command_results = %x[#{command.join(' ')} 2> /dev/null]
56
- @current_crontab = $?.exitstatus.zero? ? command_results : ''
64
+ @current_crontab = $?.exitstatus.zero? ? prepare(command_results) : ''
57
65
  end
58
66
 
59
67
  def write_crontab(contents)
@@ -77,22 +85,28 @@ module Whenever
77
85
  end
78
86
  end
79
87
 
80
- def updated_crontab
88
+ def updated_crontab
81
89
  # Check for unopened or unclosed identifier blocks
82
- if read_crontab.index(comment_open) && !read_crontab.index(comment_close)
90
+ if read_crontab =~ Regexp.new("^#{comment_open}$") && (read_crontab =~ Regexp.new("^#{comment_close}$")).nil?
83
91
  warn "[fail] Unclosed indentifier; Your crontab file contains '#{comment_open}', but no '#{comment_close}'"
84
92
  exit(1)
85
- elsif !read_crontab.index(comment_open) && read_crontab.index(comment_close)
93
+ elsif (read_crontab =~ Regexp.new("^#{comment_open}$")).nil? && read_crontab =~ Regexp.new("^#{comment_close}$")
86
94
  warn "[fail] Unopened indentifier; Your crontab file contains '#{comment_close}', but no '#{comment_open}'"
87
95
  exit(1)
88
96
  end
89
97
 
90
98
  # If an existing identier block is found, replace it with the new cron entries
91
- if read_crontab.index(comment_open) && read_crontab.index(comment_close)
92
- read_crontab.gsub(Regexp.new("#{comment_open}.+#{comment_close}", Regexp::MULTILINE), whenever_cron.chomp)
99
+ if read_crontab =~ Regexp.new("^#{comment_open}$") && read_crontab =~ Regexp.new("^#{comment_close}$")
100
+ # If the existing crontab file contains backslashes they get lost going through gsub.
101
+ # .gsub('\\', '\\\\\\') preserves them. Go figure.
102
+ read_crontab.gsub(Regexp.new("^#{comment_open}$.+^#{comment_close}$", Regexp::MULTILINE), whenever_cron.chomp.gsub('\\', '\\\\\\'))
93
103
  else # Otherwise, append the new cron entries after any existing ones
94
104
  [read_crontab, whenever_cron].join("\n\n")
95
- end
105
+ end.gsub(/\n{3,}/, "\n\n") # More than two newlines becomes just two.
106
+ end
107
+
108
+ def prepare(contents)
109
+ contents.split("\n")[@options[:cut]..-1].join("\n")
96
110
  end
97
111
 
98
112
  def comment_base