thor 0.14.4 → 0.14.5

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,3 +1,14 @@
1
+ == 0.14, released 2010-07-25
2
+ * Added CreateLink class and #link_file method
3
+ * Made Thor::Actions#run use system as default method for system calls
4
+ * Allow use of private methods from superclass as tasks
5
+ * Added mute(&block) method which allows to run block without any output
6
+ * Removed config[:pretend]
7
+ * Enabled underscores for command line switches
8
+ * Added Thor::Base.basename which is used by both Thor.banner and Thor::Group.banner
9
+ * Deprecated invoke() without arguments
10
+ * Added :only and :except to check_unknown_options
11
+
1
12
  == 0.13, released 2010-02-03
2
13
 
3
14
  * Added :lazy_default which is only triggered if a switch is given
data/Thorfile CHANGED
@@ -1,70 +1,24 @@
1
1
  # enconding: utf-8
2
-
3
- require File.join(File.dirname(__FILE__), "lib", "thor", "version")
4
- require 'rubygems'
5
2
  require 'thor/rake_compat'
6
- require 'spec/rake/spectask'
7
- begin
8
- require 'rdoc/task'
9
- rescue LoadError
10
- end
11
-
12
- GEM_NAME = 'thor'
13
- EXTRA_RDOC_FILES = ["README.md", "LICENSE", "CHANGELOG.rdoc", "Thorfile"]
14
3
 
15
4
  class Default < Thor
16
5
  include Thor::RakeCompat
17
6
 
18
- Spec::Rake::SpecTask.new(:spec) do |t|
19
- t.libs << 'lib'
20
- t.spec_opts = ['--options', "spec/spec.opts"]
21
- t.spec_files = FileList['spec/**/*_spec.rb']
22
- end
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new(:spec)
23
9
 
24
- Spec::Rake::SpecTask.new(:rcov) do |t|
25
- t.libs << 'lib'
26
- t.spec_opts = ['--options', "spec/spec.opts"]
27
- t.spec_files = FileList['spec/**/*_spec.rb']
28
- t.rcov = true
29
- t.rcov_dir = "rcov"
30
- end
10
+ require 'bundler'
11
+ Bundler::GemHelper.install_tasks
31
12
 
13
+ require 'rdoc/task'
32
14
  if defined?(RDoc)
33
15
  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)
16
+ rdoc.main = 'README.md'
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'thor'
19
+ rdoc.rdoc_files.include('README.md', 'LICENSE', 'CHANGELOG.rdoc', 'Thorfile')
38
20
  rdoc.rdoc_files.include('lib/**/*.rb')
39
21
  rdoc.options << '--line-numbers' << '--inline-source'
40
22
  end
41
23
  end
42
-
43
- begin
44
- require 'jeweler'
45
- Jeweler::Tasks.new do |s|
46
- s.name = GEM_NAME
47
- s.version = Thor::VERSION.dup
48
- s.rubyforge_project = "textmate"
49
- s.platform = Gem::Platform::RUBY
50
- s.summary = "A scripting framework that replaces rake, sake and rubigen"
51
- s.email = "ruby-thor@googlegroups.com"
52
- s.homepage = "http://yehudakatz.com"
53
- s.description = "A scripting framework that replaces rake, sake and rubigen"
54
- s.authors = ['Yehuda Katz', 'José Valim']
55
- s.has_rdoc = true
56
- s.extra_rdoc_files = EXTRA_RDOC_FILES
57
- s.require_path = 'lib'
58
- s.bindir = "bin"
59
- s.executables = %w( thor rake2thor )
60
- s.files = s.extra_rdoc_files + Dir.glob("{bin,lib}/**/*")
61
- s.test_files.include 'spec/**/*'
62
- s.test_files.include 'spec/fixtures/doc/components/.empty_directory'
63
- s.test_files.exclude 'spec/sandbox/**/*'
64
- end
65
-
66
- Jeweler::GemcutterTasks.new
67
- rescue LoadError
68
- puts "Jeweler, or one of its dependencies, is not available. Install it with: gem install jeweler"
69
- end
70
24
  end
