atli 0.1.2

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 (42) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +8 -0
  3. data/CHANGELOG.md +193 -0
  4. data/CONTRIBUTING.md +20 -0
  5. data/LICENSE.md +24 -0
  6. data/README.md +44 -0
  7. data/atli.gemspec +30 -0
  8. data/bin/thor +6 -0
  9. data/lib/thor.rb +868 -0
  10. data/lib/thor/actions.rb +322 -0
  11. data/lib/thor/actions/create_file.rb +104 -0
  12. data/lib/thor/actions/create_link.rb +60 -0
  13. data/lib/thor/actions/directory.rb +118 -0
  14. data/lib/thor/actions/empty_directory.rb +143 -0
  15. data/lib/thor/actions/file_manipulation.rb +364 -0
  16. data/lib/thor/actions/inject_into_file.rb +109 -0
  17. data/lib/thor/base.rb +773 -0
  18. data/lib/thor/command.rb +192 -0
  19. data/lib/thor/core_ext/hash_with_indifferent_access.rb +97 -0
  20. data/lib/thor/core_ext/io_binary_read.rb +12 -0
  21. data/lib/thor/core_ext/ordered_hash.rb +129 -0
  22. data/lib/thor/error.rb +32 -0
  23. data/lib/thor/group.rb +281 -0
  24. data/lib/thor/invocation.rb +182 -0
  25. data/lib/thor/line_editor.rb +17 -0
  26. data/lib/thor/line_editor/basic.rb +37 -0
  27. data/lib/thor/line_editor/readline.rb +88 -0
  28. data/lib/thor/parser.rb +5 -0
  29. data/lib/thor/parser/argument.rb +70 -0
  30. data/lib/thor/parser/arguments.rb +175 -0
  31. data/lib/thor/parser/option.rb +146 -0
  32. data/lib/thor/parser/options.rb +221 -0
  33. data/lib/thor/parser/shared_option.rb +23 -0
  34. data/lib/thor/rake_compat.rb +71 -0
  35. data/lib/thor/runner.rb +324 -0
  36. data/lib/thor/shell.rb +81 -0
  37. data/lib/thor/shell/basic.rb +439 -0
  38. data/lib/thor/shell/color.rb +149 -0
  39. data/lib/thor/shell/html.rb +126 -0
  40. data/lib/thor/util.rb +268 -0
  41. data/lib/thor/version.rb +22 -0
  42. metadata +114 -0
