josevalim-thor 0.10.23 → 0.10.25

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -1,76 +1,247 @@
1
1
  thor
2
2
  ====
3
3
 
4
- Map options to a class. Simply create a class with the appropriate annotations, and have options automatically map
5
- to functions and parameters.
4
+ Map options to a class. Simply create a class with the appropriate annotations
5
+ and have options automatically map to functions and parameters.
6
6
 
7
7
  Example:
8
8
 
9
- class MyApp < Thor # [1]
10
- map "-L" => :list # [2]
11
-
12
- desc "install APP_NAME", "install one of the available apps" # [3]
13
- method_options :force => :boolean, :alias => :optional # [4]
9
+ class App < Thor # [1]
10
+ map "-L" => :list # [2]
11
+
12
+ desc "install APP_NAME", "install one of the available apps" # [3]
13
+ method_options :force => :boolean, :alias => :string # [4]
14
14
  def install(name)
15
15
  user_alias = options[:alias]
16
16
  if options.force?
17
17
  # do something
18
18
  end
19
- # ... other code ...
19
+ # other code
20
20
  end
21
21
 
22
22
  desc "list [SEARCH]", "list all of the available apps, limited by SEARCH"
23
- def list(search = "")
23
+ def list(search="")
24
24
  # list everything
25
25
  end
26
26
  end
27
-
27
+
28
28
  Thor automatically maps commands as such:
29
29
 
30
- app install myname --force
31
-
30
+ thor app:install myname --force
31
+
32
32
  That gets converted to:
33
33
 
34
- MyApp.new.install("myname")
34
+ App.new.install("myname")
35
35
  # with {'force' => true} as options hash
36
36
 
37
37
  1. Inherit from Thor to turn a class into an option mapper
38
- 2. Map additional non-valid identifiers to specific methods. In this case,
39
- convert -L to :list
40
- 3. Describe the method immediately below. The first parameter is the usage information,
41
- and the second parameter is the description.
42
- 4. Provide any additional options. These will be marshaled from `--` and `-` params.
43
- In this case, a `--force` and a `-f` option is added.
44
-
38
+ 2. Map additional non-valid identifiers to specific methods. In this case, convert -L to :list
39
+ 3. Describe the method immediately below. The first parameter is the usage information, and the second parameter is the description
40
+ 4. Provide any additional options that will be available the instance method options.
41
+
45
42
  Types for `method_options`
46
43
  --------------------------
47
44
 
48
45
  <dl>
49
46
  <dt><code>:boolean</code></dt>
50
- <dd>true if the option is passed</dd>
51
- <dt><code>true or false</code></dt>
52
- <dd>same as <code>:boolean</code>, but fall back to given boolean as default value</dd>
53
- <dt><code>:required</code></dt>
54
- <dd>the value for this option MUST be provided</dd>
55
- <dt><code>:optional</code></dt>
56
- <dd>the value for this option MAY be provided</dd>
47
+ <dd>is parsed as --option or --option=true</dd>
48
+ <dt><code>:string</code></dt>
49
+ <dd>is parsed as --option=VALUE</dd>
57
50
  <dt><code>:numeric</code></dt>
58
- <dd>the value MAY be provided, but MUST be in numeric form</dd>
59
- <dt>a String or Numeric</dt>
60
- <dd>same as <code>:optional</code>, but fall back to the given object as default value</dd>
51
+ <dd>is parsed as --option=N</dd>
52
+ <dt><code>:array</code></dt>
53
+ <dd>is parsed as --option=one two three</dd>
54
+ <dt><code>:hash</code></dt>
55
+ <dd>is parsed as --option=key:value key:value key:value</dd>
61
56
  </dl>
62
57
 
