rio 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/ChangeLog +225 -0
  2. data/README +12 -0
  3. data/Rakefile +1 -1
  4. data/VERSION +1 -1
  5. data/doc/ANNOUNCE +160 -71
  6. data/doc/RELEASE_NOTES +71 -2
  7. data/ex/colx.rb +1 -1
  8. data/ex/passwd_report.rb +4 -8
  9. data/ex/riocat +5 -5
  10. data/ex/riogunzip +1 -1
  11. data/ex/riogzip +6 -6
  12. data/ex/rioprompt.rb +6 -0
  13. data/lib/rio.rb +3 -13
  14. data/lib/rio/arycopy.rb +1 -1
  15. data/lib/rio/base.rb +1 -5
  16. data/lib/rio/construct.rb +75 -0
  17. data/lib/rio/constructor.rb +42 -11
  18. data/lib/rio/context.rb +1 -1
  19. data/lib/rio/context/dir.rb +50 -23
  20. data/lib/rio/context/methods.rb +5 -3
  21. data/lib/rio/{cxdir.rb → context/skip.rb} +24 -36
  22. data/lib/rio/context/stream.rb +38 -16
  23. data/lib/rio/cp.rb +24 -5
  24. data/lib/rio/dir.rb +8 -7
  25. data/lib/rio/doc/HOWTO.rb +33 -33
  26. data/lib/rio/doc/INTRO.rb +416 -256
  27. data/lib/rio/doc/MISC.rb +3 -1
  28. data/lib/rio/doc/SYNOPSIS.rb +28 -33
  29. data/lib/rio/entrysel.rb +76 -9
  30. data/lib/rio/file.rb +2 -1
  31. data/lib/rio/filter.rb +95 -0
  32. data/lib/rio/filter/closeoneof.rb +1 -1
  33. data/lib/rio/grande.rb +0 -74
  34. data/lib/rio/if.rb +2 -1
  35. data/lib/rio/if/basic.rb +1 -1
  36. data/lib/rio/if/csv.rb +1 -1
  37. data/lib/rio/if/dir.rb +1 -220
  38. data/lib/rio/if/fileordir.rb +26 -12
  39. data/lib/rio/if/grande.rb +55 -6
  40. data/lib/rio/if/grande_entry.rb +355 -0
  41. data/lib/rio/if/{methods.rb → grande_stream.rb} +69 -88
  42. data/lib/rio/if/path.rb +25 -3
  43. data/lib/rio/if/stream.rb +62 -37
  44. data/lib/rio/if/temp.rb +2 -2
  45. data/lib/rio/if/test.rb +23 -0
  46. data/lib/rio/impl/path.rb +5 -0
  47. data/lib/rio/match.rb +6 -3
  48. data/lib/rio/matchrecord.rb +50 -46
  49. data/lib/rio/{filter/chomp.rb → ops/construct.rb} +12 -20
  50. data/lib/rio/ops/create.rb +3 -0
  51. data/lib/rio/ops/dir.rb +12 -6
  52. data/lib/rio/ops/either.rb +17 -3
  53. data/lib/rio/ops/path.rb +4 -1
  54. data/lib/rio/ops/stream/input.rb +6 -1
  55. data/lib/rio/ops/stream/read.rb +1 -3
  56. data/lib/rio/{context/chomp.rb → prompt.rb} +17 -13
  57. data/lib/rio/rl/base.rb +1 -1
  58. data/lib/rio/rl/builder.rb +3 -1
  59. data/lib/rio/state.rb +7 -13
  60. data/lib/rio/stream.rb +8 -5
  61. data/lib/rio/stream/open.rb +1 -1
  62. data/lib/rio/version.rb +1 -1
  63. data/test/mswin32.rb +1 -1
  64. data/test/runtests_gem.rb +1 -1
  65. data/test/tc/all.rb +3 -0
  66. data/test/tc/copy-from.rb +13 -13
  67. data/test/tc/copy-to.rb +1 -1
  68. data/test/tc/copy.rb +1 -1
  69. data/test/tc/copydir.rb +0 -24
  70. data/test/tc/copysymlink.rb +39 -0
  71. data/test/tc/csv.rb +2 -2
  72. data/test/tc/csv2.rb +4 -4
  73. data/test/tc/misc.rb +16 -16
  74. data/test/tc/nolines.rb +26 -26
  75. data/test/tc/noqae.rb +74 -74
  76. data/test/tc/overload.rb +28 -28
  77. data/test/tc/riorl.rb +36 -0
  78. data/test/tc/selnosel.rb +36 -0
  79. data/test/tc/skip.rb +58 -0
  80. data/test/tc/skiplines.rb +42 -0
  81. data/test/tc/symlink.rb +1 -1
  82. data/test/tc/symlink0.rb +1 -1
  83. data/test/tc/temp.rb +1 -1
  84. data/test/tc/tempdir.rb +1 -1
  85. data/test/tc/testcase.rb +7 -1
  86. metadata +14 -8
  87. data/lib/rio/matchcolumns.rb +0 -266
  88. data/lib/rio/rangemath.rb +0 -44
