hirb 0.2.10 → 0.3.0

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.
@@ -1,7 +1,17 @@
1
1
  module Hirb
2
2
  module Helpers #:nodoc:
3
+ @helper_classes ||= {}
4
+ def self.helper_class(klass)
5
+ @helper_classes[klass.to_s] ||= begin
6
+ if (helper_class = constants.find {|e| e.to_s == Util.camelize(klass.to_s)})
7
+ klass = "Hirb::Helpers::#{helper_class}"
8
+ end
9
+ Util.any_const_get(klass)
10
+ end
11
+ end
3
12
  end
4
13
  end
5
- %w{table object_table active_record_table auto_table tree parent_child_tree vertical_table}.each do |e|
14
+
15
+ %w{table object_table auto_table tree parent_child_tree vertical_table}.each do |e|
6
16
  require "hirb/helpers/#{e}"
7
17
  end
@@ -1,16 +1,24 @@
1
- # Detects the table class the output should use and delegates rendering to it.
2
- class Hirb::Helpers::AutoTable
3
- # Same options as Hirb::Helpers::Table.render.
1
+ # This helper wraps around the other table helpers i.e. Hirb::Helpers::Table while
2
+ # providing default helper options via Hirb::DynamicView. Using these default options, this
3
+ # helper supports views for the following modules/classes:
4
+ # ActiveRecord::Base, CouchFoo::Base, CouchPotato::Persistence, CouchRest::ExtendedDocument,
5
+ # DBI::Row, DataMapper::Resource, Friendly::Document, MongoMapper::Document, MongoMapper::EmbeddedDocument,
6
+ # Mongoid::Document, Ripple::Document, Sequel::Model.
7
+ class Hirb::Helpers::AutoTable < Hirb::Helpers::Table
8
+ extend Hirb::DynamicView
9
+
10
+ # Takes same options as Hirb::Helpers::Table.render except as noted below.
11
+ #
12
+ # ==== Options:
13
+ # [:table_class] Explicit table class to use for rendering. Defaults to
14
+ # Hirb::Helpers::ObjectTable if output is not an Array or Hash. Otherwise
15
+ # defaults to Hirb::Helpers::Table.
4
16
  def self.render(output, options={})
5
- options[:_original_class] = output.class
6
17
  output = Array(output)
7
- klass = if (output[0].is_a?(ActiveRecord::Base) rescue false)
8
- Hirb::Helpers::ActiveRecordTable
9
- elsif !(output[0].is_a?(Hash) || output[0].is_a?(Array))
10
- Hirb::Helpers::ObjectTable
11
- else
12
- Hirb::Helpers::Table
13
- end
18
+ (defaults = dynamic_options(output[0])) && (options = defaults.merge(options))
19
+ klass = options.delete(:table_class) || (
20
+ !(output[0].is_a?(Hash) || output[0].is_a?(Array)) ?
21
+ Hirb::Helpers::ObjectTable : Hirb::Helpers::Table)
14
22
  klass.render(output, options)
15
23
  end
16
- end
24
+ end
@@ -1,8 +1,8 @@
1
1
  class Hirb::Helpers::ObjectTable < Hirb::Helpers::Table
2
2
  # Rows are any ruby objects. Takes same options as Hirb::Helpers::Table.render except as noted below.
3
3
  #
4
- # Options:
5
- # :fields- Methods of the object to represent as columns. Defaults to [:to_s].
4
+ # ==== Options:
5
+ # [:fields] Methods of the object to represent as columns. Defaults to [:to_s].
6
6
  def self.render(rows, options ={})
7
7
  options[:fields] ||= [:to_s]
8
8
  options[:headers] ||= {:to_s=>'value'} if options[:fields] == [:to_s]
@@ -68,7 +68,7 @@ module Hirb
68
68
  # ==== Options:
69
69
  # [*:fields*] An array which overrides the default fields and can be used to indicate field order.
70
70
  # [*:headers*] A hash of fields and their header names. Fields that aren't specified here default to their name.
71
- # This option can also be an array but only for array rows.
71
+ # When set to false, headers are hidden. Can also be an array but only for array rows.
72
72
  # [*:max_fields*] A hash of fields and their maximum allowed lengths. Maximum length can also be a percentage of the total width
73
73
  # (decimal less than one). When a field exceeds it's maximum then it's
74
74
  # truncated and has a ... appended to it. Fields that aren't specified have no maximum.
