commandable 0.2.0.beta01

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +8 -0
  2. data/Gemfile +2 -0
  3. data/LICENCE +19 -0
  4. data/README.markdown +409 -0
  5. data/Rakefile +29 -0
  6. data/_testing/alias_trap.rb +14 -0
  7. data/autotest/discover.rb +2 -0
  8. data/bin/commandable +18 -0
  9. data/commandable.gemspec +24 -0
  10. data/lib/commandable.rb +4 -0
  11. data/lib/commandable/app_controller.rb +47 -0
  12. data/lib/commandable/commandable.rb +394 -0
  13. data/lib/commandable/exceptions.rb +61 -0
  14. data/lib/commandable/version.rb +4 -0
  15. data/lib/monkey_patch/file_utils.rb +11 -0
  16. data/spec/commandable/command_line_execution_spec.rb +154 -0
  17. data/spec/commandable/commandable_spec.rb +245 -0
  18. data/spec/commandable/help_generator_spec.rb +169 -0
  19. data/spec/commandable/helpers_spec.rb +17 -0
  20. data/spec/commandable/reset_spec.rb +26 -0
  21. data/spec/commandable/xor_groups_spec.rb +43 -0
  22. data/spec/source_code_examples/class_command_no_command.rb +27 -0
  23. data/spec/source_code_examples/class_methods.rb +20 -0
  24. data/spec/source_code_examples/class_methods_nested.rb +31 -0
  25. data/spec/source_code_examples/command_no_command.rb +27 -0
  26. data/spec/source_code_examples/deep_class.rb +14 -0
  27. data/spec/source_code_examples/default_method.rb +17 -0
  28. data/spec/source_code_examples/default_method_no_params.rb +17 -0
  29. data/spec/source_code_examples/multi_line_description.rb +17 -0
  30. data/spec/source_code_examples/multi_line_description_no_params.rb +17 -0
  31. data/spec/source_code_examples/no_description.rb +10 -0
  32. data/spec/source_code_examples/parameter_class.rb +27 -0
  33. data/spec/source_code_examples/parameter_free.rb +22 -0
  34. data/spec/source_code_examples/required_methods.rb +18 -0
  35. data/spec/source_code_examples/super_deep_class.rb +28 -0
  36. data/spec/source_code_examples/test_class.rb +13 -0
  37. data/spec/source_code_examples/xor_class.rb +37 -0
  38. data/spec/source_code_for_errors/class_bad.rb +7 -0
  39. data/spec/source_code_for_errors/default_method_bad.rb +17 -0
  40. data/spec/source_code_for_errors/private_methods_bad.rb +10 -0
  41. data/spec/spec_helper.rb +55 -0
  42. metadata +140 -0