@@ -76,6 +76,7 @@ which can be chained to a Rio method as in this example or stored in a variable.
76
76
  array = ario.readlines
77
77
 
78
78
  ario = rio('afile')
79
+
79
80
  In this case the resource specified is a relative path. After the first line
80
81
  the Rio does know or care whether it
81
82
  is a path to a file nor whether it exists. Rio provides many methods that only deal with a resource
@@ -93,6 +94,7 @@ The rio constructor can be used to specify non-file-system resources, but for th
93
94
  our discussion to paths to entities on file-systems.
94
95
 
95
96
  array = ario.readlines
97
+
96
98
  Now that we have a Rio, we can call one of its methods; in this case _readlines_. This is an example of using
97
99
  a Rio as a proxy for the builtin IO#readlines. Given the method _readlines_, the Rio opens 'afile' for reading,
98
100
  calls readlines on the resulting IO object, closes the IO object, and returns the lines read.
@@ -131,7 +133,7 @@ a second copy, we might do something like this:
131
133
  afile.rewind > rio('acopy2')
132
134
  afile.close
133
135
 
134
- Actually the 'thinking-process' of the Rio when it sees a copy-to operator is much more complex that described above.
136
+ Actually the 'thinking process' of the Rio when it sees a copy-to operator is much more complex that described above.
135
137
  If its argument had been a rio referencing a directory, it would not have opened itself for reading,
136
138
  but instead used FileUtils#cp to copy itself; if its argument had been a string, its contents would have ended up
137
139
  in the string; If its argument had been an array, its lines would been elements of that array; if its argument had
@@ -60,30 +60,37 @@ For the following assume:
60
60
  astring = ""
61
61
  anarray = []
62
62
 
63
- Copy a file into a string
64
- rio('afile') > astring
63
+ Copy or append a file to a string
64
+ rio('afile') > astring # copy
65
+ rio('afile') >> astring # append
65
66
 
66
- Copy a string into a file
67
- rio('afile') < astring
67
+ Copy or append a string to a file
68
+ rio('afile') < astring # copy
69
+ rio('afile') << astring # append
68
70
 
69
- Copy the chomped lines of a file into an array
70
- rio('afile').chomp > anarray
71
+ Copy or append the lines of a file to an array
72
+ rio('afile') > anarray
73
+ rio('afile') >> anarray
71
74
 
72
- Copy a file into another file
73
- rio('afile') > rio('another_file')
75
+ Copy or append a file to another file
76
+ rio('afile') > rio('another_file')
77
+ rio('afile') >> rio('another_file')
74
78
 
75
- Copy a file into a directory
76
- rio('afile') > rio('adir')
79
+ Copy a file to a directory
80
+ rio('adir') << rio('afile')
77
81
 
78
- Copy an entire directory structure into another directory
79
- rio('adir') > rio('another_directory')
82
+ Copy a directory structure to another directory
83
+ rio('adir') >> rio('another_directory')
80
84
 
81
- Copy a web page into a file
85
+ Copy a web-page to a file
82
86
  rio('http://rubydoc.org/') > rio('afile')
83
87
 