63
- In case of unsatisfied requirements, `Thor::Options::Error` is raised.
58
+ Besides, method_option allows a default value to be given, examples:
59
+
60
+ method_options :force => false
61
+ #=> Creates a boolean option with default value false
62
+
63
+ method_options :alias => "bar"
64
+ #=> Creates a string option with default value "bar"
65
+
66
+ method_options :threshold => 3.0
67
+ #=> Creates a numeric option with default value 3.0
68
+
69
+ You can also supply :option => :required to mark an option as required. The
70
+ type is assumed to be string. If you want a required hash with default values
71
+ as option, you can use `method_option` which uses a more declarative style:
72
+
73
+ method_option :attributes, :type => :hash, :default => {}, :required => true
74
+
75
+ All arguments can be set to nil (except required arguments), by suppling a no or
76
+ skip variant. For example:
77
+
78
+ thor app name --no-attributes
79
+
80
+ In previous versions, aliases for options were created automatically, but now
81
+ they should be explicit. You can supply aliases in both short and declarative
82
+ styles:
83
+
84
+ method_options %w( force -f ) => :boolean
85
+
86
+ Or:
87
+
88
+ method_option :force, :type => :boolean, :aliases => "-f"
89
+
90
+ You can supply as many aliases as you want.
91
+
92
+ NOTE: Type :optional available in Thor 0.9.0 was deprecated. Use :string or :boolean instead.
93
+
94
+ Namespaces
95
+ ----------
96
+
97
+ By default, your Thor tasks are invoked using Ruby namespace. In the example
98
+ above, tasks are invoked as:
99
+
100
+ thor app:install name --force
101
+
102
+ However, you could namespace your class as:
103
+
104
+ module Sinatra
105
+ class App < Thor
106
+ # tasks
107
+ end
108
+ end
109
+
110
+ And then you should invoke your tasks as:
111
+
112
+ thor sinatra:app:install name --force
113
+
114
+ If desired, you can change the namespace:
115
+
116
+ module Sinatra
117
+ class App < Thor
118
+ namespace :myapp
119
+ # tasks
120
+ end
121
+ end
122
+
123
+ And then your tasks hould be invoked as:
124
+
125
+ thor myapp:install name --force
126
+
127
+ Invocations
128
+ -----------
129
+
130
+ Thor comes with a invocation-dependency system as well which allows a task to be
131
+ invoked only once. For example:
132
+
133
+ class Counter < Thor
134
+ desc "one", "Prints 1, 2, 3"
135
+ def one
136
+ puts 1
137
+ invoke :two
138
+ invoke :three
139
+ end
140
+
141
+ desc "two", "Prints 2, 3"
142
+ def two
143
+ puts 2
144
+ invoke :three
145
+ end
146
+
147
+ desc "three", "Prints 3"
148
+ def three
149
+ puts 3
150
+ end
151
+ end
152
+
153
+ When invoking the task one:
154
+
155
+ thor counter:one
156
+
157
+ The output is "1 2 3", which means that the three task was invoked only once.
158
+ You can even invoke tasks from another class, so be sure to check the
159
+ documentation.
160
+
161
+ Thor::Group
162
+ -----------
163
+
164
+ Thor has a special class called Thor::Group. The main difference to Thor class
165
+ is that it invokes all tasks at once. The example above could be rewritten in
166
+ Thor::Group as this:
167
+
168
+ class Counter < Thor::Group
169
+ desc "Prints 1, 2, 3"
170
+
171
+ def one
172
+ puts 1
173
+ end
174
+
175
+ def two
176
+ puts 2
177
+ end
178
+
179
+ def three
180
+ puts 3
181
+ end
182
+ end
183
+
184
+ When invoked:
185
+
186
+ thor counter
187
+
188
+ It prints "1 2 3" as well. Notice you should described (desc) only the class
189
+ and not each task anymore. Thor::Group is a great tool to create generators,
190
+ since you can define several steps which are invoked in the order they are
191
+ defined (Thor::Group is the tool use in generators in Rails 3.0).
192
+
193
+ Besides, Thor::Group can parse arguments and options as Thor tasks:
194
+
195
+ class Counter < Thor::Group
196
+ # number will be available as attr_accessor
197
+ argument :number, :type => :numeric, :desc => "The number to start counting"
198
+ desc "Prints the 'number' given upto 'number+2'"
199
+
200
+ def one
201
+ puts number + 0
202
+ end
203
+
204
+ def two
205
+ puts number + 1
206
+ end
207
+
208
+ def three
209
+ puts number + 2
210
+ end
211
+ end
212
+
213
+ The counter above expects one parameter and has the folling outputs:
214
+
215
+ thor counter 5
216
+ # Prints "5 6 7"
217
+
218
+ thor counter 11
219
+ # Prints "11 12 13"
220
+
221
+ You can also give options to Thor::Group, but instead of using `method_option` and
222
+ `method_options`, you should use `class_option` and `class_options`. Both argument
223
+ and class_options methods are available to Thor class as well.
224
+
225
+ Actions
226
+ -------
227
+
228
+ Thor comes with several actions which helps with script and generator tasks. You
229
+ might be familiar with them since some came from Rails Templates. They are: `say`,
230
+ `ask`, `yes?`, `no?`, `add_file`, `remove_file`, `copy_file`, `template`,
231
+ `directory`, `inside`, `run`, `inject_into_file` and a couple more.
232
+
233
+ To use them, you just need to include Thor::Actions in your Thor classes:
234
+
235
+ class App < Thor
236
+ include Thor::Actions
237
+ # tasks
238
+ end
239
+
240
+ Some actions like copy file requires that a class method called source_root is
241
+ defined in your class. This is the directory where your templates should be
242
+ placed. Be sure to check the documentation.
64
243
 