@@ -18,6 +18,23 @@ class Thor
18
18
  end
19
19
  end
20
20
 
21
+ # Registers another Thor subclass as a command.
22
+ #
23
+ # ==== Parameters
24
+ # klass<Class>:: Thor subclass to register
25
+ # command<String>:: Subcommand name to use
26
+ # usage<String>:: Short usage for the subcommand
27
+ # description<String>:: Description for the subcommand
28
+ def register(klass, subcommand_name, usage, description, options={})
29
+ if klass <= Thor::Group
30
+ desc usage, description, options
31
+ define_method(subcommand_name) { invoke klass }
32
+ else
33
+ desc usage, description, options
34
+ subcommand subcommand_name, klass
35
+ end
36
+ end
37
+
21
38
  # Defines the usage and the description of the next task.
22
39
  #
23
40
  # ==== Parameters
@@ -168,7 +168,7 @@ class Thor
168
168
  if !File.exist?(destination_root) && !pretend
169
169
  FileUtils.mkdir_p(destination_root)
170
170
  end
171
-
171
+
172
172
  if pretend
173
173
  # In pretend mode, just yield down to the block
174
174
  block.arity == 1 ? yield(destination_root) : yield
@@ -220,7 +220,7 @@ class Thor
220
220
  #
221
221
  # ==== Parameters
222
222
  # command<String>:: the command to be executed.
223
- # config<Hash>:: give :verbose => false to not log the status. Specify :with
223
+ # config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output. Specify :with
224
224
  # to append an executable to command executation.
225
225
  #
226
226
  # ==== Example
@@ -241,7 +241,10 @@ class Thor
241
241
  end
242
242
 
243
243
  say_status :run, desc, config.fetch(:verbose, true)
244
- `#{command}` unless options[:pretend]
244
+
245
+ unless options[:pretend]
246
+ config[:capture] ? `#{command}` : system("#{command}")
247
+ end
245
248
  end
246
249
 
247
250
  # Executes a ruby script (taking into account WIN32 platform quirks).
@@ -261,8 +264,9 @@ class Thor
261
264
  # ==== Parameters
262
265
  # task<String>:: the task to be invoked
263
266
  # args<Array>:: arguments to the task
264
- # config<Hash>:: give :verbose => false to not log the status. Other options
265
- # are given as parameter to Thor.
267
+ # config<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output.
268
+ # Other options are given as parameter to Thor.
269
+ #
266
270
  #
267
271
  # ==== Examples
268
272
  #
@@ -276,12 +280,13 @@ class Thor
276
280
  config = args.last.is_a?(Hash) ? args.pop : {}
277
281
  verbose = config.key?(:verbose) ? config.delete(:verbose) : true
278
282
  pretend = config.key?(:pretend) ? config.delete(:pretend) : false
283
+ capture = config.key?(:capture) ? config.delete(:capture) : false
279
284
 
280
285
  args.unshift task
281
286
  args.push Thor::Options.to_switches(config)
282
287
  command = args.join(' ').strip
283
288
 
284
- run command, :with => :thor, :verbose => verbose, :pretend => pretend
289
+ run command, :with => :thor, :verbose => verbose, :pretend => pretend, :capture => capture
285
290
  end
286
291
 
287
292
  protected
@@ -18,7 +18,7 @@ class Thor
18
18
  # "vhost.name = #{hostname}"
19
19
  # end
20
20
  #
21
- # create_file "config/apach.conf", "your apache config"
21
+ # create_file "config/apache.conf", "your apache config"
22
22
  #
23
23
  def create_file(destination, *args, &block)
24
24
  config = args.last.is_a?(Hash) ? args.pop : {}
@@ -27,7 +27,7 @@ class Thor
27
27
  end
28
28
  alias :add_file :create_file
