atli 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -129,94 +129,21 @@ module ClassMethods
129
129
  end
130
130
 
131
131
 
132
- # Adds an argument to the class and creates an attr_accessor for it.
133
- #
134
- # Arguments are different from options in several aspects. The first one
135
- # is how they are parsed from the command line, arguments are retrieved
136
- # from position:
137
- #
138
- # thor command NAME
139
- #
140
- # Instead of:
141
- #
142
- # thor command --name=NAME
143
- #
144
- # Besides, arguments are used inside your code as an accessor
145
- # (self.argument), while options are all kept in a hash (self.options).
146
- #
147
- # Finally, arguments cannot have type :default or :boolean but can be
148
- # optional (supplying :optional => :true or :required => false), although
149
- # you cannot have a required argument after a non-required argument. If
150
- # you try it, an error is raised.
151
- #
152
- # ==== Parameters
153
- # name<Symbol>:: The name of the argument.
154
- # options<Hash>:: Described below.
155
- #
156
- # ==== Options
157
- # :desc - Description for the argument.
158
- # :required - If the argument is required or not.
159
- # :optional - If the argument is optional or not.
160
- # :type - The type of the argument, can be :string, :hash, :array,
161
- # :numeric.
162
- # :default - Default value for this argument. It cannot be required and
163
- # have default values.
164
- # :banner - String to show on usage notes.
165
- #
166
- # ==== Errors
167
- # ArgumentError:: Raised if you supply a required argument after a non
168
- # required one.
169
- #
170
- def argument(name, options = {})
171
- is_thor_reserved_word?(name, :argument)
172
- no_commands { attr_accessor name }
173
-
174
- required = if options.key?(:optional)
175
- !options[:optional]
176
- elsif options.key?(:required)
177
- options[:required]
178
- else
179
- options[:default].nil?
180
- end
181
-
182
- remove_argument name
183
-
184
- if required
185
- arguments.each do |argument|
186
- next if argument.required?
187
- raise ArgumentError,
188
- "You cannot have #{name.to_s.inspect} as required argument " \
189
- "after the non-required argument #{argument.human_name.inspect}."
190
- end
191
- end
192
-
193
- options[:required] = required
194
-
195
- arguments << Thor::Argument.new(name, options)
196
- end
197
-
198
-
199
- # Returns this class arguments, looking up in the ancestors chain.
200
- #
201
- # ==== Returns
202
- # Array[Thor::Argument]
203
- #
204
- def arguments
205
- @arguments ||= from_superclass(:arguments, [])
206
- end
207
-
208
-
209
132
  # Adds a bunch of options to the set of class options.
210
133
  #
211
134
  # class_options :foo => false, :bar => :required, :baz => :string
212
135
  #
213
136
  # If you prefer more detailed declaration, check class_option.
214
137
  #
215
- # ==== Parameters
216
- # Hash[Symbol => Object]
138
+ # @param [Hash<(String | Symbol), Object>] options
139
+ # New option definitions to add via {#build_options}.
140
+ #
141
+ # @return [HashWithIndifferentAccess<String, Thor::Option>]
142
+ # Hash of option names to the option instances.
217
143
  #
218
- def class_options(options = nil)
219
- @class_options ||= from_superclass(:class_options, {})
144
+ def class_options options = nil
145
+ @class_options ||= \
146
+ from_superclass( :class_options, HashWithIndifferentAccess.new )
220
147
  build_options(options, @class_options) if options
221
148
  @class_options
222
149
  end
@@ -248,27 +175,6 @@ module ClassMethods
248
175
  end
249
176
 
250
177
 
251
- # Removes a previous defined argument. If :undefine is given, undefine
252
- # accessors as well.
253
- #
254
- # ==== Parameters
255
- # names<Array>:: Arguments to be removed
256
- #
257
- # ==== Examples
258
- #
259
- # remove_argument :foo
260
- # remove_argument :foo, :bar, :baz, :undefine => true
261
- #
262
- def remove_argument(*names)
263
- options = names.last.is_a?(Hash) ? names.pop : {}
264
-
265
- names.each do |name|
266
- arguments.delete_if { |a| a.name == name.to_s }
267
- undef_method name, "#{name}=" if options[:undefine]
268
- end
269
- end
270
-
271
-
272
178
  # Removes a previous defined class option.
273
179
  #
274
180
  # ==== Parameters
@@ -304,25 +210,24 @@ module ClassMethods
304
210
 
305
211
  # Returns the commands for this Thor class.
306
212
  #
307
- # ==== Returns
308
- # OrderedHash:: An ordered hash with commands names as keys and
309
- # Thor::Command objects as values.
213
+ # @return [HashWithIndifferentAccess<String, Thor::Command>]
214
+ # An hash with commands names as keys and Thor::Command objects as values.
310
215
  #
