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.
@@ -0,0 +1,83 @@
1
+ class MyCounter < Thor::Group
2
+ include Thor::Actions
3
+ add_runtime_options!
4
+
5
+ def self.get_from_super
6
+ from_superclass(:get_from_super, 13)
7
+ end
8
+
9
+ def self.source_root
10
+ File.expand_path(File.dirname(__FILE__))
11
+ end
12
+ source_paths << File.expand_path("broken", File.dirname(__FILE__))
13
+
14
+ argument :first, :type => :numeric
15
+ argument :second, :type => :numeric, :default => 2
16
+
17
+ class_option :third, :type => :numeric, :desc => "The third argument", :default => 3,
18
+ :banner => "THREE", :aliases => "-t"
19
+ class_option :fourth, :type => :numeric, :desc => "The fourth argument"
20
+
21
+ desc <<-FOO
22
+ Description:
23
+ This generator run three tasks: one, two and three.
24
+ FOO
25
+
26
+ def one
27
+ first
28
+ end
29
+
30
+ def two
31
+ second
32
+ end
33
+
34
+ def three
35
+ options[:third]
36
+ end
37
+
38
+ def self.inherited(base)
39
+ super
40
+ base.source_paths.unshift(File.expand_path(File.join(File.dirname(__FILE__), "doc")))
41
+ end
42
+ end
43
+
44
+ class ClearCounter < MyCounter
45
+ remove_argument :first, :second, :undefine => true
46
+ remove_class_option :third
47
+
48
+ def self.source_root
49
+ File.expand_path(File.join(File.dirname(__FILE__), "bundle"))
50
+ end
51
+ end
52
+
53
+ class BrokenCounter < MyCounter
54
+ namespace "app:broken:counter"
55
+ class_option :fail, :type => :boolean, :default => false
56
+
57
+ class << self
58
+ undef_method :source_root
59
+ end
60
+
61
+ def one
62
+ options[:first]
63
+ end
64
+
65
+ def four
66
+ respond_to?(:fail)
67
+ end
68
+
69
+ def five
70
+ options[:fail] ? this_method_does_not_exist : 5
71
+ end
72
+ end
73
+
74
+ class WhinyGenerator < Thor::Group
75
+ include Thor::Actions
76
+
77
+ def self.source_root
78
+ File.expand_path(File.dirname(__FILE__))
79
+ end
80
+
81
+ def wrong_arity(required)
82
+ end
83
+ end
@@ -0,0 +1,112 @@
1
+ class A < Thor
2
+ include Thor::Actions
3
+
4
+ desc "one", "invoke one"
5
+ def one
6
+ p 1
7
+ invoke :two
8
+ invoke :three
9
+ end
10
+
11
+ desc "two", "invoke two"
12
+ def two
13
+ p 2
14
+ invoke :three
15
+ end
16
+
17
+ desc "three", "invoke three"
18
+ def three
19
+ p 3
20
+ end
21
+
22
+ desc "four", "invoke four"
23
+ def four
24
+ p 4
25
+ invoke "defined:five"
26
+ end
27
+
28
+ desc "five N", "check if number is equal 5"
29
+ def five(number)
30
+ number == 5
31
+ end
32
+
33
+ desc "invoker", "invoke a b task"
34
+ def invoker(*args)
35
+ invoke :b, :one, ["Jose"]
36
+ end
37
+ end
38
+
39
+ class B < Thor
40
+ class_option :last_name, :type => :string
41
+
42
+ desc "one FIRST_NAME", "invoke one"
43
+ def one(first_name)
44
+ "#{options.last_name}, #{first_name}"
45
+ end
46
+
47
+ desc "two", "invoke two"
48
+ def two
49
+ options
50
+ end
51
+
52
+ desc "three", "invoke three"
53
+ def three
54
+ self
55
+ end
56
+ end
57
+
58
+ class C < Thor::Group
59
+ include Thor::Actions
60
+
61
+ def one
62
+ p 1
63
+ end
64
+
65
+ def two
66
+ p 2
67
+ end
68
+
69
+ def three
70
+ p 3
71
+ end
72
+ end
73
+
74
+ class Defined < Thor::Group
75
+ class_option :unused, :type => :boolean, :desc => "This option has no use"
76
+
77
+ def one
78
+ p 1
79
+ invoke "a:two"
80
+ invoke "a:three"
81
+ invoke "a:four"
82
+ invoke "defined:five"
83
+ end
84
+
85
+ def five
86
+ p 5
87
+ end
88
+
89
+ def print_status
90
+ say_status :finished, :counting
91
+ end
92
+ end
93
+
94
+ class E < Thor::Group
95
+ invoke Defined
96
+ end
97
+
98
+ class F < Thor::Group
99
+ invoke "b:one" do |instance, klass, task|
100
+ instance.invoke klass, task, [ "Jose" ], :last_name => "Valim"
101
+ end
102
+ end
103
+
104
+ class G < Thor::Group
105
+ class_option :invoked, :type => :string, :default => "defined"
106
+ invoke_from_option :invoked
107
+ end
108
+
109
+ class H < Thor::Group
110
+ class_option :defined, :type => :boolean, :default => true
111
+ invoke_from_option :defined
112
+ end
@@ -0,0 +1,130 @@
1
+ class MyScript < Thor
2
+ group :script
3
+ default_task :example_default_task
4
+
5
+ map "-T" => :animal, ["-f", "--foo"] => :foo
6
+
7
+ desc "zoo", "zoo around"
8
+ def zoo
9
+ true
10
+ end
11
+
12
+ desc "animal TYPE", "horse around"
13
+
14
+ no_tasks do
15
+ def this_is_not_a_task
16
+ end
17
+ end
18
+
19
+ def animal(type)
20
+ [type]
21
+ end
22
+
23
+ desc "foo BAR", <<END
24
+ do some fooing
25
+ This is more info!
26
+ Everyone likes more info!
27
+ END
28
+ method_option :force, :type => :boolean, :desc => "Force to do some fooing"
29
+ def foo(bar)
30
+ [bar, options]
31
+ end
32
+
33
+ desc "example_default_task", "example!"
34
+ def example_default_task
35
+ options.empty? ? "default task" : options
36
+ end
37
+
38
+ desc "call_myself_with_wrong_arity", "get the right error"
39
+ def call_myself_with_wrong_arity
40
+ call_myself_with_wrong_arity(4)
41
+ end
42
+
43
+ desc "call_unexistent_method", "Call unexistent method inside a task"
44
+ def call_unexistent_method
45
+ boom!
46
+ end
47
+
48
+ desc "long_description", "a" * 80
49
+ def long_description
50
+ end
51
+
52
+ method_options :all => :boolean
53
+ desc "with_optional NAME", "invoke with optional name"
54
+ def with_optional(name=nil)
55
+ [ name, options ]
56
+ end
57
+
58
+ class AnotherScript < Thor
59
+ desc "baz", "do some bazing"
60
+ def baz
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def method_missing(meth, *args)
67
+ if meth == :boom!
68
+ super
69
+ else
70
+ [meth, args]
71
+ end
72
+ end
73
+
74
+ desc "what", "what"
75
+ def what
76
+ end
77
+ end
78
+
79
+ class MyChildScript < MyScript
80
+ remove_task :bar
81
+
82
+ method_options :force => :boolean, :param => :numeric
83
+ def initialize(*args)
84
+ super
85
+ end
86
+
87
+ desc "zoo", "zoo around"
88
+ method_options :param => :required
89
+ def zoo
90
+ options
91
+ end
92
+
93
+ desc "animal TYPE", "horse around"
94
+ def animal(type)
95
+ [type, options]
96
+ end
97
+ method_option :other, :type => :string, :default => "method default", :for => :animal
98
+ desc "animal KIND", "fish around", :for => :animal
99
+
100
+ desc "boom", "explodes everything"
101
+ def boom
102
+ end
103
+
104
+ remove_task :boom, :undefine => true
105
+ end
106
+
107
+ module Scripts
108
+ class MyScript < MyChildScript
109
+ argument :accessor, :type => :string
110
+ class_options :force => :boolean
111
+ method_option :new_option, :type => :string, :for => :example_default_task
112
+
113
+ def zoo
114
+ self.accessor
115
+ end
116
+ end
117
+
118
+ class MyDefaults < Thor
119
+ namespace :default
120
+ desc "test", "prints 'test'"
121
+ def test
122
+ puts "test"
123
+ end
124
+ end
125
+
126
+ class ChildDefault < Thor
127
+ namespace "default:child"
128
+ end
129
+ end
130
+
@@ -0,0 +1,10 @@
1
+ # module: random
2
+
3
+ class Amazing < Thor
4
+ desc "describe NAME", "say that someone is amazing"
5
+ method_options :forcefully => :boolean
6
+ def describe(name, opts)
7
+ ret = "#{name} is amazing"
8
+ puts opts["forcefully"] ? ret.upcase : ret
9
+ end
10
+ end
data/spec/group_spec.rb CHANGED
@@ -29,7 +29,7 @@ describe Thor::Group do
29
29
  end
