atli 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -2
- data/atli.gemspec +34 -3
- data/lib/thor.rb +202 -204
- data/lib/thor/base.rb +247 -185
- data/lib/thor/base/common_class_options.rb +56 -0
- data/lib/thor/command.rb +9 -1
- data/lib/thor/error.rb +16 -0
- data/lib/thor/execution.rb +276 -0
- data/lib/thor/version.rb +11 -2
- metadata +35 -5
data/lib/thor/base.rb
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# Requirements
|
2
|
+
# =======================================================================
|
3
|
+
|
4
|
+
# Stdlib
|
5
|
+
# -----------------------------------------------------------------------
|
6
|
+
|
7
|
+
# Deps
|
8
|
+
# -----------------------------------------------------------------------
|
9
|
+
require 'nrser'
|
10
|
+
|
11
|
+
# Project / Package
|
12
|
+
# -----------------------------------------------------------------------
|
1
13
|
require "thor/command"
|
2
14
|
require "thor/core_ext/hash_with_indifferent_access"
|
3
15
|
require "thor/core_ext/ordered_hash"
|
@@ -7,6 +19,16 @@ require "thor/parser"
|
|
7
19
|
require "thor/shell"
|
8
20
|
require "thor/line_editor"
|
9
21
|
require "thor/util"
|
22
|
+
require 'thor/execution'
|
23
|
+
require 'thor/base/common_class_options'
|
24
|
+
|
25
|
+
|
26
|
+
# Refinements
|
27
|
+
# =======================================================================
|
28
|
+
|
29
|
+
using NRSER
|
30
|
+
using NRSER::Types
|
31
|
+
|
10
32
|
|
11
33
|
class Thor
|
12
34
|
autoload :Actions, "thor/actions"
|
@@ -148,47 +170,69 @@ class Thor
|
|
148
170
|
|
149
171
|
# end protected
|
150
172
|
|
173
|
+
|
174
|
+
# Module Methods
|
175
|
+
# ============================================================================
|
176
|
+
|
177
|
+
# Hook called when {Thor::Base} is mixed in ({Thor} and {Thor::Group}).
|
178
|
+
#
|
179
|
+
# Extends `base` with {Thor::Base::ClassMethods}, and includes
|
180
|
+
# {Thor::Invocation} and {Thor::Shell} in `base` as well.
|
181
|
+
#
|
182
|
+
# @param [Module] base
|
183
|
+
# Module (or Class) that included {Thor::Base}.
|
184
|
+
#
|
185
|
+
# @return [void]
|
186
|
+
#
|
187
|
+
def self.included base
|
188
|
+
base.extend ClassMethods
|
189
|
+
base.send :include, Invocation
|
190
|
+
base.send :include, Shell
|
191
|
+
|
192
|
+
base.no_commands {
|
193
|
+
base.send :include, SemanticLogger::Loggable
|
194
|
+
}
|
195
|
+
|
196
|
+
end
|
151
197
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
198
|
+
# Returns the classes that inherits from Thor or Thor::Group.
|
199
|
+
#
|
200
|
+
# ==== Returns
|
201
|
+
# Array[Class]
|
202
|
+
#
|
203
|
+
def self.subclasses
|
204
|
+
@subclasses ||= []
|
205
|
+
end
|
158
206
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
207
|
+
# Returns the files where the subclasses are kept.
|
208
|
+
#
|
209
|
+
# ==== Returns
|
210
|
+
# Hash[path<String> => Class]
|
211
|
+
#
|
212
|
+
def self.subclass_files
|
213
|
+
@subclass_files ||= Hash.new { |h, k| h[k] = [] }
|
214
|
+
end
|
167
215
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
216
|
+
# Whenever a class inherits from Thor or Thor::Group, we should track the
|
217
|
+
# class and the file on Thor::Base. This is the method responsible for it.
|
218
|
+
#
|
219
|
+
def self.register_klass_file(klass) #:nodoc:
|
220
|
+
file = caller[1].match(/(.*):\d+/)[1]
|
221
|
+
unless Thor::Base.subclasses.include?(klass)
|
222
|
+
Thor::Base.subclasses << klass
|
175
223
|
end
|
176
224
|
|
177
|
-
|
178
|
-
|
179
|
-
#
|
180
|
-
def register_klass_file(klass) #:nodoc:
|
181
|
-
file = caller[1].match(/(.*):\d+/)[1]
|
182
|
-
unless Thor::Base.subclasses.include?(klass)
|
183
|
-
Thor::Base.subclasses << klass
|
184
|
-
end
|
185
|
-
|
186
|
-
file_subclasses = Thor::Base.subclass_files[File.expand_path(file)]
|
187
|
-
file_subclasses << klass unless file_subclasses.include?(klass)
|
188
|
-
end
|
225
|
+
file_subclasses = Thor::Base.subclass_files[File.expand_path(file)]
|
226
|
+
file_subclasses << klass unless file_subclasses.include?(klass)
|
189
227
|
end
|
190
|
-
|
228
|
+
|
229
|
+
|
230
|
+
# Methods that are mixed in as module/class/singleton methods to modules
|
231
|
+
# that include {Thor::Base}.
|
232
|
+
#
|
191
233
|
module ClassMethods
|
234
|
+
include Thor::Base::CommonClassOptions
|
235
|
+
|
192
236
|
def attr_reader(*) #:nodoc:
|
193
237
|
no_commands { super }
|
194
238
|
end
|
@@ -528,7 +572,7 @@ class Thor
|
|
528
572
|
@namespace ||= Thor::Util.namespace_from_thor_class(self)
|
529
573
|
end
|
530
574
|
end
|
531
|
-
|
575
|
+
|
532
576
|
# Parses the command and options from the given args, instantiate the class
|
533
577
|
# and invoke the command. This method is used when the arguments must be parsed
|
534
578
|
# from an array. If you are inside Ruby and want to use a Thor class, you
|
@@ -541,11 +585,11 @@ class Thor
|
|
541
585
|
config[:shell] ||= Thor::Base.shell.new
|
542
586
|
dispatch(nil, given_args.dup, nil, config)
|
543
587
|
rescue Thor::Error => e
|
544
|
-
config[:debug] ||
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
588
|
+
if config[:debug] || ENV["THOR_DEBUG"] == "1"
|
589
|
+
raise e
|
590
|
+
else
|
591
|
+
config[:shell].error(e.message)
|
592
|
+
end
|
549
593
|
exit(1) if exit_on_failure?
|
550
594
|
rescue Errno::EPIPE
|
551
595
|
# This happens if a thor command is piped to something like `head`,
|
@@ -554,6 +598,22 @@ class Thor
|
|
554
598
|
# computation will not occur.
|
555
599
|
exit(0)
|
556
600
|
end
|
601
|
+
|
602
|
+
|
603
|
+
# Like {#start}, but explicitly for handling over control in an
|
604
|
+
# executable.
|
605
|
+
#
|
606
|
+
# For details on why this is here see
|
607
|
+
# {file:doc/files/notes/too-broken-to-fail.md Too Broken to Fail}.
|
608
|
+
#
|
609
|
+
def exec!(given_args = ARGV, config = {})
|
610
|
+
execution = Thor::Execution.new thor_class: self,
|
611
|
+
given_args: given_args,
|
612
|
+
thor_config: config
|
613
|
+
|
614
|
+
execution.exec!
|
615
|
+
end # #start
|
616
|
+
|
557
617
|
|
558
618
|
# Allows to use private methods from parent in child classes as commands.
|
559
619
|
#
|
@@ -592,182 +652,184 @@ class Thor
|
|
592
652
|
raise InvocationError, msg
|
593
653
|
end
|
594
654
|
|
595
|
-
|
655
|
+
protected
|
656
|
+
# ============================================================================
|
596
657
|
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
658
|
+
# Prints the class options per group. If an option does not belong to
|
659
|
+
# any group, it's printed as Class option.
|
660
|
+
#
|
661
|
+
def class_options_help(shell, groups = {}) #:nodoc:
|
662
|
+
# Group options by group
|
663
|
+
class_options.each do |_, value|
|
664
|
+
groups[value.group] ||= []
|
665
|
+
groups[value.group] << value
|
666
|
+
end
|
606
667
|
|
607
|
-
|
608
|
-
|
609
|
-
|
668
|
+
# Deal with default group
|
669
|
+
global_options = groups.delete(nil) || []
|
670
|
+
print_options(shell, global_options)
|
610
671
|
|
611
|
-
|
612
|
-
|
613
|
-
|
672
|
+
# Print all others
|
673
|
+
groups.each do |group_name, options|
|
674
|
+
print_options(shell, options, group_name)
|
675
|
+
end
|
614
676
|
end
|
615
|
-
end
|
616
677
|
|
617
|
-
|
618
|
-
|
619
|
-
|
678
|
+
# Receives a set of options and print them.
|
679
|
+
def print_options(shell, options, group_name = nil)
|
680
|
+
return if options.empty?
|
620
681
|
|
621
|
-
|
622
|
-
|
682
|
+
list = []
|
683
|
+
padding = options.map { |o| o.aliases.size }.max.to_i * 4
|
623
684
|
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
685
|
+
options.each do |option|
|
686
|
+
next if option.hide
|
687
|
+
item = [option.usage(padding)]
|
688
|
+
item.push(option.description ? "# #{option.description}" : "")
|
628
689
|
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
690
|
+
list << item
|
691
|
+
list << ["", "# Default: #{option.default}"] if option.show_default?
|
692
|
+
if option.enum
|
693
|
+
list << ["", "# Possible values: #{option.enum.join(', ')}"]
|
694
|
+
end
|
633
695
|
end
|
696
|
+
|
697
|
+
shell.say(group_name ? "#{group_name} options:" : "Options:")
|
698
|
+
shell.print_table(list, :indent => 2)
|
699
|
+
shell.say ""
|
634
700
|
end
|
635
701
|
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
702
|
+
# Raises an error if the word given is a Thor reserved word.
|
703
|
+
def is_thor_reserved_word?(word, type) #:nodoc:
|
704
|
+
return false unless THOR_RESERVED_WORDS.include?(word.to_s)
|
705
|
+
raise "#{word.inspect} is a Thor reserved word and cannot be " \
|
706
|
+
"defined as #{type}"
|
707
|
+
end
|
640
708
|
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
709
|
+
# Build an option and adds it to the given scope.
|
710
|
+
#
|
711
|
+
# ==== Parameters
|
712
|
+
# name<Symbol>:: The name of the argument.
|
713
|
+
# options<Hash>:: Described in both class_option and method_option.
|
714
|
+
# scope<Hash>:: Options hash that is being built up
|
715
|
+
def build_option(name, options, scope) #:nodoc:
|
716
|
+
scope[name] = Thor::Option.new(
|
717
|
+
name,
|
718
|
+
options.merge(:check_default_type => check_default_type?)
|
719
|
+
)
|
720
|
+
end
|
647
721
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
scope
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
722
|
+
# Receives a hash of options, parse them and add to the scope. This is a
|
723
|
+
# fast way to set a bunch of options:
|
724
|
+
#
|
725
|
+
# build_options :foo => true, :bar => :required, :baz => :string
|
726
|
+
#
|
727
|
+
# ==== Parameters
|
728
|
+
# Hash[Symbol => Object]
|
729
|
+
def build_options(options, scope) #:nodoc:
|
730
|
+
options.each do |key, value|
|
731
|
+
scope[key] = Thor::Option.parse(key, value)
|
732
|
+
end
|
733
|
+
end
|
660
734
|
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
735
|
+
# Finds a command with the given name. If the command belongs to the current
|
736
|
+
# class, just return it, otherwise dup it and add the fresh copy to the
|
737
|
+
# current command hash.
|
738
|
+
def find_and_refresh_command(name) #:nodoc:
|
739
|
+
if commands[name.to_s]
|
740
|
+
commands[name.to_s]
|
741
|
+
elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition
|
742
|
+
commands[name.to_s] = command.clone
|
743
|
+
else
|
744
|
+
raise ArgumentError,
|
745
|
+
"You supplied :for => #{name.inspect}, but the command " \
|
746
|
+
"#{name.inspect} could not be found."
|
747
|
+
end
|
671
748
|
end
|
672
|
-
|
749
|
+
alias_method :find_and_refresh_task, :find_and_refresh_command
|
673
750
|
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
commands[name.to_s]
|
680
|
-
elsif command = all_commands[name.to_s] # rubocop:disable AssignmentInCondition
|
681
|
-
commands[name.to_s] = command.clone
|
682
|
-
else
|
683
|
-
raise ArgumentError,
|
684
|
-
"You supplied :for => #{name.inspect}, but the command " \
|
685
|
-
"#{name.inspect} could not be found."
|
751
|
+
# Everytime someone inherits from a Thor class, register the klass
|
752
|
+
# and file into baseclass.
|
753
|
+
def inherited(klass)
|
754
|
+
Thor::Base.register_klass_file(klass)
|
755
|
+
klass.instance_variable_set(:@no_commands, false)
|
686
756
|
end
|
687
|
-
end
|
688
|
-
alias_method :find_and_refresh_task, :find_and_refresh_command
|
689
757
|
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
klass.instance_variable_set(:@no_commands, false)
|
695
|
-
end
|
758
|
+
# Fire this callback whenever a method is added. Added methods are
|
759
|
+
# tracked as commands by invoking the create_command method.
|
760
|
+
def method_added(meth)
|
761
|
+
meth = meth.to_s
|
696
762
|
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
763
|
+
if meth == "initialize"
|
764
|
+
initialize_added
|
765
|
+
return
|
766
|
+
end
|
701
767
|
|
702
|
-
|
703
|
-
|
704
|
-
return
|
705
|
-
end
|
768
|
+
# Return if it's not a public instance method
|
769
|
+
return unless public_method_defined?(meth.to_sym)
|
706
770
|
|
707
|
-
|
708
|
-
|
771
|
+
@no_commands ||= false
|
772
|
+
return if @no_commands || !create_command(meth)
|
709
773
|
|
710
|
-
|
711
|
-
|
774
|
+
is_thor_reserved_word?(meth, :command)
|
775
|
+
Thor::Base.register_klass_file(self)
|
776
|
+
end
|
712
777
|
|
713
|
-
|
714
|
-
|
715
|
-
|
778
|
+
# Retrieves a value from superclass. If it reaches the baseclass,
|
779
|
+
# returns default.
|
780
|
+
def from_superclass(method, default = nil)
|
781
|
+
if self == baseclass || !superclass.respond_to?(method, true)
|
782
|
+
default
|
783
|
+
else
|
784
|
+
value = superclass.send(method)
|
785
|
+
|
786
|
+
# Ruby implements `dup` on Object, but raises a `TypeError`
|
787
|
+
# if the method is called on immediates. As a result, we
|
788
|
+
# don't have a good way to check whether dup will succeed
|
789
|
+
# without calling it and rescuing the TypeError.
|
790
|
+
begin
|
791
|
+
value.dup
|
792
|
+
rescue TypeError
|
793
|
+
value
|
794
|
+
end
|
716
795
|
|
717
|
-
# Retrieves a value from superclass. If it reaches the baseclass,
|
718
|
-
# returns default.
|
719
|
-
def from_superclass(method, default = nil)
|
720
|
-
if self == baseclass || !superclass.respond_to?(method, true)
|
721
|
-
default
|
722
|
-
else
|
723
|
-
value = superclass.send(method)
|
724
|
-
|
725
|
-
# Ruby implements `dup` on Object, but raises a `TypeError`
|
726
|
-
# if the method is called on immediates. As a result, we
|
727
|
-
# don't have a good way to check whether dup will succeed
|
728
|
-
# without calling it and rescuing the TypeError.
|
729
|
-
begin
|
730
|
-
value.dup
|
731
|
-
rescue TypeError
|
732
|
-
value
|
733
796
|
end
|
734
|
-
|
735
797
|
end
|
736
|
-
end
|
737
798
|
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
799
|
+
# A flag that makes the process exit with status 1 if any error happens.
|
800
|
+
def exit_on_failure?
|
801
|
+
false
|
802
|
+
end
|
742
803
|
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
804
|
+
#
|
805
|
+
# The basename of the program invoking the thor class.
|
806
|
+
#
|
807
|
+
def basename
|
808
|
+
File.basename($PROGRAM_NAME).split(" ").first
|
809
|
+
end
|
749
810
|
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
811
|
+
# SIGNATURE: Sets the baseclass. This is where the superclass lookup
|
812
|
+
# finishes.
|
813
|
+
def baseclass #:nodoc:
|
814
|
+
end
|
754
815
|
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
816
|
+
# SIGNATURE: Creates a new command if valid_command? is true. This method
|
817
|
+
# is called when a new method is added to the class.
|
818
|
+
def create_command(meth) #:nodoc:
|
819
|
+
end
|
820
|
+
alias_method :create_task, :create_command
|
760
821
|
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
822
|
+
# SIGNATURE: Defines behavior when the initialize method is added to the
|
823
|
+
# class.
|
824
|
+
def initialize_added #:nodoc:
|
825
|
+
end
|
765
826
|
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
827
|
+
# SIGNATURE: The hook invoked by start.
|
828
|
+
def dispatch(command, given_args, given_opts, config) #:nodoc:
|
829
|
+
raise NotImplementedError
|
830
|
+
end
|
831
|
+
|
832
|
+
# end protected
|
833
|
+
end # ClassMethods
|
772
834
|
end # module Base
|
773
835
|
end # class Thor
|