toys-core 0.14.7 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/toys/dsl/flag.rb CHANGED
@@ -120,7 +120,14 @@ module Toys
120
120
  # should be set. You may pass the handler as a Proc (or an object
121
121
  # responding to the `call` method) or you may pass a block.
122
122
  #
123
- # @param handler [Proc]
123
+ # You can also pass one of the special values `:set` or `:push` as the
124
+ # handler. The `:set` handler replaces the previous value (equivalent to
125
+ # `-> (val, _prev) { val }`.) The `:push` handler expects the previous
126
+ # value to be an array and pushes the given value onto it; it should be
127
+ # combined with setting the default value to `[]` and is intended for
128
+ # "multi-valued" flags.
129
+ #
130
+ # @param handler [Proc,:set,:push]
124
131
  # @param block [Proc]
125
132
  # @return [self]
126
133
  #
@@ -268,13 +275,36 @@ module Toys
268
275
  self
269
276
  end
270
277
 
278
+ ##
279
+ # Specify whether to add a method for this flag.
280
+ #
281
+ # Recognized values are true to force creation of a method, false to
282
+ # disable method creation, and nil for the default behavior. The default
283
+ # checks the name and adds a method if the name is a symbol representing
284
+ # a legal method name that starts with a letter and does not override any
285
+ # public method in the Ruby Object class or collide with any method
286
+ # directly defined in the tool class.
287
+ #
288
+ # @param value [true,false,nil]
289
+ #
290
+ def add_method(value)
291
+ @add_method =
292
+ if value.nil?
293
+ nil
294
+ elsif value
295
+ true
296
+ else
297
+ false
298
+ end
299
+ end
300
+
271
301
  ##
272
302
  # Called only from DSL::Tool
273
303
  #
274
304
  # @private
275
305
  #
276
306
  def initialize(flags, acceptor, default, handler, flag_completion, value_completion,
277
- report_collisions, group, desc, long_desc, display_name)
307
+ report_collisions, group, desc, long_desc, display_name, method_flag)
278
308
  @flags = flags
279
309
  @default = default
280
310
  @handler = handler
@@ -286,6 +316,7 @@ module Toys
286
316
  accept(acceptor)
287
317
  complete_flags(flag_completion, **{})
288
318
  complete_values(value_completion, **{})
319
+ add_method(method_flag)
289
320
  end
290
321
 
291
322
  ##
@@ -298,6 +329,13 @@ module Toys
298
329
  report_collisions: @report_collisions, group: @group,
299
330
  desc: @desc, long_desc: @long_desc, display_name: @display_name)
300
331
  end
332
+
333
+ ##
334
+ # @private
335
+ #
336
+ def _get_add_method
337
+ @add_method
338
+ end
301
339
  end
302
340
  end
303
341
  end
@@ -181,19 +181,29 @@ module Toys
181
181
  # arguments.) Defaults to the empty array.
182
182
  # @param display_name [String] A display name for this flag, used in help
183
183
  # text and error messages.
184
+ # @param add_method [true,false,nil] Whether to add a method for this
185
+ # flag. If omitted or set to nil, uses the default behavior, which
186
+ # adds the method if the key is a symbol representing a legal method
187
+ # name that starts with a letter and does not override any public
188
+ # method in the Ruby Object class or collide with any method directly
189
+ # defined in the tool class.
184
190
  # @param block [Proc] Configures the flag. See {Toys::DSL::Flag} for the
185
191
  # directives that can be called in this block.
186
192
  # @return [self]
187
193
  #
188
194
  def flag(key, *flags,
189
- accept: nil, default: nil, handler: nil, complete_flags: nil, complete_values: nil,
190
- report_collisions: true, desc: nil, long_desc: nil, display_name: nil,
195
+ accept: nil, default: nil, handler: nil,
196
+ complete_flags: nil, complete_values: nil,
197
+ report_collisions: true, desc: nil, long_desc: nil,
198
+ display_name: nil, add_method: nil,
191
199
  &block)