@@ -90,7 +90,6 @@ module Hirb
90
90
  # [*:description*] When set to true, renders row count description at bottom. Default is true.
91
91
  # [*:escape_special_chars*] When set to true, escapes special characters \n,\t,\r so they don't disrupt tables. Default is false for
92
92
  # vertical tables and true for anything else.
93
- # [*:return_rows*] When set to true, returns rows that have been initialized but not rendered. Default is false.
94
93
  # Examples:
95
94
  # Hirb::Helpers::Table.render [[1,2], [2,3]]
96
95
  # Hirb::Helpers::Table.render [[1,2], [2,3]], :max_fields=>{0=>10}, :header_filter=>:capitalize
@@ -100,7 +99,7 @@ module Hirb
100
99
  # Hirb::Helpers::Table.render [{:age=>10, :weight=>100}, {:age=>80, :weight=>500}], :filters=>{:age=>[:to_f]}
101
100
  def render(rows, options={})
102
101
  options[:vertical] ? Helpers::VerticalTable.render(rows, options) :
103
- options[:return_rows] ? new(rows, options).instance_variable_get("@rows") : new(rows, options).render
102
+ new(rows, options).render
104
103
  rescue TooManyFieldsForWidthError
105
104
  $stderr.puts "", "** Error: Too many fields for the current width. Configure your width " +
106
105
  "and/or fields to avoid this error. Defaulting to a vertical table. **"
@@ -121,6 +120,8 @@ module Hirb
121
120
  #:stopdoc:
122
121
  attr_accessor :width, :max_fields, :field_lengths, :fields
123
122
  def initialize(rows, options={})
123
+ raise ArgumentError, "Table must be an array of hashes or array of arrays" unless rows.is_a?(Array) &&
124
+ (rows[0].is_a?(Hash) or rows[0].is_a?(Array) or rows.empty?)
124
125
  @options = {:description=>true, :filters=>{}, :change_fields=>{}, :escape_special_chars=>true,
125
126
  :filter_any=>Helpers::Table.filter_any, :resize=>true}.merge(options)
126
127
  @fields = set_fields(rows)
@@ -134,19 +135,18 @@ module Hirb
134
135
  end
135
136
 
136
137
  def set_fields(rows)
137
- fields = if @options[:fields]
138
- @options[:fields].dup
138
+ @options[:change_fields] = array_to_indices_hash(@options[:change_fields]) if @options[:change_fields].is_a?(Array)
139
+ return @options[:fields].dup if @options[:fields]
140
+
141
+ fields = if rows[0].is_a?(Hash)
142
+ keys = @options[:all_fields] ? rows.map {|e| e.keys}.flatten.uniq : rows[0].keys
143
+ keys.sort {|a,b| a.to_s <=> b.to_s}
139
144
  else
140
- if rows[0].is_a?(Hash)
141
- keys = @options[:all_fields] ? rows.map {|e| e.keys}.flatten.uniq : rows[0].keys
142
- keys.sort {|a,b| a.to_s <=> b.to_s}
143
- else
144
- rows[0].is_a?(Array) ? (0..rows[0].length - 1).to_a : []
145
- end
145
+ rows[0].is_a?(Array) ? (0..rows[0].length - 1).to_a : []
146
146
  end
147
- @options[:change_fields] = array_to_indices_hash(@options[:change_fields]) if @options[:change_fields].is_a?(Array)
147
+
148
148
  @options[:change_fields].each do |oldf, newf|
149
- (index = fields.index(oldf)) ? fields[index] = newf : fields << newf
149
+ (index = fields.index(oldf)) && fields[index] = newf
150
150
  end
151
151
  fields
152
152
  end
@@ -267,7 +267,8 @@ module Hirb
267
267
 
268
268
  # find max length for each field; start with the headers
269
269
  def default_field_lengths
270
- field_lengths = @headers ? @headers.inject({}) {|h,(k,v)| h[k] = String.size(v); h} : {}
270
+ field_lengths = @headers ? @headers.inject({}) {|h,(k,v)| h[k] = String.size(v); h} :
271
+ @fields.inject({}) {|h,e| h[e] = 1; h }
271
272
  @rows.each do |row|
272
273
  @fields.each do |field|
273
274
  len = String.size(row[field])
@@ -43,6 +43,7 @@ class Hirb::Helpers::Tree
43
43
  # [:indent] Number of spaces to indent between levels for basic + number trees. Default is 4.
44
44
  # [:limit] Limits the level or depth of a tree that is displayed. Root node is level 0.
45
45
  # [:description] Displays brief description about tree ie how many nodes it has.
46
+ # [:multi_line_nodes] Handles multi-lined nodes by indenting their newlines. Default is false.
46
47
  # Examples:
47
48
  # Hirb::Helpers::Tree.render([[0, 'root'], [1, 'child']], :type=>:directory)
48
49
  def render(nodes, options={})
@@ -81,28 +82,27 @@ class Hirb::Helpers::Tree
81
82
  @indent = ' ' * (@options[:indent] || 4 )
82
83
  @nodes = @nodes.select {|e| e[:level] <= @options[:limit] } if @options[:limit]
83
84
  case @type.to_s
84
- when 'directory'
85
- render_directory
86
- when 'number'
87
- render_number
88
- else
89
- render_basic
85
+ when 'directory' then render_directory
86
+ when 'number' then render_number
87
+ else render_basic
90
88
  end
91
89
  end
92
90
 
91
+ def render_nodes
92
+ value_indent = @options[:multi_line_nodes] ? @indent : nil
93
+ @nodes.map {|e| yield(e) + e.value(value_indent) }.join("\n")
94
+ end
95
+
93
96
  def render_directory
94
97
  mark_last_nodes_per_level
95
- new_nodes = []
96
- @nodes.each_with_index {|e, i|
98
+ render_nodes {|e|
97
99
  value = ''
98
100
  unless e.root?
99
101
  value << e.render_parent_characters
100
102
  value << (e[:last_node] ? "`-- " : "|-- ")
101
103
  end
102
- value << e[:value]
103
- new_nodes << value
104
+ value
104
105
  }
105
- new_nodes.join("\n")
106
106
  end
107
107
 
108
108
  def render_number
@@ -113,13 +113,13 @@ class Hirb::Helpers::Tree
113
113
  counter[parent_level_key] += 1
114
114
  e[:pre_value] = "#{counter[parent_level_key]}. "
115
115
  }
116
- @nodes.map {|e| @indent * e[:level] + e[:pre_value] + e[:value]}.join("\n")
116
+ render_nodes {|e| @indent * e[:level] + e[:pre_value] }
117
117
  end
118
-
118
+
119
119
  def render_basic
120
- @nodes.map {|e| @indent * e[:level] + e[:value]}.join("\n")
120
+ render_nodes {|e| @indent * e[:level] }
121
121
  end
122
-
122
+
123
123
  def validate_nodes
124
124
  @nodes.each do |e|
125
125
  raise ParentlessNodeError if (e[:level] > e.previous[:level]) && (e[:level] - e.previous[:level]) > 1
@@ -146,6 +146,10 @@ class Hirb::Helpers::Tree
146
146
  replace(hash)
147
147
  end
148
148
 
149
+ def value(indent=nil)
150
+ indent ? self[:value].gsub("\n", "\n#{indent * self[:level]}") : self[:value]
151
+ end
152
+
149
153
  def parent
150
154
  self[:tree].nodes.slice(0 .. self[:index]).reverse.detect {|e| e[:level] < self[:level]}
151
155
  end
@@ -2,7 +2,7 @@ module Hirb
2
2
  module ObjectMethods
3
3
  # Takes same options as Hirb::View.render_output.
4
4
  def view(*args)
5
- Hirb::View.console_render_output(*(args.unshift(self)))
5
+ Hirb::Console.render_output(*(args.unshift(self)))
6
6
  end
7
7
  end
8
8
  end
@@ -197,7 +197,7 @@ module Hirb
197
197
  end
198
198
 
199
199
  def table_helper_class?
200
- @options[:helper_class].is_a?(Class) && (@options[:helper_class] < Helpers::Table || @options[:helper_class] == Helpers::AutoTable)
200
+ @options[:helper_class].is_a?(Class) && @options[:helper_class] < Helpers::Table
201
201
  end
202
202
 
203
203
  def unalias_field(field)
@@ -16,7 +16,7 @@ module Hirb
16
16
  nil
17
17
  end
18
18
  end
19
-
19
+
20
20
  # Recursively merge hash1 with hash2.
21
21
  def recursive_hash_merge(hash1, hash2)
22
22
  hash1.merge(hash2) {|k,o,n| (o.is_a?(Hash)) ? recursive_hash_merge(o,n) : n}
@@ -0,0 +1,3 @@
1
+ module Hirb
2
+ VERSION = '0.3.0'
3
+ end
@@ -1,6 +1,64 @@
1
1
  module Hirb
2
- # This class is responsible for managing all view-related functionality. Its functionality is determined by setting up a configuration file
3
- # as explained in Hirb and/or passed configuration directly to Hirb.enable. Most of the functionality in this class is dormant until enabled.
2
+ # This class is responsible for managing all view-related functionality.
3
+ #
4
+ # == Create a View
5
+ # Let's create a simple view for Hash objects:
6
+ # $ irb -rubygems
7
+ # >> require 'hirb'
8
+ # =>true
9
+ # >> Hirb.enable
10
+ # =>nil
11
+ # >> require 'yaml'
12
+ # =>true
13
+ #
14
+ # # A view method is the smallest view
15
+ # >> def yaml(output); output.to_yaml; end
16
+ # => nil
17
+ # # Add the view
18
+ # >> Hirb.add_view Hash, :method=>:yaml
19
+ # => true
20
+ #
21
+ # # Hashes now appear as yaml
22
+ # >> {:a=>1, :b=>{:c=>3}}
23
+ # ---
24
+ # :a : 1
25
+ # :b :
26
+ # :c : 3
27
+ # => true
28
+ #
29
+ # Another way of creating a view is a Helper class:
30
+ #
31
+ # # Create yaml view class
32
+ # >> class Hirb::Helpers::Yaml; def self.render(output, options={}); output.to_yaml; end ;end
33
+ # =>nil
34
+ # # Add the view
35
+ # >> Hirb.add_view Hash, :class=>Hirb::Helpers::Yaml
36
+ # =>true
37
+ #
38
+ # # Hashes appear as yaml like above ...
39
+ #
40
+ # == Configure a View
41
+ # To configure the above Helper class as a view, either pass Hirb.enable a hash:
42
+ # # In .irbrc
43
+ # require 'hirb'
44
+ # # View class needs to come before enable()
45
+ # class Hirb::Helpers::Yaml; def self.render(output, options={}); output.to_yaml; end ;end
46
+ # Hirb.enable :output=>{"Hash"=>{:class=>"Hirb::Helpers::Yaml"}}
47
+ #
48
+ # Or create a config file at config/hirb.yml or ~/.hirb.yml:
49
+ # # The config file for the yaml example would look like:
50
+ # # ---
51
+ # # :output :
52
+ # # Hash :
53
+ # # :class : Hirb::Helpers::Yaml
54
+ #
55
+ # # In .irbrc
56
+ # require 'hirb'
57
+ # # View class needs to come before enable()
58
+ # class Hirb::Helpers::Yaml; def self.render(output, options={}); output.to_yaml; end ;end
59
+ # Hirb.enable
60
+ #
61
+ # For more about configuring Hirb, see the Config Files section in Hirb.
4
62
  module View
5
63
  DEFAULT_WIDTH = 120
6
64
  DEFAULT_HEIGHT = 40
@@ -10,26 +68,23 @@ module Hirb
10
68
 
11
69
  # This activates view functionality i.e. the formatter, pager and size detection. If irb exists, it overrides irb's output
12
70
  # method with Hirb::View.view_output. When called multiple times, new configs are merged into the existing config.
13
- # If using Wirble, you should call this after it. The view configuration
14
- # can be specified in a hash via a config file, as options to this method, as this method's block or any combination of these three.
15
- # In addition to the config keys mentioned in Hirb, the options also take the following keys:
71
+ # If using Wirble, you should call this after it. The view configuration can be specified in a hash via a config file,
72
+ # or as options to this method. In addition to the config keys mentioned in Hirb, options also take the following keys:
16
73
  # ==== Options:
17
74
  # * config_file: Name of config file(s) that are merged into existing config
18
75
  # * output_method: Specify an object's class and instance method (separated by a period) to be realiased with
19
76
  # hirb's view system. The instance method should take a string to be output. Default is IRB::Irb.output_value
20
77
  # if using irb.
21
78
  # Examples:
22
- # Hirb::View.enable
23
- # Hirb::View.enable :formatter=>false, :output_method=>"Mini.output"
24
- # Hirb::View.enable {|c| c.output = {'String'=>{:class=>'Hirb::Helpers::Table'}} }
79
+ # Hirb.enable
80
+ # Hirb.enable :formatter=>false, :output_method=>"Mini.output"
25
81
  def enable(options={}, &block)
26
82
  Array(options.delete(:config_file)).each {|e|
27
83
  @new_config_file = true
28
84
  Hirb.config_files << e
29
85
  }
30
86
  enable_output_method(options.delete(:output_method))
31
- puts "Using a block with View.enable will be *deprecated* in the next release" if block_given?
32
- merge_or_load_config(Util.recursive_hash_merge(options, HashStruct.block_to_hash(block)))
87
+ merge_or_load_config options
33
88
  resize(config[:width], config[:height])
34
89
  @enabled = true
35
90
  end
@@ -102,14 +157,18 @@ module Hirb
102
157
  config ? config[:height] : DEFAULT_HEIGHT
103
158
  end
104
159
 
105
- # Current formatter config
160
+ # Current formatter config, storing a hash of all static views
106
161
  def formatter_config
107
162
  formatter.config
108
163
  end
109
164
 
110
- # Sets the helper config for the given output class.
111
- def format_class(klass, helper_config)
112
- formatter.format_class(klass, helper_config)
165
+ # Adds a view when View is enabled. See Formatter.add_view for more details.
166
+ def add(klass, view_config)
167
+ if enabled?
168
+ formatter.add_view(klass, view_config)
169
+ else
170
+ puts "View must be enabled to add a view"
171
+ end
113
172
  end
114
173
 
115
174
  #:stopdoc:
@@ -217,8 +276,4 @@ module Hirb
217
276
  #:startdoc:
218
277
  end
219
278
  end
220
-
221
- # Namespace for autoloaded views
222
- module Views
223
- end
224
- end
279
+ end
@@ -0,0 +1,8 @@
1
+ module Hirb
2
+ # Namespace for Helpers defining multiple views in a module i.e. via DynamicView.
3
+ module Views
4
+ module Single #:nodoc:
5
+ end
6
+ end
7
+ end
8
+ %w{rails orm mongo_db couch_db misc_db}.each {|e| require "hirb/views/#{e}" }
@@ -0,0 +1,11 @@
1
+ module Hirb::Views::CouchDb #:nodoc:
2
+ def default_couch(obj)
3
+ {:fields=>([:_id] + obj.class.properties.map {|e| e.name }) }
4
+ end
5
+
6
+ alias_method :couch_rest__extended_document_view, :default_couch
7
+ alias_method :couch_foo__base_view, :default_couch
8
+ alias_method :couch_potato__persistence_view, :default_couch
9
+ end
10
+
11
+ Hirb::DynamicView.add Hirb::Views::CouchDb, :helper=>:auto_table
@@ -0,0 +1,15 @@
1
+ module Hirb::Views::MiscDb #:nodoc:
2
+ def friendly__document_view(obj)
3
+ {:fields=>obj.class.attributes.keys - [:id]}
4
+ end
5
+
6
+ def ripple__document_view(obj)
7
+ {:fields=>obj.class.properties.keys}
8
+ end
9
+
10
+ def d_b_i__row_view(obj)
11
+ {:fields=>obj.column_names, :table_class=>Hirb::Helpers::Table}
12
+ end
13
+ end
14
+
15
+ Hirb::DynamicView.add Hirb::Views::MiscDb, :helper=>:auto_table
@@ -0,0 +1,15 @@
1
+ module Hirb::Views::MongoDb #:nodoc:
2
+ def mongoid__document_view(obj)
3
+ {:fields=>['_id'] + obj.class.fields.keys}
4
+ end
5
+
6
+ def mongo_mapper__document_view(obj)
7
+ {:fields=>obj.class.column_names}
8
+ end
9
+
10
+ def mongo_mapper__embedded_document_view(obj)
11
+ {:fields=>obj.class.column_names}
12
+ end
13
+ end
14
+
15
+ Hirb::DynamicView.add Hirb::Views::MongoDb, :helper=>:auto_table
@@ -0,0 +1,11 @@
1
+ module Hirb::Views::ORM #:nodoc:
2
+ def data_mapper__resource_view(obj)
3
+ {:fields=>obj.class.properties.map {|e| e.name }}
4
+ end
5
+
6
+ def sequel__model_view(obj)
7
+ {:fields=>obj.class.columns}
8
+ end
9
+ end
10
+
11
+ Hirb::DynamicView.add Hirb::Views::ORM, :helper=>:auto_table