ansi 1.4.1 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- # = BBCode
1
+ # BBCode
2
2
  #
3
3
  # Copyright (c) 2002 Thomas-Ivo Heinen
4
4
  #
@@ -9,31 +9,26 @@
9
9
  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10
10
  # FOR A PARTICULAR PURPOSE.
11
11
 
12
+ #
12
13
  module ANSI
13
14
 
14
- # = BBCode
15
- #
15
+ # TODO: Integrate BBCode with Code module.
16
+
16
17
  # The BBCode module helps ease the separation of core and frontend with the
17
18
  # core (or submodules) being still able to say, what colors shall be used
18
19
  # in it's responses. This is achieved by encoding formatting information
19
20
  # using the BBCode tokens. This enables you to "pipe" layout information
20
- # such as colors, style, fonttype, size and alignment through the core to
21
+ # such as colors, style, font, size and alignment through the core to
21
22
  # the frontend.
22
23
  #
23
24
  # Additionally it converts markups/codes between ANSI, HTML and BBCode
24
25
  # almost freely ;)
25
26
  #
26
- # == Usage
27
- #
28
27
  # # Converting a bbcode string to ANSI and XHTML
29
- #
30
28
  # str = "this is [COLOR=red]red[/COLOR], this is [B]bold[/B]"
31
29
  # print( BBCode.bbcode_to_ansi(str) )
32
30
  # print( BBCode.bbcode_to_html(str) )
33
31
  #
34
- #--
35
- # TODO: integrate with Code module.
36
- #++
37
32
  module BBCode
38
33
 
39
34
  ## ANSIname => ANSIcode LUT
@@ -0,0 +1,50 @@
1
+ require 'ansi/code'
2
+
3
+ module ANSI
4
+
5
+ # ANSI::Chain was inspired by Kazuyoshi Tlacaelel's Isna library.
6
+ #
7
+ class Chain
8
+
9
+ #
10
+ def initialize(string)
11
+ @string = string.to_s
12
+ @codes = []
13
+ end
14
+
15
+ #
16
+ attr :string
17
+
18
+ #
19
+ attr :codes
20
+
21
+ #
22
+ def method_missing(s, *a, &b)
23
+ if ANSI::CHART.key?(s)
24
+ @codes << s
25
+ self
26
+ else
27
+ super(s, *a, &b)
28
+ end
29
+ end
30
+
31
+ #
32
+ def to_s
33
+ if codes.empty?
34
+ result = @string
35
+ else
36
+ result = Code.ansi(@string, *codes)
37
+ codes.clear
38
+ end
39
+ result
40
+ end
41
+
42
+ #
43
+ def to_str
44
+ to_s
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
@@ -19,6 +19,7 @@ module ANSI
19
19
  :slow_blink => 5,
20
20
  :rapid => 6,
21
21
  :rapid_blink => 6,
22
+ :invert => 7,
22
23
  :inverse => 7,
23
24
  :reverse => 7,
24
25
  :negative => 7,
@@ -17,6 +17,8 @@ module ANSI
17
17
  # NOTE: This has no effect of methods that return ANSI codes.
18
18
  $ansi = true
19
19
 
20
+ # TODO: up, down, right, left, etc could have yielding methods too?
21
+
20
22
  # ANSI Codes
21
23
  #
22
24
  # Ansi::Code module makes it very easy to use ANSI codes.
@@ -32,10 +34,6 @@ module ANSI
32
34
  #
33
35
  # See {ANSI::Code::CHART} for list of all supported codes.
34
36
  #
35
- #--
36
- # TODO: up, down, right, left, etc could have yielding methods too?
37
- #++
38
-
39
37
  module Code
40
38
  extend self
41
39
 
@@ -235,9 +233,13 @@ module ANSI
235
233
 
236
234
  return string unless $ansi
237
235
 
238
- code(*codes) + string + ENDCODE
236
+ c = code(*codes)
237
+
238
+ c + string.gsub(ENDCODE, ENDCODE + c) + ENDCODE
239
239
  end
240
240
 
241
+ # TODO: Allow selective removal using *codes argument?
242
+
241
243
  # Remove ANSI codes from string or block value.
242
244
  #
243
245
  # @param [String]
@@ -246,9 +248,6 @@ module ANSI
246
248
  # @return [String]
247
249
  # String wrapped ANSI code.
248
250
  #
249
- #--
250
- # TODO: Allow selective removal using *codes argument?
251
- #++
252
251
  def unansi(string=nil) #:yield:
253
252
  if block_given?
254
253
  string = yield.to_s