311
216
  def commands
312
- @commands ||= Thor::CoreExt::OrderedHash.new
217
+ @commands ||= HashWithIndifferentAccess.new
313
218
  end
314
219
  alias_method :tasks, :commands
315
220
 
316
221
 
317
222
  # Returns the commands for this Thor class and all subclasses.
318
223
  #
319
- # ==== Returns
320
- # OrderedHash:: An ordered hash with commands names as keys and
321
- # Thor::Command objects as values.
224
+ # @return [HashWithIndifferentAccess<String, Thor::Command>]
225
+ # An hash with commands names as keys and {Thor::Command}
226
+ # objects as values.
322
227
  #
323
228
  def all_commands
324
229
  @all_commands ||= from_superclass( :all_commands,
325
- Thor::CoreExt::OrderedHash.new )
230
+ HashWithIndifferentAccess.new )
326
231
  @all_commands.merge!(commands)
327
232
  end
328
233
  alias_method :all_tasks, :all_commands
@@ -451,13 +356,12 @@ module ClassMethods
451
356
  # For details on why this is here see
452
357
  # {file:doc/files/notes/too-broken-to-fail.md Too Broken to Fail}.
453
358
  #
454
- def exec!(given_args = ARGV, config = {})
359
+ def exec! given_args = ARGV, config = {}
455
360
  execution = Thor::Execution.new thor_class: self,
456
361
  given_args: given_args,
457
362
  thor_config: config
458
-
459
363
  execution.exec!
460
- end # #start
364
+ end # #exec!
461
365
 
462
366
 
463
367
  # Allows to use private methods from parent in child classes as commands.
@@ -485,7 +389,7 @@ module ClassMethods
485
389
  "#{namespace.inspect} namespace."
486
390
  end
487
391
  raise Thor::UndefinedCommandError,
488
- "Could not find command #{command.inspect}."
392
+ "Could not find command #{command.inspect}, commands: #{ all_commands.keys }"
489
393
  end
490
394
  alias_method :handle_no_task_error, :handle_no_command_error
491
395
 
@@ -599,11 +503,12 @@ module ClassMethods
599
503
  # name<Symbol>:: The name of the argument.
600
504
  # options<Hash>:: Described in both class_option and method_option.
601
505
  # scope<Hash>:: Options hash that is being built up
