qb 0.3.25 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/ansible.cfg +10 -1
  4. data/exe/.qb_interop_receive +3 -10
  5. data/exe/qb +8 -2
  6. data/lib/python/qb/__init__.py +6 -0
  7. data/{roles/qb/ruby/rspec/setup/tasks/persistence.yml → lib/python/qb/ansible/__init__.py} +0 -0
  8. data/lib/python/qb/ansible/modules/__init__.py +0 -0
  9. data/lib/python/qb/ansible/modules/docker/__init__.py +0 -0
  10. data/lib/python/qb/ansible/modules/docker/client.py +177 -0
  11. data/lib/python/qb/ansible/modules/docker/image_manager.py +754 -0
  12. data/lib/python/qb/ipc/__init__.py +0 -0
  13. data/lib/python/qb/ipc/stdio/__init__.py +99 -0
  14. data/lib/python/qb/ipc/stdio/logging.py +151 -0
  15. data/lib/qb.rb +3 -3
  16. data/lib/qb/ansible/cmds/playbook.rb +5 -14
  17. data/lib/qb/ansible/env.rb +36 -6
  18. data/lib/qb/ansible/module.rb +396 -152
  19. data/lib/qb/ansible/module/response.rb +195 -0
  20. data/lib/qb/ansible/modules.rb +42 -0
  21. data/lib/qb/ansible/modules/docker/image.rb +273 -0
  22. data/lib/qb/cli.rb +5 -18
  23. data/lib/qb/cli/run.rb +2 -2
  24. data/lib/qb/data.rb +22 -0
  25. data/lib/qb/data/immutable.rb +39 -0
  26. data/lib/qb/docker.rb +2 -0
  27. data/lib/qb/docker/cli.rb +430 -0
  28. data/lib/qb/docker/image.rb +207 -0
  29. data/lib/qb/docker/image/name.rb +309 -0
  30. data/lib/qb/docker/image/tag.rb +113 -0
  31. data/lib/qb/docker/repo.rb +0 -0
  32. data/lib/qb/errors.rb +17 -3
  33. data/lib/qb/execution.rb +83 -0
  34. data/lib/qb/ipc.rb +48 -0
  35. data/lib/qb/ipc/stdio.rb +32 -0
  36. data/lib/qb/ipc/stdio/client.rb +267 -0
  37. data/lib/qb/ipc/stdio/server.rb +229 -0
  38. data/lib/qb/ipc/stdio/server/in_service.rb +18 -0
  39. data/lib/qb/ipc/stdio/server/log_service.rb +168 -0
  40. data/lib/qb/ipc/stdio/server/out_service.rb +20 -0
  41. data/lib/qb/ipc/stdio/server/service.rb +229 -0
  42. data/lib/qb/options.rb +360 -502
  43. data/lib/qb/options/option.rb +293 -115
  44. data/lib/qb/options/option/option_parser_concern.rb +228 -0
  45. data/lib/qb/options/types.rb +73 -0
  46. data/lib/qb/package.rb +0 -1
  47. data/lib/qb/package/version.rb +179 -58
  48. data/lib/qb/package/version/from.rb +192 -51
  49. data/lib/qb/package/version/leveled.rb +1 -1
  50. data/lib/qb/path.rb +3 -2
  51. data/lib/qb/repo/git.rb +9 -85
  52. data/lib/qb/role/default_dir.rb +2 -2
  53. data/lib/qb/role/errors.rb +2 -8
  54. data/lib/qb/util.rb +1 -2
  55. data/lib/qb/util/bundler.rb +73 -43
  56. data/lib/qb/util/decorators.rb +99 -0
  57. data/lib/qb/util/interop.rb +7 -8
  58. data/lib/qb/util/resource.rb +12 -13
  59. data/lib/qb/version.rb +10 -0
  60. data/library/path_facts +5 -10
  61. data/library/qb.module.rb +105 -0
  62. data/library/stream +6 -26
  63. data/load/ansible/module/autorun.rb +25 -0
  64. data/load/ansible/module/script.rb +123 -0
  65. data/load/rebundle.rb +39 -0
  66. data/plugins/filter/dict_filters.py +56 -0
  67. data/plugins/{filter_plugins/path_plugins.py → filter/path_filters.py} +0 -0
  68. data/plugins/{filter_plugins/ruby_interop_plugins.py → filter/ruby_interop_filters.py} +1 -17
  69. data/plugins/{filter_plugins/string_plugins.py → filter/string_filters.py} +1 -20
  70. data/plugins/{filter_plugins/version_plugins.py → filter/version_filters.py} +3 -18
  71. data/plugins/{lookup_plugins/every.py → lookup/every_lookups.py} +0 -0
  72. data/plugins/{lookup_plugins/resolve.py → lookup/resolve_lookups.py} +0 -0
  73. data/plugins/{lookup_plugins/version.py → lookup/version_lookups.py} +0 -16
  74. data/plugins/test/dict_tests.py +36 -0
  75. data/plugins/test/string_tests.py +36 -0
  76. data/qb.gemspec +7 -3
  77. data/roles/nrser.rb/library/set_fact_with_ruby.rb +3 -9
  78. data/roles/nrser.state_mate/library/state +3 -17
  79. data/roles/qb/call/meta/qb.yml +1 -1
  80. data/roles/qb/dev/ref/repo/git/meta/qb.yml +1 -1
  81. data/roles/qb/{ruby/rspec/setup → docker/mac/kubernetes}/defaults/main.yml +1 -1
  82. data/roles/qb/{ruby/rspec/setup → docker/mac/kubernetes}/meta/main.yml +3 -2
  83. data/roles/qb/{ruby/rspec/setup → docker/mac/kubernetes}/meta/qb.yml +12 -7
  84. data/roles/qb/docker/mac/kubernetes/tasks/main.yml +45 -0
  85. data/roles/qb/git/check/clean/meta/qb.yml +1 -1
  86. data/roles/qb/git/ignore/meta/qb +10 -3
  87. data/roles/qb/git/submodule/update/library/git_submodule_update +17 -27
  88. data/roles/qb/github/pages/setup/meta/qb.yml +1 -1
  89. data/roles/qb/labs/atom/apm/meta/qb.yml +1 -1
  90. data/roles/qb/osx/git/change_case/meta/qb.yml +1 -1
  91. data/roles/qb/osx/notif/meta/qb.yml +1 -1
  92. data/roles/qb/pkg/bump/library/bump +4 -16
  93. data/roles/qb/role/qb/defaults/main.yml +2 -0
  94. data/roles/qb/role/qb/meta/qb.yml +10 -5
  95. data/roles/qb/role/qb/templates/qb.yml.j2 +7 -2
  96. data/roles/qb/role/templates/library/module.rb.j2 +12 -23
  97. data/roles/qb/role/templates/meta/main.yml.j2 +14 -1
  98. data/roles/qb/ruby/bundler/meta/qb.yml +1 -1
  99. data/roles/qb/ruby/dependency/meta/qb.yml +1 -1
  100. data/roles/qb/ruby/gem/bin_stubs/meta/qb.yml +1 -1
  101. data/roles/qb/ruby/gem/bin_stubs/templates/console +8 -2
  102. data/roles/qb/ruby/gem/build/meta/qb.yml +1 -1
  103. data/roles/qb/ruby/gem/new/meta/qb.yml +1 -1
  104. data/roles/qb/ruby/nrser/rspex/generate/meta/qb.yml +5 -5
  105. data/roles/qb/ruby/nrser/rspex/issue/meta/qb.yml +1 -1
  106. data/roles/qb/ruby/yard/clean/meta/qb.yml +1 -1
  107. data/roles/qb/ruby/yard/config/library/yard.get_output_dir +5 -15
  108. data/roles/qb/ruby/yard/config/meta/qb.yml +1 -1
  109. data/roles/qb/ruby/yard/setup/meta/qb.yml +1 -1
  110. metadata +71 -22
  111. data/lib/qb/ansible_module.rb +0 -5
  112. data/lib/qb/util/stdio.rb +0 -187
  113. data/roles/qb/ruby/rspec/setup/tasks/main.yml +0 -4
