hirber 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.gemspec +21 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGELOG.rdoc +165 -0
  5. data/CONTRIBUTING.md +1 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.rdoc +205 -0
  8. data/Rakefile +35 -0
  9. data/lib/bond/completions/hirb.rb +15 -0
  10. data/lib/hirb.rb +84 -0
  11. data/lib/hirb/console.rb +43 -0
  12. data/lib/hirb/dynamic_view.rb +113 -0
  13. data/lib/hirb/formatter.rb +126 -0
  14. data/lib/hirb/helpers.rb +18 -0
  15. data/lib/hirb/helpers/auto_table.rb +24 -0
  16. data/lib/hirb/helpers/markdown_table.rb +14 -0
  17. data/lib/hirb/helpers/object_table.rb +14 -0
  18. data/lib/hirb/helpers/parent_child_tree.rb +24 -0
  19. data/lib/hirb/helpers/tab_table.rb +24 -0
  20. data/lib/hirb/helpers/table.rb +376 -0
  21. data/lib/hirb/helpers/table/filters.rb +10 -0
  22. data/lib/hirb/helpers/table/resizer.rb +82 -0
  23. data/lib/hirb/helpers/tree.rb +181 -0
  24. data/lib/hirb/helpers/unicode_table.rb +15 -0
  25. data/lib/hirb/helpers/vertical_table.rb +37 -0
  26. data/lib/hirb/import_object.rb +10 -0
  27. data/lib/hirb/menu.rb +226 -0
  28. data/lib/hirb/pager.rb +106 -0
  29. data/lib/hirb/string.rb +44 -0
  30. data/lib/hirb/util.rb +96 -0
  31. data/lib/hirb/version.rb +3 -0
  32. data/lib/hirb/view.rb +272 -0
  33. data/lib/hirb/views.rb +8 -0
  34. data/lib/hirb/views/couch_db.rb +11 -0
  35. data/lib/hirb/views/misc_db.rb +15 -0
  36. data/lib/hirb/views/mongo_db.rb +17 -0
  37. data/lib/hirb/views/orm.rb +11 -0
  38. data/lib/hirb/views/rails.rb +19 -0
  39. data/lib/ripl/hirb.rb +15 -0
  40. data/test/auto_table_test.rb +33 -0
  41. data/test/console_test.rb +27 -0
  42. data/test/dynamic_view_test.rb +94 -0
  43. data/test/formatter_test.rb +176 -0
  44. data/test/hirb_test.rb +39 -0
  45. data/test/import_test.rb +9 -0
  46. data/test/menu_test.rb +272 -0
  47. data/test/object_table_test.rb +79 -0
  48. data/test/pager_test.rb +162 -0
  49. data/test/resizer_test.rb +62 -0
  50. data/test/table_test.rb +667 -0
  51. data/test/test_helper.rb +60 -0
  52. data/test/tree_test.rb +184 -0
  53. data/test/util_test.rb +59 -0
  54. data/test/view_test.rb +178 -0
  55. data/test/views_test.rb +22 -0
  56. metadata +164 -0
