rfs 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,76 +10,62 @@ class Array
10
10
  end
11
11
 
12
12
  def rows(width = 80, spaces = 2, spacer = ' ')
13
- return '' if length == 0
14
- best = nil
15
- bestcw = nil
16
- sorted = self # changed my mind: don't sort
17
-
18
- 1.upto(width) do |columns|
19
- space = spacer.length * spaces * (columns - 1)
20
- break if columns + space > width
21
- t = []
22
- rows = []
23
- cw = [0] * columns
24
- result = sorted.each do |item|
25
- if t.length == columns
26
- break :fail unless check_cols cw, rows, t, width, space, columns
27
- t = []
13
+ results = row_col(width, spaces, spacer) do |array, cols, empty_element, max|
14
+ r = []
15
+ stat = :ok
16
+ begin
17
+ s = array.slice!(0, cols)
18
+ if max
19
+ break :fail if :fail == s.inject(0) do |a, b|
20
+ c = a + b
21
+ if c > max
22
+ stat = :fail
23
+ break :fail
24
+ else
25
+ c
26
+ end
27
+ end
28
28
  end
29
- t << item.to_s
30
- end
31
- t += [''] * (columns - t.length)
32
- unless result == :fail
33
- result = :fail unless check_cols cw, rows, t, width, space, columns
34
- end
35
- if result != :fail
36
- best = rows
37
- bestcw = cw
29
+ r << s
30
+ end until array == []
31
+ next :fail if stat == :fail
32
+ l = r.last.length
33
+ if l == 0
34
+ r.pop
35
+ elsif l < cols
36
+ r.push(r.pop + [empty_element] * (cols - l))
38
37
  end
38
+ [r, r.transpose]
39
39
  end
40
- fs = bestcw.collect {|w| "%#{w}-s" }.join(spacer * spaces)
41
- best.collect {|row| format(fs, *row) }.join "\n"
40
+ row_col_format(spaces, spacer, *results)
42
41
  end
43
-
42
+
44
43
  def columns(width = 80, spaces = 2, spacer = ' ')
45
- return '' if length == 0
46
- best = nil
47
- bestcw = nil
48
- sorted = self # changed my mind: don't sort
49
-
50
- 1.upto(width) do |columns|
51
- space = spacer.length * spaces * (columns - 1)
52
- rows = []
53
- cols = []
54
- cw = [0] * columns
55
- col_len = length / columns
56
- col_len += 1 if length > (columns * col_len)
57
-
58
- temp = nil
59
- if length % col_len > 0
60
- temp = sorted + ([''] * (col_len - length % col_len))
61
- else
62
- temp = sorted
63
- end
64
-
65
- columns.times do |c|
66
- t = temp[(col_len * c)...(col_len * (c + 1))]
67
- cols << t
44
+ results = row_col(width, spaces, spacer) do |array, cols, empty_element|
45
+ len = array.length
46
+ col_len = len / cols
47
+ if len > (cols * col_len)
48
+ col_len += 1
49
+ if col_len * cols - len >= col_len
50
+ fail = true
51
+ next :fail
52
+ end
68
53
  end
69
- next if cols.last == [] or cols.last == nil
70
-
71
- cols = cols.transpose
72
- result = cols.each do |row|
73
- break :fail unless check_cols cw, rows, row, width, space, columns
54
+ if len % col_len > 0
55
+ array += ([empty_element] * (col_len - length % col_len))
74
56
  end
75
- if result != :fail
76
- best = rows
77
- bestcw = cw
57
+ col_data = []
58
+ cols.times do |c|
59
+ col_data << array.slice!(0, col_len)
78
60
  end
79
- break if col_len == 1
80
- end
81
- fs = bestcw.collect {|w| "%#{w}-s" }.join(spacer * spaces)
82
- best.collect {|row| format(fs, *row) }.join "\n"
61
+ #if col_data.last == [] # or col_data.last == nil
62
+ ## shouldn't get here anymore...
63
+ #:fail
64
+ #else
65
+ [col_data.transpose, col_data]
66
+ #end
67
+ end
68
+ row_col_format(spaces, spacer, *results)
83
69
  end
