millisami-thor 0.14.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/.autotest +8 -0
  2. data/.gemtest +0 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +1 -0
  5. data/CHANGELOG.rdoc +103 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE.md +20 -0
  8. data/README.md +26 -0
  9. data/Thorfile +13 -0
  10. data/bin/rake2thor +86 -0
  11. data/bin/thor +6 -0
  12. data/lib/thor/actions/create_file.rb +105 -0
  13. data/lib/thor/actions/create_link.rb +57 -0
  14. data/lib/thor/actions/directory.rb +93 -0
  15. data/lib/thor/actions/empty_directory.rb +134 -0
  16. data/lib/thor/actions/file_manipulation.rb +270 -0
  17. data/lib/thor/actions/inject_into_file.rb +109 -0
  18. data/lib/thor/actions.rb +314 -0
  19. data/lib/thor/base.rb +598 -0
  20. data/lib/thor/core_ext/file_binary_read.rb +9 -0
  21. data/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  22. data/lib/thor/core_ext/ordered_hash.rb +100 -0
  23. data/lib/thor/error.rb +30 -0
  24. data/lib/thor/group.rb +276 -0
  25. data/lib/thor/invocation.rb +168 -0
  26. data/lib/thor/parser/argument.rb +67 -0
  27. data/lib/thor/parser/arguments.rb +165 -0
  28. data/lib/thor/parser/option.rb +120 -0
  29. data/lib/thor/parser/options.rb +181 -0
  30. data/lib/thor/parser.rb +4 -0
  31. data/lib/thor/rake_compat.rb +70 -0
  32. data/lib/thor/runner.rb +309 -0
  33. data/lib/thor/shell/basic.rb +302 -0
  34. data/lib/thor/shell/color.rb +108 -0
  35. data/lib/thor/shell/html.rb +121 -0
  36. data/lib/thor/shell.rb +88 -0
  37. data/lib/thor/task.rb +129 -0
  38. data/lib/thor/util.rb +229 -0
  39. data/lib/thor/version.rb +3 -0
  40. data/lib/thor.rb +336 -0
  41. data/spec/actions/create_file_spec.rb +170 -0
  42. data/spec/actions/directory_spec.rb +136 -0
  43. data/spec/actions/empty_directory_spec.rb +98 -0
  44. data/spec/actions/file_manipulation_spec.rb +317 -0
  45. data/spec/actions/inject_into_file_spec.rb +135 -0
  46. data/spec/actions_spec.rb +322 -0
  47. data/spec/base_spec.rb +274 -0
  48. data/spec/core_ext/hash_with_indifferent_access_spec.rb +43 -0
  49. data/spec/core_ext/ordered_hash_spec.rb +115 -0
  50. data/spec/fixtures/application.rb +2 -0
  51. data/spec/fixtures/bundle/execute.rb +6 -0
  52. data/spec/fixtures/bundle/main.thor +1 -0
  53. data/spec/fixtures/doc/%file_name%.rb.tt +1 -0
  54. data/spec/fixtures/doc/README +3 -0
  55. data/spec/fixtures/doc/block_helper.rb +3 -0
  56. data/spec/fixtures/doc/components/.empty_directory +0 -0
  57. data/spec/fixtures/doc/config.rb +1 -0
  58. data/spec/fixtures/doc/config.yaml.tt +1 -0
  59. data/spec/fixtures/group.thor +114 -0
  60. data/spec/fixtures/invoke.thor +112 -0
  61. data/spec/fixtures/path with spaces +0 -0
  62. data/spec/fixtures/script.thor +184 -0
  63. data/spec/fixtures/task.thor +10 -0
  64. data/spec/group_spec.rb +216 -0
  65. data/spec/invocation_spec.rb +100 -0
  66. data/spec/parser/argument_spec.rb +47 -0
  67. data/spec/parser/arguments_spec.rb +65 -0
  68. data/spec/parser/option_spec.rb +202 -0
  69. data/spec/parser/options_spec.rb +329 -0
  70. data/spec/rake_compat_spec.rb +72 -0
  71. data/spec/register_spec.rb +92 -0
  72. data/spec/runner_spec.rb +210 -0
  73. data/spec/shell/basic_spec.rb +223 -0
  74. data/spec/shell/color_spec.rb +41 -0
  75. data/spec/shell/html_spec.rb +27 -0
  76. data/spec/shell_spec.rb +47 -0
  77. data/spec/spec_helper.rb +54 -0
  78. data/spec/task_spec.rb +74 -0
  79. data/spec/thor_spec.rb +362 -0
  80. data/spec/util_spec.rb +163 -0
  81. data/thor.gemspec +25 -0
  82. metadata +241 -0