30
30
 
31
31
  it "invokes help message if any of the shortcuts is given" do
32
- stub(MyCounter).help
32
+ MyCounter.should_receive(:help)
33
33
  MyCounter.start(["-h"])
34
34
  end
35
35
  end
@@ -66,12 +66,6 @@ describe Thor::Group do
66
66
  @content.must =~ /Options/
67
67
  @content.must =~ /\[\-\-third=THREE\]/
68
68
  end
69
-
70
- it "shows only usage if a short help is required" do
71
- content = capture(:stdout){ MyCounter.help(Thor::Base.shell.new, :short => true) }
72
- content.must =~ /my_counter N \[N\]/
73
- content.must_not =~ /Options/
74
- end
75
69
  end
76
70
 
77
71
  describe "#invoke" do
data/spec/runner_spec.rb CHANGED
@@ -26,11 +26,11 @@ describe Thor::Runner do
26
26
 
27
27
  it "shows information about a specific Thor group class" do
28
28
  content = capture(:stdout){ Thor::Runner.start(["help", "my_counter"]) }
29
- content.must =~ /my_counter N \[N\]/
29
+ content.must =~ /my_counter N/
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
+ Thor::Runner.should_receive(:exit).with(1)
34
34
  content = capture(:stderr){ Thor::Runner.start(["help", "unknown"]) }