@@ -3,32 +3,47 @@ require 'ansi/terminal'
3
3
 
4
4
  module ANSI
5
5
 
6
+ #
6
7
  class Columns
7
8
 
8
9
  # Create a column-based layout.
9
10
  #
10
- # list - Multiline String or Array of strings to columnize
11
+ # @param [String,Array] list
12
+ # Multiline String or Array of strings to columnize.
11
13
  #
12
- # options[:columns] - number of columns
13
- # options[:align] - align :left or :right
14
- # options[:padding] - space to add to each cell
14
+ # @param [Hash] options
15
+ # Options to customize columnization.
16
+ #
17
+ # @option options [Fixnum] :columns
18
+ # Number of columns.
19
+ #
20
+ # @option options [Symbol] :align
21
+ # Column alignment, either :left, :right or :center.
22
+ #
23
+ # @option options [String,Fixnum] :padding
24
+ # String or number or spaces to append to each column.
15
25
  #
16
26
  # The +format+ block MUST return ANSI codes.
17
27
  def initialize(list, options={}, &format)
18
28
  self.list = list
19
29
 
20
- @columns = options[:columns]
21
- @padding = options[:padding] || 1
22
- @align = options[:align]
23
- #@ansi = [options[:ansi]].flatten
24
- @format = format
30
+ self.columns = options[:columns] || options[:cols]
31
+ self.padding = options[:padding] || 1
32
+ self.align = options[:align] || :left
33
+ #self.ansi = options[:ansi]
34
+ self.format = format
25
35
 
26
- @columns = nil if @columns == 0
36
+ #@columns = nil if @columns == 0
37
+ end
38
+
39
+ #
40
+ def inspect
41
+ "#<#{self.class}:#{object_id} #{list.inspect} x #{columns}>"
27
42
  end
28
43
 
29
44
  # List layout into columns. Each new line is taken to be
30
45
  # a row-column cell.
31
- attr_accessor :list
46
+ attr :list
32
47
 
33
48
  def list=(list)
34
49
  case list
@@ -41,38 +56,80 @@ module ANSI
41
56
 
42
57
  # Default number of columns to display. If nil then the number
43
58
  # of coumns is estimated from the size of the terminal.
44
- attr_accessor :columns
59
+ attr :columns
60
+
61
+ # Set column count ensuring value is either an integer or nil.
62
+ # The the value given is zero, it will be taken to mean the same
63
+ # as nil, which means fit-to-screen.
64
+ def columns=(integer)
65
+ integer = integer.to_i
66
+ @columns = (integer.zero? ? nil : integer)
67
+ end
45
68
 
46
69
  # Padding size to apply to cells.
47
- attr_accessor :padding
70
+ attr :padding
71
+
72
+ # Set padding to string or number (of spaces).
73
+ def padding=(pad)
74
+ case pad
75
+ when Numeric
76
+ @padding = ' ' * pad.to_i
77
+ else
78
+ @padding = pad.to_s
79
+ end
80
+ end
48
81
 
49
82
  # Alignment to apply to cells.
50
- attr_accessor :align
83
+ attr :align
84
+
85
+ # Set alignment ensuring value is a symbol.
86
+ #
87
+ # @param [Symbol] Either `:right`, `:left` or `:center`.
88
+ def align=(symbol)
89
+ symbol = symbol.to_sym
90
+ raise ArgumentError, "invalid alignment -- #{symbol.inspect}" \
91
+ unless [:left, :right, :center].include?(symbol)
92
+ @align = symbol
93
+ end
51
94
 
52
95
  # Formating to apply to cells.
53
- attr_accessor :format
96
+ attr :format
97
+
98
+ # Set formatting procedure. The procedure must return
99
+ # ANSI codes, suitable for passing to String#ansi method.
100
+ def format=(procedure)
101
+ @format = procedure ? procedure.to_proc : nil
102
+ end
103
+
104
+ # TODO: Should #to_s also take options and formatting block?
105
+ # Maybe instead have hoin take all these and leave #to_s bare.
54
106
 
55
107
  # Return string in column layout. The number of columns is determined
56
108
  # by the `columns` property or overriden by +cols+ argument.
57
- #--
58
- # TODO: Allow #to_s to take options and formating block?
59
- #++
60
109
  def to_s(cols=nil)
61
110
  to_s_columns(cols || columns)
62
111
  end
63
112
 
64
- private
113
+ #
114
+ def join(cols=nil)
115
+ to_s_columns(cols || columns)
116
+ end
117
+
118
+ private
65
119
 
66
120
  # Layout string lines into columns.
