Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 308 lines (213 sloc) 10.119 kB
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
1 # Thor
a8de418 @wycats Initial checkin of Hermes
wycats authored
2
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
3 ## Description
606d108 @seeflanigan Add description & installation instructions
seeflanigan authored
4
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
5 Thor is a simple and efficient tool for building self-documenting command line utilities. It removes the pain of parsing command line options, writing "USAGE:" banners, and can also be used as an alternative to the [Rake](http://github.com/jimweirich/rake) build tool. The syntax is Rake-like, so it should be familiar to most Rake users.
606d108 @seeflanigan Add description & installation instructions
seeflanigan authored
6
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
7 ## Installation
606d108 @seeflanigan Add description & installation instructions
seeflanigan authored
8
9 $ gem install thor
10
11 or
12
13 $ gem install wycats-thor -s http://gems.github.com
14
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
15 ## Usage
16
17 Map options to a class. Simply create a class with the appropriate annotations
18 and have options automatically map to functions and parameters.
a8de418 @wycats Initial checkin of Hermes
wycats authored
19
c0cb7aa @mislav allow specifying optional args with default values: method_options(:u…
mislav authored
20 Example:
a8de418 @wycats Initial checkin of Hermes
wycats authored
21
3289ca8 @josevalim Updated README
josevalim authored
22 class App < Thor # [1]
23 map "-L" => :list # [2]
24
25 desc "install APP_NAME", "install one of the available apps" # [3]
26 method_options :force => :boolean, :alias => :string # [4]
a699ed7 @mislav update (incorrect) README and task.thor sample file
mislav authored
27 def install(name)
28 user_alias = options[:alias]
29 if options.force?
a8de418 @wycats Initial checkin of Hermes
wycats authored
30 # do something
31 end
3289ca8 @josevalim Updated README
josevalim authored
32 # other code
a8de418 @wycats Initial checkin of Hermes
wycats authored
33 end
34
35 desc "list [SEARCH]", "list all of the available apps, limited by SEARCH"
3289ca8 @josevalim Updated README
josevalim authored
36 def list(search="")
a8de418 @wycats Initial checkin of Hermes
wycats authored
37 # list everything
38 end
39 end
3289ca8 @josevalim Updated README
josevalim authored
40
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
41 Thor automatically maps commands as such:
a8de418 @wycats Initial checkin of Hermes
wycats authored
42
3289ca8 @josevalim Updated README
josevalim authored
43 thor app:install myname --force
44
a8de418 @wycats Initial checkin of Hermes
wycats authored
45 That gets converted to:
46
3289ca8 @josevalim Updated README
josevalim authored
47 App.new.install("myname")
a699ed7 @mislav update (incorrect) README and task.thor sample file
mislav authored
48 # with {'force' => true} as options hash
a8de418 @wycats Initial checkin of Hermes
wycats authored
49
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
50 1. Inherit from Thor to turn a class into an option mapper.
51 2. Map additional non-valid identifiers to specific methods. In this case, convert -L to :list
52 3. Describe the method immediately below. The first parameter is the usage information, and the second parameter is the description.
53 4. Provide any additional options that will be available the instance method options.
a659385 @josevalim Added rdoc task and checked if a good documentation will be generated.
josevalim authored
54
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
55 ## Types for <tt>method_options</tt>
a659385 @josevalim Added rdoc task and checked if a good documentation will be generated.
josevalim authored
56
57 * :boolean - is parsed as <tt>--option</tt> or <tt>--option=true</tt>
58 * :string - is parsed as <tt>--option=VALUE</tt>
59 * :numeric - is parsed as <tt>--option=N</tt>
60 * :array - is parsed as <tt>--option=one two three</tt>
61 * :hash - is parsed as <tt>--option=name:string age:integer</tt>
a699ed7 @mislav update (incorrect) README and task.thor sample file
mislav authored
62
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
63 Besides, method_option allows a default value to be given. Examples:
3289ca8 @josevalim Updated README
josevalim authored
64
fef8852 @josevalim Improve markdown.
josevalim authored
65 method_options :force => false
66 #=> Creates a boolean option with default value false
3289ca8 @josevalim Updated README
josevalim authored
67
fef8852 @josevalim Improve markdown.
josevalim authored
68 method_options :alias => "bar"
69 #=> Creates a string option with default value "bar"
3289ca8 @josevalim Updated README
josevalim authored
70
fef8852 @josevalim Improve markdown.
josevalim authored
71 method_options :threshold => 3.0
72 #=> Creates a numeric option with default value 3.0
3289ca8 @josevalim Updated README
josevalim authored
73
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
74 You can also supply <tt>:option => :required</tt> to mark an option as required. The
75 type is assumed to be string. If you want a required hash with default values
a659385 @josevalim Added rdoc task and checked if a good documentation will be generated.
josevalim authored
76 as option, you can use <tt>method_option</tt> which uses a more declarative style:
3289ca8 @josevalim Updated README
josevalim authored
77
fef8852 @josevalim Improve markdown.
josevalim authored
78 method_option :attributes, :type => :hash, :default => {}, :required => true
3289ca8 @josevalim Updated README
josevalim authored
79
80 All arguments can be set to nil (except required arguments), by suppling a no or
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
81 skip variant. For example:
3289ca8 @josevalim Updated README
josevalim authored
82
fef8852 @josevalim Improve markdown.
josevalim authored
83 thor app name --no-attributes
3289ca8 @josevalim Updated README
josevalim authored
84
85 In previous versions, aliases for options were created automatically, but now
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
86 they should be explicit. You can supply aliases in both short and declarative
3289ca8 @josevalim Updated README
josevalim authored
87 styles:
88
fef8852 @josevalim Improve markdown.
josevalim authored
89 method_options %w( force -f ) => :boolean
3289ca8 @josevalim Updated README
josevalim authored
90
91 Or:
92
fef8852 @josevalim Improve markdown.
josevalim authored
93 method_option :force, :type => :boolean, :aliases => "-f"
3289ca8 @josevalim Updated README
josevalim authored
94
95 You can supply as many aliases as you want.
96
97 NOTE: Type :optional available in Thor 0.9.0 was deprecated. Use :string or :boolean instead.
98
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
99 ## Namespaces
3289ca8 @josevalim Updated README
josevalim authored
100
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
101 By default, your Thor tasks are invoked using Ruby namespace. In the example
3289ca8 @josevalim Updated README
josevalim authored
102 above, tasks are invoked as:
103
fef8852 @josevalim Improve markdown.
josevalim authored
104 thor app:install name --force
3289ca8 @josevalim Updated README
josevalim authored
105
106 However, you could namespace your class as:
107
fef8852 @josevalim Improve markdown.
josevalim authored
108 module Sinatra
109 class App < Thor
110 # tasks
111 end
112 end
3289ca8 @josevalim Updated README
josevalim authored
113
114 And then you should invoke your tasks as:
115
fef8852 @josevalim Improve markdown.
josevalim authored
116 thor sinatra:app:install name --force
3289ca8 @josevalim Updated README
josevalim authored
117
118 If desired, you can change the namespace:
119
fef8852 @josevalim Improve markdown.
josevalim authored
120 module Sinatra
121 class App < Thor
122 namespace :myapp
123 # tasks
124 end
125 end
3289ca8 @josevalim Updated README
josevalim authored
126
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
127 And then your tasks should be invoked as:
3289ca8 @josevalim Updated README
josevalim authored
128
fef8852 @josevalim Improve markdown.
josevalim authored
129 thor myapp:install name --force
3289ca8 @josevalim Updated README
josevalim authored
130
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
131 ## Invocations
3289ca8 @josevalim Updated README
josevalim authored
132
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
133 Thor comes with a invocation-dependency system as well, which allows a task to be invoked only once. For example:
3289ca8 @josevalim Updated README
josevalim authored
134
fef8852 @josevalim Improve markdown.
josevalim authored
135 class Counter < Thor
136 desc "one", "Prints 1, 2, 3"
137 def one
138 puts 1
139 invoke :two
140 invoke :three
141 end
142
143 desc "two", "Prints 2, 3"
144 def two
145 puts 2
146 invoke :three
147 end
148
149 desc "three", "Prints 3"
150 def three
151 puts 3
152 end
153 end
3289ca8 @josevalim Updated README
josevalim authored
154
155 When invoking the task one:
156
fef8852 @josevalim Improve markdown.
josevalim authored
157 thor counter:one
3289ca8 @josevalim Updated README
josevalim authored
158
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
159 The output is "1 2 3", which means that the three task was invoked only once.
3289ca8 @josevalim Updated README
josevalim authored
160 You can even invoke tasks from another class, so be sure to check the
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
161 [documentation](http://rdoc.info/rdoc/wycats/thor/blob/f939a3e8a854616784cac1dcff04ef4f3ee5f7ff/Thor.html).
3289ca8 @josevalim Updated README
josevalim authored
162
60fb50f @josevalim Improve docs on invoke.
josevalim authored
163 Notice invocations do not share the same object. I.e, Thor will instantiate Counter once to invoke the task one, then, it instantiates another to invoke the task two and another for task three. This happens to allow options and arguments to parsed again. For example, if two and three have different options and both of them were given to the command line, calling invoke makes them be parsed each time and used accordingly by each task.
164
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
165 ## Thor::Group
3289ca8 @josevalim Updated README
josevalim authored
166
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
167 Thor has a special class called Thor::Group. The main difference to Thor class
168 is that it invokes all tasks at once. The example above could be rewritten in
3289ca8 @josevalim Updated README
josevalim authored
169 Thor::Group as this:
170
fef8852 @josevalim Improve markdown.
josevalim authored
171 class Counter < Thor::Group
172 desc "Prints 1, 2, 3"
173
174 def one
175 puts 1
176 end
177
178 def two
179 puts 2
180 end
181
182 def three
183 puts 3
184 end
185 end
3289ca8 @josevalim Updated README
josevalim authored
186
187 When invoked:
188
fef8852 @josevalim Improve markdown.
josevalim authored
189 thor counter
3289ca8 @josevalim Updated README
josevalim authored
190
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
191 It prints "1 2 3" as well. Notice you should describe (using the method <tt>desc</tt>)
192 only the class and not each task anymore. Thor::Group is a great tool to create
a659385 @josevalim Added rdoc task and checked if a good documentation will be generated.
josevalim authored
193 generators, since you can define several steps which are invoked in the order they
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
194 are defined (Thor::Group is the tool use in generators in Rails 3.0).
3289ca8 @josevalim Updated README
josevalim authored
195
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
196 Besides, Thor::Group can parse arguments and options as Thor tasks:
3289ca8 @josevalim Updated README
josevalim authored
197
fef8852 @josevalim Improve markdown.
josevalim authored
198 class Counter < Thor::Group
199 # number will be available as attr_accessor
200 argument :number, :type => :numeric, :desc => "The number to start counting"
201 desc "Prints the 'number' given upto 'number+2'"
202
203 def one
204 puts number + 0
205 end
206
207 def two
208 puts number + 1
209 end
210
211 def three
212 puts number + 2
213 end
214 end
3289ca8 @josevalim Updated README
josevalim authored
215
216 The counter above expects one parameter and has the folling outputs:
217
fef8852 @josevalim Improve markdown.
josevalim authored
218 thor counter 5
219 # Prints "5 6 7"
3289ca8 @josevalim Updated README
josevalim authored
220
fef8852 @josevalim Improve markdown.
josevalim authored
221 thor counter 11
222 # Prints "11 12 13"
3289ca8 @josevalim Updated README
josevalim authored
223
a659385 @josevalim Added rdoc task and checked if a good documentation will be generated.
josevalim authored
224 You can also give options to Thor::Group, but instead of using <tt>method_option</tt>
225 and <tt>method_options</tt>, you should use <tt>class_option</tt> and <tt>class_options</tt>.
226 Both argument and class_options methods are available to Thor class as well.
3289ca8 @josevalim Updated README
josevalim authored
227
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
228 ## Actions
3289ca8 @josevalim Updated README
josevalim authored
229
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
230 Thor comes with several actions which helps with script and generator tasks. You
231 might be familiar with them since some came from Rails Templates. They are:
a659385 @josevalim Added rdoc task and checked if a good documentation will be generated.
josevalim authored
232 <tt>say</tt>, <tt>ask</tt>, <tt>yes?</tt>, <tt>no?</tt>, <tt>add_file</tt>,
233 <tt>remove_file</tt>, <tt>copy_file</tt>, <tt>template</tt>, <tt>directory</tt>,
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
234 <tt>inside</tt>, <tt>run</tt>, <tt>inject_into_file</tt> and a couple more.
3289ca8 @josevalim Updated README
josevalim authored
235
236 To use them, you just need to include Thor::Actions in your Thor classes:
237
fef8852 @josevalim Improve markdown.
josevalim authored
238 class App < Thor
239 include Thor::Actions
240 # tasks
241 end
3289ca8 @josevalim Updated README
josevalim authored
242
243 Some actions like copy file requires that a class method called source_root is
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
244 defined in your class. This is the directory where your templates should be
245 placed. Be sure to check the documentation on [actions](http://rdoc.info/rdoc/wycats/thor/blob/f939a3e8a854616784cac1dcff04ef4f3ee5f7ff/Thor/Actions.html).
f91c69b Adding an example generator, a section on further reading about
Jonathan Hicks authored
246
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
247 ## Generators
f91c69b Adding an example generator, a section on further reading about
Jonathan Hicks authored
248
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
249 A great use for Thor is creating custom generators. Combining Thor::Group,
250 Thor::Actions and ERB templates makes this very easy. Here is an example:
f91c69b Adding an example generator, a section on further reading about
Jonathan Hicks authored
251
649a50e @josevalim Wrap up README changes.
josevalim authored
252 class Newgem < Thor::Group
8287cf6 Spacing
Jonathan Hicks authored
253 include Thor::Actions
254
255 # Define arguments and options
256 argument :name
257 class_option :test_framework, :default => :test_unit
258
259 def self.source_root
260 File.dirname(__FILE__)
261 end
262
263 def create_lib_file
264 template('templates/newgem.tt', "#{name}/lib/#{name}.rb")
265 end
266
267 def create_test_file
268 test = options[:test_framework] == "rspec" ? :spec : :test
269 create_file "#{name}/#{test}/#{name}_#{test}.rb"
270 end
271
272 def copy_licence
649a50e @josevalim Wrap up README changes.
josevalim authored
273 if yes?("Use MIT license?")
8287cf6 Spacing
Jonathan Hicks authored
274 # Make a copy of the MITLICENSE file at the source root
275 copy_file "MITLICENSE", "#{name}/MITLICENSE"
276 else
277 say "Shame on you…", :red
278 end
279 end
280 end
f91c69b Adding an example generator, a section on further reading about
Jonathan Hicks authored
281
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
282 Doing a <tt>thor -T</tt> will show how to run our generator. It should read:
283 <tt>thor newgem NAME</tt>. This shows that we have to supply a NAME
f91c69b Adding an example generator, a section on further reading about
Jonathan Hicks authored
284 argument for our generator to run.
285
286 The <tt>create_lib_file</tt> uses an ERB template. This is what it looks like:
287
ee5d9b5 @josevalim camelize is added by ActiveSupport, so don't use it.
josevalim authored
288 class <%= name.capitalize %>
8287cf6 Spacing
Jonathan Hicks authored
289 end
f91c69b Adding an example generator, a section on further reading about
Jonathan Hicks authored
290
291 The arguments that you set in your generator will automatically be passed in
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
292 when <tt>template</tt> gets called. Be sure to read the [documentation](http://rdoc.info/rdoc/wycats/thor/blob/f939a3e8a854616784cac1dcff04ef4f3ee5f7ff/Thor/Actions.html) for
f91c69b Adding an example generator, a section on further reading about
Jonathan Hicks authored
293 more options.
294
649a50e @josevalim Wrap up README changes.
josevalim authored
295 Running the generator with <tt>thor newgem devise</tt> will
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
296 create two files: "devise/lib/devise.rb", and "devise/test/devise_test.rb". The user will then be asked (via a prompt by the <tt>yes?</tt> method) whether or not they would like to copy the MIT License. If you want to change the test framework, you can add the option: <tt>thor newgem devise --test-framework=rspec</tt>
297
298 This will generate two files - "devise/lib/devise.rb" and "devise/spec/devise_spec.rb".
f91c69b Adding an example generator, a section on further reading about
Jonathan Hicks authored
299
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
300 ## Further Reading
f91c69b Adding an example generator, a section on further reading about
Jonathan Hicks authored
301
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
302 Thor offers many scripting possibilities beyond these examples. Be sure to read
303 through the [documentation](http://rdoc.info/rdoc/wycats/thor/blob/f939a3e8a854616784cac1dcff04ef4f3ee5f7ff/Thor.html) and [specs](http://github.com/wycats/thor/tree/master/spec/) to get a better understanding of the options available.
f91c69b Adding an example generator, a section on further reading about
Jonathan Hicks authored
304
3cf7db3 @seeflanigan Minor documentation tweaks
seeflanigan authored
305 ## License
a699ed7 @mislav update (incorrect) README and task.thor sample file
mislav authored
306
606d108 @seeflanigan Add description & installation instructions
seeflanigan authored
307 Released under the MIT License. See the LICENSE file for further details.
Something went wrong with that request. Please try again.