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.
- data/.gemspec +21 -0
- data/CHANGELOG.rdoc +144 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +194 -0
- data/Rakefile +35 -0
- data/lib/bond/completions/hirb.rb +15 -0
- data/lib/hirb/console.rb +43 -0
- data/lib/hirb/dynamic_view.rb +113 -0
- data/lib/hirb/formatter.rb +126 -0
- data/lib/hirb/helpers/auto_table.rb +24 -0
- data/lib/hirb/helpers/object_table.rb +14 -0
- data/lib/hirb/helpers/parent_child_tree.rb +24 -0
- data/lib/hirb/helpers/tab_table.rb +24 -0
- data/lib/hirb/helpers/table/filters.rb +10 -0
- data/lib/hirb/helpers/table/resizer.rb +82 -0
- data/lib/hirb/helpers/table.rb +349 -0
- data/lib/hirb/helpers/tree.rb +181 -0
- data/lib/hirb/helpers/unicode_table.rb +15 -0
- data/lib/hirb/helpers/vertical_table.rb +37 -0
- data/lib/hirb/helpers.rb +18 -0
- data/lib/hirb/import_object.rb +10 -0
- data/lib/hirb/menu.rb +238 -0
- data/lib/hirb/pager.rb +105 -0
- data/lib/hirb/string.rb +44 -0
- data/lib/hirb/util.rb +96 -0
- data/lib/hirb/version.rb +3 -0
- data/lib/hirb/view.rb +270 -0
- data/lib/hirb/views/couch_db.rb +11 -0
- data/lib/hirb/views/misc_db.rb +15 -0
- data/lib/hirb/views/mongo_db.rb +14 -0
- data/lib/hirb/views/orm.rb +11 -0
- data/lib/hirb/views/rails.rb +19 -0
- data/lib/hirb/views.rb +8 -0
- data/lib/hirb.rb +82 -0
- data/lib/ripl/hirb.rb +15 -0
- data/test/auto_table_test.rb +30 -0
- data/test/console_test.rb +27 -0
- data/test/deps.rip +4 -0
- data/test/dynamic_view_test.rb +94 -0
- data/test/formatter_test.rb +176 -0
- data/test/hirb_test.rb +39 -0
- data/test/import_test.rb +9 -0
- data/test/menu_test.rb +255 -0
- data/test/object_table_test.rb +79 -0
- data/test/pager_test.rb +162 -0
- data/test/resizer_test.rb +62 -0
- data/test/table_test.rb +630 -0
- data/test/test_helper.rb +61 -0
- data/test/tree_test.rb +184 -0
- data/test/util_test.rb +59 -0
- data/test/view_test.rb +165 -0
- data/test/views_test.rb +13 -0
- 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
|
data/test/import_test.rb
ADDED
@@ -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
|