rfs 0.1 → 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.
@@ -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