84
70
 
85
71
  def pc(w = 130, s = 2, sr = ' ')
@@ -89,16 +75,39 @@ class Array
89
75
  def pr(w = 130, s = 2, sr = ' ')
90
76
  puts sort.rows(w, s, sr)
91
77
  end
92
- end
93
78
 
94
- #refactorings
95
- class Array
96
- private
97
- def check_cols(cw, rows, t, width, space, columns)
98
- idx = 0
99
- cw.collect! {|w| r = (t[idx].length > w ? t[idx].length : w); idx += 1; r }
100
- row_width = cw.inject(0){|tot, n| tot + n} + space
101
- rows << t
102
- (row_width < width) || columns == 1
79
+ protected
80
+ def row_col(width, spaces, spacer)
81
+ return '', 1, [width] if length == 0
82
+ maxlen = 0
83
+ minlen = width
84
+ lengths = collect do |item|
85
+ len = item.to_s.length
86
+ maxlen = len if len > maxlen
87
+ minlen = len if len < minlen
88
+ len
89
+ end
90
+ return self, 1, [width] if maxlen > width or length == 1
91
+ best_col_count = nil
92
+ best_col_widths = nil
93
+ max_possible_cols = width / (spaces * spacer.length + minlen)
94
+ 2.upto(max_possible_cols) do |column_count|
95
+ space = spacer.length * spaces * (column_count - 1)
96
+ row_data, column_data = result = yield(lengths.clone, column_count, 0, width - space)
97
+ next if result == :fail
98
+ col_widths = column_data.collect {|col| col.max }
99
+ total_width = col_widths.inject(0) {|a, b| a + b} + space
100
+ if total_width <= width
101
+ best_col_count = column_count
102
+ best_col_widths = col_widths
103
+ end
104
+ end
105
+ return yield(self.clone, best_col_count, '').first, best_col_count, best_col_widths
106
+ end
107
+
108
+ def row_col_format(spaces, spacer, row_data, col_count, col_widths)
109
+ fs = col_widths.collect {|w| "%#{w}-s" }.join(spacer * spaces)
110
+ row_data.collect {|row| format(fs, *row).rstrip }.join("\n")
103
111
  end
112
+
104
113
  end
@@ -1,5 +1,5 @@
1
1
 
2
- # load is not currently thread safe.
2
+ # load is not currently thread safe because of the method of recursion protection used.
3
3
  class FileLines < Array
4
4
  def initialize(fn)
5
5
  @fn = fn
@@ -70,11 +70,15 @@ class MatchData
70
70
  # Interpolates %n to the corresponding capture.
71
71
  def sub(repl, capture_num = 1)
72
72
  cn = capture_num || 1
73
- t = repl.clone
73
+ replace_capture self[cn] ? cn : 0, interpolate(repl)
74
+ end
75
+
76
+ def interpolate(s)
77
+ t = s.clone
74
78
  to_a[1..-1].each_with_index do |m, i|
75
79
  t.gsub!("%#{i + 1}", m ? m : '')
76
80
  end
77
- replace_capture self[cn] ? cn : 0, t
81
+ t
78
82
  end
79
83
  end
80
84
 
@@ -3,7 +3,7 @@ require 'innate/regexp'
3
3
  class Regexp
4
4
  # All groups are non-capturing!
5
5
  def self.ROMAN_PATTERN
6
- '(?:M{0,4})(?:C[DM]|D?C{0,3})(?:X[LC]|L?X{0,3})(?:I[VX]|V?I{0,3})'
6
+ '(?=[MCDLXVI])(?:M{0,4})(?:C[DM]|D?C{0,3})(?:X[LC]|L?X{0,3})(?:I[VX]|V?I{0,3})'
7
7
  end
8
8
 
9
9
  def self.ROMAN
@@ -16,7 +16,8 @@ class Regexp
16
16
  end
17
17
  end
18
18
 
19
-
19
+ class RomanNumeralError < RuntimeError
20
+ end
20
21
 
21
22
  class String
22
23
  def roman_numeral?
@@ -32,7 +33,7 @@ class String
32
33
  end
33
34
 
34
35
  def roman_to_i
