thor 0.11.5 → 0.11.8
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.
- data/Thorfile +8 -2
- data/bin/rake2thor +0 -1
- data/bin/thor +1 -1
- data/lib/thor/actions/directory.rb +3 -1
- data/lib/thor/actions/file_manipulation.rb +41 -17
- data/lib/thor/actions/inject_into_file.rb +43 -20
- data/lib/thor/actions.rb +16 -15
- data/lib/thor/base.rb +7 -0
- data/lib/thor/invocation.rb +1 -1
- data/lib/thor/rake_compat.rb +5 -6
- data/lib/thor/runner.rb +5 -1
- data/lib/thor/shell/basic.rb +2 -3
- data/lib/thor/shell.rb +8 -2
- data/lib/thor/task.rb +13 -7
- data/lib/thor/util.rb +10 -9
- data/lib/thor/version.rb +3 -0
- data/lib/thor.rb +1 -2
- data/spec/actions/directory_spec.rb +5 -0
- data/spec/actions/file_manipulation_spec.rb +25 -18
- data/spec/actions/inject_into_file_spec.rb +30 -4
- data/spec/fixtures/application.rb +2 -0
- data/spec/rake_compat_spec.rb +4 -0
- data/spec/runner_spec.rb +2 -2
- data/spec/shell/basic_spec.rb +5 -0
- data/spec/spec_helper.rb +2 -2
- data/spec/task_spec.rb +10 -4
- metadata +5 -5
- data/VERSION +0 -1
data/Thorfile
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# enconding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.join(File.dirname(__FILE__), "lib", "thor", "version")
|
|
2
4
|
require 'thor/rake_compat'
|
|
3
5
|
require 'spec/rake/spectask'
|
|
4
6
|
require 'rdoc/task'
|
|
@@ -10,11 +12,13 @@ class Default < Thor
|
|
|
10
12
|
include Thor::RakeCompat
|
|
11
13
|
|
|
12
14
|
Spec::Rake::SpecTask.new(:spec) do |t|
|
|
15
|
+
t.libs << 'lib'
|
|
13
16
|
t.spec_opts = ['--options', "spec/spec.opts"]
|
|
14
17
|
t.spec_files = FileList['spec/**/*_spec.rb']
|
|
15
18
|
end
|
|
16
19
|
|
|
17
20
|
Spec::Rake::SpecTask.new(:rcov) do |t|
|
|
21
|
+
t.libs << 'lib'
|
|
18
22
|
t.spec_opts = ['--options', "spec/spec.opts"]
|
|
19
23
|
t.spec_files = FileList['spec/**/*_spec.rb']
|
|
20
24
|
t.rcov = true
|
|
@@ -34,7 +38,7 @@ class Default < Thor
|
|
|
34
38
|
require 'jeweler'
|
|
35
39
|
Jeweler::Tasks.new do |s|
|
|
36
40
|
s.name = GEM_NAME
|
|
37
|
-
s.version =
|
|
41
|
+
s.version = Thor::VERSION
|
|
38
42
|
s.rubyforge_project = "textmate"
|
|
39
43
|
s.platform = Gem::Platform::RUBY
|
|
40
44
|
s.summary = "A scripting framework that replaces rake, sake and rubigen"
|
|
@@ -51,6 +55,8 @@ class Default < Thor
|
|
|
51
55
|
s.files.exclude 'spec/sandbox/**/*'
|
|
52
56
|
s.test_files.exclude 'spec/sandbox/**/*'
|
|
53
57
|
end
|
|
58
|
+
|
|
59
|
+
Jeweler::RubyforgeTasks.new
|
|
54
60
|
rescue LoadError
|
|
55
61
|
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
|
56
62
|
end
|
data/bin/rake2thor
CHANGED
data/bin/thor
CHANGED
|
@@ -73,7 +73,9 @@ class Thor
|
|
|
73
73
|
|
|
74
74
|
case file_source
|
|
75
75
|
when /\.empty_directory$/
|
|
76
|
-
|
|
76
|
+
dirname = File.dirname(file_destination).gsub(/\/\.$/, '')
|
|
77
|
+
next if dirname == given_destination
|
|
78
|
+
base.empty_directory(dirname, config)
|
|
77
79
|
when /\.tt$/
|
|
78
80
|
base.template(file_source, file_destination[0..-4], config)
|
|
79
81
|
else
|
|
@@ -100,7 +100,7 @@ class Thor
|
|
|
100
100
|
FileUtils.chmod_R(mode, path) unless options[:pretend]
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
-
# Prepend text to a file.
|
|
103
|
+
# Prepend text to a file. Since it depends on inject_into_file, it's reversible.
|
|
104
104
|
#
|
|
105
105
|
# ==== Parameters
|
|
106
106
|
# path<String>:: path of the file to be changed
|
|
@@ -111,19 +111,17 @@ class Thor
|
|
|
111
111
|
#
|
|
112
112
|
# prepend_file 'config/environments/test.rb', 'config.gem "rspec"'
|
|
113
113
|
#
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
File.open(path, 'wb') { |file| file.write(content) }
|
|
123
|
-
end
|
|
114
|
+
# prepend_file 'config/environments/test.rb' do
|
|
115
|
+
# 'config.gem "rspec"'
|
|
116
|
+
# end
|
|
117
|
+
#
|
|
118
|
+
def prepend_file(path, *args, &block)
|
|
119
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
|
120
|
+
config.merge!(:after => /\A/)
|
|
121
|
+
inject_into_file(path, *(args << config), &block)
|
|
124
122
|
end
|
|
125
123
|
|
|
126
|
-
# Append text to a file.
|
|
124
|
+
# Append text to a file. Since it depends on inject_into_file, it's reversible.
|
|
127
125
|
#
|
|
128
126
|
# ==== Parameters
|
|
129
127
|
# path<String>:: path of the file to be changed
|
|
@@ -134,11 +132,37 @@ class Thor
|
|
|
134
132
|
#
|
|
135
133
|
# append_file 'config/environments/test.rb', 'config.gem "rspec"'
|
|
136
134
|
#
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
135
|
+
# append_file 'config/environments/test.rb' do
|
|
136
|
+
# 'config.gem "rspec"'
|
|
137
|
+
# end
|
|
138
|
+
#
|
|
139
|
+
def append_file(path, *args, &block)
|
|
140
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
|
141
|
+
config.merge!(:before => /\z/)
|
|
142
|
+
inject_into_file(path, *(args << config), &block)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Injects text right after the class definition. Since it depends on
|
|
146
|
+
# inject_into_file, it's reversible.
|
|
147
|
+
#
|
|
148
|
+
# ==== Parameters
|
|
149
|
+
# path<String>:: path of the file to be changed
|
|
150
|
+
# klass<String|Class>:: the class to be manipulated
|
|
151
|
+
# data<String>:: the data to append to the class, can be also given as a block.
|
|
152
|
+
# config<Hash>:: give :verbose => false to not log the status.
|
|
153
|
+
#
|
|
154
|
+
# ==== Examples
|
|
155
|
+
#
|
|
156
|
+
# inject_into_class "app/controllers/application_controller.rb", " filter_parameter :password\n"
|
|
157
|
+
#
|
|
158
|
+
# inject_into_class "app/controllers/application_controller.rb", ApplicationController do
|
|
159
|
+
# " filter_parameter :password\n"
|
|
160
|
+
# end
|
|
161
|
+
#
|
|
162
|
+
def inject_into_class(path, klass, *args, &block)
|
|
163
|
+
config = args.last.is_a?(Hash) ? args.pop : {}
|
|
164
|
+
config.merge!(:after => /class #{klass}\n|class #{klass} .*\n/)
|
|
165
|
+
inject_into_file(path, *(args << config), &block)
|
|
142
166
|
end
|
|
143
167
|
|
|
144
168
|
# Run a regular expression replacement on a file.
|
|
@@ -3,10 +3,8 @@ require 'thor/actions/empty_directory'
|
|
|
3
3
|
class Thor
|
|
4
4
|
module Actions
|
|
5
5
|
|
|
6
|
-
# Injects the given content into a file. Different from
|
|
7
|
-
#
|
|
8
|
-
# the flag can only be strings. gsub_file is your friend if you need to
|
|
9
|
-
# deal with more complex cases.
|
|
6
|
+
# Injects the given content into a file. Different from gsub_file, this
|
|
7
|
+
# method is reversible.
|
|
10
8
|
#
|
|
11
9
|
# ==== Parameters
|
|
12
10
|
# destination<String>:: Relative path to the destination root
|
|
@@ -16,11 +14,11 @@ class Thor
|
|
|
16
14
|
#
|
|
17
15
|
# ==== Examples
|
|
18
16
|
#
|
|
19
|
-
# inject_into_file "config/environment.rb", "config.gem thor", :after => "Rails::Initializer.run do |config|\n"
|
|
17
|
+
# inject_into_file "config/environment.rb", "config.gem :thor", :after => "Rails::Initializer.run do |config|\n"
|
|
20
18
|
#
|
|
21
19
|
# inject_into_file "config/environment.rb", :after => "Rails::Initializer.run do |config|\n" do
|
|
22
20
|
# gems = ask "Which gems would you like to add?"
|
|
23
|
-
# gems.split(" ").map{ |gem| " config.gem
|
|
21
|
+
# gems.split(" ").map{ |gem| " config.gem :#{gem}" }.join("\n")
|
|
24
22
|
# end
|
|
25
23
|
#
|
|
26
24
|
def inject_into_file(destination, *args, &block)
|
|
@@ -29,40 +27,65 @@ class Thor
|
|
|
29
27
|
else
|
|
30
28
|
data, config = args.shift, args.shift
|
|
31
29
|
end
|
|
32
|
-
|
|
33
|
-
log_status = args.empty? || args.pop
|
|
34
30
|
action InjectIntoFile.new(self, destination, data, config)
|
|
35
31
|
end
|
|
36
32
|
|
|
37
33
|
class InjectIntoFile < EmptyDirectory #:nodoc:
|
|
38
|
-
attr_reader :flag, :
|
|
34
|
+
attr_reader :replacement, :flag, :behavior
|
|
39
35
|
|
|
40
36
|
def initialize(base, destination, data, config)
|
|
41
37
|
super(base, destination, { :verbose => true }.merge(config))
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
@replacement = if @config.key?(:after)
|
|
46
|
-
@flag = @config.delete(:after)
|
|
47
|
-
@flag + data
|
|
39
|
+
@behavior, @flag = if @config.key?(:after)
|
|
40
|
+
[:after, @config.delete(:after)]
|
|
48
41
|
else
|
|
49
|
-
|
|
50
|
-
data + @flag
|
|
42
|
+
[:before, @config.delete(:before)]
|
|
51
43
|
end
|
|
44
|
+
|
|
45
|
+
@replacement = data.is_a?(Proc) ? data.call : data
|
|
46
|
+
@flag = Regexp.escape(@flag) unless @flag.is_a?(Regexp)
|
|
52
47
|
end
|
|
53
48
|
|
|
54
49
|
def invoke!
|
|
55
|
-
say_status :
|
|
56
|
-
|
|
50
|
+
say_status :invoke
|
|
51
|
+
|
|
52
|
+
content = if @behavior == :after
|
|
53
|
+
'\0' + replacement
|
|
54
|
+
else
|
|
55
|
+
replacement + '\0'
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
replace!(/#{flag}/, content)
|
|
57
59
|
end
|
|
58
60
|
|
|
59
61
|
def revoke!
|
|
60
|
-
say_status :
|
|
61
|
-
|
|
62
|
+
say_status :revoke
|
|
63
|
+
|
|
64
|
+
regexp = if @behavior == :after
|
|
65
|
+
content = '\1\2'
|
|
66
|
+
/(#{flag})(.*)(#{Regexp.escape(replacement)})/m
|
|
67
|
+
else
|
|
68
|
+
content = '\2\3'
|
|
69
|
+
/(#{Regexp.escape(replacement)})(.*)(#{flag})/m
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
replace!(regexp, content)
|
|
62
73
|
end
|
|
63
74
|
|
|
64
75
|
protected
|
|
65
76
|
|
|
77
|
+
def say_status(behavior)
|
|
78
|
+
status = if flag == /\A/
|
|
79
|
+
behavior == :invoke ? :prepend : :unprepend
|
|
80
|
+
elsif flag == /\z/
|
|
81
|
+
behavior == :invoke ? :append : :unappend
|
|
82
|
+
else
|
|
83
|
+
behavior == :invoke ? :inject : :deinject
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
super(status, config[:verbose])
|
|
87
|
+
end
|
|
88
|
+
|
|
66
89
|
# Adds the content to the file.
|
|
67
90
|
#
|
|
68
91
|
def replace!(regexp, string)
|
data/lib/thor/actions.rb
CHANGED
|
@@ -8,23 +8,8 @@ class Thor
|
|
|
8
8
|
module Actions
|
|
9
9
|
attr_accessor :behavior
|
|
10
10
|
|
|
11
|
-
# On inclusion, add some options to base.
|
|
12
|
-
#
|
|
13
11
|
def self.included(base) #:nodoc:
|
|
14
12
|
base.extend ClassMethods
|
|
15
|
-
return unless base.respond_to?(:class_option)
|
|
16
|
-
|
|
17
|
-
base.class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
|
|
18
|
-
:desc => "Run but do not make any changes"
|
|
19
|
-
|
|
20
|
-
base.class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
|
|
21
|
-
:desc => "Overwrite files that already exist"
|
|
22
|
-
|
|
23
|
-
base.class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
|
|
24
|
-
:desc => "Skip files that already exist"
|
|
25
|
-
|
|
26
|
-
base.class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
|
|
27
|
-
:desc => "Supress status output"
|
|
28
13
|
end
|
|
29
14
|
|
|
30
15
|
module ClassMethods
|
|
@@ -49,6 +34,22 @@ class Thor
|
|
|
49
34
|
paths += from_superclass(:source_paths, [])
|
|
50
35
|
paths
|
|
51
36
|
end
|
|
37
|
+
|
|
38
|
+
# Add runtime options that help actions execution.
|
|
39
|
+
#
|
|
40
|
+
def add_runtime_options!
|
|
41
|
+
class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
|
|
42
|
+
:desc => "Run but do not make any changes"
|
|
43
|
+
|
|
44
|
+
class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
|
|
45
|
+
:desc => "Overwrite files that already exist"
|
|
46
|
+
|
|
47
|
+
class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
|
|
48
|
+
:desc => "Skip files that already exist"
|
|
49
|
+
|
|
50
|
+
class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
|
|
51
|
+
:desc => "Supress status output"
|
|
52
|
+
end
|
|
52
53
|
end
|
|
53
54
|
|
|
54
55
|
# Extends initializer to add more configuration options.
|
data/lib/thor/base.rb
CHANGED
|
@@ -355,6 +355,7 @@ class Thor
|
|
|
355
355
|
else
|
|
356
356
|
config[:shell].error e.message
|
|
357
357
|
end
|
|
358
|
+
exit(1) if exit_on_failure?
|
|
358
359
|
end
|
|
359
360
|
|
|
360
361
|
protected
|
|
@@ -491,6 +492,12 @@ class Thor
|
|
|
491
492
|
end
|
|
492
493
|
end
|
|
493
494
|
|
|
495
|
+
# A flag that makes the process exit with status 1 if any error happens.
|
|
496
|
+
#
|
|
497
|
+
def exit_on_failure?
|
|
498
|
+
false
|
|
499
|
+
end
|
|
500
|
+
|
|
494
501
|
# SIGNATURE: Sets the baseclass. This is where the superclass lookup
|
|
495
502
|
# finishes.
|
|
496
503
|
def baseclass #:nodoc:
|
data/lib/thor/invocation.rb
CHANGED
|
@@ -153,7 +153,7 @@ class Thor
|
|
|
153
153
|
raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
|
|
154
154
|
|
|
155
155
|
task ||= klass.default_task if klass <= Thor
|
|
156
|
-
task = klass.all_tasks[task.to_s] || Task.
|
|
156
|
+
task = klass.all_tasks[task.to_s] || Thor::Task::Dynamic.new(task) if task && !task.is_a?(Thor::Task)
|
|
157
157
|
task
|
|
158
158
|
end
|
|
159
159
|
|
data/lib/thor/rake_compat.rb
CHANGED
|
@@ -22,7 +22,8 @@ class Thor
|
|
|
22
22
|
|
|
23
23
|
def self.included(base)
|
|
24
24
|
# Hack. Make rakefile point to invoker, so rdoc task is generated properly.
|
|
25
|
-
|
|
25
|
+
rakefile = File.basename(caller[0].match(/(.*):\d+/)[1])
|
|
26
|
+
Rake.application.instance_variable_set(:@rakefile, rakefile)
|
|
26
27
|
self.rake_classes << base
|
|
27
28
|
end
|
|
28
29
|
end
|
|
@@ -43,11 +44,9 @@ class Object #:nodoc:
|
|
|
43
44
|
description.strip!
|
|
44
45
|
|
|
45
46
|
klass.desc description, task.comment || non_namespaced_name
|
|
46
|
-
klass.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
end
|
|
50
|
-
METHOD
|
|
47
|
+
klass.send :define_method, non_namespaced_name do |*args|
|
|
48
|
+
Rake::Task[task.name.to_sym].invoke(*args)
|
|
49
|
+
end
|
|
51
50
|
end
|
|
52
51
|
|
|
53
52
|
task
|
data/lib/thor/runner.rb
CHANGED
|
@@ -175,6 +175,10 @@ class Thor::Runner < Thor #:nodoc:
|
|
|
175
175
|
File.open(yaml_file, "w") { |f| f.puts yaml.to_yaml }
|
|
176
176
|
end
|
|
177
177
|
|
|
178
|
+
def self.exit_on_failure?
|
|
179
|
+
true
|
|
180
|
+
end
|
|
181
|
+
|
|
178
182
|
# Load the thorfiles. If relevant_to is supplied, looks for specific files
|
|
179
183
|
# in the thor_root instead of loading them all.
|
|
180
184
|
#
|
|
@@ -211,7 +215,7 @@ class Thor::Runner < Thor #:nodoc:
|
|
|
211
215
|
# 5. c:\ <-- no Thorfiles found!
|
|
212
216
|
#
|
|
213
217
|
def thorfiles(relevant_to=nil, skip_lookup=false)
|
|
214
|
-
#
|
|
218
|
+
# TODO Remove this dealing with deprecated thor when :namespaces: is available as constants
|
|
215
219
|
save_yaml(thor_yaml) if Thor::Util.convert_constants_to_namespaces(thor_yaml)
|
|
216
220
|
|
|
217
221
|
thorfiles = []
|
data/lib/thor/shell/basic.rb
CHANGED
|
@@ -34,12 +34,11 @@ class Thor
|
|
|
34
34
|
# ==== Example
|
|
35
35
|
# say("I know you knew that.")
|
|
36
36
|
#
|
|
37
|
-
def say(message="", color=nil, force_new_line=
|
|
37
|
+
def say(message="", color=nil, force_new_line=(message.to_s !~ /( |\t)$/))
|
|
38
38
|
message = message.to_s
|
|
39
|
-
new_line = force_new_line || !(message[-1, 1] == " " || message[-1, 1] == "\t")
|
|
40
39
|
message = set_color(message, color) if color
|
|
41
40
|
|
|
42
|
-
if
|
|
41
|
+
if force_new_line
|
|
43
42
|
$stdout.puts(message)
|
|
44
43
|
else
|
|
45
44
|
$stdout.print(message)
|
data/lib/thor/shell.rb
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
+
require 'rbconfig'
|
|
1
2
|
require 'thor/shell/color'
|
|
2
3
|
|
|
3
4
|
class Thor
|
|
4
5
|
module Base
|
|
5
|
-
# Returns the shell used in all Thor classes.
|
|
6
|
+
# Returns the shell used in all Thor classes. If you are in a Unix platform
|
|
7
|
+
# it will use a colored log, otherwise it will use a basic one without color.
|
|
6
8
|
#
|
|
7
9
|
def self.shell
|
|
8
|
-
@shell ||=
|
|
10
|
+
@shell ||= if Config::CONFIG['host_os'] =~ /mswin|mingw/
|
|
11
|
+
Thor::Shell::Basic
|
|
12
|
+
else
|
|
13
|
+
Thor::Shell::Color
|
|
14
|
+
end
|
|
9
15
|
end
|
|
10
16
|
|
|
11
17
|
# Sets the shell used in all Thor classes.
|
data/lib/thor/task.rb
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
class Thor
|
|
2
2
|
class Task < Struct.new(:name, :description, :usage, :options)
|
|
3
3
|
|
|
4
|
-
#
|
|
5
|
-
# missing calls (since a method missing does not have a task object for it).
|
|
4
|
+
# A dynamic task that handles method missing scenarios.
|
|
6
5
|
#
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
class Dynamic < Task
|
|
7
|
+
def initialize(name)
|
|
8
|
+
super(name.to_s, "A dynamically-generated task", name.to_s)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def run(instance, args=[])
|
|
12
|
+
unless (instance.methods & [name.to_s, name.to_sym]).empty?
|
|
13
|
+
raise Error, "could not find Thor class or task '#{name}'"
|
|
14
|
+
end
|
|
15
|
+
super
|
|
16
|
+
end
|
|
9
17
|
end
|
|
10
18
|
|
|
11
19
|
def initialize(name, description, usage, options=nil)
|
|
@@ -37,8 +45,6 @@ class Thor
|
|
|
37
45
|
# injected in the usage.
|
|
38
46
|
#
|
|
39
47
|
def formatted_usage(klass=nil, namespace=false, show_options=true)
|
|
40
|
-
formatted = ''
|
|
41
|
-
|
|
42
48
|
formatted = if namespace.is_a?(String)
|
|
43
49
|
"#{namespace}:"
|
|
44
50
|
elsif klass && namespace
|
|
@@ -77,7 +83,7 @@ class Thor
|
|
|
77
83
|
#
|
|
78
84
|
def public_method?(instance) #:nodoc:
|
|
79
85
|
collection = instance.private_methods + instance.protected_methods
|
|
80
|
-
|
|
86
|
+
(collection & [name.to_s, name.to_sym]).empty?
|
|
81
87
|
end
|
|
82
88
|
|
|
83
89
|
# Clean everything that comes from the Thor gempath and remove the caller.
|
data/lib/thor/util.rb
CHANGED
|
@@ -137,17 +137,18 @@ class Thor
|
|
|
137
137
|
# inherit from Thor or Thor::Group.
|
|
138
138
|
#
|
|
139
139
|
def self.namespace_to_thor_class_and_task(namespace, raise_if_nil=true)
|
|
140
|
-
|
|
140
|
+
if namespace.include?(?:)
|
|
141
|
+
pieces = namespace.split(":")
|
|
142
|
+
task = pieces.pop
|
|
143
|
+
klass = Thor::Util.find_by_namespace(pieces.join(":"))
|
|
144
|
+
end
|
|
141
145
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
task_name = namespace.pop
|
|
145
|
-
klass = Thor::Util.find_by_namespace(namespace.join(":"))
|
|
146
|
+
unless klass
|
|
147
|
+
klass, task = Thor::Util.find_by_namespace(namespace), nil
|
|
146
148
|
end
|
|
147
149
|
|
|
148
150
|
raise Error, "could not find Thor class or task '#{namespace}'" if raise_if_nil && klass.nil?
|
|
149
|
-
|
|
150
|
-
return klass, task_name
|
|
151
|
+
return klass, task
|
|
151
152
|
end
|
|
152
153
|
|
|
153
154
|
# Receives a path and load the thor file in the path. The file is evaluated
|
|
@@ -208,7 +209,7 @@ class Thor
|
|
|
208
209
|
# Returns the root where thor files are located, dependending on the OS.
|
|
209
210
|
#
|
|
210
211
|
def self.thor_root
|
|
211
|
-
File.join(user_home, ".thor")
|
|
212
|
+
File.join(user_home, ".thor").gsub(/\\/, '/')
|
|
212
213
|
end
|
|
213
214
|
|
|
214
215
|
# Returns the files in the thor root. On Windows thor_root will be something
|
|
@@ -219,7 +220,7 @@ class Thor
|
|
|
219
220
|
# If we don't #gsub the \ character, Dir.glob will fail.
|
|
220
221
|
#
|
|
221
222
|
def self.thor_root_glob
|
|
222
|
-
files = Dir["#{thor_root
|
|
223
|
+
files = Dir["#{thor_root}/*"]
|
|
223
224
|
|
|
224
225
|
files.map! do |file|
|
|
225
226
|
File.directory?(file) ? File.join(file, "main.thor") : file
|
data/lib/thor/version.rb
ADDED
data/lib/thor.rb
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
$:.unshift File.expand_path(File.dirname(__FILE__))
|
|
2
1
|
require 'thor/base'
|
|
3
2
|
require 'thor/group'
|
|
4
3
|
require 'thor/actions'
|
|
@@ -135,7 +134,7 @@ class Thor
|
|
|
135
134
|
args, opts = given_args, {}
|
|
136
135
|
end
|
|
137
136
|
|
|
138
|
-
task ||= Task.
|
|
137
|
+
task ||= Thor::Task::Dynamic.new(meth)
|
|
139
138
|
trailing = args[Range.new(arguments.size, -1)]
|
|
140
139
|
new(args, opts, config).invoke(task, trailing || [])
|
|
141
140
|
end
|
|
@@ -96,6 +96,11 @@ describe Thor::Actions::Directory do
|
|
|
96
96
|
File.exists?(file).must be_true
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
+
it "does not copy empty directories twice" do
|
|
100
|
+
content = invoke!("doc/components", "docs/components")
|
|
101
|
+
content.must_not =~ /exist/
|
|
102
|
+
end
|
|
103
|
+
|
|
99
104
|
it "logs status" do
|
|
100
105
|
content = invoke!("doc")
|
|
101
106
|
content.must =~ /create doc\/README/
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
2
|
|
|
3
|
+
class Application; end
|
|
4
|
+
|
|
3
5
|
describe Thor::Actions do
|
|
4
6
|
def runner(options={})
|
|
5
7
|
@runner ||= MyCounter.new([1], options, { :destination_root => destination_root })
|
|
@@ -193,12 +195,6 @@ describe Thor::Actions do
|
|
|
193
195
|
File.open(file).read.must == "__start__\nREADME\n__end__\nEND\n"
|
|
194
196
|
end
|
|
195
197
|
|
|
196
|
-
it "does not append if pretending" do
|
|
197
|
-
runner(:pretend => true)
|
|
198
|
-
action :append_file, "doc/README", "END\n"
|
|
199
|
-
File.open(file).read.must == "__start__\nREADME\n__end__\n"
|
|
200
|
-
end
|
|
201
|
-
|
|
202
198
|
it "accepts a block" do
|
|
203
199
|
action(:append_file, "doc/README"){ "END\n" }
|
|
204
200
|
File.open(file).read.must == "__start__\nREADME\n__end__\nEND\n"
|
|
@@ -207,10 +203,6 @@ describe Thor::Actions do
|
|
|
207
203
|
it "logs status" do
|
|
208
204
|
action(:append_file, "doc/README", "END").must == " append doc/README\n"
|
|
209
205
|
end
|
|
210
|
-
|
|
211
|
-
it "does not log status if required" do
|
|
212
|
-
action(:append_file, "doc/README", nil, :verbose => false){ "END" }.must be_empty
|
|
213
|
-
end
|
|
214
206
|
end
|
|
215
207
|
|
|
216
208
|
describe "#prepend_file" do
|
|
@@ -219,12 +211,6 @@ describe Thor::Actions do
|
|
|
219
211
|
File.open(file).read.must == "START\n__start__\nREADME\n__end__\n"
|
|
220
212
|
end
|
|
221
213
|
|
|
222
|
-
it "does not prepend if pretending" do
|
|
223
|
-
runner(:pretend => true)
|
|
224
|
-
action :prepend_file, "doc/README", "START\n"
|
|
225
|
-
File.open(file).read.must == "__start__\nREADME\n__end__\n"
|
|
226
|
-
end
|
|
227
|
-
|
|
228
214
|
it "accepts a block" do
|
|
229
215
|
action(:prepend_file, "doc/README"){ "START\n" }
|
|
230
216
|
File.open(file).read.must == "START\n__start__\nREADME\n__end__\n"
|
|
@@ -233,9 +219,30 @@ describe Thor::Actions do
|
|
|
233
219
|
it "logs status" do
|
|
234
220
|
action(:prepend_file, "doc/README", "START").must == " prepend doc/README\n"
|
|
235
221
|
end
|
|
222
|
+
end
|
|
236
223
|
|
|
237
|
-
|
|
238
|
-
|
|
224
|
+
describe "#inject_into_class" do
|
|
225
|
+
def file
|
|
226
|
+
File.join(destination_root, "application.rb")
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
it "appends content to a class" do
|
|
230
|
+
action :inject_into_class, "application.rb", Application, " filter_parameters :password\n"
|
|
231
|
+
File.open(file).read.must == "class Application < Base\n filter_parameters :password\nend\n"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
it "accepts a block" do
|
|
235
|
+
action(:inject_into_class, "application.rb", Application){ " filter_parameters :password\n" }
|
|
236
|
+
File.open(file).read.must == "class Application < Base\n filter_parameters :password\nend\n"
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it "logs status" do
|
|
240
|
+
action(:inject_into_class, "application.rb", Application, " filter_parameters :password\n").must == " inject application.rb\n"
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
it "does not append if class name does not match" do
|
|
244
|
+
action :inject_into_class, "application.rb", "App", " filter_parameters :password\n"
|
|
245
|
+
File.open(file).read.must == "class Application < Base\nend\n"
|
|
239
246
|
end
|
|
240
247
|
end
|
|
241
248
|
end
|
|
@@ -61,17 +61,43 @@ describe Thor::Actions::InjectIntoFile do
|
|
|
61
61
|
it "deinjects the destination file after injection" do
|
|
62
62
|
invoke! "doc/README", "\nmore content", :after => "__start__"
|
|
63
63
|
revoke! "doc/README", "\nmore content", :after => "__start__"
|
|
64
|
-
|
|
65
64
|
File.read(file).must == "__start__\nREADME\n__end__\n"
|
|
66
65
|
end
|
|
67
66
|
|
|
68
67
|
it "deinjects the destination file before injection" do
|
|
69
|
-
invoke! "doc/README", "
|
|
70
|
-
revoke! "doc/README", "
|
|
71
|
-
|
|
68
|
+
invoke! "doc/README", "more content\n", :before => "__start__"
|
|
69
|
+
revoke! "doc/README", "more content\n", :before => "__start__"
|
|
72
70
|
File.read(file).must == "__start__\nREADME\n__end__\n"
|
|
73
71
|
end
|
|
74
72
|
|
|
73
|
+
it "deinjects even with double after injection" do
|
|
74
|
+
invoke! "doc/README", "\nmore content", :after => "__start__"
|
|
75
|
+
invoke! "doc/README", "\nanother stuff", :after => "__start__"
|
|
76
|
+
revoke! "doc/README", "\nmore content", :after => "__start__"
|
|
77
|
+
File.read(file).must == "__start__\nanother stuff\nREADME\n__end__\n"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "deinjects even with double before injection" do
|
|
81
|
+
invoke! "doc/README", "more content\n", :before => "__start__"
|
|
82
|
+
invoke! "doc/README", "another stuff\n", :before => "__start__"
|
|
83
|
+
revoke! "doc/README", "more content\n", :before => "__start__"
|
|
84
|
+
File.read(file).must == "another stuff\n__start__\nREADME\n__end__\n"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "deinjects when prepending" do
|
|
88
|
+
invoke! "doc/README", "more content\n", :after => /\A/
|
|
89
|
+
invoke! "doc/README", "another stuff\n", :after => /\A/
|
|
90
|
+
revoke! "doc/README", "more content\n", :after => /\A/
|
|
91
|
+
File.read(file).must == "another stuff\n__start__\nREADME\n__end__\n"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "deinjects when appending" do
|
|
95
|
+
invoke! "doc/README", "more content\n", :before => /\z/
|
|
96
|
+
invoke! "doc/README", "another stuff\n", :before => /\z/
|
|
97
|
+
revoke! "doc/README", "more content\n", :before => /\z/
|
|
98
|
+
File.read(file).must == "__start__\nREADME\n__end__\nanother stuff\n"
|
|
99
|
+
end
|
|
100
|
+
|
|
75
101
|
it "shows progress information to the user" do
|
|
76
102
|
invoke!("doc/README", "\nmore content", :after => "__start__")
|
|
77
103
|
revoke!("doc/README", "\nmore content", :after => "__start__").must == " deinject doc/README\n"
|
data/spec/rake_compat_spec.rb
CHANGED
|
@@ -27,6 +27,10 @@ class ThorTask < Thor
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
describe Thor::RakeCompat do
|
|
30
|
+
it "sets the rakefile application" do
|
|
31
|
+
["rake_compat_spec.rb", "Thorfile"].must include(Rake.application.rakefile)
|
|
32
|
+
end
|
|
33
|
+
|
|
30
34
|
it "adds rake tasks to thor classes too" do
|
|
31
35
|
task = ThorTask.tasks["cool"]
|
|
32
36
|
task.must be
|
data/spec/runner_spec.rb
CHANGED
|
@@ -30,6 +30,7 @@ describe Thor::Runner do
|
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
it "raises error if a class/task cannot be found" do
|
|
33
|
+
mock(Thor::Runner).exit(1)
|
|
33
34
|
content = capture(:stderr){ Thor::Runner.start(["help", "unknown"]) }
|
|
34
35
|
content.must =~ /could not find Thor class or task 'unknown'/
|
|
35
36
|
end
|
|
@@ -67,6 +68,7 @@ describe Thor::Runner do
|
|
|
67
68
|
end
|
|
68
69
|
|
|
69
70
|
it "raises an error if class/task can't be found" do
|
|
71
|
+
mock(Thor::Runner).exit(1)
|
|
70
72
|
ARGV.replace ["unknown"]
|
|
71
73
|
capture(:stderr){ Thor::Runner.start }.must =~ /could not find Thor class or task 'unknown'/
|
|
72
74
|
end
|
|
@@ -180,10 +182,8 @@ describe Thor::Runner do
|
|
|
180
182
|
|
|
181
183
|
it "displays the modules installed in a pretty way" do
|
|
182
184
|
stdout = capture(:stdout) { Thor::Runner.start(["installed"]) }
|
|
183
|
-
|
|
184
185
|
stdout.must =~ /random\s*amazing/
|
|
185
186
|
stdout.must =~ /amazing:describe NAME \[\-\-forcefully\]\s+# say that someone is amazing/m
|
|
186
|
-
stdout.must =~ /amazing:hello\s+# say hello/m
|
|
187
187
|
end
|
|
188
188
|
end
|
|
189
189
|
|
data/spec/shell/basic_spec.rb
CHANGED
|
@@ -57,6 +57,11 @@ describe Thor::Shell::Basic do
|
|
|
57
57
|
mock($stdout).print("Running... ")
|
|
58
58
|
shell.say("Running... ")
|
|
59
59
|
end
|
|
60
|
+
|
|
61
|
+
it "prints a message to the user without new line" do
|
|
62
|
+
mock($stdout).print("Running...")
|
|
63
|
+
shell.say("Running...", nil, false)
|
|
64
|
+
end
|
|
60
65
|
end
|
|
61
66
|
|
|
62
67
|
describe "#say_status" do
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
$TESTING=true
|
|
2
2
|
|
|
3
|
-
$:.unshift
|
|
4
|
-
|
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
|
5
4
|
require 'thor'
|
|
6
5
|
require 'stringio'
|
|
6
|
+
|
|
7
7
|
require 'rubygems'
|
|
8
8
|
require 'rr'
|
|
9
9
|
require 'diff/lcs' # You need diff/lcs installed to run specs (but not to run Thor).
|
data/spec/task_spec.rb
CHANGED
|
@@ -41,10 +41,16 @@ describe Thor::Task do
|
|
|
41
41
|
|
|
42
42
|
describe "#dynamic" do
|
|
43
43
|
it "creates a dynamic task with the given name" do
|
|
44
|
-
Thor::Task.
|
|
45
|
-
Thor::Task.
|
|
46
|
-
Thor::Task.
|
|
47
|
-
Thor::Task.
|
|
44
|
+
Thor::Task::Dynamic.new('task').name.must == 'task'
|
|
45
|
+
Thor::Task::Dynamic.new('task').description.must == 'A dynamically-generated task'
|
|
46
|
+
Thor::Task::Dynamic.new('task').usage.must == 'task'
|
|
47
|
+
Thor::Task::Dynamic.new('task').options.must == {}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "does not invoke an existing method" do
|
|
51
|
+
lambda {
|
|
52
|
+
Thor::Task::Dynamic.new('to_s').run([])
|
|
53
|
+
}.must raise_error(Thor::Error, "could not find Thor class or task 'to_s'")
|
|
48
54
|
end
|
|
49
55
|
end
|
|
50
56
|
|
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.11.
|
|
4
|
+
version: 0.11.8
|
|
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: 2009-
|
|
13
|
+
date: 2009-10-21 00:00:00 -02:00
|
|
14
14
|
default_executable:
|
|
15
15
|
dependencies: []
|
|
16
16
|
|
|
@@ -26,13 +26,11 @@ extra_rdoc_files:
|
|
|
26
26
|
- LICENSE
|
|
27
27
|
- README.rdoc
|
|
28
28
|
- Thorfile
|
|
29
|
-
- VERSION
|
|
30
29
|
files:
|
|
31
30
|
- CHANGELOG.rdoc
|
|
32
31
|
- LICENSE
|
|
33
32
|
- README.rdoc
|
|
34
33
|
- Thorfile
|
|
35
|
-
- VERSION
|
|
36
34
|
- bin/rake2thor
|
|
37
35
|
- bin/thor
|
|
38
36
|
- lib/thor.rb
|
|
@@ -60,6 +58,7 @@ files:
|
|
|
60
58
|
- lib/thor/shell/color.rb
|
|
61
59
|
- lib/thor/task.rb
|
|
62
60
|
- lib/thor/util.rb
|
|
61
|
+
- lib/thor/version.rb
|
|
63
62
|
has_rdoc: true
|
|
64
63
|
homepage: http://yehudakatz.com
|
|
65
64
|
licenses: []
|
|
@@ -84,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
84
83
|
requirements: []
|
|
85
84
|
|
|
86
85
|
rubyforge_project: textmate
|
|
87
|
-
rubygems_version: 1.3.
|
|
86
|
+
rubygems_version: 1.3.5
|
|
88
87
|
signing_key:
|
|
89
88
|
specification_version: 3
|
|
90
89
|
summary: A scripting framework that replaces rake, sake and rubigen
|
|
@@ -105,6 +104,7 @@ test_files:
|
|
|
105
104
|
- spec/shell/color_spec.rb
|
|
106
105
|
- spec/group_spec.rb
|
|
107
106
|
- spec/thor_spec.rb
|
|
107
|
+
- spec/fixtures/application.rb
|
|
108
108
|
- spec/fixtures/doc/config.rb
|
|
109
109
|
- spec/fixtures/bundle/execute.rb
|
|
110
110
|
- spec/util_spec.rb
|
data/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.11.5
|