wycats-thor 0.9.8 → 0.10.26

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,9 +1,32 @@
1
1
  == TODO
2
2
 
3
- * Change Thor.start to parse ARGV in a single pass
4
3
  * Improve spec coverage for Thor::Runner
5
4
  * Improve help output to list shorthand switches, too
6
- * Investigate and fix deep namespacing ("foo:bar:baz") issues
5
+
6
+ == Current
7
+
8
+ * BACKWARDS INCOMPATIBLE: aliases are not generated automatically anymore
9
+ since it wrong behavior to the invocation system.
10
+
11
+ * thor help now show information about any class/task. All those calls are
12
+ possible:
13
+
14
+ thor help describe
15
+ thor help describe:amazing
16
+
17
+ Or even with default namespaces:
18
+
19
+ thor help :spec
20
+
21
+ * Thor::Runner now invokes the default task if none is supplied:
22
+
23
+ thor describe # invokes the default task, usually help
24
+
25
+ * Thor::Runner now works with mappings:
26
+
27
+ thor describe -h
28
+
29
+ * Added some documentation and code refactoring.
7
30
 
8
31
  == 0.9.8, released 2008-10-20
9
32
 
@@ -49,4 +72,4 @@
49
72
  * Thor::Options now doesn't parse through things that look like options but aren't.
50
73
  * Add URI detection to install task, and make sure we don't append ".thor" to URIs
51
74
  * Add rake2thor to the gem binfiles.
52
- * Make sure local Thorfiles override system-wide ones.
75
+ * Make sure local Thorfiles override system-wide ones.
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</code></dt>
52
- <dd>same as <code>:boolean</code></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/bin/rake2thor CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'ruby2ruby'
5
+ require 'parse_tree'
6
+ if Ruby2Ruby::VERSION >= "1.2.0"
7
+ require 'parse_tree_extensions'
8
+ end
5
9
  require 'rake'
6
10
 
7
11
  input = ARGV[0] || 'Rakefile'
data/bin/thor CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- mode: ruby -*-
3
3
 
4
- require File.dirname(__FILE__) + "/../lib/thor"
4
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'thor')
5
5
  require 'thor/runner'
6
6
 
7
7
  Thor::Runner.start
@@ -0,0 +1,32 @@
1
+ require 'thor/actions/templater'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Copies the file from the relative source to the relative destination. If
7
+ # the destination is not given it's assumed to be equal to the source.
8
+ #
9
+ # ==== Parameters
10
+ # source<String>:: the relative path to the source root
11
+ # destination<String>:: the relative path to the destination root
12
+ # log_status<Boolean>:: if false, does not log the status. True by default.
13
+ #
14
+ # ==== Examples
15
+ #
16
+ # copy_file "README", "doc/README"
17
+ #
18
+ # copy_file "doc/README"
19
+ #
20
+ def copy_file(source, destination=nil, log_status=true)
21
+ action CopyFile.new(self, source, destination || source, log_status)
22
+ end
23
+
24
+ class CopyFile < Templater #:nodoc:
25
+
26
+ def render
27
+ @render ||= ::File.read(source)
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,49 @@
1
+ require 'thor/actions/templater'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Create a new file relative to the destination root with the given data,
7
+ # which is the return value of a block or a data string.
8
+ #
9
+ # ==== Parameters
10
+ # destination<String>:: the relative path to the destination root.
11
+ # data<String|NilClass>:: the data to append to the file.
12
+ # log_status<Boolean>:: if false, does not log the status. True by default.
13
+ #
14
+ # ==== Examples
15
+ #
16
+ # create_file "lib/fun_party.rb" do
17
+ # hostname = ask("What is the virtual hostname I should use?")
18
+ # "vhost.name = #{hostname}"
19
+ # end
20
+ #
21
+ # create_file "config/apach.conf", "your apache config"
22
+ #
23
+ def create_file(destination, data=nil, log_status=true, &block)
24
+ action CreateFile.new(self, destination, block || data.to_s, log_status)
25
+ end
26
+ alias :add_file :create_file
27
+
28
+ # AddFile is a subset of Template, which instead of rendering a file with
29
+ # ERB, it gets the content from the user.
30
+ #
31
+ class CreateFile < Templater #:nodoc:
32
+ attr_reader :data
33
+
34
+ def initialize(base, destination, data, log_status)
35
+ super(base, nil, destination, log_status)
36
+ @data = data
37
+ end
38
+
39
+ def render
40
+ @render ||= if data.is_a?(Proc)
41
+ data.call
42
+ else
43
+ data
44
+ end
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,76 @@
1
+ require 'thor/actions/templater'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Copies interactively the files from source directory to root directory.
7
+ # If any of the files finishes with .tt, it's considered to be a template
8
+ # and is placed in the destination without the extension .tt. If any
9
+ # empty directory is found, it's copied and all .empty_directory files are
10
+ # ignored. Remember that file paths can also be encoded, let's suppose a doc
11
+ # directory with the following files:
12
+ #
13
+ # doc/
14
+ # components/.empty_directory
15
+ # README
16
+ # rdoc.rb.tt
17
+ # %app_name%.rb
18
+ #
19
+ # When invoked as:
20
+ #
21
+ # directory "doc"
22
+ #
23
+ # It will create a doc directory in the destination with the following
24
+ # files (assuming that the app_name is "blog"):
25
+ #
26
+ # doc/
27
+ # components/
28
+ # README
29
+ # rdoc.rb
30
+ # blog.rb
31
+ #
32
+ # ==== Parameters
33
+ # source<String>:: the relative path to the source root
34
+ # destination<String>:: the relative path to the destination root
35
+ # recursive<Boolean>:: if the directory must be copied recursively, true by default
36
+ # log_status<Boolean>:: if false, does not log the status. True by default.
37
+ #
38
+ # ==== Examples
39
+ #
40
+ # directory "doc"
41
+ # directory "doc", "docs", false
42
+ #
43
+ def directory(source, destination=nil, recursive=true, log_status=true)
44
+ action Directory.new(self, source, destination || source, recursive, log_status)
45
+ end
46
+
47
+ class Directory < Templater #:nodoc:
48
+ attr_reader :recursive
49
+
50
+ def initialize(base, source, destination=nil, recursive=true, log_status=true)
51
+ @recursive = recursive
52
+ super(base, source, destination, log_status)
53
+ end
54
+
55
+ def invoke!
56
+ base.empty_directory given_destination
57
+ lookup = recursive ? File.join(source, '**', '*') : File.join(source, '*')
58
+
59
+ Dir[lookup].each do |file_source|
60
+ file_destination = File.join(given_destination, file_source.gsub(source, '.'))
61
+
62
+ if File.directory?(file_source)
63
+ base.empty_directory(file_destination, @log_status) if recursive
64
+ elsif file_source !~ /\.empty_directory$/
65
+ if file_source =~ /\.tt$/
66
+ base.template(file_source, file_destination[0..-4], @log_status)
67
+ else
68
+ base.copy_file(file_source, file_destination, @log_status)
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ end
75
+ end
76
+ end