configurable 0.7.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Help/Command Line.rdoc +141 -0
- data/Help/Config Syntax.rdoc +229 -0
- data/Help/Config Types.rdoc +143 -0
- data/{History → History.rdoc} +9 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +144 -0
- data/lib/configurable.rb +7 -270
- data/lib/configurable/class_methods.rb +344 -367
- data/lib/configurable/config_classes.rb +3 -0
- data/lib/configurable/config_classes/list_config.rb +26 -0
- data/lib/configurable/config_classes/nest_config.rb +50 -0
- data/lib/configurable/config_classes/scalar_config.rb +91 -0
- data/lib/configurable/config_hash.rb +87 -112
- data/lib/configurable/config_types.rb +6 -0
- data/lib/configurable/config_types/boolean_type.rb +22 -0
- data/lib/configurable/config_types/float_type.rb +11 -0
- data/lib/configurable/config_types/integer_type.rb +11 -0
- data/lib/configurable/config_types/nest_type.rb +39 -0
- data/lib/configurable/config_types/object_type.rb +58 -0
- data/lib/configurable/config_types/string_type.rb +15 -0
- data/lib/configurable/conversions.rb +91 -0
- data/lib/configurable/module_methods.rb +0 -1
- data/lib/configurable/version.rb +1 -5
- metadata +73 -30
- data/README +0 -207
- data/lib/cdoc.rb +0 -413
- data/lib/cdoc/cdoc_html_generator.rb +0 -38
- data/lib/cdoc/cdoc_html_template.rb +0 -42
- data/lib/config_parser.rb +0 -563
- data/lib/config_parser/option.rb +0 -108
- data/lib/config_parser/switch.rb +0 -44
- data/lib/config_parser/utils.rb +0 -177
- data/lib/configurable/config.rb +0 -97
- data/lib/configurable/indifferent_access.rb +0 -35
- data/lib/configurable/nest_config.rb +0 -78
- data/lib/configurable/ordered_hash_patch.rb +0 -85
- data/lib/configurable/utils.rb +0 -186
- data/lib/configurable/validation.rb +0 -768
data/lib/config_parser/option.rb
DELETED
@@ -1,108 +0,0 @@
|
|
1
|
-
require 'config_parser/utils'
|
2
|
-
|
3
|
-
class ConfigParser
|
4
|
-
|
5
|
-
# Represents an option registered with ConfigParser.
|
6
|
-
class Option
|
7
|
-
|
8
|
-
# A format string used by to_s
|
9
|
-
LINE_FORMAT = "%-36s %-43s"
|
10
|
-
|
11
|
-
# The short switch mapping to self
|
12
|
-
attr_reader :short
|
13
|
-
|
14
|
-
# The long switch mapping to self
|
15
|
-
attr_reader :long
|
16
|
-
|
17
|
-
# The argument name printed by to_s. If arg_name
|
18
|
-
# is nil, no value will be parsed for self.
|
19
|
-
attr_reader :arg_name
|
20
|
-
|
21
|
-
# The description printed by to_s
|
22
|
-
attr_reader :desc
|
23
|
-
|
24
|
-
# The block called when one of the switches mapping
|
25
|
-
# to self is parse; block will receive the parsed
|
26
|
-
# argument if arg_name is specified.
|
27
|
-
attr_reader :block
|
28
|
-
|
29
|
-
# Initializes a new Option using attribute values for :long, :short,
|
30
|
-
# :arg_name, and :desc. The long and short values are transformed
|
31
|
-
# using Utils.longify and Utils.shortify, meaning both bare strings
|
32
|
-
# (ex 'opt', 'o') and full switches ('--opt', '-o') are valid.
|
33
|
-
def initialize(attributes={}, &block)
|
34
|
-
@short = Utils.shortify(attributes[:short])
|
35
|
-
@long = Utils.longify(attributes[:long])
|
36
|
-
@arg_name = attributes[:arg_name]
|
37
|
-
@desc = attributes[:desc]
|
38
|
-
@block = block
|
39
|
-
end
|
40
|
-
|
41
|
-
# Returns an array of non-nil switches mapping to self (ie [long, short]).
|
42
|
-
def switches
|
43
|
-
[long, short].compact
|
44
|
-
end
|
45
|
-
|
46
|
-
# Parse determines how an option is actually parsed from an argv. Parse
|
47
|
-
# recieves the switch mapping to self for cases in which it affects the
|
48
|
-
# outcome (see Switch). By default parse has two modes of action:
|
49
|
-
#
|
50
|
-
# ==== Argument-style option (arg_name is specified)
|
51
|
-
#
|
52
|
-
# If arg_name is set, then parse passes value to the block. If no value
|
53
|
-
# is specified, the next argument in argv is used instead. An error
|
54
|
-
# is raised if no value can be found.
|
55
|
-
#
|
56
|
-
# ==== Flag-style option (no arg_name is specified)
|
57
|
-
#
|
58
|
-
# In this case, parse simply calls the block. If a non-nil value is
|
59
|
-
# specified, parse raises an error.
|
60
|
-
#
|
61
|
-
def parse(switch, value, argv)
|
62
|
-
if arg_name
|
63
|
-
unless value
|
64
|
-
raise "no value provided for: #{switch}" if argv.empty?
|
65
|
-
value = argv.shift
|
66
|
-
end
|
67
|
-
block ? block.call(value) : value
|
68
|
-
else
|
69
|
-
raise "value specified for flag: #{switch}" if value
|
70
|
-
block ? block.call : nil
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
# Formats self as a help string for use on the command line.
|
75
|
-
def to_s
|
76
|
-
lines = Lazydoc::Utils.wrap(desc.to_s, 43)
|
77
|
-
|
78
|
-
header = " #{short_str}#{long_str} #{arg_name}"
|
79
|
-
header = header.length > 36 ? header.ljust(80) : (LINE_FORMAT % [header, lines.shift])
|
80
|
-
|
81
|
-
if lines.empty?
|
82
|
-
header
|
83
|
-
else
|
84
|
-
lines.collect! {|line| LINE_FORMAT % [nil, line] }
|
85
|
-
"#{header}\n#{lines.join("\n")}"
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
# helper returning short formatted for to_s
|
92
|
-
def short_str # :nodoc:
|
93
|
-
case
|
94
|
-
when short && long
|
95
|
-
"#{short}, "
|
96
|
-
when short
|
97
|
-
"#{short}"
|
98
|
-
else
|
99
|
-
' '
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# helper returning long formatted for to_s
|
104
|
-
def long_str # :nodoc:
|
105
|
-
long
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
data/lib/config_parser/switch.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
class ConfigParser
|
2
|
-
|
3
|
-
# Switch represents a special type of Option where both a positive
|
4
|
-
# (--switch) and negative (--no-switch) version of long should
|
5
|
-
# map to self. A short may be specified for Switch; it will always
|
6
|
-
# be treated like the positive switch.
|
7
|
-
class Switch < Option
|
8
|
-
|
9
|
-
# The negative long switch, determined from long.
|
10
|
-
attr_reader :negative_long
|
11
|
-
|
12
|
-
# Initializes a new Switch. Raises an error if an arg_name is
|
13
|
-
# specified for self (as switches are intended to be boolean
|
14
|
-
# in nature), or if no long option is specified.
|
15
|
-
def initialize(options={})
|
16
|
-
super
|
17
|
-
raise ArgumentError, "arg_name specified for switch: #{arg_name}" if arg_name
|
18
|
-
raise ArgumentError, "no long specified" unless long
|
19
|
-
@negative_long = Utils.prefix_long(long, 'no-')
|
20
|
-
end
|
21
|
-
|
22
|
-
# Returns an array of non-nil switches mapping to self (ie
|
23
|
-
# [long, negative_long, short]).
|
24
|
-
def switches
|
25
|
-
[long, negative_long, short].compact
|
26
|
-
end
|
27
|
-
|
28
|
-
# Calls the block with false if the negative long is specified,
|
29
|
-
# or calls the block with true in all other cases. Raises an
|
30
|
-
# error if a value is specified.
|
31
|
-
def parse(switch, value, argv)
|
32
|
-
raise "value specified for switch: #{switch}" if value
|
33
|
-
value = (switch == negative_long ? false : true)
|
34
|
-
block ? block.call(value) : value
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
# helper returning long formatted for to_s
|
40
|
-
def long_str # :nodoc:
|
41
|
-
long ? Utils.prefix_long(long, '[no-]') : ''
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
data/lib/config_parser/utils.rb
DELETED
@@ -1,177 +0,0 @@
|
|
1
|
-
class ConfigParser
|
2
|
-
|
3
|
-
# A medly of methods used throughout the ConfigParser classes.
|
4
|
-
module Utils
|
5
|
-
module_function
|
6
|
-
|
7
|
-
# The option break argument
|
8
|
-
OPTION_BREAK = "--"
|
9
|
-
|
10
|
-
# Matches a nested long option, with or without a value
|
11
|
-
# (ex: '--opt', '--nested:opt', '--opt=value'). After
|
12
|
-
# the match:
|
13
|
-
#
|
14
|
-
# $1:: the switch
|
15
|
-
# $2:: the value
|
16
|
-
#
|
17
|
-
LONG_OPTION = /^(--[A-z].*?)(?:=(.*))?$/
|
18
|
-
|
19
|
-
# Matches a nested short option, with or without a value
|
20
|
-
# (ex: '-o', '-n:o', '-o=value'). After the match:
|
21
|
-
#
|
22
|
-
# $1:: the switch
|
23
|
-
# $2:: the value
|
24
|
-
#
|
25
|
-
SHORT_OPTION = /^(-[A-z](?::[A-z])*)(?:=(.*))?$/
|
26
|
-
|
27
|
-
# Matches the alternate syntax for short options
|
28
|
-
# (ex: '-n:ovalue', '-ovalue'). After the match:
|
29
|
-
#
|
30
|
-
# $1:: the switch
|
31
|
-
# $2:: the value
|
32
|
-
#
|
33
|
-
ALT_SHORT_OPTION = /^(-[A-z](?::[A-z])*)(.+)$/
|
34
|
-
|
35
|
-
# Turns the input string into a short-format option. Raises
|
36
|
-
# an error if the option does not match SHORT_OPTION. Nils
|
37
|
-
# are returned directly.
|
38
|
-
#
|
39
|
-
# shortify("-o") # => '-o'
|
40
|
-
# shortify(:o) # => '-o'
|
41
|
-
#
|
42
|
-
def shortify(str)
|
43
|
-
return nil if str == nil
|
44
|
-
|
45
|
-
str = str.to_s
|
46
|
-
str = "-#{str}" unless str[0] == ?-
|
47
|
-
unless str =~ SHORT_OPTION && $2 == nil
|
48
|
-
raise ArgumentError, "invalid short option: #{str}"
|
49
|
-
end
|
50
|
-
str
|
51
|
-
end
|
52
|
-
|
53
|
-
# Turns the input string into a long-format option. Underscores
|
54
|
-
# are converted to hyphens. Raises an error if the option does
|
55
|
-
# not match LONG_OPTION. Nils are returned directly.
|
56
|
-
#
|
57
|
-
# longify("--opt") # => '--opt'
|
58
|
-
# longify(:opt) # => '--opt'
|
59
|
-
# longify(:opt_ion) # => '--opt-ion'
|
60
|
-
#
|
61
|
-
def longify(str)
|
62
|
-
return nil if str == nil
|
63
|
-
|
64
|
-
str = str.to_s
|
65
|
-
str = "--#{str}" unless str =~ /^--/
|
66
|
-
str.gsub!(/_/, '-')
|
67
|
-
unless str =~ LONG_OPTION && $2 == nil
|
68
|
-
raise ArgumentError, "invalid long option: #{str}"
|
69
|
-
end
|
70
|
-
str
|
71
|
-
end
|
72
|
-
|
73
|
-
# Adds a prefix onto the last nested segment of a long option.
|
74
|
-
#
|
75
|
-
# prefix_long("--opt", 'no-') # => '--no-opt'
|
76
|
-
# prefix_long("--nested:opt", 'no-') # => '--nested:no-opt'
|
77
|
-
#
|
78
|
-
def prefix_long(switch, prefix, split_char=':')
|
79
|
-
switch = switch[2,switch.length-2] if switch =~ /^--/
|
80
|
-
switch = switch.split(split_char)
|
81
|
-
switch[-1] = "#{prefix}#{switch[-1]}"
|
82
|
-
"--#{switch.join(':')}"
|
83
|
-
end
|
84
|
-
|
85
|
-
# Infers the default long using key and adds it to attributes. Returns
|
86
|
-
# attributes.
|
87
|
-
#
|
88
|
-
# infer_long(:key, {}) # => {:long => '--key'}
|
89
|
-
#
|
90
|
-
def infer_long(key, attributes)
|
91
|
-
unless attributes.has_key?(:long)
|
92
|
-
attributes[:long] = "--#{key}"
|
93
|
-
end
|
94
|
-
|
95
|
-
attributes
|
96
|
-
end
|
97
|
-
|
98
|
-
# Infers the default argname from attributes[:long] and sets it in
|
99
|
-
# attributes. Returns attributes.
|
100
|
-
#
|
101
|
-
# infer_arg_name(:key, {:long => '--opt'}) # => {:long => '--opt', :arg_name => 'OPT'}
|
102
|
-
# infer_arg_name(:key, {}) # => {:arg_name => 'KEY'}
|
103
|
-
#
|
104
|
-
def infer_arg_name(key, attributes)
|
105
|
-
if attributes.has_key?(:arg_name)
|
106
|
-
return attributes
|
107
|
-
end
|
108
|
-
|
109
|
-
if long = attributes[:long]
|
110
|
-
long.to_s =~ /^(?:--)?(.*)$/
|
111
|
-
attributes[:arg_name] = $1.upcase
|
112
|
-
else
|
113
|
-
attributes[:arg_name] = key.to_s.upcase
|
114
|
-
end
|
115
|
-
|
116
|
-
attributes
|
117
|
-
end
|
118
|
-
|
119
|
-
# Attributes:
|
120
|
-
#
|
121
|
-
# :long the long key ("--key")
|
122
|
-
# :arg_name the argument name ("KEY")
|
123
|
-
#
|
124
|
-
def setup_option(key, attributes={})
|
125
|
-
infer_long(key, attributes)
|
126
|
-
infer_arg_name(key, attributes)
|
127
|
-
|
128
|
-
lambda {|value| config[key] = value }
|
129
|
-
end
|
130
|
-
|
131
|
-
# Attributes:
|
132
|
-
#
|
133
|
-
# :long the long key ("--key")
|
134
|
-
#
|
135
|
-
def setup_flag(key, default=true, attributes={})
|
136
|
-
infer_long(key, attributes)
|
137
|
-
|
138
|
-
lambda {config[key] = !default }
|
139
|
-
end
|
140
|
-
|
141
|
-
# Attributes:
|
142
|
-
#
|
143
|
-
# :long the long key ("--[no-]key")
|
144
|
-
#
|
145
|
-
def setup_switch(key, default=true, attributes={})
|
146
|
-
infer_long(key, attributes)
|
147
|
-
|
148
|
-
if attributes[:long].to_s =~ /^(?:--)?(\[no-\])?(.*)$/
|
149
|
-
attributes[:long] = "--[no-]#{$2}" unless $1
|
150
|
-
end
|
151
|
-
|
152
|
-
lambda {|value| config[key] = value }
|
153
|
-
end
|
154
|
-
|
155
|
-
# Attributes:
|
156
|
-
#
|
157
|
-
# :long the long key ("--key")
|
158
|
-
# :arg_name the argument name ("KEY")
|
159
|
-
# :split the split character
|
160
|
-
#
|
161
|
-
def setup_list(key, attributes={})
|
162
|
-
infer_long(key, attributes)
|
163
|
-
infer_arg_name(key, attributes)
|
164
|
-
|
165
|
-
split = attributes[:split]
|
166
|
-
n = attributes[:n]
|
167
|
-
|
168
|
-
lambda do |value|
|
169
|
-
array = (config[key] ||= [])
|
170
|
-
array.concat(split ? value.split(split) : [value])
|
171
|
-
if n && array.length > n
|
172
|
-
raise "too many assignments: #{key.inspect}"
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
data/lib/configurable/config.rb
DELETED
@@ -1,97 +0,0 @@
|
|
1
|
-
module Configurable
|
2
|
-
|
3
|
-
# Configs are used by ConfigHash to determine how to delegate read/write
|
4
|
-
# operations to a receiver. Configs also track metadata related to their
|
5
|
-
# presentation in various contexts.
|
6
|
-
class Config
|
7
|
-
class << self
|
8
|
-
|
9
|
-
# Determines if the value is duplicable. Non-duplicable values
|
10
|
-
# include nil, true, false, Symbol, Numeric, Method, Module, and
|
11
|
-
# any object that does not respond to dup.
|
12
|
-
def duplicable_value?(value)
|
13
|
-
case value
|
14
|
-
when nil, true, false, Symbol, Numeric, Method, Module then false
|
15
|
-
else value.respond_to?(:dup)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
# The reader method called on a receiver during get
|
21
|
-
attr_reader :reader
|
22
|
-
|
23
|
-
# The writer method called on a receiver during set
|
24
|
-
attr_reader :writer
|
25
|
-
|
26
|
-
# An hash of metadata for self, often used to indicate how a config is
|
27
|
-
# presented in different contexts (ex on the command line, in a web form,
|
28
|
-
# or a desktop app).
|
29
|
-
attr_reader :attributes
|
30
|
-
|
31
|
-
# Initializes a new Config.
|
32
|
-
def initialize(reader, writer="#{reader}=", default=nil, attributes={}, init=true, dup=nil)
|
33
|
-
self.reader = reader
|
34
|
-
self.writer = writer
|
35
|
-
@default = default
|
36
|
-
@attributes = attributes
|
37
|
-
@init = init
|
38
|
-
@dup = dup.nil? ? Config.duplicable_value?(default) : dup
|
39
|
-
end
|
40
|
-
|
41
|
-
# Returns the default value. If duplicate is specified and the default
|
42
|
-
# may be duplicated (see Config.duplicable_value?) then a duplicate
|
43
|
-
# of the default is returned.
|
44
|
-
def default(duplicate=true)
|
45
|
-
duplicate && @dup ? @default.dup : @default
|
46
|
-
end
|
47
|
-
|
48
|
-
# Returns the value for the specified attribute, or default if the
|
49
|
-
# attribute is unspecified.
|
50
|
-
def [](key, default=nil)
|
51
|
-
attributes.has_key?(key) ? attributes[key] : default
|
52
|
-
end
|
53
|
-
|
54
|
-
# Calls reader on the receiver and returns the result.
|
55
|
-
def get(receiver)
|
56
|
-
receiver.send(reader)
|
57
|
-
end
|
58
|
-
|
59
|
-
# Calls writer on the receiver with the value.
|
60
|
-
def set(receiver, value)
|
61
|
-
receiver.send(writer, value)
|
62
|
-
end
|
63
|
-
|
64
|
-
# Sets the default value on the receiver. Normally this method is only
|
65
|
-
# called during Configurable#initialize_config, and only then when init?
|
66
|
-
# returns true.
|
67
|
-
def init(receiver)
|
68
|
-
receiver.send(writer, default)
|
69
|
-
end
|
70
|
-
|
71
|
-
# Returns true or false as specified in new. True indicates that this
|
72
|
-
# delegate is allowed to initialize values on the receiver during
|
73
|
-
# Configurable#initialize_config.
|
74
|
-
def init?
|
75
|
-
@init
|
76
|
-
end
|
77
|
-
|
78
|
-
# Returns an inspection string.
|
79
|
-
def inspect
|
80
|
-
"#<#{self.class}:#{object_id} reader=#{reader} writer=#{writer} default=#{default.inspect} >"
|
81
|
-
end
|
82
|
-
|
83
|
-
protected
|
84
|
-
|
85
|
-
# Sets the reader for self, assuring the reader is not nil.
|
86
|
-
def reader=(value) # :nodoc:
|
87
|
-
raise ArgumentError, "reader may not be nil" if value.nil?
|
88
|
-
@reader = value.to_sym
|
89
|
-
end
|
90
|
-
|
91
|
-
# Sets the writer for self, assuring the writer is not nil.
|
92
|
-
def writer=(value) # :nodoc:
|
93
|
-
raise ArgumentError, "writer may not be nil" if value.nil?
|
94
|
-
@writer = value.to_sym
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module Configurable
|
2
|
-
|
3
|
-
# Implements AGET and ASET methods that symbolize string keys, in effect
|
4
|
-
# producing indifferent access. IndifferentAccess is intended to extend
|
5
|
-
# a Hash.
|
6
|
-
#
|
7
|
-
# Note that the indifference produced by this module is very thin indeed.
|
8
|
-
# Strings may still be used as keys through store/fetch, and
|
9
|
-
# existing string keys are not changed in any way. Nonetheless,
|
10
|
-
# these methods are sufficient for Configurable and ConfigHash.
|
11
|
-
module IndifferentAccess
|
12
|
-
|
13
|
-
# Symbolizes string keys and calls super.
|
14
|
-
def [](key)
|
15
|
-
super(convert(key))
|
16
|
-
end
|
17
|
-
|
18
|
-
# Symbolizes string keys and calls super.
|
19
|
-
def []=(key, value)
|
20
|
-
super(convert(key), value)
|
21
|
-
end
|
22
|
-
|
23
|
-
# Ensures duplicates use indifferent access.
|
24
|
-
def dup
|
25
|
-
super().extend IndifferentAccess
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
# a helper to convert strings to symbols
|
31
|
-
def convert(key) # :nodoc:
|
32
|
-
key.kind_of?(String) ? key.to_sym : key
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|