65
- Examples of option parsing:
244
+ License
245
+ -------
66
246
 
67
- # let's say this is how we defined options for a method:
68
- method_options(:force => :boolean, :retries => :numeric)
69
-
70
- # here is how the following command-line invocations would be parsed:
71
-
72
- command -f --retries 5 # => {'force' => true, 'retries' => 5}
73
- command --force -r=5 # => {'force' => true, 'retries' => 5}
74
- command -fr 5 # => {'force' => true, 'retries' => 5}
75
- command --retries=5 # => {'retries' => 5}
76
- command -r5 # => {'retries' => 5}
247
+ See MIT LICENSE.
data/lib/thor.rb CHANGED
@@ -199,7 +199,7 @@ class Thor
199
199
  end
200
200
 
201
201
  def valid_task?(meth) #:nodoc:
202
- public_instance_methods.include?(meth) && @usage && @desc
202
+ @usage && @desc
203
203
  end
204
204
 
205
205
  def create_task(meth) #:nodoc:
data/lib/thor/actions.rb CHANGED
@@ -175,7 +175,9 @@ class Thor
175
175
  # If a symbol is given, uses it as the output color.
176
176
  #
177
177
  def run_ruby_script(command, log_status=true)
178
- run("ruby #{command}", log_status)
178
+ return unless behavior == :invoke
179
+ say_status File.basename(Thor::Util.ruby_command), command, log_status
180
+ `#{Thor::Util.ruby_command} #{command}` unless options[:pretend]
179
181
  end
180
182
 
181
183
  # Run a thor command. A hash of options can be given and it's converted to
@@ -198,13 +200,14 @@ class Thor
198
200
  #
199
201
  def thor(task, *args)
200
202
  log_status = args.last.is_a?(Symbol) || [true, false].include?(args.last) ? args.pop : true
201
- options = args.last.is_a?(Hash) ? args.pop : {}
203
+ options = args.last.is_a?(Hash) ? args.pop : {}
202
204
 
203
- in_root do
204
- args.unshift "thor #{task}"
205
- args.push Thor::Options.to_switches(options)
206
- run args.join(' ').strip, log_status
207
- end
205
+ args.unshift task
206
+ args.push Thor::Options.to_switches(options)
207
+ command = args.join(' ').strip
208
+
209
+ say_status :thor, command, log_status
210
+ run "thor #{command}", false
208
211
  end