@@ -1,131 +1,309 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # ========================================================================
6
+
7
+ # Deps
8
+ # ------------------------------------------------------------------------
9
+
10
+ # Need {Module#concerning}
11
+ require 'active_support/core_ext/module/concerning'
12
+
13
+ # Project / Package
14
+ # ------------------------------------------------------------------------
15
+
16
+ # Need additional {QB::Options::Types} for option type loading
17
+ require_relative './types'
18
+
19
+ # Need {OptionParserConcern} to handle fucking {OptionParser} :(
20
+ require_relative './option/option_parser_concern'
21
+
22
+
23
+ # Refinements
24
+ # ========================================================================
25
+
26
+ require 'nrser/refinements/types'
27
+ using NRSER::Types
28
+
29
+ require 'nrser/refinements/sugar'
30
+ using NRSER::Sugar
31
+
32
+
33
+ # Definitions
34
+ # ========================================================================
35
+
1
36
  module QB
2
- class Options
3
- class Option
4
- EXAMPLES_KEYS = ['examples', 'example']
37
+ class Options
38
+ class Option
39
+
40
+ # Constants
41
+ # ========================================================================
42
+
43
+ EXAMPLES_KEYS = ['examples', 'example']
44
+
45
+
46
+ # Mixins
47
+ # ============================================================================
48
+
49
+ include NRSER::Log::Mixin
50
+
51
+ include OptionParserConcern
52
+
53
+
54
+ # Attributes
55
+ # ========================================================================
56
+
57
+ # the role that this option is for
58
+ attr_reader :role
59
+
60
+ # array of strings representing how this option was included
61
+ # empty for top-level options
62
+ attr_reader :include_path
63
+
64
+ # the name of the option in the qb metadata, equal to #meta['name']
65
+ attr_reader :meta_name
66
+
67
+ # the name that this option will be available in the cli as
68
+ attr_reader :cli_name
69
+
70
+ # the name that the value will be passed to ansible as
71
+ attr_reader :var_name
72
+
73
+ # the value of the option, or `nil` if we never assign one
74
+ attr_accessor :value
75
+
76
+
77
+ # TODO document `type` attribute.
78
+ #
79
+ # @return [attr_type]
80
+ #
81
+ attr_reader :type
82
+
83
+
84
+ # Construction
85
+ # ======================================================================
86
+
87
+ def initialize role, meta, include_path
88
+ @role = role
89
+ @meta = meta.with_indifferent_access
90
+ @include_path = include_path
91
+
92
+ @meta_name = meta.fetch 'name'
93
+
94
+ @cli_name = if @include_path.empty?
95
+ QB::Options.cli_ize_name @meta_name
96
+ else
97
+ QB::Options.cli_ize_name "#{ @include_path.join('-') }-#{ @meta_name }"
98
+ end
99
+
100
+ @var_name = if meta[:var_name]
101
+ # prefer an explicit, exact variable name if provided
102
+ meta[:var_name]
103
+ elsif role.var_prefix
104
+ QB::Options.var_ize_name "#{ role.var_prefix }_#{ meta_name }"
105
+ else
106
+ QB::Options.var_ize_name meta_name
107
+ end
108
+
109
+ # Will be set when we find it out!
110
+ @value = nil
111
+
112
+ # Initialize `@type` var
113
+ init_type!
114
+ end
115
+
116
+
117
+ protected
118
+ # ========================================================================
119
+
120
+ # Initialize `@type` to the {NRSER::Types::Type} loaded from the option
121
+ # meta's `type` value.
122
+ #
123
+ # @protected
124
+ #
125
+ # @return [nil]
126
+ #
127
+ def init_type!
128
+ type_meta = meta[:type]
5
129
 