602
- def build_option(name, options, scope) #:nodoc:
603
- scope[name] = Thor::Option.new(
506
+ def build_option(name, options, scope)
507
+ option = Thor::Option.new(
604
508
  name,
605
509
  options.merge(:check_default_type => check_default_type?)
606
510
  )
511
+ scope[option.name] = option
607
512
  end
608
513
 
609
514
 
@@ -612,11 +517,17 @@ module ClassMethods
612
517
  #
613
518
  # build_options :foo => true, :bar => :required, :baz => :string
614
519
  #
615
- # ==== Parameters
616
- # Hash[Symbol => Object]
617
- def build_options(options, scope) #:nodoc:
520
+ # @param [Hash<(String | Symbol), Object>] options
521
+ #
522
+ # @param [HashWithIndifferentAccess<String, Thor::Option>] scope
523
+ #
524
+ # @return [nil]
525
+ # New {Thor::Option} are added to `scope`.
526
+ #
527
+ def build_options options, scope
618
528
  options.each do |key, value|
619
- scope[key] = Thor::Option.parse(key, value)
529
+ option = Thor::Option.parse key, value
530
+ scope[option.name] = option
620
531
  end
621
532
  end
622
533
 
@@ -0,0 +1,123 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ # Requirements
5
+ # =======================================================================
6
+
7
+ # Deps
8
+ # -----------------------------------------------------------------------
9
+
10
+ require 'active_support/concern'
11
+
12
+
13
+ # Refinements
14
+ # =======================================================================
15
+
16
+ require 'nrser/refinements/types'
17
+ using NRSER::Types
18
+
19
+ # Namespace
20
+ # =======================================================================
21
+
22
+ class Thor
23
+ module Base
24
+
25
+ # Definitions
26
+ # =======================================================================
27
+
28
+ # Share stuff... define {Thor::Argument}, {Thor::Option} and whatever else
29
+ # you like once then apply those definitions to many commands.
30
+ #
31
+ module SharedConcern
32
+
33
+ extend ActiveSupport::Concern
34
+
35
+ class_methods do
36
+ # ==========================================================================
37
+
38
+ def shared_defs
39
+ @shared_defs ||= []
40
+ end
41
+
42
+
43
+ # def normalize_kind input
44
+ # {
45
+ # 'arg' => 'argument',
46
+
47
+ # }
48
+ # end
49
+
50
+
51
+ def def_shared kind, name:, groups: nil, **options
52
+ shared_defs << {
53
+ name: name.to_s,
54
+ kind: kind,
55
+ groups: Set[*groups],
56
+ options: options,
57
+ }
58
+ end
59
+
60
+
61
+ def include_shared *names, kinds: nil, groups: nil, **overrides
62
+ find_shared( *names, kinds: kinds, groups: groups ).
63
+ each do |name:, kind:, groups:, options:|
64
+ send kind, name, **options.merge( overrides )
65
+ end
66
+ end
67
+
68
+
69
+ # Find shared options given names and groups.
70
+ #
71
+ # @param [*<Symbol>] names
72
+ # Individual shared option names to include.
73
+ #
74
+ # @param [nil | Symbol | Enumerable<Symbol>] groups:
75
+ # Single or list of shared option groups to include.
76
+ #
77
+ # @return [Hash<Symbol, Thor::SharedOption>]
78
+ # Hash mapping option names (as {Symbol}) to instances.
79
+ #
80
+ def find_shared *names, kinds: nil, groups: nil
81
+ groups_set = Set[*groups]
82
+ kinds_set = Set[*kinds]
83
+ names.map! &:to_s
84
+
85
+ results = []
86
+
87
+ shared_defs.each do |name:, kind:, groups:, options:|
88
+ match = {}
89
+
90
+ if names.include? name
91
+ match[:name] = true
92
+ end
93
+
94
+ match_groups = groups & groups_set
95
+
96
+ unless match_groups.empty?
97
+ match[:groups] = match_groups
98
+ end
99
+
100
+ if kinds_set.include? kind
101
+ match[:kind] = true
102
+ end
103
+
104
+ unless match.empty?
105
+ results << {
106
+ name: name,
107
+ kind: kind,
108
+ groups: groups,
109
+ options: options,
110
+ }
111
+ end
112
+ end
113
+ end # #find_shared
114
+
115
+ end # class_methods ********************************************************
116
+
117
+ end # module SharedConcern
118
+
119
+ # /Namespace
120
+ # =======================================================================
121
+
122
+ end # module Base
123
+ end # class Thor
@@ -0,0 +1,235 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+
5
+ # Requirements
6
+ # =======================================================================
7
+
8
+ # Deps
9
+ # -----------------------------------------------------------------------
10
+
11
+ require 'active_support/concern'
12
+
13
+
14
+ # Refinements
15
+ # =======================================================================
16
+
17
+ require 'nrser/refinements/types'
18
+ using NRSER::Types
19
+
20
+ # Namespace
21
+ # =======================================================================
22
+
23
+ class Thor
24
+ module Base
25
+
26
+
27
+ # Definitions
28
+ # =======================================================================
29
+
30
+ # Support for sharing {Thor::Option} declarations among many
31
+ # {Thor::Command} (methods). All class methods.
32
+ #
33
+ module SharedOptionsConcern
34
+
35
+ # Mixins
36
+ # ========================================================================
37
+
38
+ # Get concerned
39
+ extend ActiveSupport::Concern
40
+
41
+
42
+ class_methods do
43
+ # ==========================================================================
44
+
45
+ # Declare a shared method option with an optional groups that can then
46
+ # be added by name or group to commands.
47
+ #
48
+ # The shared options can then be added to methods individually by name and
49
+ # collectively as groups with {Thor.include_method_options}.
50
+ #
51
+ # @example
52
+ # class MyCLI < Thor
53
+ #
54
+ # # Declare a shared option:
55
+ # shared_option :force,
56
+ # groups: :write,
57
+ # desc: "Force the operation",
58
+ # type: :boolean
59
+ #
60
+ # # ...
61
+ #
62
+ # desc "write [OPTIONS] path",
63
+ # "Write to a path"
64
+ #
65
+ # # Add the shared options to the method:
66
+ # include_options groups: :write
67
+ #
68
+ # def write path
69
+ #
70
+ # # Get a slice of `#options` with any of the `:write` group options
71
+ # # that were provided and use it in a method call:
72
+ # MyModule.write path, **option_kwds( groups: :write )
73
+ #
74
+ # end
75
+ # end
76
+ #
77
+ # @param [Symbol] name
78
+ # The name of the option.
79
+ #
80
+ # @param [**<Symbol, V>] options
81
+ # Keyword args used to initialize the {Thor::SharedOption}.
82
+ #
83
+ # All +**options+ are optional.
84
+ #
85
+ # @option options [Symbol | Array<Symbol>] :groups
86
+ # One or more _shared_ _option_ _group_ that the new option will belong
87
+ # to.
88
+ #
89
+ # Examples:
90
+ # groups: :read
91
+ # groups: [:read, :write]
92
+ #
93
+ # *NOTE* The keyword is +groups+ with an +s+! {Thor::Option} already has
94
+ # a +group+ string attribute that, as far as I can tell, is only
95
+ #
96
+ # @option options [String] :desc
97
+ # Description for the option for help and feedback.
98
+ #
99
+ # @option options [Boolean] :required
100
+ # If the option is required or not.
101
+ #
102
+ # @option options [Object] :default
103
+ # Default value for this argument.
104
+ #
105
+ # It cannot be +required+ and have default values.
106
+ #
107
+ # @option options [String | Array<String>] :aliases
108
+ # Aliases for this option.
109
+ #
110
+ # Examples:
111
+ # aliases: '-s'
112
+ # aliases: '--other-name'
113
+ # aliases: ['-s', '--other-name']
114
+ #
115
+ # @option options [:string | :hash | :array | :numeric | :boolean] :type
116
+ # Type of acceptable values, see
117
+ # {types for method options}[https://github.com/erikhuda/thor/wiki/Method-Options#types-for-method_options]
118
+ # in the Thor wiki.
119
+ #
120
+ # @option options [String] :banner
121
+ # String to show on usage notes.
122
+ #
123
+ # @option options [Boolean] :hide
124
+ # If you want to hide this option from the help.
125
+ #
126
+ # @return (see .build_shared_option)
127
+ #
128
+ def shared_method_option name, **options
129
+ # Don't think the `:for` option makes sense... that would just be a
130
+ # regular method option, right? I guess `:for` could be an array and
131
+ # apply the option to each command, but it seems like that would just
132
+ # be better as an extension to the {.method_option} behavior.
133
+ #
134
+ # So, we raise if we see it
135
+ if options.key? :for
136
+ raise ArgumentError,
137
+ ".shared_method_option does not accept the `:for` option"
138
+ end
139
+
140
+ build_shared_option(name, options)
141
+ end # #shared_method_option
142
+
143
+ alias_method :shared_option, :shared_method_option
144
+
145
+
146
+ # @return [Hash<Symbol, Thor::SharedOption]
147
+ # Get all shared options
148
+ #
149
+ def shared_method_options(options = nil)
150
+ @shared_method_options ||= begin
151
+ # Reach up the inheritance chain, if there's anyone there
152
+ if superclass.respond_to? __method__
153
+ superclass.send( __method__ ).dup
154
+ else
155
+ # Or just default to empty
156
+ {}
157
+ end
158
+ end
159
+
160
+ if options
161
+ # We don't support this (yet at least)
162
+ raise NotImplementedError,
163
+ "Bulk set not supported, use .shared_method_option"
164
+ # build_shared_options(options, @shared_method_options)
165
+ end
166
+ @shared_method_options
167
+ end
168
+
169
+ alias_method :shared_options, :shared_method_options
170
+
171
+
172
+ # Find shared options given names and groups.
173
+ #
174
+ # @param [*<Symbol>] names
175
+ # Individual shared option names to include.
176
+ #
177
+ # @param [nil | Symbol | Enumerable<Symbol>] groups:
178
+ # Single or list of shared option groups to include.
179
+ #
180
+ # @return [Hash<Symbol, Thor::SharedOption>]
181
+ # Hash mapping option names (as {Symbol}) to instances.
182
+ #
183
+ def find_shared_method_options *names, groups: nil
184
+ groups_set = Set[*groups]
185
+
186
+ shared_method_options.each_with_object( {} ) do |(name, option), results|
187
+ match = {}
188
+
189
+ if names.include? name
190
+ match[:name] = true
191
+ end
192
+
193
+ match_groups = option.groups & groups_set
194
+
195
+ unless match_groups.empty?
196
+ match[:groups] = match_groups
197
+ end
198
+
199
+ unless match.empty?
200
+ results[name] = {
201
+ option: option,
202
+ match: match,
203
+ }
204
+ end
205
+ end
206
+ end # #find_shared_method_options
207
+
208
+ alias_method :find_shared_options, :find_shared_method_options
209
+
210
+
211
+ # Add the {Thor::SharedOption} instances with +names+ and in +groups+ to
212
+ # the next defined command method.
213
+ #
214
+ # @param (see .find_shared_method_options)
215
+ # @return (see .find_shared_method_options)
216
+ #
217
+ def include_method_options *names, groups: nil
218
+ find_shared_method_options( *names, groups: groups ).
219
+ each do |name, result|
220
+ method_options[name] = Thor::IncludedOption.new **result
221
+ end
222
+ end
223
+
224
+ alias_method :include_options, :include_method_options
225
+
226
+ end # class_methods ********************************************************
227
+
228
+ end # module SharedOptionsConcern
229
+
230
+
231
+ # /Namespace
232
+ # =======================================================================
233
+
234
+ end # module Base
235
+ end # class Thor