35
- raise "#{self} is not a valid roman numeral." unless roman_numeral?
36
+ raise RomanNumeralError.new("#{self} is not a valid roman numeral.") unless roman_numeral?
36
37
  s = upcase
37
38
  values = { ?M => 1000, ?D => 500, ?C => 100, ?L => 50, ?X => 10, ?V => 5, ?I => 1 }
38
39
  value = result = 0
@@ -47,8 +48,8 @@ end
47
48
 
48
49
  class Fixnum
49
50
  def roman
50
- raise 'There is no Roman representation for numbers below 1.' if self < 1
51
- raise 'There is no Roman representation for numbers above 4999.' if self > 4999
51
+ raise RomanNumeralError.new('There is no Roman representation for numbers below 1.') if self < 1
52
+ raise RomanNumeralError.new('There is no Roman representation for numbers above 4999.') if self > 4999
52
53
  elements = {1000 => 'M',500 => 'D',100 => 'C',50 => 'L',10 => 'X',5 => 'V',1 => 'I'}
53
54
  values = [1000, 500, 100, 50, 10, 5, 1]
54
55
  r = ''
@@ -1,5 +1,6 @@
1
1
  require 'test/unit'
2
2
  require 'innate/array'
3
+ require 'cursor/indexed'
3
4
 
4
5
  class TestArray < Test::Unit::TestCase
5
6
  def test_match_string
@@ -35,26 +36,29 @@ class TestArray < Test::Unit::TestCase
35
36
  to_r to_s to_sym truncate type untaint
36
37
  upto zero? | ~}
37
38
 
38
- s = "% & * ** + +@ \n" +
39
- "- -@ / < << <= \n" +
40
- "<=> == === =~ > >= \n" +
41
- ">> [] ^ __id__ __send__ abs \n" +
42
- "between? ceil chr class clone coerce \n" +
43
- "denominator display div divmod downto dup \n" +
44
- "eql? equal? extend floor freeze frozen? \n" +
45
- "gcd gcd2 gcdlcm hash id id2name \n" +
46
- "inspect instance_eval instance_of? instance_variable_get instance_variable_set instance_variables \n" +
47
- "integer? is_a? kind_of? lcm method methods \n" +
48
- "modulo next nil? nonzero? numerator object_id \n" +
49
- "power! prec prec_f prec_i private_methods protected_methods \n" +
50
- "public_methods quo rdiv remainder require require_gem \n" +
51
- "require_gem_with_options respond_to? round rpower send singleton_method_added\n" +
52
- "singleton_methods size step succ taint tainted? \n" +
53
- "times to_a to_bn to_f to_i to_int \n" +
54
- "to_r to_s to_sym truncate type untaint \n" +
55
- "upto zero? | ~ "
39
+ s = ["% & * ** + +@\n",
40
+ "- -@ / < << <=\n",
41
+ "<=> == === =~ > >=\n",
42
+ ">> [] ^ __id__ __send__ abs\n",
43
+ "between? ceil chr class clone coerce\n",
44
+ "denominator display div divmod downto dup\n",
45
+ "eql? equal? extend floor freeze frozen?\n",
46
+ "gcd gcd2 gcdlcm hash id id2name\n",
47
+ "inspect instance_eval instance_of? instance_variable_get instance_variable_set instance_variables\n",
48
+ "integer? is_a? kind_of? lcm method methods\n",
49
+ "modulo next nil? nonzero? numerator object_id\n",
50
+ "power! prec prec_f prec_i private_methods protected_methods\n",
51
+ "public_methods quo rdiv remainder require require_gem\n",
52
+ "require_gem_with_options respond_to? round rpower send singleton_method_added\n",
53
+ "singleton_methods size step succ taint tainted?\n",
54
+ "times to_a to_bn to_f to_i to_int\n",
55
+ "to_r to_s to_sym truncate type untaint\n",
56
+ "upto zero? | ~"].to_cursor
57
+
58
+ a.rows(130, 2, ' ').each_line do |l|
59
+ assert_equal s.read1next, l
60
+ end
56
61
 
57
- assert_equal s, a.rows(130, 2, ' ')
58
62
  end
59
63
 
60
64
  def test_columns
@@ -77,22 +81,54 @@ class TestArray < Test::Unit::TestCase
77
81
  to_r to_s to_sym truncate type untaint
78
82
  upto zero? | ~}
79
83
 
80
- s = "% === clone gcd kind_of? private_methods singleton_methods to_sym \n" +
81
- "& =~ coerce gcd2 lcm protected_methods size truncate\n" +
82
- "* > denominator gcdlcm method public_methods step type \n" +
83
- "** >= display hash methods quo succ untaint \n" +
84
- "+ >> div id modulo rdiv taint upto \n" +
85
- "+@ [] divmod id2name next remainder tainted? zero? \n" +
86
- "- ^ downto inspect nil? require times | \n" +
87
- "-@ __id__ dup instance_eval nonzero? require_gem to_a ~ \n" +
88
- "/ __send__ eql? instance_of? numerator require_gem_with_options to_bn \n" +
89
- "< abs equal? instance_variable_get object_id respond_to? to_f \n" +
90
- "<< between? extend instance_variable_set power! round to_i \n" +
91
- "<= ceil floor instance_variables prec rpower to_int \n" +
92
- "<=> chr freeze integer? prec_f send to_r \n" +
93
- "== class frozen? is_a? prec_i singleton_method_added to_s "
84
+ s = ["% === clone gcd kind_of? private_methods singleton_methods to_sym\n",
85
+ "& =~ coerce gcd2 lcm protected_methods size truncate\n",
86
+ "* > denominator gcdlcm method public_methods step type\n",
87
+ "** >= display hash methods quo succ untaint\n",
88
+ "+ >> div id modulo rdiv taint upto\n",
89
+ "+@ [] divmod id2name next remainder tainted? zero?\n",
90
+ "- ^ downto inspect nil? require times |\n",
91
+ "-@ __id__ dup instance_eval nonzero? require_gem to_a ~\n",
92
+ "/ __send__ eql? instance_of? numerator require_gem_with_options to_bn\n",
93
+ "< abs equal? instance_variable_get object_id respond_to? to_f\n",
94
+ "<< between? extend instance_variable_set power! round to_i\n",
95
+ "<= ceil floor instance_variables prec rpower to_int\n",
96
+ "<=> chr freeze integer? prec_f send to_r\n",
97
+ "== class frozen? is_a? prec_i singleton_method_added to_s"].to_cursor
98
+
99
+ a.columns(130, 2, ' ').each_line do |l|
100
+ assert_equal s.read1next, l
101
+ end
102
+ end
94
103
 
95
- assert_equal s, a.columns(130, 2, ' ')
96
- end
104
+ def test_empty_array
105
+ a = []
106
+ assert_equal '', a.columns(80, 2, ' ')
107
+ assert_equal '', a.rows(80, 2, ' ')
108
+ end
109
+
110
+ def test_one_element
111
+ a = ['hello']
112
+ assert_equal 'hello', a.columns(80, 2, ' ')
113
+ assert_equal 'hello', a.rows(80, 2, ' ')
114
+ end
97
115
 
116
+ def test_long_element
117
+ a = ['hello', 'this is a rather long one']
118
+ assert_equal "hello\nthis is a rather long one", a.columns(15, 2, ' ')
119
+ assert_equal "hello\nthis is a rather long one", a.rows(15, 2, ' ')
120
+ end
121
+
122
+
123
+ def test_nil_array
124
+ a = [nil]
125
+ assert_equal '', a.columns(80, 2, ' ')
126
+ assert_equal '', a.rows(80, 2, ' ')
127
+ end
128
+
129
+ def test_array_with_nil
130
+ a = [1, nil, 3, nil]
131
+ assert_equal '1 3', a.columns(80, 2, ' ')
132
+ assert_equal '1 3', a.rows(80, 2, ' ')
133
+ end
98
134
  end
@@ -50,5 +50,9 @@ class TestRoman < Test::Unit::TestCase
50
50
  (/valiant(roman)soldier/i).interpolate_roman.to_s)
51
51
  end
52
52
 