29
29
 
30
- # AddFile is a subset of Template, which instead of rendering a file with
30
+ # CreateFile is a subset of Template, which instead of rendering a file with
31
31
  # ERB, it gets the content from the user.
32
32
  #
33
33
  class CreateFile < EmptyDirectory #:nodoc:
@@ -0,0 +1,57 @@
1
+ require 'thor/actions/empty_directory'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Create a new file relative to the destination root from the given source.
7
+ #
8
+ # ==== Parameters
9
+ # destination<String>:: the relative path to the destination root.
10
+ # source<String|NilClass>:: the relative path to the source root.
11
+ # config<Hash>:: give :verbose => false to not log the status.
12
+ # :: give :symbolic => false for hard link.
13
+ #
14
+ # ==== Examples
15
+ #
16
+ # create_link "config/apache.conf", "/etc/apache.conf"
17
+ #
18
+ def create_link(destination, *args, &block)
19
+ config = args.last.is_a?(Hash) ? args.pop : {}
20
+ source = args.first
21
+ action CreateLink.new(self, destination, source, config)
22
+ end
23
+ alias :add_link :create_link
24
+
25
+ # CreateLink is a subset of CreateFile, which instead of taking a block of
26
+ # data, just takes a source string from the user.
27
+ #
28
+ class CreateLink < CreateFile #:nodoc:
29
+ attr_reader :data
30
+
31
+ # Checks if the content of the file at the destination is identical to the rendered result.
32
+ #
33
+ # ==== Returns
34
+ # Boolean:: true if it is identical, false otherwise.
35
+ #
36
+ def identical?
37
+ exists? && File.identical?(render, destination)
38
+ end
39
+
40
+ def invoke!
41
+ invoke_with_conflict_check do
42
+ FileUtils.mkdir_p(File.dirname(destination))
43
+ # Create a symlink by default
44
+ config[:symbolic] ||= true
45
+ File.unlink(destination) if exists?
46
+ if config[:symbolic]
47
+ File.symlink(render, destination)
48
+ else
49
+ File.link(render, destination)
50
+ end
51
+ end
52
+ given_destination
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -30,6 +30,28 @@ class Thor
30
30
  end
31
31
  end
32
32
 
33
+ # Links the file from the relative source to the relative destination. If
34
+ # the destination is not given it's assumed to be equal to the source.
35
+ #
36
+ # ==== Parameters
37
+ # source<String>:: the relative path to the source root.
38
+ # destination<String>:: the relative path to the destination root.
39
+ # config<Hash>:: give :verbose => false to not log the status.
40
+ #
41
+ # ==== Examples
42
+ #
43
+ # link_file "README", "doc/README"
44
+ #
45
+ # link_file "doc/README"
46
+ #
47
+ def link_file(source, *args, &block)
48
+ config = args.last.is_a?(Hash) ? args.pop : {}
49
+ destination = args.first || source
50
+ source = File.expand_path(find_in_source_paths(source.to_s))
51
+
52
+ create_link destination, source, config
53
+ end
54
+
33
55
  # Gets the content at the given address and places it at the given relative
34
56
  # destination. If a block is given instead of destination, the content of
35
57
  # the url is yielded and used as location.
@@ -110,7 +132,7 @@ class Thor
110
132
  FileUtils.chmod_R(mode, path) unless options[:pretend]
111
133
  end
112
134
 
113
- # Prepend text to a file. Since it depends on inject_into_file, it's reversible.
135
+ # Prepend text to a file. Since it depends on insert_into_file, it's reversible.
114
136
  #
115
137
  # ==== Parameters
116
138
  # path<String>:: path of the file to be changed
@@ -119,19 +141,20 @@ class Thor
119
141
  #
120
142
  # ==== Example
121
143
  #
122
- # prepend_file 'config/environments/test.rb', 'config.gem "rspec"'
144
+ # prepend_to_file 'config/environments/test.rb', 'config.gem "rspec"'
123
145
  #