@@ -0,0 +1,322 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Thor::Actions do
4
+ def runner(options={})
5
+ @runner ||= MyCounter.new([1], options, { :destination_root => destination_root })
6
+ end
7
+
8
+ def action(*args, &block)
9
+ capture(:stdout){ runner.send(*args, &block) }
10
+ end
11
+
12
+ def file
13
+ File.join(destination_root, "foo")
14
+ end
15
+
16
+ describe "on include" do
17
+ it "adds runtime options to the base class" do
18
+ MyCounter.class_options.keys.should include(:pretend)
19
+ MyCounter.class_options.keys.should include(:force)
20
+ MyCounter.class_options.keys.should include(:quiet)
21
+ MyCounter.class_options.keys.should include(:skip)
22
+ end
23
+ end
24
+
25
+ describe "#initialize" do
26
+ it "has default behavior invoke" do
27
+ runner.behavior.should == :invoke
28
+ end
29
+
30
+ it "can have behavior revoke" do
31
+ MyCounter.new([1], {}, :behavior => :revoke).behavior.should == :revoke
32
+ end
33
+
34
+ it "when behavior is set to force, overwrite options" do
35
+ runner = MyCounter.new([1], { :force => false, :skip => true }, :behavior => :force)
36
+ runner.behavior.should == :invoke
37
+ runner.options.force.should be_true
38
+ runner.options.skip.should_not be_true
39
+ end
40
+
41
+ it "when behavior is set to skip, overwrite options" do
42
+ runner = MyCounter.new([1], ["--force"], :behavior => :skip)
43
+ runner.behavior.should == :invoke
44
+ runner.options.force.should_not be_true
45
+ runner.options.skip.should be_true
46
+ end
47
+ end
48
+
49
+ describe "accessors" do
50
+ describe "#destination_root=" do
51
+ it "gets the current directory and expands the path to set the root" do
52
+ base = MyCounter.new([1])
53
+ base.destination_root = "here"
54
+ base.destination_root.should == File.expand_path(File.join(File.dirname(__FILE__), "..", "here"))
55
+ end
56
+
57
+ it "does not use the current directory if one is given" do
58
+ root = File.expand_path("/")
59
+ base = MyCounter.new([1])
60
+ base.destination_root = root
61
+ base.destination_root.should == root
62
+ end
63
+
64
+ it "uses the current directory if none is given" do
65
+ base = MyCounter.new([1])
66
+ base.destination_root.should == File.expand_path(File.join(File.dirname(__FILE__), ".."))
67
+ end
68
+ end
69
+
70
+ describe "#relative_to_original_destination_root" do
71
+ it "returns the path relative to the absolute root" do
72
+ runner.relative_to_original_destination_root(file).should == "foo"
73
+ end
74
+
75
+ it "does not remove dot if required" do
76
+ runner.relative_to_original_destination_root(file, false).should == "./foo"
77
+ end
78
+
79
+ it "always use the absolute root" do
80
+ runner.inside("foo") do
81
+ runner.relative_to_original_destination_root(file).should == "foo"
82
+ end
83
+ end
84
+
85
+ describe "#source_paths_for_search" do
86
+ it "add source_root to source_paths_for_search" do
87
+ MyCounter.source_paths_for_search.should include(File.expand_path("fixtures", File.dirname(__FILE__)))
88
+ end
89
+
90
+ it "keeps only current source root in source paths" do
91
+ ClearCounter.source_paths_for_search.should include(File.expand_path("fixtures/bundle", File.dirname(__FILE__)))
92
+ ClearCounter.source_paths_for_search.should_not include(File.expand_path("fixtures", File.dirname(__FILE__)))
93
+ end
94
+
95
+ it "customized source paths should be before source roots" do
96
+ ClearCounter.source_paths_for_search[0].should == File.expand_path("fixtures/doc", File.dirname(__FILE__))
97
+ ClearCounter.source_paths_for_search[1].should == File.expand_path("fixtures/bundle", File.dirname(__FILE__))
98
+ end
99
+
100
+ it "keeps inherited source paths at the end" do
101
+ ClearCounter.source_paths_for_search.last.should == File.expand_path("fixtures/broken", File.dirname(__FILE__))
102
+ end
103
+ end
104
+ end
105
+
106
+ describe "#find_in_source_paths" do
107
+ it "raises an error if source path is empty" do
108
+ lambda {
109
+ A.new.find_in_source_paths("foo")
110
+ }.should raise_error(Thor::Error, /Currently you have no source paths/)
111
+ end
112
+
113
+ it "finds a template inside the source path" do
114
+ runner.find_in_source_paths("doc").should == File.expand_path("doc", source_root)
115
+ lambda { runner.find_in_source_paths("README") }.should raise_error
116
+
117
+ new_path = File.join(source_root, "doc")
118
+ runner.instance_variable_set(:@source_paths, nil)
119
+ runner.source_paths.unshift(new_path)
120
+ runner.find_in_source_paths("README").should == File.expand_path("README", new_path)
121
+ end
122
+ end
123
+ end
124
+
125
+ describe "#inside" do
126
+ it "executes the block inside the given folder" do
127
+ runner.inside("foo") do
128
+ Dir.pwd.should == file
129
+ end
130
+ end
131
+
132
+ it "changes the base root" do
133
+ runner.inside("foo") do
134
+ runner.destination_root.should == file
135
+ end
136
+ end
137
+
138
+ it "creates the directory if it does not exist" do
139
+ runner.inside("foo") do
140
+ File.exists?(file).should be_true
141
+ end
142
+ end
143
+
144
+ describe "when pretending" do
145
+ it "no directories should be created" do
146
+ runner.inside("bar", :pretend => true) {}
147
+ File.exists?("bar").should be_false
148
+ end
149
+ end
150
+
151
+ describe "when verbose" do
152
+ it "logs status" do
153
+ capture(:stdout) do
154
+ runner.inside("foo", :verbose => true) {}
155
+ end.should =~ /inside foo/
156
+ end
157
+
158
+ it "uses padding in next status" do
159
+ capture(:stdout) do
160
+ runner.inside("foo", :verbose => true) do
161
+ runner.say_status :cool, :padding
162
+ end
163
+ end.should =~ /cool padding/
164
+ end
165
+
166
+ it "removes padding after block" do
167
+ capture(:stdout) do
168
+ runner.inside("foo", :verbose => true) {}
169
+ runner.say_status :no, :padding
170
+ end.should =~ /no padding/
171
+ end
172
+ end
173
+ end
174
+
175
+ describe "#in_root" do
176
+ it "executes the block in the root folder" do
177
+ runner.inside("foo") do
178
+ runner.in_root { Dir.pwd.should == destination_root }
179
+ end
180
+ end
181
+
182
+ it "changes the base root" do
183
+ runner.inside("foo") do
184
+ runner.in_root { runner.destination_root.should == destination_root }
185
+ end
186
+ end
187
+
188
+ it "returns to the previous state" do
189
+ runner.inside("foo") do
190
+ runner.in_root { }
191
+ runner.destination_root.should == file
192
+ end
193
+ end
194
+ end
195
+
196
+ describe "#apply" do
197
+ before(:each) do
198
+ @template = <<-TEMPLATE
199
+ @foo = "FOO"
200
+ say_status :cool, :padding
201
+ TEMPLATE
202
+ @template.stub(:read).and_return(@template)
203
+
204
+ @file = '/'
205
+ runner.stub(:open).and_return(@template)
206
+ end
207
+
208
+ it "accepts a URL as the path" do
209
+ @file = "http://gist.github.com/103208.txt"
210
+ runner.should_receive(:open).with(@file, "Accept" => "application/x-thor-template").and_return(@template)
211
+ action(:apply, @file)
212
+ end
213
+
214
+ it "accepts a secure URL as the path" do
215
+ @file = "https://gist.github.com/103208.txt"
216
+ runner.should_receive(:open).with(@file, "Accept" => "application/x-thor-template").and_return(@template)
217
+ action(:apply, @file)
218
+ end
219
+
220
+ it "accepts a local file path with spaces" do
221
+ @file = File.expand_path("fixtures/path with spaces", File.dirname(__FILE__))
222
+ runner.should_receive(:open).with(@file).and_return(@template)
223
+ action(:apply, @file)
224
+ end
225
+
226
+ it "opens a file and executes its content in the instance binding" do
227
+ action :apply, @file
228
+ runner.instance_variable_get("@foo").should == "FOO"
229
+ end
230
+
231
+ it "applies padding to the content inside the file" do
232
+ action(:apply, @file).should =~ /cool padding/
233
+ end
234
+
235
+ it "logs its status" do
236
+ action(:apply, @file).should =~ / apply #{@file}\n/
237
+ end
238
+
239
+ it "does not log status" do
240
+ content = action(:apply, @file, :verbose => false)
241
+ content.should =~ /cool padding/
242
+ content.should_not =~ /apply http/
243
+ end
244
+ end
245
+
246
+ describe "#run_cmd" do
247
+ before(:each) do
248
+ runner.should_receive(:system).with("ls")
249
+ end
250
+
251
+ it "executes the command given" do
252
+ action :run_cmd, "ls"
253
+ end
254
+
255
+ it "logs status" do
256
+ action(:run_cmd, "ls").should == " run_cmd ls from \".\"\n"
257
+ end
258
+
259
+ it "does not log status if required" do
260
+ action(:run_cmd, "ls", :verbose => false).should be_empty
261
+ end
262
+
263
+ it "accepts a color as status" do
264
+ runner.shell.should_receive(:say_status).with(:run_cmd, 'ls from "."', :yellow)
265
+ action :run_cmd, "ls", :verbose => :yellow
266
+ end
267
+ end
268
+
269
+ describe "#run_ruby_script" do
270
+ before(:each) do
271
+ Thor::Util.stub!(:ruby_command).and_return("/opt/jruby")
272
+ runner.should_receive(:system).with("/opt/jruby script.rb")
273
+ end
274
+
275
+ it "executes the ruby script" do
276
+ action :run_ruby_script, "script.rb"
277
+ end
278
+
279
+ it "logs status" do
280
+ action(:run_ruby_script, "script.rb").should == " run_cmd jruby script.rb from \".\"\n"
281
+ end
282
+
283
+ it "does not log status if required" do
284
+ action(:run_ruby_script, "script.rb", :verbose => false).should be_empty
285
+ end
286
+ end
287
+
288
+ describe "#thor" do
289
+ it "executes the thor command" do
290
+ runner.should_receive(:system).with("thor list")
291
+ action :thor, :list, :verbose => true
292
+ end
293
+
294
+ it "converts extra arguments to command arguments" do
295
+ runner.should_receive(:system).with("thor list foo bar")
296
+ action :thor, :list, "foo", "bar"
297
+ end
298
+
299
+ it "converts options hash to switches" do
300
+ runner.should_receive(:system).with("thor list foo bar --foo")
301
+ action :thor, :list, "foo", "bar", :foo => true
302
+
303
+ runner.should_receive(:system).with("thor list --foo 1 2 3")
304
+ action :thor, :list, :foo => [1,2,3]
305
+ end
306
+
307
+ it "logs status" do
308
+ runner.should_receive(:system).with("thor list")
309
+ action(:thor, :list).should == " run_cmd thor list from \".\"\n"
310
+ end
311
+
312
+ it "does not log status if required" do
313
+ runner.should_receive(:system).with("thor list --foo 1 2 3")
314
+ action(:thor, :list, :foo => [1,2,3], :verbose => false).should be_empty
315
+ end
316
+
317
+ it "captures the output when :capture is given" do
318
+ runner.should_receive(:`).with("thor foo bar")
319
+ action(:thor, "foo", "bar", :capture => true)
320
+ end
321
+ end
322
+ end
data/spec/base_spec.rb ADDED
@@ -0,0 +1,274 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'thor/base'
3
+
4
+ class Amazing
5
+ desc "hello", "say hello"
6
+ def hello
7
+ puts "Hello"
8
+ end
9
+ end
10
+
11
+ describe Thor::Base do
12
+ describe "#initialize" do
13
+ it "sets arguments array" do
14
+ base = MyCounter.new [1, 2]
15
+ base.first.should == 1
16
+ base.second.should == 2
17
+ end
18
+
19
+ it "sets arguments default values" do
20
+ base = MyCounter.new [1]
21
+ base.second.should == 2
22
+ end
23
+
24
+ it "sets options default values" do
25
+ base = MyCounter.new [1, 2]
26
+ base.options[:third].should == 3
27
+ end
28
+
29
+ it "allows options to be given as symbols or strings" do
30
+ base = MyCounter.new [1, 2], :third => 4
31
+ base.options[:third].should == 4
32
+
33
+ base = MyCounter.new [1, 2], "third" => 4
34
+ base.options[:third].should == 4
35
+ end
36
+
37
+ it "creates options with indifferent access" do
38
+ base = MyCounter.new [1, 2], :third => 3
39
+ base.options['third'].should == 3
40
+ end
41
+
42
+ it "creates options with magic predicates" do
43
+ base = MyCounter.new [1, 2], :third => 3
44
+ base.options.third.should == 3
45
+ end
46
+ end
47
+
48
+ describe "#no_tasks" do
49
+ it "avoids methods being added as tasks" do
50
+ MyScript.tasks.keys.should include("animal")
51
+ MyScript.tasks.keys.should_not include("this_is_not_a_task")
52
+ end
53
+ end
54
+
55
+ describe "#argument" do
56
+ it "sets a value as required and creates an accessor for it" do
57
+ MyCounter.start(["1", "2", "--third", "3"])[0].should == 1
58
+ Scripts::MyScript.start(["zoo", "my_special_param", "--param=normal_param"]).should == "my_special_param"
59
+ end
60
+
61
+ it "does not set a value in the options hash" do
62
+ BrokenCounter.start(["1", "2", "--third", "3"])[0].should be_nil
63
+ end
64
+ end
65
+
66
+ describe "#arguments" do
67
+ it "returns the arguments for the class" do
68
+ MyCounter.arguments.should have(2).items
69
+ end
70
+ end
71
+
72
+ describe "#class_option" do
73
+ it "sets options class wise" do
74
+ MyCounter.start(["1", "2", "--third", "3"])[2].should == 3
75
+ end
76
+
77
+ it "does not create an accessor for it" do
78
+ BrokenCounter.start(["1", "2", "--third", "3"])[3].should be_false
79
+ end
80
+ end
81
+
82
+ describe "#class_options" do
83
+ it "sets default options overwriting superclass definitions" do
84
+ options = Scripts::MyScript.class_options
85
+ options[:force].should_not be_required
86
+ end
87
+ end
88
+
89
+ describe "#remove_argument" do
90
+ it "removes previous defined arguments from class" do
91
+ ClearCounter.arguments.should be_empty
92
+ end
93
+
94
+ it "undefine accessors if required" do
95
+ ClearCounter.new.should_not respond_to(:first)
96
+ ClearCounter.new.should_not respond_to(:second)
97
+ end
98
+ end
99
+
100
+ describe "#remove_class_option" do
101
+ it "removes previous defined class option" do
102
+ ClearCounter.class_options[:third].should be_nil
103
+ end
104
+ end
105
+
106
+ describe "#class_options_help" do
107
+ before(:each) do
108
+ @content = capture(:stdout) { MyCounter.help(Thor::Base.shell.new) }
109
+ end
110
+
111
+ it "shows options description" do
112
+ @content.should =~ /# The third argument/
113
+ end
114
+
115
+ it "shows usage with banner content" do
116
+ @content.should =~ /\[\-\-third=THREE\]/
117
+ end
118
+
119
+ it "shows default values below description" do
120
+ @content.should =~ /# Default: 3/
121
+ end
122
+
123
+ it "shows options in different groups" do
124
+ @content.should =~ /Options\:/
125
+ @content.should =~ /Runtime options\:/
126
+ @content.should =~ /\-p, \[\-\-pretend\]/
127
+ end
128
+
129
+ it "use padding in options that does not have aliases" do
130
+ @content.should =~ /^ -t, \[--third/
131
+ @content.should =~ /^ \[--fourth/
132
+ end
133
+
134
+ it "allows extra options to be given" do
135
+ hash = { "Foo" => B.class_options.values }
136
+
137
+ content = capture(:stdout) { MyCounter.send(:class_options_help, Thor::Base.shell.new, hash) }
138
+ content.should =~ /Foo options\:/
139
+ content.should =~ /--last-name=LAST_NAME/
140
+ end
141
+ end
142
+
143
+ describe "#namespace" do
144
+ it "returns the default class namespace" do
145
+ Scripts::MyScript.namespace.should == "scripts:my_script"
146
+ end
147
+
148
+ it "sets a namespace to the class" do
149
+ Scripts::MyDefaults.namespace.should == "default"
150
+ end
151
+ end
152
+
153
+ describe "#group" do
154
+ it "sets a group" do
155
+ MyScript.group.should == "script"
156
+ end
157
+
158
+ it "inherits the group from parent" do
159
+ MyChildScript.group.should == "script"
160
+ end
161
+
162
+ it "defaults to standard if no group is given" do
163
+ Amazing.group.should == "standard"
164
+ end
165
+ end
166
+
167
+ describe "#subclasses" do
168
+ it "tracks its subclasses in an Array" do
169
+ Thor::Base.subclasses.should include(MyScript)
170
+ Thor::Base.subclasses.should include(MyChildScript)
171
+ Thor::Base.subclasses.should include(Scripts::MyScript)
172
+ end
173
+ end
174
+
175
+ describe "#subclass_files" do
176
+ it "returns tracked subclasses, grouped by the files they come from" do
177
+ thorfile = File.join(File.dirname(__FILE__), "fixtures", "script.thor")
178
+ Thor::Base.subclass_files[File.expand_path(thorfile)].should == [
179
+ MyScript, MyScript::AnotherScript, MyChildScript, Barn,
180
+ Scripts::MyScript, Scripts::MyDefaults, Scripts::ChildDefault
181
+ ]
182
+ end
183
+
184
+ it "tracks a single subclass across multiple files" do
185
+ thorfile = File.join(File.dirname(__FILE__), "fixtures", "task.thor")
186
+ Thor::Base.subclass_files[File.expand_path(thorfile)].should include(Amazing)
187
+ Thor::Base.subclass_files[File.expand_path(__FILE__)].should include(Amazing)
188
+ end
189
+ end
190
+
191
+ describe "#tasks" do
192
+ it "returns a list with all tasks defined in this class" do
193
+ MyChildScript.new.should respond_to("animal")
194
+ MyChildScript.tasks.keys.should include("animal")
195
+ end
196
+
197
+ it "raises an error if a task with reserved word is defined" do
198
+ lambda {
199
+ klass = Class.new(Thor::Group)
200
+ klass.class_eval "def shell; end"
201
+ }.should raise_error(RuntimeError, /"shell" is a Thor reserved word and cannot be defined as task/)
202
+ end
203
+ end
204
+
205
+ describe "#all_tasks" do
206
+ it "returns a list with all tasks defined in this class plus superclasses" do
207
+ MyChildScript.new.should respond_to("foo")
208
+ MyChildScript.all_tasks.keys.should include("foo")
209
+ end
210
+ end
211
+
212
+ describe "#remove_task" do
213
+ it "removes the task from its tasks hash" do
214
+ MyChildScript.tasks.keys.should_not include("bar")
215
+ MyChildScript.tasks.keys.should_not include("boom")
216
+ end
217
+
218
+ it "undefines the method if desired" do
219
+ MyChildScript.new.should_not respond_to("boom")
220
+ end
221
+ end
222
+
223
+ describe "#from_superclass" do
224
+ it "does not send a method to the superclass if the superclass does not respond to it" do
225
+ MyCounter.get_from_super.should == 13
226
+ end
227
+ end
228
+
229
+ describe "#start" do
230
+ it "raises an error instead of rescueing if THOR_DEBUG=1 is given" do
231
+ begin
232
+ ENV["THOR_DEBUG"] = 1
233
+ lambda {
234
+ MyScript.start ["what", "--debug"]
235
+ }.should raise_error(Thor::UndefinedTaskError, 'Could not find task "what" in "my_script" namespace.')
236
+ rescue
237
+ ENV["THOR_DEBUG"] = nil
238
+ end
239
+ end
240
+
241
+ it "does not steal args" do
242
+ args = ["foo", "bar", "--force", "true"]
243
+ MyScript.start(args)
244
+ args.should == ["foo", "bar", "--force", "true"]
245
+ end
246
+
247
+ it "checks unknown options" do
248
+ capture(:stderr) {
249
+ MyScript.start(["foo", "bar", "--force", "true", "--unknown", "baz"])
250
+ }.strip.should == "Unknown switches '--unknown'"
251
+ end
252
+
253
+ it "checks unknown options except specified" do
254
+ capture(:stderr) {
255
+ MyScript.start(["with_optional", "NAME", "--omg", "--invalid"]).should == ["NAME", {}, ["--omg", "--invalid"]]
256
+ }.strip.should be_empty
257
+ end
258
+ end
259
+
260
+ describe "attr_*" do
261
+ it "should not add attr_reader as a task" do
262
+ capture(:stderr){ MyScript.start(["another_attribute"]) }.should =~ /Could not find/
263
+ end
264
+
265
+ it "should not add attr_writer as a task" do
266
+ capture(:stderr){ MyScript.start(["another_attribute=", "foo"]) }.should =~ /Could not find/
267
+ end
268
+
269
+ it "should not add attr_accessor as a task" do
270
+ capture(:stderr){ MyScript.start(["some_attribute"]) }.should =~ /Could not find/
271
+ capture(:stderr){ MyScript.start(["some_attribute=", "foo"]) }.should =~ /Could not find/
272
+ end
273
+ end
274
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'thor/core_ext/hash_with_indifferent_access'
3
+
4
+ describe Thor::CoreExt::HashWithIndifferentAccess do
5
+ before(:each) do
6
+ @hash = Thor::CoreExt::HashWithIndifferentAccess.new :foo => 'bar', 'baz' => 'bee', :force => true
7
+ end
8
+
9
+ it "has values accessible by either strings or symbols" do
10
+ @hash['foo'].should == 'bar'
11
+ @hash[:foo].should == 'bar'
12
+
13
+ @hash.values_at(:foo, :baz).should == ['bar', 'bee']
14
+ @hash.delete(:foo).should == 'bar'
15
+ end
16
+
17
+ it "handles magic boolean predicates" do
18
+ @hash.force?.should be_true
19
+ @hash.foo?.should be_true
20
+ @hash.nothing?.should be_false
21
+ end
22
+
23
+ it "handles magic comparisions" do
24
+ @hash.foo?('bar').should be_true
25
+ @hash.foo?('bee').should be_false
26
+ end
27
+
28
+ it "maps methods to keys" do
29
+ @hash.foo.should == @hash['foo']
30
+ end
31
+
32
+ it "merges keys independent if they are symbols or strings" do
33
+ @hash.merge!('force' => false, :baz => "boom")
34
+ @hash[:force].should == false
35
+ @hash[:baz].should == "boom"
36
+ end
37
+
38
+ it "creates a new hash by merging keys independent if they are symbols or strings" do
39
+ other = @hash.merge('force' => false, :baz => "boom")
40
+ other[:force].should == false
41
+ other[:baz].should == "boom"
42
+ end
43
+ end