hsume2-hirb 0.6.0.beta.1

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 (53) hide show
  1. data/.gemspec +21 -0
  2. data/CHANGELOG.rdoc +144 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.rdoc +194 -0
  5. data/Rakefile +35 -0
  6. data/lib/bond/completions/hirb.rb +15 -0
  7. data/lib/hirb/console.rb +43 -0
  8. data/lib/hirb/dynamic_view.rb +113 -0
  9. data/lib/hirb/formatter.rb +126 -0
  10. data/lib/hirb/helpers/auto_table.rb +24 -0
  11. data/lib/hirb/helpers/object_table.rb +14 -0
  12. data/lib/hirb/helpers/parent_child_tree.rb +24 -0
  13. data/lib/hirb/helpers/tab_table.rb +24 -0
  14. data/lib/hirb/helpers/table/filters.rb +10 -0
  15. data/lib/hirb/helpers/table/resizer.rb +82 -0
  16. data/lib/hirb/helpers/table.rb +349 -0
  17. data/lib/hirb/helpers/tree.rb +181 -0
  18. data/lib/hirb/helpers/unicode_table.rb +15 -0
  19. data/lib/hirb/helpers/vertical_table.rb +37 -0
  20. data/lib/hirb/helpers.rb +18 -0
  21. data/lib/hirb/import_object.rb +10 -0
  22. data/lib/hirb/menu.rb +238 -0
  23. data/lib/hirb/pager.rb +105 -0
  24. data/lib/hirb/string.rb +44 -0
  25. data/lib/hirb/util.rb +96 -0
  26. data/lib/hirb/version.rb +3 -0
  27. data/lib/hirb/view.rb +270 -0
  28. data/lib/hirb/views/couch_db.rb +11 -0
  29. data/lib/hirb/views/misc_db.rb +15 -0
  30. data/lib/hirb/views/mongo_db.rb +14 -0
  31. data/lib/hirb/views/orm.rb +11 -0
  32. data/lib/hirb/views/rails.rb +19 -0
  33. data/lib/hirb/views.rb +8 -0
  34. data/lib/hirb.rb +82 -0
  35. data/lib/ripl/hirb.rb +15 -0
  36. data/test/auto_table_test.rb +30 -0
  37. data/test/console_test.rb +27 -0
  38. data/test/deps.rip +4 -0
  39. data/test/dynamic_view_test.rb +94 -0
  40. data/test/formatter_test.rb +176 -0
  41. data/test/hirb_test.rb +39 -0
  42. data/test/import_test.rb +9 -0
  43. data/test/menu_test.rb +255 -0
  44. data/test/object_table_test.rb +79 -0
  45. data/test/pager_test.rb +162 -0
  46. data/test/resizer_test.rb +62 -0
  47. data/test/table_test.rb +630 -0
  48. data/test/test_helper.rb +61 -0
  49. data/test/tree_test.rb +184 -0
  50. data/test/util_test.rb +59 -0
  51. data/test/view_test.rb +165 -0
  52. data/test/views_test.rb +13 -0
  53. metadata +184 -0