84
- Copy a file from a ftp server into a local file
85
- rio('ftp://host/afile.gz') > rio('afile.gz')
86
-
88
+ Ways to get the chomped lines of a file into an array
89
+ anarray = rio('afile').chomp[] # subscript operator
90
+ rio('afile').chomp > anarray # copy-to operator
91
+ anarray = rio('afile').chomp.to_a # to_a
92
+ anarray = rio('afile').chomp.readlines # IO#readlines
93
+
87
94
  Copy a gzipped file un-gzipping it
88
95
  rio('afile.gz').gzip > rio('afile')
89
96
 
@@ -102,11 +109,8 @@ Iterate over only the files in a directory
102
109
  Iterate over only the .rb files in a directory
103
110
  rio('adir').files('*.rb') { |entrio| ... }
104
111
 
105
- Iterate over only the directories in a directory
106
- rio('adir').dirs { |entrio| ... }
107
-
108
112
  Iterate over only the _dot_ files in a directory
109
- rio('adir').dirs(/^\./) { |entrio| ... }
113
+ rio('adir').files(/^\./) { |entrio| ... }
110
114
 
111
115
  Iterate over the files in a directory and its subdirectories, skipping '.svn' and 'CVS' directories
112
116
  rio('adir').norecurse(/^\.svn$/,'CVS').files { |entrio| ... }
@@ -114,24 +118,15 @@ Iterate over the files in a directory and its subdirectories, skipping '.svn' an
114
118
  Create an array of the .rb entries in a directory
115
119
  anarray = rio('adir')['*.rb']
116
120
 
117
- Iterate over the .rb files in a directory and its subdirectories
118
- rio('adir').all.files('*.rb') { |entrio| ... }
119
-
120
121
  Create an array of the .rb entries in a directory and its subdirectories
121
122
  anarray = rio('adir').all['*.rb']
122
123
 
123
- Create an array of the .rb files in a directory and its subdirectories
124
- anarray = rio('adir').all.files['*.rb']
124
+ Iterate over the .rb files in a directory and its subdirectories
125
+ rio('adir').all.files('*.rb') { |entrio| ... }
125
126
 
126
127
  Copy an entire directory structure and the .rb files within it
127
128
  rio('adir').dirs.files('*.rb') > rio('another_directory')
128
129
 
129
- Iterate over the chomped lines of a file
130
- rio('afile').chomp.lines { |line| ... }
131
-
132
- Put the chomped lines of a file into an array
133
- anarray = rio('afile').chomp.lines[]
134
-
135
130
  Iterate over the first 10 chomped lines of a file
136
131
  rio('afile').chomp.lines(0..9) { |line| ... }
137
132
 
@@ -154,10 +149,10 @@ Put chomped lines that start with 'Rio' into an array
154
149
  anarray = rio('afile').chomp[/^Rio/]
155
150
 
156
151
  Iterate over the non-empty, non-comment chomped lines of a file
