thor 0.14.4 → 0.14.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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