@@ -0,0 +1,94 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "DynamicView" do
4
+ def output_expects(output, expects)
5
+ Helpers::ObjectTable.expects(:render).with(output, expects)
6
+ Helpers::AutoTable.render(output)
7
+ end
8
+
9
+ describe "add" do
10
+ before_all { View.load_config }
11
+
12
+ it "raises error if no :helper option" do
13
+ lambda { Hirb.add_dynamic_view 'Blah', {} }.should.raise(ArgumentError).
14
+ message.should =~ /:helper.*required/
15
+ end
16
+
17
+ it "raises error if :helper option not a dynamic_view module" do
18
+ lambda { Hirb.add_dynamic_view('Blah', :helper=>:table) {|obj| } }.
19
+ should.raise(ArgumentError).message.should =~ /:helper.*must/
20
+ end
21
+
22
+ it "raises error if views module not a module" do
23
+ lambda { Hirb.add_dynamic_view 'Blah', :helper=>:auto_table }.should.raise(ArgumentError).
24
+ message.should =~ /must be a module/
25
+ end
26
+
27
+ it "adds a view with block" do
28
+ Hirb.add_dynamic_view('Date', :helper=>:auto_table) do |obj|
29
+ {:fields=>obj.class::DAYNAMES}
30
+ end
31
+ output_expects [Date.new], :fields=>Date::DAYNAMES
32
+ end
33
+
34
+ it "when adding views with a block, second view for same class overrides first one" do
35
+ Hirb.add_dynamic_view('Date', :helper=>:auto_table) do |obj|
36
+ {:fields=>obj.class::DAYNAMES}
37
+ end
38
+ Hirb.add_dynamic_view('Date', :helper=>:auto_table) do |obj|
39
+ {:fields=>[:blah]}
40
+ end
41
+ output_expects [Date.new], :fields=>[:blah]
42
+ end
43
+ end
44
+
45
+ it "class_to_method and method_to_class convert to each other" do
46
+ ["DBI::Row", "Hirb::View"].each do |e|
47
+ Helpers::AutoTable.method_to_class(DynamicView.class_to_method(e).downcase).should == e
48
+ end
49
+ end
50
+
51
+ it "class_to_method converts correctly" do
52
+ DynamicView.class_to_method("DBI::Row").should == 'd_b_i__row_view'
53
+ end
54
+
55
+ describe "dynamic_view" do
56
+ def define_view(mod_name= :Blah, &block)
57
+ mod = Views.const_set(mod_name, Module.new)
58
+ mod_block = block_given? ? block : lambda {|obj| {:fields=>obj.class::DAYNAMES}}
59
+ mod.send(:define_method, :date_view, mod_block)
60
+ Hirb.add_dynamic_view mod, :helper=>:auto_table
61
+ end
62
+
63
+ before_all { View.load_config }
64
+ before { Formatter.dynamic_config = {} }
65
+ after { Views.send(:remove_const, :Blah) }
66
+
67
+ it "sets a view's options" do
68
+ define_view
69
+ output_expects [Date.new], :fields=>Date::DAYNAMES
70
+ end
71
+
72
+ it "does override existing formatter dynamic_config" do
73
+ Formatter.dynamic_config["Date"] = {:class=>Helpers::Table}
74
+ define_view
75
+ Formatter.dynamic_config["Date"].should == {:class=>Hirb::Helpers::AutoTable, :ancestor=>true}
76
+ end
77
+
78
+ it "raises a readable error when error occurs in a view" do
79
+ define_view {|obj| raise 'blah' }
80
+ lambda { Helpers::AutoTable.render([Date.new]) }.should.raise(RuntimeError).
81
+ message.should =~ /'Date'.*date_view.*\nblah/
82
+ end
83
+
84
+ it "another view can reuse an old view's options" do
85
+ define_view
86
+ define_view(:Blah2) do |obj|
87
+ {:fields=>obj.class::DAYNAMES + ['blah']}
88
+ end
89
+ output_expects [Date.new], :fields=>(Date::DAYNAMES + ['blah'])
90
+ end
91
+ after_all { reset_config }
92
+ end
93
+ after_all { Formatter.dynamic_config = {} }
94
+ end
@@ -0,0 +1,176 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "Formatter" do
4
+ def set_formatter(hash={})
5
+ @formatter = Formatter.new(hash)
6
+ end
7
+
8
+ describe "klass_config" do
9
+ it "recursively merges ancestor options" do
10
+ @formatter = set_formatter "String"=>{:args=>[1,2], :options=>{:fields=>[:to_s]}},
11
+ "Object"=>{:method=>:object_output, :ancestor=>true, :options=>{:vertical=>true}},
12
+ "Kernel"=>{:method=>:default_output}
13
+ expected_result = {:method=>:object_output, :args=>[1, 2], :ancestor=>true, :options=>{:fields=>[:to_s], :vertical=>true}}
14
+ @formatter.klass_config(::String).should == expected_result
15
+ end
16
+
17
+ it "doesn't merge ancestor options" do
18
+ @formatter = set_formatter "String"=>{:args=>[1,2]}, "Object"=>{:method=>:object_output},
19
+ "Kernel"=>{:method=>:default_output}
20
+ @formatter.klass_config(::String).should == {:args=>[1, 2]}
21
+ end
22
+
23
+ it "returns hash when nothing found" do
24
+ set_formatter.klass_config(::String).should == {}
25
+ end
26
+
27
+ describe "with dynamic_config" do
28
+ def set_formatter(hash={})
29
+ @formatter = Formatter.new(hash)
30
+ end
31
+ after { Formatter.dynamic_config = {}}
32
+
33
+ it "merges ancestor options and sets local config" do
34
+ Formatter.dynamic_config = {"Object"=>{:method=>:blah}, "Kernel"=>{:args=>[1,2], :ancestor=>true}}
35
+ set_formatter.klass_config(::String).should == {:args=>[1,2], :ancestor=>true}
36
+ @formatter.config['Kernel'].should == {:args=>[1,2], :ancestor=>true}
37
+ end
38
+
39
+ it "uses local config over dynamic_config" do
40
+ Formatter.dynamic_config = {"String"=>{:method=>:blah}}
41
+ set_formatter "String"=>{:args=>[1,2]}
42
+ @formatter.klass_config(::String).should == {:args=>[1,2]}
43
+ end
44
+
45
+ it "uses dynamic_config and sets local config" do
46
+ Formatter.dynamic_config = {"String"=>{:method=>:blah}}
47
+ set_formatter.klass_config(::String).should == {:method=>:blah}
48
+ @formatter.config['String'].should == {:method=>:blah}
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "formatter methods:" do
54
+ before_all { eval "module ::Dooda; end" }
55
+
56
+ it "#add_view sets formatter config" do
57
+ @formatter = set_formatter
58
+ @formatter.add_view ::Dooda, :class=>"DoodaView"
59
+ @formatter.klass_config(::Dooda).should == {:class=>"DoodaView"}
60
+ end
61
+
62
+ it "#add_view overwrites existing formatter config" do
63
+ @formatter = set_formatter "Dooda"=>{:class=>"DoodaView"}
64
+ @formatter.add_view ::Dooda, :class=>"DoodaView2"
65
+ @formatter.klass_config(::Dooda).should == {:class=>"DoodaView2"}
66
+ end
67
+
68
+ it "#parse_console_options passes all options except for formatter options into :options" do
69
+ @formatter = set_formatter
70
+ options = {:class=>'blah', :method=>'blah', :output_method=>'blah', :blah=>'blah'}
71
+ expected_options = {:class=>'blah', :method=>'blah', :output_method=>'blah', :options=>{:blah=>'blah'}}
72
+ @formatter.parse_console_options(options).should == expected_options
73
+ end
74
+
75
+ it "#determine_output_class recognizes subclasses of to_a classes" do
76
+ class Array2 < Array; end
77
+ @formatter.determine_output_class(Array2.new(%w{ok dude})).should == String
78
+ end
79
+ end
80
+
81
+ describe "format_output" do
82
+ def view_output(*args, &block); View.view_output(*args, &block); end
83
+ def render_method(*args); View.render_method(*args); end
84
+
85
+ def enable_with_output(value)
86
+ Hirb.enable :output=>value
87
+ end
88
+
89
+ before_all {
90
+ eval %[module ::Commify
91
+ def self.render(strings)
92
+ strings = Array(strings)
93
+ strings.map {|e| e.split('').join(',')}.join("\n")
94
+ end
95
+ end]
96
+ reset_config
97
+ }
98
+ before { View.formatter = nil; reset_config }
99
+ after { Hirb.disable }
100
+
101
+ it "formats with method option" do
102
+ eval "module ::Kernel; def commify(string); string.split('').join(','); end; end"
103
+ enable_with_output "String"=>{:method=>:commify}
104
+ render_method.expects(:call).with('d,u,d,e')
105
+ view_output('dude')
106
+ end
107
+
108
+ it "formats with class option" do
109
+ enable_with_output "String"=>{:class=>"Commify"}
110
+ render_method.expects(:call).with('d,u,d,e')
111
+ view_output('dude')
112
+ end
113
+
114
+ it "formats with class option as symbol" do
115
+ enable_with_output "String"=>{:class=>:auto_table}
116
+ Helpers::AutoTable.expects(:render)
117
+ view_output('dude')
118
+ end
119
+
120
+ it "formats arrays" do
121
+ enable_with_output "String"=>{:class=>"Commify"}
122
+ render_method.expects(:call).with('d,u,d,e')
123
+ view_output(['dude'])
124
+ end
125
+
126
+ it "formats array-like objects" do
127
+ enable_with_output "String"=>{:class=>"Commify"}
128
+ render_method.expects(:call).with('d,u,d,e')
129
+ require 'set'
130
+ view_output Set.new(['dude'])
131
+ end
132
+
133
+ it "formats with options option" do
134
+ eval "module ::Blahify; def self.render(*args); end; end"
135
+ enable_with_output "String"=>{:class=>"Blahify", :options=>{:fields=>%w{a b}}}
136
+ Blahify.expects(:render).with('dude', :fields=>%w{a b})
137
+ view_output('dude')
138
+ end
139
+
140
+ it "doesn't format and returns false when no format method found" do
141
+ Hirb.enable
142
+ render_method.expects(:call).never
143
+ view_output(Date.today).should == false
144
+ end
145
+
146
+ it "formats with output_method option as method" do
147
+ enable_with_output 'String'=>{:class=>"Commify", :output_method=>:chop}
148
+ render_method.expects(:call).with('d,u,d')
149
+ view_output('dude')
150
+ end
151
+
152
+ it "formats with output_method option as proc" do
153
+ enable_with_output 'String'=>{:class=>"Commify", :output_method=>lambda {|e| e.chop}}
154
+ render_method.expects(:call).with('d,u,d')
155
+ view_output('dude')
156
+ end
157
+
158
+ it "formats output array with output_method option" do
159
+ enable_with_output 'String'=>{:class=>"Commify", :output_method=>:chop}
160
+ render_method.expects(:call).with("d,u,d\nm,a")
161
+ view_output(['dude', 'man'])
162
+ end
163
+
164
+ it "formats with explicit class option" do
165
+ enable_with_output 'String'=>{:class=>"Blahify"}
166
+ render_method.expects(:call).with('d,u,d,e')
167
+ view_output('dude', :class=>"Commify")
168
+ end
169
+
170
+ it "formats with explicit options option merges with existing options" do
171
+ enable_with_output "String"=>{:class=>"Commify", :options=>{:fields=>%w{f1 f2}}}
172
+ Commify.expects(:render).with('dude', :max_width=>10, :fields=>%w{f1 f2})
173
+ view_output('dude', :options=>{:max_width=>10})
174
+ end
175
+ end
176
+ end
data/test/hirb_test.rb ADDED
@@ -0,0 +1,39 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "Hirb" do
4
+ before_all { Hirb.config_files = nil }
5
+ before { Hirb.config = nil }
6
+
7
+ it "config converts yaml when config file exists" do
8
+ yaml_data = {:blah=>'blah'}
9
+ File.stubs('exists?').returns(true)
10
+ Hirb.config_files = ['ok']
11
+ YAML::expects(:load_file).returns(yaml_data)
12
+ Hirb.config.should == yaml_data
13
+ end
14
+
15
+ it "config defaults to hash when no config file" do
16
+ File.stubs('exists?').returns(false)
17
+ Hirb.config.should == {}
18
+ end
19
+
20
+ it "config reloads if given explicit reload" do
21
+ Hirb.config
22
+ Hirb.expects(:read_config_file).returns({})
23
+ Hirb.config(true)
24
+ end
25
+
26
+ it "config reads multiple config files and merges them" do
27
+ Hirb.config_files = %w{one two}
28
+ Hirb.expects(:read_config_file).times(2).returns({:output=>{"String"=>:auto_table}}, {:output=>{"Array"=>:auto_table}})
29
+ Hirb.config.should == {:output=>{"Array"=>:auto_table, "String"=>:auto_table}}
30
+ Hirb.config_files = nil
31
+ end
32
+
33
+ it "config_file sets correctly when no ENV['HOME']" do
34
+ Hirb.config_files = nil
35
+ home = ENV.delete('HOME')
36
+ Hirb.config_files[0].class.should == String
37
+ ENV["HOME"] = home
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "import" do
4
+ it "require import_object extends Object" do
5
+ Object.ancestors.map {|e| e.to_s}.include?("Hirb::ObjectMethods").should == false
6
+ require 'hirb/import_object'
7
+ Object.ancestors.map {|e| e.to_s}.include?("Hirb::ObjectMethods").should == true
8
+ end
9
+ end
data/test/menu_test.rb ADDED
@@ -0,0 +1,255 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "Menu" do
4
+ before_all { View.instance_variable_set("@config", :width=>Hirb::View::DEFAULT_WIDTH) }
5
+
6
+ def menu(*args, &block)
7
+ # testing via menu's main use case (through console) instead of Menu.render
8
+ @console ||= Object.new.extend(Hirb::Console)
9
+ @console.menu(*args, &block)
10
+ end
11
+
12
+ def basic_menu(*args, &block)
13
+ menu_input('1')
14
+ capture_stdout { menu(*args, &block).should == [1] }
15
+ end
16
+
17
+ def menu_input(input='')
18
+ $stdin.expects(:gets).returns(input)
19
+ end
20
+
21
+ describe "menu" do
22
+ it "by default renders table menu" do
23
+ expected_menu = <<-MENU.unindent
24
+ +--------+-------+
25
+ | number | value |
26
+ +--------+-------+
27
+ | 1 | 1 |
28
+ | 2 | 2 |
29
+ | 3 | 3 |
30
+ +--------+-------+
31
+ 3 rows in set
32
+ MENU
33
+ basic_menu([1,2,3]).include?(expected_menu).should == true
34
+ end
35
+
36
+ it "with block renders" do
37
+ menu_input "1,2"
38
+ expected_result = [1,2]
39
+ capture_stdout {
40
+ menu([1,2,3]) {|e| e.should == expected_result }.should == expected_result
41
+ }
42
+ end
43
+
44
+ it "with block and no chosen doesn't call block" do
45
+ menu_input ""
46
+ block = lambda {|e| @called = true }
47
+ capture_stdout {
48
+ menu([1,2,3], &block).should == []
49
+ }
50
+ assert !@called
51
+ end
52
+
53
+ it "with valid helper_class option renders" do
54
+ Helpers::Table.expects(:render)
55
+ basic_menu [1,2,3], :helper_class=>"Hirb::Helpers::Table"
56
+ end
57
+
58
+ it "with invalid helper_class option renders default menu" do
59
+ expected_menu = <<-MENU.unindent
60
+ 1: 1
61
+ 2: 2
62
+ 3: 3
63
+ MENU
64
+ basic_menu([1,2,3], :helper_class=>"SomeHelper").include?(expected_menu).should == true
65
+ end
66
+
67
+ it "with false helper_class option renders default menu" do
68
+ expected_menu = <<-MENU.unindent
69
+ 1: 1
70
+ 2: 2
71
+ 3: 3
72
+ MENU
73
+ basic_menu([1,2,3], :helper_class=>false).include?(expected_menu).should == true
74
+ end
75
+
76
+ it "prints prompt option" do
77
+ prompt = "Input or else ..."
78
+ basic_menu([1,2,3], :prompt=>prompt).include?(prompt).should == true
79
+ end
80
+
81
+ it "converts non-array inputs to array" do
82
+ Helpers::AutoTable.expects(:render).with([1], anything)
83
+ basic_menu 1
84
+ end
85
+
86
+ it "with false ask option returns one choice without asking" do
87
+ $stdin.expects(:gets).never
88
+ menu([1], :ask=>false).should == [1]
89
+ end
90
+
91
+ it "with no items to choose from always return without asking" do
92
+ $stdin.expects(:gets).never
93
+ menu([], :ask=>false).should == []
94
+ menu([], :ask=>true).should == []
95
+ end
96
+
97
+ it "with directions option turns off directions" do
98
+ menu_input('blah')
99
+ capture_stdout { menu([1], :directions=>false) }.should.not =~ /range.*all/
100
+ end
101
+
102
+ it "with true reopen option reopens" do
103
+ $stdin.expects(:reopen).with('/dev/tty')
104
+ basic_menu [1], :reopen=>true
105
+ end
106
+
107
+ it "with string reopen option reopens" do
108
+ $stdin.expects(:reopen).with('/dev/blah')
109
+ basic_menu [1], :reopen=>'/dev/blah'
110
+ end
111
+ end
112
+
113
+ def two_d_menu(options={})
114
+ if options[:invokes] || options[:invoke]
115
+ cmd = options[:command] || 'p'
116
+ (options[:invokes] || [options[:invoke]]).each {|e|
117
+ Menu.any_instance.expects(:invoke).with(cmd, e)
118
+ }
119
+ end
120
+
121
+ capture_stdout {
122
+ return menu(options[:output] || [{:a=>1, :bro=>2}, {:a=>3, :bro=>4}],
123
+ {:two_d=>true}.merge(options))
124
+ }
125
+ end
126
+
127
+ describe "2d menu" do
128
+ it "with default field from last_table renders" do
129
+ menu_input "1"
130
+ two_d_menu.should == [1]
131
+ end
132
+
133
+ it "with default field from fields option renders" do
134
+ menu_input "1"
135
+ two_d_menu(:fields=>[:bro, :a]).should == [2]
136
+ end
137
+
138
+ it "with default field option renders" do
139
+ menu_input "1"
140
+ two_d_menu(:default_field=>:bro).should == [2]
141
+ end
142
+
143
+ it "with non-table helper class renders" do
144
+ menu_input "1"
145
+ two_d_menu(:helper_class=>false, :fields=>[:a,:bro]).should == [1]
146
+ end
147
+
148
+ it "with no default field prints error" do
149
+ menu_input "1"
150
+ capture_stderr { two_d_menu(:fields=>[]) }.should =~ /No default.*found/
151
+ end
152
+
153
+ it "with invalid field prints error" do
154
+ menu_input "1:z"
155
+ capture_stderr { two_d_menu }.should =~ /Invalid.*'z'/
156
+ end
157
+
158
+ it "with choice from abbreviated field" do
159
+ menu_input "2:b"
160
+ two_d_menu.should == [4]
161
+ end
162
+
163
+ it "with choices from multiple fields renders" do
164
+ menu_input "1 2:bro"
165
+ two_d_menu.should == [1,4]
166
+ end
167
+ end
168
+
169
+ describe "action menu" do
170
+ it "invokes" do
171
+ menu_input "p 1 2:bro"
172
+ two_d_menu(:action=>true, :invoke=>[[1,4]])
173
+ end
174
+
175
+ it "with 1d invokes" do
176
+ menu_input "p 1"
177
+ two_d_menu(:action=>true, :two_d=>nil, :invoke=>[[{:a=>1, :bro=>2}]])
178
+ end
179
+
180
+ it "with non-choice arguments invokes" do
181
+ menu_input "p arg1 1"
182
+ two_d_menu :action=>true, :invoke=>['arg1', [1]]
183
+ end
184
+
185
+ it "with multiple choice arguments flattens them into arg" do
186
+ menu_input "p arg1 1 2:bro arg2"
187
+ two_d_menu :action=>true, :invoke=>['arg1', [1,4], 'arg2']
188
+ end
189
+
190
+ it "with nothing chosen prints error" do
191
+ menu_input "cmd"
192
+ capture_stderr { two_d_menu(:action=>true) }.should =~ /No rows chosen/
193
+ end
194
+
195
+ it "with all choices" do
196
+ menu_input "p *"
197
+ two_d_menu(:action=>true, :invoke=>[[{:a => 1, :bro => 2}, {:a => 3, :bro => 4}]])
198
+ end
199
+
200
+ it "with multiple all choices" do
201
+ menu_input "p * * 2:bro"
202
+ two_d_menu(:action=>true, :invoke=>[[{:a => 1, :bro => 2}, {:a => 3, :bro => 4}, {:a => 1, :bro => 2}, {:a => 3, :bro => 4}, 4]])
203
+ end
204
+
205
+ it "with no command given prints error" do
206
+ menu_input "1"
207
+ capture_stderr { two_d_menu(:action=>true) }.should =~ /No command given/
208
+ end
209
+
210
+ it "with array menu items" do
211
+ menu_input "p 1"
212
+ two_d_menu :action=>true, :output=>[['some', 'choice'], ['and', 'another']],
213
+ :invokes=>[[['some']]]
214
+ end
215
+
216
+ it "with array menu items and all choices" do
217
+ menu_input "p 1 *"
218
+ two_d_menu :action=>true, :output=>[['some', 'choice'], ['and', 'another']],
219
+ :invokes=>[[['some', 'some', 'choice', 'and', 'another']]]
220
+ end
221
+
222
+ it "with multi_action option invokes" do
223
+ menu_input "p 1 2:bro"
224
+ two_d_menu(:action=>true, :multi_action=>true, :invokes=>[[1], [4]])
225
+ end
226
+
227
+ it "with command option invokes" do
228
+ menu_input "1"
229
+ two_d_menu(:action=>true, :command=>'p', :invoke=>[[1]])
230
+ end
231
+
232
+ it "with command option and empty input doesn't invoke action and exists silently" do
233
+ Menu.any_instance.expects(:invoke).never
234
+ menu_input ""
235
+ two_d_menu(:action=>true, :command=>'p').should == nil
236
+ end
237
+
238
+ it "with action_object option invokes" do
239
+ obj = mock(:blah=>true)
240
+ menu_input "blah 1"
241
+ two_d_menu(:action=>true, :action_object=>obj)
242
+ end
243
+
244
+ it "with ask false and defaults invokes" do
245
+ two_d_menu(:output=>[{:a=>1, :bro=>2}], :action=>true, :ask=>false, :default_field=>:a,
246
+ :command=>'p', :invoke=>[[1]])
247
+ end
248
+
249
+ it "with ask false and no defaults prints error" do
250
+ capture_stderr {
251
+ two_d_menu(:output=>[{:a=>1, :bro=>2}], :action=>true, :ask=>false, :command=>'p')
252
+ }.should =~ /Default.*required/
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,79 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "object table" do
4
+ def table(*args)
5
+ Helpers::ObjectTable.render(*args)
6
+ end
7
+
8
+ before_all {
9
+ @pets = [stub(:name=>'rufus', :age=>7, :to_s=>'rufus'), stub(:name=>'alf', :age=>101, :to_s=>'alf')]
10
+ }
11
+ it "renders" do
12
+ expected_table = <<-TABLE.unindent
13
+ +-------+-----+
14
+ | name | age |
15
+ +-------+-----+
16
+ | rufus | 7 |
17
+ | alf | 101 |
18
+ +-------+-----+
19
+ 2 rows in set
20
+ TABLE
21
+ table(@pets, :fields=>[:name, :age]).should == expected_table
22
+ end
23
+
24
+ it "with no options defaults to to_s field" do
25
+ expected_table = <<-TABLE.unindent
26
+ +-------+
27
+ | value |
28
+ +-------+
29
+ | rufus |
30
+ | alf |
31
+ +-------+
32
+ 2 rows in set
33
+ TABLE
34
+ table(@pets).should == expected_table
35
+ end
36
+
37
+ it "renders simple arrays" do
38
+ expected_table = <<-TABLE.unindent
39
+ +-------+
40
+ | value |
41
+ +-------+
42
+ | 1 |
43
+ | 2 |
44
+ | 3 |
45
+ | 4 |
46
+ +-------+
47
+ 4 rows in set
48
+ TABLE
49
+ table([1,2,3,4]).should == expected_table
50
+ end
51
+
52
+ it "renders simple arrays with custom header" do
53
+ expected_table = <<-TABLE.unindent
54
+ +-----+
55
+ | num |
56
+ +-----+
57
+ | 1 |
58
+ | 2 |
59
+ | 3 |
60
+ | 4 |
61
+ +-----+
62
+ 4 rows in set
63
+ TABLE
64
+ table([1,2,3,4], :headers=>{:to_s=>'num'}).should == expected_table
65
+ end
66
+
67
+ it "with empty fields" do
68
+ expected_table = <<-TABLE.unindent
69
+ 0 rows in set
70
+ TABLE
71
+ table(@pets, :fields => []).should == expected_table
72
+ end
73
+
74
+ it "doesn't raise error for objects that don't have :send defined" do
75
+ object = Object.new
76
+ class<<object; self; end.send :undef_method, :send
77
+ should.not.raise(NoMethodError) { table([object], :fields=>[:to_s]) }
78
+ end
79
+ end