67
121
  #
68
- # TODO: put in empty strings for blank cells
122
+ # @todo Put in empty strings for blank cells.
123
+ # @todo Centering look like it's off by one to the right.
124
+ #
69
125
  def to_s_columns(columns=nil)
70
126
  lines = list.to_a
71
127
  count = lines.size
72
128
  max = lines.map{ |l| l.size }.max
129
+
73
130
  if columns.nil?
74
131
  width = Terminal.terminal_width
75
- columns = (width / (max + padding)).to_i
132
+ columns = (width / (max + padding.size)).to_i
76
133
  end
77
134
 
78
135
  rows = []
@@ -83,12 +140,12 @@ module ANSI
83
140
  (rows[index % mod] ||=[]) << line.strip
84
141
  end
85
142
 
86
- pad = " " * padding
143
+ pad = padding
87
144
  tmp = template(max, pad)
88
145
  str = ""
89
146
  rows.each_with_index do |row, ri|
90
147
  row.each_with_index do |cell, ci|
91
- ansi_codes = ansi_formating(cell, ci, ri)
148
+ ansi_codes = ansi_formatting(cell, ci, ri)
92
149
  if ansi_codes.empty?
93
150
  str << (tmp % cell)
94
151
  else
@@ -102,10 +159,11 @@ module ANSI
102
159
  end
103
160
 
104
161
  # Aligns the cell left or right.
105
- #
106
- # TODO: Handle centered alignment.
107
162
  def template(max, pad)
108
163
  case align
164
+ when :center, 'center'
165
+ offset = " " * (max / 2)
166
+ "#{offset}%#{max}s#{offset}#{pad}"
109
167
  when :right, 'right'
110
168
  "%#{max}s#{pad}"
111
169
  else
@@ -113,8 +171,8 @@ module ANSI
113
171
  end
114
172
  end
115
173
 
116
- # Used to apply ANSI formating to each cell.
117
- def ansi_formating(cell, col, row)
174
+ # Used to apply ANSI formatting to each cell.
175
+ def ansi_formatting(cell, col, row)
118
176
  if @format
119
177
  case @format.arity
120
178
  when 0
@@ -1,10 +1,17 @@
1
1
  module ANSI
2
2
 
3
+ require 'ansi/chart'
4
+
3
5
  # Converts {CHART} and {SPECIAL_CHART} entries into constants.
6
+ # So for example, the CHART entry for :red becomes:
7
+ #
8
+ # ANSI::Constants::RED #=> "\e[31m"
9
+ #
10
+ # The ANSI Constants are include into ANSI::Code and can be included
11
+ # any where will they would be of use.
12
+ #
4
13
  module Constants
5
14
 
6
- require 'ansi/chart'
7
-
8
15
  CHART.each do |name, code|
9
16
  const_set(name.to_s.upcase, "\e[#{code}m")
10
17
  end
@@ -1,9 +1,15 @@
1
1
  require 'ansi/code'
2
+ require 'ansi/chain'
2
3
 
3
4
  class ::String
5
+
4
6
  #
5
7
  def ansi(*codes)
6
- ANSI::Code.ansi(self, *codes)
8
+ if codes.empty?
9
+ ANSI::Chain.new(self)
10
+ else
11
+ ANSI::Code.ansi(self, *codes)
12
+ end
7
13
  end
8
14
 
9
15
  #
@@ -2,9 +2,33 @@ require 'ansi/code'
2
2
 
3
3
  module ANSI
4
4
 
5
- # Diff can produced a colorized difference of two string or objects.
5
+ # Diff produces colorized differences of two string or objects.
6
+ #
6
7
  class Diff
7
8
 
9
+ # Highlights the differnce between two strings.
10
+ #
11
+ # This class method is equivalent to calling:
12
+ #
13
+ # ANSI::Diff.new(object1, object2).to_a
14
+ #
15
+ def self.diff(object1, object2, options={})
16
+ new(object1, object2, options={}).to_a
17
+ end
18
+
19
+ # Setup new Diff object. If the objects given are not Strings
20
+ # and do not have `#to_str` defined to coerce them to such, then
21
+ # their `#inspect` methods are used to convert them to strings
22
+ # for comparison.
23
+ #
24
+ # @param [Object] object1
25
+ # First object to compare.
26
+ #
27
+ # @param [Object] object2
28
+ # Second object to compare.
29
+ #
30
+ # @param [Hash] options
31
+ # Options for contoller the way difference is shown. (Not yet used.)
8
32
  #
9
33
  def initialize(object1, object2, options={})
