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