thor 0.12.0 → 0.12.3
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/CHANGELOG.rdoc +3 -5
- data/Thorfile +2 -1
- data/bin/thor +1 -0
- data/lib/thor/actions/create_file.rb +2 -2
- data/lib/thor/actions/directory.rb +2 -4
- data/lib/thor/actions/file_manipulation.rb +10 -6
- data/lib/thor/actions/inject_into_file.rb +1 -1
- data/lib/thor/actions.rb +6 -5
- data/lib/thor/base.rb +30 -32
- data/lib/thor/core_ext/file_binary_read.rb +9 -0
- data/lib/thor/group.rb +44 -36
- data/lib/thor/runner.rb +44 -40
- data/lib/thor/shell/basic.rb +49 -29
- data/lib/thor/shell/color.rb +1 -1
- data/lib/thor/shell.rb +1 -1
- data/lib/thor/task.rb +32 -43
- data/lib/thor/util.rb +4 -22
- data/lib/thor/version.rb +1 -1
- data/lib/thor.rb +43 -43
- data/spec/actions/create_file_spec.rb +7 -7
- data/spec/actions/directory_spec.rb +5 -4
- data/spec/actions/file_manipulation_spec.rb +29 -16
- data/spec/actions_spec.rb +14 -13
- data/spec/base_spec.rb +1 -1
- data/spec/fixtures/bundle/main.thor +1 -0
- data/spec/fixtures/doc/%file_name%.rb.tt +1 -0
- data/spec/fixtures/doc/README +3 -0
- data/spec/fixtures/group.thor +83 -0
- data/spec/fixtures/invoke.thor +112 -0
- data/spec/fixtures/script.thor +130 -0
- data/spec/fixtures/task.thor +10 -0
- data/spec/group_spec.rb +1 -7
- data/spec/runner_spec.rb +35 -39
- data/spec/shell/basic_spec.rb +56 -62
- data/spec/shell/color_spec.rb +6 -6
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +4 -4
- data/spec/task_spec.rb +14 -32
- data/spec/thor_spec.rb +21 -22
- data/spec/util_spec.rb +7 -31
- metadata +28 -19
data/lib/thor/task.rb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
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
4
|
|
|
4
5
|
# A dynamic task that handles method missing scenarios.
|
|
5
|
-
#
|
|
6
6
|
class Dynamic < Task
|
|
7
|
-
def initialize(name)
|
|
8
|
-
super(name.to_s, "A dynamically-generated task", name.to_s)
|
|
7
|
+
def initialize(name, options=nil)
|
|
8
|
+
super(name.to_s, "A dynamically-generated task", name.to_s, options)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def run(instance, args=[])
|
|
@@ -25,84 +25,73 @@ class Thor
|
|
|
25
25
|
self.options = other.options.dup if other.options
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
def short_description
|
|
29
|
-
description.split("\n").first if description
|
|
30
|
-
end
|
|
31
|
-
|
|
32
28
|
# By default, a task invokes a method in the thor class. You can change this
|
|
33
29
|
# implementation to create custom tasks.
|
|
34
|
-
#
|
|
35
30
|
def run(instance, args=[])
|
|
36
31
|
raise UndefinedTaskError, "the '#{name}' task of #{instance.class} is private" unless public_method?(instance)
|
|
37
32
|
instance.send(name, *args)
|
|
38
33
|
rescue ArgumentError => e
|
|
34
|
+
raise e if instance.class.respond_to?(:debugging) && instance.class.debugging
|
|
39
35
|
parse_argument_error(instance, e, caller)
|
|
40
36
|
rescue NoMethodError => e
|
|
37
|
+
raise e if instance.class.respond_to?(:debugging) && instance.class.debugging
|
|
41
38
|
parse_no_method_error(instance, e)
|
|
42
39
|
end
|
|
43
40
|
|
|
44
|
-
# Returns the formatted usage
|
|
45
|
-
#
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"#{
|
|
41
|
+
# Returns the formatted usage by injecting given required arguments
|
|
42
|
+
# and required options into the given usage.
|
|
43
|
+
def formatted_usage(klass, namespace=true)
|
|
44
|
+
namespace = klass.namespace unless namespace == false
|
|
45
|
+
|
|
46
|
+
# Add namespace
|
|
47
|
+
formatted = if namespace
|
|
48
|
+
"#{namespace.gsub(/^(default|thor:runner:)/,'')}:"
|
|
52
49
|
else
|
|
53
50
|
""
|
|
54
51
|
end
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
formatted <<
|
|
58
|
-
formatted.strip!
|
|
59
|
-
formatted
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# Injects the class arguments into the task usage.
|
|
63
|
-
#
|
|
64
|
-
def formatted_arguments(klass)
|
|
65
|
-
if klass && !klass.arguments.empty?
|
|
53
|
+
# Add usage with required arguments
|
|
54
|
+
formatted << if klass && !klass.arguments.empty?
|
|
66
55
|
usage.to_s.gsub(/^#{name}/) do |match|
|
|
67
|
-
match << " " << klass.arguments.map{ |a| a.usage }.join(' ')
|
|
56
|
+
match << " " << klass.arguments.map{ |a| a.usage }.compact.join(' ')
|
|
68
57
|
end
|
|
69
58
|
else
|
|
70
59
|
usage.to_s
|
|
71
60
|
end
|
|
72
|
-
end
|
|
73
61
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
62
|
+
# Add required options
|
|
63
|
+
formatted << " #{required_options}"
|
|
64
|
+
|
|
65
|
+
# Strip and go!
|
|
66
|
+
formatted.strip
|
|
78
67
|
end
|
|
79
68
|
|
|
80
69
|
protected
|
|
81
70
|
|
|
71
|
+
def required_options
|
|
72
|
+
@required_options ||= options.map{ |_, o| o.usage if o.required? }.compact.sort.join(" ")
|
|
73
|
+
end
|
|
74
|
+
|
|
82
75
|
# Given a target, checks if this class name is not a private/protected method.
|
|
83
|
-
#
|
|
84
76
|
def public_method?(instance) #:nodoc:
|
|
85
77
|
collection = instance.private_methods + instance.protected_methods
|
|
86
78
|
(collection & [name.to_s, name.to_sym]).empty?
|
|
87
79
|
end
|
|
88
80
|
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
def
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
saned -= caller
|
|
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
|
|
95
86
|
end
|
|
96
87
|
|
|
97
88
|
def parse_argument_error(instance, e, caller) #:nodoc:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if backtrace.empty? && e.message =~ /wrong number of arguments/
|
|
89
|
+
if e.message =~ /wrong number of arguments/ && backtrace_match?(e.backtrace.first.to_s)
|
|
101
90
|
if instance.is_a?(Thor::Group)
|
|
102
91
|
raise e, "'#{name}' was called incorrectly. Are you sure it has arity equals to 0?"
|
|
103
92
|
else
|
|
104
93
|
raise InvocationError, "'#{name}' was called incorrectly. Call as " <<
|
|
105
|
-
"'#{formatted_usage(instance.class
|
|
94
|
+
"'#{formatted_usage(instance.class)}'"
|
|
106
95
|
end
|
|
107
96
|
else
|
|
108
97
|
raise e
|
data/lib/thor/util.rb
CHANGED
|
@@ -76,8 +76,10 @@ class Thor
|
|
|
76
76
|
# Returns the thor classes declared inside the given class.
|
|
77
77
|
#
|
|
78
78
|
def self.thor_classes_in(klass)
|
|
79
|
+
stringfied_constants = klass.constants.map { |c| c.to_s }
|
|
79
80
|
Thor::Base.subclasses.select do |subclass|
|
|
80
|
-
|
|
81
|
+
next unless subclass.name
|
|
82
|
+
stringfied_constants.include?(subclass.name.gsub("#{klass.name}::", ''))
|
|
81
83
|
end
|
|
82
84
|
end
|
|
83
85
|
|
|
@@ -155,7 +157,7 @@ class Thor
|
|
|
155
157
|
# inside the sandbox to avoid namespacing conflicts.
|
|
156
158
|
#
|
|
157
159
|
def self.load_thorfile(path, content=nil)
|
|
158
|
-
content ||= File.
|
|
160
|
+
content ||= File.binread(path)
|
|
159
161
|
|
|
160
162
|
begin
|
|
161
163
|
Thor::Sandbox.class_eval(content, path)
|
|
@@ -164,26 +166,6 @@ class Thor
|
|
|
164
166
|
end
|
|
165
167
|
end
|
|
166
168
|
|
|
167
|
-
# Receives a yaml (hash) and updates all constants entries to namespace.
|
|
168
|
-
# This was added to deal with deprecated versions of Thor.
|
|
169
|
-
#
|
|
170
|
-
# TODO Deprecate this method in the future.
|
|
171
|
-
#
|
|
172
|
-
# ==== Returns
|
|
173
|
-
# TrueClass|FalseClass:: Returns true if any change to the yaml file was made.
|
|
174
|
-
#
|
|
175
|
-
def self.convert_constants_to_namespaces(yaml)
|
|
176
|
-
yaml_changed = false
|
|
177
|
-
|
|
178
|
-
yaml.each do |k, v|
|
|
179
|
-
next unless v[:constants] && v[:namespaces].nil?
|
|
180
|
-
yaml_changed = true
|
|
181
|
-
yaml[k][:namespaces] = v[:constants].map{|c| Thor::Util.namespace_from_thor_class(c)}
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
yaml_changed
|
|
185
|
-
end
|
|
186
|
-
|
|
187
169
|
def self.user_home
|
|
188
170
|
@@user_home ||= if ENV["HOME"]
|
|
189
171
|
ENV["HOME"]
|
data/lib/thor/version.rb
CHANGED
data/lib/thor.rb
CHANGED
|
@@ -2,6 +2,7 @@ require 'thor/base'
|
|
|
2
2
|
require 'thor/group'
|
|
3
3
|
require 'thor/actions'
|
|
4
4
|
|
|
5
|
+
# TODO: Update thor to allow for git-style CLI (git bisect run)
|
|
5
6
|
class Thor
|
|
6
7
|
class << self
|
|
7
8
|
# Sets the default task when thor is executed without an explicit task to be called.
|
|
@@ -78,14 +79,14 @@ class Thor
|
|
|
78
79
|
@method_options
|
|
79
80
|
end
|
|
80
81
|
|
|
81
|
-
# Adds an option to the set of
|
|
82
|
+
# Adds an option to the set of method options. If :for is given as option,
|
|
82
83
|
# it allows you to change the options from a previous defined task.
|
|
83
84
|
#
|
|
84
85
|
# def previous_task
|
|
85
86
|
# # magic
|
|
86
87
|
# end
|
|
87
88
|
#
|
|
88
|
-
#
|
|
89
|
+
# method_option :foo => :bar, :for => :previous_task
|
|
89
90
|
#
|
|
90
91
|
# def next_task
|
|
91
92
|
# # magic
|
|
@@ -101,7 +102,6 @@ class Thor
|
|
|
101
102
|
# :default - Default value for this argument. It cannot be required and have default values.
|
|
102
103
|
# :aliases - Aliases for this option.
|
|
103
104
|
# :type - The type of the argument, can be :string, :hash, :array, :numeric or :boolean.
|
|
104
|
-
# :group - The group for this options. Use by class options to output options in different levels.
|
|
105
105
|
# :banner - String to show on usage notes.
|
|
106
106
|
#
|
|
107
107
|
def method_option(name, options={})
|
|
@@ -140,49 +140,48 @@ class Thor
|
|
|
140
140
|
end
|
|
141
141
|
end
|
|
142
142
|
|
|
143
|
-
# Prints help information
|
|
144
|
-
# only about the specific task.
|
|
143
|
+
# Prints help information for the given task.
|
|
145
144
|
#
|
|
146
145
|
# ==== Parameters
|
|
147
|
-
#
|
|
146
|
+
# shell<Thor::Shell>
|
|
147
|
+
# task_name<String>
|
|
148
|
+
#
|
|
149
|
+
def task_help(shell, task_name)
|
|
150
|
+
task = all_tasks[task_name]
|
|
151
|
+
raise UndefinedTaskError, "task '#{task_name}' could not be found in namespace '#{self.namespace}'" unless task
|
|
152
|
+
|
|
153
|
+
shell.say "Usage:"
|
|
154
|
+
shell.say " #{banner(task)}"
|
|
155
|
+
shell.say
|
|
156
|
+
class_options_help(shell, nil => task.options.map { |_, o| o })
|
|
157
|
+
shell.say task.description
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Prints help information for this class.
|
|
148
161
|
#
|
|
149
|
-
# ====
|
|
150
|
-
#
|
|
151
|
-
# skip_inherited:: When true, does not show tasks from superclass.
|
|
162
|
+
# ==== Parameters
|
|
163
|
+
# shell<Thor::Shell>
|
|
152
164
|
#
|
|
153
|
-
def help(shell
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
shell.say "Usage:"
|
|
161
|
-
shell.say " #{banner(task, options[:namespace], false)}"
|
|
162
|
-
shell.say
|
|
163
|
-
class_options_help(shell, "Class", :Method => task.options.map { |_, o| o })
|
|
164
|
-
shell.say task.description
|
|
165
|
-
else
|
|
166
|
-
list = (options[:short] ? tasks : all_tasks).map do |_, task|
|
|
167
|
-
item = [ banner(task, options[:namespace]) ]
|
|
168
|
-
item << "# #{task.short_description}" if task.short_description
|
|
169
|
-
item << " "
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
options[:ident] ||= 2
|
|
173
|
-
if options[:short]
|
|
174
|
-
shell.print_list(list, :ident => options[:ident])
|
|
175
|
-
else
|
|
176
|
-
shell.say "Tasks:"
|
|
177
|
-
shell.print_list(list, :ident => options[:ident])
|
|
178
|
-
end
|
|
165
|
+
def help(shell)
|
|
166
|
+
list = printable_tasks
|
|
167
|
+
Thor::Util.thor_classes_in(self).each do |klass|
|
|
168
|
+
list += klass.printable_tasks(false)
|
|
169
|
+
end
|
|
170
|
+
list.sort!{ |a,b| a[0] <=> b[0] }
|
|
179
171
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
172
|
+
shell.say "Tasks:"
|
|
173
|
+
shell.print_table(list, :ident => 2, :truncate => true)
|
|
174
|
+
shell.say
|
|
175
|
+
class_options_help(shell)
|
|
176
|
+
end
|
|
184
177
|
|
|
185
|
-
|
|
178
|
+
# Returns tasks ready to be printed.
|
|
179
|
+
def printable_tasks(all=true)
|
|
180
|
+
(all ? all_tasks : tasks).map do |_, task|
|
|
181
|
+
item = []
|
|
182
|
+
item << banner(task)
|
|
183
|
+
item << (task.description ? "# #{task.description.gsub(/\s+/m,' ')}" : "")
|
|
184
|
+
item
|
|
186
185
|
end
|
|
187
186
|
end
|
|
188
187
|
|
|
@@ -193,8 +192,9 @@ class Thor
|
|
|
193
192
|
# the task that is going to be invoked and a boolean which indicates if
|
|
194
193
|
# the namespace should be displayed as arguments.
|
|
195
194
|
#
|
|
196
|
-
def banner(task
|
|
197
|
-
|
|
195
|
+
def banner(task)
|
|
196
|
+
base = $thor_runner ? "thor" : File.basename($0.split(" ").first)
|
|
197
|
+
"#{base} #{task.formatted_usage(self, base == "thor")}"
|
|
198
198
|
end
|
|
199
199
|
|
|
200
200
|
def baseclass #:nodoc:
|
|
@@ -237,6 +237,6 @@ class Thor
|
|
|
237
237
|
|
|
238
238
|
desc "help [TASK]", "Describe available tasks or one specific task"
|
|
239
239
|
def help(task=nil)
|
|
240
|
-
self.class.
|
|
240
|
+
task ? self.class.task_help(shell, task) : self.class.help(shell)
|
|
241
241
|
end
|
|
242
242
|
end
|
|
@@ -8,7 +8,7 @@ describe Thor::Actions::CreateFile do
|
|
|
8
8
|
|
|
9
9
|
def create_file(destination=nil, config={}, options={})
|
|
10
10
|
@base = MyCounter.new([1,2], options, { :destination_root => destination_root })
|
|
11
|
-
stub(
|
|
11
|
+
@base.stub!(:file_name).and_return('rdoc')
|
|
12
12
|
|
|
13
13
|
@action = Thor::Actions::CreateFile.new(@base, destination, "CONFIGURATION",
|
|
14
14
|
{ :verbose => !@silence }.merge(config))
|
|
@@ -103,7 +103,7 @@ describe Thor::Actions::CreateFile do
|
|
|
103
103
|
|
|
104
104
|
it "shows conflict status to ther user" do
|
|
105
105
|
create_file("doc/config.rb").must_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!
|
|
@@ -114,21 +114,21 @@ describe Thor::Actions::CreateFile do
|
|
|
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
118
|
invoke!.must =~ /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
124
|
invoke!.must =~ /skip doc\/config\.rb/
|
|
125
125
|
end
|
|
126
126
|
|
|
127
127
|
it "executes the block given to show file content" do
|
|
128
128
|
create_file("doc/config.rb")
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
$stdin.should_receive(:gets).and_return('d')
|
|
130
|
+
$stdin.should_receive(:gets).and_return('n')
|
|
131
|
+
@base.shell.should_receive(:system).with(/diff -u/)
|
|
132
132
|
invoke!
|
|
133
133
|
end
|
|
134
134
|
end
|
|
@@ -4,7 +4,7 @@ require 'thor/actions'
|
|
|
4
4
|
describe Thor::Actions::Directory do
|
|
5
5
|
before(:each) do
|
|
6
6
|
::FileUtils.rm_rf(destination_root)
|
|
7
|
-
stub(
|
|
7
|
+
invoker.stub!(:file_name).and_return("rdoc")
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def invoker
|
|
@@ -110,10 +110,11 @@ describe Thor::Actions::Directory do
|
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
it "yields a block" do
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
checked = false
|
|
114
|
+
invoke!("doc") do |content|
|
|
115
|
+
checked ||= !!(content =~ /FOO/)
|
|
116
116
|
end
|
|
117
|
+
checked.must be_true
|
|
117
118
|
end
|
|
118
119
|
end
|
|
119
120
|
|
|
@@ -29,23 +29,23 @@ describe Thor::Actions do
|
|
|
29
29
|
|
|
30
30
|
describe "#chmod" do
|
|
31
31
|
it "executes the command given" do
|
|
32
|
-
|
|
32
|
+
FileUtils.should_receive(:chmod_R).with(0755, file)
|
|
33
33
|
action :chmod, "foo", 0755
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
it "does not execute the command if pretending given" do
|
|
37
|
-
|
|
37
|
+
FileUtils.should_not_receive(:chmod_R)
|
|
38
38
|
runner(:pretend => true)
|
|
39
39
|
action :chmod, "foo", 0755
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
it "logs status" do
|
|
43
|
-
|
|
43
|
+
FileUtils.should_receive(:chmod_R).with(0755, file)
|
|
44
44
|
action(:chmod, "foo", 0755).must == " chmod foo\n"
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
it "does not log status if required" do
|
|
48
|
-
|
|
48
|
+
FileUtils.should_receive(:chmod_R).with(0755, file)
|
|
49
49
|
action(:chmod, "foo", 0755, :verbose => false).must be_empty
|
|
50
50
|
end
|
|
51
51
|
end
|
|
@@ -65,13 +65,19 @@ describe Thor::Actions do
|
|
|
65
65
|
runner.inside("doc") do
|
|
66
66
|
action :copy_file, "README"
|
|
67
67
|
end
|
|
68
|
-
|
|
69
68
|
exists_and_identical?("doc/README", "doc/README")
|
|
70
69
|
end
|
|
71
70
|
|
|
72
71
|
it "logs status" do
|
|
73
72
|
action(:copy_file, "task.thor").must == " create task.thor\n"
|
|
74
73
|
end
|
|
74
|
+
|
|
75
|
+
it "accepts a block to change output" do
|
|
76
|
+
action :copy_file, "task.thor" do |content|
|
|
77
|
+
"OMG" + content
|
|
78
|
+
end
|
|
79
|
+
File.read(File.join(destination_root, "task.thor")).must =~ /^OMG/
|
|
80
|
+
end
|
|
75
81
|
end
|
|
76
82
|
|
|
77
83
|
describe "#get" do
|
|
@@ -117,7 +123,7 @@ describe Thor::Actions do
|
|
|
117
123
|
end
|
|
118
124
|
|
|
119
125
|
it "converts enconded instructions" do
|
|
120
|
-
|
|
126
|
+
runner.should_receive(:file_name).and_return("rdoc")
|
|
121
127
|
action :template, "doc/%file_name%.rb.tt"
|
|
122
128
|
file = File.join(destination_root, "doc/rdoc.rb.tt")
|
|
123
129
|
File.exists?(file).must be_true
|
|
@@ -126,6 +132,13 @@ describe Thor::Actions do
|
|
|
126
132
|
it "logs status" do
|
|
127
133
|
capture(:stdout){ runner.template("doc/config.rb") }.must == " create doc/config.rb\n"
|
|
128
134
|
end
|
|
135
|
+
|
|
136
|
+
it "accepts a block to change output" do
|
|
137
|
+
action :template, "doc/config.rb" do |content|
|
|
138
|
+
"OMG" + content
|
|
139
|
+
end
|
|
140
|
+
File.read(File.join(destination_root, "doc/config.rb")).must =~ /^OMG/
|
|
141
|
+
end
|
|
129
142
|
end
|
|
130
143
|
|
|
131
144
|
describe "when changing existent files" do
|
|
@@ -166,18 +179,18 @@ describe Thor::Actions do
|
|
|
166
179
|
describe "#gsub_file" do
|
|
167
180
|
it "replaces the content in the file" do
|
|
168
181
|
action :gsub_file, "doc/README", "__start__", "START"
|
|
169
|
-
File.
|
|
182
|
+
File.binread(file).must == "START\nREADME\n__end__\n"
|
|
170
183
|
end
|
|
171
184
|
|
|
172
185
|
it "does not replace if pretending" do
|
|
173
186
|
runner(:pretend => true)
|
|
174
187
|
action :gsub_file, "doc/README", "__start__", "START"
|
|
175
|
-
File.
|
|
188
|
+
File.binread(file).must == "__start__\nREADME\n__end__\n"
|
|
176
189
|
end
|
|
177
190
|
|
|
178
191
|
it "accepts a block" do
|
|
179
192
|
action(:gsub_file, "doc/README", "__start__"){ |match| match.gsub('__', '').upcase }
|
|
180
|
-
File.
|
|
193
|
+
File.binread(file).must == "START\nREADME\n__end__\n"
|
|
181
194
|
end
|
|
182
195
|
|
|
183
196
|
it "logs status" do
|
|
@@ -192,12 +205,12 @@ describe Thor::Actions do
|
|
|
192
205
|
describe "#append_file" do
|
|
193
206
|
it "appends content to the file" do
|
|
194
207
|
action :append_file, "doc/README", "END\n"
|
|
195
|
-
File.
|
|
208
|
+
File.binread(file).must == "__start__\nREADME\n__end__\nEND\n"
|
|
196
209
|
end
|
|
197
210
|
|
|
198
211
|
it "accepts a block" do
|
|
199
212
|
action(:append_file, "doc/README"){ "END\n" }
|
|
200
|
-
File.
|
|
213
|
+
File.binread(file).must == "__start__\nREADME\n__end__\nEND\n"
|
|
201
214
|
end
|
|
202
215
|
|
|
203
216
|
it "logs status" do
|
|
@@ -208,12 +221,12 @@ describe Thor::Actions do
|
|
|
208
221
|
describe "#prepend_file" do
|
|
209
222
|
it "prepends content to the file" do
|
|
210
223
|
action :prepend_file, "doc/README", "START\n"
|
|
211
|
-
File.
|
|
224
|
+
File.binread(file).must == "START\n__start__\nREADME\n__end__\n"
|
|
212
225
|
end
|
|
213
226
|
|
|
214
227
|
it "accepts a block" do
|
|
215
228
|
action(:prepend_file, "doc/README"){ "START\n" }
|
|
216
|
-
File.
|
|
229
|
+
File.binread(file).must == "START\n__start__\nREADME\n__end__\n"
|
|
217
230
|
end
|
|
218
231
|
|
|
219
232
|
it "logs status" do
|
|
@@ -228,12 +241,12 @@ describe Thor::Actions do
|
|
|
228
241
|
|
|
229
242
|
it "appends content to a class" do
|
|
230
243
|
action :inject_into_class, "application.rb", Application, " filter_parameters :password\n"
|
|
231
|
-
File.
|
|
244
|
+
File.binread(file).must == "class Application < Base\n filter_parameters :password\nend\n"
|
|
232
245
|
end
|
|
233
246
|
|
|
234
247
|
it "accepts a block" do
|
|
235
248
|
action(:inject_into_class, "application.rb", Application){ " filter_parameters :password\n" }
|
|
236
|
-
File.
|
|
249
|
+
File.binread(file).must == "class Application < Base\n filter_parameters :password\nend\n"
|
|
237
250
|
end
|
|
238
251
|
|
|
239
252
|
it "logs status" do
|
|
@@ -242,7 +255,7 @@ describe Thor::Actions do
|
|
|
242
255
|
|
|
243
256
|
it "does not append if class name does not match" do
|
|
244
257
|
action :inject_into_class, "application.rb", "App", " filter_parameters :password\n"
|
|
245
|
-
File.
|
|
258
|
+
File.binread(file).must == "class Application < Base\nend\n"
|
|
246
259
|
end
|
|
247
260
|
end
|
|
248
261
|
end
|
data/spec/actions_spec.rb
CHANGED
|
@@ -55,9 +55,10 @@ describe Thor::Actions do
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
it "does not use the current directory if one is given" do
|
|
58
|
+
root = File.expand_path("/")
|
|
58
59
|
base = MyCounter.new([1])
|
|
59
|
-
base.destination_root =
|
|
60
|
-
base.destination_root.must ==
|
|
60
|
+
base.destination_root = root
|
|
61
|
+
base.destination_root.must == root
|
|
61
62
|
end
|
|
62
63
|
|
|
63
64
|
it "uses the current directory if none is given" do
|
|
@@ -194,7 +195,7 @@ describe Thor::Actions do
|
|
|
194
195
|
@template.instance_eval "def read; self; end" # Make the string respond to read
|
|
195
196
|
|
|
196
197
|
@file = "http://gist.github.com/103208.txt"
|
|
197
|
-
|
|
198
|
+
runner.should_receive(:open).and_return(@template)
|
|
198
199
|
end
|
|
199
200
|
|
|
200
201
|
it "opens a file and executes its content in the instance binding" do
|
|
@@ -219,7 +220,7 @@ describe Thor::Actions do
|
|
|
219
220
|
|
|
220
221
|
describe "#run" do
|
|
221
222
|
before(:each) do
|
|
222
|
-
|
|
223
|
+
runner.should_receive(:system).with("ls")
|
|
223
224
|
end
|
|
224
225
|
|
|
225
226
|
it "executes the command given" do
|
|
@@ -235,15 +236,15 @@ describe Thor::Actions do
|
|
|
235
236
|
end
|
|
236
237
|
|
|
237
238
|
it "accepts a color as status" do
|
|
238
|
-
|
|
239
|
+
runner.shell.should_receive(:say_status).with(:run, 'ls from "."', :yellow)
|
|
239
240
|
action :run, "ls", :verbose => :yellow
|
|
240
241
|
end
|
|
241
242
|
end
|
|
242
243
|
|
|
243
244
|
describe "#run_ruby_script" do
|
|
244
245
|
before(:each) do
|
|
245
|
-
|
|
246
|
-
|
|
246
|
+
Thor::Util.stub!(:ruby_command).and_return("/opt/jruby")
|
|
247
|
+
runner.should_receive(:system).with("/opt/jruby script.rb")
|
|
247
248
|
end
|
|
248
249
|
|
|
249
250
|
it "executes the ruby script" do
|
|
@@ -261,30 +262,30 @@ describe Thor::Actions do
|
|
|
261
262
|
|
|
262
263
|
describe "#thor" do
|
|
263
264
|
it "executes the thor command" do
|
|
264
|
-
|
|
265
|
+
runner.should_receive(:system).with("thor list")
|
|
265
266
|
action :thor, :list, :verbose => true
|
|
266
267
|
end
|
|
267
268
|
|
|
268
269
|
it "converts extra arguments to command arguments" do
|
|
269
|
-
|
|
270
|
+
runner.should_receive(:system).with("thor list foo bar")
|
|
270
271
|
action :thor, :list, "foo", "bar"
|
|
271
272
|
end
|
|
272
273
|
|
|
273
274
|
it "converts options hash to switches" do
|
|
274
|
-
|
|
275
|
+
runner.should_receive(:system).with("thor list foo bar --foo")
|
|
275
276
|
action :thor, :list, "foo", "bar", :foo => true
|
|
276
277
|
|
|
277
|
-
|
|
278
|
+
runner.should_receive(:system).with("thor list --foo 1 2 3")
|
|
278
279
|
action :thor, :list, :foo => [1,2,3]
|
|
279
280
|
end
|
|
280
281
|
|
|
281
282
|
it "logs status" do
|
|
282
|
-
|
|
283
|
+
runner.should_receive(:system).with("thor list")
|
|
283
284
|
action(:thor, :list).must == " run thor list from \".\"\n"
|
|
284
285
|
end
|
|
285
286
|
|
|
286
287
|
it "does not log status if required" do
|
|
287
|
-
|
|
288
|
+
runner.should_receive(:system).with("thor list --foo 1 2 3")
|
|
288
289
|
action(:thor, :list, :foo => [1,2,3], :verbose => false).must be_empty
|
|
289
290
|
end
|
|
290
291
|
end
|
data/spec/base_spec.rb
CHANGED
|
@@ -134,7 +134,7 @@ describe Thor::Base do
|
|
|
134
134
|
it "allows extra options to be given" do
|
|
135
135
|
hash = { "Foo" => B.class_options.values }
|
|
136
136
|
|
|
137
|
-
content = capture(:stdout) { MyCounter.send(:class_options_help, Thor::Base.shell.new,
|
|
137
|
+
content = capture(:stdout) { MyCounter.send(:class_options_help, Thor::Base.shell.new, hash) }
|
|
138
138
|
content.must =~ /Foo options\:/
|
|
139
139
|
content.must =~ /--last-name=LAST_NAME/
|
|
140
140
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'execute')
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
FOO = <%= "FOO" %>
|