Chrononaut-hirb 0.2.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.
@@ -0,0 +1,10 @@
1
+ module Hirb
2
+ module ObjectMethods
3
+ # Takes same options as Hirb::View.render_output.
4
+ def view(*args)
5
+ Hirb::View.console_render_output(*(args.unshift(self)))
6
+ end
7
+ end
8
+ end
9
+
10
+ Object.send :include, Hirb::ObjectMethods
data/lib/hirb/menu.rb ADDED
@@ -0,0 +1,47 @@
1
+ module Hirb
2
+ # This class provides a selection menu using Hirb's table helpers by default to display choices.
3
+ class Menu
4
+ # Menu which asks to select from the given array and returns the selected menu items as an array. See Hirb::Util.choose_from_array
5
+ # for the syntax for specifying selections. All options except for the ones below are passed to render the menu.
6
+ #
7
+ # ==== Options:
8
+ # [:helper_class] Helper class to render menu. Helper class is expected to implement numbering given a :number option.
9
+ # To use a very basic menu, set this to false. Defaults to Hirb::Helpers::AutoTable.
10
+ # [:prompt] String for menu prompt. Defaults to "Choose: ".
11
+ # [:validate_one] Validates that only one item in array is chosen and returns just that item. Default is false.
12
+ # [:ask] Always ask for input, even if there is only one choice. Default is true.
13
+ # Examples:
14
+ # extend Hirb::Console
15
+ # menu([1,2,3], :fields=>[:field1, :field2], :validate_one=>true)
16
+ # menu([1,2,3], :helper_class=>Hirb::Helpers::Table)
17
+ def self.render(output, options={})
18
+ default_options = {:helper_class=>Hirb::Helpers::AutoTable, :prompt=>"Choose #{options[:validate_one] ? 'one' : ''}: ", :ask=>true}
19
+ options = default_options.merge(options)
20
+ output = [output] unless output.is_a?(Array)
21
+ chosen = choose_from_menu(output, options)
22
+ yield(chosen) if block_given? && chosen.is_a?(Array) && chosen.size > 0
23
+ chosen
24
+ end
25
+
26
+ def self.choose_from_menu(output, options) #:nodoc:
27
+ return output if output.size == 1 && !options[:ask]
28
+ if (helper_class = Util.any_const_get(options[:helper_class]))
29
+ View.render_output(output, :class=>options[:helper_class], :options=>options.merge(:number=>true))
30
+ else
31
+ output.each_with_index {|e,i| puts "#{i+1}: #{e}" }
32
+ end
33
+ print options[:prompt]
34
+ input = $stdin.gets.chomp.strip
35
+ chosen = Util.choose_from_array(output, input)
36
+ if options[:validate_one]
37
+ if chosen.size != 1
38
+ $stderr.puts "Choose one. You chose #{chosen.size} items."
39
+ return nil
40
+ else
41
+ return chosen[0]
42
+ end
43
+ end
44
+ chosen
45
+ end
46
+ end
47
+ end
data/lib/hirb/pager.rb ADDED
@@ -0,0 +1,94 @@
1
+ module Hirb
2
+ # This class provides class methods for paging and an object which can conditionally page given a terminal size that is exceeded.
3
+ class Pager
4
+ class<<self
5
+ # Pages using a configured or detected shell command.
6
+ def command_pager(output, options={})
7
+ basic_pager(output) if valid_pager_command?(options[:pager_command])
8
+ end
9
+
10
+ def pager_command(*commands) #:nodoc:
11
+ @pager_command = (!@pager_command.nil? && commands.empty?) ? @pager_command :
12
+ begin
13
+ commands = [ENV['PAGER'], 'less', 'more', 'pager'] if commands.empty?
14
+ commands.compact.uniq.find {|e| Util.command_exists?(e[/\w+/]) }
15
+ end
16
+ end
17
+
18
+ # Pages with a ruby-only pager which either pages or quits.
19
+ def default_pager(output, options={})
20
+ pager = new(options[:width], options[:height])
21
+ while pager.activated_by?(output, options[:inspect])
22
+ puts pager.slice!(output, options[:inspect])
23
+ return unless continue_paging?
24
+ end
25
+ puts output
26
+ puts "=== Pager finished. ==="
27
+ end
28
+
29
+ #:stopdoc:
30
+ def valid_pager_command?(cmd)
31
+ cmd ? pager_command(cmd) : pager_command
32
+ end
33
+
34
+ private
35
+ def basic_pager(output)
36
+ pager = IO.popen(pager_command, "w")
37
+ begin
38
+ save_stdout = STDOUT.clone
39
+ STDOUT.reopen(pager)
40
+ STDOUT.puts output
41
+ ensure
42
+ STDOUT.reopen(save_stdout)
43
+ save_stdout.close
44
+ pager.close
45
+ end
46
+ end
47
+
48
+ def continue_paging?
49
+ puts "=== Press enter/return to continue or q to quit: ==="
50
+ !$stdin.gets.chomp[/q/i]
51
+ end
52
+ #:startdoc:
53
+ end
54
+
55
+ attr_reader :width, :height
56
+
57
+ def initialize(width, height, options={})
58
+ resize(width, height)
59
+ @pager_command = options[:pager_command] if options[:pager_command]
60
+ end
61
+
62
+ # Pages given string using configured pager.
63
+ def page(string, inspect_mode)
64
+ if self.class.valid_pager_command?(@pager_command)
65
+ self.class.command_pager(string, :pager_command=>@pager_command)
66
+ else
67
+ self.class.default_pager(string, :width=>@width, :height=>@height, :inspect=>inspect_mode)
68
+ end
69
+ end
70
+
71
+ def slice!(output, inspect_mode=false) #:nodoc:
72
+ effective_height = @height - 2 # takes into account pager prompt
73
+ if inspect_mode
74
+ sliced_output = output.slice(0, @width * effective_height)
75
+ output.replace output.slice(@width * effective_height..-1)
76
+ sliced_output
77
+ else
78
+ # could use output.scan(/[^\n]*\n?/) instead of split
79
+ sliced_output = output.split("\n").slice(0, effective_height).join("\n")
80
+ output.replace output.split("\n").slice(effective_height..-1).join("\n")
81
+ sliced_output
82
+ end
83
+ end
84
+
85
+ # Determines if string should be paged based on configured width and height.
86
+ def activated_by?(string_to_page, inspect_mode=false)
87
+ inspect_mode ? (string_to_page.size > @height * @width) : (string_to_page.count("\n") > @height)
88
+ end
89
+
90
+ def resize(width, height) #:nodoc:
91
+ @width, @height = Hirb::View.determine_terminal_size(width, height)
92
+ end
93
+ end
94
+ end
data/lib/hirb/util.rb ADDED
@@ -0,0 +1,80 @@
1
+ module Hirb
2
+ # Group of handy utility functions used throughout Hirb.
3
+ module Util
4
+ extend self
5
+ # Returns a constant like Module#const_get no matter what namespace it's nested in.
6
+ # Returns nil if the constant is not found.
7
+ def any_const_get(name)
8
+ return name if name.is_a?(Module)
9
+ begin
10
+ klass = Object
11
+ name.split('::').each {|e|
12
+ klass = klass.const_get(e)
13
+ }
14
+ klass
15
+ rescue
16
+ nil
17
+ end
18
+ end
19
+
20
+ # Recursively merge hash1 with hash2.
21
+ def recursive_hash_merge(hash1, hash2)
22
+ hash1.merge(hash2) {|k,o,n| (o.is_a?(Hash)) ? recursive_hash_merge(o,n) : n}
23
+ end
24
+
25
+ # From Rails ActiveSupport, converting undescored lowercase to camel uppercase.
26
+ def camelize(string)
27
+ string.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
28
+ end
29
+
30
+ # Used by Hirb::Menu to select items from an array. Array counting starts at 1. Ranges of numbers are specified with a '-' or '..'.
31
+ # Multiple ranges can be comma delimited. Anything that isn't a valid number is ignored. All elements can be returned with a '*'.
32
+ # Examples:
33
+ # 1-3,5-6 -> [1,2,3,5,6]
34
+ # * -> all elements in array
35
+ # '' -> []
36
+ def choose_from_array(array, input, options={})
37
+ options = {:splitter=>","}.merge(options)
38
+ return array if input.strip == '*'
39
+ result = []
40
+ input.split(options[:splitter]).each do |e|
41
+ if e =~ /-|\.\./
42
+ min,max = e.split(/-|\.\./)
43
+ slice_min = min.to_i - 1
44
+ result.push(*array.slice(slice_min, max.to_i - min.to_i + 1))
45
+ elsif e =~ /\s*(\d+)\s*/
46
+ index = $1.to_i - 1
47
+ next if index < 0
48
+ result.push(array[index]) if array[index]
49
+ end
50
+ end
51
+ return result
52
+ end
53
+
54
+ # Determines if a shell command exists by searching for it in ENV['PATH'].
55
+ def command_exists?(command)
56
+ ENV['PATH'].split(File::PATH_SEPARATOR).any? {|d| File.exists? File.join(d, command) }
57
+ end
58
+
59
+ # Returns [width, height] of terminal when detected, nil if not detected.
60
+ # Think of this as a simpler version of Highline's Highline::SystemExtensions.terminal_size()
61
+ def detect_terminal_size
62
+ (ENV['COLUMNS'] =~ /^\d+$/) && (ENV['LINES'] =~ /^\d+$/) ? [ENV['COLUMNS'].to_i, ENV['LINES'].to_i] :
63
+ ( command_exists?('stty') ? `stty size`.scan(/\d+/).map { |s| s.to_i }.reverse : nil )
64
+ rescue
65
+ nil
66
+ end
67
+
68
+ # Captures STDOUT of anything run in its block and returns it as string.
69
+ def capture_stdout(&block)
70
+ original_stdout = $stdout
71
+ $stdout = fake = StringIO.new
72
+ begin
73
+ yield
74
+ ensure
75
+ $stdout = original_stdout
76
+ end
77
+ fake.string
78
+ end
79
+ end
80
+ end
data/lib/hirb/view.rb ADDED
@@ -0,0 +1,177 @@
1
+ module Hirb
2
+ # This class is responsible for managing all view-related functionality. Its functionality is determined by setting up a configuration file
3
+ # as explained in Hirb and/or passed configuration directly to Hirb.enable. Most of the functionality in this class is dormant until enabled.
4
+ module View
5
+ DEFAULT_WIDTH = 120
6
+ DEFAULT_HEIGHT = 40
7
+ class << self
8
+ attr_accessor :render_method
9
+ attr_reader :config
10
+
11
+ # This activates view functionality i.e. the formatter, pager and size detection. If irb exists, it overrides irb's output
12
+ # method with Hirb::View.view_output. If using Wirble, you should call this after it. The view configuration
13
+ # can be specified in a hash via a config file, as options to this method, as this method's block or any combination of these three.
14
+ # In addition to the config keys mentioned in Hirb, the options also take the following keys:
15
+ # Options:
16
+ # * config_file: Name of config file to read.
17
+ # Examples:
18
+ # Hirb::View.enable
19
+ # Hirb::View.enable :formatter=>false
20
+ # Hirb::View.enable {|c| c.output = {'String'=>{:class=>'Hirb::Helpers::Table'}} }
21
+ def enable(options={}, &block)
22
+ return puts("Already enabled.") if @enabled
23
+ @enabled = true
24
+ Hirb.config_file = options.delete(:config_file) if options[:config_file]
25
+ load_config(Util.recursive_hash_merge(options, HashStruct.block_to_hash(block)))
26
+ resize(config[:width], config[:height])
27
+ if Object.const_defined?(:IRB)
28
+ ::IRB::Irb.class_eval do
29
+ alias :non_hirb_view_output :output_value
30
+ def output_value #:nodoc:
31
+ Hirb::View.view_output(@context.last_value) || Hirb::View.page_output(@context.last_value.inspect, true) ||
32
+ non_hirb_view_output
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ # Indicates if Hirb::View is enabled.
39
+ def enabled?
40
+ @enabled || false
41
+ end
42
+
43
+ # Disable's Hirb's output and revert's irb's output method if irb exists.
44
+ def disable
45
+ @enabled = false
46
+ if Object.const_defined?(:IRB)
47
+ ::IRB::Irb.class_eval do
48
+ alias :output_value :non_hirb_view_output
49
+ end
50
+ end
51
+ end
52
+
53
+ # Toggles pager on or off. The pager only works while Hirb::View is enabled.
54
+ def toggle_pager
55
+ config[:pager] = !config[:pager]
56
+ end
57
+
58
+ # Toggles formatter on or off.
59
+ def toggle_formatter
60
+ config[:formatter] = !config[:formatter]
61
+ end
62
+
63
+ # Resizes the console width and height for use with the table and pager i.e. after having resized the console window. *nix users
64
+ # should only have to call this method. Non-*nix users should call this method with explicit width and height. If you don't know
65
+ # your width and height, in irb play with "a"* width to find width and puts "a\n" * height to find height.
66
+ def resize(width=nil, height=nil)
67
+ config[:width], config[:height] = determine_terminal_size(width, height)
68
+ pager.resize(config[:width], config[:height])
69
+ end
70
+
71
+ # This is the main method of this class. When view is enabled, this method searches for a formatter it can use for the output and if
72
+ # successful renders it using render_method(). The options this method takes are helper config hashes as described in
73
+ # Hirb::Formatter.format_output(). Returns true if successful and false if no formatting is done or if not enabled.
74
+ def view_output(output, options={})
75
+ enabled? && config[:formatter] && render_output(output, options)
76
+ end
77
+
78
+ # Captures STDOUT and renders it using render_method(). The main use case is to conditionally page captured stdout.
79
+ def capture_and_render(&block)
80
+ render_method.call Util.capture_stdout(&block)
81
+ end
82
+
83
+ # A lambda or proc which handles the final formatted object.
84
+ # Although this pages/puts the object by default, it could be set to do other things
85
+ # i.e. write the formatted object to a file.
86
+ def render_method
87
+ @render_method ||= default_render_method
88
+ end
89
+
90
+ # Resets render_method back to its default.
91
+ def reset_render_method
92
+ @render_method = default_render_method
93
+ end
94
+
95
+ # Current console width
96
+ def width
97
+ config ? config[:width] : DEFAULT_WIDTH
98
+ end
99
+
100
+ # Current console height
101
+ def height
102
+ config ? config[:height] : DEFAULT_HEIGHT
103
+ end
104
+
105
+ # Current formatter config
106
+ def formatter_config
107
+ formatter.config
108
+ end
109
+
110
+ # Sets the helper config for the given output class.
111
+ def format_class(klass, helper_config)
112
+ formatter.format_class(klass, helper_config)
113
+ end
114
+
115
+ #:stopdoc:
116
+ def render_output(output, options={})
117
+ if (formatted_output = formatter.format_output(output, options))
118
+ render_method.call(formatted_output)
119
+ true
120
+ else
121
+ false
122
+ end
123
+ end
124
+
125
+ def determine_terminal_size(width, height)
126
+ detected = (width.nil? || height.nil?) ? Util.detect_terminal_size || [] : []
127
+ [width || detected[0] || DEFAULT_WIDTH , height || detected[1] || DEFAULT_HEIGHT]
128
+ end
129
+
130
+ def page_output(output, inspect_mode=false)
131
+ if enabled? && config[:pager] && pager.activated_by?(output, inspect_mode)
132
+ pager.page(output, inspect_mode)
133
+ true
134
+ else
135
+ false
136
+ end
137
+ end
138
+
139
+ def pager
140
+ @pager ||= Pager.new(config[:width], config[:height], :pager_command=>config[:pager_command])
141
+ end
142
+
143
+ def pager=(value); @pager = value; end
144
+
145
+ def formatter(reload=false)
146
+ @formatter = reload || @formatter.nil? ? Formatter.new(config[:output]) : @formatter
147
+ end
148
+
149
+ def formatter=(value); @formatter = value; end
150
+
151
+ def load_config(additional_config={})
152
+ @config = Util.recursive_hash_merge default_config, additional_config
153
+ formatter(true)
154
+ true
155
+ end
156
+
157
+ def config_loaded?; !!@config; end
158
+
159
+ def config
160
+ @config
161
+ end
162
+
163
+ def default_render_method
164
+ lambda {|output| page_output(output) || puts(output) }
165
+ end
166
+
167
+ def default_config
168
+ Util.recursive_hash_merge({:pager=>true, :formatter=>true}, Hirb.config || {})
169
+ end
170
+ #:startdoc:
171
+ end
172
+ end
173
+
174
+ # Namespace for autoloaded views
175
+ module Views
176
+ end
177
+ end
@@ -0,0 +1,9 @@
1
+ class Hirb::Views::ActiveRecord_Base #:nodoc:
2
+ def self.default_options
3
+ {:ancestor=>true}
4
+ end
5
+
6
+ def self.render(*args)
7
+ Hirb::Helpers::ActiveRecordTable.render(*args)
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class Hirb::ConsoleTest < Test::Unit::TestCase
4
+ context "parse_input" do
5
+ test "config is set if it wasn't before" do
6
+ reset_config
7
+ Hirb::View.expects(:render_output)
8
+ Hirb::Console.render_output('blah')
9
+ Hirb::View.config.is_a?(Hash).should == true
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,172 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ module Hirb
4
+ class FormatterTest < Test::Unit::TestCase
5
+ context "formatter" do
6
+ def set_formatter(hash={})
7
+ @formatter = Formatter.new(hash)
8
+ end
9
+
10
+ before(:all) { eval "module ::Dooda; end" }
11
+
12
+ test "klass_config merges ancestor options" do
13
+ set_formatter "String"=>{:args=>[1,2]}, "Object"=>{:method=>:object_output, :ancestor=>true}, "Kernel"=>{:method=>:default_output}
14
+ expected_result = {:method=>:object_output, :args=>[1, 2], :ancestor=>true}
15
+ @formatter.klass_config(String).should == expected_result
16
+ end
17
+
18
+ test "klass_config doesn't merge ancestor options" do
19
+ set_formatter "String"=>{:args=>[1,2]}, "Object"=>{:method=>:object_output}, "Kernel"=>{:method=>:default_output}
20
+ expected_result = {:args=>[1, 2]}
21
+ @formatter.klass_config(String).should == expected_result
22
+ end
23
+
24
+ test "klass_config returns hash when nothing found" do
25
+ set_formatter.klass_config(String).should == {}
26
+ end
27
+
28
+ test "reload detects new Hirb::Views" do
29
+ set_formatter
30
+ @formatter.config.keys.include?('Zzz').should be(false)
31
+ eval "module ::Hirb::Views::Zzz; def self.render; end; end"
32
+ @formatter.reload
33
+ @formatter.config.keys.include?('Zzz').should be(true)
34
+ end
35
+
36
+ test "format_class sets formatter config" do
37
+ set_formatter
38
+ @formatter.format_class ::Dooda, :class=>"DoodaView"
39
+ @formatter.klass_config(::Dooda).should == {:class=>"DoodaView"}
40
+ end
41
+
42
+ test "format_class overwrites existing formatter config" do
43
+ set_formatter "Dooda"=>{:class=>"DoodaView"}
44
+ @formatter.format_class ::Dooda, :class=>"DoodaView2"
45
+ @formatter.klass_config(::Dooda).should == {:class=>"DoodaView2"}
46
+ end
47
+
48
+ test "parse_console_options passes all options except for formatter options into :options" do
49
+ set_formatter
50
+ options = {:class=>'blah', :method=>'blah', :output_method=>'blah', :blah=>'blah'}
51
+ expected_options = {:class=>'blah', :method=>'blah', :output_method=>'blah', :options=>{:blah=>'blah'}}
52
+ @formatter.parse_console_options(options).should == expected_options
53
+ end
54
+ end
55
+
56
+ context "enable" do
57
+ before(:each) { View.formatter = nil; reset_config }
58
+ after(:each) { Hirb.disable }
59
+
60
+ def formatter_config
61
+ View.formatter.config
62
+ end
63
+
64
+ test "sets default formatter config" do
65
+ eval "module ::Hirb::Views::Something_Base; def self.render; end; end"
66
+ Hirb.enable
67
+ formatter_config["Something::Base"].should == {:class=>"Hirb::Views::Something_Base"}
68
+ end
69
+
70
+ test "sets default formatter config with default_options" do
71
+ eval "module ::Hirb::Views::Blah; def self.render; end; def self.default_options; {:ancestor=>true}; end; end"
72
+ Hirb.enable
73
+ formatter_config["Blah"].should == {:class=>"Hirb::Views::Blah", :ancestor=>true}
74
+ end
75
+
76
+ test "with block sets formatter config" do
77
+ class_hash = {"Something::Base"=>{:class=>"BlahBlah"}}
78
+ Hirb.enable {|c| c.output = class_hash }
79
+ formatter_config['Something::Base'].should == class_hash['Something::Base']
80
+ end
81
+ end
82
+
83
+ context "format_output" do
84
+ def view_output(*args, &block); View.view_output(*args, &block); end
85
+ def render_method(*args); View.render_method(*args); end
86
+
87
+ def enable_with_output(value)
88
+ Hirb.enable :output=>value
89
+ end
90
+
91
+ before(:all) {
92
+ eval %[module ::Commify
93
+ def self.render(strings)
94
+ strings = [strings] unless strings.is_a?(Array)
95
+ strings.map {|e| e.split('').join(',')}.join("\n")
96
+ end
97
+ end]
98
+ reset_config
99
+ }
100
+ before(:each) { View.formatter = nil; reset_config }
101
+ after(:each) { Hirb.disable }
102
+
103
+ test "formats with method option" do
104
+ eval "module ::Kernel; def commify(string); string.split('').join(','); end; end"
105
+ enable_with_output "String"=>{:method=>:commify}
106
+ render_method.expects(:call).with('d,u,d,e')
107
+ view_output('dude')
108
+ end
109
+
110
+ test "formats with class option" do
111
+ enable_with_output "String"=>{:class=>"Commify"}
112
+ render_method.expects(:call).with('d,u,d,e')
113
+ view_output('dude')
114
+ end
115
+
116
+ test "formats with class option as symbol" do
117
+ enable_with_output "String"=>{:class=>:auto_table}
118
+ Helpers::AutoTable.expects(:render)
119
+ view_output('dude')
120
+ end
121
+
122
+ test "formats output array" do
123
+ enable_with_output "String"=>{:class=>"Commify"}
124
+ render_method.expects(:call).with('d,u,d,e')
125
+ view_output(['dude'])
126
+ end
127
+
128
+ test "formats with options option" do
129
+ eval "module ::Blahify; def self.render(*args); end; end"
130
+ enable_with_output "String"=>{:class=>"Blahify", :options=>{:fields=>%w{a b}}}
131
+ Blahify.expects(:render).with('dude', :fields=>%w{a b})
132
+ view_output('dude')
133
+ end
134
+
135
+ test "doesn't format and returns false when no format method found" do
136
+ Hirb.enable
137
+ render_method.expects(:call).never
138
+ view_output(Date.today).should == false
139
+ end
140
+
141
+ test "formats with output_method option as method" do
142
+ enable_with_output 'String'=>{:class=>"Commify", :output_method=>:chop}
143
+ render_method.expects(:call).with('d,u,d')
144
+ view_output('dude')
145
+ end
146
+
147
+ test "formats with output_method option as proc" do
148
+ enable_with_output 'String'=>{:class=>"Commify", :output_method=>lambda {|e| e.chop}}
149
+ render_method.expects(:call).with('d,u,d')
150
+ view_output('dude')
151
+ end
152
+
153
+ test "formats output array with output_method option" do
154
+ enable_with_output 'String'=>{:class=>"Commify", :output_method=>:chop}
155
+ render_method.expects(:call).with("d,u,d\nm,a")
156
+ view_output(['dude', 'man'])
157
+ end
158
+
159
+ test "formats with explicit class option" do
160
+ enable_with_output 'String'=>{:class=>"Blahify"}
161
+ render_method.expects(:call).with('d,u,d,e')
162
+ view_output('dude', :class=>"Commify")
163
+ end
164
+
165
+ test "formats with explicit options option merges with existing options" do
166
+ enable_with_output "String"=>{:class=>"Commify", :options=>{:fields=>%w{f1 f2}}}
167
+ Commify.expects(:render).with('dude', :max_width=>10, :fields=>%w{f1 f2})
168
+ view_output('dude', :options=>{:max_width=>10})
169
+ end
170
+ end
171
+ end
172
+ end