bin_diesel 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ # - 1.8.7
5
+ - 2.0.0
6
+ # - 1.9.2
7
+ # - jruby-18mode
8
+ # - jruby-19mode
9
+ notifications:
10
+ email: false
@@ -0,0 +1,85 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ class PurgeableFileList
4
+ KNOWN_SKIPPABLES = ['.', '..']
5
+ attr_reader :files
6
+ def initialize path, age
7
+ @path = path
8
+ @age_cutoff = Time.zone.now - age.days
9
+ generate_file_list
10
+ end
11
+
12
+ private
13
+ def generate_file_list
14
+ get_all_files_in_purge_directory
15
+ remove_known_skippable_files
16
+ remove_files_too_young_to_purge
17
+ end
18
+
19
+ def get_all_files_in_purge_directory
20
+ @files = Dir.entries(@path)
21
+ @files.map!{|file| File.join(@path, file)}
22
+ end
23
+
24
+ def remove_known_skippable_files
25
+ @files = @files - KNOWN_SKIPPABLES
26
+ end
27
+ def remove_files_too_young_to_purge
28
+ @files.reject!{|file| File.mtime(file) > @age_cutoff }
29
+ end
30
+ end
31
+
32
+ class PurgeFiles
33
+ DEFAULT_DAYS_TO_KEEP = 30
34
+
35
+ opts_banner = "Usage: ./purge_report_files.rb [options]"
36
+ opts_description "By default, this will purge UI Report Files, though it can be\nturned on other things with the proper options."
37
+
38
+ opts_required :path_to_purge
39
+ opts_accessor :keep_n_days, :path_to_purge
40
+
41
+ opts_on("-k", "--keep-n-days DAYS", Integer, "Keep N days of files.", "\tDefault: --keep-n-days #{DEFAULT_DAYS_TO_KEEP}") do |days|
42
+ options.keep_n_days = days
43
+ end
44
+
45
+ opts_on("-p", "--path-to-purge PATH", "Purge files from PATH", "Required") do |path|
46
+ options.path_to_purge = path
47
+ end
48
+
49
+
50
+ def post_initialize
51
+ options.keep_n_days ||= DEFAULT_DAYS_TO_KEEP
52
+ end
53
+
54
+ run do
55
+ message "Checking for directory #{options.patth_to_purge}."
56
+ if directory_found?
57
+ message "Directory #{options.path_to_purge} found."
58
+ message "Getting list of files."
59
+ message "#{files.size} files found."
60
+ remove_files
61
+ message "Fin!"
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def directory_found?
68
+ found = File.directory? path_to_purge
69
+ error_message "Directory '#{options.path_to_purge}'not found." unless found
70
+ found
71
+ end
72
+
73
+ def files
74
+ @files ||= PurgeableFileList.new(path_to_purge, keep_n_days).files
75
+ end
76
+
77
+ def remove_files
78
+ files.each do |file|
79
+ message "Deleting '#{file}'."
80
+ File.delete(file) unless options.dry_run
81
+ end
82
+ end
83
+ end
84
+
85
+ exit PurgeFiles.new(ARGV).run
@@ -0,0 +1,48 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # This require allows you to load the Rails environment for use in your scripts.
4
+ require File.expand_path(File.join(File.dirname(__FILE__),'../config/environment.rb'))
5
+
6
+ class Test
7
+ # We are using ActiveSupport Concern. You'll need to do this. If you don't
8
+ # include the Rails environment as part of loading, you'll have to load
9
+ # lib/bin_diesel.rb first.
10
+ include BinDiesel
11
+
12
+ # Message says it all
13
+ def post_initialize
14
+ message "This runs after you initialize the your instance. Could be handy."
15
+ message "You don't need to provide me."
16
+ end
17
+
18
+ # opts_banner is the standard header for how to execute your script.
19
+ opts_banner "Usage: ./my_parse_example.rb [options]"
20
+
21
+ # opts_descriptions is the description of what this script does.
22
+ opts_description "By default, this will be an awesome description."
23
+ opts_description "You can have as many descriptions as you like,\nor add line breaks manually."
24
+
25
+ # opts_on is how you specify additional options for your script
26
+ # You have access to 'options', which is a struct for holding your options.
27
+ # options.dry_run and options.verbose are provided by default, set to false.
28
+ # It takes the option flags, description strings, and a block. Only the first
29
+ # option flag is required.
30
+ opts_on "-p", "--pass-param PARAM", "Pass a param" do |param|
31
+ options.param = param
32
+ end
33
+ opts_on "-r", "--run-fast", "Something" do
34
+ options.fast = true
35
+ end
36
+ opts_on "-x", "marks the spot"
37
+
38
+ # run is is the big deal. It is what will get run when you execute
39
+ # your script. It evaluated in an instance context.
40
+ run do
41
+ message "I only show up if we are verbose and executing."
42
+ puts options
43
+ puts "INSERT CODE WITH SIDE EFFECTS HERE. :)"
44
+ end
45
+ end
46
+ # Run this script ala the command line...
47
+ # exit Test.new(ARGV).run
48
+ # > ./bin/test -v
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bin_diesel.gemspec
4
+ gemspec
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2013, Andrew J Vargo
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+ * Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ * Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+ * Neither the name of the <organization> nor the
12
+ names of its contributors may be used to endorse or promote products
13
+ derived from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,240 @@
1
+ # Bin Diesel
2
+
3
+ ## Build Status
4
+
5
+ ![Build Status](https://api.travis-ci.org/dataxu/bin_diesel.png)
6
+
7
+ [Brought to you by the fine folks at Travis-CI](https://travis-ci.org/dataxu/bin_diesel)
8
+
9
+ ## Introduction
10
+ Bin Diesel is a utility that will allow you to create re-usable, executable scripts easier.
11
+
12
+ Bin Diesel abstracts option parsing to simplify your 'bin' scripting. It provides a number of wrapper methods for OptionParser, so I'd suggest having a look at that documentation to understand more of what this provides. [OptionParser Complete Example](http://ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/OptionParser.html#label-Complete+example)
13
+
14
+ ## What's provided? AKA, the API
15
+
16
+ It is important to note that methods are executed in the order defined. This means you should set all options and text helpers *before* defining `run`.
17
+
18
+ ### Default options
19
+
20
+ Using Bin Diesel, you get the following options for free:
21
+
22
+ * `-d`, `--dry-run`, Run script without any real changes. Sets `@dry_run` and `options.dry_run` to `true`. Sets --verbose by default.`
23
+
24
+ The intent of `--dry-run` is to provide you with a way to run through the script and note output to verify that the script runs as intended.
25
+ We generally use this flag on `ActiveRecord` calls. For example:
26
+
27
+ ```ruby
28
+ # ...
29
+ run do
30
+ users = User.where(organization: Organization.where(name: 'DataXu'))
31
+ message "Updating #{users.count} DataXu users to be admins"
32
+ users.update_all(admin: true) unless options.dry_run
33
+ end
34
+ # ...
35
+ ```
36
+
37
+ The first time through, users can run the script with `--dry-run` and note the number of users that would be modified. A second run of the script without the `--dry-run` option
38
+ will make the modifications.
39
+
40
+ * `-v, --[no-]verbose, Run verbosely`
41
+
42
+ * `-h, --help, Show description and options, and exit`
43
+
44
+ ### Attributes for your ready use
45
+
46
+ * `verbose` - false by default
47
+
48
+ The built in message helpers won't print if verbose if false, saving you the hassle.
49
+
50
+ ```ruby
51
+ puts 'Something' if verbose
52
+ message "Event" # I only print if verbose is true!
53
+ ```
54
+
55
+ * `options`
56
+
57
+ This is a struct that allows you to access options you configure. Options are generally defined in `opts_on` blocks. For example:
58
+
59
+ ```ruby
60
+ class SimpleScript
61
+ include BinDiesel
62
+
63
+ # Accepts three arguments and a block. The signature is:
64
+ # opts_on [short flag], [long flag], [help text for the option]
65
+ opts_on '-f', '--file [FILE]', 'The file to operate on' do |file_name|
66
+ options.file_name = file_name
67
+ end
68
+ end
69
+ ```
70
+
71
+ The first two arguments define the short and long switches for the option. The remaining N arguments are used as a description of the option (separated by newlines) displayed when the '--help' switch is provided.
72
+
73
+ See [the OptionParser documentation for `#make_switch`](http://ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/OptionParser.html#method-i-make_switch) for
74
+ a description of the arguments `opts_on` accepts. If the defined option accepts a value, the value will be passed to the block.
75
+
76
+ * `dry_run` - false by default. This is also available through `options.dry_run`.
77
+
78
+ ```ruby
79
+ do_irrevocable_change unless dry_run
80
+ ```
81
+
82
+ * `args`
83
+
84
+ The args passed in to the run method. You may have a required thing that isn't a `--option` you need to use. This is generally an array that looks something like this (depending on the options supplied at the command line):
85
+
86
+ ```ruby
87
+ ['--file', 'file_name.txt', '--verbose', '--dry-run']
88
+ ```
89
+
90
+ ### Methods for your use
91
+
92
+ * `opts_banner(text)`
93
+
94
+ Set banner text for your script. Usually the bare usage line to show an example run.
95
+
96
+ * `opts_description(text)`
97
+
98
+ Longer form text explaining what your script does.
99
+
100
+ * `opts_on *opts, &block`
101
+
102
+ Meat and potatoes. This is what you'll use to set your own options. The examples provided or [OptionParser Complete example](http://ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/OptionParser.html#label-Complete+example) will give you more of an idea of what is possible. Also see [the OptionParser documentation for `#make_switch`](http://ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/OptionParser.html#method-i-make_switch).
103
+
104
+ Note the usage of `options` in the block to set values you'll use in your executing code. Instance variables (instead of using `options`) are also acceptable.
105
+
106
+ ```ruby
107
+ opts.on("-d", "--dry-run", "Run script without any real changes.", "\tSets --verbose by default.") do |dry_run|
108
+ options.dry_run = true
109
+ options.verbose = true
110
+ end
111
+ ```
112
+
113
+ * `opts_required *args`
114
+
115
+ When parsing is done, `OptionParser::MissingArguement` will be raised for anything specified here that `options` does not respond to.
116
+
117
+ ```ruby
118
+ opts_required :path
119
+ # if you never set options.path, things go BOOM.
120
+ ```
121
+
122
+ * `opts_accessor *args`
123
+
124
+ Turns the provided args into accessors to help in your script writing.
125
+
126
+ ```ruby
127
+ opts_accessor :path
128
+ # allows
129
+ File.open path
130
+ # instead of
131
+ File.open options.path
132
+ # or
133
+ File.open @path
134
+ ```
135
+
136
+ * `dry_run?`
137
+
138
+ Some sugar for checking if `dry_run` was set.
139
+
140
+ ```ruby
141
+ save_records unless dry_run?
142
+ ```
143
+
144
+ * `post_initialize`
145
+
146
+ Provided so you don't have to overide Bin Diesel's initialize method. It executes *after* all the parsing and what not, so you'll have access to options and the accessors.
147
+
148
+ ```ruby
149
+ class SimpleExample
150
+ include BinDiesel
151
+
152
+ post_initialize do
153
+ # Set some other useful instance variables
154
+ @base_directory = File.dirname(__FILE__)
155
+ end
156
+ end
157
+ ```
158
+
159
+ * `run &block`
160
+
161
+ This is the big deal of your script. You should use this as the method that'll be called to kick off your script. We do nice things for you, like catch exceptions and exit and return 1 or return 0 if all goes well.
162
+
163
+ If `run` is not implemented, the script will raise `NotImplementedError.
164
+
165
+ ```ruby
166
+ run do
167
+ campaigns = find_campaigns(options.campaign_uids)
168
+ campaigns.each do |campaign|
169
+ campaign.update_attribute(:name, "#{campaign.name} Update Example") unless options.dry_run
170
+ end
171
+ end
172
+ ```
173
+
174
+ * `message(text)`
175
+
176
+ puts text if `verbose` is set to `false`. This is an extremely simple wrapper around `puts`:
177
+
178
+ ```ruby
179
+ def message(text)
180
+ puts text if verbose
181
+ end
182
+ ```
183
+
184
+ * `info_message(text)`
185
+
186
+ Like `message`, but prepends with `**`
187
+
188
+ * `error_message(text)`
189
+
190
+ `puts` text, no matter the setting of `verbose`. It also prepends text with "!! "
191
+
192
+ ## Installation
193
+
194
+ Add this line to your application's Gemfile:
195
+
196
+ gem 'bin_diesel'
197
+
198
+ And then execute:
199
+
200
+ $ bundle
201
+
202
+ Or install it yourself as:
203
+
204
+ $ gem install bin_diesel
205
+
206
+ ## Usage
207
+
208
+ This is the most basic way to use Bin Diesel:
209
+
210
+ ```ruby
211
+ #! /usr/bin/env ruby
212
+
213
+ class MyScript
214
+ include BinDiesel # ahh yeah, goodies
215
+
216
+ post_initialize do
217
+ # Do some stuff with options before `run` is called
218
+ end
219
+
220
+ run do
221
+ # I am required and will throw and exception if not defined.
222
+ # This is what you should call, and should contain the main logic of your script.
223
+ # If there is no exception, it'll return 0, otherwise 1 for use as an exit code
224
+ end
225
+ end
226
+
227
+ if __FILE__ == $0 # don't run it if not called alone
228
+ exit MyScript.new(ARGV).run # the 0 or 1 allows you to get a proper exit code
229
+ end
230
+ ```
231
+
232
+ See the Examples directory for more examples.
233
+
234
+ ## Contributing
235
+
236
+ 1. Fork it
237
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
238
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
239
+ 4. Push to the branch (`git push origin my-new-feature`)
240
+ 5. Create new Pull Request
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs.push "test"
6
+ t.pattern = 'test/**/*_test.rb'
7
+ t.warning = true
8
+ end
9
+
10
+ task default: :test
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'bin_diesel/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "bin_diesel"
8
+ spec.version = BinDiesel::VERSION
9
+ spec.authors = ["Andrew J Vargo", "Anthony White"]
10
+ spec.email = ["avargo@dataxu.com", "awhite@dataxu.com"]
11
+ spec.description = %q{Bin Diesel allows you to write scripts relying on Option Parser with DSL that eliminates the boiler plate code. Define options and run. }
12
+ spec.summary = %q{Easier "bin" scripts built with Option Parser.}
13
+ spec.homepage = "http://www.dataxu.com"
14
+ spec.license = "New BSD License"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "minitest"
24
+ spec.add_development_dependency "debugger"
25
+ end
@@ -0,0 +1,185 @@
1
+ require_relative "bin_diesel/version"
2
+ require 'optparse'
3
+ require 'ostruct'
4
+
5
+
6
+ module BinDiesel
7
+ OPTS = {:banner => nil, :description => [], :user_options => [], :required_options => [], :accessible_options => []}
8
+ attr_reader :verbose, :options, :args, :dry_run
9
+
10
+ module ClassMethods
11
+ def run &block
12
+ define_method :run do
13
+ begin
14
+ puts "DRY RUN" if options.dry_run
15
+ instance_eval(&block)
16
+ ending = happy_ending
17
+ rescue Exception => e
18
+ error_message "FAILED: #{e.message}"
19
+ puts e.backtrace
20
+ ending = unhappy_ending
21
+ ensure
22
+ ending
23
+ end
24
+ end
25
+ end
26
+
27
+ def post_initialize &block
28
+ define_method :post_initialize do
29
+ instance_eval(&block)
30
+ end
31
+ end
32
+
33
+ def opts_banner text
34
+ OPTS[:banner] = text
35
+ end
36
+
37
+ def opts_description text
38
+ OPTS[:description] << text
39
+ end
40
+
41
+ def opts_on *opts, &block
42
+ OPTS[:user_options] << {:options => opts, :block => block }
43
+ end
44
+
45
+ def opts_required *args
46
+ OPTS[:required_options] += args
47
+ end
48
+
49
+ def opts_accessor *args
50
+ OPTS[:accessible_options] += args
51
+ end
52
+ end
53
+
54
+ module InstanceMethods
55
+ def initialize args=["--help"]
56
+ @args = args
57
+ @options = OpenStruct.new(:dry_run => false, :verbose => false)
58
+
59
+ begin
60
+ parse_options
61
+ rescue OptionParser::MissingArgument => e
62
+ error_message e.message
63
+ exit unhappy_ending
64
+ end
65
+
66
+ @verbose = @options.verbose
67
+ @dry_run = @options.dry_run
68
+
69
+ setup_option_accessors
70
+
71
+ begin
72
+ post_initialize
73
+ rescue Exception => e
74
+ error_message e.message
75
+ exit unhappy_ending
76
+ end
77
+ end
78
+
79
+ def dry_run?
80
+ @options.dry_run
81
+ end
82
+
83
+ def run
84
+ raise NotImplementedError, "#{self.class} does not implement method run. You may do this explictly, or via the class level DSL (recommended):\nrun do\n ...\nend"
85
+ end
86
+
87
+ def post_initialize
88
+ # TODO: EXPLAIN ME
89
+ end
90
+
91
+ def message text
92
+ puts text if verbose
93
+ end
94
+
95
+ def info_message text
96
+ message "** #{text}"
97
+ end
98
+
99
+ def error_message text
100
+ # Always print out error messages, regardless of verbose mode
101
+ puts "!! #{text}"
102
+ end
103
+
104
+ private
105
+
106
+ def happy_ending
107
+ 0
108
+ end
109
+
110
+ def unhappy_ending
111
+ 1
112
+ end
113
+
114
+ def setup_option_accessors
115
+ OPTS[:accessible_options].each do |opt|
116
+ define_singleton_method opt do
117
+ @options.send(opt)
118
+ end
119
+
120
+ define_singleton_method "#{opt}=" do |val|
121
+ @options.send("#{opt}=", val)
122
+ end
123
+ end
124
+ end
125
+
126
+ def parse_options
127
+ opts = OptionParser.new do |opt_parser|
128
+ opt_parser.banner = OPTS[:banner]
129
+ opt_parser.separator ""
130
+
131
+ OPTS[:description].each{|description| opt_parser.separator description }
132
+ opt_parser.separator ""
133
+
134
+ opt_parser.separator "Specific options:"
135
+ opt_parser.on("-d", "--dry-run", "Run script without any real changes.", "\tSets --verbose by default.") do |dry_run|
136
+ options.dry_run = true
137
+ options.verbose = true
138
+ end
139
+
140
+ opt_parser.on("-v", "--[no-]verbose", "Run verbosely") do |v|
141
+ options.verbose = v
142
+ end
143
+ opt_parser.separator ""
144
+
145
+ # USER SPECIFIED
146
+ OPTS[:user_options].each do |option|
147
+ # We allow the user to define the proc for the opts.on block via option[:block].
148
+ # OptionParser can get confused by the last argument (the block), and sometimes defines it twice,
149
+ # which blows up spectacularly with an ArgumentError
150
+ option[:options].reject! {|o| o.class.to_s == 'Proc'}
151
+
152
+ if option[:block]
153
+ opt_parser.on(*(option[:options] << Proc.new{|*args| self.instance_exec(*args, &option[:block])}))
154
+ else
155
+ opt_parser.on(*option[:options])
156
+ end
157
+ end
158
+ opt_parser.separator ""
159
+
160
+ opt_parser.separator "Common options:"
161
+ opt_parser.on_tail("-h", "--help", "Show this message") do
162
+ puts opt_parser
163
+ exit happy_ending
164
+ end
165
+ end
166
+
167
+ the_options = opts.parse! args
168
+
169
+ OPTS[:required_options].each do |required_option|
170
+ raise OptionParser::MissingArgument.new("#{optionize(required_option.to_s)} - Run with --help for help.") if @options.send(required_option).nil?
171
+ end
172
+
173
+ the_options
174
+ end
175
+
176
+ def optionize string
177
+ "--#{string.gsub('_', '-')}"
178
+ end
179
+ end
180
+
181
+ def self.included(base)
182
+ base.send :include, InstanceMethods
183
+ base.send :extend, ClassMethods
184
+ end
185
+ end
@@ -0,0 +1,3 @@
1
+ module BinDiesel
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,7 @@
1
+ require_relative '../../test_helper'
2
+
3
+ describe BinDiesel do
4
+ it "must be defined" do
5
+ BinDiesel::VERSION.wont_be_nil
6
+ end
7
+ end
@@ -0,0 +1,462 @@
1
+ require_relative '../../lib/bin_diesel'
2
+ require_relative '../test_helper'
3
+
4
+ describe BinDiesel do
5
+ describe "help flag" do
6
+ it 'is equivalent to call -h and --help' do
7
+ vincent = Class.new(TestDiesel)
8
+
9
+ help_output = capture_std_out do
10
+ swallow_exit { vincent.new(['--help']).run }
11
+ end
12
+
13
+ h_output = capture_std_out do
14
+ swallow_exit { vincent.new(['-h']).run }
15
+ end
16
+
17
+ help_output.must_equal(h_output)
18
+ end
19
+
20
+ it 'swallows other options if help is called' do
21
+ vincent = Class.new(TestDiesel) do
22
+ opts_banner "This is my banner"
23
+
24
+ opts_on '-e', '--error', 'Raise an error' do
25
+ options.error = "Raised error"
26
+ end
27
+
28
+ run do
29
+ puts options.error
30
+ end
31
+ end
32
+
33
+ swallow_exit do
34
+ lambda { vincent.new(['--error', '--help']).run }.must_output "This is my banner"
35
+ end
36
+ end
37
+
38
+ it 'raises a system exit' do
39
+ vincent = Class.new(TestDiesel)
40
+ swallow_std_out do
41
+ lambda{ vincent.new(["--help"]).run }.must_raise(SystemExit)
42
+ end
43
+ end
44
+
45
+ it 'is not required' do
46
+ vincent = Class.new(TestDiesel) do
47
+ opts_banner "And here is my banner"
48
+ end
49
+
50
+ swallow_exit do
51
+ lambda{ vincent.new.run }.must_output("-h, --help")
52
+ end
53
+ end
54
+
55
+ describe "opts_banner" do
56
+ it 'prints specified text on the first line when using a help flag' do
57
+ swallow_exit do
58
+ lambda{TestDiesel.new(["--help"]).run}.must_output("And here is my banner")
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ describe "opts_description" do
65
+ it 'prints in help text' do
66
+ vincent = Class.new(TestDiesel) do
67
+ opts_description "My description"
68
+ end
69
+
70
+ swallow_exit do
71
+ lambda { vincent.new(['--help']).run }.must_output("My description")
72
+ end
73
+ end
74
+
75
+ it 'prints after banner in help text' do
76
+ vincent = Class.new(TestDiesel) do
77
+ opts_banner "The banner"
78
+ opts_description "The description"
79
+ end
80
+
81
+ swallow_exit do
82
+ lambda { vincent.new(['--help']).run }.must_output("The banner\n\nThe description")
83
+ end
84
+ end
85
+
86
+ it 'is not required' do
87
+ vincent = Class.new(TestDiesel) do
88
+ opts_banner "My banner"
89
+ end
90
+
91
+ swallow_exit do
92
+ lambda { vincent.new(['--help']).run }.must_output("My banner")
93
+ end
94
+ end
95
+
96
+ it 'prints in order specified, on separate lines' do
97
+ vincent = Class.new(TestDiesel) do
98
+ opts_banner "My Banner"
99
+
100
+ opts_description "description 1"
101
+ opts_description "description 2"
102
+ end
103
+
104
+ swallow_exit do
105
+ lambda { vincent.new(['--help']).run }.must_output("description 1\ndescription 2")
106
+ end
107
+ end
108
+ end
109
+
110
+ describe "opts_required" do
111
+ it 'raises an error if option not given during execution' do
112
+ vincent = Class.new(TestDiesel) do
113
+ opts_on '-r', '--required OPTION', 'A required option' do |value|
114
+ options.required = value
115
+ end
116
+
117
+ opts_required :required
118
+ end
119
+
120
+ swallow_exit do
121
+ lambda { vincent.new([]) }.must_output("!! missing argument: --required - Run with --help for help")
122
+ end
123
+ end
124
+
125
+ it 'allows for more than one required option at a time' do
126
+ vincent = Class.new(TestDiesel) do
127
+ opts_on '-r', '--required OPTION', 'A required option' do |value|
128
+ options.required = value
129
+ end
130
+
131
+ opts_on '-o', '--option OPTION', 'Another required option' do |value|
132
+ options.option = value
133
+ end
134
+
135
+ opts_required :required, :option
136
+ end
137
+
138
+ swallow_exit do
139
+ -> { vincent.new([]) }.must_output "!! missing argument: --required"
140
+ -> { vincent.new(['--required', 'test']) }.must_output "!! missing argument: --option"
141
+ end
142
+ end
143
+
144
+ it 'allows for more than one required option, specified in different calls' do
145
+ vincent = Class.new(TestDiesel) do
146
+ opts_on '-r', '--required OPTION', 'A required option' do |value|
147
+ options.required = value
148
+ end
149
+
150
+ opts_on '-o', '--option OPTION', 'Another required option' do |value|
151
+ options.option = value
152
+ end
153
+
154
+ opts_required :required
155
+ opts_required :option
156
+ end
157
+
158
+ swallow_exit do
159
+ -> { vincent.new([]) }.must_output "!! missing argument: --required"
160
+ -> { vincent.new(['--required', 'test']) }.must_output "!! missing argument: --option"
161
+ end
162
+ end
163
+ end
164
+
165
+ describe "opts_accessor" do
166
+ it 'sets an attribute_reader for the given option' do
167
+ vincent = Class.new(TestDiesel) do
168
+ opts_on '-o', '--option [OPTION]', 'An option' do |value|
169
+ options.option = value
170
+ end
171
+
172
+ opts_accessor :option
173
+ end
174
+
175
+ swallow_exit do
176
+ vincent.new(['--option', 'value']).option.must_equal('value')
177
+ end
178
+ end
179
+
180
+ it 'allows for more than one option accessor at one time' do
181
+ vincent = Class.new(TestDiesel) do
182
+ opts_on '-o', '--option [OPTION]', 'An option' do |value|
183
+ options.option = value
184
+ end
185
+
186
+ opts_on '-a', '--another-option [OPTION]', 'Another option' do |value|
187
+ options.another_option = value
188
+ end
189
+
190
+ opts_accessor :option, :another_option
191
+ end
192
+
193
+ swallow_exit do
194
+ vincent.new(['--option', 'value']).option.must_equal('value')
195
+ vincent.new(['--another-option', 'value']).another_option.must_equal('value')
196
+ end
197
+ end
198
+
199
+ it 'allows for more than one option accessor, specified in different calls' do
200
+ vincent = Class.new(TestDiesel) do
201
+ opts_on '-o', '--option [OPTION]', 'An option' do |value|
202
+ options.option = value
203
+ end
204
+
205
+ opts_on '-a', '--another-option [OPTION]', 'Another option' do |value|
206
+ options.another_option = value
207
+ end
208
+
209
+ opts_accessor :option
210
+ opts_accessor :another_option
211
+ end
212
+
213
+ swallow_exit do
214
+ vincent.new(['--option', 'value']).option.must_equal('value')
215
+ vincent.new(['--another-option', 'value']).another_option.must_equal('value')
216
+ end
217
+ end
218
+
219
+ end
220
+
221
+ describe "opts_on" do
222
+ it 'outputs help for the option with the --help flag' do
223
+ vincent = Class.new(TestDiesel) do
224
+ opts_on '-f', '--flag', 'A boolean flag' do |value|
225
+ options.flag = value
226
+ end
227
+ end
228
+
229
+ swallow_exit do
230
+ lambda { vincent.new(['--help']).run }.must_output("A boolean flag")
231
+ end
232
+ end
233
+
234
+ it 'allows boolean options' do
235
+ vincent = Class.new(TestDiesel) do
236
+ opts_on '-b', '--boolean-flag', 'A boolean flag' do |value|
237
+ options.flag = value
238
+ end
239
+
240
+ run do
241
+ puts "flag: #{flag}"
242
+ end
243
+ end
244
+
245
+ swallow_exit do
246
+ vbomb = vincent.new(['--boolean-flag'])
247
+ vbomb.instance_variable_get(:@options).flag.must_equal(true)
248
+ end
249
+ end
250
+
251
+ it 'allows options with user supplied values' do
252
+ vincent = Class.new(TestDiesel) do
253
+ opts_on '-u', '--user-specified [OPTION]', 'A user specified option' do |value|
254
+ options.user_specified = value
255
+ end
256
+
257
+ run do
258
+ puts "user_specified: #{options.user_specified}"
259
+ end
260
+ end
261
+
262
+ swallow_exit do
263
+ vbomb = vincent.new(['--user-specified', 'option'])
264
+ vbomb.instance_variable_get(:@options).user_specified.must_equal('option')
265
+ end
266
+ end
267
+
268
+ it 'accepts a short flag' do
269
+ vincent = Class.new(TestDiesel) do
270
+ opts_on '-s', '--short [OPTION]', 'A short option' do |value|
271
+ options.short = value
272
+ end
273
+ end
274
+
275
+ swallow_exit do
276
+ vbomb = vincent.new(['-s', 'short'])
277
+ vbomb.instance_variable_get(:@options).short.must_equal('short')
278
+ end
279
+ end
280
+
281
+ it 'accepts a long flag' do
282
+ vincent = Class.new(TestDiesel) do
283
+ opts_on '-l', '--long [OPTION]', 'A long flag' do |value|
284
+ options.long = value
285
+ end
286
+ end
287
+
288
+ swallow_exit do
289
+ vbomb = vincent.new(['--long', 'long'])
290
+ vbomb.instance_variable_get(:@options).long.must_equal('long')
291
+ end
292
+ end
293
+ end
294
+
295
+ describe "dry_run flag" do
296
+ it 'sets the `dry_run` var to true' do
297
+ vincent = Class.new(TestDiesel)
298
+
299
+ swallow_exit do
300
+ vincent.new(['--dry-run']).dry_run.must_equal(true)
301
+ end
302
+ end
303
+ end
304
+
305
+ describe "verbose flag" do
306
+ it 'sets the `verbose` var to true' do
307
+ swallow_exit do
308
+ TestDiesel.new(['--verbose']).verbose.must_equal(true)
309
+ end
310
+ end
311
+
312
+ it 'allows info messages to be printed' do
313
+ vincent = Class.new(TestDiesel) do
314
+ run do
315
+ info_message "An info message"
316
+ end
317
+ end
318
+
319
+ swallow_exit do
320
+ -> { vincent.new(['--verbose']).run }.must_output("** An info message\n")
321
+ end
322
+ end
323
+
324
+ it 'allows messages from `message` to be printed' do
325
+ vincent = Class.new(TestDiesel) do
326
+ run do
327
+ message "A message"
328
+ end
329
+ end
330
+
331
+ swallow_exit do
332
+ -> { vincent.new(['--verbose']).run }.must_output("A message\n")
333
+ end
334
+ end
335
+ end
336
+
337
+ describe "post_initialize" do
338
+ it 'runs before `run`' do
339
+ vincent = Class.new(TestDiesel) do
340
+ post_initialize do
341
+ message "post-initialize"
342
+ end
343
+
344
+ run do
345
+ message "run"
346
+ end
347
+ end
348
+
349
+ swallow_exit do
350
+ -> { vincent.new(['--verbose']).run }.must_output("post-initialize\nrun\n")
351
+ end
352
+ end
353
+ end
354
+
355
+ describe "message" do
356
+ it 'prints messages when verbose is true' do
357
+ vincent = Class.new(TestDiesel) do
358
+ run do
359
+ message "A message"
360
+ end
361
+ end
362
+
363
+ swallow_exit do
364
+ -> { vincent.new(['--verbose']).run }.must_output("A message\n")
365
+ end
366
+ end
367
+
368
+ it 'does not print messages when verbose is false' do
369
+ vincent = Class.new(TestDiesel) do
370
+ run do
371
+ message "A message"
372
+ end
373
+ end
374
+
375
+ output = capture_std_out do
376
+ swallow_exit { vincent.new([]).run }
377
+ end
378
+
379
+ output.to_s.wont_include("A message")
380
+ end
381
+ end
382
+
383
+ describe "info_message" do
384
+ it 'prepends messages with `**`' do
385
+ vincent = Class.new(TestDiesel) do
386
+ run do
387
+ info_message("An info message")
388
+ end
389
+ end
390
+
391
+ swallow_exit do
392
+ -> { vincent.new(['--verbose']).run }.must_output("** An info message\n")
393
+ end
394
+ end
395
+
396
+ it 'does not print messages when verbose is false' do
397
+ vincent = Class.new(TestDiesel) do
398
+ run do
399
+ info_message("An info message")
400
+ end
401
+ end
402
+
403
+ output = capture_std_out do
404
+ swallow_exit { vincent.new([]).run }
405
+ end
406
+
407
+ output.to_s.wont_include("** An info message")
408
+ end
409
+
410
+ it 'prints messages when verbose is true' do
411
+ vincent = Class.new(TestDiesel) do
412
+ run do
413
+ info_message "An info message"
414
+ end
415
+ end
416
+
417
+ swallow_exit do
418
+ -> { vincent.new(['--verbose']).run }.must_output("** An info message\n")
419
+ end
420
+ end
421
+ end
422
+
423
+ describe "error_message" do
424
+ it 'prepends messages with `!!`' do
425
+ vincent = Class.new(TestDiesel) do
426
+ run do
427
+ error_message("An error message")
428
+ end
429
+ end
430
+
431
+ swallow_exit do
432
+ -> { vincent.new(['--verbose']).run }.must_output("!! An error message\n")
433
+ end
434
+ end
435
+
436
+ it 'prints messages regardless of `verbose`' do
437
+ vincent = Class.new(TestDiesel) do
438
+ run do
439
+ error_message("An error message")
440
+ end
441
+ end
442
+
443
+ swallow_exit do
444
+ -> { vincent.new([]).run }.must_output("!! An error message\n")
445
+ end
446
+ end
447
+ end
448
+
449
+ describe "dry_run?" do
450
+ it 'returns true if the dry-run option is set' do
451
+ swallow_exit do
452
+ TestDiesel.new(['--dry-run']).dry_run?.must_equal(true)
453
+ end
454
+ end
455
+
456
+ it 'returns false if the dry-run option is not set' do
457
+ swallow_exit do
458
+ TestDiesel.new([]).dry_run?.must_equal(false)
459
+ end
460
+ end
461
+ end
462
+ end
@@ -0,0 +1,5 @@
1
+ class TestDiesel
2
+ include BinDiesel
3
+ def run
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ require 'minitest/autorun'
2
+ require File.expand_path('../../lib/bin_diesel.rb', __FILE__)
3
+ require 'test_diesel'
4
+ require 'stringio'
5
+ require 'debugger'
6
+
7
+ def swallow_std_out
8
+ out = StringIO.new
9
+ $stdout = out
10
+ yield
11
+ ensure
12
+ $stdout = STDOUT
13
+ end
14
+
15
+ def capture_std_out
16
+ out = StringIO.new
17
+ $stdout = out
18
+ yield
19
+ ensure
20
+ $stdout = STDOUT
21
+ out
22
+ end
23
+
24
+ def swallow_exit
25
+ begin
26
+ yield
27
+ rescue SystemExit
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bin_diesel
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Andrew J Vargo
9
+ - Anthony White
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2014-09-03 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: bundler
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '1.3'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '1.3'
31
+ - !ruby/object:Gem::Dependency
32
+ name: rake
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: minitest
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: debugger
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ description: ! 'Bin Diesel allows you to write scripts relying on Option Parser with
80
+ DSL that eliminates the boiler plate code. Define options and run. '
81
+ email:
82
+ - avargo@dataxu.com
83
+ - awhite@dataxu.com
84
+ executables: []
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - .gitignore
89
+ - .travis.yml
90
+ - Examples/purge_files.rb
91
+ - Examples/test.rb
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - bin_diesel.gemspec
97
+ - lib/bin_diesel.rb
98
+ - lib/bin_diesel/version.rb
99
+ - test/lib/bin_diesel/version_test.rb
100
+ - test/lib/bin_diesel_test.rb
101
+ - test/test_diesel.rb
102
+ - test/test_helper.rb
103
+ homepage: http://www.dataxu.com
104
+ licenses:
105
+ - New BSD License
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project:
124
+ rubygems_version: 1.8.23
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Easier "bin" scripts built with Option Parser.
128
+ test_files:
129
+ - test/lib/bin_diesel/version_test.rb
130
+ - test/lib/bin_diesel_test.rb
131
+ - test/test_diesel.rb
132
+ - test/test_helper.rb
133
+ has_rdoc: