qb 0.3.25 → 0.4.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.
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