atli 0.1.2 → 0.1.3
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.
- 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
|