157
- rio('afile').chomp.nolines(:empty?,/^\s*#/) { |line| ... }
152
+ rio('afile').chomp.skiplines(:empty?,/^\s*#/) { |line| ... }
158
153
 
159
154
  Copy the output of th ps command into an array, skipping the header line and the ps command entry
160
- rio(?-,'ps -a').nolines(0,/ps$/) > anarray
155
+ rio(?-,'ps -a').skiplines(0,/ps$/) > anarray
161
156
 
162
157
  Prompt for input and return what was typed
163
158
  ans = rio(?-).print("Type Something: ").chomp.gets
@@ -54,7 +54,7 @@ module RIO
54
54
  end
55
55
  def ===(el) self =~ el end
56
56
  abstract_method :=~
57
-
57
+
58
58
  end
59
59
  class Any < Base
60
60
  def =~(entry) true end
@@ -74,6 +74,14 @@ module RIO
74
74
  class Symbol < Base
75
75
  def =~(entry) entry.__send__(@match_to) end
76
76
  end
77
+ class And < Base
78
+ def initialize(matches)
79
+ super(matches.flatten.map { |arg| Match::Entry.create(arg) })
80
+ end
81
+ def =~(el)
82
+ (@match_to.empty? or @match_to.all? { |sel| sel =~ el })
83
+ end
84
+ end
77
85
  def create(arg)
78
86
  case arg
79
87
  when ::String then Glob.new(arg)
@@ -82,6 +90,7 @@ module RIO
82
90
  when ::Symbol then Symbol.new(arg)
83
91
  when ::TrueClass then Any.new(arg)
84
92
  when ::FalseClass then None.new(arg)
93
+ when ::Array then And.new(arg)
85
94
  else raise ArgumentError,"a String,Regexp,Proc or Symbol is required (#{arg})"
86
95
  end
87
96
  end
@@ -93,9 +102,6 @@ module RIO
93
102
  module Match
94
103
  module Entry
95
104
  class List
96
- def callstr(func,*args)
97
- self.class.to_s+'['+self.to_s+']'+'.'+func.to_s+'('+args.join(',')+')'
98
- end
99
105
  attr_reader :sym
100
106
  attr_accessor :list
101
107
  def initialize(sym,*args)
@@ -116,9 +122,14 @@ module RIO
116
122
  end
117
123
  extend Forwardable
118
124
  def_instance_delegators(:@list,:each)
125
+ def callstr(func,*args)
126
+ self.class.to_s+'['+self.to_s+']'+'.'+func.to_s+'('+args.join(',')+')'
127
+ end
119
128
  end
120
129
  class Sels < Array
121
130
  def <<(entry_list)
131
+ #p callstr('<<',entry_list)
132
+
122
133
  same_sym = self.grep(entry_list)
123
134
  if same_sym.empty?
124
135
  super
@@ -126,11 +137,59 @@ module RIO
126
137
  same_sym[0].list = entry_list.list
127
138
  end
128
139
  end
140
+ def callstr(func,*args)
141
+ self.class.to_s+'['+self.to_s+']'+'.'+func.to_s+'('+args.join(',')+')'
142
+ end
129
143
  end
130
144
  class Selector
131
- def initialize(sel,nosel)
132
- @sel = sel
133
- @nosel = nosel
145
+ attr_reader :sel,:nosel
146
+ def initialize(entry_sel)
147
+ @entry_sel = entry_sel
148
+ @sel = @nosel = nil
149
+ process_entry_sel() if @entry_sel
150
+ end
151
+ def es_args()
152
+ es = @entry_sel
153
+ es['args']
154
+ end
155
+ def something_selected?
156
+ %w[entries files dirs].any? { |k| es_args.has_key?(k) }
157
+ end
158
+ def something_skipped?
159
+ %w[skipentries skipfiles skipdirs].any? { |k| es_args.has_key?(k) }
160
+ end
161
+ def skip_type(skip_args)
162
+
163
+ end
164
+ def process_entry_sel()
165
+ ea = es_args
166
+ raise RuntimeError, "Internal error: entry_sel_args not set" unless ea
167
+ if something_selected?
168
+ @sel = Match::Entry::Sels.new
169
+ @sel << Match::Entry::List.new(:true?,*ea['entries']) if ea.has_key?('entries')
170
+ @sel << Match::Entry::List.new(:file?,*ea['files']) if ea.has_key?('files')
171
+ @sel << Match::Entry::List.new(:dir?,*ea['dirs']) if ea.has_key?('dirs')
172
+ end
173
+ if something_skipped?
174
+ @nosel = Match::Entry::Sels.new
175
+ if ea.has_key?('skipentries')
176
+ @nosel << Match::Entry::List.new(:true?,*ea['skipentries'])
177
+ end
178
+ if ea.has_key?('skipfiles')
179
+ @nosel << Match::Entry::List.new(:file?,*ea['skipfiles'])
180
+ unless ea['skipfiles'].empty? or ea.has_key?('files')
181
+ @sel ||= Match::Entry::Sels.new
182
+ @sel << Match::Entry::List.new(:file?)
183
+ end
184
+ end
185
+ if ea.has_key?('skipdirs')
186
+ @nosel << Match::Entry::List.new(:dir?,*ea['skipdirs'])
187
+ unless ea['skipdirs'].empty? or ea.has_key?('dirs')
188
+ @sel ||= Match::Entry::Sels.new
189
+ @sel << Match::Entry::List.new(:dir?)
190
+ end
191
+ end
192
+ end
134
193
  end
135
194
  def inspect()
136
195
  str = sprintf('#<Selector:0x%08x',self.object_id)
@@ -144,7 +203,7 @@ module RIO
144
203
 
145
204
  def yes?(el)
146
205
  @sel.nil? or @sel.detect { |match_entry| match_entry =~ el }
147
- # @sel.nil? or @sel.grep(el)
206
+ # @sel.nil? or @sel.grep(el)
148
207
  end
149
208
  def no?(el)
150
209
  @nosel.detect { |match_entry| match_entry =~ el } unless @nosel.nil?
@@ -155,8 +214,16 @@ module RIO
155
214
  def match?(el)
156
215
  yes?(el) and not no?(el)
157
216
  end
217
+ def callstr(func,*args)
218
+ self.class.to_s+'['+self.to_s+']'+'.'+func.to_s+'('+args.join(',')+')'
219
+ end
220
+ end
221
+ class SelectorClassic < Selector
222
+ def initialize(sel,nosel)
223
+ @sel = sel
224
+ @nosel = nosel
225
+ end
158
226
  end
159
227
  end
160
-
161
228
  end
162
229
  end
@@ -64,7 +64,8 @@ module RIO
64
64
  def each(*args,&block)
65
65
  #p "#{callstr('each',*args)} ss_type=#{ss_type?}"
66
66
  if ss_type? == 'files' and !stream_iter?
67
- sel = Match::Entry::Selector.new(cx['sel'],cx['nosel'])
67
+ #sel = Match::Entry::Selector.new(cx['sel'],cx['nosel'])
68
+ sel = Match::Entry::Selector.new(cx['entry_sel'])
68
69
  yield new_rio_cx(self) if sel.match?(self)
69
70
  else
70
71
  fstream.each(*args,&block)
@@ -0,0 +1,95 @@
1
+ #--
2
+ # ===============================================================================
3
+ # Copyright (c) 2005, Christopher Kleckner
4
+ # All rights reserved
5
+ #
6
+ # This file is part of the Rio library for ruby.
7
+ #
8
+ # Rio is free software; you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation; either version 2 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # Rio is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with Rio; if not, write to the Free Software
20
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ # ===============================================================================
22
+ #++
23
+ #
24
+ # To create the documentation for Rio run the command
25
+ # rake rdoc
26
+ # from the distribution directory. Then point your browser at the 'doc/rdoc' directory.
27
+ #
28
+ # Suggested Reading
29
+ # * RIO::Doc::SYNOPSIS
30
+ # * RIO::Doc::INTRO
31
+ # * RIO::Doc::HOWTO
32
+ # * RIO::Rio
33
+ #
34
+ # <b>Rio is pre-alpha software.
35
+ # The documented interface and behavior is subject to change without notice.</b>
36
+
37
+
38
+ module RIO
39
+ module Filter #:nodoc: all
40
+ def self.make_line_filter(sym)
41
+ module_eval %{
42
+ module #{sym.to_s.capitalize}
43
+ module IOE
44
+ def gets(*args) super.__send__(:#{sym}) end
45
+ def readline(*args) super.__send__(:#{sym}) end
46
+ def each_line(*args,&block) super { |l| yield l.__send__(:#{sym}) } end
47
+ def readlines(*args) super.map(&:#{sym}) end
48
+ end
49
+ include IOE
50
+ end
51
+ }
52
+ end
53
+ end
54
+ end
55
+ module RIO
56
+ module Cx
57
+ module Methods
58
+ require 'rio/context/cxx.rb'
59
+ def self.make_filter_methods(sym)
60
+ module_eval %{
61
+ def #{sym}(arg=true,&block)
62
+ cx['#{sym}'] = arg
63
+ add_filter(Filter::#{sym.to_s.capitalize}) if arg and self.ioh
64
+ each(&block) if block_given?
65
+ self
66
+ end
67
+ def #{sym}?() cxx?('#{sym}') end
68
+ def no#{sym}(arg=false,&block) #{sym}(arg,&block) end
69
+ }
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ module RIO
76
+ FILTER_SYMS = [:chomp, :strip, :lstrip, :rstrip]
77
+ FILTER_SYMS.each { |sym|
78
+ Filter.make_line_filter(sym)
79
+ Cx::Methods.make_filter_methods(sym)
80
+ }
81
+ module Stream
82
+ module Filters
83
+
84
+ def add_line_filters()
85
+ add_filter(Filter::Chomp) if chomp?
86
+ add_filter(Filter::Strip) if strip?
87
+ add_filter(Filter::Lstrip) if lstrip?
88
+ add_filter(Filter::Rstrip) if rstrip?
89
+ end
90
+
91
+ end
92
+ end
93
+ end
94
+
95
+ __END__
@@ -70,7 +70,7 @@ module RIO
70
70
  #p callstr('copy_stream',dst)
71
71
  close_on_eof(super)
72
72
  end
73
- def slurp()
73
+ def contents()
74
74
  close_on_eof(super)
75
75
  end
76
76
  def readlines(*args)
@@ -75,77 +75,3 @@ module RIO
75
75
 
76
76
  end
77
77
  end
78
- module RIO
79
- module Grande
80
- module Dir
81
-
82
- def each_(*args,&block)
83
- #p "#{callstr('each_',*args)} sel=#{cx['sel'].inspect} nosel=#{cx['nosel'].inspect}"
84
- sel = Match::Entry::Selector.new(cx['sel'],cx['nosel'])
85
- selfstr = (self.to_s == '.' ? nil : self.to_s)
86
- self.ioh.each do |estr|
87
- next if estr =~ /^\.(\.)?$/
88
- begin
89
- erio = new_rio_cx(selfstr ? Impl::U.join(selfstr,estr) : estr )
90
-
91
- if stream_iter?
92
- _add_stream_iter_cx(erio).each(&block) if erio.file? and sel.match?(erio)
93
- else
94
- yield _add_iter_cx(erio) if sel.match?(erio)
95
- end
96
-
97
- if cx.has_key?('all') and erio.dir?
98
- rsel = Match::Entry::Selector.new(cx['r_sel'],cx['r_nosel'])
99
- _add_recurse_iter_cx(erio).each(&block) if rsel.match?(erio)
100
- end
101
-
102
- rescue ::Errno::ENOENT, ::URI::InvalidURIError => ex
103
- $stderr.puts(ex.message+". Skipping.")
104
- end
105
- end
106
- closeoneof? ? self.close.softreset : self
107
- end
108
-
109
-
110
-
111
- private
112
-
113
- def _ss_keys() Cx::SS::ENTRY_KEYS + Cx::SS::STREAM_KEYS end
114
- CX_ALL_SKIP_KEYS = ['retrystate']
115
- def _add_recurse_iter_cx(ario)
116
- new_cx = ario.cx
117
- cx.keys.reject { |k| CX_ALL_SKIP_KEYS.include?(k) }.each { |k|
118
- new_cx.set_(k,cx[k])
119
- }
120
- ario.cx = new_cx
121
- ario
122
- end
123
- def _add_cx(ario,keys)
124
- new_cx = ario.cx
125
- keys.each {|k|
126
- next unless cx.has_key?(k)
127
- new_cx.set_(k,cx[k])
128
- }
129
- ario.cx = new_cx
130
- end
131
- CX_DIR_ITER_KEYS = %w[sel nosel]
132
- CX_STREAM_ITER_KEYS = %w[stream_rectype stream_itertype stream_sel stream_nosel]
133
- def _add_iter_cx(ario)
134
- if nostreamenum?
135
- _add_cx(ario,CX_DIR_ITER_KEYS)
136
- end
137
- _add_stream_iter_cx(ario)
138
- end
139
- def _add_stream_iter_cx(ario)
140
- _add_cx(ario,CX_STREAM_ITER_KEYS)
141
- new_cx = ario.cx
142
- if stream_iter?
143
- new_cx.set_('ss_args',cx['ss_args']) if cx.has_key?('ss_args')
144
- new_cx.set_('ss_type',cx['ss_type']) if cx.has_key?('ss_type')
145
- end
146
- ario.cx = new_cx
147
- ario
148
- end
149
- end
150
- end
151
- end