209
212
 
210
213
  # Removes a file at the given location.
@@ -221,9 +224,10 @@ class Thor
221
224
  #
222
225
  def remove_file(path, log_status=true)
223
226
  return unless behavior == :invoke
224
- path = File.expand_path(path, root)
225
- say_status :remove, relative_to_absolute_root(path), log_status
227
+ path = File.expand_path(path, root)
228
+ color = log_status.is_a?(Symbol) ? log_status : :red
226
229
 
230
+ say_status :remove, relative_to_absolute_root(path), log_status
227
231
  ::FileUtils.rm_rf(path) if !options[:pretend] && File.exists?(path)
228
232
  end
229
233
 
@@ -305,11 +309,11 @@ class Thor
305
309
 
306
310
  # Allow current root to be shared between invocations.
307
311
  #
308
- def _shared_configuration
312
+ def _shared_configuration #:nodoc:
309
313
  super.merge!(:root => self.root)
310
314
  end
311
315
 
312
- def _cleanup_options_and_set(options, key)
316
+ def _cleanup_options_and_set(options, key) #:nodoc:
313
317
  case options
314
318
  when Array
315
319
  %w(--force -f --skip -s).each { |i| options.delete(i) }
@@ -53,13 +53,14 @@ class Thor
53
53
  end
54
54
 
55
55
  def invoke!
56
+ base.empty_directory given_destination
56
57
  lookup = recursive ? File.join(source, '**', '*') : File.join(source, '*')
57
58
 
58
59
  Dir[lookup].each do |file_source|
59
60
  file_destination = File.join(given_destination, file_source.gsub(source, '.'))
60
61
 
61
62
  if File.directory?(file_source)
62
- base.empty_directory(file_destination, @log_status)
63
+ base.empty_directory(file_destination, @log_status) if recursive
63
64
  elsif file_source !~ /\.empty_directory$/
64
65
  if file_source =~ /\.tt$/
65
66
  base.template(file_source, file_destination[0..-4], @log_status)
@@ -65,7 +65,7 @@ class Thor
65
65
  # Revokes the action.
66
66
  #
67
67
  def revoke!
68
- say_status :remove, :green
68
+ say_status :remove, :red
69
69
  ::FileUtils.rm_rf(destination) if !pretend? && exists?
70
70
  end
71
71
 
data/lib/thor/base.rb CHANGED
@@ -374,7 +374,7 @@ class Thor
374
374
  groups[value.group] << value
375
375
  end
376
376
 
377
- printer = lambda do |group_name, options|
377
+ printer = proc do |group_name, options|
378
378
  list = []
379
379
  padding = options.collect{ |o| o.aliases.size }.max.to_i * 4
380
380
 
@@ -471,7 +471,13 @@ class Thor
471
471
  return
472
472
  end
473
473
 
474
+ # Return if it's not a public instance method
475
+ return unless public_instance_methods.include?(meth) ||
476
+ public_instance_methods.include?(meth.to_sym)
477
+
478
+ # Return if @no_tasks is enabled or it's not a valid task
474
479
  return if @no_tasks || !valid_task?(meth)
480
+
475
481
  is_thor_reserved_word?(meth, :task)
476
482
  Thor::Base.register_klass_file(self)
477
483
  create_task(meth)
@@ -497,6 +503,7 @@ class Thor
497
503
  # SIGNATURE: Defines if a given method is a valid_task?. This method is
498
504
  # called before a new method is added to the class.
499
505
  def valid_task?(meth) #:nodoc:
506
+ true # unless otherwise given
500
507
  end
501
508
 
502
509
  # SIGNATURE: Creates a new task if valid_task? is true. This method is
@@ -3,94 +3,100 @@ require 'forwardable'
3
3
  class Thor #:nodoc:
4
4
  module CoreExt #:nodoc:
5
5
 
