millisami-thor 0.14.6

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.
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