124
- # prepend_file 'config/environments/test.rb' do
146
+ # prepend_to_file 'config/environments/test.rb' do
125
147
  # 'config.gem "rspec"'
126
148
  # end
127
149
  #
128
- def prepend_file(path, *args, &block)
150
+ def prepend_to_file(path, *args, &block)
129
151
  config = args.last.is_a?(Hash) ? args.pop : {}
130
152
  config.merge!(:after => /\A/)
131
- inject_into_file(path, *(args << config), &block)
153
+ insert_into_file(path, *(args << config), &block)
132
154
  end
155
+ alias_method :prepend_file, :prepend_to_file
133
156
 
134
- # Append text to a file. Since it depends on inject_into_file, it's reversible.
157
+ # Append text to a file. Since it depends on insert_into_file, it's reversible.
135
158
  #
136
159
  # ==== Parameters
137
160
  # path<String>:: path of the file to be changed
@@ -140,20 +163,21 @@ class Thor
140
163
  #
141
164
  # ==== Example
142
165
  #
143
- # append_file 'config/environments/test.rb', 'config.gem "rspec"'
166
+ # append_to_file 'config/environments/test.rb', 'config.gem "rspec"'
144
167
  #
145
- # append_file 'config/environments/test.rb' do
168
+ # append_to_file 'config/environments/test.rb' do
146
169
  # 'config.gem "rspec"'
147
170
  # end
148
171
  #
149
- def append_file(path, *args, &block)
172
+ def append_to_file(path, *args, &block)
150
173
  config = args.last.is_a?(Hash) ? args.pop : {}
151
174
  config.merge!(:before => /\z/)
152
- inject_into_file(path, *(args << config), &block)
175
+ insert_into_file(path, *(args << config), &block)
153
176
  end
177
+ alias_method :append_file, :append_to_file
154
178
 
155
179
  # Injects text right after the class definition. Since it depends on
156
- # inject_into_file, it's reversible.
180
+ # insert_into_file, it's reversible.
157
181
  #
158
182
  # ==== Parameters
159
183
  # path<String>:: path of the file to be changed
@@ -172,7 +196,7 @@ class Thor
172
196
  def inject_into_class(path, klass, *args, &block)
173
197
  config = args.last.is_a?(Hash) ? args.pop : {}
174
198
  config.merge!(:after => /class #{klass}\n|class #{klass} .*\n/)
175
- inject_into_file(path, *(args << config), &block)
199
+ insert_into_file(path, *(args << config), &block)
176
200
  end
177
201
 
178
202
  # Run a regular expression replacement on a file.
@@ -10,19 +10,19 @@ 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) or :force => true for
13
+ # for injection (:after or :before) or :force => true for
14
14
  # insert two or more times the same content.
15
- #
15
+ #
16
16
  # ==== Examples
17
17
  #
18
- # inject_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
18
+ # insert_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
19
19
  #
20
- # inject_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
20
+ # insert_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
21
21
  # gems = ask "Which gems would you like to add?"
22
22
  # gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
23
23
  # end
24
24
  #
25
- def inject_into_file(destination, *args, &block)
25
+ def insert_into_file(destination, *args, &block)
26
26
  if block_given?
27
27
  data, config = block, args.shift
28
28
  else
@@ -30,6 +30,7 @@ class Thor
30
30
  end
31
31
  action InjectIntoFile.new(self, destination, data, config)
32
32
  end
33
+ alias_method :inject_into_file, :insert_into_file
33
34
 
34
35
  class InjectIntoFile < EmptyDirectory #:nodoc:
35
36
  attr_reader :replacement, :flag, :behavior
@@ -76,12 +77,16 @@ class Thor
76
77
  protected
77
78
 
78
79
  def say_status(behavior)