@@ -0,0 +1,192 @@
1
+ require 'semantic_logger'
2
+
3
+ class Thor
4
+ class Command < Struct.new( :name,
5
+ :description,
6
+ :long_description,
7
+ :usage,
8
+ :options,
9
+ :ancestor_name )
10
+ include SemanticLogger::Loggable
11
+
12
+ FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
13
+
14
+ def initialize(name, description, long_description, usage, options = nil)
15
+ super(name.to_s, description, long_description, usage, options || {})
16
+ end
17
+
18
+ def initialize_copy(other) #:nodoc:
19
+ super(other)
20
+ self.options = other.options.dup if other.options
21
+ end
22
+
23
+ def hidden?
24
+ false
25
+ end
26
+
27
+ # By default, a command invokes a method in the thor class. You can change
28
+ # this implementation to create custom commands.
29
+ def run(instance, args = [])
30
+ logger.trace "Command#run",
31
+ self: self,
32
+ instance: instance,
33
+ args: args
34
+
35
+ arity = nil
36
+
37
+ if private_method?(instance)
38
+ instance.class.handle_no_command_error(name)
39
+ elsif public_method?(instance)
40
+ arity = instance.method(name).arity
41
+ instance.__send__(name, *args)
42
+ elsif local_method?(instance, :method_missing)
43
+ instance.__send__(:method_missing, name.to_sym, *args)
44
+ else
45
+ instance.class.handle_no_command_error(name)
46
+ end
47
+ rescue ArgumentError => e
48
+ if handle_argument_error?(instance, e, caller)
49
+ instance.class.handle_argument_error(self, e, args, arity)
50
+ else
51
+ raise e
52
+ end
53
+ rescue NoMethodError => e
54
+ if handle_no_method_error?(instance, e, caller)
55
+ instance.class.handle_no_command_error(name)
56
+ else
57
+ raise e
58
+ end
59
+ rescue Exception => error
60
+ instance.send :on_run_error, error, self, args
61
+
62
+ # We should not get here!!!
63
+ # {Thor::Base#on_run_error} should exit or re-raise :(
64
+ logger.error "#on_run_error failed to exit or re-raise", error: error
65
+
66
+ # If you want something done right...
67
+ raise error
68
+ end
69
+
70
+ # Returns the formatted usage by injecting given required arguments
71
+ # and required options into the given usage.
72
+ def formatted_usage(klass, namespace = true, subcommand = false)
73
+ logger.trace "Formatting usage",
74
+ self: self,
75
+ klass: klass,
76
+ namespace: namespace,
77
+ subcommand: subcommand,
78
+ ancestor_name: ancestor_name
79
+
80
+ if ancestor_name
81
+ formatted = "#{ancestor_name} ".dup # add space
82
+ elsif namespace
83
+ namespace = klass.namespace
84
+ formatted = "#{namespace.gsub(/^(default)/, '')}:".dup
85
+ end
86
+ formatted ||= "#{klass.namespace.split(':').last} ".dup if subcommand
87
+
88
+ formatted ||= "".dup
89
+
90
+ # Add usage with required arguments
91
+ formatted << if klass && !klass.arguments.empty?
92
+ usage.to_s.gsub(/^#{name}/) do |match|
93
+ match << " " \
94
+ << klass.arguments.map(&:usage).compact.join(" ")
95
+ end
96
+ else
97
+ usage.to_s
98
+ end
99
+
100
+ # Add required options
101
+ formatted << " #{required_options}"
102
+
103
+ # Strip and go!
104
+ formatted.strip
105
+ end
106
+
107
+ protected
108
+
109
+ def not_debugging?(instance)
110
+ !(instance.class.respond_to?(:debugging) && instance.class.debugging)
111
+ end
112
+
113
+ def required_options
114
+ @required_options ||= options.
115
+ map { |_, o| o.usage if o.required? }.
116
+ compact.
117
+ sort.
118
+ join(" ")
119
+ end
120
+
121
+ # Given a target, checks if this class name is a public method.
122
+ def public_method?(instance) #:nodoc:
123
+ !(instance.public_methods & [name.to_s, name.to_sym]).empty?
124
+ end
125
+
126
+ def private_method?(instance)
127
+ !(instance.private_methods & [name.to_s, name.to_sym]).empty?
128
+ end
129
+
130
+ def local_method?(instance, name)
131
+ methods = instance.public_methods(false) +
132
+ instance.private_methods(false) +
133
+ instance.protected_methods(false)
134
+ !(methods & [name.to_s, name.to_sym]).empty?
135
+ end
136
+
137
+ def sans_backtrace(backtrace, caller) #:nodoc:
138
+ saned = backtrace.reject { |frame|
139
+ (frame =~ FILE_REGEXP) ||
140
+ (frame =~ /\.java:/ && RUBY_PLATFORM =~ /java/) ||
141
+ (frame =~ %r{^kernel/} && RUBY_ENGINE =~ /rbx/)
142
+ }
143
+ saned - caller
144
+ end
145
+
146
+ def handle_argument_error?(instance, error, caller)
147
+ not_debugging?(instance) \
148
+ && ( error.message =~ /wrong number of arguments/ \
149
+ || error.message =~ /given \d*, expected \d*/ ) \
150
+ && begin
151
+ saned = sans_backtrace(error.backtrace, caller)
152
+ # Ruby 1.9 always include the called method in the backtrace
153
+ saned.empty? || (saned.size == 1 && RUBY_VERSION >= "1.9")
154
+ end
155
+ end
156
+
157
+ def handle_no_method_error?(instance, error, caller)
158
+ not_debugging?(instance) &&
159
+ error.message =~ \
160
+ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
161
+ end
162
+ end
163
+ Task = Command
164
+
165
+ # A command that is hidden in help messages but still invocable.
166
+ class HiddenCommand < Command
167
+ def hidden?
168
+ true
169
+ end
170
+ end
171
+ HiddenTask = HiddenCommand
172
+
173
+ # A dynamic command that handles method missing scenarios.
174
+ class DynamicCommand < Command
175
+ def initialize(name, options = nil)
176
+ super( name.to_s,
177
+ "A dynamically-generated command",
178
+ name.to_s,
179
+ name.to_s,
180
+ options )
181
+ end
182
+
183
+ def run(instance, args = [])
184
+ if (instance.methods & [name.to_s, name.to_sym]).empty?
185
+ super
186
+ else
187
+ instance.class.handle_no_command_error(name)
188
+ end
189
+ end
190
+ end
191
+ DynamicTask = DynamicCommand
192
+ end
@@ -0,0 +1,97 @@
1
+ class Thor
2
+ module CoreExt #:nodoc:
3
+ # A hash with indifferent access and magic predicates.
4
+ #
5
+ # hash = Thor::CoreExt::HashWithIndifferentAccess.new 'foo' => 'bar', 'baz' => 'bee', 'force' => true
6
+ #
7
+ # hash[:foo] #=> 'bar'
8
+ # hash['foo'] #=> 'bar'
9
+ # hash.foo? #=> true
10
+ #
11
+ class HashWithIndifferentAccess < ::Hash #:nodoc:
12
+ def initialize(hash = {})
13
+ super()
14
+ hash.each do |key, value|
15
+ self[convert_key(key)] = value
16
+ end
17
+ end
18
+
19
+ def [](key)
20
+ super(convert_key(key))
21
+ end
22
+
23
+ def []=(key, value)
24
+ super(convert_key(key), value)
25
+ end
26
+
27
+ def delete(key)
28
+ super(convert_key(key))
29
+ end
30
+
31
+ def fetch(key, *args)
32
+ super(convert_key(key), *args)
33
+ end
34
+
35
+ def key?(key)
36
+ super(convert_key(key))
37
+ end
38
+
39
+ def values_at(*indices)
40
+ indices.map { |key| self[convert_key(key)] }
41
+ end
42
+
43
+ def merge(other)
44
+ dup.merge!(other)
45
+ end
46
+
47
+ def merge!(other)
48
+ other.each do |key, value|
49
+ self[convert_key(key)] = value
50
+ end
51
+ self
52
+ end
53
+
54
+ def reverse_merge(other)
55
+ self.class.new(other).merge(self)
56
+ end
57
+
58
+ def reverse_merge!(other_hash)
59
+ replace(reverse_merge(other_hash))
60
+ end
61
+
62
+ def replace(other_hash)
63
+ super(other_hash)
64
+ end
65
+
66
+ # Convert to a Hash with String keys.
67
+ def to_hash
68
+ Hash.new(default).merge!(self)
69
+ end
70
+
71
+ protected
72
+
73
+ def convert_key(key)
74
+ key.is_a?(Symbol) ? key.to_s : key
75
+ end
76
+
77
+ # Magic predicates. For instance:
78
+ #
79
+ # options.force? # => !!options['force']
80
+ # options.shebang # => "/usr/lib/local/ruby"
81
+ # options.test_framework?(:rspec) # => options[:test_framework] == :rspec
82
+ #
83
+ def method_missing(method, *args)
84
+ method = method.to_s
85
+ if method =~ /^(\w+)\?$/
86
+ if args.empty?
87
+ !!self[$1]
88
+ else
89
+ self[$1] == args.first
90
+ end
91
+ else
92
+ self[method]
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,12 @@
1
+ class IO #:nodoc:
2
+ class << self
3
+ unless method_defined? :binread
4
+ def binread(file, *args)
5
+ raise ArgumentError, "wrong number of arguments (#{1 + args.size} for 1..3)" unless args.size < 3
6
+ File.open(file, "rb") do |f|
7
+ f.read(*args)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,129 @@
1
+ class Thor
2
+ module CoreExt
3
+ class OrderedHash < ::Hash
4
+ if RUBY_VERSION < "1.9"
5
+ def initialize(*args, &block)
6
+ super
7
+ @keys = []
8
+ end
9
+
10
+ def initialize_copy(other)
11
+ super
12
+ # make a deep copy of keys
13
+ @keys = other.keys
14
+ end
15
+
16
+ def []=(key, value)
17
+ @keys << key unless key?(key)
18
+ super
19
+ end
20
+
21
+ def delete(key)
22
+ if key? key
23
+ index = @keys.index(key)
24
+ @keys.delete_at index
25
+ end
26
+ super
27
+ end
28
+
29
+ def delete_if
30
+ super
31
+ sync_keys!
32
+ self
33
+ end
34
+
35
+ alias_method :reject!, :delete_if
36
+
37
+ def reject(&block)
38
+ dup.reject!(&block)
39
+ end
40
+
41
+ def keys
42
+ @keys.dup
43
+ end
44
+
45
+ def values
46
+ @keys.map { |key| self[key] }
47
+ end
48
+
49
+ def to_hash
50
+ self
51
+ end
52
+
53
+ def to_a
54
+ @keys.map { |key| [key, self[key]] }
55
+ end
56
+
57
+ def each_key
58
+ return to_enum(:each_key) unless block_given?
59
+ @keys.each { |key| yield(key) }
60
+ self
61
+ end
62
+
63
+ def each_value
64
+ return to_enum(:each_value) unless block_given?
65
+ @keys.each { |key| yield(self[key]) }
66
+ self
67
+ end
68
+
69
+ def each
70
+ return to_enum(:each) unless block_given?
71
+ @keys.each { |key| yield([key, self[key]]) }
72
+ self
73
+ end
74
+
75
+ def each_pair
76
+ return to_enum(:each_pair) unless block_given?
77
+ @keys.each { |key| yield(key, self[key]) }
78
+ self
79
+ end
80
+
81
+ alias_method :select, :find_all
82
+
83
+ def clear
84
+ super
85
+ @keys.clear
86
+ self
87
+ end
88
+
89
+ def shift
90
+ k = @keys.first
91
+ v = delete(k)
92
+ [k, v]
93
+ end
94
+
95
+ def merge!(other_hash)
96
+ if block_given?
97
+ other_hash.each { |k, v| self[k] = key?(k) ? yield(k, self[k], v) : v }
98
+ else
99
+ other_hash.each { |k, v| self[k] = v }
100
+ end
101
+ self
102
+ end
103
+
104
+ alias_method :update, :merge!
105
+
106
+ def merge(other_hash, &block)
107
+ dup.merge!(other_hash, &block)
108
+ end
109
+
110
+ # When replacing with another hash, the initial order of our keys must come from the other hash -ordered or not.
111
+ def replace(other)
112
+ super
113
+ @keys = other.keys
114
+ self
115
+ end
116
+
117
+ def inspect
118
+ "#<#{self.class} #{super}>"
119
+ end
120
+
121
+ private
122
+
123
+ def sync_keys!
124
+ @keys.delete_if { |k| !key?(k) }
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
data/lib/thor/error.rb ADDED
@@ -0,0 +1,32 @@
1
+ class Thor
2
+ # Thor::Error is raised when it's caused by wrong usage of thor classes. Those
3
+ # errors have their backtrace suppressed and are nicely shown to the user.
4
+ #
5
+ # Errors that are caused by the developer, like declaring a method which
6
+ # overwrites a thor keyword, SHOULD NOT raise a Thor::Error. This way, we
7
+ # ensure that developer errors are shown with full backtrace.
8
+ class Error < StandardError
9
+ end
10
+
11
+ # Raised when a command was not found.
12
+ class UndefinedCommandError < Error
13
+ end
14
+ UndefinedTaskError = UndefinedCommandError
15
+
16
+ class AmbiguousCommandError < Error
17
+ end
18
+ AmbiguousTaskError = AmbiguousCommandError
19
+
20
+ # Raised when a command was found, but not invoked properly.
21
+ class InvocationError < Error
22
+ end
23
+
24
+ class UnknownArgumentError < Error
25
+ end
26
+
27
+ class RequiredArgumentMissingError < InvocationError
28
+ end
29
+
30
+ class MalformattedArgumentError < InvocationError
31
+ end
32
+ end