app-ctx 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README +109 -0
  2. data/lib/app-ctx.rb +228 -0
  3. data/lib/app-ctx/dlog.rb +164 -0
  4. data/test/t_app-ctx.rb +199 -0
  5. metadata +49 -0
data/README ADDED
@@ -0,0 +1,109 @@
1
+
2
+ Application Context
3
+
4
+ Every application needs configuration and app-ctx provides a concise way of
5
+ doing it.
6
+
7
+ For all applications (you are not a mouseclicker, are u?), once in a while
8
+ you need to supply some configuration values to overrule the built-in
9
+ defaults. The app-ctx gem does unify and organize built-in constants,
10
+ config files and commandline option with a clearly defined priority, from
11
+ low to high:
12
+
13
+ - procedural: App::Config#set_default_values
14
+ - default values YAML file from next to the $0 script
15
+ - user supplied configuration file, eg.: --config=/tmp/foo.yml
16
+ - command line options and flags: --foo --bar=foo
17
+
18
+ But for your application it is of no interesst from where the values are
19
+ coming: command line option: "--port=1234", a user configuration file or
20
+ from the applications built-in default values. Therefor +app-ctx+ combines
21
+ value settings from various sources into a single configuration hash.
22
+
23
+ basically you have two ways to use it:
24
+
25
+ require 'app-ctx' # of course,and than...
26
+
27
+ 1. closures (see examples/run_with_block.rb)
28
+
29
+ App::ctx.run do |context| ... end
30
+
31
+ or 2. with a mainclass(see examples/run_with_class.rb)
32
+
33
+ App::ctx.run YourClassHere
34
+
35
+ The context object provides:
36
+
37
+ values: the combined key and value settings
38
+ argv: remaining argument(not the options) of the command line
39
+ defaults_path: full path to the defaults file
40
+
41
+ for the second case(with a mainclass) an application instance of this class
42
+ is created. The first argument is than taken as method name and executed,
43
+ again with a context oject provided:
44
+
45
+ prompt: ruby example/run_with_class show
46
+
47
+ will result in the :show method beeing called:
48
+
49
+ context = Config.new...
50
+ ...
51
+ app = Simple.new...
52
+ app.show(context)
53
+
54
+
55
+ Conversions
56
+
57
+ Commandline options are strings only, but sometimes you need strongly typed
58
+ primitive values. +app-ctx+ does automatically convert integer and float
59
+ values, see "examples/conversions.rb" for:
60
+
61
+ prompt: ./examples/conversions.rb
62
+ {:i=>23, :f=>3.14}
63
+ typeof 'i': Fixnum
64
+ typeof 'f': Float
65
+ prompt: ./examples/conversions.rb -i=17 -f=2.12
66
+ {:i=>17, :f=>2.12}
67
+ typeof 'i': Fixnum
68
+ typeof 'f': Float
69
+ prompt: ./examples/conversions.rb -i=i -f=f
70
+ {:i=>"i", :f=>"f"}
71
+ typeof 'i': String
72
+ typeof 'f': String
73
+
74
+
75
+ Flags/Boolean values
76
+
77
+ Flags(options without values) are converted to boolean values, see
78
+ examples/boolean.rb:
79
+
80
+ dluesebrink dl-mbook ruby/app-ctx: r examples/boolean.rb
81
+ {:bool=>false}
82
+ typeof 'bool': FalseClass
83
+ dluesebrink dl-mbook ruby/app-ctx: r examples/boolean.rb --bool
84
+ {:bool=>true}
85
+ typeof 'bool': TrueClass
86
+
87
+
88
+ Ruby Conversions
89
+
90
+ When Fixnum, Float and boolean conversion are not enough, as a last resort,
91
+ you can use ruby code directly for evaluation of option values. Replacing
92
+ '=' with ':' results in assigning the ruby evaluation value to the key, see
93
+ examples/ruby_conv.rb:
94
+
95
+ prompt: examples/ruby_conv.rb
96
+ {:r=>1..10, :a=>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}
97
+ typeof 'r': Range
98
+ typeof 'a': Array
99
+ prompt: ./examples/ruby_conv.rb -r:2..3 -a:'(-1..1).to_a'
100
+ {:r=>2..3, :a=>[-1, 0, 1]}
101
+ typeof 'r': Range
102
+ typeof 'a': Array
103
+ prompt: ./examples/ruby_conv.rb -r:2..3 -a:\(-1..1\).to_a
104
+ {:r=>2..3, :a=>[-1, 0, 1]}
105
+ typeof 'r': Range
106
+ typeof 'a': Array
107
+
108
+
109
+ # vim: set tw=80 syntax=txt nosmartindent:
@@ -0,0 +1,228 @@
1
+
2
+ require 'yaml'
3
+ require 'rdoc/usage'
4
+
5
+ require 'app-ctx/dlog'
6
+
7
+ module App
8
+
9
+ # the priority of configuation settings is:
10
+ # 1. command line options
11
+ # 2. configuration from custom file, eg.: --config=/tmp/foo.yml
12
+ # 3. built-in default values from yaml file next to $0 script
13
+ class Config
14
+
15
+ include DL::LoggerMixin
16
+
17
+ attr_reader :values, :argv, :defaults_path
18
+
19
+ # params are :argv and :defaults_path which are defaulting to ARGV and
20
+ # the applications defaults which are loaded from a yaml file next to
21
+ # the '$0' application script.
22
+ def initialize params = {}
23
+ params = {
24
+ :argv => ARGV,
25
+ :defaults_path => App.config_path($0)
26
+ }.update(params)
27
+
28
+ @argv = params[:argv]
29
+ @defaults_path = params[:defaults_path]
30
+
31
+ load_config_file(@defaults_path)
32
+ @values, @argv = parse_command_line @argv
33
+ end
34
+
35
+ # programatic way to define the default values other then from defaults
36
+ # file.
37
+ def set_default_values defaults
38
+ @values = defaults.merge(@values)
39
+ end
40
+
41
+
42
+ def to_s
43
+ <<-EOT
44
+ args : #{argv.inspect}
45
+ values : #{values.inspect}
46
+ defaults : '#{defaults_path}'
47
+ user config : '#{values[:config]}'
48
+ EOT
49
+ end
50
+
51
+ # overwrite current configuration with values from file
52
+ #
53
+ def load_config_file cpath
54
+ @values ||= {}
55
+ if File.exists? cpath = File.expand_path(cpath)
56
+ begin
57
+ @values.update YAML.load_file(cpath)
58
+ info "loaded(#{cpath})"
59
+ debug "config values: #{@values.inspect}"
60
+ rescue => e
61
+ warn "failed to load: #{cpath}", e
62
+ end
63
+ else
64
+ debug "no such config file: #{cpath}"
65
+ end
66
+ end
67
+
68
+ # methods below are related to option parsing and are used only at
69
+ # object creastions time from the c'tor
70
+ private
71
+
72
+ # overide default configuration with command line arguments.
73
+ # --flag becomes [ :flag => true]
74
+ # --option=value becomes [ :option => "value"]
75
+ # --int=1 becomes [ :int => 1]
76
+ # --float=2.3 becomes [ :float => 2.3]
77
+ # --txt="foo bar" becomes [ :txt => "foo bar"]
78
+ #
79
+ # --list:(1..10) becomes [ :list => (1..10) ]
80
+ def parse_command_line argv
81
+ c = {}
82
+ argv = argv.clone.delete_if do |a|
83
+ #if m = /^--(\w+)(=(.+))?$/.match(a)
84
+ if m = /^(-(\w)|--(\w\w+))(=(.+))?$/.match(a)
85
+ debug "#{m.to_a.inspect}" if m
86
+ val = parse_arg m[5]
87
+ key = m[2] || m[3]
88
+ c[key.to_sym] = val
89
+
90
+ # eval as ruby snippet
91
+ elsif m = /^(-(\w)|--(\w\w+)):(.+)$/.match(a)
92
+ debug "#{m.to_a.inspect}" if m
93
+ val = eval m[4]
94
+ key = m[2] || m[3]
95
+ c[key.to_sym] = val
96
+ end
97
+ end
98
+ debug "command line options: #{c.inspect}"
99
+
100
+ # overload "--config=..." file before command line options
101
+ if cpath = c[:config]
102
+ if file_config = load_config_file(cpath)
103
+ c = file_config.update(c)
104
+ else
105
+ warn "configuration file not found: '#{cpath}'"
106
+ end
107
+ end
108
+
109
+ #[@values.dup.update(c), av]
110
+ @values.update(c)
111
+ [@values, argv]
112
+ end
113
+
114
+ def parse_arg val
115
+ return true unless val # options are booleans
116
+ Integer(val) rescue Float(val) rescue parse_string(val)
117
+ end
118
+
119
+ def parse_string s
120
+ if s.match %r{^['"].*['"]$}
121
+ s[1..-2]
122
+ else
123
+ s
124
+ end
125
+ end
126
+ end
127
+
128
+ class Container
129
+
130
+ Messages = {
131
+ :no_entrypoint => <<-'EOM'
132
+
133
+ ::app-ctx::
134
+
135
+ -> sorry, your main class (#{clazz}) seems not to have a default
136
+ -> 'application_main' entrypoint and no method argument was given, so i don't
137
+ -> know what to do.
138
+
139
+ thank you, good bye and have a nice day
140
+
141
+ EOM
142
+ }
143
+
144
+ def inform message_id, binding
145
+ m = Messages[message_id]
146
+ puts eval("\"#{m}\"", binding)
147
+ end
148
+
149
+ def initialize context
150
+ @context = context
151
+ end
152
+
153
+ def execute clazz = nil
154
+
155
+ if block_given?
156
+ warn "attached block takes precedence over class!" if clazz
157
+ return yield(@context)
158
+ end
159
+
160
+ # create applicaton instance with or without context c'tor (this is
161
+ # IoC: Constructor Dependency Injection)
162
+ app = clazz.new(@context) rescue clazz.new
163
+
164
+ setter_injection app, @context
165
+
166
+ begin
167
+ # first try the default entry point
168
+ app.application_main @context
169
+
170
+ rescue NoMethodError => e
171
+ if app.respond_to? :application_main
172
+ DL.logger.error "failed invokation", e
173
+ else
174
+ if 0 == @context.argv.length
175
+ inform :no_entrypoint, binding()
176
+ RDoc::usage
177
+ return
178
+ else
179
+ # one or more args => first arg is method with rest
180
+ # as params
181
+ begin
182
+ op = @context.argv.shift
183
+ app.send(op, @context)
184
+ rescue => e
185
+ DL.logger.error "oops: #{e}", e
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ app # the created application instance
192
+ end
193
+
194
+ # IoC setter dependency injection:
195
+ # try all context keys as setter class
196
+ def setter_injection obj, context
197
+ # try setters for keys from context(this is IoC: Setter dependency
198
+ # injection)
199
+ context.values.each do |key, value|
200
+ #p "#{key} #{value}"
201
+ begin
202
+ obj.send("#{key}=", value)
203
+ rescue NoMethodError
204
+ #ntdh
205
+ end
206
+ end
207
+ end
208
+ private :setter_injection
209
+ end
210
+
211
+ class << self
212
+ def run params = {}, &block
213
+ # create application container from command line context
214
+ container = Container.new(Config.new(params))
215
+ if block_given?
216
+ container.execute {|context| block.call(context) }
217
+ else
218
+ container.execute params[:class]
219
+ end
220
+ end
221
+
222
+ def config_path app_path
223
+ defaults_path = File.expand_path(app_path)
224
+ ext = File.extname(defaults_path)
225
+ defaults_path.sub((ext == "" && /$/ || /#{ext}$/), ".yml")
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,164 @@
1
+ # once (shamelessly) stolen(for testing(and squeezed)) from rails...
2
+ # now degenerated beyong comprehension
3
+ # awaiting a major refactoring to get a managble configuration...
4
+
5
+ module DL
6
+
7
+ AllLoggersByPrefix = {} # list of all loggers
8
+
9
+ class Logger
10
+
11
+ LevelMetrics = {
12
+ :fatal => 0.0,
13
+ :error => 1.0,
14
+ :warn => 2.0,
15
+ :info => 3.0,
16
+ :debug => 4.0,
17
+ }
18
+
19
+ # XXX das mit diesem config kram ist alles noch ziemlicher mist...
20
+ DefaultLogger = {
21
+ :prefix => "???",
22
+ :out => $stderr,
23
+ :fmt => "%c %23s %s%s\n", # "%c %-13s: %s%s\n",
24
+ #:include_levels => /^(fatal|error|warn|info)/i, # no debug
25
+ :include_levels => nil, # all inclusive
26
+ #:exclude_levels => nil,
27
+ :exclude_levels => /^debug/i, # no debug on default
28
+ :quiet => false,
29
+ :level => 3.0,
30
+ }
31
+ Config = {
32
+ :default => DefaultLogger,
33
+ }
34
+
35
+ attr_accessor :prefix, :out, :fmt, :include_levels, :exclude_levels
36
+ attr_accessor :quiet, :level
37
+
38
+ def initialize prefix, config = DefaultLogger
39
+ @nesting_level = 0
40
+ @config = DefaultLogger.dup
41
+ @config[:prefix] = prefix
42
+ configure config
43
+ end
44
+
45
+ def configure settings
46
+ @config.update(settings)
47
+ @prefix = @config[:prefix]
48
+ @out = @config[:out]
49
+ @fmt = @config[:fmt]
50
+ @include_levels = @config[:include_levels]
51
+ @exclude_levels = @config[:exclude_levels]
52
+ @quiet = @config[:quiet]
53
+ @level = @config[:level]
54
+ end
55
+
56
+ def self.[] prefix
57
+ self.get prefix
58
+ end
59
+
60
+ def log(status, message, exception, &block)
61
+ unless quiet
62
+ #return "excluded" if exclude_levels and exclude_levels.match(status)
63
+ #if include_levels and !include_levels.match(status)
64
+ # return "not included"
65
+ #end
66
+ msg = @fmt % [status[0], prefix, ' ' * @nesting_level, message]
67
+ @out.print(msg)
68
+ if exception
69
+ callstack = exception.backtrace
70
+ @out.print " !! #{exception}\n\t#{callstack.join("\n\t")}\n"
71
+ begin
72
+ reason = exception.reason
73
+ callstack = reason.backtrace
74
+ txt = "#{reason}\n\t#{callstack.join("\n\t")}\n"
75
+ @out.print "(Cause)>> #{txt}"
76
+ rescue
77
+ # noop
78
+ end
79
+ end
80
+ end
81
+ indent(&block) if block_given?
82
+ end
83
+
84
+ def flush
85
+ @out.flush
86
+ end
87
+
88
+ def indent(&block)
89
+ @nesting_level += 1
90
+ if block_given?
91
+ begin
92
+ block.call
93
+ ensure
94
+ outdent
95
+ end
96
+ end
97
+ end
98
+
99
+ def outdent
100
+ @nesting_level -= 1
101
+ if block_given?
102
+ begin
103
+ block.call
104
+ ensure
105
+ indent
106
+ end
107
+ end
108
+ end
109
+
110
+ private
111
+ def method_missing(method, *args, &block)
112
+ message, execption = args
113
+ if LevelMetrics[method.to_sym] <= level
114
+ log(method.to_s.upcase, message, execption, &block)
115
+ end
116
+ end
117
+ end
118
+
119
+ def self.logger(prefix = $0, out = $stdout)
120
+ prefix = self.find_prefix(prefix)
121
+ unless log = AllLoggersByPrefix[prefix]
122
+ c = Logger::Config[prefix] || {}
123
+ #c[:fmt] = "%c %23s %s%s\n"
124
+ log = (AllLoggersByPrefix[prefix] = Logger.new(prefix, c))
125
+ end
126
+ log
127
+ end
128
+
129
+ def self.find_prefix prefix
130
+ raise "nil prefix not yet implemented!" unless prefix
131
+ return prefix if prefix.kind_of? String
132
+ return prefix.name if prefix.kind_of? Class
133
+ return prefix.name if prefix.kind_of? Module
134
+ return prefix.class.name
135
+ end
136
+
137
+ module LoggerMixin
138
+ def logger
139
+ @dl_class_logger ||= DL.logger(self) # class logger
140
+ end
141
+
142
+ def debug *args
143
+ logger.debug *args
144
+ end
145
+ def info *args
146
+ logger.info *args
147
+ end
148
+ def warn *args
149
+ logger.warn *args
150
+ end
151
+ def error *args
152
+ logger.error *args
153
+ end
154
+ def fatal *args
155
+ logger.fatal *args
156
+ end
157
+ def log_level
158
+ logger.level
159
+ end
160
+ def set_log_level level
161
+ logger.level= level
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,199 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'pp'
5
+
6
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ require 'app-ctx'
8
+
9
+ class AppModuleTest < Test::Unit::TestCase
10
+
11
+ class With_application_main
12
+ attr_reader :context
13
+ attr_accessor :baroque
14
+ # application_main is the default catch-all entry point for app-ctx
15
+ def application_main context
16
+ puts "#{self}: #{context.inspect}"
17
+ @context = context
18
+ end
19
+ end
20
+ def test_default_entry_point
21
+ puts "\n --> #{self.name}"
22
+ argv = ["-f", "--foo=bar", "--baroque=gaga", "arg1", "arg2"]
23
+ app = App::run :class => With_application_main, :argv => argv
24
+ assert_not_nil app
25
+ assert_equal With_application_main, app.class
26
+ assert_not_nil app.context
27
+ assert_equal({:f=>true, :foo=>"bar", :baroque =>"gaga"}, app.context.values)
28
+ assert_equal ["arg1", "arg2"], app.context.argv
29
+ assert_equal "gaga", app.baroque
30
+ end
31
+
32
+ class ArgumentEntryPoint
33
+ attr_reader :context
34
+ def entrypoint context
35
+ puts "#{self}: #{context.inspect}"
36
+ @context = context
37
+ end
38
+ end
39
+ def test_run_without_point
40
+ puts "\n --> #{self.name}"
41
+ argv = ["-f", "--foo=bar", "entrypoint", "first_method_arg"]
42
+ app = App::run :class => ArgumentEntryPoint, :argv => argv
43
+ assert_not_nil app
44
+ assert_equal ArgumentEntryPoint, app.class
45
+ assert_not_nil app.context
46
+ assert_equal({:f=>true, :foo=>"bar"}, app.context.values)
47
+ assert_equal ["first_method_arg"], app.context.argv
48
+ end
49
+
50
+ end
51
+
52
+ class AppConfigTest < Test::Unit::TestCase
53
+
54
+ include App
55
+
56
+ def test_config_block
57
+ puts "\n --> #{self.name}"
58
+ App::Config.new do |context|
59
+ puts "--------------->context: #{context.inspect}"
60
+ assert_not_nil context
61
+ assert_equal({}, context.values)
62
+ end
63
+
64
+ App::Config.new :argv=>["-f", "--foo=bar", "arg1", "arg2"] do |context|
65
+ puts "--------------->context: #{context.inspect}"
66
+ assert_not_nil context
67
+ assert_equal({:f=>true, :foo=>"bar"}, context.values)
68
+ assert_equal ["arg1", "arg2"], context.argv
69
+ end
70
+ end
71
+
72
+ def test_load_config_file
73
+ puts "\n --> #{self.name}"
74
+ c = App::Config.new
75
+ # config file does not exist:w
76
+ c.load_config_file File.join(File.dirname($0), "no-such-file")
77
+ assert_equal({}, c.values)
78
+
79
+ # load configuration from file
80
+ c.load_config_file File.join(File.dirname($0), "config-1.yml")
81
+ assert_equal({
82
+ :f=>3.21, :i=>17, :empty_hash=>{}, :assoc=>{:key=>"foo"}
83
+ }, c.values)
84
+
85
+ # config overloading
86
+ c.load_config_file File.join(File.dirname($0), "config-2.yml")
87
+ assert_equal({
88
+ :f=>3.21, :i=>17, :empty_hash=>{},
89
+ :assoc=>{:key=>"bar"}, :f2=>-3.21
90
+ }, c.values)
91
+ end
92
+
93
+ def test_configure_defaults
94
+ puts "\n --> #{self.name}"
95
+ c = App::Config.new
96
+ assert_equal ARGV, c.argv
97
+ assert_equal({}, c.values)
98
+
99
+ # find the default values config file next to the $0 script
100
+ assert_equal File.expand_path($0).sub(/.rb$/, ".yml"), c.defaults_path
101
+ end
102
+
103
+ def test_config_path
104
+ puts "\n --> #{self.name}"
105
+
106
+ cpath = App.config_path "foo.bar"
107
+ assert_not_nil cpath
108
+ assert_equal File.expand_path(File.join(".", "foo.yml")), cpath
109
+
110
+ cpath = App.config_path "/tmp/foo.rb.rb"
111
+ assert_not_nil cpath
112
+ assert_equal File.expand_path(File.join("/", "tmp", "foo.rb.yml")), cpath
113
+
114
+ # XXX this might fail on windows??
115
+ cpath = App.config_path "~/foo.bar"
116
+ assert_not_nil cpath
117
+ assert_equal File.expand_path(File.join("~", "foo.yml")), cpath
118
+ end
119
+
120
+ def test_parse_ruby_options
121
+ puts "\n --> #{self.name}"
122
+
123
+ c = Config.new :argv => ["--list:(1..10).to_a"]
124
+ cfg, av = c.values, c.argv
125
+ assert_equal({:list => (1..10).to_a}, cfg)
126
+
127
+ c = Config.new :argv => ["--list:(1..10)"]
128
+ cfg, av = c.values, c.argv
129
+ assert_equal({:list => (1..10)}, cfg)
130
+ assert cfg[:list].kind_of?(Range)
131
+ end
132
+
133
+ def test_parse_command_line_options
134
+ puts "\n --> #{self.name}"
135
+
136
+ c = Config.new :argv => []
137
+ cfg, av = c.values, c.argv
138
+ assert_equal({}, cfg)
139
+ assert_equal [], av
140
+
141
+ c = Config.new :argv => ["-a"]
142
+ cfg, av = c.values, c.argv
143
+ assert cfg[:a]
144
+ assert ! cfg[:b]
145
+ end
146
+
147
+ def test_parse_command_line_int_float_flags
148
+ puts "\n --> #{self.name}"
149
+
150
+ c = Config.new :argv => ["-a", "--int=5", "--float=2.34"]
151
+ cfg, av = c.values, c.argv
152
+ assert_equal({:a=>true,:int=>5, :float=>2.34}, cfg)
153
+ assert_equal [], av
154
+ end
155
+
156
+ def test_various_string_values
157
+ puts "\n --> #{self.name}"
158
+
159
+ c = Config.new :argv => ["xxx"]
160
+ cfg, av = c.values, c.argv
161
+ assert_equal ["xxx"], av
162
+ assert_equal({}, cfg)
163
+
164
+ c = Config.new :argv => ["foo", "bar"]
165
+ cfg, av = c.values, c.argv
166
+ assert_equal({}, cfg)
167
+ assert_equal ["foo", "bar"], av
168
+
169
+ c = Config.new :argv => ["--foo", "bar"]
170
+ cfg, av = c.values, c.argv
171
+ assert_equal({:foo=>true}, cfg)
172
+ assert_equal ["bar"], av
173
+
174
+ c = Config.new :argv => ["foo", "--bar"]
175
+ cfg, av = c.values, c.argv
176
+ assert_equal({:bar=>true}, cfg)
177
+ assert_equal ["foo"], av
178
+
179
+ c = Config.new :argv => ["--key=val", "foo"]
180
+ cfg, av = c.values, c.argv
181
+ assert_equal({:key=>'val'}, cfg)
182
+ assert_equal ["foo"], av
183
+
184
+ c = Config.new :argv => ["--key=val", "--key=ooo"]
185
+ cfg, av = c.values, c.argv
186
+ assert_equal({:key=>'ooo'}, cfg)
187
+ assert_equal [], av
188
+
189
+ c = Config.new :argv => ["-a='foo bar'", '-b="bar foo"']
190
+ cfg, av = c.values, c.argv
191
+ assert_equal [], av
192
+ assert_equal({:a=>"foo bar", :b=>"bar foo"}, cfg)
193
+
194
+ c = Config.new :argv => ["--aa='foo bar'", '--bb="bar foo"']
195
+ cfg, av = c.values, c.argv
196
+ assert_equal [], av
197
+ assert_equal({:aa=>"foo bar", :bb=>"bar foo"}, cfg)
198
+ end
199
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: app-ctx
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.2
7
+ date: 2006-09-18 00:00:00 +02:00
8
+ summary: command line application startup and config context
9
+ require_paths:
10
+ - lib
11
+ email: dirk.luesebrink@idmedia.com
12
+ homepage: http://www.idmedia.com/
13
+ rubyforge_project:
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - Dirk Luesebrink
30
+ files:
31
+ - lib/app-ctx.rb
32
+ - lib/app-ctx/dlog.rb
33
+ - test/t_app-ctx.rb
34
+ - README
35
+ test_files:
36
+ - test/t_app-ctx.rb
37
+ rdoc_options:
38
+ - --main
39
+ - README
40
+ extra_rdoc_files:
41
+ - README
42
+ executables: []
43
+
44
+ extensions: []
45
+
46
+ requirements: []
47
+
48
+ dependencies: []
49
+