79
- status = if flag == /\A/
80
- behavior == :invoke ? :prepend : :unprepend
81
- elsif flag == /\z/
82
- behavior == :invoke ? :append : :unappend
80
+ status = if behavior == :invoke
81
+ if flag == /\A/
82
+ :prepend
83
+ elsif flag == /\z/
84
+ :append
85
+ else
86
+ :insert
87
+ end
83
88
  else
84
- behavior == :invoke ? :inject : :deinject
89
+ :subtract
85
90
  end
86
91
 
87
92
  super(status, config[:verbose])
@@ -37,7 +37,7 @@ class Thor
37
37
  # string (--foo=value) or booleans (just --foo).
38
38
  #
39
39
  # By default all options are optional, unless :required is given.
40
- #
40
+ #
41
41
  def self.parse(key, value)
42
42
  if key.is_a?(Array)
43
43
  name, *aliases = key
@@ -111,4 +111,4 @@ class Thor
111
111
  end
112
112
  end
113
113
  end
114
- end
114
+ end
@@ -1,3 +1,3 @@
1
1
  class Thor
2
- VERSION = "0.14.4".freeze
2
+ VERSION = "0.14.5".freeze
3
3
  end
@@ -30,36 +30,36 @@ describe Thor::Actions::CreateFile do
30
30
  it "creates a file" do
31
31
  create_file("doc/config.rb")
32
32
  invoke!
33
- File.exists?(File.join(destination_root, "doc/config.rb")).must be_true
33
+ File.exists?(File.join(destination_root, "doc/config.rb")).should be_true
34
34
  end
35
35
 
36
36
  it "does not create a file if pretending" do
37
37
  create_file("doc/config.rb", {}, :pretend => true)
38
38
  invoke!
39
- File.exists?(File.join(destination_root, "doc/config.rb")).must be_false
39
+ File.exists?(File.join(destination_root, "doc/config.rb")).should be_false
40
40
  end
41
41
 
42
42
  it "shows created status to the user" do
43
43
  create_file("doc/config.rb")
44
- invoke!.must == " create doc/config.rb\n"
44
+ invoke!.should == " create doc/config.rb\n"
45
45
  end
46
46
 
47
47
  it "does not show any information if log status is false" do
48
48
  silence!
49
49
  create_file("doc/config.rb")
50
- invoke!.must be_empty
50
+ invoke!.should be_empty
51
51
  end
52
52
 
53
53
  it "returns the given destination" do
54
54
  capture(:stdout) do
55
- create_file("doc/config.rb").invoke!.must == "doc/config.rb"
55
+ create_file("doc/config.rb").invoke!.should == "doc/config.rb"
56
56
  end
57
57
  end
58
58
 
59
59
  it "converts encoded instructions" do
60
60
  create_file("doc/%file_name%.rb.tt")
61
61
  invoke!
62
- File.exists?(File.join(destination_root, "doc/rdoc.rb.tt")).must be_true
62
+ File.exists?(File.join(destination_root, "doc/rdoc.rb.tt")).should be_true
63
63
  end
64
64
 
65
65
  describe "when file exists" do
@@ -72,7 +72,7 @@ describe Thor::Actions::CreateFile do
72
72
  it "shows identical status" do
73
73
  create_file("doc/config.rb")
74
74
  invoke!
75
- invoke!.must == " identical doc/config.rb\n"
75
+ invoke!.should == " identical doc/config.rb\n"
76
76
  end
77
77
  end
78
78
 
@@ -82,46 +82,46 @@ describe Thor::Actions::CreateFile do
82
82
  end
83
83
 
84
84
  it "shows forced status to the user if force is given" do
85
- create_file("doc/config.rb", {}, :force => true).must_not be_identical
86
- invoke!.must == " force doc/config.rb\n"
85
+ create_file("doc/config.rb", {}, :force => true).should_not be_identical
86
+ invoke!.should == " force doc/config.rb\n"
87
87
  end
88
88
 
89
89
  it "shows skipped status to the user if skip is given" do