192
- flag_dsl = DSL::Flag.new(flags, accept, default, handler, complete_flags, complete_values,
193
- report_collisions, @flag_group, desc, long_desc, display_name)
200
+ flag_dsl = DSL::Flag.new(flags, accept, default, handler,
201
+ complete_flags, complete_values,
202
+ report_collisions, @flag_group, desc, long_desc,
203
+ display_name, add_method)
194
204
  flag_dsl.instance_exec(flag_dsl, &block) if block
195
205
  flag_dsl._add_to(@tool, key)
196
- DSL::Internal.maybe_add_getter(@tool_dsl, key)
206
+ DSL::Internal.maybe_add_getter(@tool_dsl, key, flag_dsl._get_add_method)
197
207
  self
198
208
  end
199
209
 
@@ -8,6 +8,14 @@ module Toys
8
8
  # @private
9
9
  #
10
10
  module Internal
11
+ ##
12
+ # @private A list of method names to avoid using as getters
13
+ #
14
+ AVOID_GETTERS = (::Object.instance_methods + [:run, :initialize])
15
+ .find_all { |name| /^[a-z]\w*$/.match?(name) }
16
+ .map { |name| [name, true] }.to_h
17
+ .freeze
18
+
11
19
  class << self
12
20
  ##
13
21
  # Called by the Loader and InputFile to prepare a tool class for running
@@ -91,14 +99,21 @@ module Toys
91
99
  #
92
100
  # @private
93
101
  #
94
- def maybe_add_getter(tool_class, key)
95
- if key.is_a?(::Symbol) && key.to_s =~ /^[_a-zA-Z]\w*[!?]?$/ && key != :run
96
- unless tool_class.public_method_defined?(key)
97
- tool_class.class_eval do
98
- define_method(key) do
99
- self[key]
100
- end
101
- end
102
+ def maybe_add_getter(tool_class, key, force)
103
+ return unless key.is_a?(::Symbol)
104
+ case force
105
+ when false
106
+ return
107
+ when true
108
+ return unless /^[_a-zA-Z]\w*[!?]?$/.match(key.to_s)
109
+ when nil
110
+ return if !/^[a-zA-Z]\w*[!?]?$/.match?(key.to_s) ||
111
+ AVOID_GETTERS.key?(key) ||
112
+ Compat.method_defined_without_ancestors?(tool_class, key)
113
+ end
114
+ tool_class.class_eval do
115
+ define_method(key) do
116
+ self[key]
102
117
  end
103
118
  end
104
119
  end
@@ -141,18 +141,42 @@ module Toys
141
141
  self
142
142
  end
143
143
 
144
+ ##
145
+ # Specify whether to add a method for this argument.
146
+ #
147
+ # Recognized values are true to force creation of a method, false to
148
+ # disable method creation, and nil for the default behavior. The default
149
+ # checks the name and adds a method if the name is a symbol representing
150
+ # a legal method name that starts with a letter and does not override any
151
+ # public method in the Ruby Object class or collide with any method
152
+ # directly defined in the tool class.
153
+ #
154
+ # @param value [true,false,nil]
155
+ #
156
+ def add_method(value)
157
+ @add_method =
158
+ if value.nil?
159
+ nil
160
+ elsif value
161
+ true
162
+ else
163
+ false
164
+ end
165
+ end
166
+
144
167
  ##
145
168
  # Called only from DSL::Tool
146
169
  #
147
170
  # @private
148
171
  #
149
- def initialize(acceptor, default, completion, display_name, desc, long_desc)
172
+ def initialize(acceptor, default, completion, display_name, desc, long_desc, method_flag)
150
173
  @default = default
151
174
  @display_name = display_name
152
175
  @desc = desc
153
176
  @long_desc = long_desc || []
154
177
  accept(acceptor, **{})
155
178
  complete(completion, **{})
179
+ add_method(method_flag)
156
180
  end
157
181
 
158
182
  ##
@@ -181,6 +205,13 @@ module Toys
181
205
  accept: @acceptor, default: @default, complete: @completion,
182
206
  display_name: @display_name, desc: @desc, long_desc: @long_desc)
183
207
  end
208
+
209
+ ##
210
+ # @private
211
+ #
212
+ def _get_add_method
213
+ @add_method
214
+ end
184
215
  end
185
216
  end
186
217
  end