cldwalker-hirb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ The MIT LICENSE
2
+
3
+ Copyright (c) 2009 Gabriel Horner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,216 @@
1
+ == Description
2
+
3
+ Hirb currently provides a mini view framework for console applications, designed with irb in mind.
4
+ This framework is activated by one method, which given the output of a console application, renders
5
+ a configured view based on the output's class. The framework encourages reusing views by letting you
6
+ package them in classes and associate them with any number of output classes. Hirb comes with table
7
+ views (see Hirb::Helpers::Table) which work out of the box with any output class, especially Rails'
8
+ model classes.
9
+
10
+ == Install
11
+
12
+ Install the gem with:
13
+
14
+ sudo gem install cldwalker-hirb -s http://gems.github.com
15
+
16
+ == Rails Example
17
+
18
+ Let's load and enable the view framework:
19
+ bash> script/console
20
+ Loading local environment (Rails 2.2.2)
21
+ irb>> require 'hirb'
22
+ => true
23
+ irb>> Hirb::View.enable
24
+ => nil
25
+
26
+ The default configuration provides table views for ActiveRecord::Base descendants.
27
+ If a class isn't configured, Hirb reverts to irb's default echo mode.
28
+ irb>> Hirb::View.output_config
29
+ => {"ActiveRecord::Base"=>{:class=>"Hirb::Views::ActiveRecord_Base", :ancestor=>true}}
30
+
31
+ # Tag is a model class and descendant of ActiveRecord::Base
32
+ irb>> Tag.last
33
+ +-----+-------------------------+-------------+---------------+-----------+-----------+-------+
34
+ | id | created_at | description | name | namespace | predicate | value |
35
+ +-----+-------------------------+-------------+---------------+-----------+-----------+-------+
36
+ | 907 | 2009-03-06 21:10:41 UTC | | gem:tags=yaml | gem | tags | yaml |
37
+ +-----+-------------------------+-------------+---------------+-----------+-----------+-------+
38
+ 1 row in set
39
+
40
+ irb>> 'plain ol irb'
41
+ => 'plain ol irb'
42
+ irb>> :blah
43
+ => :blah
44
+
45
+ From above you can see there were no views configured for a String or a Symbol so Hirb defaulted to
46
+ irb's echo mode. Also note that Tag was able to inherit its view from the ActiveRecord::Base config
47
+ because it had an :ancestor option.
48
+
49
+ Now that you understand that Hirb displays views based on an output object's class,
50
+ you may appreciate it also detects configured output objects in an array:
51
+
52
+ irb>> Tag.all :limit=>3, :order=>"id DESC"
53
+ +-----+-------------------------+-------------+-------------------+-----------+-----------+----------+
54
+ | id | created_at | description | name | namespace | predicate | value |
55
+ +-----+-------------------------+-------------+-------------------+-----------+-----------+----------+
56
+ | 907 | 2009-03-06 21:10:41 UTC | | gem:tags=yaml | gem | tags | yaml |
57
+ | 906 | 2009-03-06 08:47:04 UTC | | gem:tags=nomonkey | gem | tags | nomonkey |
58
+ | 905 | 2009-03-04 00:30:10 UTC | | article:tags=ruby | article | tags | ruby |
59
+ +-----+-------------------------+-------------+-------------------+-----------+-----------+----------+
60
+ 3 rows in set
61
+
62
+ At any time you can disable Hirb if you really like irb's lovely echo mode:
63
+ irb>> Hirb::View.disable
64
+ => nil
65
+ irb>> Tag.all :limit=>3, :order=>"id DESC"
66
+ => [#<Tag id: 907, name: "gem:tags=yaml", description: nil, created_at: "2009-03-06 21:10:41",
67
+ namespace: "gem", predicate: "tags", value: "yaml">, #<Tag id: 906, name: "gem:tags=nomonkey",
68
+ description: nil, created_at: "2009-03-06 08:47:04", namespace: "gem", predicate: "tags", value:
69
+ "nomonkey">, #<Tag id: 905, name: "article:tags=ruby", description: nil, created_at: "2009-03-04
70
+ 00:30:10", namespace: "article", predicate: "tags", value: "ruby">]
71
+
72
+ == Views: Anytime, Anywhere
73
+ While preconfigured tables are great for database records, sometimes you just want to create
74
+ tables/views for any output object:
75
+
76
+ #These examples don't need to have Hirb::View enabled.
77
+ irb>>Hirb::View.disable
78
+ =>nil
79
+
80
+ # Imports table() and view()
81
+ irb>>extend Hirb::Console
82
+ =>main
83
+
84
+ # Create a table of Dates comparing them with different formats.
85
+ irb>> table [Date.today, Date.today.next_month], :fields=>[:to_s, :ld, :ajd, :amjd, :asctime]
86
+ +------------+--------+-----------+-------+--------------------------+
87
+ | to_s | ld | ajd | amjd | asctime |
88
+ +------------+--------+-----------+-------+--------------------------+
89
+ | 2009-03-11 | 155742 | 4909803/2 | 54901 | Wed Mar 11 00:00:00 2009 |
90
+ | 2009-04-11 | 155773 | 4909865/2 | 54932 | Sat Apr 11 00:00:00 2009 |
91
+ +------------+--------+-----------+-------+--------------------------+
92
+ 2 rows in set
93
+
94
+ # Same table as the previous method. However view() will be able to call any view created.
95
+ irb>> view [Date.today, Date.today.next_month], :class=>Hirb::Helpers::ObjectTable,
96
+ :fields=>[:to_s, :ld, :ajd, :amjd, :asctime]
97
+
98
+ If these console methods weren't convenient enough, try:
99
+
100
+ # Imports view() to all objects.
101
+ irb>> require 'hirb/import_object'
102
+ =>true
103
+ # Yields same table as above examples.
104
+ irb>> [Date.today, Date.today.next_month].view :class=>Hirb::Helpers::ObjectTable,
105
+ :fields=>[:to_s, :ld, :ajd, :amjd, :asctime]
106
+
107
+ Although views by default are printed to STDOUT, they can be easily modified to write anywhere:
108
+ # Setup views to write to file 'console.log'.
109
+ irb>> Hirb::View.render_method = lambda {|output| File.open("console.log", 'w') {|f| f.write(output) } }
110
+
111
+ # Writes to file with same table output as above example.
112
+ irb>> view [Date.today, Date.today.next_month], :class=>Hirb::Helpers::ObjectTable,
113
+ :fields=>[:to_s, :ld, :ajd, :amjd, :asctime]
114
+
115
+ # Doesn't write to file because Symbol isn't configured to use Hirb::View and thus defaults to irb's echo mode.
116
+ irb>> :blah
117
+ =>:blah
118
+
119
+ # Go back to printing Hirb views to STDOUT.
120
+ irb>> Hirb::View.reset_render_method
121
+
122
+ == Create and Configure Views
123
+ Let's create a simple view and configure it in different ways to be Hash's default view:
124
+
125
+ === Setup
126
+ irb>> require 'hirb'
127
+ =>true
128
+ irb>> Hirb::View.enable
129
+ =>nil
130
+ irb>> require 'yaml'
131
+ =>true
132
+
133
+ === Configure As View Method
134
+ A view method is the smallest reuseable view.
135
+ # Create yaml view method
136
+ irb>> def yaml(output); output.to_yaml; end
137
+ =>nil
138
+
139
+ # Configure view and reload it
140
+ irb>>Hirb::View.output_config = {"Hash"=>{:method=>:yaml}}
141
+ =>{"Hash"=>{:method=>:yaml}}
142
+ irb>>Hash::View.reload_config
143
+ =>true
144
+
145
+ # Hashes now appear as yaml
146
+ irb>>{:a=>1, :b=>{:c=>3}}
147
+ ---
148
+ :a : 1
149
+ :b :
150
+ :c : 3
151
+ => true
152
+
153
+ === Configure As View Class
154
+ A view class is suited for more complex views. View classes can be under any namespace
155
+ and are expected to provide a render method. However, if a class is under the Hirb::Views namespace,
156
+ it will be automatically loaded with no configuration. Something to think about when
157
+ sharing views with others.
158
+
159
+ # Create yaml view class
160
+ irb>> class Hirb::Views::Hash; def self.render(output); output.to_yaml; end ;end
161
+ =>nil
162
+ # Just reload since no configuration is necessary
163
+ irb>>Hirb::View.reload_config
164
+
165
+ # Hashes now appear as yaml ...
166
+
167
+ Although the Hirb::Views namespace is great for quick classes that just plug and play, you
168
+ often want view classes that can be reused with multiple outputs. For this case, it's recommended to
169
+ use the Hirb::Helpers namespace.
170
+
171
+ # Create yaml view class
172
+ irb>> class Hirb::Helpers::Yaml; def self.render(output); output.to_yaml; end ;end
173
+ =>nil
174
+
175
+ # Configure view and reload it
176
+ irb>>Hirb::View.output_config = {"Hash"=>{:class=>"Hirb::Helpers::Yaml"}}
177
+ =>{"Hash"=>{:class=>"Hirb::Helpers::Yaml"}}
178
+ irb>>Hirb::View.reload_config
179
+
180
+ # Hashes now appear as yaml ...
181
+
182
+ === Configure At Startup
183
+ Once you know what views are associated with what output classes, you can configure
184
+ them at startup by passing Hirb::View.enable a block:
185
+ # In .irbrc
186
+ require 'hirb'
187
+ # View class needs to come before enable()
188
+ class Hirb::Helpers::Yaml; def self.render(output); output.to_yaml; end ;end
189
+ Hirb::View.enable {|conf| conf.output = {"Hash"=>{:class=>"Hirb::Helpers::Yaml"}} }
190
+
191
+ Or by creating a config file at config/hirb.yml or ~/.hirb.yml:
192
+ # The config file for the yaml example would look like:
193
+ # ---
194
+ # :view :
195
+ # :output :
196
+ # Hash :
197
+ # :class : Hirb::Helpers::Yaml
198
+
199
+ # In .irbrc
200
+ require 'hirb'
201
+ # View class needs to come before enable()
202
+ class Hirb::Helpers::Yaml; def self.render(output); output.to_yaml; end ;end
203
+ Hirb::View.enable
204
+
205
+ == Limitations
206
+ Although Hirb preserves Wirble colorizing irb's default echo mode, it doesn't colorize its own views.
207
+ This is mainly because colorizing caused table classes to render incorrectly. If you can get tables
208
+ and colors to work nicely, please fork. To colorize your Hirb output:
209
+ Hirb::View.render_method = lambda {|output| puts Wirble::Colorize.colorize(output) }
210
+
211
+ == Todo
212
+ * Create tree views.
213
+ * Possibly add non-view irb goodies ie command manager.
214
+ * Configurable max height, which if exceeded activates a pager.
215
+ * Provides helper methods to all view classes.
216
+ * Consider adding a template system as needed.
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ begin
5
+ require 'rcov/rcovtask'
6
+
7
+ Rcov::RcovTask.new do |t|
8
+ t.libs << 'test'
9
+ t.test_files = FileList['test/**/*_test.rb']
10
+ t.rcov_opts = ["-T -x '/Library/Ruby/*'"]
11
+ t.verbose = true
12
+ end
13
+ rescue LoadError
14
+ puts "Rcov not available. Install it for rcov-related tasks with: sudo gem install rcov"
15
+ end
16
+
17
+ begin
18
+ require 'jeweler'
19
+ Jeweler::Tasks.new do |s|
20
+ s.name = "hirb"
21
+ s.description = "A mini view framework for console/irb that's easy to use, even while under its influence."
22
+ s.summary = s.description
23
+ s.email = "gabriel.horner@gmail.com"
24
+ s.homepage = "http://github.com/cldwalker/hirb"
25
+ s.authors = ["Gabriel Horner"]
26
+ s.has_rdoc = true
27
+ s.extra_rdoc_files = ["README.rdoc", "LICENSE.txt"]
28
+ s.files = FileList["Rakefile", "VERSION.yml", "README.rdoc", "LICENSE.txt", "{bin,lib,test}/**/*"]
29
+ end
30
+
31
+ rescue LoadError
32
+ puts "Jeweler not available. Install it for jeweler-related tasks with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
33
+ end
34
+
35
+ Rake::TestTask.new do |t|
36
+ t.libs << 'lib'
37
+ t.pattern = 'test/**/*_test.rb'
38
+ t.verbose = false
39
+ end
40
+
41
+ Rake::RDocTask.new do |rdoc|
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = 'test'
44
+ rdoc.options << '--line-numbers' << '--inline-source'
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
48
+
49
+ task :default => :test
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 0
@@ -0,0 +1,17 @@
1
+ module Hirb
2
+ # This class is meant to be extended to provide methods for use in a console/irb shell.
3
+ # For example:
4
+ # irb>> extend Hirb::Console
5
+ # irb>> view 'some string', :class=>Some::String::Formatter
6
+ # irb>> table [[:row1], [:row2]]
7
+ module Console
8
+ # Renders a table for the given object. Takes same options as Hirb::Helpers::Table.render.
9
+ def table(output, options={})
10
+ Hirb::View.console_render_output(output, options.merge(:class=>"Hirb::Helpers::AutoTable"))
11
+ end
12
+ # Renders any specified view for the given object. Takes same options as Hirb::View.render_output.
13
+ def view(*args)
14
+ Hirb::View.console_render_output(*args)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require 'ostruct'
2
+
3
+ class Hirb::HashStruct < OpenStruct #:nodoc:
4
+ def self.block_to_hash(block=nil)
5
+ config = self.new
6
+ if block
7
+ block.call(config)
8
+ config.to_hash
9
+ else
10
+ {}
11
+ end
12
+ end
13
+
14
+ def to_hash
15
+ @table
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ class Hirb::Helpers::ActiveRecordTable < Hirb::Helpers::ObjectTable
2
+ # Rows are Rails' ActiveRecord::Base objects.
3
+ # Takes same options as Hirb::Helpers::Table.render except as noted below.
4
+ #
5
+ # Options:
6
+ # :fields- Can be any attribute, column or not. If not given, this defaults to the database table's columns.
7
+ def self.render(rows, options={})
8
+ rows = [rows] unless rows.is_a?(Array)
9
+ options[:fields] ||=
10
+ begin
11
+ fields = rows.first.attribute_names
12
+ fields.unshift(fields.delete('id')) if fields.include?('id')
13
+ fields
14
+ end
15
+ super(rows, options)
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ # Attempts to autodetect the table class the output represents and delegates rendering to it.
2
+ class Hirb::Helpers::AutoTable
3
+ # Same options as Hirb::Helpers::Table.render.
4
+ def self.render(output, options={})
5
+ klass = if ((output.is_a?(Array) && output[0].is_a?(ActiveRecord::Base)) or output.is_a?(ActiveRecord::Base) rescue false)
6
+ Hirb::Helpers::ActiveRecordTable
7
+ elsif options[:fields]
8
+ Hirb::Helpers::ObjectTable
9
+ else
10
+ Hirb::Helpers::Table
11
+ end
12
+ klass.render(output, options)
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ class Hirb::Helpers::ObjectTable < Hirb::Helpers::Table
2
+ # Rows are any ruby objects. Takes same options as Hirb::Helpers::Table.render except as noted below.
3
+ #
4
+ # Options:
5
+ # :fields- Methods of the object which are represented as columns in the table. Required option.
6
+ # All method values are converted to strings via to_s.
7
+ def self.render(rows, options ={})
8
+ raise(ArgumentError, "Option 'fields' is required.") unless options[:fields]
9
+ rows = [rows] unless rows.is_a?(Array)
10
+ item_hashes = rows.inject([]) {|t,item|
11
+ t << options[:fields].inject({}) {|h,f| h[f] = item.send(f).to_s; h}
12
+ }
13
+ super(item_hashes, options)
14
+ end
15
+ end
@@ -0,0 +1,169 @@
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 << self
30
+ attr_accessor :max_width
31
+
32
+ # Main method which returns a formatted table.
33
+ # ==== Options:
34
+ # [:fields] An array which overrides the default fields and can be used to indicate field order.
35
+ # [:headers] A hash of fields and their header names. Fields that aren't specified here default to their name.
36
+ # This option can also be an array but only for array rows.
37
+ # [:field_lengths] A hash of fields and their maximum allowed lengths. If a field exceeds it's maximum
38
+ # length than it's truncated and has a ... appended to it. Fields that aren't specified here have no maximum allowed
39
+ # length.
40
+ # [:max_width] The maximum allowed width of all fields put together. This option is enforced except when the field_lengths option is set.
41
+ # Examples:
42
+ # Hirb::Helpers::Table.render [[1,2], [2,3]]
43
+ # Hirb::Helpers::Table.render [[1,2], [2,3]], :field_lengths=>{0=>10}
44
+ # Hirb::Helpers::Table.render [{:age=>10, :weight=>100}, {:age=>80, :weight=>500}]
45
+ # Hirb::Helpers::Table.render [{:age=>10, :weight=>100}, {:age=>80, :weight=>500}], :headers=>{:weight=>"Weight(lbs)"}
46
+ def render(rows, options={})
47
+ new(rows,options).render
48
+ end
49
+ end
50
+
51
+ #:stopdoc:
52
+ def initialize(rows, options={})
53
+ @options = options
54
+ @fields = options[:fields] || ((rows[0].is_a?(Hash)) ? rows[0].keys.sort {|a,b| a.to_s <=> b.to_s} :
55
+ rows[0].is_a?(Array) ? (0..rows[0].length - 1).to_a : [])
56
+ @rows = setup_rows(rows)
57
+ @headers = @fields.inject({}) {|h,e| h[e] = e.to_s; h}
58
+ if options.has_key?(:headers)
59
+ @headers = options[:headers].is_a?(Hash) ? @headers.merge(options[:headers]) :
60
+ (options[:headers].is_a?(Array) ? array_to_indices_hash(options[:headers]) : options[:headers])
61
+ end
62
+ end
63
+
64
+ def setup_rows(rows)
65
+ rows ||= []
66
+ rows = [rows] unless rows.is_a?(Array)
67
+ if rows[0].is_a?(Array)
68
+ rows = rows.inject([]) {|new_rows, row|
69
+ new_rows << array_to_indices_hash(row)
70
+ }
71
+ end
72
+ validate_values(rows)
73
+ rows
74
+ end
75
+
76
+ def render
77
+ body = []
78
+ unless @rows.length == 0
79
+ setup_field_lengths
80
+ body += @headers ? render_header : [render_border]
81
+ body += render_rows
82
+ body << render_border
83
+ end
84
+ body << render_table_description
85
+ body.join("\n")
86
+ end
87
+
88
+ def render_header
89
+ title_row = '| ' + @fields.map {|f|
90
+ format_cell(@headers[f], @field_lengths[f])
91
+ }.join(' | ') + ' |'
92
+ [render_border, title_row, render_border]
93
+ end
94
+
95
+ def render_border
96
+ '+-' + @fields.map {|f| '-' * @field_lengths[f] }.join('-+-') + '-+'
97
+ end
98
+
99
+ def format_cell(value, cell_width)
100
+ text = value.length > cell_width ?
101
+ (
102
+ (cell_width < 3) ? value.slice(0,cell_width) : value.slice(0, cell_width - 3) + '...'
103
+ ) : value
104
+ sprintf("%-#{cell_width}s", text)
105
+ end
106
+
107
+ def render_rows
108
+ @rows.map do |row|
109
+ row = '| ' + @fields.map {|f|
110
+ format_cell(row[f], @field_lengths[f])
111
+ }.join(' | ') + ' |'
112
+ end
113
+ end
114
+
115
+ def render_table_description
116
+ (@rows.length == 0) ? "0 rows in set" :
117
+ "#{@rows.length} #{@rows.length == 1 ? 'row' : 'rows'} in set"
118
+ end
119
+
120
+ def setup_field_lengths
121
+ @field_lengths = default_field_lengths
122
+ if @options[:field_lengths]
123
+ @field_lengths.merge!(@options[:field_lengths])
124
+ else
125
+ max_width = @options[:max_width] || Hirb::Helpers::Table.max_width || DEFAULT_MAX_WIDTH
126
+ restrict_field_lengths(@field_lengths, max_width)
127
+ end
128
+ end
129
+
130
+ # Simple algorithm which given a max width, allows smaller fields to be displayed while
131
+ # restricting longer fields at a new_long_field_length.
132
+ def restrict_field_lengths(field_lengths, max_width)
133
+ total_length = field_lengths.values.inject {|t,n| t += n}
134
+ if total_length > max_width
135
+ average_field_length = total_length / @fields.size.to_f
136
+ long_lengths, short_lengths = field_lengths.values.partition {|e| e > average_field_length}
137
+ new_long_field_length = (max_width - short_lengths.inject {|t,n| t += n}) / long_lengths.size
138
+ field_lengths.each {|f,length|
139
+ field_lengths[f] = new_long_field_length if length > new_long_field_length
140
+ }
141
+ end
142
+ end
143
+
144
+ # find max length for each field; start with the headers
145
+ def default_field_lengths
146
+ field_lengths = @headers ? @headers.inject({}) {|h,(k,v)| h[k] = v.length; h} : {}
147
+ @rows.each do |row|
148
+ @fields.each do |field|
149
+ len = row[field].length
150
+ field_lengths[field] = len if len > field_lengths[field].to_i
151
+ end
152
+ end
153
+ field_lengths
154
+ end
155
+
156
+ def validate_values(rows)
157
+ rows.each {|row|
158
+ @fields.each {|f|
159
+ row[f] = row[f].to_s || ''
160
+ }
161
+ }
162
+ end
163
+
164
+ # Converts an array to a hash mapping a numerical index to its array value.
165
+ def array_to_indices_hash(array)
166
+ array.inject({}) {|hash,e| hash[hash.size] = e; hash }
167
+ end
168
+ #:startdoc:
169
+ end
@@ -0,0 +1,7 @@
1
+ module Hirb
2
+ module Helpers #:nodoc:
3
+ end
4
+ end
5
+ %w{table object_table active_record_table auto_table}.each do |e|
6
+ require "hirb/helpers/#{e}"
7
+ 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
data/lib/hirb/util.rb ADDED
@@ -0,0 +1,19 @@
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
+ end
19
+ end
data/lib/hirb/view.rb ADDED
@@ -0,0 +1,179 @@
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.
45
+ # [:options] Options to pass the formatter method or class.
46
+ def render_output(output, options={}, &block)
47
+ if block && block.arity > 0
48
+ formatted_output = block.call(output)
49
+ render_method.call(formatted_output)
50
+ true
51
+ elsif (formatted_output = format_output(output, options))
52
+ render_method.call(formatted_output)
53
+ true
54
+ else
55
+ false
56
+ end
57
+ end
58
+
59
+ # A lambda or proc which handles the final formatted object.
60
+ # Although this puts the object by default, it could be set to do other things
61
+ # ie write the formatted object to a file.
62
+ def render_method
63
+ @render_method ||= default_render_method
64
+ end
65
+
66
+ def reset_render_method
67
+ @render_method = default_render_method
68
+ end
69
+
70
+ # Config hash which maps classes to view hashes. View hashes are the same as the options hash of render_output().
71
+ def output_config
72
+ @config[:output]
73
+ end
74
+
75
+ def output_config=(value)
76
+ @config[:output] = value
77
+ end
78
+
79
+ # Needs to be called for config changes to take effect. Reloads Hirb::Views classes and registers
80
+ # most recent config changes.
81
+ def reload_config
82
+ current_config = self.config.dup.merge(:output=>output_config)
83
+ load_config(current_config)
84
+ end
85
+
86
+ #:stopdoc:
87
+ def console_render_output(output, options={}, &block)
88
+ # iterates over format_output options that aren't :options
89
+ real_options = [:method, :class].inject({}) do |h, e|
90
+ h[e] = options.delete(e) if options[e]
91
+ h
92
+ end
93
+ render_output(output, real_options.merge(:options=>options), &block)
94
+ end
95
+
96
+ def format_output(output, options={})
97
+ output_class = determine_output_class(output)
98
+ options = output_class_options(output_class).merge(options)
99
+ args = [output]
100
+ args << options[:options] if options[:options] && !options[:options].empty?
101
+ if options[:method]
102
+ new_output = send(options[:method],*args)
103
+ elsif options[:class] && (view_class = Util.any_const_get(options[:class]))
104
+ new_output = view_class.render(*args)
105
+ end
106
+ new_output
107
+ end
108
+
109
+ def determine_output_class(output)
110
+ if output.is_a?(Array)
111
+ output[0].class
112
+ else
113
+ output.class
114
+ end
115
+ end
116
+
117
+ # Loads config
118
+ def load_config(additional_config={})
119
+ new_config = default_config
120
+ new_config[:output].merge!(additional_config.delete(:output) || {})
121
+ self.config = new_config.merge(additional_config)
122
+ true
123
+ end
124
+
125
+ # Stores all view config. Current valid keys:
126
+ # :output- contains value of output_config
127
+ def config=(value)
128
+ reset_cached_output_config
129
+ @config = value
130
+ end
131
+
132
+ def reset_cached_output_config
133
+ @cached_output_config = nil
134
+ end
135
+
136
+ # Internal view options built from user-defined ones. Options are built by recursively merging options from oldest
137
+ # ancestors to the most recent ones.
138
+ def output_class_options(output_class)
139
+ @cached_output_config ||= {}
140
+ @cached_output_config[output_class] ||=
141
+ begin
142
+ output_ancestors_with_config = output_class.ancestors.map {|e| e.to_s}.select {|e| output_config.has_key?(e)}
143
+ @cached_output_config[output_class] = output_ancestors_with_config.reverse.inject({}) {|h, klass|
144
+ (klass == output_class.to_s || output_config[klass][:ancestor]) ? h.update(output_config[klass]) : h
145
+ }
146
+ end
147
+ @cached_output_config[output_class]
148
+ end
149
+
150
+ def cached_output_config; @cached_output_config; end
151
+
152
+ def default_render_method
153
+ lambda {|output| puts output}
154
+ end
155
+
156
+ def default_config
157
+ conf = Hirb.config[:view] || {}
158
+ conf[:output] = default_output_config.merge(conf[:output] || {})
159
+ conf
160
+ end
161
+
162
+ def default_output_config
163
+ Hirb::Views.constants.inject({}) {|h,e|
164
+ output_class = e.to_s.gsub("_", "::")
165
+ if (views_class = Hirb::Views.const_get(e)) && views_class.respond_to?(:render)
166
+ default_options = views_class.respond_to?(:default_options) ? views_class.default_options : {}
167
+ h[output_class] = default_options.merge({:class=>"Hirb::Views::#{e}"})
168
+ end
169
+ h
170
+ }
171
+ end
172
+ #:startdoc:
173
+ end
174
+ end
175
+
176
+ # Namespace for autoloaded views
177
+ module Views
178
+ end
179
+ 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
data/lib/hirb.rb ADDED
@@ -0,0 +1,31 @@
1
+ current_dir = File.dirname(__FILE__)
2
+ $:.unshift(current_dir) unless $:.include?(current_dir) || $:.include?(File.expand_path(current_dir))
3
+ require 'hirb/util'
4
+ require 'hirb/hash_struct'
5
+ require 'hirb/helpers'
6
+ require 'hirb/view'
7
+ require 'hirb/views/activerecord_base'
8
+ require 'hirb/console'
9
+
10
+ # Most of Hirb's functionality currently resides in Hirb::View.
11
+ # Hirb has an optional yaml config file defined by config_file. This config file
12
+ # has the following top level keys:
13
+ # [:view] See Hirb::View for the value of this entry.
14
+ module Hirb
15
+ class <<self
16
+ # Default is config/hirb.yml or ~/hirb.yml in that order.
17
+ def config_file
18
+ File.exists?('config/hirb.yml') ? 'config/hirb.yml' : File.expand_path(File.join("~",".hirb.yml"))
19
+ end
20
+
21
+ #:stopdoc:
22
+ def read_config_file(file=config_file)
23
+ File.exists?(file) ? YAML::load_file(file) : {}
24
+ end
25
+
26
+ def config(reload=false)
27
+ @config = (@config.nil? || reload) ? read_config_file : @config
28
+ end
29
+ #:startdoc:
30
+ end
31
+ end
data/test/hirb_test.rb ADDED
@@ -0,0 +1,23 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class HirbTest < Test::Unit::TestCase
4
+ before(:each) {Hirb.instance_eval "@config = nil"}
5
+
6
+ test "config converts yaml when config file exists" do
7
+ yaml_data = {:blah=>'blah'}
8
+ File.stubs('exists?').returns(true)
9
+ YAML::expects(:load_file).returns(yaml_data)
10
+ Hirb.config.should == yaml_data
11
+ end
12
+
13
+ test "config defaults to hash when no config file" do
14
+ File.stubs('exists?').returns(false)
15
+ Hirb.config.should == {}
16
+ end
17
+
18
+ test "config reloads if given explicit reload" do
19
+ Hirb.config
20
+ Hirb.expects(:read_config_file)
21
+ Hirb.config(true)
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class Hirb::ImportTest < Test::Unit::TestCase
4
+ test "require import_object extends Object" do
5
+ Object.ancestors.map {|e| e.to_s}.include?("Hirb::ObjectMethods").should be(false)
6
+ require 'hirb/import_object'
7
+ Object.ancestors.map {|e| e.to_s}.include?("Hirb::ObjectMethods").should be(true)
8
+ end
9
+ end
@@ -0,0 +1,242 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class Hirb::Helpers::TableTest < Test::Unit::TestCase
4
+ def table(*args)
5
+ Hirb::Helpers::Table.render(*args)
6
+ end
7
+
8
+ context "basic table" do
9
+ test "renders" do
10
+ expected_table = <<-TABLE.unindent
11
+ +---+---+
12
+ | a | b |
13
+ +---+---+
14
+ | 1 | 2 |
15
+ | 3 | 4 |
16
+ +---+---+
17
+ 2 rows in set
18
+ TABLE
19
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}]).should == expected_table
20
+ end
21
+
22
+ test "with no headers renders" do
23
+ expected_table = <<-TABLE.unindent
24
+ +---+---+
25
+ | 1 | 2 |
26
+ +---+---+
27
+ 1 row in set
28
+ TABLE
29
+ table([{:a=>1, :b=>2}], :headers=>nil).should == expected_table
30
+ end
31
+
32
+ test "with string keys renders" do
33
+ expected_table = <<-TABLE.unindent
34
+ +---+---+
35
+ | a | b |
36
+ +---+---+
37
+ | 1 | 2 |
38
+ | 3 | 4 |
39
+ +---+---+
40
+ 2 rows in set
41
+ TABLE
42
+ table([{'a'=>1, 'b'=>2}, {'a'=>3, 'b'=>4}]).should == expected_table
43
+ end
44
+
45
+ test "with array only rows renders" do
46
+ expected_table = <<-TABLE.unindent
47
+ +---+---+
48
+ | 0 | 1 |
49
+ +---+---+
50
+ | 1 | 2 |
51
+ | 3 | 4 |
52
+ +---+---+
53
+ 2 rows in set
54
+ TABLE
55
+ table([[1,2], [3,4]]).should == expected_table
56
+ end
57
+
58
+ test "with no rows renders" do
59
+ table([]).should == "0 rows in set"
60
+ end
61
+ end
62
+
63
+ context "table with" do
64
+ test "fields option renders" do
65
+ expected_table = <<-TABLE.unindent
66
+ +---+---+
67
+ | b | a |
68
+ +---+---+
69
+ | 2 | 1 |
70
+ | 4 | 3 |
71
+ +---+---+
72
+ 2 rows in set
73
+ TABLE
74
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], :fields=>[:b, :a]).should == expected_table
75
+ end
76
+
77
+ test "fields option and array only rows" do
78
+ expected_table = <<-TABLE.unindent
79
+ +---+---+
80
+ | 0 | 2 |
81
+ +---+---+
82
+ | 1 | 3 |
83
+ +---+---+
84
+ 1 row in set
85
+ TABLE
86
+ table([[1,2,3]], :fields=>[0,2]).should == expected_table
87
+ end
88
+
89
+ test "invalid fields option renders empty columns" do
90
+ expected_table = <<-TABLE.unindent
91
+ +---+---+
92
+ | b | c |
93
+ +---+---+
94
+ | 2 | |
95
+ | 4 | |
96
+ +---+---+
97
+ 2 rows in set
98
+ TABLE
99
+ table([{:a=>1, :b=>2}, {:a=>3, :b=>4}], :fields=>[:b, :c]).should == expected_table
100
+ end
101
+
102
+ test "invalid fields in field_lengths option renders" do
103
+ expected_table = <<-TABLE.unindent
104
+ +------------+---+
105
+ | a | b |
106
+ +------------+---+
107
+ | AAAAAAA... | 2 |
108
+ +------------+---+
109
+ 1 row in set
110
+ TABLE
111
+ table([{:a=> "A" * 50, :b=>2}], :field_lengths=>{:a=>10,:c=>10}).should == expected_table
112
+ end
113
+
114
+ test "field_lengths option and field_lengths less than 3 characters renders" do
115
+ expected_table = <<-TABLE.unindent
116
+ +----+---+
117
+ | a | b |
118
+ +----+---+
119
+ | AA | 2 |
120
+ +----+---+
121
+ 1 row in set
122
+ TABLE
123
+ table([{:a=> "A" * 50, :b=>2}], :field_lengths=>{:a=>2}).should == expected_table
124
+ end
125
+
126
+ test "field_lengths option renders" do
127
+ expected_table = <<-TABLE.unindent
128
+ +------------+---+
129
+ | a | b |
130
+ +------------+---+
131
+ | AAAAAAA... | 2 |
132
+ +------------+---+
133
+ 1 row in set
134
+ TABLE
135
+ table([{:a=> "A" * 50, :b=>2}], :field_lengths=>{:a=>10}).should == expected_table
136
+ end
137
+
138
+ test "max_width option renders" do
139
+ expected_table = <<-TABLE.unindent
140
+ +---------------------+---+------------+
141
+ | a | b | c |
142
+ +---------------------+---+------------+
143
+ | AAAAAAAAAAAAAAAA... | 2 | CCCCCCCCCC |
144
+ +---------------------+---+------------+
145
+ 1 row in set
146
+ TABLE
147
+ table([{:a=> "A" * 50, :b=>2, :c=>"C"*10}], :max_width=>30).should == expected_table
148
+ end
149
+
150
+ test "global max_width renders" do
151
+ expected_table = <<-TABLE.unindent
152
+ +---------------------+---+------------+
153
+ | a | b | c |
154
+ +---------------------+---+------------+
155
+ | AAAAAAAAAAAAAAAA... | 2 | CCCCCCCCCC |
156
+ +---------------------+---+------------+
157
+ 1 row in set
158
+ TABLE
159
+ Hirb::Helpers::Table.max_width = 30
160
+ table([{:a=> "A" * 50, :b=>2, :c=>"C"*10}]).should == expected_table
161
+ Hirb::Helpers::Table.max_width = Hirb::Helpers::Table::DEFAULT_MAX_WIDTH
162
+ end
163
+
164
+ test "headers option and headers longer than fields renders" do
165
+ expected_table = <<-TABLE.unindent
166
+ +---+---------+---------+
167
+ | a | field B | field C |
168
+ +---+---------+---------+
169
+ | A | 2 | C |
170
+ +---+---------+---------+
171
+ 1 row in set
172
+ TABLE
173
+ table([{:a=> "A", :b=>2, :c=>"C"}], :headers=>{:b=>"field B", :c=>"field C"}).should == expected_table
174
+ end
175
+
176
+ test "headers option and headers shortened by field_lengths renders" do
177
+ expected_table = <<-TABLE.unindent
178
+ +-------+---+
179
+ | fi... | b |
180
+ +-------+---+
181
+ | A | 2 |
182
+ +-------+---+
183
+ 1 row in set
184
+ TABLE
185
+ table([{:a=> "A", :b=>2}], :headers=>{:a=>"field A"}, :field_lengths=>{:a=>5}).should == expected_table
186
+ end
187
+
188
+ test "with headers option as an array renders" do
189
+ expected_table = <<-TABLE.unindent
190
+ +---+---+
191
+ | A | B |
192
+ +---+---+
193
+ | 1 | 2 |
194
+ | 3 | 4 |
195
+ +---+---+
196
+ 2 rows in set
197
+ TABLE
198
+ table([[1,2], [3,4]], :headers=>['A', 'B']).should == expected_table
199
+ end
200
+
201
+ end
202
+
203
+ context "object table" do
204
+ before(:all) {
205
+ @pets = [stub(:name=>'rufus', :age=>7), stub(:name=>'alf', :age=>101)]
206
+ }
207
+ test "renders" do
208
+ expected_table = <<-TABLE.unindent
209
+ +-------+-----+
210
+ | name | age |
211
+ +-------+-----+
212
+ | rufus | 7 |
213
+ | alf | 101 |
214
+ +-------+-----+
215
+ 2 rows in set
216
+ TABLE
217
+ Hirb::Helpers::ObjectTable.render(@pets, :fields=>[:name, :age]).should == expected_table
218
+ end
219
+
220
+ test "with no options fields raises ArgumentError" do
221
+ assert_raises(ArgumentError) { Hirb::Helpers::ObjectTable.render(@pets) }
222
+ end
223
+ end
224
+
225
+ context "activerecord table" do
226
+ before(:all) {
227
+ @pets = [stub(:name=>'rufus', :age=>7, :attribute_names=>['age', 'name']), stub(:name=>'alf', :age=>101)]
228
+ }
229
+ test "renders" do
230
+ expected_table = <<-TABLE.unindent
231
+ +-----+-------+
232
+ | age | name |
233
+ +-----+-------+
234
+ | 7 | rufus |
235
+ | 101 | alf |
236
+ +-----+-------+
237
+ 2 rows in set
238
+ TABLE
239
+ Hirb::Helpers::ActiveRecordTable.render(@pets).should == expected_table
240
+ end
241
+ end
242
+ end
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'context' #gem install jeremymcanally-context -s http://gems.github.com
4
+ require 'matchy' #gem install jeremymcanally-matchy -s http://gems.github.com
5
+ require 'mocha'
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ require 'hirb'
8
+
9
+ class Test::Unit::TestCase
10
+ end
11
+
12
+ class String
13
+ def unindent
14
+ gsub(/^\s*/, '').chomp
15
+ end
16
+ end
data/test/util_test.rb ADDED
@@ -0,0 +1,15 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class Hirb::UtilTest < Test::Unit::TestCase
4
+ test "any_const_get returns nested class" do
5
+ Hirb::Util.any_const_get("Test::Unit").should == ::Test::Unit
6
+ end
7
+
8
+ test "any_const_get returns nil for invalid class" do
9
+ Hirb::Util.any_const_get("Basdfr").should == nil
10
+ end
11
+
12
+ test "any_const_get returns class when given class" do
13
+ Hirb::Util.any_const_get(String).should == String
14
+ end
15
+ end
data/test/view_test.rb ADDED
@@ -0,0 +1,151 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ # mocks IRB for testing
4
+ module ::IRB
5
+ class Irb
6
+ def initialize(context)
7
+ @context = context
8
+ end
9
+ def output_value; end
10
+ end
11
+ end
12
+
13
+ class Hirb::ViewTest < Test::Unit::TestCase
14
+ def set_config(value)
15
+ Hirb::View.output_config = value
16
+ Hirb::View.reset_cached_output_config
17
+ end
18
+
19
+ def output_config
20
+ Hirb::View.config[:output]
21
+ end
22
+
23
+ test "output_class_options merges ancestor options" do
24
+ set_config "String"=>{:args=>[1,2]}, "Object"=>{:method=>:object_output, :ancestor=>true}, "Kernel"=>{:method=>:default_output}
25
+ expected_result = {:method=>:object_output, :args=>[1, 2], :ancestor=>true}
26
+ Hirb::View.output_class_options(String).should == expected_result
27
+ end
28
+
29
+ test "output_class_options doesn't ancestor options" do
30
+ set_config "String"=>{:args=>[1,2]}, "Object"=>{:method=>:object_output}, "Kernel"=>{:method=>:default_output}
31
+ expected_result = {:args=>[1, 2]}
32
+ Hirb::View.output_class_options(String).should == expected_result
33
+ end
34
+
35
+ test "output_class_options returns hash when nothing found" do
36
+ Hirb::View.load_config
37
+ Hirb::View.output_class_options(String).should == {}
38
+ end
39
+
40
+ context "enable" do
41
+ before(:each) {Hirb::View.config = {}}
42
+ after(:each) { Hirb::View.disable }
43
+ test "redefines irb output_value" do
44
+ Hirb::View.expects(:render_output).once
45
+ Hirb::View.enable
46
+ context_stub = stub(:last_value=>'')
47
+ ::IRB::Irb.new(context_stub).output_value
48
+ end
49
+
50
+ test "sets default config" do
51
+ eval "module ::Hirb::Views::Something_Base; def self.render; end; end"
52
+ Hirb::View.enable
53
+ output_config["Something::Base"].should == {:class=>"Hirb::Views::Something_Base"}
54
+ end
55
+
56
+ test "sets default config with default_options" do
57
+ eval "module ::Hirb::Views::Blah; def self.render; end; def self.default_options; {:ancestor=>true}; end; end"
58
+ Hirb::View.enable
59
+ output_config["Blah"].should == {:class=>"Hirb::Views::Blah", :ancestor=>true}
60
+ end
61
+
62
+ test "with block sets config" do
63
+ class_hash = {"Something::Base"=>{:class=>"BlahBlah"}}
64
+ Hirb::View.enable {|c| c.output = class_hash }
65
+ output_config['Something::Base'].should == class_hash['Something::Base']
66
+ end
67
+ end
68
+
69
+ test "reload_config resets config to detect new Hirb::Views" do
70
+ Hirb::View.load_config
71
+ output_config.keys.include?('Zzz').should be(false)
72
+ eval "module ::Hirb::Views::Zzz; def self.render; end; end"
73
+ Hirb::View.reload_config
74
+ output_config.keys.include?('Zzz').should be(true)
75
+ end
76
+
77
+ test "reload_config picks up local changes" do
78
+ Hirb::View.load_config
79
+ output_config.keys.include?('Dooda').should be(false)
80
+ Hirb::View.output_config.merge!('Dooda'=>{:class=>"DoodaView"})
81
+ Hirb::View.reload_config
82
+ output_config['Dooda'].should == {:class=>"DoodaView"}
83
+ end
84
+
85
+ test "disable points output_value back to original output_value" do
86
+ Hirb::View.expects(:render_output).never
87
+ Hirb::View.enable
88
+ Hirb::View.disable
89
+ context_stub = stub(:last_value=>'')
90
+ ::IRB::Irb.new(context_stub).output_value
91
+ end
92
+
93
+ context "render_output" do
94
+ before(:all) {
95
+ eval %[module ::Commify
96
+ def self.render(strings)
97
+ strings = [strings] unless strings.is_a?(Array)
98
+ strings.map {|e| e.split('').join(',')}.join("\n")
99
+ end
100
+ end]
101
+ Hirb::View.enable
102
+ }
103
+ after(:all) { Hirb::View.disable }
104
+
105
+ test "formats with config method option" do
106
+ eval "module ::Kernel; def commify(string); string.split('').join(','); end; end"
107
+ set_config "String"=>{:method=>:commify}
108
+ Hirb::View.render_method.expects(:call).with('d,u,d,e')
109
+ Hirb::View.render_output('dude')
110
+ end
111
+
112
+ test "formats with config class option" do
113
+ set_config "String"=>{:class=>"Commify"}
114
+ Hirb::View.render_method.expects(:call).with('d,u,d,e')
115
+ Hirb::View.render_output('dude')
116
+ end
117
+
118
+ test "formats with output array" do
119
+ set_config "String"=>{:class=>"Commify"}
120
+ Hirb::View.render_method.expects(:call).with('d,u,d,e')
121
+ Hirb::View.render_output(['dude'])
122
+ end
123
+
124
+ test "formats with config options option" do
125
+ eval "module ::Blahify; def self.render(*args); end; end"
126
+ set_config "String"=>{:class=>"Blahify", :options=>{:fields=>%w{a b}}}
127
+ Blahify.expects(:render).with('dude', :fields=>%w{a b})
128
+ Hirb::View.render_output('dude')
129
+ end
130
+
131
+ test "doesn't format and returns false when no format method found" do
132
+ Hirb::View.load_config
133
+ Hirb::View.render_method.expects(:call).never
134
+ Hirb::View.render_output(Date.today).should == false
135
+ end
136
+
137
+ test "formats with explicit class option" do
138
+ set_config 'String'=>{:class=>"Blahify"}
139
+ Hirb::View.render_method.expects(:call).with('d,u,d,e')
140
+ Hirb::View.render_output('dude', :class=>"Commify")
141
+ end
142
+
143
+ test "formats with block" do
144
+ Hirb::View.load_config
145
+ Hirb::View.render_method.expects(:call).with('=dude=')
146
+ Hirb::View.render_output('dude') {|output|
147
+ "=#{output}="
148
+ }
149
+ end
150
+ end
151
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cldwalker-hirb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gabriel Horner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-12 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A mini view framework for irb that's easy to use, even while under its influence.
17
+ email: gabriel.horner@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ - LICENSE.txt
25
+ files:
26
+ - Rakefile
27
+ - VERSION.yml
28
+ - README.rdoc
29
+ - LICENSE.txt
30
+ - lib/hirb
31
+ - lib/hirb/console.rb
32
+ - lib/hirb/hash_struct.rb
33
+ - lib/hirb/helpers
34
+ - lib/hirb/helpers/active_record_table.rb
35
+ - lib/hirb/helpers/auto_table.rb
36
+ - lib/hirb/helpers/object_table.rb
37
+ - lib/hirb/helpers/table.rb
38
+ - lib/hirb/helpers.rb
39
+ - lib/hirb/import_object.rb
40
+ - lib/hirb/util.rb
41
+ - lib/hirb/view.rb
42
+ - lib/hirb/views
43
+ - lib/hirb/views/activerecord_base.rb
44
+ - lib/hirb.rb
45
+ - test/hirb_test.rb
46
+ - test/import_test.rb
47
+ - test/table_test.rb
48
+ - test/test_helper.rb
49
+ - test/util_test.rb
50
+ - test/view_test.rb
51
+ has_rdoc: true
52
+ homepage: http://github.com/cldwalker/hirb
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --inline-source
56
+ - --charset=UTF-8
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.2.0
75
+ signing_key:
76
+ specification_version: 2
77
+ summary: A mini view framework for irb that's easy to use, even while under its influence.
78
+ test_files: []
79
+