6
- # the role that this option is for
7
- # attr_reader :role
8
-
9
- # the entry from the qb metadata for this option
10
- attr_reader :meta
11
-
12
- # array of strings representing how this option was included
13
- # empty for top-level options
14
- attr_reader :include_path
15
-
16
- # the name of the option in the qb metadata, equal to #meta['name']
17
- attr_reader :meta_name
18
-
19
- # the name that this option will be available in the cli as
20
- attr_reader :cli_name
21
-
22
- # the name that the value will be passed to ansible as
23
- attr_reader :var_name
24
-
25
- # the value of the option, or `nil` if we never assign one
26
- attr_accessor :value
130
+ if type_meta.nil?
131
+ raise QB::Role::MetadataError.new \
132
+ "Option", meta_name, "for role", role.name, "missing `type`",
133
+ role_meta_path: role.meta_path,
134
+ option_meta: meta
135
+ end
27
136
 
28
- def initialize role, meta, include_path
29
- # @role = WeakRef.new role
30
- @meta = meta
31
- @include_path = include_path
137
+ if t.non_empty_str === type_meta &&
138
+ type_meta.include?( '::' )
32
139
 
33
- @meta_name = meta.fetch 'name'
140
+ const = type_meta.safe_constantize
34
141
 
35
- @cli_name = if @include_path.empty?
36
- Options.cli_ize_name @meta_name
37
- else
38
- Options.cli_ize_name "#{ @include_path.join('-') }-#{ @meta_name }"
142
+ if const &&
143
+ const.is_a?( Class ) &&
144
+ ( const < NRSER::Types::Type ||
145
+ const < NRSER::Props )
146
+ @type = const
147
+ return
39
148
  end
