bbcloud 0.6.2 → 0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/bbcloud.gemspec +1 -3
- data/lib/bbcloud/commands/servers-show.rb +1 -1
- data/lib/bbcloud/version.rb +1 -1
- metadata +26 -61
- data/lib/bbcloud/commands/servers-restart.rb +0 -30
- data/lib/bbcloud/vendor/hirb/.gemspec +0 -22
- data/lib/bbcloud/vendor/hirb/CHANGELOG.rdoc +0 -106
- data/lib/bbcloud/vendor/hirb/LICENSE.txt +0 -22
- data/lib/bbcloud/vendor/hirb/README.rdoc +0 -182
- data/lib/bbcloud/vendor/hirb/Rakefile +0 -35
- data/lib/bbcloud/vendor/hirb/lib/bond/completions/hirb.rb +0 -15
- data/lib/bbcloud/vendor/hirb/lib/hirb/console.rb +0 -43
- data/lib/bbcloud/vendor/hirb/lib/hirb/dynamic_view.rb +0 -113
- data/lib/bbcloud/vendor/hirb/lib/hirb/formatter.rb +0 -116
- data/lib/bbcloud/vendor/hirb/lib/hirb/helpers/auto_table.rb +0 -24
- data/lib/bbcloud/vendor/hirb/lib/hirb/helpers/object_table.rb +0 -14
- data/lib/bbcloud/vendor/hirb/lib/hirb/helpers/parent_child_tree.rb +0 -24
- data/lib/bbcloud/vendor/hirb/lib/hirb/helpers/table/filters.rb +0 -10
- data/lib/bbcloud/vendor/hirb/lib/hirb/helpers/table/resizer.rb +0 -82
- data/lib/bbcloud/vendor/hirb/lib/hirb/helpers/table.rb +0 -323
- data/lib/bbcloud/vendor/hirb/lib/hirb/helpers/tree.rb +0 -181
- data/lib/bbcloud/vendor/hirb/lib/hirb/helpers/vertical_table.rb +0 -37
- data/lib/bbcloud/vendor/hirb/lib/hirb/helpers.rb +0 -17
- data/lib/bbcloud/vendor/hirb/lib/hirb/import_object.rb +0 -10
- data/lib/bbcloud/vendor/hirb/lib/hirb/menu.rb +0 -221
- data/lib/bbcloud/vendor/hirb/lib/hirb/pager.rb +0 -95
- data/lib/bbcloud/vendor/hirb/lib/hirb/string.rb +0 -44
- data/lib/bbcloud/vendor/hirb/lib/hirb/util.rb +0 -96
- data/lib/bbcloud/vendor/hirb/lib/hirb/version.rb +0 -3
- data/lib/bbcloud/vendor/hirb/lib/hirb/view.rb +0 -284
- data/lib/bbcloud/vendor/hirb/lib/hirb/views/couch_db.rb +0 -11
- data/lib/bbcloud/vendor/hirb/lib/hirb/views/misc_db.rb +0 -15
- data/lib/bbcloud/vendor/hirb/lib/hirb/views/mongo_db.rb +0 -14
- data/lib/bbcloud/vendor/hirb/lib/hirb/views/orm.rb +0 -11
- data/lib/bbcloud/vendor/hirb/lib/hirb/views/rails.rb +0 -19
- data/lib/bbcloud/vendor/hirb/lib/hirb/views.rb +0 -8
- data/lib/bbcloud/vendor/hirb/lib/hirb.rb +0 -81
- data/lib/bbcloud/vendor/hirb/test/auto_table_test.rb +0 -30
- data/lib/bbcloud/vendor/hirb/test/console_test.rb +0 -27
- data/lib/bbcloud/vendor/hirb/test/deps.rip +0 -4
- data/lib/bbcloud/vendor/hirb/test/dynamic_view_test.rb +0 -94
- data/lib/bbcloud/vendor/hirb/test/formatter_test.rb +0 -171
- data/lib/bbcloud/vendor/hirb/test/hirb_test.rb +0 -39
- data/lib/bbcloud/vendor/hirb/test/import_test.rb +0 -9
- data/lib/bbcloud/vendor/hirb/test/menu_test.rb +0 -239
- data/lib/bbcloud/vendor/hirb/test/object_table_test.rb +0 -79
- data/lib/bbcloud/vendor/hirb/test/pager_test.rb +0 -162
- data/lib/bbcloud/vendor/hirb/test/resizer_test.rb +0 -62
- data/lib/bbcloud/vendor/hirb/test/table_test.rb +0 -550
- data/lib/bbcloud/vendor/hirb/test/test_helper.rb +0 -61
- data/lib/bbcloud/vendor/hirb/test/tree_test.rb +0 -184
- data/lib/bbcloud/vendor/hirb/test/util_test.rb +0 -59
- data/lib/bbcloud/vendor/hirb/test/view_test.rb +0 -172
- data/lib/bbcloud/vendor/hirb/test/views_test.rb +0 -13
@@ -1,323 +0,0 @@
|
|
1
|
-
require 'hirb/helpers/table/filters'
|
2
|
-
require 'hirb/helpers/table/resizer'
|
3
|
-
|
4
|
-
module Hirb
|
5
|
-
# Base Table class from which other table classes inherit.
|
6
|
-
# By default, a table is constrained to a default width but this can be adjusted
|
7
|
-
# via the max_width option or Hirb::View.width.
|
8
|
-
# Rows can be an array of arrays or an array of hashes.
|
9
|
-
#
|
10
|
-
# An array of arrays ie [[1,2], [2,3]], would render:
|
11
|
-
# +---+---+
|
12
|
-
# | 0 | 1 |
|
13
|
-
# +---+---+
|
14
|
-
# | 1 | 2 |
|
15
|
-
# | 2 | 3 |
|
16
|
-
# +---+---+
|
17
|
-
#
|
18
|
-
# By default, the fields/columns are the numerical indices of the array.
|
19
|
-
#
|
20
|
-
# An array of hashes ie [{:age=>10, :weight=>100}, {:age=>80, :weight=>500}], would render:
|
21
|
-
# +-----+--------+
|
22
|
-
# | age | weight |
|
23
|
-
# +-----+--------+
|
24
|
-
# | 10 | 100 |
|
25
|
-
# | 80 | 500 |
|
26
|
-
# +-----+--------+
|
27
|
-
#
|
28
|
-
# By default, the fields/columns are the keys of the first hash.
|
29
|
-
#
|
30
|
-
# === Custom Callbacks
|
31
|
-
# Callback methods can be defined to add your own options that modify rows right before they are rendered.
|
32
|
-
# Here's an example that allows for searching with a :query option:
|
33
|
-
# module Query
|
34
|
-
# # Searches fields given a query hash
|
35
|
-
# def query_callback(rows, options)
|
36
|
-
# return rows unless options[:query]
|
37
|
-
# options[:query].map {|field,query|
|
38
|
-
# rows.select {|e| e[field].to_s =~ /#{query}/i }
|
39
|
-
# }.flatten.uniq
|
40
|
-
# end
|
41
|
-
# end
|
42
|
-
# Hirb::Helpers::Table.send :include, Query
|
43
|
-
#
|
44
|
-
# >> puts Hirb::Helpers::Table.render [{:name=>'batman'}, {:name=>'robin'}], :query=>{:name=>'rob'}
|
45
|
-
# +-------+
|
46
|
-
# | name |
|
47
|
-
# +-------+
|
48
|
-
# | robin |
|
49
|
-
# +-------+
|
50
|
-
# 1 row in set
|
51
|
-
#
|
52
|
-
# Callback methods:
|
53
|
-
# * must be defined in Helpers::Table and end in '_callback'.
|
54
|
-
# * should expect rows and a hash of render options. Rows will be an array of hashes.
|
55
|
-
# * are expected to return an array of hashes.
|
56
|
-
# * are invoked in alphabetical order.
|
57
|
-
# For a thorough example, see {Boson::Pipe}[http://github.com/cldwalker/boson/blob/master/lib/boson/pipe.rb].
|
58
|
-
#--
|
59
|
-
# derived from http://gist.github.com/72234
|
60
|
-
class Helpers::Table
|
61
|
-
BORDER_LENGTH = 3 # " | " and "-+-" are the borders
|
62
|
-
MIN_FIELD_LENGTH = 3
|
63
|
-
class TooManyFieldsForWidthError < StandardError; end
|
64
|
-
|
65
|
-
class << self
|
66
|
-
|
67
|
-
# Main method which returns a formatted table.
|
68
|
-
# ==== Options:
|
69
|
-
# [*:fields*] An array which overrides the default fields and can be used to indicate field order.
|
70
|
-
# [*:headers*] A hash of fields and their header names. Fields that aren't specified here default to their name.
|
71
|
-
# When set to false, headers are hidden. Can also be an array but only for array rows.
|
72
|
-
# [*:max_fields*] A hash of fields and their maximum allowed lengths. Maximum length can also be a percentage of the total width
|
73
|
-
# (decimal less than one). When a field exceeds it's maximum then it's
|
74
|
-
# truncated and has a ... appended to it. Fields that aren't specified have no maximum.
|
75
|
-
# [*:max_width*] The maximum allowed width of all fields put together including field borders. Only valid when :resize is true.
|
76
|
-
# Default is Hirb::View.width.
|
77
|
-
# [*:resize*] Resizes table to display all columns in allowed :max_width. Default is true. Setting this false will display the full
|
78
|
-
# length of each field.
|
79
|
-
# [*:number*] When set to true, numbers rows by adding a :hirb_number column as the first column. Default is false.
|
80
|
-
# [*:change_fields*] A hash to change old field names to new field names. This can also be an array of new names but only for array rows.
|
81
|
-
# This is useful when wanting to change auto-generated keys to more user-friendly names i.e. for array rows.
|
82
|
-
# [*:filters*] A hash of fields and their filters, applied to every row in a field. A filter can be a proc, an instance method
|
83
|
-
# applied to the field value or a Filters method. Also see the filter_classes attribute below.
|
84
|
-
# [*:header_filter*] A filter, like one in :filters, that is applied to all headers after the :headers option.
|
85
|
-
# [*:filter_any*] When set to true, any cell defaults to being filtered by its class in :filter_classes.
|
86
|
-
# Default Hirb::Helpers::Table.filter_any().
|
87
|
-
# [*:filter_classes*] Hash which maps classes to filters. Default is Hirb::Helpers::Table.filter_classes().
|
88
|
-
# [*:vertical*] When set to true, renders a vertical table using Hirb::Helpers::VerticalTable. Default is false.
|
89
|
-
# [*:all_fields*] When set to true, renders fields in all rows. Valid only in rows that are hashes. Default is false.
|
90
|
-
# [*:description*] When set to true, renders row count description at bottom. Default is true.
|
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
|
-
# vertical tables and true for anything else.
|
93
|
-
# Examples:
|
94
|
-
# Hirb::Helpers::Table.render [[1,2], [2,3]]
|
95
|
-
# Hirb::Helpers::Table.render [[1,2], [2,3]], :max_fields=>{0=>10}, :header_filter=>:capitalize
|
96
|
-
# Hirb::Helpers::Table.render [['a',1], ['b',2]], :change_fields=>%w{letters numbers}, :max_fields=>{'numbers'=>0.4}
|
97
|
-
# Hirb::Helpers::Table.render [{:age=>10, :weight=>100}, {:age=>80, :weight=>500}]
|
98
|
-
# Hirb::Helpers::Table.render [{:age=>10, :weight=>100}, {:age=>80, :weight=>500}], :headers=>{:weight=>"Weight(lbs)"}
|
99
|
-
# Hirb::Helpers::Table.render [{:age=>10, :weight=>100}, {:age=>80, :weight=>500}], :filters=>{:age=>[:to_f]}
|
100
|
-
def render(rows, options={})
|
101
|
-
options[:vertical] ? Helpers::VerticalTable.render(rows, options) :
|
102
|
-
new(rows, options).render
|
103
|
-
rescue TooManyFieldsForWidthError
|
104
|
-
$stderr.puts "", "** Error: Too many fields for the current width. Configure your width " +
|
105
|
-
"and/or fields to avoid this error. Defaulting to a vertical table. **"
|
106
|
-
Helpers::VerticalTable.render(rows, options)
|
107
|
-
end
|
108
|
-
|
109
|
-
# A hash which maps a cell value's class to a filter. This serves to set a default filter per field if all of its
|
110
|
-
# values are a class in this hash. By default, Array values are comma joined and Hashes are inspected.
|
111
|
-
# See the :filter_any option to apply this filter per value.
|
112
|
-
attr_accessor :filter_classes
|
113
|
-
# Boolean which sets the default for :filter_any option.
|
114
|
-
attr_accessor :filter_any
|
115
|
-
# Holds last table object created
|
116
|
-
attr_accessor :last_table
|
117
|
-
end
|
118
|
-
self.filter_classes = { Array=>:comma_join, Hash=>:inspect }
|
119
|
-
|
120
|
-
#:stopdoc:
|
121
|
-
attr_accessor :width, :max_fields, :field_lengths, :fields
|
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?)
|
125
|
-
@options = {:description=>true, :filters=>{}, :change_fields=>{}, :escape_special_chars=>true,
|
126
|
-
:filter_any=>Helpers::Table.filter_any, :resize=>true}.merge(options)
|
127
|
-
@fields = set_fields(rows)
|
128
|
-
@rows = set_rows(rows)
|
129
|
-
@headers = set_headers
|
130
|
-
if @options[:number]
|
131
|
-
@headers[:hirb_number] = "number"
|
132
|
-
@fields.unshift :hirb_number
|
133
|
-
end
|
134
|
-
Helpers::Table.last_table = self
|
135
|
-
end
|
136
|
-
|
137
|
-
def set_fields(rows)
|
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}
|
144
|
-
else
|
145
|
-
rows[0].is_a?(Array) ? (0..rows[0].length - 1).to_a : []
|
146
|
-
end
|
147
|
-
|
148
|
-
@options[:change_fields].each do |oldf, newf|
|
149
|
-
(index = fields.index(oldf)) && fields[index] = newf
|
150
|
-
end
|
151
|
-
fields
|
152
|
-
end
|
153
|
-
|
154
|
-
def set_rows(rows)
|
155
|
-
rows = Array(rows)
|
156
|
-
if rows[0].is_a?(Array)
|
157
|
-
rows = rows.inject([]) {|new_rows, row|
|
158
|
-
new_rows << array_to_indices_hash(row)
|
159
|
-
}
|
160
|
-
end
|
161
|
-
@options[:change_fields].each do |oldf, newf|
|
162
|
-
rows.each {|e| e[newf] = e.delete(oldf) if e.key?(oldf) }
|
163
|
-
end
|
164
|
-
rows = filter_values(rows)
|
165
|
-
rows.each_with_index {|e,i| e[:hirb_number] = (i + 1).to_s} if @options[:number]
|
166
|
-
deleted_callbacks = Array(@options[:delete_callbacks]).map {|e| "#{e}_callback" }
|
167
|
-
(methods.grep(/_callback$/).map {|e| e.to_s} - deleted_callbacks).sort.each do |meth|
|
168
|
-
rows = send(meth, rows, @options.dup)
|
169
|
-
end
|
170
|
-
validate_values(rows)
|
171
|
-
rows
|
172
|
-
end
|
173
|
-
|
174
|
-
def set_headers
|
175
|
-
headers = @fields.inject({}) {|h,e| h[e] = e.to_s; h}
|
176
|
-
if @options.has_key?(:headers)
|
177
|
-
headers = @options[:headers].is_a?(Hash) ? headers.merge(@options[:headers]) :
|
178
|
-
(@options[:headers].is_a?(Array) ? array_to_indices_hash(@options[:headers]) : @options[:headers])
|
179
|
-
end
|
180
|
-
if @options[:header_filter]
|
181
|
-
headers.each {|k,v|
|
182
|
-
headers[k] = call_filter(@options[:header_filter], v)
|
183
|
-
}
|
184
|
-
end
|
185
|
-
headers
|
186
|
-
end
|
187
|
-
|
188
|
-
def render
|
189
|
-
body = []
|
190
|
-
unless @rows.length == 0
|
191
|
-
setup_field_lengths
|
192
|
-
body += render_header
|
193
|
-
body += render_rows
|
194
|
-
body += render_footer
|
195
|
-
end
|
196
|
-
body << render_table_description if @options[:description]
|
197
|
-
body.join("\n")
|
198
|
-
end
|
199
|
-
|
200
|
-
def render_header
|
201
|
-
@headers ? render_table_header : [render_border]
|
202
|
-
end
|
203
|
-
|
204
|
-
def render_footer
|
205
|
-
[render_border]
|
206
|
-
end
|
207
|
-
|
208
|
-
def render_table_header
|
209
|
-
title_row = '| ' + @fields.map {|f|
|
210
|
-
format_cell(@headers[f], @field_lengths[f])
|
211
|
-
}.join(' | ') + ' |'
|
212
|
-
[render_border, title_row, render_border]
|
213
|
-
end
|
214
|
-
|
215
|
-
def render_border
|
216
|
-
'+-' + @fields.map {|f| '-' * @field_lengths[f] }.join('-+-') + '-+'
|
217
|
-
end
|
218
|
-
|
219
|
-
def format_cell(value, cell_width)
|
220
|
-
text = String.size(value) > cell_width ?
|
221
|
-
(
|
222
|
-
(cell_width < 5) ? String.slice(value, 0, cell_width) : String.slice(value, 0, cell_width - 3) + '...'
|
223
|
-
) : value
|
224
|
-
String.ljust(text, cell_width)
|
225
|
-
end
|
226
|
-
|
227
|
-
def render_rows
|
228
|
-
@rows.map do |row|
|
229
|
-
row = '| ' + @fields.map {|f|
|
230
|
-
format_cell(row[f], @field_lengths[f])
|
231
|
-
}.join(' | ') + ' |'
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
def render_table_description
|
236
|
-
(@rows.length == 0) ? "0 rows in set" :
|
237
|
-
"#{@rows.length} #{@rows.length == 1 ? 'row' : 'rows'} in set"
|
238
|
-
end
|
239
|
-
|
240
|
-
def setup_field_lengths
|
241
|
-
@field_lengths = default_field_lengths
|
242
|
-
if @options[:resize]
|
243
|
-
raise TooManyFieldsForWidthError if @fields.size > self.actual_width.to_f / MIN_FIELD_LENGTH
|
244
|
-
Resizer.resize!(self)
|
245
|
-
else
|
246
|
-
enforce_field_constraints
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
def enforce_field_constraints
|
251
|
-
max_fields.each {|k,max| @field_lengths[k] = max if @field_lengths[k].to_i > max }
|
252
|
-
end
|
253
|
-
|
254
|
-
def max_fields
|
255
|
-
@max_fields ||= (@options[:max_fields] ||= {}).each {|k,v|
|
256
|
-
@options[:max_fields][k] = (actual_width * v.to_f.abs).floor if v.to_f.abs < 1
|
257
|
-
}
|
258
|
-
end
|
259
|
-
|
260
|
-
def actual_width
|
261
|
-
@actual_width ||= self.width - (@fields.size * BORDER_LENGTH + 1)
|
262
|
-
end
|
263
|
-
|
264
|
-
def width
|
265
|
-
@width ||= @options[:max_width] || View.width
|
266
|
-
end
|
267
|
-
|
268
|
-
# find max length for each field; start with the headers
|
269
|
-
def default_field_lengths
|
270
|
-
field_lengths = @headers ? @headers.inject({}) {|h,(k,v)| h[k] = String.size(v); h} :
|
271
|
-
@fields.inject({}) {|h,e| h[e] = 1; h }
|
272
|
-
@rows.each do |row|
|
273
|
-
@fields.each do |field|
|
274
|
-
len = String.size(row[field])
|
275
|
-
field_lengths[field] = len if len > field_lengths[field].to_i
|
276
|
-
end
|
277
|
-
end
|
278
|
-
field_lengths
|
279
|
-
end
|
280
|
-
|
281
|
-
def set_filter_defaults(rows)
|
282
|
-
@filter_classes.each do |klass, filter|
|
283
|
-
@fields.each {|field|
|
284
|
-
if rows.all? {|r| r[field].class == klass }
|
285
|
-
@options[:filters][field] ||= filter
|
286
|
-
end
|
287
|
-
}
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
def filter_values(rows)
|
292
|
-
@filter_classes = Helpers::Table.filter_classes.merge @options[:filter_classes] || {}
|
293
|
-
set_filter_defaults(rows) unless @options[:filter_any]
|
294
|
-
rows.map {|row|
|
295
|
-
@fields.inject({}) {|new_row,f|
|
296
|
-
(filter = @options[:filters][f]) || (@options[:filter_any] && (filter = @filter_classes[row[f].class]))
|
297
|
-
new_row[f] = filter ? call_filter(filter, row[f]) : row[f]
|
298
|
-
new_row
|
299
|
-
}
|
300
|
-
}
|
301
|
-
end
|
302
|
-
|
303
|
-
def call_filter(filter, val)
|
304
|
-
filter.is_a?(Proc) ? filter.call(val) :
|
305
|
-
val.respond_to?(Array(filter)[0]) ? val.send(*filter) : Filters.send(filter, val)
|
306
|
-
end
|
307
|
-
|
308
|
-
def validate_values(rows)
|
309
|
-
rows.each {|row|
|
310
|
-
@fields.each {|f|
|
311
|
-
row[f] = row[f].to_s || ''
|
312
|
-
row[f] = row[f].gsub(/(\t|\r|\n)/) {|e| e.dump.gsub('"','') } if @options[:escape_special_chars]
|
313
|
-
}
|
314
|
-
}
|
315
|
-
end
|
316
|
-
|
317
|
-
# Converts an array to a hash mapping a numerical index to its array value.
|
318
|
-
def array_to_indices_hash(array)
|
319
|
-
array.inject({}) {|hash,e| hash[hash.size] = e; hash }
|
320
|
-
end
|
321
|
-
#:startdoc:
|
322
|
-
end
|
323
|
-
end
|
@@ -1,181 +0,0 @@
|
|
1
|
-
# Base tree class which given an array of nodes produces different types of trees.
|
2
|
-
# The types of trees currently are:
|
3
|
-
# * basic:
|
4
|
-
# 0
|
5
|
-
# 1
|
6
|
-
# 2
|
7
|
-
# 3
|
8
|
-
# 4
|
9
|
-
#
|
10
|
-
# * directory:
|
11
|
-
# 0
|
12
|
-
# |-- 1
|
13
|
-
# | |-- 2
|
14
|
-
# | `-- 3
|
15
|
-
# `-- 4
|
16
|
-
#
|
17
|
-
# * number:
|
18
|
-
# 1. 0
|
19
|
-
# 1. 1
|
20
|
-
# 1. 2
|
21
|
-
# 2. 3
|
22
|
-
# 2. 4
|
23
|
-
#
|
24
|
-
# Tree nodes can be given as an array of arrays or an array of hashes.
|
25
|
-
# To render the above basic tree with an array of hashes:
|
26
|
-
# Hirb::Helpers::Tree.render([{:value=>0, :level=>0}, {:value=>1, :level=>1}, {:value=>2, :level=>2},
|
27
|
-
# {:value=>3, :level=>2}, {:value=>4, :level=>1}])
|
28
|
-
# Note from the hash keys that :level refers to the depth of the tree while :value refers to the text displayed
|
29
|
-
# for a node.
|
30
|
-
#
|
31
|
-
# To render the above basic tree with an array of arrays:
|
32
|
-
# Hirb::Helpers::Tree.render([[0,0], [1,1], [2,2], [2,3], [1,4]])
|
33
|
-
# Note that the each array pair consists of the level and the value for the node.
|
34
|
-
class Hirb::Helpers::Tree
|
35
|
-
class ParentlessNodeError < StandardError; end
|
36
|
-
|
37
|
-
class <<self
|
38
|
-
# Main method which renders a tree.
|
39
|
-
# ==== Options:
|
40
|
-
# [:type] Type of tree. Either :basic, :directory or :number. Default is :basic.
|
41
|
-
# [:validate] Boolean to validate tree. Checks to see if all nodes have parents. Raises ParentlessNodeError if
|
42
|
-
# an invalid node is found. Default is false.
|
43
|
-
# [:indent] Number of spaces to indent between levels for basic + number trees. Default is 4.
|
44
|
-
# [:limit] Limits the level or depth of a tree that is displayed. Root node is level 0.
|
45
|
-
# [:description] Displays brief description about tree ie how many nodes it has.
|
46
|
-
# [:multi_line_nodes] Handles multi-lined nodes by indenting their newlines. Default is false.
|
47
|
-
# Examples:
|
48
|
-
# Hirb::Helpers::Tree.render([[0, 'root'], [1, 'child']], :type=>:directory)
|
49
|
-
def render(nodes, options={})
|
50
|
-
new(nodes, options).render
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# :stopdoc:
|
55
|
-
attr_accessor :nodes
|
56
|
-
|
57
|
-
def initialize(input_nodes, options={})
|
58
|
-
@options = options
|
59
|
-
@type = options[:type] || :basic
|
60
|
-
if input_nodes[0].is_a?(Array)
|
61
|
-
@nodes = input_nodes.map {|e| Node.new(:level=>e[0], :value=>e[1]) }
|
62
|
-
else
|
63
|
-
@nodes = input_nodes.map {|e| Node.new(e)}
|
64
|
-
end
|
65
|
-
@nodes.each_with_index {|e,i| e.merge!(:tree=>self, :index=>i)}
|
66
|
-
@nodes.each {|e| e[:value] = e[:value].to_s }
|
67
|
-
validate_nodes if options[:validate]
|
68
|
-
self
|
69
|
-
end
|
70
|
-
|
71
|
-
def render
|
72
|
-
body = render_tree
|
73
|
-
body += render_description if @options[:description]
|
74
|
-
body
|
75
|
-
end
|
76
|
-
|
77
|
-
def render_description
|
78
|
-
"\n\n#{@nodes.length} #{@nodes.length == 1 ? 'node' : 'nodes'} in tree"
|
79
|
-
end
|
80
|
-
|
81
|
-
def render_tree
|
82
|
-
@indent = ' ' * (@options[:indent] || 4 )
|
83
|
-
@nodes = @nodes.select {|e| e[:level] <= @options[:limit] } if @options[:limit]
|
84
|
-
case @type.to_s
|
85
|
-
when 'directory' then render_directory
|
86
|
-
when 'number' then render_number
|
87
|
-
else render_basic
|
88
|
-
end
|
89
|
-
end
|
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
|
-
|
96
|
-
def render_directory
|
97
|
-
mark_last_nodes_per_level
|
98
|
-
render_nodes {|e|
|
99
|
-
value = ''
|
100
|
-
unless e.root?
|
101
|
-
value << e.render_parent_characters
|
102
|
-
value << (e[:last_node] ? "`-- " : "|-- ")
|
103
|
-
end
|
104
|
-
value
|
105
|
-
}
|
106
|
-
end
|
107
|
-
|
108
|
-
def render_number
|
109
|
-
counter = {}
|
110
|
-
@nodes.each {|e|
|
111
|
-
parent_level_key = "#{(e.parent ||{})[:index]}.#{e[:level]}"
|
112
|
-
counter[parent_level_key] ||= 0
|
113
|
-
counter[parent_level_key] += 1
|
114
|
-
e[:pre_value] = "#{counter[parent_level_key]}. "
|
115
|
-
}
|
116
|
-
render_nodes {|e| @indent * e[:level] + e[:pre_value] }
|
117
|
-
end
|
118
|
-
|
119
|
-
def render_basic
|
120
|
-
render_nodes {|e| @indent * e[:level] }
|
121
|
-
end
|
122
|
-
|
123
|
-
def validate_nodes
|
124
|
-
@nodes.each do |e|
|
125
|
-
raise ParentlessNodeError if (e[:level] > e.previous[:level]) && (e[:level] - e.previous[:level]) > 1
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
# walks tree accumulating last nodes per unique parent+level
|
130
|
-
def mark_last_nodes_per_level
|
131
|
-
@nodes.each {|e| e.delete(:last_node)}
|
132
|
-
last_node_hash = @nodes.inject({}) {|h,e|
|
133
|
-
h["#{(e.parent ||{})[:index]}.#{e[:level]}"] = e; h
|
134
|
-
}
|
135
|
-
last_node_hash.values.uniq.each {|e| e[:last_node] = true}
|
136
|
-
end
|
137
|
-
#:startdoc:
|
138
|
-
class Node < ::Hash #:nodoc:
|
139
|
-
class MissingLevelError < StandardError; end
|
140
|
-
class MissingValueError < StandardError; end
|
141
|
-
|
142
|
-
def initialize(hash)
|
143
|
-
super
|
144
|
-
raise MissingLevelError unless hash.has_key?(:level)
|
145
|
-
raise MissingValueError unless hash.has_key?(:value)
|
146
|
-
replace(hash)
|
147
|
-
end
|
148
|
-
|
149
|
-
def value(indent=nil)
|
150
|
-
indent ? self[:value].gsub("\n", "\n#{indent * self[:level]}") : self[:value]
|
151
|
-
end
|
152
|
-
|
153
|
-
def parent
|
154
|
-
self[:tree].nodes.slice(0 .. self[:index]).reverse.detect {|e| e[:level] < self[:level]}
|
155
|
-
end
|
156
|
-
|
157
|
-
def next
|
158
|
-
self[:tree].nodes[self[:index] + 1]
|
159
|
-
end
|
160
|
-
|
161
|
-
def previous
|
162
|
-
self[:tree].nodes[self[:index] - 1]
|
163
|
-
end
|
164
|
-
|
165
|
-
def root?; self[:level] == 0; end
|
166
|
-
|
167
|
-
# refers to characters which connect parent nodes
|
168
|
-
def render_parent_characters
|
169
|
-
parent_chars = []
|
170
|
-
get_parents_character(parent_chars)
|
171
|
-
parent_chars.reverse.map {|level| level + ' ' * 3 }.join('')
|
172
|
-
end
|
173
|
-
|
174
|
-
def get_parents_character(parent_chars)
|
175
|
-
if self.parent
|
176
|
-
parent_chars << (self.parent[:last_node] ? ' ' : '|') unless self.parent.root?
|
177
|
-
self.parent.get_parents_character(parent_chars)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
class Hirb::Helpers::VerticalTable < Hirb::Helpers::Table
|
2
|
-
|
3
|
-
# Renders a vertical table using the same options as Hirb::Helpers::Table.render except for the ones below
|
4
|
-
# and :max_fields, :vertical and :max_width which aren't used.
|
5
|
-
# ==== Options:
|
6
|
-
# [:hide_empty] Boolean which hides empty values (nil or '') from being displayed. Default is false.
|
7
|
-
def self.render(rows, options={})
|
8
|
-
new(rows, {:escape_special_chars=>false, :resize=>false}.merge(options)).render
|
9
|
-
end
|
10
|
-
|
11
|
-
#:stopdoc:
|
12
|
-
def setup_field_lengths
|
13
|
-
@field_lengths = default_field_lengths
|
14
|
-
end
|
15
|
-
|
16
|
-
def render_header; []; end
|
17
|
-
def render_footer; []; end
|
18
|
-
|
19
|
-
def render_rows
|
20
|
-
i = 0
|
21
|
-
longest_header = Hirb::String.size @headers.values.sort_by {|e| Hirb::String.size(e) }.last
|
22
|
-
stars = "*" * [(longest_header + (longest_header / 2)), 3].max
|
23
|
-
@rows.map do |row|
|
24
|
-
row = "#{stars} #{i+1}. row #{stars}\n" +
|
25
|
-
@fields.map {|f|
|
26
|
-
if !@options[:hide_empty] || (@options[:hide_empty] && !row[f].empty?)
|
27
|
-
"#{Hirb::String.rjust(@headers[f], longest_header)}: #{row[f]}"
|
28
|
-
else
|
29
|
-
nil
|
30
|
-
end
|
31
|
-
}.compact.join("\n")
|
32
|
-
i+= 1
|
33
|
-
row
|
34
|
-
end
|
35
|
-
end
|
36
|
-
#:startdoc:
|
37
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Hirb
|
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
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
%w{table object_table auto_table tree parent_child_tree vertical_table}.each do |e|
|
16
|
-
require "hirb/helpers/#{e}"
|
17
|
-
end
|