tty 0.0.1 → 0.0.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.
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  *.swp
2
+ *.swo
2
3
  *.gem
3
4
  *.rbc
4
5
  .bundle
data/README.md CHANGED
@@ -1,11 +1,10 @@
1
1
  # TTY
2
- [![Build Status](https://secure.travis-ci.org/peter-murach/tty.png?branch=master)][travis] [![Dependency Status](https://gemnasium.com/peter-murach/tty.png?travis)][gemnasium] [![Code Climate](https://codeclimate.com/badge.png)][codeclimate]
2
+ [![Build Status](https://secure.travis-ci.org/peter-murach/tty.png?branch=master)][travis] [![Code Climate](https://codeclimate.com/badge.png)][codeclimate]
3
3
 
4
4
  [travis]: http://travis-ci.org/peter-murach/tty
5
- [gemnasium]: https://gemnasium.com/peter-murach/tty
6
5
  [codeclimate]: https://codeclimate.com/github/peter-murach/tty
7
6
 
8
- Toolbox for developing CLI clients.
7
+ Toolbox for developing CLI clients in Ruby.
9
8
 
10
9
  ## Features
11
10
 
@@ -14,9 +13,11 @@ Jump-start development of your command line app:
14
13
  * Fully customizable table rendering with an easy-to-use API.
15
14
  (status: In Progress)
16
15
  * Terminal output colorization. (status: TODO)
17
- * Terminal & System detection utilities. (status: TODO)
16
+ * Terminal & System detection utilities. (status: In Progress)
18
17
  * Text alignment/padding and diffs. (status: TODO)
19
18
  * Shell user interface. (status: TODO)
19
+ * Progress bar. (status: TODO)
20
+ * Fully tested with major ruby interpreters.
20
21
  * No dependencies to allow for easy gem vendoring.
21
22
 
22
23
  ## Installation
@@ -37,14 +38,22 @@ Or install it yourself as:
37
38
 
38
39
  ### Table
39
40
 
40
- Creating tables
41
+ To instantiate table
42
+
43
+ ```ruby
44
+ table = TTY::Table.new :rows => [['a1', 'a2'], ['b1', 'b2']]
45
+ table = TTY::Table[['a1', 'a2'], ['b1', 'b2']]
46
+ ```
47
+
48
+ Table behaves like an array so `<<` and similar methods can be used
41
49
 
42
50
  ```ruby
43
- table = TTY::Table.new ['Header 1', 'Header 2']
44
51
  table << ['a1', 'a2', 'a3']
45
52
  table << ['b1', 'b2', 'b3']
46
53
  ```
47
54
 
55
+ or pass your rows in a block
56
+
48
57
  ```ruby
49
58
  table = TTY::Table.new header: ['Header 1', 'Header 2'] do |t|
50
59
  t << ['a1', 'a2', 'a3']
@@ -52,6 +61,36 @@ Creating tables
52
61
  end
53
62
  ```
54
63
 
64
+ And then to print do
65
+
66
+ ```ruby
67
+ table.to_s # => a1 a2 a3
68
+ # b1 b2 b3
69
+ ```
70
+
71
+ To print `unicode` table
72
+
73
+ ```ruby
74
+ table = TTY::Table.new renderer: 'unicode'
75
+ table.to_s
76
+ ```
77
+
78
+ ### Terminal
79
+
80
+ ```ruby
81
+ term = TTY::Terminal.new
82
+ term.width # => 140
83
+ term.height # => 60
84
+ term.color? # => true or false
85
+ ```
86
+
87
+ ### System
88
+
89
+ ```ruby
90
+ TTY::System.unix? # => true
91
+ TTY::System.windows? # => false
92
+ ```
93
+
55
94
  ## Contributing
56
95
 
57
96
  1. Fork it
data/lib/tty.rb CHANGED
@@ -1,11 +1,32 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  require 'tty/version'
4
- require 'tty/table'
5
- require 'tty/color'
6
4
 
7
5
  require 'tty/support/utils'
6
+ require 'tty/support/delegatable'
7
+ require 'tty/support/conversion'
8
+
9
+ require 'tty/color'
10
+ require 'tty/terminal'
11
+ require 'tty/system'
12
+ require 'tty/table'
8
13
 
9
14
  module TTY
10
15
 
16
+ # Raised when the argument type is different from expected
17
+ class TypeError < ArgumentError; end
18
+
19
+ class << self
20
+
21
+ # Return terminal instance
22
+ #
23
+ # @return [TTY::Terminal]
24
+ #
25
+ # @api public
26
+ def terminal
27
+ @terminal ||= Terminal.new
28
+ end
29
+
30
+ end
31
+
11
32
  end # TTY
data/lib/tty/color.rb CHANGED
@@ -10,9 +10,5 @@ module TTY
10
10
 
11
11
  attr_reader :enabled
12
12
 
13
- def self.color?
14
- %x{tput colors 2>/dev/null}.to_i > 2
15
- end
16
-
17
13
  end # Color
18
14
  end # TTY
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ # A mixin to allow instances conversion to different types
5
+ module Conversion
6
+
7
+ # Converts the object into an Array. If copy is set to true
8
+ # a copy of object will be made.
9
+ #
10
+ # @param [Object] object
11
+ #
12
+ # @param [Boolean] copy
13
+ #
14
+ # @return [Array]
15
+ #
16
+ # @api private
17
+ def convert_to_array(object, copy=false)
18
+ case object
19
+ when Array
20
+ copy ? object.dup : object
21
+ when Hash
22
+ Array(object)
23
+ else
24
+ begin
25
+ converted = object.to_ary
26
+ rescue Exception => e
27
+ raise TTY::TypeError, "Cannot convert #{object.class} into an Array (#{e.message})"
28
+ end
29
+ converted
30
+ end
31
+ end
32
+
33
+ end # Conversion
34
+ end # TTY
@@ -0,0 +1,44 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module TTY
4
+ # A mixin to allow delegetable methods to be added
5
+ module Delegatable
6
+
7
+ # Create delegator for each specified method
8
+ #
9
+ # @example
10
+ # delegatable_method :source, :method
11
+ #
12
+ # @param [Symbol] source
13
+ #
14
+ # @param [Array] methods
15
+ #
16
+ # @return [self]
17
+ #
18
+ # @api public
19
+ def delegatable_method(source, *methods)
20
+ methods.each { |method| define_delegatable_method(source, method)}
21
+ self
22
+ end
23
+
24
+ private
25
+
26
+ # Create a delegator method for the method name
27
+ #
28
+ # @param [Symbol] source
29
+ #
30
+ # @param [Symbol] method name
31
+ #
32
+ # @return [undefined]
33
+ #
34
+ # @api private
35
+ def define_delegatable_method(source, method)
36
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
37
+ def #{method}(*args, &block)
38
+ #{source}.#{method}(*args, &block)
39
+ end
40
+ RUBY
41
+ end
42
+
43
+ end # Delegatable
44
+ end # TTY
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module TTY
2
4
  module Utils
3
5
  extend self
data/lib/tty/system.rb ADDED
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'rbconfig'
4
+
5
+ module TTY
6
+ class System
7
+
8
+ class << self
9
+
10
+ # Check if windows platform.
11
+ #
12
+ # @return [Boolean]
13
+ #
14
+ # @api public
15
+ def windows?
16
+ RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw|windows/
17
+ end
18
+
19
+ # Check if unix platform
20
+ #
21
+ # @return [Boolean]
22
+ #
23
+ # @api public
24
+ def unix?
25
+ RbConfig::CONFIG['host_os'] =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
26
+ end
27
+
28
+ end
29
+
30
+ end # System
31
+ end # TTY
data/lib/tty/table.rb CHANGED
@@ -2,10 +2,13 @@
2
2
 
3
3
  require 'forwardable'
4
4
  require 'tty/table/renderer'
5
+ require 'tty/table/error'
6
+ require 'tty/table/validatable'
5
7
 
6
8
  module TTY
7
9
  class Table
8
- include Comparable, Enumerable, Renderer
10
+ include Comparable, Enumerable, Renderer, Conversion
11
+ include Validatable
9
12
  extend Forwardable
10
13
 
11
14
  # The table header
@@ -34,6 +37,16 @@ module TTY
34
37
  # TODO implement table orientation
35
38
  end
36
39
 
40
+ # Create a new Table where each argument is a row
41
+ #
42
+ # @example
43
+ # table = TTY::Table.new[['a1', 'a2'], ['b1', 'b2']]
44
+ #
45
+ # @api public
46
+ def self.[](*rows)
47
+ self.new(:rows => rows)
48
+ end
49
+
37
50
  # Instantiate a new Table
38
51
  #
39
52
  # @example of direct parameters
@@ -44,6 +57,8 @@ module TTY
44
57
  # rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
45
58
  # table = Table.new :header => ['Header 1', 'Header 2'], :rows => rows
46
59
  #
60
+ # @param [Array[Symbol], Hash] *args
61
+ #
47
62
  # @api public
48
63
  def self.new(*args, &block)
49
64
  options = Utils.extract_options!(args)
@@ -58,28 +73,105 @@ module TTY
58
73
  # Initialize a Table
59
74
  #
60
75
  # @param [Hash] options
76
+ # the options to create the table with
77
+ # @option options [String] :header
78
+ # column names to be displayed
79
+ # @option options [String] :rows
80
+ # Array of Arrays expressin the rows
81
+ # @option options [String] :renderer
82
+ # used to format table output
83
+ #
61
84
  # @return [Table]
62
85
  #
63
86
  # @api private
64
87
  def initialize(options={}, &block)
65
88
  @header = options.fetch :header, []
66
- @rows = options.fetch :rows, []
89
+ @rows = coerce(options.fetch :rows, [])
67
90
  @renderer = pick_renderer options[:renderer]
91
+ assert_row_sizes @rows
68
92
  yield_or_eval &block if block_given?
69
93
  end
70
94
 
71
- # Lookup an attribute value given an attribute name
95
+ # Lookup element of the table given a row(i) and column(j)
72
96
  #
73
- def [](index)
74
- if index >= 0
75
- rows.map { |row| row[0] }.compact
97
+ # @api public
98
+ def [](i, j)
99
+ if i >= 0 && j >= 0
100
+ rows.fetch(i){return nil}[j]
76
101
  else
77
102
  raise IndexError.new("index #{index} not found")
78
103
  end
79
104
  end
105
+ alias element []
106
+ alias component []
107
+
108
+ # Set table value at row(i) and column(j)
109
+ #
110
+ # @api private
111
+ def []=(i, j, val)
112
+ @rows[i][j] = val
113
+ end
114
+ private :[]=
115
+
116
+ # Return a row number at the index of the table as an Array.
117
+ # When a block is given, the elements of that Array are iterated over.
118
+ #
119
+ # @example
120
+ # rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
121
+ # table = TTY::Table.new :rows => rows
122
+ # table.row(1) { |element| ... }
123
+ #
124
+ # @param [Integer] index
125
+ #
126
+ # @yield []
127
+ # optional block to execute in the iteration operation
128
+ #
129
+ # @return [self]
130
+ #
131
+ # @api public
132
+ def row(index, &block)
133
+ if block_given?
134
+ rows.fetch(index){return self}.each(&block)
135
+ self
136
+ else
137
+ rows.fetch(index){return nil}
138
+ end
139
+ end
80
140
 
141
+ # Return a column number at the index of the table as an Array.
142
+ # When a block is given, the elements of that Array are iterated over.
143
+ #
144
+ # @example
145
+ # rows = [ ['a1', 'a2'], ['b1', 'b2'] ]
146
+ # table = TTY::Table.new :rows => rows
147
+ # table.column(1) { |element| ... }
148
+ #
149
+ # @param [Integer] index
150
+ #
151
+ # @yield []
152
+ # optional block to execute in the iteration operation
153
+ #
154
+ # @return [self]
155
+ #
156
+ # @api public
157
+ def column(index)
158
+ if block_given?
159
+ return self if index >= column_size || index < 0
160
+ rows.map { |row| yield row[index].compact }
161
+ else
162
+ return nil if index >= column_size || index < 0
163
+ rows.map { |row| row[index] }.compact
164
+ end
165
+ end
166
+
167
+ # Add row to table
168
+ #
169
+ # @param [Array] row
170
+ #
81
171
  # @api public
82
172
  def <<(row)
173
+ rows_copy = rows.dup
174
+ assert_row_sizes rows_copy << row
83
175
  rows << row
84
176
  end
85
177
 
@@ -87,11 +179,12 @@ module TTY
87
179
  #
88
180
  # @example
89
181
  # table = TTY::Table.new(header, tuples)
90
- # table.each { |tuple| ... }
182
+ # table.each { |row| ... }
91
183
  #
92
- # @yield [tuple]
184
+ # @yield [Array[Array]]
93
185
  #
94
186
  # @return [self]
187
+ #
95
188
  # @api public
96
189
  def each
97
190
  return to_enum unless block_given?
@@ -101,22 +194,62 @@ module TTY
101
194
  self
102
195
  end
103
196
 
197
+ # Return the number of columns
198
+ #
199
+ # @example
200
+ # table.column_size # => 5
201
+ #
202
+ # @return [Integer]
203
+ #
204
+ # @api public
205
+ def column_size
206
+ return rows[0].size if (rows.size > 0)
207
+ return 0
208
+ end
209
+
104
210
  # Return the number of rows
105
211
  #
106
212
  # @example
107
- # table.size # => 5
213
+ # table.row_size # => 5
108
214
  #
109
215
  # @return [Integer]
216
+ #
217
+ # @api public
218
+ def row_size
219
+ rows.size
220
+ end
221
+
222
+ # Return the number of rows and columns
223
+ #
224
+ # @example
225
+ # table.size # => [3,5]
226
+ #
227
+ # @return [Array] row x columns
228
+ #
229
+ # @api public
110
230
  def size
111
- return rows[0].length if (rows.length > 0)
112
- return 0
231
+ [row_size, column_size]
113
232
  end
114
233
 
115
234
  # Check table width
116
235
  #
117
236
  # @return [Integer] width
237
+ #
238
+ # @api public
118
239
  def width
119
-
240
+ extract_column_widths(rows)
241
+ total_width
242
+ end
243
+
244
+ # Compare this table with other table for equality
245
+ #
246
+ # @param [TTY::Table] other
247
+ #
248
+ # @return [Boolean]
249
+ #
250
+ # @api public
251
+ def eql?(other)
252
+ instance_of?(other.class)
120
253
  end
121
254
 
122
255
  # Compare the table with other table for equivalency
@@ -135,23 +268,25 @@ module TTY
135
268
 
136
269
  # Return string representation of table
137
270
  #
271
+ # @return [String]
272
+ #
138
273
  # @api public
139
274
  def to_s
140
- renderer.render(rows)
275
+ render(rows)
141
276
  end
142
277
 
143
278
  # Coerce an Enumerable into a Table
279
+ # This coercion mechanism is used by Table to handle Enumerable types
280
+ # and force them into array type.
144
281
  #
145
282
  # @param [Enumerable] object
146
283
  # the object to coerce
147
284
  #
148
- def self.coerce(object)
149
- if object.kind_of?(TTY::Table)
150
- object
151
- elsif object.kind_of?(Hash)
152
- array = [object.keys]
153
- array << object.values
154
- end
285
+ # @return [Array]
286
+ #
287
+ # @api public
288
+ def coerce(rows)
289
+ convert_to_array(rows)
155
290
  end
156
291
 
157
292
  private