@@ -0,0 +1,169 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commandable do
4
+
5
+ before(:each) { Commandable.reset_all }
6
+
7
+ # Mostly de-brittled these tests...
8
+
9
+ context "when setting verbose_parameters" do
10
+
11
+ it "prints short parameters when false" do
12
+ Commandable.verbose_parameters = false
13
+ load 'parameter_class.rb'
14
+ Commandable.help.to_s.should_not match("1492")
15
+ end
16
+
17
+ it "prints short parameters when false" do
18
+ Commandable.verbose_parameters = true
19
+ load 'parameter_class.rb'
20
+ Commandable.help.to_s.should match("1492")
21
+ end
22
+
23
+ end
24
+
25
+ context "when generating the help command" do
26
+
27
+ it "has a help command when no commands have been added" do
28
+ Commandable.commands.first[0].should == :help
29
+ end
30
+
31
+ it "still has the help command after Commandable is cleared" do
32
+ load 'parameter_class.rb'
33
+ Commandable.clear_commands
34
+ Commandable.commands.first[0].should == :help
35
+ end
36
+
37
+ it "always has the help command as the last command (so it's pretty)" do
38
+ load 'parameter_class.rb'
39
+ Commandable.help.compact.last.should match(/help/)
40
+ end
41
+
42
+ end
43
+
44
+ context "when formating the help message" do
45
+
46
+ it "formats a basic help message with commands sorted alphabetically (help last)" do
47
+ load 'parameter_class.rb'
48
+ Commandable.help.to_s.should match(/Usage:(.*)Command(.*)bar(.*)baz(.*)foo(.*)qux(.*)help/)
49
+ end
50
+
51
+ it "adds the application name to the help output if it's given" do
52
+ load 'parameter_class.rb'
53
+ Commandable.app_name = "mycoolapp"
54
+ Commandable.help.to_s.should match(/Usage: mycoolapp <command>/)
55
+ end
56
+
57
+ it "adds appliction information if given" do
58
+ load 'parameter_class.rb'
59
+ Commandable.app_name = "mycoolapp"
60
+ app_info =
61
+ """
62
+ My Cool App - It does stuff and things!
63
+ Copyright (c) 2011 Acme Inc.
64
+ """
65
+ Commandable.app_info = app_info
66
+ Commandable.help.inspect.should match(/My Cool App - It does stuff and things(.*)Copyright \(c\) 2011 Acme Inc/)
67
+ end
68
+
69
+ it "adds (default) to the end of the default command description when printing" do
70
+ load 'default_method.rb'
71
+ Commandable.help.to_s.should match(/\(default\)/)
72
+ end
73
+
74
+ context "and there are no parameters" do
75
+
76
+ before(:each){load 'parameter_free.rb' }
77
+
78
+ it "hides the Parameters header" do
79
+ execute_output_s([]).should_not match(/Command Parameters/)
80
+ end
81
+
82
+ it "hides the doesn't show [parameters] in the usage instructions" do
83
+ Commandable.app_name = "fakeapp"
84
+ execute_output_s([]).should_not match(/\[parameters\]/)
85
+ end
86
+
87
+
88
+ end
89
+
90
+ context "and there is a new line in a description" do
91
+
92
+ it "indents the new line to match the preceding line" do
93
+ load("multi_line_description.rb")
94
+ execute_output_s(["blah"]).should match(/ so you can have really long descriptions\n And another line/)
95
+ end
96
+
97
+ it "indents the new line to match the preceding line" do
98
+ load("multi_line_description_no_params.rb")
99
+ execute_output_s(["blah"]).should match(/ so you can have really long descriptions\n And another line/)
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+
106
+ context "when using color_output" do
107
+
108
+ before(:each) do
109
+ load 'private_methods_bad.rb'
110
+ Commandable.app_name = "mycoolapp"
111
+ Commandable.app_info =
112
+ """ My Cool App - It does stuff and things!
113
+ Copyright (c) 2011 Acme Inc."""
114
+ end
115
+
116
+ let(:c) {Term::ANSIColor}
117
+
118
+ it "changes the output if color is enabled" do
119
+ Commandable.color_output = false
120
+ lambda {Commandable.color_output = true}.should change{Commandable.help}
121
+ end
122
+
123
+ it "resets text to plain if colors are turned off" do
124
+ Commandable.color_output = true
125
+ lambda {Commandable.color_output = false}.should change{Commandable.help}
126
+ end
127
+
128
+ context "when a specific setting's color is changed" do
129
+
130
+ before(:each) { Commandable.color_output = true }
131
+
132
+ # This seems ripe for meta-zation
133
+ context "when app_info is changed" do
134
+ specify {lambda {Commandable.color_app_info = c.black}.should change{Commandable.help}}
135
+ end
136
+
137
+ context "when app_name is changed" do
138
+ specify {lambda {Commandable.color_app_name = c.black}.should change{Commandable.help}}
139
+ end
140
+
141
+ context "when color_command is changed" do
142
+ specify {lambda {Commandable.color_command = c.black}.should change{Commandable.help}}
143
+ end
144
+
145
+ context "when color_description is changed" do
146
+ specify {lambda {Commandable.color_description = c.black}.should change{Commandable.help}}
147
+ end
148
+
149
+ context "when color_parameter is changed" do
150
+ specify {lambda {Commandable.color_parameter = c.black}.should change{Commandable.help}}
151
+ end
152
+
153
+ context "when color_usage is changed" do
154
+ specify {lambda {Commandable.color_usage = c.black}.should change{Commandable.help}}
155
+ end
156
+
157
+ context "when there is an error" do
158
+
159
+ specify { lambda {Commandable.color_error_word = c.magenta}.should change{capture_output{Commandable.execute(["fly", "navy"])}}}
160
+ specify { lambda {Commandable.color_error_name = c.intense_red}.should change{capture_output{Commandable.execute(["fly", "navy"])}}}
161
+ specify { lambda {Commandable.color_error_description = c.black + c.bold}.should change{capture_output{Commandable.execute(["fly", "navy"])}}}
162
+
163
+ end
164
+
165
+ end
166
+
167
+ end
168
+
169
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commandable do
4
+
5
+ context "when parsing optional parameters" do
6
+
7
+ before(:each) {load 'private_methods_bad.rb'}
8
+
9
+ specify {PrivateMethods.send(:parse_optional, "def bar(x=14243)", "x").should == "14243"}
10
+ specify {PrivateMethods.send(:parse_optional,"def bar x = 144444", "x").should == "144444"}
11
+ specify {PrivateMethods.send(:parse_optional,"def bar x=12", "x").should == "12"}
12
+ specify {PrivateMethods.send(:parse_optional,'def bar (x="42", y)', "x").should == "\"42\""}
13
+ specify {PrivateMethods.send(:parse_optional,'def bar(y="kjljlj",x="I love Ruby")', "x").should == "\"I love Ruby\""}
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commandable do
4
+
5
+ before(:each) do
6
+ Commandable.reset_all
7
+ load 'parameter_class.rb'
8
+ Commandable.app_name = "mycoolapp"
9
+ Commandable.app_info =
10
+ """ My Cool App - It does stuff and things!
11
+ Copyright (c) 2011 Acme Inc."""
12
+ end
13
+
14
+ context "when reseting all values" do
15
+
16
+ specify {lambda{Commandable.reset_all}.should change{Commandable.app_name}.from("mycoolapp").to(nil)}
17
+ specify {lambda{Commandable.reset_all}.should change{Commandable.app_info}.
18
+ from(%{ My Cool App - It does stuff and things!\n Copyright (c) 2011 Acme Inc.}).
19
+ to(nil)
20
+ }
21
+ specify {lambda{Commandable.reset_all}.should change{Commandable.commands.length}.from(5).to(1)}
22
+
23
+
24
+
25
+ end
26
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commandable do
4
+
5
+ before(:each) do
6
+ Commandable.reset_all
7
+ Commandable.color_output = true
8
+ load 'xor_class.rb'
9
+ end
10
+
11
+ context "when exclusive methods are specified" do
12
+
13
+ # this seems like I'm testing internal state instead of specifying behavior...
14
+ specify {Commandable.commands[:xor_method1][:xor].should == :xor}
15
+ specify {Commandable.commands[:normal_method][:xor].should be_nil}
16
+ specify {Commandable.commands[:xor_method3][:xor].should == :xor_group}
17
+
18
+ context "when more than one members of an exclusive group is used" do
19
+
20
+ specify{lambda{Commandable.execution_queue(["xor_method1", "xor_method2"])}.should raise_error(Commandable::ExclusiveMethodClashError)}
21
+ specify{lambda{Commandable.execution_queue(["xor_method3", "xor_method4"])}.should raise_error(Commandable::ExclusiveMethodClashError)}
22
+ specify{lambda{Commandable.execution_queue(["xor_method1", "xor_method3"])}.should_not raise_error}
23
+ specify{lambda{Commandable.execution_queue(["normal_method", "xor_method3"])}.should_not raise_error}
24
+ specify{lambda{Commandable.execution_queue(["normal_method", "normal_method2"])}.should_not raise_error}
25
+
26
+ end
27
+
28
+ context "when printing help" do
29
+
30
+ it "puts the default xor group :xor in the description" do
31
+ execute_output_s(["help"]).should match(/xor/)
32
+ end
33
+
34
+ it "puts the xor group :xor_group in the description" do
35
+ execute_output_s(["help"]).should match(/xor/)
36
+ end
37
+
38
+ end
39
+
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,27 @@
1
+ @@command_options
2
+ require "commandable"
3
+
4
+ class ClassCommandNoCommand
5
+ extend Commandable
6
+
7
+ command 'a method with a command'
8
+ def class_command_method1
9
+ "class_command_method1"
10
+ end
11
+
12
+ # this method should not be in the commands list
13
+ def class_no_command_method1(flappity)
14
+ "class_no_command_method1: #{flappity}"
15
+ end
16
+
17
+ command 'another method with a command'
18
+ def class_command_method2(some_parameter)
19
+ "class_command_method2: #{some_parameter}"
20
+ end
21
+
22
+ # this method shouldn't be in the list either
23
+ def class_no_command_method2(flippity)
24
+ "class_no_command_method2: #{flippity}"
25
+ end
26
+
27
+ end
@@ -0,0 +1,20 @@
1
+ @@command_options
2
+ require "commandable"
3
+
4
+ class ClassMethods
5
+
6
+ extend Commandable
7
+
8
+ command 'does some stuff'
9
+ def self.class_method(string_arg1)
10
+ string_arg1
11
+ end
12
+
13
+ command "another one"
14
+ class << self
15
+ def class_method2(integer_arg1)
16
+ integer_arg1
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,31 @@
1
+ @@command_options
2
+ require "commandable"
3
+
4
+ class ClassMethodsNested
5
+
6
+ class << self
7
+ extend Commandable
8
+
9
+ command "class foo, look at you!"
10
+ def class_foo(int_arg1, number_arg2)
11
+ [int_arg1, number_arg2]
12
+ end
13
+
14
+ command "classy bar? probably not"
15
+ def class_bar(int_arg1, string_arg2="Number 42")
16
+ [int_arg1, string_arg2]
17
+ end
18
+
19
+ command "run me for stuff to happen"
20
+ def class_qux string_arg1 ="1492", string_arg2 = "I'm a tricky one"
21
+ [string_arg1, string_arg2]
22
+ end
23
+
24
+ command "I'm another function!"
25
+ def class_baz number_arg1, string_arg2 = "blorp", *array_arg3
26
+ [number_arg1, string_arg2, array_arg3]
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,27 @@
1
+ @@command_options
2
+ require "commandable"
3
+
4
+ class CommandNoCommand
5
+ extend Commandable
6
+
7
+ command 'a method with a command'
8
+ def command_method1
9
+ "command_method1"
10
+ end
11
+
12
+ # this method should not be in the commands list
13
+ def no_command_method1(flappity)
14
+ "no_command_method1"
15
+ end
16
+
17
+ command 'another method with a command'
18
+ def command_method2(some_parameter)
19
+ "command_method2"
20
+ end
21
+
22
+ # this method shouldn't be in the list either
23
+ def no_command_method2(flippity)
24
+ "no_command_method2"
25
+ end
26
+
27
+ end
@@ -0,0 +1,14 @@
1
+ @@command_options
2
+ require "commandable"
3
+
4
+ module TopModule
5
+ class ParentClass
6
+ class DeepClass
7
+ extend Commandable
8
+ command 'this is a deep method call'
9
+ def deep_method
10
+ "you called a deep method"
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ @@command_options
2
+ require "commandable"
3
+
4
+ class DefaultMethods
5
+ extend Commandable
6
+
7
+ command 'the default method', :default
8
+ def default_method(name)
9
+ "default method called with: #{name}"
10
+ end
11
+
12
+ command 'does other stuff'
13
+ def not_a_default_method(name="Cleveland", age)
14
+ ["not a default method, called with: #{name}", age]
15
+ end
16
+
17
+ end
@@ -0,0 +1,17 @@
1
+ @@command_options
2
+ require "commandable"
3
+
4
+ class DefaultMethodNoParams
5
+ extend Commandable
6
+
7
+ command 'does some stuff', :default
8
+ def default_no_params
9
+ "default method called, has no params"
10
+ end
11
+
12
+ command 'does other stuff'
13
+ def not_a_default_method(name="Cleveland", age)
14
+ ["not a default method: #{name}", age]
15
+ end
16
+
17
+ end
@@ -0,0 +1,17 @@
1
+ @@command_options
2
+ require "commandable"
3
+
4
+ class MultiLineDescription
5
+ extend Commandable
6
+
7
+ command "this description will be on multiple lines\nso you can have really long descriptions\nAnd another line\nAnd another"
8
+ def multiline_function1
9
+ "multiline_function1"
10
+ end
11
+
12
+ command "Line one is short line two blah, blah! Oh, and blah!"
13
+ def multiline_function2(foo)
14
+ "multiline_function2: #{foo}"
15
+ end
16
+
17
+ end
@@ -0,0 +1,17 @@
1
+ @@command_options
2
+ require "commandable"
3
+
4
+ class MultiLineDescriptionNoParams
5
+ extend Commandable
6
+
7
+ command "this description will be on multiple lines\nso you can have really long descriptions\nAnd another line\nAnd another"
8
+ def multiline_function_no_params1
9
+ "multiline_function_no_params1"
10
+ end
11
+
12
+ command "Line one is short line two blah, blah! Oh, and blah!"
13
+ def multiline_function_no_params2
14
+ "multiline_function_no_params2"
15
+ end
16
+
17
+ end