90
- create_file("doc/config.rb", {}, :skip => true).must_not be_identical
91
- invoke!.must == " skip doc/config.rb\n"
90
+ create_file("doc/config.rb", {}, :skip => true).should_not be_identical
91
+ invoke!.should == " skip doc/config.rb\n"
92
92
  end
93
93
 
94
94
  it "shows forced status to the user if force is configured" do
95
- create_file("doc/config.rb", :force => true).must_not be_identical
96
- invoke!.must == " force doc/config.rb\n"
95
+ create_file("doc/config.rb", :force => true).should_not be_identical
96
+ invoke!.should == " force doc/config.rb\n"
97
97
  end
98
98
 
99
99
  it "shows skipped status to the user if skip is configured" do
100
- create_file("doc/config.rb", :skip => true).must_not be_identical
101
- invoke!.must == " skip doc/config.rb\n"
100
+ create_file("doc/config.rb", :skip => true).should_not be_identical
101
+ invoke!.should == " skip doc/config.rb\n"
102
102
  end
103
103
 
104
104
  it "shows conflict status to ther user" do
105
- create_file("doc/config.rb").must_not be_identical
105
+ create_file("doc/config.rb").should_not be_identical
106
106
  $stdin.should_receive(:gets).and_return('s')
107
107
  file = File.join(destination_root, 'doc/config.rb')
108
108
 
109
109
  content = invoke!
110
- content.must =~ /conflict doc\/config\.rb/
111
- content.must =~ /Overwrite #{file}\? \(enter "h" for help\) \[Ynaqdh\]/
112
- content.must =~ /skip doc\/config\.rb/
110
+ content.should =~ /conflict doc\/config\.rb/
111
+ content.should =~ /Overwrite #{file}\? \(enter "h" for help\) \[Ynaqdh\]/
112
+ content.should =~ /skip doc\/config\.rb/
113
113
  end
114
114
 
115
115
  it "creates the file if the file collision menu returns true" do
116
116
  create_file("doc/config.rb")
117
117
  $stdin.should_receive(:gets).and_return('y')
118
- invoke!.must =~ /force doc\/config\.rb/
118
+ invoke!.should =~ /force doc\/config\.rb/
119
119
  end
120
120
 
121
121
  it "skips the file if the file collision menu returns false" do
122
122
  create_file("doc/config.rb")
123
123
  $stdin.should_receive(:gets).and_return('n')
124
- invoke!.must =~ /skip doc\/config\.rb/
124
+ invoke!.should =~ /skip doc\/config\.rb/
125
125
  end
126
126
 
127
127
  it "executes the block given to show file content" do
@@ -140,31 +140,31 @@ describe Thor::Actions::CreateFile do
140
140
  create_file("doc/config.rb")
141
141
  invoke!
142
142
  revoke!
143
- File.exists?(@action.destination).must be_false
143
+ File.exists?(@action.destination).should be_false
144
144
  end
145
145
 
146
146
  it "does not raise an error if the file does not exist" do
147
147
  create_file("doc/config.rb")
148
148
  revoke!
149
- File.exists?(@action.destination).must be_false
149
+ File.exists?(@action.destination).should be_false
150
150
  end
151
151
  end
152
152
 
153
153
  describe "#exists?" do
154
154
  it "returns true if the destination file exists" do
155
155
  create_file("doc/config.rb")
156
- @action.exists?.must be_false
156
+ @action.exists?.should be_false
157
157
  invoke!
158
- @action.exists?.must be_true
158
+ @action.exists?.should be_true
159
159
  end
160
160
  end
161
161
 
162
162
  describe "#identical?" do
163
163
  it "returns true if the destination file and is identical" do
164
164
  create_file("doc/config.rb")
165
- @action.identical?.must be_false
165
+ @action.identical?.should be_false
166
166
  invoke!
167
- @action.identical?.must be_true
167
+ @action.identical?.should be_true
168
168
  end
169
169
  end
170
170
  end