tty-option 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README.md +1200 -488
- data/lib/tty/option/conversions.rb +27 -17
- data/lib/tty/option/deep_dup.rb +43 -19
- data/lib/tty/option/errors.rb +33 -3
- data/lib/tty/option/formatter.rb +364 -69
- data/lib/tty/option/param_permitted.rb +7 -3
- data/lib/tty/option/param_validation.rb +124 -20
- data/lib/tty/option/parameter.rb +2 -1
- data/lib/tty/option/parser/options.rb +6 -1
- data/lib/tty/option/version.rb +1 -1
- metadata +3 -2
@@ -23,8 +23,10 @@ module TTY
|
|
23
23
|
end
|
24
24
|
|
25
25
|
convert :date do |val|
|
26
|
+
require "date" unless defined?(::Date)
|
27
|
+
next val if val.is_a?(::Date)
|
28
|
+
|
26
29
|
begin
|
27
|
-
require "date" unless defined?(::Date)
|
28
30
|
::Date.parse(val)
|
29
31
|
rescue ArgumentError, TypeError
|
30
32
|
Const::Undefined
|
@@ -48,13 +50,19 @@ module TTY
|
|
48
50
|
end
|
49
51
|
|
50
52
|
convert :pathname, :path do |val|
|
51
|
-
require "pathname"
|
52
|
-
::Pathname
|
53
|
+
require "pathname" unless defined?(::Pathname)
|
54
|
+
next val if val.is_a?(::Pathname)
|
55
|
+
|
56
|
+
begin
|
57
|
+
::Pathname.new(val)
|
58
|
+
rescue TypeError
|
59
|
+
Const::Undefined
|
60
|
+
end
|
53
61
|
end
|
54
62
|
|
55
63
|
convert :regexp do |val|
|
56
64
|
begin
|
57
|
-
Regexp.new(val
|
65
|
+
Regexp.new(val)
|
58
66
|
rescue TypeError, RegexpError
|
59
67
|
Const::Undefined
|
60
68
|
end
|
@@ -63,14 +71,16 @@ module TTY
|
|
63
71
|
convert :sym, :symbol do |val|
|
64
72
|
begin
|
65
73
|
String(val).to_sym
|
66
|
-
rescue ArgumentError
|
74
|
+
rescue ArgumentError, TypeError
|
67
75
|
Const::Undefined
|
68
76
|
end
|
69
77
|
end
|
70
78
|
|
71
79
|
convert :uri do |val|
|
80
|
+
require "uri" unless defined?(::URI)
|
81
|
+
next val if val.is_a?(::URI)
|
82
|
+
|
72
83
|
begin
|
73
|
-
require "uri"
|
74
84
|
::URI.parse(val)
|
75
85
|
rescue ::URI::InvalidURIError
|
76
86
|
Const::Undefined
|
@@ -79,24 +89,24 @@ module TTY
|
|
79
89
|
|
80
90
|
convert :list, :array do |val|
|
81
91
|
next Const::Undefined if val.nil?
|
92
|
+
next Array(val) unless val.respond_to?(:split)
|
82
93
|
|
83
|
-
|
84
|
-
|
85
|
-
|
94
|
+
val.split(/(?<!\\),/)
|
95
|
+
.map { |v| v.strip.gsub(/\\,/, ",") }
|
96
|
+
.reject(&:empty?)
|
86
97
|
end
|
87
98
|
|
88
99
|
convert :map, :hash do |val|
|
89
100
|
next Const::Undefined if val.nil?
|
101
|
+
next val if val.is_a?(Hash)
|
90
102
|
|
91
|
-
values = val.respond_to?(:
|
103
|
+
values = val.respond_to?(:split) ? val.split(/[& ]/) : Array(val)
|
92
104
|
values.each_with_object({}) do |pair, pairs|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
end
|
99
|
-
pairs
|
105
|
+
is_string = pair.respond_to?(:split)
|
106
|
+
key, value = is_string ? pair.split(/[=:]/, 2) : pair
|
107
|
+
new_key = is_string ? key.to_sym : key
|
108
|
+
current = pairs[new_key]
|
109
|
+
pairs[new_key] = current ? Array(current) << value : value
|
100
110
|
end
|
101
111
|
end
|
102
112
|
|
data/lib/tty/option/deep_dup.rb
CHANGED
@@ -2,46 +2,70 @@
|
|
2
2
|
|
3
3
|
module TTY
|
4
4
|
module Option
|
5
|
+
# Responsible for deep copying an object
|
6
|
+
#
|
7
|
+
# @api private
|
5
8
|
module DeepDup
|
6
9
|
NONDUPLICATABLE = [
|
7
|
-
Symbol, TrueClass, FalseClass, NilClass, Numeric, Method
|
10
|
+
Symbol, TrueClass, FalseClass, NilClass, Numeric, Method, UnboundMethod
|
8
11
|
].freeze
|
9
12
|
|
10
|
-
#
|
13
|
+
# Deep copy an object
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# DeepDeup.deep_dup({foo: {bar: [1, 2]}})
|
11
17
|
#
|
12
18
|
# @param [Object] object
|
19
|
+
# the object to deep copy
|
20
|
+
# @param [Hash] cache
|
21
|
+
# the cache of copied objects
|
22
|
+
#
|
23
|
+
# @return [Object]
|
13
24
|
#
|
14
25
|
# @api public
|
15
|
-
def self.deep_dup(object)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
26
|
+
def self.deep_dup(object, cache = {})
|
27
|
+
cache[object.object_id] ||=
|
28
|
+
case object
|
29
|
+
when *NONDUPLICATABLE then object
|
30
|
+
when Array then deep_dup_array(object, cache)
|
31
|
+
when Hash then deep_dup_hash(object, cache)
|
32
|
+
else object.dup
|
33
|
+
end
|
22
34
|
end
|
23
35
|
|
24
|
-
#
|
36
|
+
# Deep copy an array
|
25
37
|
#
|
26
|
-
# @param [
|
38
|
+
# @param [Array] object
|
39
|
+
# the array object to deep copy
|
40
|
+
# @param [Hash] cache
|
41
|
+
# the cache of copied objects
|
42
|
+
#
|
43
|
+
# @return [Array]
|
27
44
|
#
|
28
45
|
# @api private
|
29
|
-
def self.
|
30
|
-
object.each_with_object(
|
31
|
-
|
46
|
+
def self.deep_dup_array(object, cache)
|
47
|
+
object.each_with_object(cache[object.object_id] = []) do |val, array|
|
48
|
+
array << deep_dup(val, cache)
|
32
49
|
end
|
33
50
|
end
|
51
|
+
private_class_method :deep_dup_array
|
34
52
|
|
35
|
-
#
|
53
|
+
# Deep copy a hash
|
36
54
|
#
|
37
|
-
# @param [
|
55
|
+
# @param [Hash] object
|
56
|
+
# the hash object to deep copy
|
57
|
+
# @param [Hash] cache
|
58
|
+
# the cache of copied objects
|
59
|
+
#
|
60
|
+
# @return [Hash]
|
38
61
|
#
|
39
62
|
# @api private
|
40
|
-
def self.
|
41
|
-
object.each_with_object([]) do |
|
42
|
-
|
63
|
+
def self.deep_dup_hash(object, cache)
|
64
|
+
object.each_with_object(cache[object.object_id] = {}) do |(k, v), hash|
|
65
|
+
hash[deep_dup(k, cache)] = deep_dup(v, cache)
|
43
66
|
end
|
44
67
|
end
|
68
|
+
private_class_method :deep_dup_hash
|
45
69
|
end # DeepDup
|
46
70
|
end # Option
|
47
71
|
end # TTY
|
data/lib/tty/option/errors.rb
CHANGED
@@ -22,6 +22,22 @@ module TTY
|
|
22
22
|
# Raised during command line input parsing
|
23
23
|
class ParseError < Error
|
24
24
|
attr_accessor :param
|
25
|
+
|
26
|
+
# Format value
|
27
|
+
#
|
28
|
+
# @param [Object] value
|
29
|
+
# the value to format
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# format_value([:a, 1])
|
33
|
+
# # => a:1
|
34
|
+
#
|
35
|
+
# @return [String]
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def format_value(value)
|
39
|
+
value.respond_to?(:to_ary) ? value.join(":") : value.to_s
|
40
|
+
end
|
25
41
|
end
|
26
42
|
|
27
43
|
# Raised when found unrecognized parameter
|
@@ -39,7 +55,7 @@ module TTY
|
|
39
55
|
@param = param_or_message
|
40
56
|
|
41
57
|
message = format(MESSAGE,
|
42
|
-
value: value,
|
58
|
+
value: format_value(value),
|
43
59
|
name: param.name,
|
44
60
|
type: param.to_sym)
|
45
61
|
else
|
@@ -129,16 +145,30 @@ module TTY
|
|
129
145
|
if param_or_message.is_a?(Parameter)
|
130
146
|
@param = param_or_message
|
131
147
|
message = format(MESSAGE,
|
132
|
-
value: value,
|
148
|
+
value: format_value(value),
|
133
149
|
name: param.name,
|
134
150
|
type: param.to_sym,
|
135
|
-
choices: param.permit
|
151
|
+
choices: format_choices(param.permit))
|
136
152
|
else
|
137
153
|
message = param_or_message
|
138
154
|
end
|
139
155
|
|
140
156
|
super(message)
|
141
157
|
end
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
# Format permitted choices
|
162
|
+
#
|
163
|
+
# @param [Array<Object>] choices
|
164
|
+
# the choices to format
|
165
|
+
#
|
166
|
+
# @return [String]
|
167
|
+
#
|
168
|
+
# @api private
|
169
|
+
def format_choices(choices)
|
170
|
+
choices.map { |val| format_value(val) }.join(", ")
|
171
|
+
end
|
142
172
|
end
|
143
173
|
end # Option
|
144
174
|
end # TTY
|