10
34
  @object1 = convert(object1)
@@ -13,25 +37,56 @@ module ANSI
13
37
  @diff1, @diff2 = diff_string(@object1, @object2)
14
38
  end
15
39
 
16
- #
40
+ # Returns the first object's difference string.
17
41
  def diff1
18
42
  @diff1
19
43
  end
20
44
 
21
- #
45
+ # Returns the second object's difference string.
22
46
  def diff2
23
47
  @diff2
24
48
  end
25
49
 
50
+ # Returns both first and second difference strings separated by a
51
+ # new line character.
26
52
  #
53
+ # @todo Should we use `$/` record separator instead?
54
+ #
55
+ # @return [String] Joined difference strings.
27
56
  def to_s
28
57
  "#{@diff1}\n#{@diff2}"
29
58
  end
30
59
 
31
- private
60
+ # Returns both first and second difference strings separated by a
61
+ # the given `separator`. The default is `$/`, the record separator.
62
+ #
63
+ # @param [String] separator
64
+ # The string to use as the separtor between the difference strings.
65
+ #
66
+ # @return [String] Joined difference strings.
67
+ def join(separator=$/)
68
+ "#{@diff1}#{separator}#{@diff2}"
69
+ end
70
+
71
+ # Returns the first and second difference strings in an array.
72
+ #
73
+ # @return [Array] Both difference strings.
74
+ def to_a
75
+ [diff1, diff2]
76
+ end
77
+
78
+ private
32
79
 
33
80
  # Take two plain strings and produce colorized
34
81
  # versions of each highlighting their differences.
82
+ #
83
+ # @param [String] string1
84
+ # First string to compare.
85
+ #
86
+ # @param [String] string2
87
+ # Second string to compare.
88
+ #
89
+ # @return [Array<String>] The two difference strings.
35
90
  def diff_string(string1, string2)
36
91
  compare(string1, string2)
37
92
  end
@@ -52,7 +107,16 @@ module ANSI
52
107
  # Rotation of colors for diff output.
53
108
  COLORS = [:red, :yellow, :magenta]
54
109
 
110
+ # Take two plain strings and produce colorized
111
+ # versions of each highlighting their differences.
55
112
  #
113
+ # @param [String] string1
114
+ # First string to compare.
115
+ #
116
+ # @param [String] string2
117
+ # Second string to compare.
118
+ #
119
+ # @return [Array<String>] The two difference strings.
56
120
  def compare(x, y)
57
121
  c = common(x, y)
58
122
  a = x.dup
@@ -70,7 +134,8 @@ module ANSI
70
134
  return a, b
71
135
  end
72
136
 
73
- #
137
+ # Oh, I should have documented this will I knew what the
138
+ # hell it was doing ;)
74
139
  def common(x,y)
75
140
  c = lcs(x, y)
76
141
 
@@ -99,24 +164,7 @@ module ANSI
99
164
  [l, c, r].flatten.reject{ |s| s.empty? }
100
165
  end
101
166
 
102
- #
103
- def lcs_size(s1, s2)
104
- num=Array.new(s1.size){Array.new(s2.size)}
105
- len,ans=0
106
- s1.scan(/./).each_with_index do |l1,i |
107
- s2.scan(/./).each_with_index do |l2,j |
108
- unless l1==l2
109
- num[i][j]=0
110
- else
111
- (i==0 || j==0)? num[i][j]=1 : num[i][j]=1 + num[i-1][j-1]
112
- len = ans = num[i][j] if num[i][j] > len
113
- end
114
- end
115
- end
116
- ans
117
- end
118
-
119
- #
167
+ # Least common string.
120
168
  def lcs(s1, s2)
121
169
  res=""
122
170
  num=Array.new(s1.size){Array.new(s2.size)}
@@ -145,6 +193,23 @@ module ANSI
145
193
  res
146
194
  end
147
195
 
196
+ # Hmm... is this even useful?
197
+ def lcs_size(s1, s2)
198
+ num=Array.new(s1.size){Array.new(s2.size)}
199
+ len,ans=0,0
200
+ s1.scan(/./).each_with_index do |l1,i |
201
+ s2.scan(/./).each_with_index do |l2,j |
202
+ unless l1==l2
203
+ num[i][j]=0
204
+ else
205
+ (i==0 || j==0)? num[i][j]=1 : num[i][j]=1 + num[i-1][j-1]
206
+ len = ans = num[i][j] if num[i][j] > len
207
+ end
208
+ end
209
+ end
210
+ ans
211
+ end
212
+
148
213
  end
149
214
 
150
215
  end