hirb 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ == 0.1.2
2
+ * Added tree views.
3
+ * Added output_method option to Hirb::View.render_output.
4
+
5
+ == 0.1.1
6
+ * Fixed bug when rendering table with many fields.
7
+
8
+ == 0.1.0
9
+ * Initial release
@@ -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.
@@ -0,0 +1,231 @@
1
+ == Description
2
+
3
+ Hirb currently provides a mini view framework for console applications, designed with irb in mind.
4
+ Given the output of a console application, it renders a view if there is one configured, based on
5
+ the output's class. The framework encourages reusing views by letting you package them in classes
6
+ and associate them with any number of output classes. Hirb comes with tree views (see
7
+ Hirb::Helpers::Tree) and table views (see Hirb::Helpers::Table). By default Hirb displays Rails'
8
+ model classes as tables.
9
+
10
+ == Install
11
+
12
+ Install the gem with:
13
+
14
+ sudo gem install cldwalker-hirb --source 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, options={}); 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, options={}); 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, options={}); 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, options={}); output.to_yaml; end ;end
203
+ Hirb::View.enable
204
+
205
+ == Contributing Views
206
+ If you have views of your own you'd like to share, fork Hirb and put your views under
207
+ the Hirb::Helpers namespace and the view files under lib/hirb/helpers/.
208
+
209
+ == Limitations
210
+ Although Hirb preserves Wirble colorizing irb's default echo mode, it doesn't colorize its own views.
211
+ This is mainly because colorizing caused table classes to render incorrectly. If you can get tables
212
+ and colors to work nicely, please fork. To colorize your Hirb output:
213
+ Hirb::View.render_method = lambda {|output| puts Wirble::Colorize.colorize(output) }
214
+
215
+ == Motivation
216
+ Table code from http://gist.github.com/72234 and {my console
217
+ app's needs}[http://github.com/cldwalker/tag-tree].
218
+
219
+ == Bugs
220
+ Please report them as tickets here: http://cldwalker.lighthouseapp.com/projects/27735-hirb/tickets
221
+
222
+ == Links
223
+ * http://tagaholic.me/2009/03/13/hirb-irb-on-the-good-stuff.html
224
+ * http://tagaholic.me/2009/03/18/ruby-class-trees-rails-plugin-trees-with-hirb.html
225
+
226
+ == Todo
227
+ * Configurable max height, which if exceeded activates a pager.
228
+ * Possibly add non-view irb goodies ie command manager.
229
+ * Consider applying multiple views/filters to output.
230
+ * Provides helper methods to all view classes.
231
+ * Consider adding a template system as needed.
@@ -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["[A-Z]*", "{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
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 2
@@ -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
@@ -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.console_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,7 @@
1
+ module Hirb
2
+ module Helpers #:nodoc:
3
+ end
4
+ end
5
+ %w{table object_table active_record_table auto_table tree parent_child_tree}.each do |e|
6
+ require "hirb/helpers/#{e}"
7
+ 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.map {|e| e.to_sym }
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