40
149
 
41
- @var_name = if @meta['var_name']
42
- # prefer an explicit, exact variable name if provided
43
- @meta['var_name']
44
- elsif role.var_prefix
45
- Options.var_ize_name "#{ role.var_prefix }_#{ @meta_name }"
46
- else
47
- Options.var_ize_name @meta_name
48
- end
49
-
50
- @value = nil
51
- end
52
-
53
- # if the option is required in the cli
54
- def required?
55
- !!meta_or(['required', 'require'], false)
56
150
  end
57
151
 
58
- # if we should save the option value in .qb-options.yml
59
- def save?
60
- !!meta_or('save', true)
61
- end
62
-
63
- def description
64
- value = meta_or 'description',
65
- "set the #{ @var_name } role variable"
152
+ message = t.match type_meta,
153
+ t.non_empty_str, ->( str ) {
154
+ NRSER::Message.new str
155
+ },
66
156
 
67
- line_break = "\n" + "\t" * 5
157
+ t.pair( value: (t.hash_ | t.array) ), ->( hash_pair ) {
158
+ name, params = hash_pair.first
68
159
 
69
- if @meta['type'].is_a?(Hash) && @meta['type'].key?('one_of')
70
- value += " options:" +
71
- "#{ line_break }#{ @meta['type']['one_of'].join(line_break) }"
72
- end
73
-
74
- value
75
- end
76
-
77
- def boolean?
78
- (
79
- meta['type'].is_a?(String) &&
80
- ['boolean', 'bool'].include?(meta['type'].downcase)
81
- )
82
- end
83
-
84
- def usage
85
- if boolean?
86
- "--[no-]#{ cli_name }"
87
- else
88
- "--#{ cli_name }=#{ meta_name.upcase }"
89
- end
90
- end
91
-
92
- # test if the option has any examples.
93
- #
94
- # @return [Boolean]
95
- #
96
- def has_examples?
97
- EXAMPLES_KEYS.any? {|key| meta.key? key}
98
- end
99
-
100
- # get an array of examples for the option. returns `[]` if no examples
101
- # are defined.
102
- #
103
- # @return [Array<String>]
104
- #
105
- def examples
106
- value = meta_or EXAMPLES_KEYS, []
107
-
108
- if value.is_a? String then [value] else value end
109
- end
160
+ NRSER::Message.from( name, params ).symbolize_options
161
+ }
110
162
 
111
-
112
- private
113
-
114
- # get the value at the first found of the keys or the default.
115
- #
116
- # `nil` (`null` in yaml files) are treated like they're not there at
117
- # all. you need to use `false` if you want to tell QB not to do something.
118
- #
119
- def meta_or keys, default
120
- keys = [keys] if keys.is_a? String
121
- keys.each do |key|
122
- if meta.key?(key) && !meta[key].nil?
123
- return meta[key]
163
+ @type = [
164
+ QB::Options::Types,
165
+ t,
166
+ ].find_map { |mod|
167
+ if mod.respond_to? message.symbol
168
+ begin
169
+ type = message.send_to mod
170
+ rescue Exception => error
171
+ logger.warn "Type factory failed",
172
+ { message: message },
173
+ error
174
+
175
+ nil
176
+ else
177
+ type if type.is_a?( t::Type )
124
178
  end
125
179
  end
126
- default
180
+ }
181
+
182
+ if @type.nil?
183
+ raise QB::Role::MetadataError.new \
184
+ "Unable to find type factory for", type_meta,
185
+ role_meta_path: role.meta_path,
186
+ option_meta: meta,
187
+ message: message
127
188
  end
128
189
 
