usps-imis-api 0.12.11 → 0.13.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/lib/usps/imis/command_line/help.rb +181 -0
- data/lib/usps/imis/command_line/options.yml.erb +158 -129
- data/lib/usps/imis/command_line/options_parser.rb +60 -55
- data/lib/usps/imis/command_line/options_parser_config.rb +68 -0
- data/lib/usps/imis/command_line/performers.rb +11 -11
- data/lib/usps/imis/command_line.rb +2 -0
- data/lib/usps/imis/logger_formatter.rb +1 -1
- data/lib/usps/imis/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 01ea56e2c86361876d694df871ed74b17ead231c2a04956cbcf4121e9ea81a43
|
|
4
|
+
data.tar.gz: f1bb3827652a82ef2bbd821267305e200da82adc5305a3e8743634574ac8cba7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7d827dc920c5b0db49ec6e965d1a6991e6c2198671db810fc8bd76f8d50e74ae1f3f8bcfe4c98bc1af97a6f54444b41ed94893f240bad5ec0987772bae2fe95b
|
|
7
|
+
data.tar.gz: c0887342a3a94477e4a2bf9e888443b4a1db68ce343b0555b5dcd9a8dd1706f70c15962a7088c19d2613f3e13f1ef6c669bdcd8f192e5c1708c41f34f77591f6
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Usps
|
|
4
|
+
module Imis
|
|
5
|
+
module CommandLine
|
|
6
|
+
# Custom help page generator for the command line interface
|
|
7
|
+
#
|
|
8
|
+
# @private
|
|
9
|
+
#
|
|
10
|
+
module Help
|
|
11
|
+
TERMINAL_WIDTH = 120
|
|
12
|
+
GAP = 4
|
|
13
|
+
|
|
14
|
+
def banner_header(version)
|
|
15
|
+
<<~BANNER
|
|
16
|
+
#{version.bold.blue}
|
|
17
|
+
#{'P/R/C Julian Fiander, SN'.gray}
|
|
18
|
+
BANNER
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def banner_contents
|
|
22
|
+
<<~BANNER
|
|
23
|
+
#{'Usage'.underline}
|
|
24
|
+
|
|
25
|
+
#{'imis'.bold} #{'[command] [options]'.gray}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
#{'Further Help'.underline}
|
|
29
|
+
|
|
30
|
+
For an explanation of how to provide API configuration, more details on the options,
|
|
31
|
+
and usage examples, please refer to the wiki:
|
|
32
|
+
|
|
33
|
+
https://github.com/unitedstatespowersquadrons/imis-api-ruby/wiki/Command-Line
|
|
34
|
+
|
|
35
|
+
BANNER
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Build the custom help page
|
|
39
|
+
#
|
|
40
|
+
def custom_help
|
|
41
|
+
[banner_header(Api.version), '', banner_contents].tap do |lines|
|
|
42
|
+
help_commands(lines)
|
|
43
|
+
help_options(lines)
|
|
44
|
+
help_legacy_flags(lines)
|
|
45
|
+
end.join("\n")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Format a single option line for the help page
|
|
49
|
+
#
|
|
50
|
+
def format_option(key)
|
|
51
|
+
raw_description, details = options[key]
|
|
52
|
+
details ||= {}
|
|
53
|
+
|
|
54
|
+
flag = option_flag_string(key, details).ljust(option_column_width)
|
|
55
|
+
left_width = option_column_width + indent(3).length # Indent additional lines one step further
|
|
56
|
+
tags = [
|
|
57
|
+
(" (default: #{details[:default]})" if details[:default]),
|
|
58
|
+
(" (max: #{details[:max]})" if details[:max])
|
|
59
|
+
].compact.join
|
|
60
|
+
|
|
61
|
+
"#{flag}#{wrap_description(raw_description, left_width, suffix: tags)}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def help_commands(lines)
|
|
67
|
+
# Adjust the underlying command padding to account for non-printing characters
|
|
68
|
+
#
|
|
69
|
+
# Bold and gray each add 14:
|
|
70
|
+
# '-'.bold.length == 15
|
|
71
|
+
# '-'.gray.length == 15
|
|
72
|
+
#
|
|
73
|
+
escape_padding = 14
|
|
74
|
+
|
|
75
|
+
command_lengths = subcommands.map { |name, details| name.length + details[:value].to_s.length }
|
|
76
|
+
command_width = command_lengths.max + GAP + escape_padding
|
|
77
|
+
|
|
78
|
+
lines << "#{'Commands'.underline}\n"
|
|
79
|
+
subcommands.each do |name, details|
|
|
80
|
+
combined_name = details[:value] ? "#{name.bold} #{"<#{details[:value]}>".gray}" : name.bold
|
|
81
|
+
lines << [
|
|
82
|
+
indent(1),
|
|
83
|
+
combined_name.ljust(command_width + (details[:value] ? escape_padding : 0)),
|
|
84
|
+
details[:description]
|
|
85
|
+
].join
|
|
86
|
+
end
|
|
87
|
+
lines << "\n"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def help_options(lines)
|
|
91
|
+
lines << "#{'Options'.underline}\n"
|
|
92
|
+
option_groups.each do |group_name, option_keys|
|
|
93
|
+
lines << "#{indent(1)}#{group_name.underline}"
|
|
94
|
+
option_keys.each { lines << "#{indent(2)}#{format_option(it)}" }
|
|
95
|
+
lines << ''
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def help_legacy_flags(lines)
|
|
100
|
+
lines << "#{indent(1)}#{'Legacy Flags'.underline}\n"
|
|
101
|
+
lines << "#{indent(2)}The following options are still supported, but have been replaced by subcommands:\n"
|
|
102
|
+
legacy_flags.each do |flags, replacement|
|
|
103
|
+
lines << "#{indent(2)}#{flags.ljust(option_column_width)}use: #{replacement}"
|
|
104
|
+
end
|
|
105
|
+
lines << "\n"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def indent(level) = ' ' * level
|
|
109
|
+
|
|
110
|
+
def option_flag_string(key, details)
|
|
111
|
+
[
|
|
112
|
+
details[:short] ? "-#{details[:short]}, " : indent(2),
|
|
113
|
+
"--#{key.to_s.tr('_', '-')}",
|
|
114
|
+
type_suffix(details[:type])
|
|
115
|
+
].join
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def type_suffix(type)
|
|
119
|
+
case type
|
|
120
|
+
when :string then '=<s>'
|
|
121
|
+
when :strings then '=<s+>'
|
|
122
|
+
when :integer then '=<i>'
|
|
123
|
+
when :ints then '=<i+>'
|
|
124
|
+
when :float then '=<f>'
|
|
125
|
+
when :floats then '=<f+>'
|
|
126
|
+
when :date then '=<d>'
|
|
127
|
+
when :dates then '=<d+>'
|
|
128
|
+
when :io then '=<io>'
|
|
129
|
+
when :ios then '=<io+>'
|
|
130
|
+
else ''
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def wrap_description(text, left_width, suffix: '')
|
|
135
|
+
max_width = TERMINAL_WIDTH - left_width
|
|
136
|
+
padding = "\n#{' ' * left_width}"
|
|
137
|
+
|
|
138
|
+
lines = text.split("\n").flat_map { word_wrap(it, max_width) }
|
|
139
|
+
|
|
140
|
+
if suffix.empty? || visible_length("#{lines.last}#{suffix}") <= max_width
|
|
141
|
+
lines[-1] = "#{lines.last}#{suffix}"
|
|
142
|
+
else
|
|
143
|
+
lines << suffix.lstrip
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
lines.join(padding)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def word_wrap(text, max_width)
|
|
150
|
+
return [text] if max_width <= 0 || visible_length(text) <= max_width
|
|
151
|
+
|
|
152
|
+
words = text.split
|
|
153
|
+
lines = [words.shift]
|
|
154
|
+
words.each do |word|
|
|
155
|
+
candidate = "#{lines.last} #{word}"
|
|
156
|
+
if visible_length(candidate) <= max_width
|
|
157
|
+
lines[-1] = candidate
|
|
158
|
+
else
|
|
159
|
+
lines << word
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
lines
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def visible_length(text)
|
|
166
|
+
text.gsub(/\e\[[0-9;]*m/, '').length
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def option_column_width
|
|
170
|
+
option_widths = option_groups.values.flatten.map do |key|
|
|
171
|
+
_, details = options[key]
|
|
172
|
+
option_flag_string(key, details || {}).length
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
all_widths = option_widths + legacy_flags.keys.map(&:length)
|
|
176
|
+
all_widths.max + GAP
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
@@ -1,137 +1,166 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
Subcommands:
|
|
2
|
+
object:
|
|
3
|
+
description: Interact with a Business Object
|
|
4
|
+
value: name
|
|
5
|
+
legacy_name: 'on'
|
|
6
|
+
option:
|
|
7
|
+
- Business Object name
|
|
8
|
+
- type: string
|
|
9
|
+
short: O
|
|
10
|
+
panel:
|
|
11
|
+
description: Interact with a Panel
|
|
12
|
+
value: name
|
|
13
|
+
option:
|
|
14
|
+
- Panel name
|
|
15
|
+
- type: string
|
|
16
|
+
short: P
|
|
17
|
+
query:
|
|
18
|
+
description: Run an IQA or Business Object Query
|
|
19
|
+
value: name
|
|
20
|
+
option:
|
|
21
|
+
- IQA Query or Business Object name to query
|
|
22
|
+
- type: string
|
|
23
|
+
short: Q
|
|
24
|
+
mapper:
|
|
25
|
+
description: Interact with mapped fields
|
|
26
|
+
option:
|
|
27
|
+
- Interact with mapped fields
|
|
28
|
+
- short: M
|
|
29
|
+
map:
|
|
30
|
+
description: "Shorthand for `<%= 'mapper -f'.green %>` to access a single mapped field"
|
|
31
|
+
value: field
|
|
32
|
+
option:
|
|
33
|
+
- "Shorthand for <%= '-Mf'.green %> to access a single mapped field"
|
|
34
|
+
- type: string
|
|
35
|
+
short: m
|
|
36
|
+
business-objects:
|
|
37
|
+
description: List available Business Objects
|
|
38
|
+
option:
|
|
39
|
+
- List available Business Objects
|
|
40
|
+
- short: B
|
|
41
|
+
auth-token:
|
|
42
|
+
description: Return an auth token for other language wrappers
|
|
43
|
+
option:
|
|
44
|
+
- Return an auth token for other language wrappers
|
|
45
|
+
- short: T
|
|
18
46
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- type: string
|
|
38
|
-
short: m
|
|
39
|
-
business_objects:
|
|
40
|
-
- List available Business Objects
|
|
41
|
-
- short: B
|
|
47
|
+
Options:
|
|
48
|
+
Identity:
|
|
49
|
+
certificate:
|
|
50
|
+
- Member certificate number
|
|
51
|
+
- type: string
|
|
52
|
+
short: c
|
|
53
|
+
id:
|
|
54
|
+
- Member iMIS ID
|
|
55
|
+
- type: integer
|
|
56
|
+
short: i
|
|
57
|
+
record_id:
|
|
58
|
+
- Specific Record ID
|
|
59
|
+
- type: integer
|
|
60
|
+
short: I
|
|
61
|
+
uuid:
|
|
62
|
+
- Record UUID
|
|
63
|
+
- type: string
|
|
64
|
+
short: u
|
|
42
65
|
|
|
43
|
-
|
|
44
|
-
create:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
delete:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
all:
|
|
51
|
-
|
|
52
|
-
|
|
66
|
+
Business Object or Panel:
|
|
67
|
+
create:
|
|
68
|
+
- "Send a <%= 'POST'.cyan %> request"
|
|
69
|
+
- short: C
|
|
70
|
+
delete:
|
|
71
|
+
- "Send a <%= 'DELETE'.cyan %> request"
|
|
72
|
+
- short: D
|
|
73
|
+
all:
|
|
74
|
+
- "Send a <%= 'GET'.cyan %> request for all records for a member"
|
|
75
|
+
- short: A
|
|
53
76
|
|
|
54
|
-
|
|
55
|
-
ordinal:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
field:
|
|
60
|
-
- Specific field to return or update
|
|
61
|
-
- type: string
|
|
62
|
-
short: f
|
|
63
|
-
fields:
|
|
64
|
-
- Specific field(s) to return
|
|
65
|
-
- type: strings
|
|
66
|
-
short: F
|
|
67
|
-
data:
|
|
68
|
-
- "JSON string input -- <%= 'STDIN'.red %> takes priority"
|
|
69
|
-
- type: string
|
|
70
|
-
short: d
|
|
77
|
+
Panel:
|
|
78
|
+
ordinal:
|
|
79
|
+
- Ordinal ID within a Panel
|
|
80
|
+
- type: integer
|
|
81
|
+
short: r
|
|
71
82
|
|
|
72
|
-
|
|
73
|
-
page:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
page_size:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
Query:
|
|
84
|
+
page:
|
|
85
|
+
- Specific page number from a query to return
|
|
86
|
+
- type: integer
|
|
87
|
+
short: p
|
|
88
|
+
page_size:
|
|
89
|
+
- Maximum number of records to include on a single page
|
|
90
|
+
- type: integer
|
|
91
|
+
default: 100
|
|
92
|
+
max: 500
|
|
93
|
+
short: s
|
|
94
|
+
offset:
|
|
95
|
+
- Number of records to skip from the beginning of a query
|
|
96
|
+
- type: integer
|
|
97
|
+
short: o
|
|
86
98
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
Data Input:
|
|
100
|
+
field:
|
|
101
|
+
- Specific field to return or update
|
|
102
|
+
- type: string
|
|
103
|
+
short: f
|
|
104
|
+
fields:
|
|
105
|
+
- Specific field(s) to return
|
|
106
|
+
- type: strings
|
|
107
|
+
short: F
|
|
108
|
+
data:
|
|
109
|
+
- "JSON string input -- <%= 'STDIN'.red %> takes priority"
|
|
110
|
+
- type: string
|
|
111
|
+
short: d
|
|
97
112
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
- type: string
|
|
109
|
-
short: Y
|
|
110
|
-
show_config:
|
|
111
|
-
- Return the active config file path
|
|
112
|
-
- short: X
|
|
113
|
-
include_ids:
|
|
114
|
-
- "Include any <%= 'iMIS ID'.yellow %> and <%= 'Ordinal'.yellow %> properties in returned data"
|
|
115
|
-
- short: N
|
|
113
|
+
Output Format:
|
|
114
|
+
raw:
|
|
115
|
+
- Return raw JSON output, rather than simplified data
|
|
116
|
+
- short: R
|
|
117
|
+
jsonl:
|
|
118
|
+
- Format array output as JSONL
|
|
119
|
+
- short: j
|
|
120
|
+
csv:
|
|
121
|
+
- Format output as CSV (if possible)
|
|
122
|
+
- short: S
|
|
116
123
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
Configuration:
|
|
125
|
+
config:
|
|
126
|
+
- "Path to the JSON/YAML config file to use, or one of the following preset options:\
|
|
127
|
+
\n`<%= 'local_dot'.yellow %>`, \
|
|
128
|
+
`<%= 'local'.yellow %>`, \
|
|
129
|
+
`<%= 'local_dot_config'.yellow %>`, \
|
|
130
|
+
`<%= 'local_config'.yellow %>`, \
|
|
131
|
+
`<%= 'user'.yellow %>`, \
|
|
132
|
+
`<%= 'system'.yellow %>`\
|
|
133
|
+
\nIf no option is provided, the first matching preset option will be automatically used."
|
|
134
|
+
- type: string
|
|
135
|
+
short: Y
|
|
136
|
+
show_config:
|
|
137
|
+
- Return the active config file path
|
|
138
|
+
- short: X
|
|
139
|
+
include_ids:
|
|
140
|
+
- "Include any <%= 'iMIS ID'.yellow %> and <%= 'Ordinal'.yellow %> properties in returned data"
|
|
141
|
+
- short: N
|
|
142
|
+
token:
|
|
143
|
+
- Provide an existing auth token
|
|
144
|
+
- type: string
|
|
145
|
+
short: t
|
|
125
146
|
|
|
126
|
-
|
|
127
|
-
quiet:
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
log:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
log_level:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
147
|
+
Logging:
|
|
148
|
+
quiet:
|
|
149
|
+
- "Suppress logging to <%= 'STDERR'.red %>"
|
|
150
|
+
- short: q
|
|
151
|
+
log:
|
|
152
|
+
- "Redirect logging to <%= 'STDOUT'.red %>"
|
|
153
|
+
- short: l
|
|
154
|
+
log_level:
|
|
155
|
+
- Set the logging level
|
|
156
|
+
- type: string
|
|
157
|
+
default: info
|
|
158
|
+
short: L
|
|
159
|
+
|
|
160
|
+
Misc:
|
|
161
|
+
version:
|
|
162
|
+
- Print version and exit
|
|
163
|
+
- short: v
|
|
164
|
+
help:
|
|
165
|
+
- Show this message
|
|
166
|
+
- short: h
|
|
@@ -6,12 +6,15 @@ module Usps
|
|
|
6
6
|
# Command line options parser
|
|
7
7
|
#
|
|
8
8
|
class OptionsParser
|
|
9
|
+
extend OptionsParserConfig
|
|
10
|
+
extend Help
|
|
11
|
+
|
|
9
12
|
SOLO_FLAGS = %i[show_config auth_token business_objects].freeze
|
|
10
13
|
QUERY_FLAGS = %i[query page page_size offset].freeze
|
|
11
14
|
CONFLICTING_OPTION_GROUPS = [
|
|
12
15
|
%i[certificate id uuid],
|
|
13
|
-
%i[record_id uuid],
|
|
14
|
-
%i[
|
|
16
|
+
%i[certificate record_id uuid],
|
|
17
|
+
%i[object panel query mapper map] + SOLO_FLAGS,
|
|
15
18
|
%i[field fields map query],
|
|
16
19
|
%i[raw include_ids],
|
|
17
20
|
%i[raw jsonl csv],
|
|
@@ -25,71 +28,56 @@ module Usps
|
|
|
25
28
|
|
|
26
29
|
*(SOLO_FLAGS + QUERY_FLAGS + %i[mapper map field fields certificate]).map { [:create, it] },
|
|
27
30
|
*(SOLO_FLAGS + QUERY_FLAGS + %i[mapper map field fields certificate data raw]).map { [:delete, it] },
|
|
28
|
-
*(SOLO_FLAGS + QUERY_FLAGS + %i[mapper map
|
|
31
|
+
*(SOLO_FLAGS + QUERY_FLAGS + %i[mapper map object]).map { [:ordinal, it] },
|
|
29
32
|
*(SOLO_FLAGS + %i[certificate]).map { [:data, it] }
|
|
30
33
|
].freeze
|
|
31
34
|
|
|
32
|
-
attr_reader :
|
|
33
|
-
|
|
34
|
-
def self.options
|
|
35
|
-
return @options if @options
|
|
36
|
-
|
|
37
|
-
raw_yaml_erb = File.read("#{File.dirname(__FILE__)}/options.yml.erb")
|
|
38
|
-
rendered_yaml = ERB.new(raw_yaml_erb).result.gsub("\x1b", '\u001b')
|
|
39
|
-
options = YAML.safe_load(rendered_yaml)
|
|
40
|
-
|
|
41
|
-
@options = options.transform_keys(&:to_sym).transform_values do |description, details|
|
|
42
|
-
next [description] if details.nil?
|
|
43
|
-
|
|
44
|
-
details = details.transform_keys(&:to_sym).each_with_object({}) do |(key, value), hash|
|
|
45
|
-
hash[key] = key == :default ? value : value.to_sym
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
[description, details]
|
|
49
|
-
end
|
|
50
|
-
end
|
|
35
|
+
attr_reader :options
|
|
51
36
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
37
|
+
# Render the custom help page and exit
|
|
38
|
+
#
|
|
39
|
+
# :nocov:
|
|
40
|
+
def self.help
|
|
41
|
+
IO.popen('less -R', 'w') { it.puts custom_help }
|
|
42
|
+
exit 0
|
|
57
43
|
end
|
|
44
|
+
# :nocov:
|
|
58
45
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
#{'imis'.bold} #{'[options]'.gray}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
#{'Further Help'.underline}
|
|
46
|
+
# Pre-process ARGV to convert subcommands and legacy aliases to current flags
|
|
47
|
+
#
|
|
48
|
+
def self.preprocess_argv!
|
|
49
|
+
return if ARGV.empty?
|
|
67
50
|
|
|
68
|
-
|
|
69
|
-
|
|
51
|
+
ARGV.map! do |arg|
|
|
52
|
+
flag, value = arg.split('=', 2)
|
|
53
|
+
next arg unless legacy_aliases.key?(flag)
|
|
70
54
|
|
|
71
|
-
|
|
55
|
+
[legacy_aliases[flag], value].compact.join('=')
|
|
56
|
+
end
|
|
72
57
|
|
|
58
|
+
return unless (subcommand = subcommands[ARGV[0]])
|
|
73
59
|
|
|
74
|
-
|
|
75
|
-
|
|
60
|
+
name = ARGV.shift
|
|
61
|
+
value = ARGV.shift if subcommand[:value]
|
|
62
|
+
ARGV.unshift("--#{name}", *[value].compact)
|
|
76
63
|
end
|
|
77
64
|
|
|
78
65
|
def initialize
|
|
66
|
+
self.class.preprocess_argv!
|
|
67
|
+
|
|
68
|
+
# Manually render help page before parsing options, to override the default behavior
|
|
69
|
+
#
|
|
70
|
+
# :nocov:
|
|
71
|
+
self.class.help if ARGV.delete('-h') || ARGV.delete('--help')
|
|
72
|
+
# :nocov:
|
|
73
|
+
|
|
79
74
|
@options = parse_options.compact
|
|
80
|
-
@arguments = ARGV # Not currently used
|
|
81
75
|
|
|
82
76
|
# Set the default behavior to --help instead of --version
|
|
83
77
|
#
|
|
84
|
-
#
|
|
85
|
-
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
# - The default behavior is to print just the version label to the terminal
|
|
89
|
-
# - CommandLine::Performers#perform! *must* expect a `version:` pattern,
|
|
90
|
-
# and will return a quoted string of the version label
|
|
91
|
-
#
|
|
92
|
-
Optimist.educate if ARGV.empty? && defaults?
|
|
78
|
+
# :nocov:
|
|
79
|
+
self.class.help if ARGV.empty? && defaults?
|
|
80
|
+
# :nocov:
|
|
93
81
|
|
|
94
82
|
pre_process_options!
|
|
95
83
|
end
|
|
@@ -130,15 +118,24 @@ module Usps
|
|
|
130
118
|
@options[:data] = JSON.parse(@options[:data]) if @options[:data]
|
|
131
119
|
|
|
132
120
|
validate_query_options!
|
|
133
|
-
|
|
134
|
-
raise Errors::CommandLineError, 'Maximum page size is 500' if @options[:page_size] > 500
|
|
121
|
+
validate_max_values!
|
|
135
122
|
|
|
136
123
|
@options[:offset] = (@options[:page] - 1) * @options[:page_size] if @options[:page]
|
|
137
124
|
|
|
138
|
-
|
|
139
|
-
|
|
125
|
+
set_shorthand_query_data if @options[:query]
|
|
126
|
+
end
|
|
140
127
|
|
|
141
|
-
|
|
128
|
+
# Support shorthand for setting identity param on queries
|
|
129
|
+
#
|
|
130
|
+
# Doesn't currently support record_id
|
|
131
|
+
#
|
|
132
|
+
def set_shorthand_query_data
|
|
133
|
+
case @options
|
|
134
|
+
in id: _ then @options[:data] = { 'id' => @options.delete(:id) }
|
|
135
|
+
in certificate: _ then @options[:data] = { 'certificate' => @options.delete(:certificate) }
|
|
136
|
+
in uuid: _ then @options[:data] = { 'id' => @options.delete(:uuid) }
|
|
137
|
+
else # Do nothing
|
|
138
|
+
end
|
|
142
139
|
end
|
|
143
140
|
|
|
144
141
|
def validate_query_options!
|
|
@@ -147,6 +144,14 @@ module Usps
|
|
|
147
144
|
|
|
148
145
|
Optimist.die(:query, "must be provided if any of --#{query_options.join(', --').gsub('_', '-')} are provided")
|
|
149
146
|
end
|
|
147
|
+
|
|
148
|
+
def validate_max_values!
|
|
149
|
+
self.class.options.each do |option, (_, details)|
|
|
150
|
+
next unless details&.key?(:max) && @options[option] > details[:max]
|
|
151
|
+
|
|
152
|
+
Optimist.die(option, "must be at most #{details[:max]}")
|
|
153
|
+
end
|
|
154
|
+
end
|
|
150
155
|
end
|
|
151
156
|
end
|
|
152
157
|
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Usps
|
|
4
|
+
module Imis
|
|
5
|
+
module CommandLine
|
|
6
|
+
# Command line options parser config loading and processing
|
|
7
|
+
#
|
|
8
|
+
# @private
|
|
9
|
+
#
|
|
10
|
+
module OptionsParserConfig
|
|
11
|
+
def subcommands
|
|
12
|
+
@subcommands ||= yaml['Subcommands'].transform_values { it.transform_keys(&:to_sym) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def option_groups
|
|
16
|
+
@option_groups ||= yaml['Options'].transform_values { it.keys.map(&:to_sym) }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def options
|
|
20
|
+
@options ||= merged_options.transform_keys(&:to_sym).transform_values do |description, details|
|
|
21
|
+
[
|
|
22
|
+
description,
|
|
23
|
+
details.transform_keys(&:to_sym).each_with_object({}) do |(key, value), hash|
|
|
24
|
+
hash[key] = %i[type short].include?(key) ? value.to_sym : value
|
|
25
|
+
end
|
|
26
|
+
]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def legacy_aliases
|
|
31
|
+
@legacy_aliases ||= subcommands.each_with_object({}) do |(name, details), aliases|
|
|
32
|
+
next unless details[:legacy_name]
|
|
33
|
+
|
|
34
|
+
aliases["--#{details[:legacy_name]}"] = "--#{name}"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def legacy_flags
|
|
39
|
+
@legacy_flags ||= subcommands.to_h do |name, details|
|
|
40
|
+
flag_name = details[:legacy_name] || name.tr('-', '_')
|
|
41
|
+
option_key = name.tr('-', '_').to_sym
|
|
42
|
+
_, option_details = options[option_key]
|
|
43
|
+
|
|
44
|
+
display = option_flag_string(flag_name.to_sym, option_details || {})
|
|
45
|
+
replacement = ["imis #{name}".bold, details[:value] && "<#{details[:value]}>".gray].compact.join(' ')
|
|
46
|
+
|
|
47
|
+
[display, replacement]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def yaml
|
|
54
|
+
return @yaml if @yaml
|
|
55
|
+
|
|
56
|
+
raw_yaml_erb = File.read("#{File.dirname(__FILE__)}/options.yml.erb")
|
|
57
|
+
rendered_yaml = ERB.new(raw_yaml_erb).result.gsub("\x1b", '\u001b')
|
|
58
|
+
@yaml = YAML.safe_load(rendered_yaml)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def merged_options
|
|
62
|
+
subcommand_options = subcommands.transform_values { it[:option] }.transform_keys { it.gsub('-', '_') }
|
|
63
|
+
yaml['Options'].values.inject(:merge).merge(subcommand_options)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -13,7 +13,7 @@ module Usps
|
|
|
13
13
|
def perform!
|
|
14
14
|
case convert(options)
|
|
15
15
|
in mapper:, **extra then perform_mapper(mapper, **extra)
|
|
16
|
-
in
|
|
16
|
+
in object:, **extra then perform_object(object, **extra)
|
|
17
17
|
in panel:, **extra then perform_panel(panel, **extra)
|
|
18
18
|
in query:, **extra then perform_query(query, **extra)
|
|
19
19
|
in business_objects: true then api.business_objects
|
|
@@ -31,7 +31,7 @@ module Usps
|
|
|
31
31
|
case converted
|
|
32
32
|
in map: then converted.merge!(mapper: api.mapper, field: map)
|
|
33
33
|
in mapper: true then converted[:mapper] = api.mapper
|
|
34
|
-
in
|
|
34
|
+
in object: then converted[:object] = api.on(object)
|
|
35
35
|
in panel: then converted[:panel] = api.panels.public_send(panel)
|
|
36
36
|
else # Nothing to convert
|
|
37
37
|
end
|
|
@@ -50,16 +50,16 @@ module Usps
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
def
|
|
53
|
+
def perform_object(object, **options)
|
|
54
54
|
case options
|
|
55
|
-
in delete: true then
|
|
56
|
-
in create: true, data: then
|
|
57
|
-
in all: true then
|
|
58
|
-
in data:, field: then
|
|
59
|
-
in data: then
|
|
60
|
-
in fields: then
|
|
61
|
-
in field: then
|
|
62
|
-
else
|
|
55
|
+
in delete: true then object.delete
|
|
56
|
+
in create: true, data: then object.post(data)
|
|
57
|
+
in all: true then object.list
|
|
58
|
+
in data:, field: then object.put_field(field, data)
|
|
59
|
+
in data: then object.put_fields(data)
|
|
60
|
+
in fields: then object.get_fields(*fields)
|
|
61
|
+
in field: then object.get_field(field)
|
|
62
|
+
else object.get
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
|
data/lib/usps/imis/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: usps-imis-api
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Julian Fiander
|
|
@@ -95,9 +95,11 @@ files:
|
|
|
95
95
|
- lib/usps/imis/business_object.rb
|
|
96
96
|
- lib/usps/imis/command_line.rb
|
|
97
97
|
- lib/usps/imis/command_line/formatters.rb
|
|
98
|
+
- lib/usps/imis/command_line/help.rb
|
|
98
99
|
- lib/usps/imis/command_line/interface.rb
|
|
99
100
|
- lib/usps/imis/command_line/options.yml.erb
|
|
100
101
|
- lib/usps/imis/command_line/options_parser.rb
|
|
102
|
+
- lib/usps/imis/command_line/options_parser_config.rb
|
|
101
103
|
- lib/usps/imis/command_line/performers.rb
|
|
102
104
|
- lib/usps/imis/config.rb
|
|
103
105
|
- lib/usps/imis/data.rb
|