configurable 0.7.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/Help/Command Line.rdoc +141 -0
  2. data/Help/Config Syntax.rdoc +229 -0
  3. data/Help/Config Types.rdoc +143 -0
  4. data/{History → History.rdoc} +9 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.rdoc +144 -0
  7. data/lib/configurable.rb +7 -270
  8. data/lib/configurable/class_methods.rb +344 -367
  9. data/lib/configurable/config_classes.rb +3 -0
  10. data/lib/configurable/config_classes/list_config.rb +26 -0
  11. data/lib/configurable/config_classes/nest_config.rb +50 -0
  12. data/lib/configurable/config_classes/scalar_config.rb +91 -0
  13. data/lib/configurable/config_hash.rb +87 -112
  14. data/lib/configurable/config_types.rb +6 -0
  15. data/lib/configurable/config_types/boolean_type.rb +22 -0
  16. data/lib/configurable/config_types/float_type.rb +11 -0
  17. data/lib/configurable/config_types/integer_type.rb +11 -0
  18. data/lib/configurable/config_types/nest_type.rb +39 -0
  19. data/lib/configurable/config_types/object_type.rb +58 -0
  20. data/lib/configurable/config_types/string_type.rb +15 -0
  21. data/lib/configurable/conversions.rb +91 -0
  22. data/lib/configurable/module_methods.rb +0 -1
  23. data/lib/configurable/version.rb +1 -5
  24. metadata +73 -30
  25. data/README +0 -207
  26. data/lib/cdoc.rb +0 -413
  27. data/lib/cdoc/cdoc_html_generator.rb +0 -38
  28. data/lib/cdoc/cdoc_html_template.rb +0 -42
  29. data/lib/config_parser.rb +0 -563
  30. data/lib/config_parser/option.rb +0 -108
  31. data/lib/config_parser/switch.rb +0 -44
  32. data/lib/config_parser/utils.rb +0 -177
  33. data/lib/configurable/config.rb +0 -97
  34. data/lib/configurable/indifferent_access.rb +0 -35
  35. data/lib/configurable/nest_config.rb +0 -78
  36. data/lib/configurable/ordered_hash_patch.rb +0 -85
  37. data/lib/configurable/utils.rb +0 -186
  38. data/lib/configurable/validation.rb +0 -768
@@ -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
@@ -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
@@ -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
@@ -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