35
35
  content.must =~ /could not find Thor class or task 'unknown'/
36
36
  end
@@ -39,7 +39,7 @@ describe Thor::Runner do
39
39
  describe "#start" do
40
40
  it "invokes a task from Thor::Runner" do
41
41
  ARGV.replace ["list"]
42
- capture(:stdout){ Thor::Runner.start }.must =~ /my_counter N \[N\]/
42
+ capture(:stdout){ Thor::Runner.start }.must =~ /my_counter N/
43
43
  end
44
44
 
45
45
  it "invokes a task from a specific Thor class" do
@@ -68,7 +68,7 @@ describe Thor::Runner do
68
68
  end
69
69
 
70
70
  it "raises an error if class/task can't be found" do
71
- mock(Thor::Runner).exit(1)
71
+ Thor::Runner.should_receive(:exit).with(1)
72
72
  ARGV.replace ["unknown"]
73
73
  capture(:stderr){ Thor::Runner.start }.must =~ /could not find Thor class or task 'unknown'/
74
74
  end
@@ -78,12 +78,12 @@ describe Thor::Runner do
78
78
  lambda { Thor::Runner.start }.must raise_error(NoMethodError)
79
79
  end
80
80
 
81
- it "does not swallow Thor::Group ArgumentError" do
81
+ it "does not swallow Thor::Group InvocationError" do
82
82
  ARGV.replace ["whiny_generator"]
83
83
  lambda { Thor::Runner.start }.must raise_error(ArgumentError, /Are you sure it has arity equals to 0\?/)
84
84
  end
85
85
 
86
- it "does not swallow Thor ArgumentError" do
86
+ it "does not swallow Thor InvocationError" do
87
87
  ARGV.replace ["my_script:animal"]
88
88
  capture(:stderr) { Thor::Runner.start }.must =~ /'animal' was called incorrectly\. Call as 'my_script:animal TYPE'/
89
89
  end
@@ -96,26 +96,28 @@ describe Thor::Runner do
96
96
  "random" => {
97
97
  :location => @location,
98
98
  :filename => "4a33b894ffce85d7b412fc1b36f88fe0",
99
- :constants => ["Amazing"]
99
+ :namespaces => ["amazing"]
100
100
  }
101
101
  }
102
102
 
103
+ root_file = File.join(Thor::Util.thor_root, "thor.yml")
104
+
103
105
  # Stub load and save to avoid thor.yaml from being overwritten
104
- stub(YAML).load_file { @original_yaml }
105
- stub(File).exists?(File.join(Thor::Util.thor_root, "thor.yml")){ true }
106
- stub(File).open(File.join(Thor::Util.thor_root, "thor.yml"), "w")
106
+ YAML.stub!(:load_file).and_return(@original_yaml)
107
+ File.stub!(:exists?).with(root_file).and_return(true)
108
+ File.stub!(:open).with(root_file, "w")
107
109
  end
108
110
 
109
111
  describe "list" do
110
112
  it "gives a list of the available tasks" do
111
113
  ARGV.replace ["list"]
112
114
  content = capture(:stdout) { Thor::Runner.start }