129
- end # Option
130
- end # Options
131
- end # QB
190
+ end # #init_type!
191
+
192
+ public # end protected *****************************************************
193
+
194
+
195
+ # Instance Methods
196
+ # ========================================================================
197
+
198
+ def meta *keys, type: t.any, default: nil
199
+ return @meta if keys.empty?
200
+
201
+ keys.each do |key|
202
+ return type.check!( @meta[key] ) unless @meta[key].nil?
203
+ end
204
+
205
+ type.check! default
206
+ end
207
+
208
+
209
+ def meta? *keys
210
+ keys.any? { |key| @meta.key? key }
211
+ end
212
+
213
+
214
+ def value_data
215
+ if value.respond_to? :to_data
216
+ value.to_data
217
+ else
218
+ value
219
+ end
220
+ end
221
+
222
+
223
+ # Is the option is required in the CLI?
224
+ #
225
+ # @return [Boolean]
226
+ #
227
+ def required?
228
+ meta :required, :require, type: t.bool, default: false
229
+ end
230
+
231
+
232
+ # Should we save the option value in `./.qb-options.yml`?
233
+ #
234
+ # @return [Boolean]
235
+ #
236
+ def save?
237
+ meta :save, type: t.bool, default: true
238
+ end
239
+
240
+
241
+ # Description of the option.
242
+ #
243
+ # @return [String]
244
+ #
245
+ def description
246
+ meta(
247
+ :description,
248
+ default: "Set the #{ @var_name } role variable"
249
+ ).to_s
250
+ end
251
+
252
+
253
+ def boolean?
254
+ type == t.bool
255
+ end
256
+
257
+
258
+ def usage
259
+ if boolean?
260
+ "--[no-]#{ cli_name }"
261
+ else
262
+ "--#{ cli_name }=#{ meta_name.upcase }"
263
+ end
264
+ end
265
+
266
+
267
+ # test if the option has any examples.
268
+ #
269
+ # @return [Boolean]
270
+ #
271
+ def has_examples?
272
+ meta? *EXAMPLES_KEYS
273
+ end
274
+
275
+ # get an array of examples for the option. returns `[]` if no examples
276
+ # are defined.
277
+ #
278
+ # @return [Array<String>]
279
+ #
280
+ def examples
281
+ Array meta( *EXAMPLES_KEYS, type: (t.nil | t.str | t.array( t.str )) )
282
+ end
283
+
284
+
285
+ # Does the option accept `false` as value?
286
+ #
287
+ # If it does, and is not a boolean option, we also accept a `--no-<name>`
288
+ # option format to set the value to `false`.
289
+ #
290
+ # This is useful to explicitly tell QB "no, I don't want this", since we
291
+ # treat `nil`/`null` as the same as absent, which will cause a
292
+ # default value to be used (if available).
293
+ #
294
+ # This feature does not apply to {#boolean?} options themselves, only options
295
+ # that accept other values (though this method will of course return `true`
296
+ # for {#boolean?} options, since they do accept `false`).
297
+ #
298
+ # @return [Boolean]
299
+ #
300
+ def accept_false?
301
+ return true if meta[:accept_false]
302
+
303
+ return false if type.is_a?( Class ) && type < NRSER::Props
304
+
305
+ type.test?( false )
306
+ end
307
+
308
+
309
+ end; end; end # class QB::Options::Option
@@ -0,0 +1,228 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Deps
8
+ # -----------------------------------------------------------------------
9
+
10
+ # Need {ActiveSupport::Concern} duh
11
+ require 'active_support/concern'
12
+
13
+
14
+ # Project / Package
15
+ # -----------------------------------------------------------------------
16
+
17
+ require 'qb/util'
18
+
19
+ # Refinements
20
+ # =======================================================================
21
+
22
+ require 'nrser/refinements/types'
23
+ using NRSER::Types
24
+
25
+ require 'nrser/refinements/sugar'
26
+ using NRSER::Sugar
27
+
28
+
29
+ # Definitions
30
+ # =======================================================================
31
+
32
+ module QB
33
+ class Options
34
+ class Option
35
+ module OptionParserConcern
36
+
37
+ extend ActiveSupport::Concern
38
+ extend ::MethodDecorators
39
+
40
+ include NRSER::Log::Mixin
41
+
42
+ class TypeAcceptable
43
+ def self.name
44
+ if self == TypeAcceptable
45
+ "TypeAcceptable"
46
+ else
47
+ "TypeAcceptable<#{ type }>"
48
+ end
49
+ end
50
+
51
+ singleton_class.send :alias_method, :to_s, :name
52
+ singleton_class.send :alias_method, :inspect, :name
53
+
54
+ def self.type
55
+ @type
56
+ end
57
+
58
+ def self.parse string
59
+ type.from_s string
60
+ end
61
+ end
62
+
63
+
64
+ def option_parser_spacer
65
+ ' '
66
+ end
67
+
68
+
69
+ def option_parser_type_acceptable
70
+ acceptable = Class.new TypeAcceptable
71
+ acceptable.instance_variable_set :@type, self.type
72
+ acceptable
73
+ end
74
+
75
+
76
+ def option_parser_value_name
77
+ meta_name.upcase
78
+ end
79
+
80
+
81
+ +QB::Util::Decorators::EnumFor
82
+ def option_parser_format_multiline string, &block
83
+ lines = string.lines.to_a
84
+
85
+ lines.map do |line|
86
+ yield case line
87
+ when "\n"
88
+ # Need a space for {OptionParser} to respect it
89
+ option_parser_spacer + line
90
+ when /\A\s*\-\ /
91
+ line.sub '-', '*'
92
+ else
93
+ line
94
+ end
95
+ end
96
+
97
+ yield option_parser_spacer if lines.length > 1
98
+ end
99
+
100
+
101
+ +QB::Util::Decorators::EnumFor
102
+ def option_parser_description &block
103
+ option_parser_format_multiline description, &block
104
+ end
105
+
106
+
107
+ +QB::Util::Decorators::EnumFor
108
+ def option_parser_bool_args included:, &block
109
+ # Don't use short names when included (for now)
110
+ if !included && meta[:short]
111
+ yield "-#{ meta[:short] }"
112
+ end
113
+
114
+ yield "--[no-]#{ cli_name }"
115
+ end
116
+
117
+
118
+ +QB::Util::Decorators::EnumFor
119
+ def option_parser_non_bool_args included:, &block
120
+ # don't use short names when included (for now)
121
+ if !included && meta[:short]
122
+ yield "-#{ meta[:short] } #{ option_parser_value_name }"
123
+ end
124
+
125
+ # We allow options to also accept
126
+ if accept_false?
127
+ yield "--[no-]#{ cli_name }=#{ option_parser_value_name }"
128
+ else
129
+ yield "--#{ cli_name }=#{ option_parser_value_name }"
130
+ end
131
+
132
+ yield option_parser_type_acceptable
133
+ end
134
+
135
+
136
+ +QB::Util::Decorators::EnumFor
137
+ def option_parser_default &block
138
+ ans_src_default = role.defaults[var_name]
139
+
140
+ # If we don't have shit in the role default Ansible source file, nothing
141
+ # to do here
142
+ return if ans_src_default.nil?
143
+
144
+ if boolean?
145
+ yield "DEFAULT: --#{ ans_src_default ? '' : 'no-' }#{ cli_name }"
146
+ else
147
+ # This is just the Ansible "source code", which is shitty and ugly
148
+ # for anything that's not a literal, but it at least gives you something
149
+ # to see
150
+ option_parser_format_multiline "DEFAULT: #{ ans_src_default }", &block
151
+ end
152
+ end
153
+
154
+
155
+ +QB::Util::Decorators::EnumFor
156
+ def option_parser_examples &block
157
+ return unless has_examples?
158
+
159
+ yield 'Examples:'
160
+
161
+ examples.each_with_index do |example, index|
162
+ lines = example.lines.to_a
163
+
164
+ yield ((index + 1).to_s + '.').ljust(4) + lines.first.chomp
165
+
166
+ lines[1..-1].each do |line|
167
+ yield " ".ljust(4) + line.chomp
168
+ end
169
+ end
170
+ end
171
+
172
+
173
+ +QB::Util::Decorators::EnumFor
174
+ def option_parser_type &block
175
+ option_parser_format_multiline "TYPE: #{ type }", &block
176
+ end
177
+
178
+
179
+ +QB::Util::Decorators::EnumFor
180
+ def option_parser_args included:, &block
181
+ if boolean?
182
+ option_parser_bool_args included: included, &block
183
+ else
184
+ option_parser_non_bool_args included: included, &block
185
+ end
186
+
187
+ option_parser_description &block
188
+
189
+ yield "REQUIRED." if required?
190
+
191
+ option_parser_type &block
192
+
193
+ option_parser_default &block
194
+
195
+ option_parser_examples &block
196
+
197
+ yield option_parser_spacer
198
+
199
+ end
200
+
201
+
202
+ def option_parser_add option_parser, included:
203
+ args = option_parser_args( included: included ).to_a
204
+
205
+ args.find do |arg|
206
+ if arg.is_a?( Class )
207
+ option_parser.accept( arg ) do |value|
208
+ arg.parse value
209
+ end
210
+
211
+ true
212
+ end
213
+ end
214
+
215
+ logger.trace "Adding option to {OptionParser}",
216
+ option_meta_name: meta_name,
217
+ args: args
218
+
219
+ option_parser.on( *args ) do |value|
220
+ logger.debug "Setting option value",
221
+ option_meta_name: meta_name,
222
+ value: value
223
+
224
+ self.value = value
225
+ end
226
+ end
227
+
228
+ end; end; end; end # module QB::Options::Option::OptionParserConcern