6
- # This class is based on the Ruby 1.9 ordered hashes.
7
- #
8
- # It keeps the semantics and most of the efficiency of normal hashes
9
- # while also keeping track of the order in which elements were set.
10
- #
11
- class OrderedHash #:nodoc:
12
- include Enumerable
13
-
14
- Node = Struct.new(:key, :value, :next, :prev)
15
-
16
- def initialize
17
- @hash = {}
18
- end
19
-
20
- def [](key)
21
- @hash[key] && @hash[key].value
6
+ if RUBY_VERSION >= '1.9'
7
+ class OrderedHash < ::Hash
22
8
  end
9
+ else
10
+ # This class is based on the Ruby 1.9 ordered hashes.
11
+ #
12
+ # It keeps the semantics and most of the efficiency of normal hashes
13
+ # while also keeping track of the order in which elements were set.
14
+ #
15
+ class OrderedHash #:nodoc:
16
+ include Enumerable
17
+
18
+ Node = Struct.new(:key, :value, :next, :prev)
19
+
20
+ def initialize
21
+ @hash = {}
22
+ end
23
23
 
24
- def []=(key, value)
25
- if node = @hash[key]
26
- node.value = value
27
- else
28
- node = Node.new(key, value)
24
+ def [](key)
25
+ @hash[key] && @hash[key].value
26
+ end
29
27
 
30
- if @first.nil?
31
- @first = @last = node
28
+ def []=(key, value)
29
+ if node = @hash[key]
30
+ node.value = value
32
31
  else
33
- node.prev = @last
34
- @last.next = node
35
- @last = node
32
+ node = Node.new(key, value)
33
+
34
+ if @first.nil?
35
+ @first = @last = node
36
+ else
37
+ node.prev = @last
38
+ @last.next = node
39
+ @last = node
40
+ end
36
41
  end
42
+
43
+ @hash[key] = node
44
+ value
37
45
  end
38
46
 
39
- @hash[key] = node
40
- value
41
- end
47
+ def delete(key)
48
+ if node = @hash[key]
49
+ prev_node = node.prev
50
+ next_node = node.next
42
51
 
43
- def delete(key)
44
- if node = @hash[key]
45
- prev_node = node.prev
46
- next_node = node.next
52
+ next_node.prev = prev_node if next_node
53
+ prev_node.next = next_node if prev_node
47
54
 
48
- next_node.prev = prev_node if next_node
49
- prev_node.next = next_node if prev_node
55
+ @first = next_node if @first == node
56
+ @last = prev_node if @last == node
50
57
 
51
- @first = next_node if @first == node
52
- @last = prev_node if @last == node
58
+ value = node.value
59
+ end
53
60
 
54
- value = node.value
61
+ @hash.delete(key)
62
+ value
55
63
  end
56
64
 
57
- @hash.delete(key)
58
- value
59
- end
65
+ def keys
66
+ self.map { |k, v| k }
67
+ end
60
68
 
61
- def keys
62
- self.map { |k, v| k }
63
- end
69
+ def values
70
+ self.map { |k, v| v }
71
+ end
64
72
 
65
- def values
66
- self.map { |k, v| v }
67
- end
73
+ def each
74
+ return unless @first
75
+ yield [@first.key, @first.value]
76
+ node = @first
77
+ yield [node.key, node.value] while node = node.next
78
+ self
79
+ end
68
80
 
69
- def each
70
- return unless @first
71
- yield [@first.key, @first.value]
72
- node = @first
73
- yield [node.key, node.value] while node = node.next
74
- self
75
- end
81
+ def merge(other)
82
+ hash = self.class.new
76
83
 
77
- def merge(other)
78
- hash = self.class.new
84
+ self.each do |key, value|
85
+ hash[key] = value
86
+ end
79
87
 
80
- self.each do |key, value|
81
- hash[key] = value
82
- end
88
+ other.each do |key, value|
89
+ hash[key] = value
90
+ end
83
91
 
84
- other.each do |key, value|
85
- hash[key] = value
92
+ hash
86
93
  end
