thor 0.12.3 → 0.13.0

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.
@@ -1,5 +1,7 @@
1
1
  == 0.12, released 2010-01-02
2
2
 
3
+ * Methods generated by attr_* are automatically not marked as tasks
4
+ * inject_into_file does not add the same content twice, unless :force is set
3
5
  * Removed rr in favor to rspec mock framework
4
6
  * Improved output for thor -T
5
7
  * [#7] Do not force white color on status
@@ -145,7 +145,7 @@ When invoking the task one:
145
145
 
146
146
  The output is "1 2 3", which means that the three task was invoked only once.
147
147
  You can even invoke tasks from another class, so be sure to check the
148
- documentation.
148
+ documentation[http://rdoc.info/rdoc/wycats/thor/blob/f939a3e8a854616784cac1dcff04ef4f3ee5f7ff/Thor.html].
149
149
 
150
150
  == Thor::Group
151
151
 
@@ -227,7 +227,70 @@ To use them, you just need to include Thor::Actions in your Thor classes:
227
227
 
228
228
  Some actions like copy file requires that a class method called source_root is
229
229
  defined in your class. This is the directory where your templates should be
230
- placed. Be sure to check the documentation.
230
+ placed. Be sure to check the documentation on actions[http://rdoc.info/rdoc/wycats/thor/blob/f939a3e8a854616784cac1dcff04ef4f3ee5f7ff/Thor/Actions.html].
231
+
232
+ == Generators
233
+
234
+ A great use for Thor is creating custom generators. Combining Thor::Group,
235
+ Thor::Actions and ERB templates makes this very easy. Here is an example:
236
+
237
+ class Newgem < Thor::Group
238
+ include Thor::Actions
239
+
240
+ # Define arguments and options
241
+ argument :name
242
+ class_option :test_framework, :default => :test_unit
243
+
244
+ def self.source_root
245
+ File.dirname(__FILE__)
246
+ end
247
+
248
+ def create_lib_file
249
+ template('templates/newgem.tt', "#{name}/lib/#{name}.rb")
250
+ end
251
+
252
+ def create_test_file
253
+ test = options[:test_framework] == "rspec" ? :spec : :test
254
+ create_file "#{name}/#{test}/#{name}_#{test}.rb"
255
+ end
256
+
257
+ def copy_licence
258
+ if yes?("Use MIT license?")
259
+ # Make a copy of the MITLICENSE file at the source root
260
+ copy_file "MITLICENSE", "#{name}/MITLICENSE"
261
+ else
262
+ say "Shame on you…", :red
263
+ end
264
+ end
265
+ end
266
+
267
+ Doing a <tt>thor -T</tt> will show how to run our generator. It should read:
268
+ <tt>thor newgem NAME</tt>. This shows that we have to supply a NAME
269
+ argument for our generator to run.
270
+
271
+ The <tt>create_lib_file</tt> uses an ERB template. This is what it looks like:
272
+
273
+ class <%= name.camelize %>
274
+ end
275
+
276
+ The arguments that you set in your generator will automatically be passed in
277
+ when <tt>template</tt> gets called. Be sure to read the documentation[http://rdoc.info/rdoc/wycats/thor/blob/f939a3e8a854616784cac1dcff04ef4f3ee5f7ff/Thor/Actions.html] for
278
+ more options.
279
+
280
+ Running the generator with <tt>thor newgem devise</tt> will
281
+ create two files: "devise/lib/devise.rb",
282
+ "devise/test/devise_test.rb". The user will then be prompt (with the
283
+ use of the method <tt>yes?</tt>) if he wants to copy the MITLICENSE. If you
284
+ want to change the test framework, you can add the option:
285
+ <tt>thor newgem devise --test-framework=rspec</tt>
286
+ This will generate: "devise/lib/devise.rb" and
287
+ "devise/spec/devise_spec.rb".
288
+
289
+ == Further Reading
290
+
291
+ Thor has many scripting possibilities beyond these examples. Be sure to read
292
+ 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 all the
293
+ options Thor offers.
231
294
 
232
295
  == License
233
296
 
data/Thorfile CHANGED
@@ -4,7 +4,10 @@ require File.join(File.dirname(__FILE__), "lib", "thor", "version")
4
4
  require 'rubygems'
5
5
  require 'thor/rake_compat'
6
6
  require 'spec/rake/spectask'
7
- require 'rdoc/task'
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ end
8
11
 
9
12
  GEM_NAME = 'thor'
10
13
  EXTRA_RDOC_FILES = ["README.rdoc", "LICENSE", "CHANGELOG.rdoc", "VERSION", "Thorfile"]
@@ -26,13 +29,15 @@ class Default < Thor
26
29
  t.rcov_dir = "rcov"
27
30
  end
28
31
 
29
- RDoc::Task.new do |rdoc|
30
- rdoc.main = "README.rdoc"
31
- rdoc.rdoc_dir = "rdoc"
32
- rdoc.title = GEM_NAME
33
- rdoc.rdoc_files.include(*EXTRA_RDOC_FILES)
34
- rdoc.rdoc_files.include('lib/**/*.rb')
35
- rdoc.options << '--line-numbers' << '--inline-source'
32
+ if defined?(RDoc)
33
+ RDoc::Task.new do |rdoc|
34
+ rdoc.main = "README.rdoc"
35
+ rdoc.rdoc_dir = "rdoc"
36
+ rdoc.title = GEM_NAME
37
+ rdoc.rdoc_files.include(*EXTRA_RDOC_FILES)
38
+ rdoc.rdoc_files.include('lib/**/*.rb')
39
+ rdoc.options << '--line-numbers' << '--inline-source'
40
+ end
36
41
  end
37
42
 
38
43
  begin
@@ -1,6 +1,4 @@
1
1
  require 'thor/base'
2
- require 'thor/group'
3
- require 'thor/actions'
4
2
 
5
3
  # TODO: Update thor to allow for git-style CLI (git bisect run)
6
4
  class Thor
@@ -10,7 +10,8 @@ class Thor
10
10
  # destination<String>:: Relative path to the destination root
11
11
  # data<String>:: Data to add to the file. Can be given as a block.
12
12
  # config<Hash>:: give :verbose => false to not log the status and the flag
13
- # for injection (:after or :before).
13
+ # for injection (:after or :before) or :force => true for
14
+ # insert two or more times the same content.
14
15
  #
15
16
  # ==== Examples
16
17
  #
@@ -55,7 +56,7 @@ class Thor
55
56
  replacement + '\0'
56
57
  end
57
58
 
58
- replace!(/#{flag}/, content)
59
+ replace!(/#{flag}/, content, config[:force])
59
60
  end
60
61
 
61
62
  def revoke!
@@ -69,7 +70,7 @@ class Thor
69
70
  /(#{Regexp.escape(replacement)})(.*)(#{flag})/m
70
71
  end
71
72
 
72
- replace!(regexp, content)
73
+ replace!(regexp, content, true)
73
74
  end
74
75
 
75
76
  protected
@@ -88,11 +89,13 @@ class Thor
88
89
 
89
90
  # Adds the content to the file.
90
91
  #
91
- def replace!(regexp, string)
92
+ def replace!(regexp, string, force)
92
93
  unless base.options[:pretend]
93
94
  content = File.binread(destination)
94
- content.gsub!(regexp, string)
95
- File.open(destination, 'wb') { |file| file.write(content) }
95
+ if force || !content.include?(replacement)
96
+ content.gsub!(regexp, string)
97
+ File.open(destination, 'wb') { |file| file.write(content) }
98
+ end
96
99
  end
97
100
  end
98
101
 
@@ -8,6 +8,9 @@ require 'thor/task'
8
8
  require 'thor/util'
9
9
 
10
10
  class Thor
11
+ autoload :Actions, 'thor/actions'
12
+ autoload :RakeCompat, 'thor/rake_compat'
13
+
11
14
  # Shortcuts for help.
12
15
  HELP_MAPPINGS = %w(-h -? --help -D)
13
16
 
@@ -94,6 +97,18 @@ class Thor
94
97
  module ClassMethods
95
98
  attr_accessor :debugging
96
99
 
100
+ def attr_reader(*) #:nodoc:
101
+ no_tasks { super }
102
+ end
103
+
104
+ def attr_writer(*) #:nodoc:
105
+ no_tasks { super }
106
+ end
107
+
108
+ def attr_accessor(*) #:nodoc:
109
+ no_tasks { super }
110
+ end
111
+
97
112
  # Adds an argument to the class and creates an attr_accessor for it.
98
113
  #
99
114
  # Arguments are different from options in several aspects. The first one
@@ -1,8 +1,9 @@
1
+ require 'thor/base'
2
+
1
3
  # Thor has a special class called Thor::Group. The main difference to Thor class
2
4
  # is that it invokes all tasks at once. It also include some methods that allows
3
5
  # invocations to be done at the class method, which are not available to Thor
4
6
  # tasks.
5
- #
6
7
  class Thor::Group
7
8
  class << self
8
9
  # The descrition for this Thor::Group. If none is provided, but a source root
@@ -1,4 +1,5 @@
1
1
  require 'fileutils'
2
+ require 'thor/core_ext/file_binary_read'
2
3
  require 'open-uri'
3
4
  require 'yaml'
4
5
  require 'digest/md5'
@@ -32,7 +33,7 @@ class Thor::Runner < Thor #:nodoc:
32
33
  end
33
34
 
34
35
  desc "install NAME", "Install an optionally named Thor file into your system tasks"
35
- method_options :as => :string, :relative => :boolean
36
+ method_options :as => :string, :relative => :boolean, :force => :boolean
36
37
  def install(name)
37
38
  initialize_thorfiles
38
39
 
@@ -55,7 +56,9 @@ class Thor::Runner < Thor #:nodoc:
55
56
  say "Your Thorfile contains:"
56
57
  say contents
57
58
 
58
- return false if no?("Do you wish to continue [y/N]?")
59
+ unless options["force"]
60
+ return false if no?("Do you wish to continue [y/N]?")
61
+ end
59
62
 
60
63
  as = options["as"] || begin
61
64
  first_line = contents.split("\n")[0]
@@ -1,6 +1,6 @@
1
1
  class Thor
2
2
  class Task < Struct.new(:name, :description, :usage, :options)
3
- FILE_REGEXP = /^#{Regexp.escape(File.expand_path(__FILE__))}:[\w:]+ `run'$/
3
+ FILE_REGEXP = /^#{Regexp.escape(File.dirname(__FILE__))}/
4
4
 
5
5
  # A dynamic task that handles method missing scenarios.
6
6
  class Dynamic < Task
@@ -78,15 +78,15 @@ class Thor
78
78
  (collection & [name.to_s, name.to_sym]).empty?
79
79
  end
80
80
 
81
- # For Ruby <= 1.8.7, we have to match the method name that we are trying to call.
82
- # In Ruby >= 1.9.1, we have to match the method run in this file.
83
- def backtrace_match?(backtrace) #:nodoc:
84
- method_name = /`#{Regexp.escape(name.split(':').last)}'/
85
- backtrace =~ method_name || backtrace =~ FILE_REGEXP
81
+ def sans_backtrace(backtrace, caller) #:nodoc:
82
+ saned = backtrace.reject { |frame| frame =~ FILE_REGEXP }
83
+ saned -= caller
86
84
  end
87
85
 
88
86
  def parse_argument_error(instance, e, caller) #:nodoc:
89
- if e.message =~ /wrong number of arguments/ && backtrace_match?(e.backtrace.first.to_s)
87
+ backtrace = sans_backtrace(e.backtrace, caller)
88
+
89
+ if backtrace.empty? && e.message =~ /wrong number of arguments/
90
90
  if instance.is_a?(Thor::Group)
91
91
  raise e, "'#{name}' was called incorrectly. Are you sure it has arity equals to 0?"
92
92
  else
@@ -1,3 +1,3 @@
1
1
  class Thor
2
- VERSION = "0.12.3".freeze
2
+ VERSION = "0.13.0".freeze
3
3
  end
@@ -55,6 +55,35 @@ describe Thor::Actions::InjectIntoFile do
55
55
  invoke! "doc/README", "\nmore content", :after => "__start__"
56
56
  File.read(file).must == "__start__\nREADME\n__end__\n"
57
57
  end
58
+
59
+ it "does not change the file if already include content" do
60
+ invoke! "doc/README", :before => "__end__" do
61
+ "more content\n"
62
+ end
63
+
64
+ File.read(file).must == "__start__\nREADME\nmore content\n__end__\n"
65
+
66
+ invoke! "doc/README", :before => "__end__" do
67
+ "more content\n"
68
+ end
69
+
70
+ File.read(file).must == "__start__\nREADME\nmore content\n__end__\n"
71
+ end
72
+
73
+ it "does change the file if already include content and :force == true" do
74
+ invoke! "doc/README", :before => "__end__" do
75
+ "more content\n"
76
+ end
77
+
78
+ File.read(file).must == "__start__\nREADME\nmore content\n__end__\n"
79
+
80
+ invoke! "doc/README", :before => "__end__", :force => true do
81
+ "more content\n"
82
+ end
83
+
84
+ File.read(file).must == "__start__\nREADME\nmore content\nmore content\n__end__\n"
85
+ end
86
+
58
87
  end
59
88
 
60
89
  describe "#revoke!" do
@@ -233,4 +233,19 @@ describe Thor::Base do
233
233
  }.must raise_error(Thor::UndefinedTaskError, /the 'what' task of MyScript is private/)
234
234
  end
235
235
  end
236
+
237
+ describe "attr_*" do
238
+ it "should not add attr_reader as a task" do
239
+ capture(:stderr){ MyScript.start(["another_attribute"]) }.must =~ /could not find/
240
+ end
241
+
242
+ it "should not add attr_writer as a task" do
243
+ capture(:stderr){ MyScript.start(["another_attribute=", "foo"]) }.must =~ /could not find/
244
+ end
245
+
246
+ it "should not add attr_accessor as a task" do
247
+ capture(:stderr){ MyScript.start(["some_attribute"]) }.must =~ /could not find/
248
+ capture(:stderr){ MyScript.start(["some_attribute=", "foo"]) }.must =~ /could not find/
249
+ end
250
+ end
236
251
  end
@@ -1,4 +1,8 @@
1
1
  class MyScript < Thor
2
+ attr_accessor :some_attribute
3
+ attr_writer :another_attribute
4
+ attr_reader :another_attribute
5
+
2
6
  group :script
3
7
  default_task :example_default_task
4
8
 
@@ -2,6 +2,7 @@ $TESTING=true
2
2
 
3
3
  $:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
4
4
  require 'thor'
5
+ require 'thor/group'
5
6
  require 'stringio'
6
7
 
7
8
  require 'rubygems'
@@ -133,7 +133,7 @@ describe Thor do
133
133
  end
134
134
 
135
135
  it "raises when an exception happens within the task call" do
136
- lambda { MyScript.start(["call_myself_with_wrong_arity", "--debug"]) }.must raise_error
136
+ lambda { MyScript.start(["call_myself_with_wrong_arity"]) }.must raise_error(ArgumentError)
137
137
  end
138
138
  end
139
139
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.3
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yehuda Katz
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2010-01-18 00:00:00 +01:00
13
+ date: 2010-02-03 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies: []
16
16