rubikon 0.4.1 → 0.5.0
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.
- data/README.md +4 -3
- data/lib/core_ext/object.rb +2 -1
- data/lib/rubikon.rb +1 -1
- data/lib/rubikon/application/class_methods.rb +5 -1
- data/lib/rubikon/application/dsl_methods.rb +39 -15
- data/lib/rubikon/application/instance_methods.rb +75 -28
- data/lib/rubikon/application/sandbox.rb +5 -3
- data/lib/rubikon/colored_io.rb +105 -0
- data/lib/rubikon/command.rb +18 -8
- data/lib/rubikon/config/auto_provider.rb +39 -0
- data/lib/rubikon/config/factory.rb +65 -0
- data/lib/rubikon/config/ini_provider.rb +60 -0
- data/lib/rubikon/config/yaml_provider.rb +30 -0
- data/lib/rubikon/exceptions.rb +12 -0
- data/lib/rubikon/flag.rb +2 -0
- data/lib/rubikon/has_arguments.rb +2 -0
- data/lib/rubikon/parameter.rb +11 -8
- data/lib/rubikon/progress_bar.rb +12 -6
- data/lib/rubikon/throbber.rb +6 -6
- data/samples/config/config_sample.rb +39 -0
- data/samples/helloworld/hello_world.rb +8 -2
- data/test/test_application.rb +6 -6
- data/test/test_command.rb +13 -13
- data/test/test_config.rb +41 -0
- data/test/test_flag.rb +4 -4
- data/test/test_has_arguments.rb +24 -24
- data/test/test_ini_provider.rb +26 -0
- data/test/test_progress_bar.rb +18 -0
- metadata +15 -5
data/lib/rubikon/command.rb
CHANGED
@@ -56,6 +56,8 @@ module Rubikon
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
private
|
60
|
+
|
59
61
|
# Add a new parameter for this command
|
60
62
|
#
|
61
63
|
# @param [Parameter, Hash] parameter The parameter to add to this
|
@@ -119,6 +121,11 @@ module Rubikon
|
|
119
121
|
# @see Flag
|
120
122
|
# @see Option
|
121
123
|
def parse_arguments(args)
|
124
|
+
current_param = Application::InstanceMethods.
|
125
|
+
instance_method(:current_param).bind(@app)
|
126
|
+
set_current_param = Application::InstanceMethods.
|
127
|
+
instance_method(:current_param=).bind(@app)
|
128
|
+
|
122
129
|
@args = []
|
123
130
|
args.each do |arg|
|
124
131
|
if arg.start_with?('-')
|
@@ -128,20 +135,20 @@ module Rubikon
|
|
128
135
|
end
|
129
136
|
|
130
137
|
unless parameter.nil?
|
131
|
-
|
132
|
-
|
138
|
+
current_param.call.send(:active!) unless current_param.call.nil?
|
139
|
+
set_current_param.call(parameter)
|
133
140
|
next
|
134
141
|
end
|
135
142
|
|
136
|
-
if
|
143
|
+
if current_param.call.nil? || !current_param.call.send(:more_args?)
|
137
144
|
self << arg
|
138
145
|
else
|
139
|
-
|
146
|
+
current_param.call.send(:<<, arg)
|
140
147
|
end
|
141
148
|
end
|
142
149
|
|
143
|
-
|
144
|
-
|
150
|
+
current_param.call.send(:active!) unless current_param.call.nil?
|
151
|
+
set_current_param.call(nil)
|
145
152
|
end
|
146
153
|
|
147
154
|
# Resets this command to its initial state
|
@@ -150,7 +157,9 @@ module Rubikon
|
|
150
157
|
# @since 0.4.0
|
151
158
|
def reset
|
152
159
|
super
|
153
|
-
@params.values.uniq.each
|
160
|
+
@params.values.uniq.each do |param|
|
161
|
+
param.send(:reset) if param.is_a? Parameter
|
162
|
+
end
|
154
163
|
end
|
155
164
|
|
156
165
|
# Checks whether a parameter with the given name exists for this command
|
@@ -171,7 +180,8 @@ module Rubikon
|
|
171
180
|
def run(*args)
|
172
181
|
parse_arguments(args)
|
173
182
|
check_args
|
174
|
-
|
183
|
+
Application::InstanceMethods.instance_method(:sandbox).bind(@app).call.
|
184
|
+
instance_eval(&@block)
|
175
185
|
end
|
176
186
|
|
177
187
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
module Rubikon
|
7
|
+
|
8
|
+
module Config
|
9
|
+
|
10
|
+
# A configuration provider loading various configuration file formats using
|
11
|
+
# another provider depending on the extension of the configuration file.
|
12
|
+
#
|
13
|
+
# @author Sebastian Staudt
|
14
|
+
# @since 0.5.0
|
15
|
+
class AutoProvider
|
16
|
+
|
17
|
+
# Load a configuration file with the corresponding provider detected
|
18
|
+
# from the file extension
|
19
|
+
#
|
20
|
+
# @param [String] file The path of the config file to load
|
21
|
+
# @return [Hash] The configuration values loaded from the file
|
22
|
+
# @see YamlProvider
|
23
|
+
def self.load_config(file)
|
24
|
+
ext = File.extname(file)
|
25
|
+
case ext
|
26
|
+
when '.ini'
|
27
|
+
IniProvider.load_config file
|
28
|
+
when '.yaml', '.yml'
|
29
|
+
YamlProvider.load_config file
|
30
|
+
else
|
31
|
+
raise UnsupportedConfigFormatError.new(ext)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'rubikon/config/auto_provider'
|
7
|
+
require 'rubikon/config/ini_provider'
|
8
|
+
require 'rubikon/config/yaml_provider'
|
9
|
+
|
10
|
+
module Rubikon
|
11
|
+
|
12
|
+
# This module contains several classes used to load configuration data from
|
13
|
+
# various sources
|
14
|
+
#
|
15
|
+
# @author Sebastian Staudt
|
16
|
+
# @since 0.5.0
|
17
|
+
module Config
|
18
|
+
|
19
|
+
# The configuration factory is used to load one or more configuration
|
20
|
+
# files from different search paths and using different file formats, e.g.
|
21
|
+
# YAML.
|
22
|
+
#
|
23
|
+
# @author Sebastian Staudt
|
24
|
+
class Factory
|
25
|
+
|
26
|
+
# Providers available for use
|
27
|
+
PROVIDERS = [ :auto, :ini, :yaml ]
|
28
|
+
|
29
|
+
# @return [Hash] The configuration data loaded from the configuration
|
30
|
+
# files found inside the search paths
|
31
|
+
attr_reader :config
|
32
|
+
|
33
|
+
# @return [Array<String>] The paths of the configuration files found and
|
34
|
+
# loaded
|
35
|
+
attr_reader :files
|
36
|
+
|
37
|
+
# Creates a new factory instance with a given file name to be searched in
|
38
|
+
# the given paths and using the specified provider to load the
|
39
|
+
# configuration data from the files.
|
40
|
+
#
|
41
|
+
# @param [String] name The name of the configuration file
|
42
|
+
# @param [Array<String>] search_paths An array of paths to be searched
|
43
|
+
# for configuration files
|
44
|
+
# @param [PROVIDERS] provider The provider to use for loading
|
45
|
+
# configuration data from the files found
|
46
|
+
def initialize(name, search_paths, provider = :yaml)
|
47
|
+
provider = :auto unless PROVIDERS.include?(provider)
|
48
|
+
provider = Config.const_get("#{provider.to_s.capitalize}Provider")
|
49
|
+
|
50
|
+
@files = []
|
51
|
+
@config = {}
|
52
|
+
search_paths.each do |path|
|
53
|
+
config_file = File.join path, name
|
54
|
+
if File.exists? config_file
|
55
|
+
@config.merge! provider.load_config(config_file)
|
56
|
+
@files << config_file
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
module Rubikon
|
7
|
+
|
8
|
+
module Config
|
9
|
+
|
10
|
+
# A configuration provider loading configuration data from INI files
|
11
|
+
#
|
12
|
+
# @author Sebastian Staudt
|
13
|
+
# @since 0.5.0
|
14
|
+
class IniProvider
|
15
|
+
|
16
|
+
# Loads a configuration Hash from a INI file
|
17
|
+
#
|
18
|
+
# This method is taken from code written by gdsx in #ruby-lang (see
|
19
|
+
# http://snippets.dzone.com/posts/show/563).
|
20
|
+
#
|
21
|
+
# @param [String] file The path of the file to load
|
22
|
+
# @return [Hash] The configuration data loaded from the file
|
23
|
+
def self.load_config(file)
|
24
|
+
content = File.new(file).readlines.map do |line|
|
25
|
+
line.gsub(/(?:#|;).*/, '').strip
|
26
|
+
end.join("\n")
|
27
|
+
|
28
|
+
config = {}
|
29
|
+
content = content.split(/\[([^\]]+)\]/)[1..-1]
|
30
|
+
content.inject([]) do |temp, field|
|
31
|
+
temp << field
|
32
|
+
if temp.length == 2
|
33
|
+
value = temp[1].sub(/^\s+/,'').sub(/\s+$/,'')
|
34
|
+
if config[temp[0]].nil?
|
35
|
+
config[temp[0]] = value
|
36
|
+
else
|
37
|
+
config[temp[0]] << "\n#{value}"
|
38
|
+
end
|
39
|
+
temp.clear
|
40
|
+
end
|
41
|
+
temp
|
42
|
+
end
|
43
|
+
|
44
|
+
config.dup.each do |key, value|
|
45
|
+
value_list = value.split /[\r\n]+/
|
46
|
+
config[key] = value_list.inject({}) do |hash, val|
|
47
|
+
k, v = val.split /\s*=\s*/
|
48
|
+
hash[k] = v
|
49
|
+
hash
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
config
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
module Rubikon
|
9
|
+
|
10
|
+
module Config
|
11
|
+
|
12
|
+
# A configuration provider loading configuration data from YAML files
|
13
|
+
#
|
14
|
+
# @author Sebastian Staudt
|
15
|
+
# @since 0.5.0
|
16
|
+
class YamlProvider
|
17
|
+
|
18
|
+
# Loads a configuration Hash from a YAML formatted file
|
19
|
+
#
|
20
|
+
# @param [String] file The path of the file to load
|
21
|
+
# @return [Hash] The configuration data loaded from the file
|
22
|
+
def self.load_config(file)
|
23
|
+
YAML.load_file file
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/lib/rubikon/exceptions.rb
CHANGED
@@ -78,4 +78,16 @@ module Rubikon
|
|
78
78
|
|
79
79
|
end
|
80
80
|
|
81
|
+
# Raised if a command has been supplied that does not exist
|
82
|
+
#
|
83
|
+
# @author Sebastian Staudt
|
84
|
+
# @since 0.5.0
|
85
|
+
class UnsupportedConfigFormatError < ArgumentError
|
86
|
+
|
87
|
+
def initialize(ext)
|
88
|
+
super "Unknown config file extension: #{ext}"
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
81
93
|
end
|
data/lib/rubikon/flag.rb
CHANGED
data/lib/rubikon/parameter.rb
CHANGED
@@ -36,14 +36,6 @@ module Rubikon
|
|
36
36
|
@name = name.to_sym
|
37
37
|
end
|
38
38
|
|
39
|
-
# Marks this parameter as active when it has been supplied by the user on
|
40
|
-
# the command-line. This also calls the code block of the parameter if it
|
41
|
-
# exists
|
42
|
-
def active!
|
43
|
-
@active = true
|
44
|
-
@app.sandbox.instance_eval(&@block) unless @block.nil?
|
45
|
-
end
|
46
|
-
|
47
39
|
# Returns whether this parameter has is active, i.e. it has been supplied
|
48
40
|
# by the user on the command-line
|
49
41
|
#
|
@@ -53,6 +45,17 @@ module Rubikon
|
|
53
45
|
end
|
54
46
|
alias_method :given?, :active?
|
55
47
|
|
48
|
+
protected
|
49
|
+
|
50
|
+
# Marks this parameter as active when it has been supplied by the user on
|
51
|
+
# the command-line. This also calls the code block of the parameter if it
|
52
|
+
# exists
|
53
|
+
def active!
|
54
|
+
@active = true
|
55
|
+
Application::InstanceMethods.instance_method(:sandbox).bind(@app).call.
|
56
|
+
instance_eval(&@block) unless @block.nil?
|
57
|
+
end
|
58
|
+
|
56
59
|
# Resets this parameter to its initial state
|
57
60
|
#
|
58
61
|
# @since 0.4.0
|
data/lib/rubikon/progress_bar.rb
CHANGED
@@ -35,13 +35,19 @@ module Rubikon
|
|
35
35
|
end
|
36
36
|
@maximum.round
|
37
37
|
|
38
|
-
@progress_char
|
39
|
-
@ostream
|
40
|
-
@progress
|
41
|
-
@size
|
42
|
-
@factor
|
43
|
-
@value
|
38
|
+
@progress_char = options[:char] || '#'
|
39
|
+
@ostream = options[:ostream] || $stdout
|
40
|
+
@progress = 0
|
41
|
+
@size = options[:size] || 20
|
42
|
+
@factor = @size.round.to_f / @maximum
|
43
|
+
@value = 0
|
44
|
+
@brackets = options[:brackets] || false
|
45
|
+
@bracket_filler = options[:bracket_filler] || ' '
|
44
46
|
|
47
|
+
if @brackets
|
48
|
+
@ostream << '[' + @bracket_filler * @size + ']'+ "\b" * (@size + 1)
|
49
|
+
@ostream.flush
|
50
|
+
end
|
45
51
|
self + (options[:start] || 0)
|
46
52
|
end
|
47
53
|
|
data/lib/rubikon/throbber.rb
CHANGED
@@ -21,16 +21,16 @@ module Rubikon
|
|
21
21
|
# @param [Thread] thread The thread that should be watched
|
22
22
|
# @see Application::InstanceMethods#throbber
|
23
23
|
def initialize(ostream, thread)
|
24
|
-
proc = Proc.new do |
|
24
|
+
proc = Proc.new do |os, thr|
|
25
25
|
step = 0
|
26
|
-
|
27
|
-
while
|
28
|
-
|
29
|
-
|
26
|
+
os.putc 32
|
27
|
+
while thr.alive?
|
28
|
+
os << "\b#{SPINNER[step].chr}"
|
29
|
+
os.flush
|
30
30
|
step = (step + 1) % 4
|
31
31
|
sleep 0.25
|
32
32
|
end
|
33
|
-
|
33
|
+
os.putc 8
|
34
34
|
end
|
35
35
|
|
36
36
|
super { proc.call(ostream, thread) }
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This code is free software; you can redistribute it and/or modify it under
|
4
|
+
# the terms of the new BSD License.
|
5
|
+
#
|
6
|
+
# Copyright (c) 2010, Sebastian Staudt
|
7
|
+
|
8
|
+
if ENV['RUBIKON_DEV']
|
9
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', 'lib', 'rubikon')
|
10
|
+
else
|
11
|
+
require 'rubygems'
|
12
|
+
require 'rubikon'
|
13
|
+
end
|
14
|
+
|
15
|
+
# A Rubikon application demonstrating the configuration feature
|
16
|
+
class ConfigSample < Rubikon::Application::Base
|
17
|
+
|
18
|
+
dir = File.dirname __FILE__
|
19
|
+
global_dir = File.join dir, 'global'
|
20
|
+
local_dir = File.join dir, 'local'
|
21
|
+
|
22
|
+
set :config_file, 'config.yml'
|
23
|
+
set :config_paths, [ global_dir, local_dir ]
|
24
|
+
|
25
|
+
global_flag :'exclude-local' do
|
26
|
+
set :config_paths, [ global_dir ]
|
27
|
+
|
28
|
+
puts "Seems like you changed the truth...\n\n"
|
29
|
+
end
|
30
|
+
|
31
|
+
default do
|
32
|
+
puts "A pretty #{config[:string]} example of Rubikon's config."
|
33
|
+
puts "#{config[:number]} is greater than 1."
|
34
|
+
puts "A lie is never #{config[:boolean]}."
|
35
|
+
puts 'Global configs are loaded...' if config[:global]
|
36
|
+
puts 'and overriden by local configs' if config[:local]
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -15,11 +15,16 @@ end
|
|
15
15
|
# A relatively simple Hello World application using Rubikon
|
16
16
|
class HelloWorld < Rubikon::Application::Base
|
17
17
|
|
18
|
+
set :config_file, 'helloworld.ini'
|
19
|
+
set :config_format, :ini
|
20
|
+
|
18
21
|
# Greet the whole world per default
|
19
22
|
flag :more
|
20
23
|
option :name, [:who]
|
21
24
|
option :names, -1
|
22
25
|
default 'Simple hello world' do
|
26
|
+
p config
|
27
|
+
|
23
28
|
debug 'Starting to greet the world...'
|
24
29
|
if given? :name
|
25
30
|
greet parameters[:name].who
|
@@ -38,14 +43,15 @@ class HelloWorld < Rubikon::Application::Base
|
|
38
43
|
# Ask the user for his name and greet him
|
39
44
|
command :interactive, 'Greet interactively' do
|
40
45
|
name = input 'Please enter your name'
|
41
|
-
|
46
|
+
call :'__default', '--name', name
|
42
47
|
end
|
43
48
|
|
44
49
|
# Show a progress bar while iterating through a loop
|
50
|
+
flag :brackets
|
45
51
|
command :progress, 'Display a progress bar' do
|
46
52
|
put 'Watch my progress while I greet the world: '
|
47
53
|
x = 1000000
|
48
|
-
progress_bar(:char => '+', :maximum => x, :size => 30) do |progress|
|
54
|
+
progress_bar(:char => '+', :maximum => x, :size => 30, :brackets => brackets.given?, :bracket_filler => '-') do |progress|
|
49
55
|
x.times do
|
50
56
|
progress.+
|
51
57
|
end
|