87
94
 
88
- hash
89
- end
90
-
91
- def empty?
92
- @hash.empty?
95
+ def empty?
96
+ @hash.empty?
97
+ end
93
98
  end
94
99
  end
100
+
95
101
  end
96
102
  end
data/lib/thor/group.rb CHANGED
@@ -63,10 +63,6 @@ class Thor::Group
63
63
  Thor::Group
64
64
  end
65
65
 
66
- def valid_task?(meth) #:nodoc:
67
- public_instance_methods.include?(meth)
68
- end
69
-
70
66
  def create_task(meth) #:nodoc:
71
67
  tasks[meth.to_s] = Thor::Task.new(meth, nil, nil, nil)
72
68
  end
@@ -97,7 +97,7 @@ class Thor
97
97
  method_args = []
98
98
  current = @_invocations[klass]
99
99
 
100
- iterator = lambda do |_, task|
100
+ iterator = proc do |_, task|
101
101
  unless current.include?(task.name)
102
102
  current << task.name
103
103
  task.run(instance, method_args)
@@ -80,7 +80,7 @@ class Thor
80
80
  end
81
81
 
82
82
  def usage(padding=0)
83
- sample = if banner
83
+ sample = if banner && !banner.to_s.empty?
84
84
  "#{switch_name}=#{banner}"
85
85
  else
86
86
  switch_name
data/lib/thor/runner.rb CHANGED
@@ -243,8 +243,7 @@ class Thor::Runner < Thor
243
243
  v[:namespaces] && !(v[:namespaces] & lookup).empty?
244
244
  end
245
245
 
246
- files.map! { |k, v| File.join(thor_root, "#{v[:filename]}") }
247
- files
246
+ files.map { |k, v| File.join(thor_root, "#{v[:filename]}") }
248
247
  end
249
248
 
250
249
  # Display information about the given klasses. If with_module is given,
@@ -60,7 +60,7 @@ class Thor
60
60
  # available.
61
61
  #
62
62
  def show_diff(destination, content)
63
- if diff_lcs_loaded?
63
+ if diff_lcs_loaded? && ENV['THOR_DIFF'].nil? && ENV['RAILS_DIFF'].nil?
64
64
  actual = File.read(destination).to_s.split("\n")
65
65
  content = content.to_s.split("\n")
66
66
 
data/lib/thor/util.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'rbconfig'
2
+
1
3
  class Thor
2
4
  module Sandbox; end
3
5
 
@@ -203,5 +205,19 @@ class Thor
203
205
  ["#{path}/Thorfile", "#{path}/*.thor", "#{path}/tasks/*.thor", "#{path}/lib/tasks/*.thor"]
204
206
  end
205
207
 
208
+ # Return the path to the ruby interpreter taking into account multiple
209
+ # installations and windows extensions.
210
+ #
211
+ def self.ruby_command #:nodoc:
212
+ @ruby_command ||= begin
213
+ ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
214
+ ruby << Config::CONFIG['EXEEXT']
215
+
216
+ # escape string in case path to ruby executable contain spaces.
217
+ ruby.sub!(/.*\s.*/m, '"\&"')
218
+ ruby
219
+ end
220
+ end
221
+
206
222
  end
207
223
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: josevalim-thor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.23
4
+ version: 0.10.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yehuda Katz
@@ -9,11 +9,11 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-02 00:00:00 -07:00
12
+ date: 2009-07-04 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
- description: A gem that maps options to a class
16
+ description: A scripting framework that replaces rake, sake and rubigen
17
17
  email: wycats@gmail.com
18
18
  executables:
19
19
  - thor
@@ -93,6 +93,6 @@ rubyforge_project: thor
93
93
  rubygems_version: 1.2.0
94
94
  signing_key:
95
95
  specification_version: 3
96
- summary: A gem that maps options to a class
96
+ summary: A scripting framework that replaces rake, sake and rubigen
97
97
  test_files: []
98
98