yacl 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.rdoc +5 -0
- data/LICENSE +16 -0
- data/Manifest.txt +48 -0
- data/README.rdoc +55 -0
- data/Rakefile +308 -0
- data/example/myapp-simple/bin/myapp +16 -0
- data/example/myapp-simple/config/database.yml +8 -0
- data/example/myapp-simple/config/host.yml +2 -0
- data/example/myapp-simple/config/pipeline.yml +1 -0
- data/example/myapp-simple/lib/myapp.rb +53 -0
- data/example/myapp/bin/myapp +17 -0
- data/example/myapp/bin/myapp-job +10 -0
- data/example/myapp/config/database.yml +8 -0
- data/example/myapp/config/httpserver.yml +3 -0
- data/example/myapp/config/pipeline.yml +1 -0
- data/example/myapp/lib/myapp.rb +6 -0
- data/example/myapp/lib/myapp/cli.rb +92 -0
- data/example/myapp/lib/myapp/defaults.rb +28 -0
- data/example/myapp/lib/myapp/job.rb +56 -0
- data/lib/yacl.rb +12 -0
- data/lib/yacl/define.rb +9 -0
- data/lib/yacl/define/cli.rb +7 -0
- data/lib/yacl/define/cli/options.rb +97 -0
- data/lib/yacl/define/cli/parser.rb +112 -0
- data/lib/yacl/define/cli/runner.rb +82 -0
- data/lib/yacl/define/defaults.rb +58 -0
- data/lib/yacl/define/plan.rb +197 -0
- data/lib/yacl/loader.rb +80 -0
- data/lib/yacl/loader/env.rb +103 -0
- data/lib/yacl/loader/yaml_dir.rb +137 -0
- data/lib/yacl/loader/yaml_file.rb +102 -0
- data/lib/yacl/properties.rb +144 -0
- data/lib/yacl/simple.rb +52 -0
- data/spec/data/yaml_dir/database.yml +8 -0
- data/spec/data/yaml_dir/httpserver.yml +3 -0
- data/spec/define/cli/options_spec.rb +47 -0
- data/spec/define/cli/parser_spec.rb +64 -0
- data/spec/define/cli/runner_spec.rb +57 -0
- data/spec/define/defaults_spec.rb +24 -0
- data/spec/define/plan_spec.rb +77 -0
- data/spec/loader/env_spec.rb +32 -0
- data/spec/loader/yaml_dir_spec.rb +43 -0
- data/spec/loader/yaml_file_spec.rb +80 -0
- data/spec/loader_spec.rb +16 -0
- data/spec/properties_spec.rb +60 -0
- data/spec/simple_spec.rb +85 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/version_spec.rb +8 -0
- metadata +207 -0
@@ -0,0 +1 @@
|
|
1
|
+
dir: /tmp/foo/bar
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'yacl'
|
2
|
+
module MyApp
|
3
|
+
# This is a simplier version of 'myapp' example where we use a DSL instead of
|
4
|
+
# explicit classes. Under hte covers, this creats classes that do the same as
|
5
|
+
# the explicit version.
|
6
|
+
#
|
7
|
+
# For simpler cases where you want to put all of this together this may make
|
8
|
+
# more sense.
|
9
|
+
class Application < ::Yacl::Simple
|
10
|
+
|
11
|
+
# This defines a MyApp::Application::Defaults class. This class is also
|
12
|
+
# available via MyApp::Application.defaults
|
13
|
+
defaults do
|
14
|
+
default 'archive.uri' , 'http://archive.example.com'
|
15
|
+
default 'messaging.uri' , 'kestrel://messaging1.example.com:2229/'
|
16
|
+
default 'messaging.queue', 'pending'
|
17
|
+
default 'system' , 'main'
|
18
|
+
default 'timelimit' , '10'
|
19
|
+
end
|
20
|
+
|
21
|
+
# This defines a MyApp::Application::Parser class. This class is also
|
22
|
+
# available via MyApp::Application.parser
|
23
|
+
parser do
|
24
|
+
banner "myapp [options]+"
|
25
|
+
opt 'pipeline.dir', :long => 'pipeline-dir', :short => 'd', :description => "The pipeline directory we are using", :cast => :string
|
26
|
+
opt 'config.dir' , :long => 'config-dir', :short => 'c', :description => "The directory to load configuration from", :cast => :string
|
27
|
+
opt 'timelimit' , :long => 'time-limit', :short => 't', :description => "The amount of time to run for", :cast => :integer
|
28
|
+
opt 'system' , :long => 'system', :short => 's', :description => "The system setting", :cast => :string
|
29
|
+
opt 'debug' , :long => 'debug', :sortt => 'D', :description => "Turn on debugging", :cast => :boolean
|
30
|
+
end
|
31
|
+
|
32
|
+
# This defines a MyApp::Application::Plan class. This class is also
|
33
|
+
# available via MyApp::Application.plan
|
34
|
+
plan do
|
35
|
+
try MyApp::Application.parser
|
36
|
+
try Yacl::Loader::Env, :prefix => 'MY_APP'
|
37
|
+
try Yacl::Loader::YamlDir, :parameter => 'config.dir'
|
38
|
+
try MyApp::Application.defaults
|
39
|
+
|
40
|
+
on_error do |exception|
|
41
|
+
$stderr.puts "ERROR: #{exception}"
|
42
|
+
$stderr.puts "Try --help for help"
|
43
|
+
exit 1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# This is the method that will be run when it is executed on the
|
48
|
+
# commandline.
|
49
|
+
def run
|
50
|
+
puts properties.map.inspect
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# load path munging so the example works from a git checkout, do not do this
|
4
|
+
# in your program
|
5
|
+
$: << File.expand_path( "../../../../lib", __FILE__ ) # yacl library
|
6
|
+
$: << File.expand_path( "../../lib", __FILE__ ) # lib dir of this sample app
|
7
|
+
require 'rubygems'
|
8
|
+
|
9
|
+
#------------------------------------------------------------------------------
|
10
|
+
# This would be the top level commandline entry point for your program. Feel
|
11
|
+
# free to have multiple of them if that is what your situation requires.
|
12
|
+
#------------------------------------------------------------------------------
|
13
|
+
|
14
|
+
require 'myapp'
|
15
|
+
require 'myapp/cli'
|
16
|
+
|
17
|
+
MyApp::Cli::Runner.go( ARGV, ENV )
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#------------------------------------------------------------------------------
|
4
|
+
# This would be a top-level entrypoint into your system that was not commandline
|
5
|
+
# based. Think loaded by some other framework. Maybe a Torquebox Job or a
|
6
|
+
# Resqueue Job or something that was more static.
|
7
|
+
#------------------------------------------------------------------------------
|
8
|
+
|
9
|
+
require 'myapp'
|
10
|
+
MyApp::Job::ForSomething.new( "pipeline.dir" => "/over/there" )
|
@@ -0,0 +1 @@
|
|
1
|
+
dir: /tmp/foo/bar
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'myapp/defaults'
|
2
|
+
module MyApp
|
3
|
+
# In this example I am encapsulating everything that has to do with a
|
4
|
+
# commandline program within the Cli module. For this example, there is one
|
5
|
+
# and only one commandline program.
|
6
|
+
module Cli
|
7
|
+
|
8
|
+
# The Commandline options for our program. This maps the commandline
|
9
|
+
# options, given in the :long and :short style for consistency in
|
10
|
+
# commandline functionalyt to their property names which have a dotten
|
11
|
+
# notation and make property access consistent throughout the program.
|
12
|
+
#
|
13
|
+
# These Options are to be used by the Parser class.
|
14
|
+
class Options < Yacl::Define::Cli::Options
|
15
|
+
opt 'pipeline.dir', :long => 'pipeline-dir', :short => 'd', :description => "The pipeline directory we are using", :cast => :string
|
16
|
+
opt 'config.dir' , :long => 'config-dir', :short => 'c', :description => "The directory to load configuration from", :cast => :string
|
17
|
+
opt 'timelimit' , :long => 'time-limit', :short => 't', :description => "The amount of time to run for", :cast => :integer
|
18
|
+
opt 'system' , :long => 'system', :short => 's', :description => "The system setting", :cast => :string
|
19
|
+
opt 'debug' , :long => 'debug', :sortt => 'D', :description => "Turn on debugging", :cast => :boolean
|
20
|
+
end
|
21
|
+
|
22
|
+
# The Parser class. This is kept explicitly separate from the Options class
|
23
|
+
# so that, you may, if you like use whatever commadnline parser
|
24
|
+
# library/program you whish. By default this library will automatically use
|
25
|
+
# trollop and generate a commandline for you from it. If you whish to use
|
26
|
+
# another commandline library, you may define your own Parser class.
|
27
|
+
#
|
28
|
+
# Use Yacl::Define::Cli::Parser as a template for how you would like to do
|
29
|
+
# your work. YOu can probably get by with inheriting from
|
30
|
+
# Yacl::Define::Cli::Parser and overwriting the #delegate_parser and #parse
|
31
|
+
# methods.
|
32
|
+
class Parser < Yacl::Define::Cli::Parser
|
33
|
+
banner "myapp [options]+"
|
34
|
+
options MyApp::Cli::Options
|
35
|
+
end
|
36
|
+
|
37
|
+
# The Plan class, this defines the order of loading of your properties and the
|
38
|
+
# order of resolution of when looking up a property. The property Loaders
|
39
|
+
# are loaded in the defined order below, and that is their priority. For
|
40
|
+
# example the 'config.dir' property may be defiend in the Parser and the
|
41
|
+
# Environment, and in this case if it has a value in the Env but not the
|
42
|
+
# Parser the Env value will take precidence. If there is a value in the
|
43
|
+
# Parser though, that will be the value used.
|
44
|
+
#
|
45
|
+
# In this case, since we know that this plan has a commandline, we're
|
46
|
+
# catching any load errors and printing out to stderr on a failure. If this
|
47
|
+
# perhaps was used in a non-commandline situation the on_error block could
|
48
|
+
# do something completely different.
|
49
|
+
class Plan < Yacl::Define::Plan
|
50
|
+
|
51
|
+
# 1) parse the commandline and load properties from the mapping of the
|
52
|
+
# commandline to the property names.
|
53
|
+
try MyApp::Cli::Parser
|
54
|
+
|
55
|
+
# 2) using the environment and only those environment variables that
|
56
|
+
# start with MY_APP load additional properties.
|
57
|
+
try Yacl::Loader::Env, :prefix => 'MY_APP'
|
58
|
+
|
59
|
+
# 3) using the config.dir value, which is probably set via the
|
60
|
+
# --config-dir parser option, or via the MY_APP_CONFIG_DIR environment
|
61
|
+
# variable laod up some more properties.
|
62
|
+
try Yacl::Loader::YamlDir, :parameter => 'config.dir'
|
63
|
+
|
64
|
+
# 4) if a property is not found in any of the previous locations, then use
|
65
|
+
# the defaults. And if it is not in the defaults, then we will return nil
|
66
|
+
try MyApp::Defaults
|
67
|
+
|
68
|
+
# If an error happens while attempting to load the properties the print a
|
69
|
+
# message on stderr and exit the program.
|
70
|
+
on_error do |exception|
|
71
|
+
$stderr.puts "ERROR: #{exception}"
|
72
|
+
$stderr.puts "Try --help for help"
|
73
|
+
exit 1
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# The Runner class, this is what is instantiated in the bin script and
|
78
|
+
# invoked from the commandline. It uses the Plan and a #run method you
|
79
|
+
# define to take actione.
|
80
|
+
#
|
81
|
+
# In this particular case, it just prints out the properties.
|
82
|
+
class Runner < ::Yacl::Define::Cli::Runner
|
83
|
+
plan MyApp::Cli::Plan
|
84
|
+
|
85
|
+
def run
|
86
|
+
p = properties
|
87
|
+
puts p.map.inspect
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'yacl'
|
2
|
+
module MyApp
|
3
|
+
# The core defaults of your system. Not all of your default properties need to
|
4
|
+
# be defined. It is your choice what is defined and what isn't. Think of these
|
5
|
+
# as the hardcoded defaults that if the property is not overwritte by
|
6
|
+
# something else in the system, then it will fall back to this.
|
7
|
+
#
|
8
|
+
# Sensible Defaults in other words.
|
9
|
+
#
|
10
|
+
# Possible ways of using these:
|
11
|
+
#
|
12
|
+
# - Have different Defaults for development/test/production
|
13
|
+
# - Use this for things that are hardly ever overwritten
|
14
|
+
# - global defaults that are common across many sub-components.
|
15
|
+
#
|
16
|
+
# It would be perfectly reasonable to have different classes defined for
|
17
|
+
# different things. Different commandline applications, or entrypoints into
|
18
|
+
# the library etc.
|
19
|
+
class Defaults < Yacl::Define::Defaults
|
20
|
+
default 'archive.uri' , 'http://archive.example.com'
|
21
|
+
default 'messaging.uri' , 'kestrel://messaging1.example.com:2229/'
|
22
|
+
default 'messaging.queue', 'pending'
|
23
|
+
default 'system' , 'main'
|
24
|
+
default 'timelimit' , '10'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'myapp/defaults'
|
2
|
+
module MyApp
|
3
|
+
# In this case we are assuming that the application is not part of a
|
4
|
+
# commandline program and it may be used from some other library and it still
|
5
|
+
# needs to load its config from some location.
|
6
|
+
#
|
7
|
+
# This could be the case of :
|
8
|
+
# - Resque or some other background job system
|
9
|
+
# - Part of a torquebox configuration
|
10
|
+
# - embedded in some other library
|
11
|
+
module Job
|
12
|
+
|
13
|
+
# We have a plan just as we did with the commandline one, but without the
|
14
|
+
# commandline parser.
|
15
|
+
class Plan < Yacl::Define::Plan
|
16
|
+
# First try to load properties from the environment variables that start
|
17
|
+
# with MY_PREFIX
|
18
|
+
try Yacl::Loader::Env, :prefix => 'MY_APP'
|
19
|
+
|
20
|
+
# Next we will load from an explicit directory.
|
21
|
+
try Yacl::Loader::YamlDir, :path => File.expand_path( "../../../config", __FILE__ )
|
22
|
+
|
23
|
+
# And finally we will use the built in defaults
|
24
|
+
try MyApp::Defaults
|
25
|
+
|
26
|
+
# On an error we just print to stderr saying that we do not know what is
|
27
|
+
# going on. We could re-reise the exception, or just let it naturally
|
28
|
+
# percolate up if we wanted something else to handle it.
|
29
|
+
on_error do |exception|
|
30
|
+
$stderr.puts exception
|
31
|
+
$stderr.puts exception.backtrace.join("\n")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# In this situation we have a class that needs to use the plan and do
|
36
|
+
# something with it. Instead of having a commandline program, this is the
|
37
|
+
# clasee that serves as the interface between our code and someone elses
|
38
|
+
# code.
|
39
|
+
class ForSomething
|
40
|
+
|
41
|
+
# We will take a hash here so that the external program can explicitly
|
42
|
+
# pass in as set of initial properties and have them bee the most highly
|
43
|
+
# prioritiezed values in the plan stack.
|
44
|
+
#
|
45
|
+
# We also explictly use the Plan here, and do not assume that there is a
|
46
|
+
# runner.
|
47
|
+
def initialize( params )
|
48
|
+
p = Yacl::Properties.new( params )
|
49
|
+
plan = Job::Plan.new( :initial_properties => p )
|
50
|
+
puts plan.properties.map.inspect
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
data/lib/yacl.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# Yacl is Your Application Configuration Library.
|
2
|
+
#
|
3
|
+
# See the README
|
4
|
+
module Yacl
|
5
|
+
# The Current Version of the library
|
6
|
+
VERSION = "1.0.0"
|
7
|
+
class Error < ::StandardError; end
|
8
|
+
end
|
9
|
+
require 'yacl/properties'
|
10
|
+
require 'yacl/loader'
|
11
|
+
require 'yacl/define'
|
12
|
+
require 'yacl/simple'
|
data/lib/yacl/define.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
module Yacl::Define::Cli
|
2
|
+
|
3
|
+
# Internal: Encapsulation of all the elements pertaining to a single
|
4
|
+
# commandline option.
|
5
|
+
Option = Struct.new( :property_name, :long, :short, :description, :cast)
|
6
|
+
|
7
|
+
# Public: Inherit from Cli::Options to define your the mapping between your
|
8
|
+
# application properties and commandline switches.
|
9
|
+
#
|
10
|
+
# The class you create from here is to be used in conjuction with a class you
|
11
|
+
# create that is a child class of Cli::Parser.
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
#
|
15
|
+
# class MyOptions < ::Yacl::Define::Cli::Options
|
16
|
+
# opt 'log.level', :long => 'log-level', :short => 'l', :description => "Logging Level", :cast => :string
|
17
|
+
# opt 'config.dir',:long => 'config-dir', :short => 'c', :description => "Configuration directory", :cast => :string
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# o = MyOptions.new( 'log-level' => 'debug', 'config-dir' => '/tmp/foo' )
|
21
|
+
# o.properties # => Properties instance with 'log.level' => debug and 'config.dir' => '/tmp/foo'
|
22
|
+
#
|
23
|
+
class Options < ::Yacl::Loader
|
24
|
+
|
25
|
+
# Internal: access to the defined list of options
|
26
|
+
#
|
27
|
+
# Returns the Array of options
|
28
|
+
def self.opt_list
|
29
|
+
@opt_list ||= []
|
30
|
+
end
|
31
|
+
|
32
|
+
# Public: Declare a property and its corresponding commandline options.
|
33
|
+
#
|
34
|
+
# name - The property name as a String
|
35
|
+
# params - The Hash options to accompany the property name (default: {})
|
36
|
+
# :long - The long commandline option. Without leading dashes
|
37
|
+
# :short - The short commandline option. Without leading dashes
|
38
|
+
# :description - The text description of this commandline option
|
39
|
+
# :cast - What to cast the value of the commandline option
|
40
|
+
# to. This can be one of: :integer, :float, :string,
|
41
|
+
# :boolean
|
42
|
+
#
|
43
|
+
# Examples:
|
44
|
+
#
|
45
|
+
# opt 'app.thing.one', :long => 'thing-one', :short => 't', :description => "Thing One", :cast => :string
|
46
|
+
#
|
47
|
+
# Returns nothing.
|
48
|
+
def self.opt(name, params = {} )
|
49
|
+
opt_list << Option.new( name, params[:long], params[:short], params[:description ], params[:cast] )
|
50
|
+
end
|
51
|
+
|
52
|
+
# Public: Load the Properties from the options that were passed to the
|
53
|
+
# initializer.
|
54
|
+
#
|
55
|
+
# Returns a Properties instance.
|
56
|
+
def properties
|
57
|
+
load_properties( @options )
|
58
|
+
end
|
59
|
+
|
60
|
+
# Public: yield each defined Option in this class to the caller
|
61
|
+
#
|
62
|
+
# Yields the Option instance of the iteration.
|
63
|
+
#
|
64
|
+
# Returns nothing.
|
65
|
+
def each
|
66
|
+
opt_list.each do |o|
|
67
|
+
yield o
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Internal: Return the list of defined options for this Class.
|
72
|
+
#
|
73
|
+
# Returns an Array of Option instances
|
74
|
+
def opt_list
|
75
|
+
self.class.opt_list
|
76
|
+
end
|
77
|
+
|
78
|
+
# Internal: convert the given hash of long options into a Properties
|
79
|
+
# instance using the defined options.
|
80
|
+
#
|
81
|
+
# It is assumed that the commandline has already been parsed and that the
|
82
|
+
# hash passed in is the long options that were parsed out of the
|
83
|
+
# commandline.
|
84
|
+
#
|
85
|
+
# hash - a Hash of long options and their values.
|
86
|
+
#
|
87
|
+
# Returns a Properties instance
|
88
|
+
def load_properties( hash )
|
89
|
+
prop_hash = {}
|
90
|
+
opt_list.each do |o|
|
91
|
+
next unless hash.has_key?( o.long )
|
92
|
+
prop_hash[o.property_name] = hash[o.long]
|
93
|
+
end
|
94
|
+
return Yacl::Properties.new( prop_hash )
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'trollop'
|
2
|
+
module Yacl::Define::Cli
|
3
|
+
# Public: Parser is a Loader that uses a Cli::Options class and the Trollop
|
4
|
+
# parser to convert commandline options into a Properties instance. It is to
|
5
|
+
# be inherited from so you can have your own parser per commandline program in
|
6
|
+
# your application suite.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
#
|
10
|
+
# class MyOptions < ::Yacl::Define::Cli::Options
|
11
|
+
# opt 'log.level', :long => 'log-level', :short => 'l', :description => "Logging Level", :cast => :string
|
12
|
+
# opt 'config.dir',:long => 'config-dir', :short => 'c', :description => "Configuration directory", :cast => :string
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# class MyParser < ::Yacl::Define::Cli::Parser
|
16
|
+
# banner "Usage: myapp [options]+"
|
17
|
+
# options MyOptions
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# p = MyParser.new( :argv => ARGV )
|
21
|
+
# p.properties #=> a Properties instance
|
22
|
+
#
|
23
|
+
class Parser < ::Yacl::Loader
|
24
|
+
|
25
|
+
# Public: Define the options Class that is be used by this Parser, or return
|
26
|
+
# the existin Class if it is already defined.
|
27
|
+
#
|
28
|
+
# klass - A Class that is a child class of Cli::Options.
|
29
|
+
#
|
30
|
+
# Returns the current options Class.
|
31
|
+
def self.options( *args )
|
32
|
+
@options_klass ||= args.first unless args.empty?
|
33
|
+
return @options_klass
|
34
|
+
end
|
35
|
+
|
36
|
+
# Public: Set or retrieve the banner text.
|
37
|
+
#
|
38
|
+
# text - A String to be displayed as part of the help text.
|
39
|
+
#
|
40
|
+
# Returns the value set, or the default value if one is not set.
|
41
|
+
def self.banner( *args )
|
42
|
+
@banner = args.first unless args.empty?
|
43
|
+
@banner ||= "Usage : #{File.basename($0)} [options]+\nOptions:"
|
44
|
+
end
|
45
|
+
|
46
|
+
# Public: Define a commandline option for this Parser.
|
47
|
+
# Using 'opt' over options will dynamically create a child class of Options
|
48
|
+
# for use by this class
|
49
|
+
def self.opt( *args )
|
50
|
+
options( Class.new( Yacl::Define::Cli::Options ) )
|
51
|
+
options.opt( *args )
|
52
|
+
end
|
53
|
+
|
54
|
+
# Create a new Parser instance
|
55
|
+
#
|
56
|
+
# opts - The hash of options for this Loader
|
57
|
+
# :argv - The commandline options passed to the Parser.
|
58
|
+
# other options as per the Loader class.
|
59
|
+
#
|
60
|
+
def initialize( opts = {} )
|
61
|
+
super
|
62
|
+
@argv = opts[:argv] || []
|
63
|
+
end
|
64
|
+
|
65
|
+
# Public: Retrive the class level banner text.
|
66
|
+
#
|
67
|
+
# Returns the String banner text
|
68
|
+
def banner
|
69
|
+
self.class.banner
|
70
|
+
end
|
71
|
+
|
72
|
+
# Public: Return the Properties instance that is created by parsing the
|
73
|
+
# commandline options.
|
74
|
+
#
|
75
|
+
# Nil values from possible defaults from the commandline parser are
|
76
|
+
# filtered out before being merged onto the options.
|
77
|
+
#
|
78
|
+
# Returns a Properties instance.
|
79
|
+
def properties
|
80
|
+
h = {}
|
81
|
+
parse( @argv ).each do |k,v|
|
82
|
+
h[k] = v unless v.nil?
|
83
|
+
end
|
84
|
+
o = options_klass.new( h )
|
85
|
+
o.properties
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# Internal: Return the class level value stored in Parser#options
|
91
|
+
#
|
92
|
+
# Returns a Class
|
93
|
+
def options_klass
|
94
|
+
self.class.options
|
95
|
+
end
|
96
|
+
|
97
|
+
def delegate_parser
|
98
|
+
Trollop::Parser.new( options_klass.new, self.banner ) do |trollop_options, banner_text|
|
99
|
+
text banner_text
|
100
|
+
trollop_options.each do |x|
|
101
|
+
opt x.long, x.description, :type => x.cast
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def parse( argv )
|
107
|
+
Trollop::with_standard_exception_handling( delegate_parser ) do
|
108
|
+
delegate_parser.parse( argv )
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|