113
- content.must =~ /amazing:describe NAME \[\-\-forcefully\]\s+# say that someone is amazing/m
115
+ content.must =~ /amazing:describe NAME\s+# say that someone is amazing/m
114
116
  end
115
117
 
116
118
  it "gives a list of the available Thor::Group classes" do
117
119
  ARGV.replace ["list"]
118
- capture(:stdout) { Thor::Runner.start }.must =~ /my_counter N \[N\]/
120
+ capture(:stdout) { Thor::Runner.start }.must =~ /my_counter N/
119
121
  end
120
122
 
121
123
  it "can filter a list of the available tasks by --group" do
@@ -141,33 +143,19 @@ describe Thor::Runner do
141
143
 
142
144
  it "presents tasks in the default namespace with an empty namespace" do
143
145
  ARGV.replace ["list"]
144
- capture(:stdout) { Thor::Runner.start }.must =~ /^:test\s+# prints 'test'/m
146
+ capture(:stdout) { Thor::Runner.start }.must =~ /^thor :test\s+# prints 'test'/m
145
147
  end
146
148
 
147
149
  it "runs tasks with an empty namespace from the default namespace" do
148
150
  ARGV.replace [":test"]
149
151
  capture(:stdout) { Thor::Runner.start }.must == "test\n"
150
152
  end
151
-
152
- it "updates the yaml file when invoked" do
153
- capture(:stdout) { Thor::Runner.start(["list"]) }
154
- @original_yaml["random"][:namespaces].must == ["amazing"]
155
- end
156
- end
157
-
158
- describe "update" do
159
- it "updates existing thor files" do
160
- mock.instance_of(Thor::Runner).install(@original_yaml["random"][:location]) { true }
161
- stub(File).delete(File.join(Thor::Util.thor_root, @original_yaml["random"][:filename]))
162
- silence(:stdout) { Thor::Runner.start(["update", "random"]) }
163
- end
164
153
  end
165
154
 
166
155
  describe "uninstall" do
167
156
  before(:each) do
168
- stub.instance_of(Thor::Runner).save_yaml(anything)
169
- stub(File).delete(anything)
170
- stub(@original_yaml).delete(anything)
157
+ path = File.join(Thor::Util.thor_root, @original_yaml["random"][:filename])
158
+ FileUtils.should_receive(:rm_rf).with(path)
171
159
  end
172
160
 
173
161
  it "uninstalls existing thor modules" do
@@ -177,26 +165,34 @@ describe Thor::Runner do
177
165
 
178
166
  describe "installed" do
179
167
  before(:each) do
180
- stub(Dir).[](anything) { [] }
168
+ Dir.should_receive(:[]).and_return([])
181
169
  end
182
170
 
183
171
  it "displays the modules installed in a pretty way" do
184
172
  stdout = capture(:stdout) { Thor::Runner.start(["installed"]) }
185
173
  stdout.must =~ /random\s*amazing/
186
- stdout.must =~ /amazing:describe NAME \[\-\-forcefully\]\s+# say that someone is amazing/m
174
+ stdout.must =~ /amazing:describe NAME\s+# say that someone is amazing/m
187
175
  end
188
176
  end
189
177
 
190
- describe "install" do
191
- it "installs thor files" do
192
- ARGV.replace ["install", @location]
178
+ describe "install/update" do
179
+ before(:each) do
180
+ FileUtils.stub!(:mkdir_p)
181
+ FileUtils.stub!(:touch)
182
+ $stdin.stub!(:gets).and_return("Y")
193
183
 
194
- # Stubs for the file system interactions
195
- stub.instance_of(Thor::Base.shell).no? { false }
196
- stub(FileUtils).mkdir_p
197
- stub(FileUtils).touch
184
+ path = File.join(Thor::Util.thor_root, Digest::MD5.hexdigest(@location + "random"))
185
+ File.should_receive(:open).with(path, "w")
186
+ end
198
187
 
199
- mock(File).open(File.join(Thor::Util.thor_root, Digest::MD5.hexdigest(@location + "random")), "w")
188
+ it "updates existing thor files" do
189
+ path = File.join(Thor::Util.thor_root, @original_yaml["random"][:filename])
190
+ File.should_receive(:delete).with(path)
191
+ silence(:stdout) { Thor::Runner.start(["update", "random"]) }
192
+ end
193
+
194
+ it "installs thor files" do
195
+ ARGV.replace ["install", @location]
200
196
  silence(:stdout) { Thor::Runner.start }
201
197
  end
202
198
  end