@@ -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
@@ -0,0 +1,272 @@
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 1d invokes on range of choices" do
181
+ menu_input "p 1,2 1-2 1..2"
182
+ choices = [{:a => 1, :bro => 2}, {:a => 3, :bro => 4}]
183
+ two_d_menu(:action=>true, :two_d=>nil, :invoke=>[Array.new(3, choices).flatten])
184
+ end
185
+
186
+ it "with 1d and all choices" do
187
+ menu_input "p *"
188
+ two_d_menu(:action=>true, :two_d => nil, :invoke=>[[{:a => 1, :bro => 2}, {:a => 3, :bro => 4}]])
189
+ end
190
+
191
+ it "with non-choice arguments invokes" do
192
+ menu_input "p arg1 1"
193
+ two_d_menu :action=>true, :invoke=>['arg1', [1]]
194
+ end
195
+
196
+ it "with multiple choice arguments flattens them into arg" do
197
+ menu_input "p arg1 1 2:bro arg2"
198
+ two_d_menu :action=>true, :invoke=>['arg1', [1,4], 'arg2']
199
+ end
200
+
201
+ it "with nothing chosen prints error" do
202
+ menu_input "cmd"
203
+ capture_stderr { two_d_menu(:action=>true) }.should =~ /No rows chosen/
204
+ end
205
+
206
+ it "with range of choices" do
207
+ menu_input "p 1,2:a 1-2:a 1..2:a"
208
+ choices = [1,3]
209
+ two_d_menu(:action=>true, :invoke=>[Array.new(3, choices).flatten])
210
+ end
211
+
212
+ it "with multiple all choices" do
213
+ menu_input "p * * 2:bro"
214
+ two_d_menu(:action=>true, :invoke=>[[1,3,1,3,4]])
215
+ end
216
+
217
+ it "with all choices with field" do
218
+ menu_input "p *:bro"
219
+ two_d_menu(:action=>true, :invoke=>[[2, 4]])
220
+ end
221
+
222
+ it "with no command given prints error" do
223
+ menu_input "1"
224
+ capture_stderr { two_d_menu(:action=>true) }.should =~ /No command given/
225
+ end
226
+
227
+ it "with array menu items" do
228
+ menu_input "p 1"
229
+ two_d_menu :action=>true, :output=>[['some', 'choice'], ['and', 'another']],
230
+ :invokes=>[[['some']]]
231
+ end
232
+
233
+ it "with array menu items and all choices" do
234
+ menu_input "p 1 *"
235
+ two_d_menu :action=>true, :output=>[['some', 'choice'], ['and', 'another']],
236
+ :invokes=>[[['some', 'some', 'and']]]
237
+ end
238
+
239
+ it "with multi_action option invokes" do
240
+ menu_input "p 1 2:bro"
241
+ two_d_menu(:action=>true, :multi_action=>true, :invokes=>[[1], [4]])
242
+ end
243
+
244
+ it "with command option invokes" do
245
+ menu_input "1"
246
+ two_d_menu(:action=>true, :command=>'p', :invoke=>[[1]])
247
+ end
248
+
249
+ it "with command option and empty input doesn't invoke action and exists silently" do
250
+ Menu.any_instance.expects(:invoke).never
251
+ menu_input ""
252
+ two_d_menu(:action=>true, :command=>'p').should == nil
253
+ end
254
+
255
+ it "with action_object option invokes" do
256
+ obj = mock(:blah=>true)
257
+ menu_input "blah 1"
258
+ two_d_menu(:action=>true, :action_object=>obj)
259
+ end
260
+
261
+ it "with ask false and defaults invokes" do
262
+ two_d_menu(:output=>[{:a=>1, :bro=>2}], :action=>true, :ask=>false, :default_field=>:a,
263
+ :command=>'p', :invoke=>[[1]])
264
+ end
265
+
266
+ it "with ask false and no defaults prints error" do
267
+ capture_stderr {
268
+ two_d_menu(:output=>[{:a=>1, :bro=>2}], :action=>true, :ask=>false, :command=>'p')
269
+ }.should =~ /Default.*required/
270
+ end
271
+ end
272
+ 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
@@ -0,0 +1,162 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ describe "Pager" do
4
+ def pager; View.pager; end
5
+
6
+ def create_pageable_string(inspect_mode=false, size={})
7
+ size = {:width=>pager.width, :height=>pager.height}.merge(size)
8
+ seed = inspect_mode ? "a" : "a\n"
9
+ if inspect_mode
10
+ seed * (size[:width] * size[:height] + 1)
11
+ else
12
+ seed * (size[:height] + 1)
13
+ end
14
+ end
15
+
16
+ it "command_pager sets pager_command when command exists" do
17
+ Util.expects(:command_exists?).returns(true)
18
+ Pager.expects(:basic_pager)
19
+ Pager.command_pager 'blah', :pager_command=>'less'
20
+ end
21
+
22
+ it "command_pager doesn't set pager_command when command doesn't exist" do
23
+ Util.expects(:command_exists?).returns(false)
24
+ Pager.expects(:basic_pager).never
25
+ Pager.command_pager 'blah', :pager_command=>'moreless'
26
+ end
27
+
28
+ describe "default_pager" do
29
+ before_all { reset_config; Hirb.enable :pager=>true }
30
+ before { View.pager = nil; Pager.stubs(:pager_command).returns(nil) }
31
+
32
+ it "pages once in normal mode" do
33
+ $stdin.expects(:gets).returns("\n")
34
+ output = capture_stdout { pager.page(create_pageable_string, false) }
35
+ output.include?('quit').should == true
36
+ output.include?('finished').should == true
37
+ end
38
+
39
+ it "doesn't page in normal mode" do
40
+ $stdin.expects(:gets).never
41
+ output = capture_stdout { pager.page("a\n", false) }
42
+ output.include?("a\n=== Pager finished. ===\n").should == true
43
+ end
44
+
45
+ it "pages once in inspect mode" do
46
+ $stdin.expects(:gets).returns("\n")
47
+ output = capture_stdout { pager.page(create_pageable_string(true), true) }
48
+ output.include?('quit').should == true
49
+ output.include?('finished').should == true
50
+ end
51
+
52
+ it "doesn't page in inspect mode" do
53
+ $stdin.expects(:gets).never
54
+ output = capture_stdout { pager.page("a", true) }
55
+ output.include?("a\n=== Pager finished. ===\n").should == true
56
+ end
57
+ after_all { Hirb.disable }
58
+ end
59
+
60
+ describe "pager" do
61
+ before_all { reset_config; Hirb.enable }
62
+ before { View.pager = nil; View.formatter = nil }
63
+
64
+ def irb_eval(string)
65
+ context_stub = stub(:last_value=>string)
66
+ ::IRB::Irb.new(context_stub).output_value
67
+ end
68
+
69
+ # this mode is called within @irb.output_value
70
+ describe "in inspect_mode" do
71
+ it "activates when output is wide enough" do
72
+ output = create_pageable_string(true)
73
+ pager.expects(:page).with(output.inspect, true)
74
+ View.expects(:render_output).returns(false)
75
+ irb_eval output
76
+ end
77
+
78
+ it "doesn't activate when output isn't wide enough" do
79
+ pager.expects(:page).never
80
+ View.expects(:render_output).returns(false)
81
+ irb_eval("a")
82
+ end
83
+
84
+ it "activates with an explicit width" do
85
+ View.config[:width] = 10
86
+ output = create_pageable_string true, :width=>10
87
+ pager.expects(:page).with(output.inspect, true)
88
+ View.expects(:render_output).returns(false)
89
+ irb_eval output
90
+ end
91
+
92
+ it "activates default_pager when pager command is invalid" do
93
+ Pager.expects(:pager_command).returns(nil)
94
+ output = create_pageable_string(true)
95
+ Pager.expects(:default_pager).with(output.inspect, anything)
96
+ View.expects(:render_output).returns(false)
97
+ capture_stdout { irb_eval output }
98
+ end
99
+ end
100
+
101
+ # this mode is called within View.render_output
102
+ describe "in normal mode" do
103
+ it "activates when output is long enough" do
104
+ output = create_pageable_string
105
+ View.formatter.expects(:format_output).returns(output)
106
+ pager.expects(:page).with(output, false)
107
+ irb_eval(output)
108
+ end
109
+
110
+ it "doesn't activate when output isn't long enough" do
111
+ output = "a\n"
112
+ View.formatter.expects(:format_output).returns(output)
113
+ pager.expects(:page).never
114
+ capture_stdout { irb_eval(output) }
115
+ end
116
+
117
+ it "activates with an explicit height" do
118
+ View.config[:height] = 100
119
+ output = create_pageable_string false, :height=>100
120
+ View.formatter.expects(:format_output).returns(output)
121
+ pager.expects(:page).with(output, false)
122
+ irb_eval(output)
123
+ end
124
+
125
+ it "activates default_pager when pager_command is invalid" do
126
+ Pager.expects(:pager_command).returns(nil)
127
+ output = create_pageable_string
128
+ Pager.expects(:default_pager).with(output, anything)
129
+ View.formatter.expects(:format_output).returns(output)
130
+ capture_stdout { irb_eval output }
131
+ end
132
+ end
133
+
134
+ it "activates pager_command with valid pager_command option" do
135
+ View.config[:pager_command] = "less"
136
+ View.expects(:render_output).returns(false)
137
+ Util.expects(:command_exists?).returns(true)
138
+ Pager.expects(:command_pager)
139
+ irb_eval create_pageable_string(true)
140
+ View.config[:pager_command] = nil
141
+ end
142
+
143
+ it "activates pager_command with pager_command option that has command options" do
144
+ View.config[:pager_command] = "less -r"
145
+ View.expects(:render_output).returns(false)
146
+ Util.expects(:command_exists?).with('less').returns(true)
147
+ Pager.expects(:command_pager)
148
+ irb_eval create_pageable_string(true)
149
+ View.config[:pager_command] = nil
150
+ end
151
+
152
+ it "doesn't activate pager_command with invalid pager_command option" do
153
+ View.config[:pager_command] = "moreless"
154
+ View.expects(:render_output).returns(false)
155
+ Util.expects(:command_exists?).returns(false)
156
+ Pager.expects(:default_pager)
157
+ irb_eval create_pageable_string(true)
158
+ View.config[:pager_command] = nil
159
+ end
160
+ end
161
+ after_all { Hirb.disable }
162
+ end