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
data/lib/thor/group.rb ADDED
@@ -0,0 +1,281 @@
1
+ require "thor/base"
2
+
3
+ # Thor has a special class called Thor::Group. The main difference to Thor class
4
+ # is that it invokes all commands at once. It also include some methods that allows
5
+ # invocations to be done at the class method, which are not available to Thor
6
+ # commands.
7
+ class Thor::Group
8
+ class << self
9
+ # The description for this Thor::Group. If none is provided, but a source root
10
+ # exists, tries to find the USAGE one folder above it, otherwise searches
11
+ # in the superclass.
12
+ #
13
+ # ==== Parameters
14
+ # description<String>:: The description for this Thor::Group.
15
+ #
16
+ def desc(description = nil)
17
+ if description
18
+ @desc = description
19
+ else
20
+ @desc ||= from_superclass(:desc, nil)
21
+ end
22
+ end
23
+
24
+ # Prints help information.
25
+ #
26
+ # ==== Options
27
+ # short:: When true, shows only usage.
28
+ #
29
+ def help(shell)
30
+ shell.say "Usage:"
31
+ shell.say " #{banner}\n"
32
+ shell.say
33
+ class_options_help(shell)
34
+ shell.say desc if desc
35
+ end
36
+
37
+ # Stores invocations for this class merging with superclass values.
38
+ #
39
+ def invocations #:nodoc:
40
+ @invocations ||= from_superclass(:invocations, {})
41
+ end
42
+
43
+ # Stores invocation blocks used on invoke_from_option.
44
+ #
45
+ def invocation_blocks #:nodoc:
46
+ @invocation_blocks ||= from_superclass(:invocation_blocks, {})
47
+ end
48
+
49
+ # Invoke the given namespace or class given. It adds an instance
50
+ # method that will invoke the klass and command. You can give a block to
51
+ # configure how it will be invoked.
52
+ #
53
+ # The namespace/class given will have its options showed on the help
54
+ # usage. Check invoke_from_option for more information.
55
+ #
56
+ def invoke(*names, &block)
57
+ options = names.last.is_a?(Hash) ? names.pop : {}
58
+ verbose = options.fetch(:verbose, true)
59
+
60
+ names.each do |name|
61
+ invocations[name] = false
62
+ invocation_blocks[name] = block if block_given?
63
+
64
+ class_eval <<-METHOD, __FILE__, __LINE__
65
+ def _invoke_#{name.to_s.gsub(/\W/, '_')}
66
+ klass, command = self.class.prepare_for_invocation(nil, #{name.inspect})
67
+
68
+ if klass
69
+ say_status :invoke, #{name.inspect}, #{verbose.inspect}
70
+ block = self.class.invocation_blocks[#{name.inspect}]
71
+ _invoke_for_class_method klass, command, &block
72
+ else
73
+ say_status :error, %(#{name.inspect} [not found]), :red
74
+ end
75
+ end
76
+ METHOD
77
+ end
78
+ end
79
+
80
+ # Invoke a thor class based on the value supplied by the user to the
81
+ # given option named "name". A class option must be created before this
82
+ # method is invoked for each name given.
83
+ #
84
+ # ==== Examples
85
+ #
86
+ # class GemGenerator < Thor::Group
87
+ # class_option :test_framework, :type => :string
88
+ # invoke_from_option :test_framework
89
+ # end
90
+ #
91
+ # ==== Boolean options
92
+ #
93
+ # In some cases, you want to invoke a thor class if some option is true or
94
+ # false. This is automatically handled by invoke_from_option. Then the
95
+ # option name is used to invoke the generator.
96
+ #
97
+ # ==== Preparing for invocation
98
+ #
99
+ # In some cases you want to customize how a specified hook is going to be
100
+ # invoked. You can do that by overwriting the class method
101
+ # prepare_for_invocation. The class method must necessarily return a klass
102
+ # and an optional command.
103
+ #
104
+ # ==== Custom invocations
105
+ #
106
+ # You can also supply a block to customize how the option is going to be
107
+ # invoked. The block receives two parameters, an instance of the current
108
+ # class and the klass to be invoked.
109
+ #
110
+ def invoke_from_option(*names, &block)
111
+ options = names.last.is_a?(Hash) ? names.pop : {}
112
+ verbose = options.fetch(:verbose, :white)
113
+
114
+ names.each do |name|
115
+ unless class_options.key?(name)
116
+ raise ArgumentError, "You have to define the option #{name.inspect} " \
117
+ "before setting invoke_from_option."
118
+ end
119
+
120
+ invocations[name] = true
121
+ invocation_blocks[name] = block if block_given?
122
+
123
+ class_eval <<-METHOD, __FILE__, __LINE__
124
+ def _invoke_from_option_#{name.to_s.gsub(/\W/, '_')}
125
+ return unless options[#{name.inspect}]
126
+
127
+ value = options[#{name.inspect}]
128
+ value = #{name.inspect} if TrueClass === value
129
+ klass, command = self.class.prepare_for_invocation(#{name.inspect}, value)
130
+
131
+ if klass
132
+ say_status :invoke, value, #{verbose.inspect}
133
+ block = self.class.invocation_blocks[#{name.inspect}]
134
+ _invoke_for_class_method klass, command, &block
135
+ else
136
+ say_status :error, %(\#{value} [not found]), :red
137
+ end
138
+ end
139
+ METHOD
140
+ end
141
+ end
142
+
143
+ # Remove a previously added invocation.
144
+ #
145
+ # ==== Examples
146
+ #
147
+ # remove_invocation :test_framework
148
+ #
149
+ def remove_invocation(*names)
150
+ names.each do |name|
151
+ remove_command(name)
152
+ remove_class_option(name)
153
+ invocations.delete(name)
154
+ invocation_blocks.delete(name)
155
+ end
156
+ end
157
+
158
+ # Overwrite class options help to allow invoked generators options to be
159
+ # shown recursively when invoking a generator.
160
+ #
161
+ def class_options_help(shell, groups = {}) #:nodoc:
162
+ get_options_from_invocations(groups, class_options) do |klass|
163
+ klass.send(:get_options_from_invocations, groups, class_options)
164
+ end
165
+ super(shell, groups)
166
+ end
167
+
168
+ # Get invocations array and merge options from invocations. Those
169
+ # options are added to group_options hash. Options that already exists
170
+ # in base_options are not added twice.
171
+ #
172
+ def get_options_from_invocations(group_options, base_options) #:nodoc: # rubocop:disable MethodLength
173
+ invocations.each do |name, from_option|
174
+ value = if from_option
175
+ option = class_options[name]
176
+ option.type == :boolean ? name : option.default
177
+ else
178
+ name
179
+ end
180
+ next unless value
181
+
182
+ klass, _ = prepare_for_invocation(name, value)
183
+ next unless klass && klass.respond_to?(:class_options)
184
+
185
+ value = value.to_s
186
+ human_name = value.respond_to?(:classify) ? value.classify : value
187
+
188
+ group_options[human_name] ||= []
189
+ group_options[human_name] += klass.class_options.values.select do |class_option|
190
+ base_options[class_option.name.to_sym].nil? && class_option.group.nil? &&
191
+ !group_options.values.flatten.any? { |i| i.name == class_option.name }
192
+ end
193
+
194
+ yield klass if block_given?
195
+ end
196
+ end
197
+
198
+ # Returns commands ready to be printed.
199
+ def printable_commands(*)
200
+ item = []
201
+ item << banner
202
+ item << (desc ? "# #{desc.gsub(/\s+/m, ' ')}" : "")
203
+ [item]
204
+ end
205
+ alias_method :printable_tasks, :printable_commands
206
+
207
+ def handle_argument_error(command, error, _args, arity) #:nodoc:
208
+ msg = "#{basename} #{command.name} takes #{arity} argument".dup
209
+ msg << "s" if arity > 1
210
+ msg << ", but it should not."
211
+ raise error, msg
212
+ end
213
+
214
+ protected
215
+
216
+ # The method responsible for dispatching given the args.
217
+ def dispatch(command, given_args, given_opts, config) #:nodoc:
218
+ if Thor::HELP_MAPPINGS.include?(given_args.first)
219
+ help(config[:shell])
220
+ return
221
+ end
222
+
223
+ args, opts = Thor::Options.split(given_args)
224
+ opts = given_opts || opts
225
+
226
+ instance = new(args, opts, config)
227
+ yield instance if block_given?
228
+
229
+ if command
230
+ instance.invoke_command(all_commands[command])
231
+ else
232
+ instance.invoke_all
233
+ end
234
+ end
235
+
236
+ # The banner for this class. You can customize it if you are invoking the
237
+ # thor class by another ways which is not the Thor::Runner.
238
+ def banner
239
+ "#{basename} #{self_command.formatted_usage(self, false)}"
240
+ end
241
+
242
+ # Represents the whole class as a command.
243
+ def self_command #:nodoc:
244
+ Thor::DynamicCommand.new(namespace, class_options)
245
+ end
246
+ alias_method :self_task, :self_command
247
+
248
+ def baseclass #:nodoc:
249
+ Thor::Group
250
+ end
251
+
252
+ def create_command(meth) #:nodoc:
253
+ commands[meth.to_s] = Thor::Command.new(meth, nil, nil, nil, nil)
254
+ true
255
+ end
256
+ alias_method :create_task, :create_command
257
+ end
258
+
259
+ include Thor::Base
260
+
261
+ protected
262
+
263
+ # Shortcut to invoke with padding and block handling. Use internally by
264
+ # invoke and invoke_from_option class methods.
265
+ def _invoke_for_class_method(klass, command = nil, *args, &block) #:nodoc:
266
+ with_padding do
267
+ if block
268
+ case block.arity
269
+ when 3
270
+ yield(self, klass, command)
271
+ when 2
272
+ yield(self, klass)
273
+ when 1
274
+ instance_exec(klass, &block)
275
+ end
276
+ else
277
+ invoke klass, command, *args
278
+ end
279
+ end
280
+ end
281
+ end
@@ -0,0 +1,182 @@
1
+ class Thor
2
+ # @note
3
+ # Included when {Thor::Base} is included - and that's the only place it's
4
+ # included from what I can find, so this stuff just ends up in {Thor}
5
+ # and {Thor::Group}.
6
+ #
7
+ module Invocation
8
+ def self.included(base) #:nodoc:
9
+ base.extend ClassMethods
10
+ end
11
+
12
+ module ClassMethods
13
+ # This method is responsible for receiving a name and find the proper
14
+ # class and command for it. The key is an optional parameter which is
15
+ # available only in class methods invocations (i.e. in Thor::Group).
16
+ def prepare_for_invocation(key, name) #:nodoc:
17
+ case name
18
+ when Symbol, String
19
+ Thor::Util.find_class_and_command_by_namespace(name.to_s, !key)
20
+ else
21
+ name
22
+ end
23
+ end
24
+ end
25
+
26
+ # Make initializer aware of invocations and the initialization args.
27
+ def initialize(args = [], options = {}, config = {}, &block) #:nodoc:
28
+ @_invocations = config[:invocations] || Hash.new { |h, k| h[k] = [] }
29
+ @_initializer = [args, options, config]
30
+ super
31
+ end
32
+
33
+ # Make the current command chain accessible with in a Thor-(sub)command
34
+ def current_command_chain
35
+ @_invocations.values.flatten.map(&:to_sym)
36
+ end
37
+
38
+ # Receives a name and invokes it. The name can be a string (either "command" or
39
+ # "namespace:command"), a Thor::Command, a Class or a Thor instance. If the
40
+ # command cannot be guessed by name, it can also be supplied as second argument.
41
+ #
42
+ # You can also supply the arguments, options and configuration values for
43
+ # the command to be invoked, if none is given, the same values used to
44
+ # initialize the invoker are used to initialize the invoked.
45
+ #
46
+ # When no name is given, it will invoke the default command of the current class.
47
+ #
48
+ # ==== Examples
49
+ #
50
+ # class A < Thor
51
+ # def foo
52
+ # invoke :bar
53
+ # invoke "b:hello", ["Erik"]
54
+ # end
55
+ #
56
+ # def bar
57
+ # invoke "b:hello", ["Erik"]
58
+ # end
59
+ # end
60
+ #
61
+ # class B < Thor
62
+ # def hello(name)
63
+ # puts "hello #{name}"
64
+ # end
65
+ # end
66
+ #
67
+ # You can notice that the method "foo" above invokes two commands: "bar",
68
+ # which belongs to the same class and "hello" which belongs to the class B.
69
+ #
70
+ # By using an invocation system you ensure that a command is invoked only once.
71
+ # In the example above, invoking "foo" will invoke "b:hello" just once, even
72
+ # if it's invoked later by "bar" method.
73
+ #
74
+ # When class A invokes class B, all arguments used on A initialization are
75
+ # supplied to B. This allows lazy parse of options. Let's suppose you have
76
+ # some rspec commands:
77
+ #
78
+ # class Rspec < Thor::Group
79
+ # class_option :mock_framework, :type => :string, :default => :rr
80
+ #
81
+ # def invoke_mock_framework
82
+ # invoke "rspec:#{options[:mock_framework]}"
83
+ # end
84
+ # end
85
+ #
86
+ # As you noticed, it invokes the given mock framework, which might have its
87
+ # own options:
88
+ #
89
+ # class Rspec::RR < Thor::Group
90
+ # class_option :style, :type => :string, :default => :mock
91
+ # end
92
+ #
93
+ # Since it's not rspec concern to parse mock framework options, when RR
94
+ # is invoked all options are parsed again, so RR can extract only the options
95
+ # that it's going to use.
96
+ #
97
+ # If you want Rspec::RR to be initialized with its own set of options, you
98
+ # have to do that explicitly:
99
+ #
100
+ # invoke "rspec:rr", [], :style => :foo
101
+ #
102
+ # Besides giving an instance, you can also give a class to invoke:
103
+ #
104
+ # invoke Rspec::RR, [], :style => :foo
105
+ #
106
+ def invoke(name = nil, *args)
107
+ if name.nil?
108
+ warn "[Thor] Calling invoke() without argument is deprecated. Please use invoke_all instead.\n#{caller.join("\n")}"
109
+ return invoke_all
110
+ end
111
+
112
+ args.unshift(nil) if args.first.is_a?(Array) || args.first.nil?
113
+ command, args, opts, config = args
114
+
115
+ klass, command = _retrieve_class_and_command(name, command)
116
+ raise "Missing Thor class for invoke #{name}" unless klass
117
+ raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
118
+
119
+ args, opts, config = _parse_initialization_options(args, opts, config)
120
+ klass.send(:dispatch, command, args, opts, config) do |instance|
121
+ instance.parent_options = options
122
+ end
123
+ end
124
+
125
+ # Invoke the given command if the given args.
126
+ def invoke_command(command, *args) #:nodoc:
127
+ current = @_invocations[self.class]
128
+
129
+ unless current.include?(command.name)
130
+ current << command.name
131
+ command.run(self, *args)
132
+ end
133
+ end
134
+ alias_method :invoke_task, :invoke_command
135
+
136
+ # Invoke all commands for the current instance.
137
+ def invoke_all #:nodoc:
138
+ self.class.all_commands.map { |_, command| invoke_command(command) }
139
+ end
140
+
141
+ # Invokes using shell padding.
142
+ def invoke_with_padding(*args)
143
+ with_padding { invoke(*args) }
144
+ end
145
+
146
+ protected
147
+
148
+ # Configuration values that are shared between invocations.
149
+ def _shared_configuration #:nodoc:
150
+ {:invocations => @_invocations}
151
+ end
152
+
153
+ # This method simply retrieves the class and command to be invoked.
154
+ # If the name is nil or the given name is a command in the current class,
155
+ # use the given name and return self as class. Otherwise, call
156
+ # prepare_for_invocation in the current class.
157
+ def _retrieve_class_and_command(name, sent_command = nil) #:nodoc:
158
+ if name.nil?
159
+ [self.class, nil]
160
+ elsif self.class.all_commands[name.to_s]
161
+ [self.class, name.to_s]
162
+ else
163
+ klass, command = self.class.prepare_for_invocation(nil, name)
164
+ [klass, command || sent_command]
165
+ end
166
+ end
167
+ alias_method :_retrieve_class_and_task, :_retrieve_class_and_command
168
+
169
+ # Initialize klass using values stored in the @_initializer.
170
+ def _parse_initialization_options(args, opts, config) #:nodoc:
171
+ stored_args, stored_opts, stored_config = @_initializer
172
+
173
+ args ||= stored_args.dup
174
+ opts ||= stored_opts.dup
175
+
176
+ config ||= {}
177
+ config = stored_config.merge(_shared_configuration).merge!(config)
178
+
179
+ [args, opts, config]
180
+ end
181
+ end
182
+ end