hirb 0.1.2

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,22 @@
1
+ class Hirb::Helpers::ParentChildTree < Hirb::Helpers::Tree
2
+ class <<self
3
+ # Starting with the given node, this builds a tree by recursively calling a children method.
4
+ # Takes same options as Hirb::Helper::Table.render with some additional ones below.
5
+ # ==== Options:
6
+ # [:value_method] Method to call to display as a node's value. If not given, uses :name if node
7
+ # responds to :name or defaults to :object_id.
8
+ # [:children_method] Method to call to obtain a node's children. Default is :children.
9
+ def render(root_node, options={})
10
+ @value_method = options[:value_method] || (root_node.respond_to?(:name) ? :name : :object_id)
11
+ @children_method = options[:children_method] || :children
12
+ @nodes = []
13
+ build_node(root_node, 0)
14
+ super(@nodes, options)
15
+ end
16
+
17
+ def build_node(node, level) #:nodoc:
18
+ @nodes << {:value=>node.send(@value_method), :level=>level}
19
+ node.send(@children_method).each {|e| build_node(e, level + 1)}
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,175 @@
1
+ # Base Table class from which other table classes inherit.
2
+ # By default, a table is constrained to a default width but this can be adjusted
3
+ # via options as well as Hirb:Helpers::Table.max_width.
4
+ # Rows can be an array of arrays or an array of hashes.
5
+ #
6
+ # An array of arrays ie [[1,2], [2,3]], would render:
7
+ # +---+---+
8
+ # | 0 | 1 |
9
+ # +---+---+
10
+ # | 1 | 2 |
11
+ # | 2 | 3 |
12
+ # +---+---+
13
+ #
14
+ # By default, the fields/columns are the numerical indices of the array.
15
+ #
16
+ # An array of hashes ie [{:age=>10, :weight=>100}, {:age=>80, :weight=>500}], would render:
17
+ # +-----+--------+
18
+ # | age | weight |
19
+ # +-----+--------+
20
+ # | 10 | 100 |
21
+ # | 80 | 500 |
22
+ # +-----+--------+
23
+ #
24
+ # By default, the fields/columns are the keys of the first hash.
25
+ #--
26
+ # derived from http://gist.github.com/72234
27
+ class Hirb::Helpers::Table
28
+ DEFAULT_MAX_WIDTH = 150
29
+ class TooManyFieldsForWidthError < StandardError; end
30
+ class << self
31
+ attr_accessor :max_width
32
+
33
+ # Main method which returns a formatted table.
34
+ # ==== Options:
35
+ # [:fields] An array which overrides the default fields and can be used to indicate field order.
36
+ # [:headers] A hash of fields and their header names. Fields that aren't specified here default to their name.
37
+ # This option can also be an array but only for array rows.
38
+ # [:field_lengths] A hash of fields and their maximum allowed lengths. If a field exceeds it's maximum
39
+ # length than it's truncated and has a ... appended to it. Fields that aren't specified here have no maximum allowed
40
+ # length.
41
+ # [:max_width] The maximum allowed width of all fields put together. This option is enforced except when the field_lengths option is set.
42
+ # This doesn't count field borders as part of the total.
43
+ # Examples:
44
+ # Hirb::Helpers::Table.render [[1,2], [2,3]]
45
+ # Hirb::Helpers::Table.render [[1,2], [2,3]], :field_lengths=>{0=>10}
46
+ # Hirb::Helpers::Table.render [{:age=>10, :weight=>100}, {:age=>80, :weight=>500}]
47
+ # Hirb::Helpers::Table.render [{:age=>10, :weight=>100}, {:age=>80, :weight=>500}], :headers=>{:weight=>"Weight(lbs)"}
48
+ def render(rows, options={})
49
+ new(rows,options).render
50
+ end
51
+ end
52
+
53
+ #:stopdoc:
54
+ def initialize(rows, options={})
55
+ @options = options
56
+ @fields = options[:fields] || ((rows[0].is_a?(Hash)) ? rows[0].keys.sort {|a,b| a.to_s <=> b.to_s} :
57
+ rows[0].is_a?(Array) ? (0..rows[0].length - 1).to_a : [])
58
+ @rows = setup_rows(rows)
59
+ @headers = @fields.inject({}) {|h,e| h[e] = e.to_s; h}
60
+ if options.has_key?(:headers)
61
+ @headers = options[:headers].is_a?(Hash) ? @headers.merge(options[:headers]) :
62
+ (options[:headers].is_a?(Array) ? array_to_indices_hash(options[:headers]) : options[:headers])
63
+ end
64
+ end
65
+
66
+ def setup_rows(rows)
67
+ rows ||= []
68
+ rows = [rows] unless rows.is_a?(Array)
69
+ if rows[0].is_a?(Array)
70
+ rows = rows.inject([]) {|new_rows, row|
71
+ new_rows << array_to_indices_hash(row)
72
+ }
73
+ end
74
+ validate_values(rows)
75
+ rows
76
+ end
77
+
78
+ def render
79
+ body = []
80
+ unless @rows.length == 0
81
+ setup_field_lengths
82
+ body += @headers ? render_header : [render_border]
83
+ body += render_rows
84
+ body << render_border
85
+ end
86
+ body << render_table_description
87
+ body.join("\n")
88
+ end
89
+
90
+ def render_header
91
+ title_row = '| ' + @fields.map {|f|
92
+ format_cell(@headers[f], @field_lengths[f])
93
+ }.join(' | ') + ' |'
94
+ [render_border, title_row, render_border]
95
+ end
96
+
97
+ def render_border
98
+ '+-' + @fields.map {|f| '-' * @field_lengths[f] }.join('-+-') + '-+'
99
+ end
100
+
101
+ def format_cell(value, cell_width)
102
+ text = value.length > cell_width ?
103
+ (
104
+ (cell_width < 5) ? value.slice(0,cell_width) : value.slice(0, cell_width - 3) + '...'
105
+ ) : value
106
+ sprintf("%-#{cell_width}s", text)
107
+ end
108
+
109
+ def render_rows
110
+ @rows.map do |row|
111
+ row = '| ' + @fields.map {|f|
112
+ format_cell(row[f], @field_lengths[f])
113
+ }.join(' | ') + ' |'
114
+ end
115
+ end
116
+
117
+ def render_table_description
118
+ (@rows.length == 0) ? "0 rows in set" :
119
+ "#{@rows.length} #{@rows.length == 1 ? 'row' : 'rows'} in set"
120
+ end
121
+
122
+ def setup_field_lengths
123
+ @field_lengths = default_field_lengths
124
+ if @options[:field_lengths]
125
+ @field_lengths.merge!(@options[:field_lengths])
126
+ else
127
+ table_max_width = Hirb::Helpers::Table.max_width || DEFAULT_MAX_WIDTH
128
+ table_max_width = @options[:max_width] if @options.has_key?(:max_width)
129
+ restrict_field_lengths(@field_lengths, table_max_width)
130
+ end
131
+ end
132
+
133
+ # Simple algorithm which given a max width, allows smaller fields to be displayed while
134
+ # restricting longer fields at an average_long_field_length.
135
+ def restrict_field_lengths(field_lengths, max_width)
136
+ total_length = field_lengths.values.inject {|t,n| t += n}
137
+ if max_width && total_length > max_width
138
+ min_field_length = 3
139
+ raise TooManyFieldsForWidthError if @fields.size > max_width.to_f / min_field_length
140
+ average_field_length = total_length / @fields.size.to_f
141
+ long_lengths = field_lengths.values.select {|e| e > average_field_length}
142
+ total_long_field_length = (long_lengths.inject {|t,n| t += n}) * max_width/total_length
143
+ average_long_field_length = total_long_field_length / long_lengths.size
144
+ field_lengths.each {|f,length|
145
+ field_lengths[f] = average_long_field_length if length > average_long_field_length
146
+ }
147
+ end
148
+ end
149
+
150
+ # find max length for each field; start with the headers
151
+ def default_field_lengths
152
+ field_lengths = @headers ? @headers.inject({}) {|h,(k,v)| h[k] = v.length; h} : {}
153
+ @rows.each do |row|
154
+ @fields.each do |field|
155
+ len = row[field].length
156
+ field_lengths[field] = len if len > field_lengths[field].to_i
157
+ end
158
+ end
159
+ field_lengths
160
+ end
161
+
162
+ def validate_values(rows)
163
+ rows.each {|row|
164
+ @fields.each {|f|
165
+ row[f] = row[f].to_s || ''
166
+ }
167
+ }
168
+ end
169
+
170
+ # Converts an array to a hash mapping a numerical index to its array value.
171
+ def array_to_indices_hash(array)
172
+ array.inject({}) {|hash,e| hash[hash.size] = e; hash }
173
+ end
174
+ #:startdoc:
175
+ end
@@ -0,0 +1,177 @@
1
+ # Base tree class which given an array of nodes produces different types of trees.
2
+ # The types of trees currently are:
3
+ # * basic:
4
+ # 0
5
+ # 1
6
+ # 2
7
+ # 3
8
+ # 4
9
+ #
10
+ # * directory:
11
+ # 0
12
+ # |-- 1
13
+ # | |-- 2
14
+ # | `-- 3
15
+ # `-- 4
16
+ #
17
+ # * number:
18
+ # 1. 0
19
+ # 1. 1
20
+ # 1. 2
21
+ # 2. 3
22
+ # 2. 4
23
+ #
24
+ # Tree nodes can be given as an array of arrays or an array of hashes.
25
+ # To render the above basic tree with an array of hashes:
26
+ # Hirb::Helpers::Tree.render([{:value=>0, :level=>0}, {:value=>1, :level=>1}, {:value=>2, :level=>2},
27
+ # {:value=>3, :level=>2}, {:value=>4, :level=>1}])
28
+ # Note from the hash keys that :level refers to the depth of the tree while :value refers to the text displayed
29
+ # for a node.
30
+ #
31
+ # To render the above basic tree with an array of arrays:
32
+ # Hirb::Helpers::Tree.render([[0,0], [1,1], [2,2], [2,3], [1,4]])
33
+ # Note that the each array pair consists of the level and the value for the node.
34
+ class Hirb::Helpers::Tree
35
+ class ParentlessNodeError < StandardError; end
36
+
37
+ class <<self
38
+ # Main method which renders a tree.
39
+ # ==== Options:
40
+ # [:type] Type of tree. Either :basic, :directory or :number. Default is :basic.
41
+ # [:validate] Boolean to validate tree. Checks to see if all nodes have parents. Raises ParentlessNodeError if
42
+ # an invalid node is found. Default is false.
43
+ # [:indent] Number of spaces to indent between levels for basic + number trees. Default is 4.
44
+ # [:limit] Limits the level or depth of a tree that is displayed. Root node is level 0.
45
+ # [:description] Displays brief description about tree ie how many nodes it has.
46
+ # Examples:
47
+ # Hirb::Helpers::Tree.render([[0, 'root'], [1, 'child']], :type=>:directory)
48
+ def render(nodes, options={})
49
+ new(nodes, options).render
50
+ end
51
+ end
52
+
53
+ # :stopdoc:
54
+ attr_accessor :nodes
55
+
56
+ def initialize(input_nodes, options={})
57
+ @options = options
58
+ @type = options[:type] || :basic
59
+ if input_nodes[0].is_a?(Array)
60
+ @nodes = input_nodes.map {|e| Node.new(:level=>e[0], :value=>e[1]) }
61
+ else
62
+ @nodes = input_nodes.map {|e| Node.new(e)}
63
+ end
64
+ @nodes.each_with_index {|e,i| e.merge!(:tree=>self, :index=>i)}
65
+ @nodes.each {|e| e[:value] = e[:value].to_s }
66
+ validate_nodes if options[:validate]
67
+ self
68
+ end
69
+
70
+ def render
71
+ body = render_tree
72
+ body += render_description if @options[:description]
73
+ body
74
+ end
75
+
76
+ def render_description
77
+ "\n\n#{@nodes.length} #{@nodes.length == 1 ? 'node' : 'nodes'} in tree"
78
+ end
79
+
80
+ def render_tree
81
+ @indent = ' ' * (@options[:indent] || 4 )
82
+ @nodes = @nodes.select {|e| e[:level] <= @options[:limit] } if @options[:limit]
83
+ case @type.to_s
84
+ when 'directory'
85
+ render_directory
86
+ when 'number'
87
+ render_number
88
+ else
89
+ render_basic
90
+ end
91
+ end
92
+
93
+ def render_directory
94
+ mark_last_nodes_per_level
95
+ new_nodes = []
96
+ @nodes.each_with_index {|e, i|
97
+ value = ''
98
+ unless e.root?
99
+ value << e.render_parent_characters
100
+ value << (e[:last_node] ? "`-- " : "|-- ")
101
+ end
102
+ value << e[:value]
103
+ new_nodes << value
104
+ }
105
+ new_nodes.join("\n")
106
+ end
107
+
108
+ def render_number
109
+ counter = {}
110
+ @nodes.each {|e|
111
+ parent_level_key = "#{(e.parent ||{})[:index]}.#{e[:level]}"
112
+ counter[parent_level_key] ||= 0
113
+ counter[parent_level_key] += 1
114
+ e[:pre_value] = "#{counter[parent_level_key]}. "
115
+ }
116
+ @nodes.map {|e| @indent * e[:level] + e[:pre_value] + e[:value]}.join("\n")
117
+ end
118
+
119
+ def render_basic
120
+ @nodes.map {|e| @indent * e[:level] + e[:value]}.join("\n")
121
+ end
122
+
123
+ def validate_nodes
124
+ @nodes.each do |e|
125
+ raise ParentlessNodeError if (e[:level] > e.previous[:level]) && (e[:level] - e.previous[:level]) > 1
126
+ end
127
+ end
128
+
129
+ # walks tree accumulating last nodes per unique parent+level
130
+ def mark_last_nodes_per_level
131
+ @nodes.each {|e| e.delete(:last_node)}
132
+ last_node_hash = @nodes.inject({}) {|h,e|
133
+ h["#{(e.parent ||{})[:index]}.#{e[:level]}"] = e; h
134
+ }
135
+ last_node_hash.values.uniq.each {|e| e[:last_node] = true}
136
+ end
137
+ #:startdoc:
138
+ class Node < ::Hash #:nodoc:
139
+ class MissingLevelError < StandardError; end
140
+ class MissingValueError < StandardError; end
141
+
142
+ def initialize(hash)
143
+ super
144
+ raise MissingLevelError unless hash.has_key?(:level)
145
+ raise MissingValueError unless hash.has_key?(:value)
146
+ replace(hash)
147
+ end
148
+
149
+ def parent
150
+ self[:tree].nodes.slice(0 .. self[:index]).reverse.detect {|e| e[:level] < self[:level]}
151
+ end
152
+
153
+ def next
154
+ self[:tree].nodes[self[:index] + 1]
155
+ end
156
+
157
+ def previous
158
+ self[:tree].nodes[self[:index] - 1]
159
+ end
160
+
161
+ def root?; self[:level] == 0; end
162
+
163
+ # refers to characters which connect parent nodes
164
+ def render_parent_characters
165
+ parent_chars = []
166
+ get_parents_character(parent_chars)
167
+ parent_chars.reverse.map {|level| level + ' ' * 3 }.to_s
168
+ end
169
+
170
+ def get_parents_character(parent_chars)
171
+ if self.parent
172
+ parent_chars << (self.parent[:last_node] ? ' ' : '|') unless self.parent.root?
173
+ self.parent.get_parents_character(parent_chars)
174
+ end
175
+ end
176
+ end
177
+ end
@@ -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
@@ -0,0 +1,29 @@
1
+ module Hirb
2
+ module Util
3
+ extend self
4
+ # Returns a constant like const_get() no matter what namespace it's nested in.
5
+ # Returns nil if the constant is not found.
6
+ def any_const_get(name)
7
+ return name if name.is_a?(Module)
8
+ begin
9
+ klass = Object
10
+ name.split('::').each {|e|
11
+ klass = klass.const_get(e)
12
+ }
13
+ klass
14
+ rescue
15
+ nil
16
+ end
17
+ end
18
+
19
+ # Recursively merge hash1 with hash2.
20
+ def recursive_hash_merge(hash1, hash2)
21
+ hash1.merge(hash2) {|k,o,n| (o.is_a?(Hash)) ? recursive_hash_merge(o,n) : n}
22
+ end
23
+
24
+ # from Rails ActiveSupport
25
+ def camelize(string)
26
+ string.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,201 @@
1
+ module Hirb
2
+ # This class contains one method, render_output, which formats and renders the output its given from a console application.
3
+ # However, this only happens for output classes that are configured to do so or if render_output is explicitly given
4
+ # a view formatter. The hash with the following keys are valid for Hirb::View.config as well as the :view key mentioned in Hirb:
5
+ # [:output] This hash is saved to output_config. It maps output classes to hashes that are passed to render_output. Thus these hashes
6
+ # take the same options as render_output. In addition it takes the following keys:
7
+ # * :ancestor- Boolean which if true allows all subclasses of the configured output class to inherit this config.
8
+ #
9
+ # Example: {'String'=>{:class=>'Hirb::Helpers::Table', :ancestor=>true, :options=>{:max_width=>180}}}
10
+ module View
11
+ class<<self
12
+ attr_accessor :config, :render_method
13
+
14
+ # Overrides irb's output method with Hirb::View.render_output. Takes an optional
15
+ # block which sets the view config.
16
+ # Examples:
17
+ # Hirb.enable
18
+ # Hirb.enable {|c| c.output = {'String'=>{:class=>'Hirb::Helpers::Table'}} }
19
+ def enable(&block)
20
+ return puts("Already enabled.") if @enabled
21
+ @enabled = true
22
+ load_config(Hirb::HashStruct.block_to_hash(block))
23
+ ::IRB::Irb.class_eval do
24
+ alias :non_hirb_render_output :output_value
25
+ def output_value #:nodoc:
26
+ Hirb::View.render_output(@context.last_value) || non_hirb_render_output
27
+ end
28
+ end
29
+ end
30
+
31
+ # Disable's Hirb's output by reverting back to irb's.
32
+ def disable
33
+ @enabled = false
34
+ ::IRB::Irb.class_eval do
35
+ alias :output_value :non_hirb_render_output
36
+ end
37
+ end
38
+
39
+ # This is the main method of this class. This method searches for the first formatter it can apply
40
+ # to the object in this order: local block, method option, class option. If a formatter is found it applies it to the object
41
+ # and returns true. Returns false if no formatter found.
42
+ # ==== Options:
43
+ # [:method] Specifies a global (Kernel) method to do the formatting.
44
+ # [:class] Specifies a class to do the formatting, using its render() class method. The render() method's arguments are the output and
45
+ # an options hash.
46
+ # [:output_method] Specifies a method to call on output before passing it to a formatter.
47
+ # [:options] Options to pass the formatter method or class.
48
+ def render_output(output, options={}, &block)
49
+ if block && block.arity > 0
50
+ formatted_output = block.call(output)
51
+ render_method.call(formatted_output)
52
+ true
53
+ elsif (formatted_output = format_output(output, options))
54
+ render_method.call(formatted_output)
55
+ true
56
+ else
57
+ false
58
+ end
59
+ end
60
+
61
+ # A lambda or proc which handles the final formatted object.
62
+ # Although this puts the object by default, it could be set to do other things
63
+ # ie write the formatted object to a file.
64
+ def render_method
65
+ @render_method ||= default_render_method
66
+ end
67
+
68
+ def reset_render_method
69
+ @render_method = default_render_method
70
+ end
71
+
72
+ # Config hash which maps classes to view hashes. View hashes are the same as the options hash of render_output().
73
+ def output_config
74
+ config[:output]
75
+ end
76
+
77
+ def output_config=(value)
78
+ @config[:output] = value
79
+ end
80
+
81
+ # Needs to be called for config changes to take effect. Reloads Hirb::Views classes and registers
82
+ # most recent config changes.
83
+ def reload_config
84
+ current_config = self.config.dup.merge(:output=>output_config)
85
+ load_config(current_config)
86
+ end
87
+
88
+ # A console version of render_output which takes its same options but allows for some shortcuts.
89
+ # Examples:
90
+ # console_render_output output, :tree, :type=>:directory
91
+ # # is the same as:
92
+ # render_output output, :class=>"Hirb::Helpers::Tree", :options=> {:type=>:directory}
93
+ #
94
+ def console_render_output(*args, &block)
95
+ load_config unless @config
96
+ output = args.shift
97
+ if args[0].is_a?(Symbol) && (view = args.shift)
98
+ symbol_options = find_view(view)
99
+ end
100
+ options = args[-1].is_a?(Hash) ? args[-1] : {}
101
+ options.merge!(symbol_options) if symbol_options
102
+ # iterates over format_output options that aren't :options
103
+ real_options = [:method, :class, :output_method].inject({}) do |h, e|
104
+ h[e] = options.delete(e) if options[e]; h
105
+ end
106
+ render_output(output, real_options.merge(:options=>options), &block)
107
+ end
108
+
109
+ #:stopdoc:
110
+ def find_view(name)
111
+ name = name.to_s
112
+ if (view_method = output_config.values.find {|e| e[:method] == name })
113
+ {:method=>view_method[:method]}
114
+ elsif (view_class = Hirb::Helpers.constants.find {|e| e == Util.camelize(name)})
115
+ {:class=>"Hirb::Helpers::#{view_class}"}
116
+ else
117
+ {}
118
+ end
119
+ end
120
+
121
+ def format_output(output, options={})
122
+ output_class = determine_output_class(output)
123
+ options = Util.recursive_hash_merge(output_class_options(output_class), options)
124
+ output = options[:output_method] ? (output.is_a?(Array) ? output.map {|e| e.send(options[:output_method])} :
125
+ output.send(options[:output_method]) ) : output
126
+ args = [output]
127
+ args << options[:options] if options[:options] && !options[:options].empty?
128
+ if options[:method]
129
+ new_output = send(options[:method],*args)
130
+ elsif options[:class] && (view_class = Util.any_const_get(options[:class]))
131
+ new_output = view_class.render(*args)
132
+ end
133
+ new_output
134
+ end
135
+
136
+ def determine_output_class(output)
137
+ if output.is_a?(Array)
138
+ output[0].class
139
+ else
140
+ output.class
141
+ end
142
+ end
143
+
144
+ def load_config(additional_config={})
145
+ self.config = Util.recursive_hash_merge default_config, additional_config
146
+ true
147
+ end
148
+
149
+ # Stores all view config. Current valid keys:
150
+ # :output- contains value of output_config
151
+ def config=(value)
152
+ reset_cached_output_config
153
+ @config = value
154
+ end
155
+
156
+ def reset_cached_output_config
157
+ @cached_output_config = nil
158
+ end
159
+
160
+ # Internal view options built from user-defined ones. Options are built by recursively merging options from oldest
161
+ # ancestors to the most recent ones.
162
+ def output_class_options(output_class)
163
+ @cached_output_config ||= {}
164
+ @cached_output_config[output_class] ||=
165
+ begin
166
+ output_ancestors_with_config = output_class.ancestors.map {|e| e.to_s}.select {|e| output_config.has_key?(e)}
167
+ @cached_output_config[output_class] = output_ancestors_with_config.reverse.inject({}) {|h, klass|
168
+ (klass == output_class.to_s || output_config[klass][:ancestor]) ? h.update(output_config[klass]) : h
169
+ }
170
+ end
171
+ @cached_output_config[output_class]
172
+ end
173
+
174
+ def cached_output_config; @cached_output_config; end
175
+
176
+ def default_render_method
177
+ lambda {|output| puts output}
178
+ end
179
+
180
+ def default_config
181
+ Hirb::Util.recursive_hash_merge({:output=>default_output_config}, Hirb.config[:view] || {} )
182
+ end
183
+
184
+ def default_output_config
185
+ Hirb::Views.constants.inject({}) {|h,e|
186
+ output_class = e.to_s.gsub("_", "::")
187
+ if (views_class = Hirb::Views.const_get(e)) && views_class.respond_to?(:render)
188
+ default_options = views_class.respond_to?(:default_options) ? views_class.default_options : {}
189
+ h[output_class] = default_options.merge({:class=>"Hirb::Views::#{e}"})
190
+ end
191
+ h
192
+ }
193
+ end
194
+ #:startdoc:
195
+ end
196
+ end
197
+
198
+ # Namespace for autoloaded views
199
+ module Views
200
+ end
201
+ end