hirber 0.8.0

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