coursemology-evaluator 0.1.6 → 0.1.7
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.
- checksums.yaml +4 -4
- data/.env +3 -3
- data/.gitignore +23 -23
- data/.hound.yml +8 -8
- data/.idea/Coursemology Evaluator.iml +8 -8
- data/.rspec +2 -2
- data/.rubocop.unhound.yml +109 -109
- data/.rubocop.yml +46 -46
- data/.travis.yml +17 -17
- data/Gemfile +4 -4
- data/Procfile +1 -1
- data/README.md +52 -52
- data/Rakefile +6 -6
- data/bin/evaluator +5 -5
- data/coursemology-evaluator.gemspec +38 -38
- data/lib/coursemology/evaluator.rb +41 -41
- data/lib/coursemology/evaluator/cli.rb +74 -74
- data/lib/coursemology/evaluator/client.rb +84 -84
- data/lib/coursemology/evaluator/docker_container.rb +79 -79
- data/lib/coursemology/evaluator/logging.rb +12 -12
- data/lib/coursemology/evaluator/logging/client_log_subscriber.rb +25 -25
- data/lib/coursemology/evaluator/logging/docker_log_subscriber.rb +21 -21
- data/lib/coursemology/evaluator/models.rb +7 -7
- data/lib/coursemology/evaluator/models/base.rb +50 -50
- data/lib/coursemology/evaluator/models/programming_evaluation.rb +55 -55
- data/lib/coursemology/evaluator/models/programming_evaluation/package.rb +12 -12
- data/lib/coursemology/evaluator/services.rb +6 -6
- data/lib/coursemology/evaluator/services/evaluate_programming_package_service.rb +151 -151
- data/lib/coursemology/evaluator/string_io.rb +14 -14
- data/lib/coursemology/evaluator/utils.rb +42 -42
- data/lib/coursemology/evaluator/version.rb +5 -5
- data/lib/coursemology/polyglot/extensions.rb +3 -3
- data/lib/coursemology/polyglot/extensions/language.rb +24 -24
- metadata +3 -3
data/Gemfile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in coursemology-evaluator.gemspec
|
4
|
-
gemspec
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in coursemology-evaluator.gemspec
|
4
|
+
gemspec
|
data/Procfile
CHANGED
@@ -1 +1 @@
|
|
1
|
-
evaluator: evaluator --host=$HOST --api-token=$API_TOKEN --api-user-email=$API_USER_EMAIL
|
1
|
+
evaluator: evaluator --host=$HOST --api-token=$API_TOKEN --api-user-email=$API_USER_EMAIL
|
data/README.md
CHANGED
@@ -1,52 +1,52 @@
|
|
1
|
-
# Coursemology Code Evaluator [](https://travis-ci.org/Coursemology/evaluator-slave)
|
2
|
-
[](https://codeclimate.com/github/Coursemology/evaluator-slave) [](https://coveralls.io/github/Coursemology/evaluator-slave?branch=master) [](https://hakiri.io/github/Coursemology/evaluator-slave/master) [](http://inch-ci.org/github/coursemology/evaluator-slave) [](https://badge.fury.io/rb/coursemology-evaluator)
|
3
|
-
|
4
|
-
This is the evaluator program which will query Coursemology for pending evaluation jobs.
|
5
|
-
|
6
|
-
## Setting up the Evaluator Slave
|
7
|
-
|
8
|
-
### System Requirements
|
9
|
-
|
10
|
-
1. Ruby (>= 2.1.0)
|
11
|
-
2. Linux (tested on Ubuntu 14.04)
|
12
|
-
3. Docker (the user the evaluator runs as must be able to talk to the Docker Remote API endpoint)
|
13
|
-
|
14
|
-
### Getting Started
|
15
|
-
|
16
|
-
1. Install the gem
|
17
|
-
|
18
|
-
```sh
|
19
|
-
$ gem install coursemology-evaluator
|
20
|
-
```
|
21
|
-
|
22
|
-
2. Modify `.env` to suit your environment. Point to the host to your Coursemology instance, and
|
23
|
-
specify the API email and API key.
|
24
|
-
|
25
|
-
1. You might need to configure a new user on your Coursemology instance, enable token
|
26
|
-
authentication, and grant the `auto_grader` system/instance permission.
|
27
|
-
|
28
|
-
3. Start the evaluator using the Procfile. You can use [foreman](https://github.com/ddollar/foreman)
|
29
|
-
or any similar tool to generate system scripts for boot.
|
30
|
-
|
31
|
-
### Command Line Options
|
32
|
-
|
33
|
-
#### Compulsory Options
|
34
|
-
|
35
|
-
1. `--host`: Coursemology host to connect to
|
36
|
-
2. `--api-user-email`: User with autograder flag set
|
37
|
-
3. `--api-token`: Authentication token of the user
|
38
|
-
|
39
|
-
#### Optional Options
|
40
|
-
|
41
|
-
Time options are expected to be strings in [ISO8601 format](https://en.wikipedia.org/wiki/ISO_8601#Durations).
|
42
|
-
|
43
|
-
1. `--interval`: Time interval between checks for programming allocations. As this time is
|
44
|
-
expected to be short, specify it with the time components of ISO8601 only. (Hours, minutes, seconds)
|
45
|
-
The time designator `T` must be left out.
|
46
|
-
|
47
|
-
2. `--lifetime`: Length of time to cache Docker images. This is expected to be in the order of days.
|
48
|
-
If more granularity is needed, the time designator is required.
|
49
|
-
|
50
|
-
E.g. `1DT2H5M10S`
|
51
|
-
|
52
|
-
3. `--one-shot`: Runs once and terminates. Primarily used for testing.
|
1
|
+
# Coursemology Code Evaluator [](https://travis-ci.org/Coursemology/evaluator-slave)
|
2
|
+
[](https://codeclimate.com/github/Coursemology/evaluator-slave) [](https://coveralls.io/github/Coursemology/evaluator-slave?branch=master) [](https://hakiri.io/github/Coursemology/evaluator-slave/master) [](http://inch-ci.org/github/coursemology/evaluator-slave) [](https://badge.fury.io/rb/coursemology-evaluator)
|
3
|
+
|
4
|
+
This is the evaluator program which will query Coursemology for pending evaluation jobs.
|
5
|
+
|
6
|
+
## Setting up the Evaluator Slave
|
7
|
+
|
8
|
+
### System Requirements
|
9
|
+
|
10
|
+
1. Ruby (>= 2.1.0)
|
11
|
+
2. Linux (tested on Ubuntu 14.04)
|
12
|
+
3. Docker (the user the evaluator runs as must be able to talk to the Docker Remote API endpoint)
|
13
|
+
|
14
|
+
### Getting Started
|
15
|
+
|
16
|
+
1. Install the gem
|
17
|
+
|
18
|
+
```sh
|
19
|
+
$ gem install coursemology-evaluator
|
20
|
+
```
|
21
|
+
|
22
|
+
2. Modify `.env` to suit your environment. Point to the host to your Coursemology instance, and
|
23
|
+
specify the API email and API key.
|
24
|
+
|
25
|
+
1. You might need to configure a new user on your Coursemology instance, enable token
|
26
|
+
authentication, and grant the `auto_grader` system/instance permission.
|
27
|
+
|
28
|
+
3. Start the evaluator using the Procfile. You can use [foreman](https://github.com/ddollar/foreman)
|
29
|
+
or any similar tool to generate system scripts for boot.
|
30
|
+
|
31
|
+
### Command Line Options
|
32
|
+
|
33
|
+
#### Compulsory Options
|
34
|
+
|
35
|
+
1. `--host`: Coursemology host to connect to
|
36
|
+
2. `--api-user-email`: User with autograder flag set
|
37
|
+
3. `--api-token`: Authentication token of the user
|
38
|
+
|
39
|
+
#### Optional Options
|
40
|
+
|
41
|
+
Time options are expected to be strings in [ISO8601 format](https://en.wikipedia.org/wiki/ISO_8601#Durations).
|
42
|
+
|
43
|
+
1. `--interval`: Time interval between checks for programming allocations. As this time is
|
44
|
+
expected to be short, specify it with the time components of ISO8601 only. (Hours, minutes, seconds)
|
45
|
+
The time designator `T` must be left out.
|
46
|
+
|
47
|
+
2. `--lifetime`: Length of time to cache Docker images. This is expected to be in the order of days.
|
48
|
+
If more granularity is needed, the time designator is required.
|
49
|
+
|
50
|
+
E.g. `1DT2H5M10S`
|
51
|
+
|
52
|
+
3. `--one-shot`: Runs once and terminates. Primarily used for testing.
|
data/Rakefile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require 'bundler/gem_tasks'
|
2
|
-
require 'rspec/core/rake_task'
|
3
|
-
|
4
|
-
RSpec::Core::RakeTask.new(:spec)
|
5
|
-
|
6
|
-
task default: :spec
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
|
6
|
+
task default: :spec
|
data/bin/evaluator
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'coursemology/evaluator'
|
3
|
-
|
4
|
-
Coursemology::Evaluator.eager_load!
|
5
|
-
Coursemology::Evaluator::CLI.start(ARGV)
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'coursemology/evaluator'
|
3
|
+
|
4
|
+
Coursemology::Evaluator.eager_load!
|
5
|
+
Coursemology::Evaluator::CLI.start(ARGV)
|
@@ -1,38 +1,38 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'coursemology/evaluator/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = 'coursemology-evaluator'
|
8
|
-
spec.version = Coursemology::Evaluator::VERSION
|
9
|
-
spec.authors = ['Joel Low']
|
10
|
-
spec.email = ['joel@joelsplace.sg']
|
11
|
-
spec.license = 'MIT'
|
12
|
-
|
13
|
-
spec.summary = 'Coursemology programming package evaluator'
|
14
|
-
spec.description = 'Sets up a consistent environment for evaluating programming packages.'
|
15
|
-
spec.homepage = 'https://github.com/Coursemology/evaluator-slave'
|
16
|
-
spec.files = `git ls-files -z`.split("\x0").
|
17
|
-
reject { |f| f.match(/^(test|spec|features)\//) }
|
18
|
-
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
19
|
-
spec.require_paths = ['lib']
|
20
|
-
|
21
|
-
spec.add_development_dependency 'bundler'
|
22
|
-
spec.add_development_dependency 'rake'
|
23
|
-
spec.add_development_dependency 'rspec'
|
24
|
-
spec.add_development_dependency 'factory_girl'
|
25
|
-
spec.add_development_dependency 'simplecov'
|
26
|
-
spec.add_development_dependency 'coveralls'
|
27
|
-
spec.add_development_dependency 'codeclimate-test-reporter'
|
28
|
-
spec.add_development_dependency 'vcr'
|
29
|
-
|
30
|
-
spec.add_dependency 'activesupport', '~> 4.2.0', '>= 4.2.2'
|
31
|
-
spec.add_dependency 'iso8601', '~> 0.9.1'
|
32
|
-
spec.add_dependency 'flexirest', '~> 1.2', '>= 1.2.6'
|
33
|
-
spec.add_dependency 'faraday_middleware'
|
34
|
-
|
35
|
-
spec.add_dependency 'coursemology-polyglot', '>= 0.0.3'
|
36
|
-
spec.add_dependency 'docker-api', '>= 1.29.1'
|
37
|
-
spec.add_dependency 'rubyzip'
|
38
|
-
end
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'coursemology/evaluator/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'coursemology-evaluator'
|
8
|
+
spec.version = Coursemology::Evaluator::VERSION
|
9
|
+
spec.authors = ['Joel Low']
|
10
|
+
spec.email = ['joel@joelsplace.sg']
|
11
|
+
spec.license = 'MIT'
|
12
|
+
|
13
|
+
spec.summary = 'Coursemology programming package evaluator'
|
14
|
+
spec.description = 'Sets up a consistent environment for evaluating programming packages.'
|
15
|
+
spec.homepage = 'https://github.com/Coursemology/evaluator-slave'
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").
|
17
|
+
reject { |f| f.match(/^(test|spec|features)\//) }
|
18
|
+
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'rspec'
|
24
|
+
spec.add_development_dependency 'factory_girl'
|
25
|
+
spec.add_development_dependency 'simplecov'
|
26
|
+
spec.add_development_dependency 'coveralls'
|
27
|
+
spec.add_development_dependency 'codeclimate-test-reporter'
|
28
|
+
spec.add_development_dependency 'vcr'
|
29
|
+
|
30
|
+
spec.add_dependency 'activesupport', '~> 4.2.0', '>= 4.2.2'
|
31
|
+
spec.add_dependency 'iso8601', '~> 0.9.1'
|
32
|
+
spec.add_dependency 'flexirest', '~> 1.2', '>= 1.2.6'
|
33
|
+
spec.add_dependency 'faraday_middleware'
|
34
|
+
|
35
|
+
spec.add_dependency 'coursemology-polyglot', '>= 0.0.3'
|
36
|
+
spec.add_dependency 'docker-api', '>= 1.29.1'
|
37
|
+
spec.add_dependency 'rubyzip'
|
38
|
+
end
|
@@ -1,41 +1,41 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'active_support/all'
|
3
|
-
require 'flexirest'
|
4
|
-
require 'faraday_middleware'
|
5
|
-
require 'docker'
|
6
|
-
require 'zip'
|
7
|
-
Docker.validate_version!
|
8
|
-
|
9
|
-
require 'coursemology/polyglot'
|
10
|
-
require 'coursemology/polyglot/extensions'
|
11
|
-
require 'coursemology/evaluator/version'
|
12
|
-
require 'iso8601'
|
13
|
-
|
14
|
-
module Coursemology::Evaluator
|
15
|
-
extend ActiveSupport::Autoload
|
16
|
-
include ActiveSupport::Configurable
|
17
|
-
|
18
|
-
autoload :Client
|
19
|
-
autoload :DockerContainer
|
20
|
-
autoload :CLI
|
21
|
-
autoload :Models
|
22
|
-
autoload :Services
|
23
|
-
autoload :StringIO
|
24
|
-
autoload :Utils
|
25
|
-
|
26
|
-
eager_autoload do
|
27
|
-
autoload :Logging
|
28
|
-
end
|
29
|
-
|
30
|
-
# The logger to use for the client.
|
31
|
-
mattr_reader(:logger) { ActiveSupport::Logger.new(STDOUT) }
|
32
|
-
|
33
|
-
# The cache to use for the client.
|
34
|
-
mattr_reader(:cache) { ActiveSupport::Cache.lookup_store }
|
35
|
-
|
36
|
-
def self.eager_load!
|
37
|
-
super
|
38
|
-
Coursemology::Polyglot.eager_load!
|
39
|
-
Logging.eager_load!
|
40
|
-
end
|
41
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/all'
|
3
|
+
require 'flexirest'
|
4
|
+
require 'faraday_middleware'
|
5
|
+
require 'docker'
|
6
|
+
require 'zip'
|
7
|
+
Docker.validate_version!
|
8
|
+
|
9
|
+
require 'coursemology/polyglot'
|
10
|
+
require 'coursemology/polyglot/extensions'
|
11
|
+
require 'coursemology/evaluator/version'
|
12
|
+
require 'iso8601'
|
13
|
+
|
14
|
+
module Coursemology::Evaluator
|
15
|
+
extend ActiveSupport::Autoload
|
16
|
+
include ActiveSupport::Configurable
|
17
|
+
|
18
|
+
autoload :Client
|
19
|
+
autoload :DockerContainer
|
20
|
+
autoload :CLI
|
21
|
+
autoload :Models
|
22
|
+
autoload :Services
|
23
|
+
autoload :StringIO
|
24
|
+
autoload :Utils
|
25
|
+
|
26
|
+
eager_autoload do
|
27
|
+
autoload :Logging
|
28
|
+
end
|
29
|
+
|
30
|
+
# The logger to use for the client.
|
31
|
+
mattr_reader(:logger) { ActiveSupport::Logger.new(STDOUT) }
|
32
|
+
|
33
|
+
# The cache to use for the client.
|
34
|
+
mattr_reader(:cache) { ActiveSupport::Cache.lookup_store }
|
35
|
+
|
36
|
+
def self.eager_load!
|
37
|
+
super
|
38
|
+
Coursemology::Polyglot.eager_load!
|
39
|
+
Logging.eager_load!
|
40
|
+
end
|
41
|
+
end
|
@@ -1,74 +1,74 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'optparse'
|
3
|
-
|
4
|
-
class Coursemology::Evaluator::CLI
|
5
|
-
Options = Struct.new(:host, :api_token, :api_user_email,
|
6
|
-
:one_shot, :poll_interval, :image_lifetime)
|
7
|
-
|
8
|
-
def self.start(argv)
|
9
|
-
new.start(argv)
|
10
|
-
end
|
11
|
-
|
12
|
-
def start(argv)
|
13
|
-
run(argv)
|
14
|
-
end
|
15
|
-
|
16
|
-
def run(argv)
|
17
|
-
options = optparse!(argv)
|
18
|
-
Coursemology::Evaluator.config.poll_interval =
|
19
|
-
::ISO8601::Duration.new("PT#{options.poll_interval}".upcase).to_seconds
|
20
|
-
|
21
|
-
# Must include the time designator T if hours/minutes/seconds are required.
|
22
|
-
Coursemology::Evaluator.config.image_lifetime =
|
23
|
-
::ISO8601::Duration.new("P#{options.image_lifetime}".upcase).to_seconds
|
24
|
-
|
25
|
-
Coursemology::Evaluator::Client.initialize(options.host, options.api_user_email,
|
26
|
-
options.api_token)
|
27
|
-
Coursemology::Evaluator::Client.new(options.one_shot).run
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
# Parses the options specified on the command line.
|
33
|
-
#
|
34
|
-
# @param [Array<String>] argv The arguments specified on the command line.
|
35
|
-
# @return [Coursemology::Evaluator::CLI::Options]
|
36
|
-
def optparse!(argv) # rubocop:disable Metrics/MethodLength
|
37
|
-
options = Options.new
|
38
|
-
|
39
|
-
# default options for optional parameters
|
40
|
-
options.poll_interval = '10S'
|
41
|
-
options.image_lifetime = '1D'
|
42
|
-
options.one_shot = false
|
43
|
-
|
44
|
-
option_parser = OptionParser.new do |parser|
|
45
|
-
parser.banner = "Usage: #{parser.program_name} [options]"
|
46
|
-
parser.on('-hHOST', '--host=HOST', 'Coursemology host to connect to') do |host|
|
47
|
-
options.host = host
|
48
|
-
end
|
49
|
-
|
50
|
-
parser.on('-tTOKEN', '--api-token=TOKEN') do |token|
|
51
|
-
options.api_token = token
|
52
|
-
end
|
53
|
-
|
54
|
-
parser.on('-uUSER', '--api-user-email=USER') do |user|
|
55
|
-
options.api_user_email = user
|
56
|
-
end
|
57
|
-
|
58
|
-
parser.on('-iINTERVAL', '--interval=INTERVAL') do |interval|
|
59
|
-
options.poll_interval = interval
|
60
|
-
end
|
61
|
-
|
62
|
-
parser.on('-lLIFETIME', '--lifetime=LIFETIME') do |lifetime|
|
63
|
-
options.image_lifetime = lifetime
|
64
|
-
end
|
65
|
-
|
66
|
-
parser.on('-o', '--one-shot') do
|
67
|
-
options.one_shot = true
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
option_parser.parse!(argv)
|
72
|
-
options
|
73
|
-
end
|
74
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
class Coursemology::Evaluator::CLI
|
5
|
+
Options = Struct.new(:host, :api_token, :api_user_email,
|
6
|
+
:one_shot, :poll_interval, :image_lifetime)
|
7
|
+
|
8
|
+
def self.start(argv)
|
9
|
+
new.start(argv)
|
10
|
+
end
|
11
|
+
|
12
|
+
def start(argv)
|
13
|
+
run(argv)
|
14
|
+
end
|
15
|
+
|
16
|
+
def run(argv)
|
17
|
+
options = optparse!(argv)
|
18
|
+
Coursemology::Evaluator.config.poll_interval =
|
19
|
+
::ISO8601::Duration.new("PT#{options.poll_interval}".upcase).to_seconds
|
20
|
+
|
21
|
+
# Must include the time designator T if hours/minutes/seconds are required.
|
22
|
+
Coursemology::Evaluator.config.image_lifetime =
|
23
|
+
::ISO8601::Duration.new("P#{options.image_lifetime}".upcase).to_seconds
|
24
|
+
|
25
|
+
Coursemology::Evaluator::Client.initialize(options.host, options.api_user_email,
|
26
|
+
options.api_token)
|
27
|
+
Coursemology::Evaluator::Client.new(options.one_shot).run
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Parses the options specified on the command line.
|
33
|
+
#
|
34
|
+
# @param [Array<String>] argv The arguments specified on the command line.
|
35
|
+
# @return [Coursemology::Evaluator::CLI::Options]
|
36
|
+
def optparse!(argv) # rubocop:disable Metrics/MethodLength
|
37
|
+
options = Options.new
|
38
|
+
|
39
|
+
# default options for optional parameters
|
40
|
+
options.poll_interval = '10S'
|
41
|
+
options.image_lifetime = '1D'
|
42
|
+
options.one_shot = false
|
43
|
+
|
44
|
+
option_parser = OptionParser.new do |parser|
|
45
|
+
parser.banner = "Usage: #{parser.program_name} [options]"
|
46
|
+
parser.on('-hHOST', '--host=HOST', 'Coursemology host to connect to') do |host|
|
47
|
+
options.host = host
|
48
|
+
end
|
49
|
+
|
50
|
+
parser.on('-tTOKEN', '--api-token=TOKEN') do |token|
|
51
|
+
options.api_token = token
|
52
|
+
end
|
53
|
+
|
54
|
+
parser.on('-uUSER', '--api-user-email=USER') do |user|
|
55
|
+
options.api_user_email = user
|
56
|
+
end
|
57
|
+
|
58
|
+
parser.on('-iINTERVAL', '--interval=INTERVAL') do |interval|
|
59
|
+
options.poll_interval = interval
|
60
|
+
end
|
61
|
+
|
62
|
+
parser.on('-lLIFETIME', '--lifetime=LIFETIME') do |lifetime|
|
63
|
+
options.image_lifetime = lifetime
|
64
|
+
end
|
65
|
+
|
66
|
+
parser.on('-o', '--one-shot') do
|
67
|
+
options.one_shot = true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
option_parser.parse!(argv)
|
72
|
+
options
|
73
|
+
end
|
74
|
+
end
|