53
+ def test_roman_regexp
54
+ assert_equal('mcmxiv', Regexp.new("(#{Regexp.ROMAN_PATTERN})", Regexp::IGNORECASE).match('the war of mcmxiv.')[1])
55
+ end
56
+
53
57
  end
54
58
 
@@ -28,37 +28,36 @@ module Options
28
28
  def opt(sym, *types)
29
29
  v = @options[sym]
30
30
  if v
31
- unless types.empty?
32
- if types.find {|t| v.is_a? t}
33
- if block_given?
34
- yield v
35
- else
36
- v
37
- end
38
- else
39
- raise BadOptionValueError.new(sym, v.class, types)
40
- end
41
- else
42
- if block_given?
43
- yield v
44
- else
45
- v
46
- end
31
+ if !types.empty? and !types.find {|t| v.is_a? t}
32
+ raise BadOptionValueError.new(sym, v.class, types)
47
33
  end
48
34
  elsif !types.include? NilClass
49
35
  raise MissingOptionError.new(sym)
50
36
  end
37
+ if block_given?
38
+ yield v
39
+ else
40
+ v
41
+ end
51
42
  end
52
43
 
53
44
  def opt_if(sym, *types)
54
- begin
55
- v = opt sym, *types
56
- rescue OptionError
45
+ v = @options[sym]
46
+ r = if v
47
+ if types.empty?
48
+ :ok
49
+ elsif types.find {|t| v.is_a? t}
50
+ :ok
51
+ end
52
+ elsif types.include? NilClass
53
+ :ok
57
54
  end
58
- if block_given?
59
- yield v if v
60
- else
61
- v
55
+ if r == :ok
56
+ if block_given?
57
+ yield v
58
+ else
59
+ v
60
+ end
62
61
  end
63
62
  end
64
63
  end
@@ -1,7 +1,8 @@
1
-
2
1
  module Provider
3
2
  module Folder
4
3
  class Tree
4
+ include Enumerable
5
+
5
6
  def initialize(tree)
6
7
  @tree = tree
7
8
  end
@@ -25,6 +26,7 @@ module Provider
25
26
 
26
27
  module File
27
28
  class Base
29
+ attr_reader :folders
28
30
  def initialize(folder_provider)
29
31
  @folders = folder_provider
30
32
  @iterator = :each
@@ -72,6 +74,7 @@ module Provider
72
74
  end
73
75
  end
74
76
 
77
+
75
78
  class Array < Base
76
79
  attr_accessor :files
77
80
 
@@ -87,6 +90,62 @@ module Provider
87
90
  end
88
91
  end
89
92
  end
93
+
94
+
95
+ ##I am decomissioning this code because
96
+ ##it did not result in any performance
97
+ ##improvement. Upon profiling the program
98
+ ##it turns out (to my surprise) that
99
+ ##retrieving file listings was not a
100
+ ##bottleneck at all.
101
+ #class Cache < Base
102
+ #def initialize(file_provider)
103
+ #@fp = file_provider
104
+ #reset_cache
105
+ #end
106
+
107
+ #def reset_cache
108
+ #@fg = Generator.new(@fp)
109
+ #@cache = []
110
+ #@cache_complete = false
111
+ #end
112
+
113
+ #def each
114
+ #@cache.each do |a|
115
+ #yield a.first, a.last
116
+ #end
117
+ #unless @cache_complete
118
+ #while @fg.next?
119
+ #begin
120
+ #Thread.critical = true
121
+ #path, file = @fg.next
122
+ #@cache << [path, file]
123
+ #@cache_complete = true unless @fg.next?
124
+ #ensure
125
+ #Thread.critical = false
126
+ #end
127
+ #yield path, file
128
+ #end
129
+ #end
130
+ #end
131
+ #end
132
+
133
+
134
+ #class EnumerableFoldersCache < Cache
135
+ #def initialize(file_provider)
136
+ #@folders = []
137
+ #super
138
+ #end
139
+
140
+ #def each(&b)
141
+ #f = @fp.folders.collect
142
+ #unless f == @folders
143
+ #reset_cache
144
+ #@folders = f
145
+ #end
146
+ #super
147
+ #end
148
+ #end
90
149
  end
91
150
  end
92
151