wishdev-rio 0.4.3.1

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.
Files changed (296) hide show
  1. data/COPYING +341 -0
  2. data/README +81 -0
  3. data/Rakefile +281 -0
  4. data/build_doc.rb +94 -0
  5. data/doc/ANNOUNCE +159 -0
  6. data/doc/RELEASE_NOTES +308 -0
  7. data/doc/RIOIS +215 -0
  8. data/doc/generators/template/html/rio.css +428 -0
  9. data/doc/generators/template/html/rio.rb +523 -0
  10. data/doc/generators/template/html/ugly.rb +132 -0
  11. data/doc/pkg_def.rb +60 -0
  12. data/doc/rfc1738.txt +1403 -0
  13. data/doc/rfc959.txt +3933 -0
  14. data/ex/catcsv.rb +64 -0
  15. data/ex/colx.rb +8 -0
  16. data/ex/findinruby +15 -0
  17. data/ex/findruby +14 -0
  18. data/ex/passwd_report.rb +8 -0
  19. data/ex/prompt.rb +25 -0
  20. data/ex/rgb.txt.gz +0 -0
  21. data/ex/riocat +42 -0
  22. data/ex/riogunzip +31 -0
  23. data/ex/riogzip +24 -0
  24. data/ex/rioprompt.rb +10 -0
  25. data/ex/targz2zip +17 -0
  26. data/ex/tonl +10 -0
  27. data/lib/rio/abstract_method.rb +56 -0
  28. data/lib/rio/argv.rb +56 -0
  29. data/lib/rio/arycopy.rb +43 -0
  30. data/lib/rio/assert.rb +114 -0
  31. data/lib/rio/base.rb +56 -0
  32. data/lib/rio/callstr.rb +46 -0
  33. data/lib/rio/const.rb +51 -0
  34. data/lib/rio/construct.rb +50 -0
  35. data/lib/rio/constructor.rb +258 -0
  36. data/lib/rio/context/autoclose.rb +72 -0
  37. data/lib/rio/context/copying.rb +55 -0
  38. data/lib/rio/context/cxx.rb +66 -0
  39. data/lib/rio/context/dir.rb +120 -0
  40. data/lib/rio/context/gzip.rb +50 -0
  41. data/lib/rio/context/methods.rb +182 -0
  42. data/lib/rio/context/skip.rb +66 -0
  43. data/lib/rio/context/stream.rb +229 -0
  44. data/lib/rio/context.rb +117 -0
  45. data/lib/rio/cp.rb +370 -0
  46. data/lib/rio/def.rb +53 -0
  47. data/lib/rio/dir.rb +144 -0
  48. data/lib/rio/doc/EXAMPLES.rb +299 -0
  49. data/lib/rio/doc/HOWTO.rb +737 -0
  50. data/lib/rio/doc/INDEX.rb +311 -0
  51. data/lib/rio/doc/INTRO.rb +1068 -0
  52. data/lib/rio/doc/OPTIONAL.rb +130 -0
  53. data/lib/rio/doc/SYNOPSIS.rb +183 -0
  54. data/lib/rio/doc.rb +45 -0
  55. data/lib/rio/entrysel.rb +246 -0
  56. data/lib/rio/exception/copy.rb +97 -0
  57. data/lib/rio/exception/notimplemented.rb +57 -0
  58. data/lib/rio/exception/notsupported.rb +46 -0
  59. data/lib/rio/exception/open.rb +61 -0
  60. data/lib/rio/exception/state.rb +73 -0
  61. data/lib/rio/exception.rb +41 -0
  62. data/lib/rio/ext/csv.rb +351 -0
  63. data/lib/rio/ext/if.rb +45 -0
  64. data/lib/rio/ext/mp3info.rb +80 -0
  65. data/lib/rio/ext/splitlines.rb +253 -0
  66. data/lib/rio/ext/yaml/doc.rb +133 -0
  67. data/lib/rio/ext/yaml/tie.rb +149 -0
  68. data/lib/rio/ext/yaml.rb +164 -0
  69. data/lib/rio/ext/zipfile/fs.rb +116 -0
  70. data/lib/rio/ext/zipfile/rl.rb +251 -0
  71. data/lib/rio/ext/zipfile/rootdir.rb +117 -0
  72. data/lib/rio/ext/zipfile/state.rb +161 -0
  73. data/lib/rio/ext/zipfile/wrap.rb +204 -0
  74. data/lib/rio/ext/zipfile.rb +110 -0
  75. data/lib/rio/ext.rb +138 -0
  76. data/lib/rio/factory.rb +436 -0
  77. data/lib/rio/file.rb +118 -0
  78. data/lib/rio/filter/closeoneof.rb +103 -0
  79. data/lib/rio/filter/gzip.rb +70 -0
  80. data/lib/rio/filter.rb +94 -0
  81. data/lib/rio/fs/base.rb +41 -0
  82. data/lib/rio/fs/impl.rb +122 -0
  83. data/lib/rio/fs/native.rb +75 -0
  84. data/lib/rio/fs/stream.rb +61 -0
  85. data/lib/rio/fs/url.rb +63 -0
  86. data/lib/rio/ftp/conncache.rb +101 -0
  87. data/lib/rio/ftp/dir.rb +94 -0
  88. data/lib/rio/ftp/fs.rb +180 -0
  89. data/lib/rio/ftp/ftpfile.rb +20 -0
  90. data/lib/rio/grande.rb +97 -0
  91. data/lib/rio/handle.rb +100 -0
  92. data/lib/rio/if/basic.rb +64 -0
  93. data/lib/rio/if/csv.rb +76 -0
  94. data/lib/rio/if/dir.rb +157 -0
  95. data/lib/rio/if/file.rb +89 -0
  96. data/lib/rio/if/fileordir.rb +268 -0
  97. data/lib/rio/if/grande.rb +729 -0
  98. data/lib/rio/if/grande_entry.rb +379 -0
  99. data/lib/rio/if/grande_stream.rb +693 -0
  100. data/lib/rio/if/internal.rb +125 -0
  101. data/lib/rio/if/path.rb +462 -0
  102. data/lib/rio/if/rubyio.rb +681 -0
  103. data/lib/rio/if/string.rb +83 -0
  104. data/lib/rio/if/temp.rb +45 -0
  105. data/lib/rio/if/test.rb +282 -0
  106. data/lib/rio/if/yaml.rb +206 -0
  107. data/lib/rio/if.rb +64 -0
  108. data/lib/rio/ioh.rb +162 -0
  109. data/lib/rio/iomode.rb +109 -0
  110. data/lib/rio/ios/fail.rb +106 -0
  111. data/lib/rio/ios/generic.rb +119 -0
  112. data/lib/rio/ios/mode.rb +60 -0
  113. data/lib/rio/ios/null.rb +119 -0
  114. data/lib/rio/iowrap.rb +128 -0
  115. data/lib/rio/kernel.rb +54 -0
  116. data/lib/rio/local.rb +62 -0
  117. data/lib/rio/match.rb +53 -0
  118. data/lib/rio/matchrecord.rb +283 -0
  119. data/lib/rio/no_warn.rb +49 -0
  120. data/lib/rio/nullio.rb +159 -0
  121. data/lib/rio/open3.rb +68 -0
  122. data/lib/rio/ops/construct.rb +61 -0
  123. data/lib/rio/ops/create.rb +77 -0
  124. data/lib/rio/ops/dir.rb +346 -0
  125. data/lib/rio/ops/either.rb +134 -0
  126. data/lib/rio/ops/file.rb +102 -0
  127. data/lib/rio/ops/path.rb +296 -0
  128. data/lib/rio/ops/stream/input.rb +267 -0
  129. data/lib/rio/ops/stream/output.rb +100 -0
  130. data/lib/rio/ops/stream/read.rb +86 -0
  131. data/lib/rio/ops/stream/write.rb +57 -0
  132. data/lib/rio/ops/stream.rb +87 -0
  133. data/lib/rio/ops/symlink.rb +80 -0
  134. data/lib/rio/path/reset.rb +69 -0
  135. data/lib/rio/path.rb +129 -0
  136. data/lib/rio/piper/cp.rb +80 -0
  137. data/lib/rio/piper.rb +122 -0
  138. data/lib/rio/prompt.rb +66 -0
  139. data/lib/rio/rectype.rb +88 -0
  140. data/lib/rio/rl/base.rb +118 -0
  141. data/lib/rio/rl/builder.rb +117 -0
  142. data/lib/rio/rl/chmap.rb +66 -0
  143. data/lib/rio/rl/fs2url.rb +82 -0
  144. data/lib/rio/rl/ioi.rb +78 -0
  145. data/lib/rio/rl/path.rb +110 -0
  146. data/lib/rio/rl/pathmethods.rb +116 -0
  147. data/lib/rio/rl/uri.rb +200 -0
  148. data/lib/rio/rl/withpath.rb +296 -0
  149. data/lib/rio/scheme/aryio.rb +88 -0
  150. data/lib/rio/scheme/cmdio.rb +80 -0
  151. data/lib/rio/scheme/cmdpipe.rb +118 -0
  152. data/lib/rio/scheme/fd.rb +65 -0
  153. data/lib/rio/scheme/ftp.rb +141 -0
  154. data/lib/rio/scheme/http.rb +78 -0
  155. data/lib/rio/scheme/null.rb +55 -0
  156. data/lib/rio/scheme/path.rb +98 -0
  157. data/lib/rio/scheme/stderr.rb +55 -0
  158. data/lib/rio/scheme/stdio.rb +71 -0
  159. data/lib/rio/scheme/strio.rb +87 -0
  160. data/lib/rio/scheme/sysio.rb +63 -0
  161. data/lib/rio/scheme/tcp.rb +75 -0
  162. data/lib/rio/scheme/temp.rb +200 -0
  163. data/lib/rio/state/error.rb +72 -0
  164. data/lib/rio/state.rb +242 -0
  165. data/lib/rio/stream/base.rb +54 -0
  166. data/lib/rio/stream/duplex.rb +79 -0
  167. data/lib/rio/stream/open.rb +202 -0
  168. data/lib/rio/stream.rb +181 -0
  169. data/lib/rio/symantics.rb +45 -0
  170. data/lib/rio/tempdir.rb +132 -0
  171. data/lib/rio/to_rio/all.rb +39 -0
  172. data/lib/rio/to_rio/array.rb +39 -0
  173. data/lib/rio/to_rio/io.rb +40 -0
  174. data/lib/rio/to_rio/object.rb +42 -0
  175. data/lib/rio/to_rio/string.rb +40 -0
  176. data/lib/rio/to_rio.rb +67 -0
  177. data/lib/rio/uri/file.rb +198 -0
  178. data/lib/rio/util.rb +48 -0
  179. data/lib/rio/version.rb +51 -0
  180. data/lib/rio.rb +162 -0
  181. data/setup.rb +1360 -0
  182. data/test/bin/count_lines.rb +11 -0
  183. data/test/bin/find_lines.rb +13 -0
  184. data/test/bin/list_dir.rb +14 -0
  185. data/test/ftp/all.rb +9 -0
  186. data/test/ftp/anon_copy_data.rb +36 -0
  187. data/test/ftp/anon_misc.rb +124 -0
  188. data/test/ftp/anon_read.rb +105 -0
  189. data/test/ftp/anon_special.rb +68 -0
  190. data/test/ftp/anon_write.rb +70 -0
  191. data/test/ftp/ftp2ftp.rb +51 -0
  192. data/test/ftp/initftpfiles.rb +14 -0
  193. data/test/ftp/testdef.rb +55 -0
  194. data/test/gem_runtests.rb +15 -0
  195. data/test/http/all.rb +4 -0
  196. data/test/http/copy-from-http.rb +141 -0
  197. data/test/http/uri-meta.rb +72 -0
  198. data/test/lib/temp_server.rb +46 -0
  199. data/test/runalltests.rb +17 -0
  200. data/test/runftptests.rb +14 -0
  201. data/test/runhttp.rb +11 -0
  202. data/test/runhttptests.rb +14 -0
  203. data/test/runtests.rb +52 -0
  204. data/test/tc/abs.rb +355 -0
  205. data/test/tc/all.rb +80 -0
  206. data/test/tc/base.rb +31 -0
  207. data/test/tc/base2.rb +87 -0
  208. data/test/tc/cd1.rb +113 -0
  209. data/test/tc/clearsel.rb +68 -0
  210. data/test/tc/clone.rb +208 -0
  211. data/test/tc/closeoncopy.rb +102 -0
  212. data/test/tc/closeoneof.rb +194 -0
  213. data/test/tc/cmdpipe.rb +149 -0
  214. data/test/tc/copy-dir-samevar.rb +91 -0
  215. data/test/tc/copy-from.rb +129 -0
  216. data/test/tc/copy-to.rb +91 -0
  217. data/test/tc/copy.rb +74 -0
  218. data/test/tc/copyarray.rb +188 -0
  219. data/test/tc/copydest.rb +50 -0
  220. data/test/tc/copydir.rb +166 -0
  221. data/test/tc/copydirlines.rb +121 -0
  222. data/test/tc/copylines.rb +46 -0
  223. data/test/tc/copynonex.rb +118 -0
  224. data/test/tc/copysymlink.rb +39 -0
  225. data/test/tc/create.rb +114 -0
  226. data/test/tc/csv.rb +226 -0
  227. data/test/tc/csv2.rb +138 -0
  228. data/test/tc/csv_columns.rb +37 -0
  229. data/test/tc/csvutil.rb +56 -0
  230. data/test/tc/dir.rb +76 -0
  231. data/test/tc/dir_iter.rb +383 -0
  232. data/test/tc/dirautoclose.rb +67 -0
  233. data/test/tc/dirent.rb +178 -0
  234. data/test/tc/dirss.rb +81 -0
  235. data/test/tc/each.rb +111 -0
  236. data/test/tc/each_break.rb +243 -0
  237. data/test/tc/edf.rb +81 -0
  238. data/test/tc/empty.rb +51 -0
  239. data/test/tc/emptyriodir.rb +129 -0
  240. data/test/tc/entary.rb +227 -0
  241. data/test/tc/entsel.rb +110 -0
  242. data/test/tc/eq.rb +101 -0
  243. data/test/tc/expand_path.rb +69 -0
  244. data/test/tc/ext.rb +136 -0
  245. data/test/tc/fileno.rb +94 -0
  246. data/test/tc/files_select.rb +92 -0
  247. data/test/tc/get.rb +152 -0
  248. data/test/tc/getrec.rb +137 -0
  249. data/test/tc/gzip.rb +109 -0
  250. data/test/tc/io_each_byte.rb +60 -0
  251. data/test/tc/io_read.rb +80 -0
  252. data/test/tc/iometh.rb +149 -0
  253. data/test/tc/likeio.rb +116 -0
  254. data/test/tc/line_record_row.rb +51 -0
  255. data/test/tc/lineno.rb +196 -0
  256. data/test/tc/lines.rb +66 -0
  257. data/test/tc/misc.rb +432 -0
  258. data/test/tc/nolines.rb +204 -0
  259. data/test/tc/noqae.rb +879 -0
  260. data/test/tc/null.rb +45 -0
  261. data/test/tc/once.rb +6 -0
  262. data/test/tc/overload.rb +140 -0
  263. data/test/tc/pa.rb +158 -0
  264. data/test/tc/path_parts.rb +175 -0
  265. data/test/tc/pathop.rb +60 -0
  266. data/test/tc/paths.rb +145 -0
  267. data/test/tc/pid.rb +31 -0
  268. data/test/tc/piper.rb +143 -0
  269. data/test/tc/programs_util.rb +24 -0
  270. data/test/tc/qae.rb +493 -0
  271. data/test/tc/qae_riovar.rb +499 -0
  272. data/test/tc/readline.rb +30 -0
  273. data/test/tc/records.rb +68 -0
  274. data/test/tc/rename.rb +233 -0
  275. data/test/tc/rename_assign.rb +45 -0
  276. data/test/tc/riorl.rb +181 -0
  277. data/test/tc/route.rb +51 -0
  278. data/test/tc/selnosel.rb +33 -0
  279. data/test/tc/skip.rb +89 -0
  280. data/test/tc/skiplines.rb +71 -0
  281. data/test/tc/split.rb +28 -0
  282. data/test/tc/splitlines.rb +65 -0
  283. data/test/tc/splitpath.rb +83 -0
  284. data/test/tc/sub.rb +46 -0
  285. data/test/tc/symlink.rb +176 -0
  286. data/test/tc/symlink0.rb +348 -0
  287. data/test/tc/symlink1.rb +114 -0
  288. data/test/tc/synopsis.rb +75 -0
  289. data/test/tc/temp.rb +152 -0
  290. data/test/tc/tempdir.rb +60 -0
  291. data/test/tc/tempfile.rb +66 -0
  292. data/test/tc/testcase.rb +170 -0
  293. data/test/tc/tonl.rb +37 -0
  294. data/test/tc/truncate.rb +39 -0
  295. data/test/tc/yaml.rb +275 -0
  296. metadata +387 -0
@@ -0,0 +1,89 @@
1
+ #--
2
+ # ===============================================================================
3
+ # Copyright (c) 2005,2006,2007 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
+ # ruby build_doc.rb
26
+ # from the distribution directory.
27
+ #
28
+ # Suggested Reading
29
+ # * RIO::Doc::SYNOPSIS
30
+ # * RIO::Doc::INTRO
31
+ # * RIO::Doc::HOWTO
32
+ # * RIO::Doc::EXAMPLES
33
+ # * RIO::Rio
34
+ #
35
+
36
+
37
+ module RIO
38
+ module IF
39
+ module File
40
+
41
+ # Calls FileUtils#rm
42
+ #
43
+ # Deletes the referenced file, returning the Rio. Raises an exception on any error.
44
+ #
45
+ # See also IF::Grande#delete, IF::Grande#delete!, IF::Dir#rmdir.
46
+ def rm() target.rm(); self end
47
+
48
+
49
+ # Calls FileUtils#touch
50
+ #
51
+ # Updates modification time (mtime) and access time (atime) of a Rio.
52
+ # A file is created if it doesn't exist.
53
+ #
54
+ def touch() target.touch(); self end
55
+
56
+ # Calls File#truncate
57
+ #
58
+ # Truncates a file referenced by a Rio to be at most +sz+ bytes long.
59
+ # Not available on all platforms.
60
+ #
61
+ # f = rio("out")
62
+ # f.print!("1234567890")
63
+ # f.size #=> 10
64
+ # f.truncate(5)
65
+ # f.size() #=> 5
66
+ #
67
+ # If called with no arguments, truncates the Rio at the
68
+ # value returned by IF::FileOrDir#pos().
69
+ # f.read(2)
70
+ # f.truncate.size #=> 2
71
+ # f.contents #=> "12"
72
+ #
73
+ # Returns the Rio
74
+ #
75
+ def truncate(sz=pos()) target.truncate(sz); self end
76
+
77
+ # Calls IF::File#truncate(0)
78
+ #
79
+ def clear() target.clear(); self end
80
+
81
+ end
82
+ end
83
+ end
84
+
85
+ module RIO
86
+ class Rio
87
+ include RIO::IF::File
88
+ end
89
+ end
@@ -0,0 +1,268 @@
1
+ #--
2
+ # ===============================================================================
3
+ # Copyright (c) 2005,2006,2007 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
+ # ruby build_doc.rb
26
+ # from the distribution directory.
27
+ #
28
+ # Suggested Reading
29
+ # * RIO::Doc::SYNOPSIS
30
+ # * RIO::Doc::INTRO
31
+ # * RIO::Doc::HOWTO
32
+ # * RIO::Doc::EXAMPLES
33
+ # * RIO::Rio
34
+ #
35
+
36
+
37
+ module RIO
38
+ module IF
39
+ module FileOrDir
40
+
41
+ # undocumented
42
+ def open(m,*args,&block) target.open(m,*args,&block); self end
43
+
44
+ # Creates a symbolic link _dest_ which points to the Rio's IF::Path#fspath.
45
+ # Raises a NotImplementedError exception on platforms that do not support symbolic links.
46
+ # _dest_ may be a Rio, a String, or anything that will create an appropriate Rio
47
+ # when passed to Rio#new .
48
+ # If _dest_ already exists and is a directory, creates a symbolic link in the _dest_ directory,
49
+ # named with the name returned by IF::Path#filename.
50
+ # If _dest_ already exists and it is not a directory, raises Errno::EEXIST.
51
+ #
52
+ # Returns the Rio (not the symlink).
53
+ #
54
+ # IF::FileOrDir#symlink differs from File#symlink when the Rio or the _dest_ path has directory information.
55
+ # In this case IF::FileOrDir#symlink creates a symlink that actually refers to the Rio's location
56
+ # from the perspective of the link's location.
57
+ #
58
+ # For example: Given an existing file 'adir/afile' and a _dest_ of 'adir/alink'
59
+ # ::File.symlink('adir/afile','adir/alink1') # creates 'adir/alink1 -> adir/afile'
60
+ # ::File.exist?('adir/alink1') # false
61
+ # rio('adir/afile').symlink('adir/alink2') # creates 'adir/alink2 -> afile'
62
+ # ::File.exist?('adir/alink2') # true
63
+ #
64
+ # To replace an existing symlink use the following Rio idiom
65
+ # rio('afile').symlink( rio('link_name').delete ) # delete 'link_name' and recreate linked to 'afile'
66
+ #
67
+ # Examples
68
+ # rio('afile').symlink('alink') # create the symbolic link 'alink' which references 'afile'
69
+ # rio('afile').symlink('adir/alink') # create a symlink 'adir/alink' -> '../afile'
70
+ # rio('adir/afile').symlink('alink') # create a symlink 'alink' -> 'adir/afile'
71
+ # rio('adir/afile').symlink('adir/alink') # create a symlink 'adir/alink' -> 'afile'
72
+ # rio('adir/afile').symlink('adir/alink') # create a symlink 'adir/alink' -> 'afile'
73
+ # rio('adir1/afile').symlink('adir2/alink') # create a symlink 'adir2/alink' -> '../adir1/afile'
74
+ # rio('/tmp/afile').symlink('alink') # create a symlink 'adir/alink' -> '/tmp/afile'
75
+ def symlink(dest) target.symlink(dest); self end
76
+
77
+
78
+ # Calls File#readlink
79
+ #
80
+ # Returns a Rio referencing the file referenced by the given link. Not available on all platforms.
81
+ #
82
+ def readlink(*args) target.readlink(*args) end
83
+
84
+ # If called with an argument calls FileUtils#rename.
85
+ # If called without an argument puts the Rio in "rename mode".
86
+ #
87
+ # Proxy for FileUtils#rename
88
+ # ario = rio('afile.cpp')
89
+ # ario.rename('afile.cxx') # renamed the file, but ario still references
90
+ # # the old path
91
+ # ===== Rename Mode
92
+ #
93
+ # In rename mode, changes to a Rio's path using IF::Path#dirname=, IF::Path#filename=,
94
+ # IF::Path#basename=, and IF::Path#extname= also cause the object on the filesystem
95
+ # to be renamed.
96
+ #
97
+ # Change the extension of all'.cpp' files in 'adir' to '.cxx'
98
+ # rio('adir').rename.files('*.cpp') do |file|
99
+ # file.ext = '.cxx' # 'file' references the new path and the actual file is renamed
100
+ # end
101
+ #
102
+ # Recursively change all '.tar.gz' files to '.tgz' files
103
+ # rio('adir').rename.all.files('*.tar.gz') do |gzfile|
104
+ # gzfile.ext('.tar.gz').ext = '.tgz'
105
+ # end
106
+ #
107
+ # See IF::Path#dirname=, IF::Path#filename=, IF::Path#basename=, and IF::Path#extname=
108
+ #
109
+ def rename(*args,&block) target.rename(*args,&block); self end
110
+
111
+
112
+ # Behaves like IF::FileOrDir#rename, but also changes the calling Rio to
113
+ # refer to the renamed path
114
+ def rename!(*args,&block) target.rename!(*args,&block); self end
115
+
116
+
117
+ # For directories calls Dir#read, otherwise calls IO#read
118
+ #
119
+ # For streams calls IO#read
120
+ # ario.read([integer [, buffer]]) => string, buffer, or nil
121
+ # Reads at most _integer_ bytes from the I/O stream, or to the end of
122
+ # file if _integer_ is omitted or is +nil+. If the optional _buffer_
123
+ # argument is present, it must reference a String, which will receive
124
+ # the data. Returns +nil+ if called at end of file.
125
+ #
126
+ # f = rio("testfile")
127
+ # f.read(16) #=> "This is line one"
128
+ #
129
+ # rio("testfile").read(16) #=> "This is line one"
130
+ #
131
+ # For directories calls Dir#read
132
+ # dir.read => ario or nil
133
+ #------------------------------------------------------------------------
134
+ # Reads the next entry from _dir_ and returns it as a Rio. Returns
135
+ # +nil+ at the end of the stream.
136
+ # d = rio("testdir")
137
+ # d.read #=> rio(".")
138
+ # d.read #=> rio("..")
139
+ # d.read #=> rio("config.h")
140
+ #
141
+ def read(*args) target.read(*args)end
142
+
143
+ # For directories proxies Dir#rewind, otherwise proxies IO#rewind
144
+ #
145
+ # Proxy for IO#rewind
146
+ # ario.rewind => ario
147
+ # Positions _ario_ to the beginning of input, resetting lineno to zero.
148
+ #
149
+ # Returns the Rio
150
+ #
151
+ # f = rio("testfile")
152
+ # f.readline #=> "This is line one\n"
153
+ # f.rewind #=> f
154
+ # f.lineno #=> 0
155
+ # f.readline #=> "This is line one\n"
156
+ #
157
+ # f.rewind.readline #=> "This is line one\n"
158
+ #
159
+ # Proxy for Dir#rewind
160
+ # ario.rewind => ario
161
+ #------------------------------------------------------------------------
162
+ # Repositions _ario_ to the first entry.
163
+ #
164
+ # d = rio("testdir")
165
+ # d.read #=> rio(".")
166
+ # d.rewind.read #=> rio(".")
167
+ def rewind(&block) target.rewind(&block); self end
168
+
169
+ # For directories calls Dir#seek, otherwise calls IO#seek
170
+ #
171
+ # For streams calls IO#seek
172
+ # ario.seek(amount, whence=SEEK_SET) -> ario
173
+ # Seeks to a given offset _amount_ in the stream according to the
174
+ # value of _whence_:
175
+ #
176
+ # IO::SEEK_CUR | Seeks to 'amount' plus current position
177
+ # --------------+----------------------------------------------------
178
+ # IO::SEEK_END | Seeks to 'amount' plus end of stream (you probably
179
+ # | want a negative value for 'amount')
180
+ # --------------+----------------------------------------------------
181
+ # IO::SEEK_SET | Seeks to the absolute location given by 'amount'
182
+ #
183
+ # Example:
184
+ #
185
+ # f = rio("testfile")
186
+ # f.seek(-28, IO::SEEK_END).readline #=> "happily ever after. The End\n"
187
+ #
188
+ # For directories calls Dir#seek
189
+ # ario.seek( integer ) => ario
190
+ # Seeks to a particular location in _ario_. _integer_ must be a value
191
+ # returned by IF::FileOrDir#tell.
192
+ #
193
+ # d = rio("testdir") #=> #<RIO::Rio:0x401b3c40>
194
+ # d.read #=> rio(".")
195
+ # i = d.tell #=> 12
196
+ # d.read #=> rio("..")
197
+ # d.seek(i) #=> #<RIO::Rio:0x401b3c40>
198
+ # d.read #=> rio("..")
199
+ def seek(*args) target.seek(*args); self end
200
+ #def seek(amount,whence=IO::SEEK_SET) target.seek(amount,whence) end
201
+
202
+
203
+
204
+ # For directories calls Dir#pos, otherwise calls IO#pos
205
+ #
206
+ # For streams calls IO#pos
207
+ # ario.pos => integer
208
+ # ario.tell => integer
209
+ # Returns the current offset (in bytes) of _ario_.
210
+ #
211
+ # f = rio("testfile")
212
+ # f.pos #=> 0
213
+ # f.gets #=> "This is line one\n"
214
+ # f.pos #=> 17
215
+ #
216
+ #
217
+ # For directories calls Dir#pos
218
+ # ario.pos => integer
219
+ # ario.tell => integer
220
+ # Returns the current position in _dir_. See also IF::FileOrDir#seek.
221
+ #
222
+ # d = rio("testdir")
223
+ # d.pos #=> 0
224
+ # d.read #=> rio(".")
225
+ # d.pos #=> 12
226
+ #
227
+ def pos() target.pos end
228
+
229
+ # See IF::FileOrDir#pos
230
+ def tell() target.tell end
231
+
232
+ # For directories calls Dir#pos=, otherwise calls IO#pos=
233
+ #
234
+ # For streams calls IO#pos=
235
+ # ario.pos = integer => 0
236
+ # Seeks to the given position (in bytes) in _ario_.
237
+ #
238
+ # f = rio("testfile")
239
+ # f.pos = 17
240
+ # f.gets #=> "This is line two\n"
241
+ #
242
+ # For directories calls Dir#pos=
243
+ # ario.pos = integer => integer
244
+ #------------------------------------------------------------------------
245
+ # Synonym for +IF::FileOrDir#seek+, but returns the position parameter.
246
+ #
247
+ # d = rio("testdir") #=> d
248
+ # d.read #=> rio(".")
249
+ # i = d.pos #=> 12
250
+ # d.read #=> rio("..")
251
+ # d.pos = i #=> 12
252
+ # d.read #=> rio("..")
253
+ #
254
+ def pos=(integer) target.pos = integer end
255
+
256
+ # For Streams calls IO#reopen, otherwise closes and re-opens
257
+ # the Rio.
258
+ #
259
+ def reopen(mode=nil) target.reopen(mode); self end
260
+ end
261
+ end
262
+ end
263
+
264
+ module RIO
265
+ class Rio
266
+ include RIO::IF::FileOrDir
267
+ end
268
+ end
@@ -0,0 +1,729 @@
1
+ #--
2
+ # ===============================================================================
3
+ # Copyright (c) 2005,2006,2007 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
+ # ruby build_doc.rb
26
+ # from the distribution directory.
27
+ #
28
+ # Suggested Reading
29
+ # * RIO::Doc::SYNOPSIS
30
+ # * RIO::Doc::INTRO
31
+ # * RIO::Doc::HOWTO
32
+ # * RIO::Doc::EXAMPLES
33
+ # * RIO::Rio
34
+ #
35
+
36
+ require 'rio/no_warn'
37
+ module RIO
38
+ module IF
39
+ module Grande
40
+
41
+ # Returns the contents of the rio as an array. (See ::Enumerable#to_a)
42
+ #
43
+ # IF::Grande#to_a is implemented in terms of #each so the the following are roughly equivelent
44
+ #
45
+ # ary = ario.to_a
46
+ #
47
+ # ary = []
48
+ # ario.each do |rec|
49
+ # ary << ary
50
+ # end
51
+ #
52
+ # What constitutes an array element is determined by IF::GrandeStream#lines,
53
+ # IF::GrandeStream#bytes, IF::GrandeStream#records, IF::GrandeStream#rows or
54
+ # by an extension such as IF::CSV#csv. IF::GrandeStream#lines is the default.
55
+ #
56
+ # rio('afile.txt').to_a # returns an array of the lines in afile.txt
57
+ #
58
+ # rio('afile.txt').lines(1...3).to_a # an array containing lines 1 and 2 of afile.txt
59
+ #
60
+ # rio('afile.dat').bytes(50).to_a # an array containing the contents of afile.dat broken
61
+ # # up into 50 byte chunks
62
+ #
63
+ # See also IF::Grande#[] (subscript operator)
64
+ #
65
+ def to_a() target.to_a() end
66
+
67
+ # Grande subscript operator.
68
+ #
69
+ # For files this returns all or part of a file as an array.
70
+ #
71
+ # For directories this returns all or some of the entries in a directory
72
+ #
73
+ # === Files
74
+ #
75
+ # This combines the record selection offered by IF::GrandeStream#records with
76
+ # the conversion to an array provided by IF::Grande#to_a. The following two are equivelant:
77
+ # ario[*args]
78
+ # ario.records(*args).to_a
79
+ #
80
+ # What constitutes an array element is determined by IF::GrandeStream#lines, IF::GrandeStream#bytes,
81
+ # or by an extension such as IF::CSV#csv. IF::GrandeStream#lines is the default.
82
+ #
83
+ # Arguments may consist of zero or more integers, ranges, regular expressions, symbols,
84
+ # procs, and arrays
85
+ # An empty argument list selects all records
86
+ #
87
+ # Records are selected as follows.
88
+ # range:: specifies a range of records to be selected (zero based)
89
+ # regexp:: matching records will be selected.
90
+ # integer:: treated like a one element range
91
+ # symbol:: the symbol is sent to each record. Record is selected
92
+ # unless false is returned
93
+ # proc:: the proc is called with the record as an argument.
94
+ # Record is selected unless false is returned
95
+ # array:: the array may contain any of the other selector types. Record is selected
96
+ # unless any of the selectors returns false. (a logical and)
97
+ #
98
+ # A record matching *any* of the selectors will be included in the array. (acts like an _or_)
99
+ #
100
+ # Because this is implemented in terms of the IF::Grande#each,
101
+ # When only record ranges are used to select records,
102
+ # iteration will stop when the recno exceeds the maximum of any range. That is to say
103
+ #
104
+ # This reads one record from a file and returns it
105
+ # rio('bigfile.mp3').bytes(1024)[0]
106
+ # While this reads *all* records from a file and returns the first one
107
+ # rio('bigfile.mp3').bytes(1024).to_a[0]
108
+ #
109
+ # === Directories
110
+ #
111
+ # This combines the entry selection offered by IF::GrandeEntry#entries with
112
+ # the conversion to an array provided by IF::Grande#to_a. The following two are equivelant:
113
+ # ario[*args]
114
+ # ario.entries(*args).to_a
115
+ #
116
+ # Arguments may consist of strings (treated as globs) or regular expressions.
117
+ # An empty argument list selects all entries
118
+ # See ::Dir#glob and ::File::fnmatch? for more in information on _globs_.
119
+ # Be warned that using the '**' glob
120
+ # recurses into directories independently of IF::GrandeEntry#all and using both is unsupported.
121
+ #
122
+ # ario = rio('adir')
123
+ # ario[] # returns an array containg all entries in _adir_
124
+ # ario[/^zippy/] # all entries starting with 'zippy'
125
+ # ario['zippy*'] # same thing
126
+ #
127
+ # As with IF::Grande#each:
128
+ # * Files and directories are returned as Rios
129
+ # * The types of entries is also affected by IF::GrandeEntry#files and IF::GrandeEntry#dirs.
130
+ # rio('adir').files['*.txt'] # array of all .txt files
131
+ # rio('adir').dirs[/^\./] # array of all dot directories
132
+ # * Recursion is enabled using IF::GrandeEntry#all
133
+ # rio('adir').all.files['*.[ch]'] # array of c source files in adir and its subdirecories
134
+ # rio('adir').all.dirs[/^\.svn/] # array of subversion directories in adir and subdirectories
135
+ # * IF::GrandeEntry#files and IF::GrandeEntry#dirs act independently of each other.
136
+ # Specifying both will cause both to be returned.
137
+ # The argument list to IF::Grande#[] will be applied to the closest.
138
+ # rio('adir').files('*.rb').dirs['ruby*'] # array of .rb files and
139
+ # # directories starting with 'ruby'
140
+ # rio('adir').dirs('ruby*').files['*.rb'] # same thing
141
+ #
142
+ # === Lines
143
+ # This section applies similarly to IF::GrandeStream#lines, IF::GrandeStream#bytes,
144
+ # IF::GrandeStream#records, and IF::GrandeStream#rows
145
+ #
146
+ # Using IF::GrandeStream#lines and related methods with a Rio referencing a directory
147
+ # imples IF::GrandeEntry#files and will cause an array of the lines or bytes in the
148
+ # files to be returned. As above,
149
+ # the arguments to the subscript operator will be applied to the closest.
150
+ # rio('adir').lines[] # array of all lines in the files in 'adir'
151
+ # rio('adir').files.lines[] # same thing
152
+ # rio('adir').lines(0..9).files['*.txt'] # array of the first ten lines of all .txt files
153
+ # rio('adir').files('*.txt').lines[0..9] # same thing
154
+ # rio('adir').all.files('*.rb').lines[/^\s*require/] # array of 'require' lines in .rb files in
155
+ # # 'adir and its subdirectories
156
+ #
157
+ # Note the difference between the following similar usages
158
+ # it1 = rio('adir').files('*.rb') # returns a Rio, prepared for selecting ruby files
159
+ # it2 = rio('adir').files['*.rb'] # returns an array of the ruby files
160
+ #
161
+ # The second example above could have been written
162
+ # it2 = it1.to_a
163
+ #
164
+ # Examples:
165
+ #
166
+ # rio('afile.txt').lines[1..2] # array containing the 2nd and 3rd line
167
+ #
168
+ # rio('afile.txt')[1,3..5] # array containing lines 1,3,4 and 5
169
+ #
170
+ # rio('afile.txt')[/Zippy/] # array of all lines containing 'Zippy'
171
+ #
172
+ # rio('afile.txt')[1,3..5,/Zippy/] # array with lines 1,3,4 and 5 and all lines containing 'Zippy'
173
+ #
174
+ # rio('afile.dat').bytes(50)[] # array containing the contents of afile.dat broken up into 50 byte chunks
175
+ #
176
+ # rio('afile.dat').bytes(50)[0,2] # array containing the first and third such chunk
177
+ #
178
+ # rio('afile.dat').bytes(50).records[0,2] # same thing
179
+ #
180
+ # rio('afile.dat').bytes(50).records(0,2).to_a # once again
181
+ #
182
+ # rio('afile.csv').csv[0..9] # array of the first 10 records of afile.csv parsed by the ::CSV module
183
+ #
184
+ # rio('afile.csv').csv.records[0..9] # same thing
185
+ #
186
+ # rio('afile.csv').csv(';').records[0..9] # same thing using semi-colon as the value separator
187
+ #
188
+ # rio('afile.csv').csv.records[0,/Zippy/] # record 0 and all records containing 'Zippy'
189
+ # # the regexp is matched against the line before parsing by ::CSV
190
+ #
191
+ # rio('adir')[] # array of entries in 'adir'
192
+ #
193
+ # rio('adir')['*.txt'] # array of all .txt entries
194
+ #
195
+ # rio('adir').all['*.txt'] # array of all .txt entries in 'adir and its subdirectories
196
+ #
197
+ # rio('adir').files['*.txt'] # array of all .txt files
198
+ #
199
+ # rio('adir').dirs['CSV'] # array of all CSV directories
200
+ # rio('adir').skipdirs['CSV'] # array of all non-CSV directories
201
+ #
202
+ def [](*selectors) target[*selectors] end
203
+
204
+
205
+
206
+ # Iterate through a rio. Executes the block for each item selected for the Rio.
207
+ # See IF::GrandeStream#lines, IF::GrandeStream#records, IF::GrandeStream#bytes,
208
+ # IF::GrandeEntry#files, IF::GrandeEntry#dirs, IF::Grande#[]
209
+ # and IF::Grande#to_a for more information
210
+ # on how records are selected and what kind of record is passed to the block.
211
+ #
212
+ # IF::Grande#each is the fundemental method for all the Rio grande operators.
213
+ # IF::Grande#to_a and the Rio copy operators
214
+ # IF::Grande#<, IF::Grande#<<, IF::Grande#>>, and IF::Grande#>
215
+ # are all implemented in terms of IF::Grande#each.
216
+ #
217
+ # While IF::Grande#each is fundamental to a Rio, it rarely needs
218
+ # actually be called because all the grande configuration methods will also take a block
219
+ # and call IF::Grande#each if one is given.
220
+ # So the existance of a block after many methods is taken as an implied
221
+ # IF::Grande#each
222
+ #
223
+ # For Rios that refer to files, the item passed to the block is a String containing
224
+ # the line or block as selected by IF::GrandeStream#lines, or IF::GrandeStream#bytes.
225
+ # +lines+ is the default.
226
+ # rio('afile').lines.each { |line| ...}
227
+ #
228
+ # The block passed to +each+ will also accept an optional second parameter which will contain
229
+ # the result of the matching function. What this variable contains depends on the argument
230
+ # to +lines+ that resulted in the match as follows:
231
+ #
232
+ # Regexp:: The MatchData that resulted from the match.
233
+ # Range:: The record number of the matching record.
234
+ # Fixnum:: The record number of the matching record.
235
+ # Proc:: The value returned by the proc.
236
+ # Symbol:: The value resulting from sending the symbol to the String.
237
+ #
238
+ # If no selection arguments were used, this variable will simply contain +true+.
239
+ #
240
+ # rio(??).puts(%w[0:zero 1:one]).rewind.lines(/(\d+):([a-z]+)/) do |line,match|
241
+ # puts("#{match[1]} is spelled '#{match[2]}'")
242
+ # end
243
+ #
244
+ # Produces:
245
+ # 0 is spelled 'zero'
246
+ # 1 is spelled 'one'
247
+ #
248
+ #
249
+ # For Rios that refer to directories, the item passed to the block is a Rio refering to
250
+ # the directory entry.
251
+ #
252
+ # rio('adir').files.each do |file|
253
+ # file.kind_of?(RIO::Rio) # true
254
+ # end
255
+ #
256
+ # In addition, the Rio passed to the block inherits certain attributes from the directory Rio.
257
+ #
258
+ # rio('adir').files.chomp.each do |file| # chomp is ignored for directories,
259
+ # file.each do |line| # chomp attribute is inherited by the file rio
260
+ # # .. line is chomped
261
+ # end
262
+ # end
263
+ #
264
+ # IF::Grande#each returns the Rio which called it.
265
+ #
266
+ # Here are a few illustrative examples
267
+ #
268
+ # * Processing lines in a file
269
+ #
270
+ # rio('f.txt').each { |line| ... } # execute block for every line in the file
271
+ # rio('f.txt').lines.each { |line| ... } # same thing
272
+ # rio('f.txt').lines { |line| ... } # same thing
273
+ #
274
+ # rio('f.txt').chomp.each { |line| ... } # same as above with lines chomped
275
+ # rio('f.txt').chomp { |line| ... } # ditto
276
+ # rio('f.txt').lines.chomp { |line| ... } # ditto
277
+ # rio('f.txt').chomp.lines { |line| ... } # ditto
278
+ #
279
+ # rio('f.txt.gz').gzip.each { |line| ... } # execute block for every line in a gzipped file
280
+ # rio('f.txt.gz').gzip { |line| ... } # same thing
281
+ # rio('f.txt.gz').lines.gzip { |line| ... } # same thing
282
+ #
283
+ # rio('f.txt.gz').gzip.chomp { |line| ... } # chomp lines from a gzipped file
284
+ # rio('f.txt.gz').gzip.chomp.each { |line| ... } # ditto
285
+ # rio('f.txt.gz').chomp.lines.gzip { |line| ... } # ditto
286
+ #
287
+ # rio('f.txt').lines(0..9) { |line| ... } # execute block for the first 10 lines in the file
288
+ # rio('f.txt').lines(0..9).each { |line| ... } # same thing
289
+ #
290
+ # rio('f.txt').lines(/^\s*#/) { |line| ... } # execute block for comment-only lines
291
+ # rio('f.txt').lines(/^\s*#/).each { |line| ... } # same thing
292
+ #
293
+ # rio('f.txt').lines(0,/Rio/) { |line| ... } # execute block for the first line and
294
+ # # all lines containing 'Rio'
295
+ #
296
+ # rio('f.txt.gz').gzip.chomp.lines(0..1) { |line| ... } # first 2 lines chomped from a gzip file
297
+ #
298
+ # * Processing a file a block at a time
299
+ #
300
+ # rio('f.dat').bytes(10).each { |data| ... } # process the file 10 bytes at a time
301
+ # rio('f.dat').bytes(10) { |data| ... } # same thing
302
+ # rio('f.dat').bytes(10).records(2,4) { |data| ... } # only 3rd and 5th ten-byte data-block
303
+ # rio('f.dat.gz').gzip.records(2,4).bytes(10) { |data| ... } # same from a gzipped file
304
+ #
305
+ # * Iterating over directories
306
+ # rio('adir').each { |ent| ... } # execute the block for each entry in the directory 'adir'
307
+ # rio('adir').files.each { |file| ...} # only files
308
+ # rio('adir').files { |file| ...} # ditto
309
+ # rio('adir').all.files { |file| ...} # files, recurse into subdirectories
310
+ # rio('adir').dirs { |dir| ...} # only directories
311
+ # rio('adir').files('*.rb') { |file| ...} # only .rb files using a glob
312
+ # rio('adir').files(/\.rb$/) { |file| ...} # only .rb files using a regular expression
313
+ # rio('adir').all.files('*.rb') { |file| ...} # .rb files, recursing into subdirectories
314
+ # rio('adir').dirs(/^\./) { |dir| ... } # only dot directories
315
+ # rio('adir').dirs('/home/*') { |dir| ... } # home directories
316
+ #
317
+ # See RIO::Doc::HOWTO and RIO::Doc::SYNOPSIS for more examples, and RIO::Doc::INTRO for further explanation.
318
+ #
319
+ def each(*args,&block) target.each(*args,&block); self end
320
+
321
+
322
+ # For a file Rio +delete+ calls FileUtils#rm.
323
+ # For a directory Rio +delete+ calls FileUtils#rmdir
324
+ # Returns the Rio. If the Rio does not exist, simply return the Rio.
325
+ #
326
+ # rio('afile,txt').delete # delete 'afile.txt'
327
+ # rio('adir').delete # delete adir
328
+ # rio('something').delete # delete something
329
+ #
330
+ def delete() target.delete(); self end
331
+
332
+ # See IF::Grande#delete
333
+ def unlink() target.unlink(); self end
334
+
335
+ # For a file IF::Grande#delete! calls FileUtils#rm.
336
+ # For a directory IF::Grande#delete! calls FileUtils#rmtree.
337
+ # Returns the Rio. If the rio does not exist, simply returns itself.
338
+ #
339
+ # rio('afile,txt').delete! # delete f.txt
340
+ # rio('adir').delete! # delete adir
341
+ #
342
+ # # create a directory, after deleting anything that previously had its name
343
+ # rio('adir/asubdir').delete!.mkpath
344
+ #
345
+ # ==== Deleting Summary
346
+ # * To delete something only if it is not a directory use IF::File#rm
347
+ # * To delete an empty directory use IF::Dir#rmdir
348
+ # * To delete an entire directory tree use IF::Dir#rmtree
349
+ # * To delete anything except a populated directory use IF::Grande#delete
350
+ # * To delete anything use IF::Grande#delete!
351
+ #
352
+ # In all cases, deleting something that does not exist is considered successful.
353
+ #
354
+ def delete!() target.delete!(); self end
355
+
356
+ # Grande Copy-To Operator
357
+ #
358
+ # The copy grande-operator copies a Rio to a another Rio or another ruby object. The behaviour
359
+ # and the library used depend on the types of the of the source and destination. For
360
+ # simple file or directory copying ::FileUtils#cp or ::FileUtils#cp_r will be used. If
361
+ # any of the Rio grande methods are specified for the source or destination, the
362
+ # source Rio will be iterated through copying records to the destintion as specified. Roughly
363
+ # equivelant to
364
+ # dst = rio('dst_file')
365
+ # rio('src_file').each do |line|
366
+ # dst.print(line)
367
+ # end
368
+ # dst.close
369
+ #
370
+ # The destination of the copy operators may be a:
371
+ # IO:: Each record of the Rio is written to the IO using IO#print. The IO must be opened for writing.
372
+ # Array:: Each record or entry of the Rio becomes an element of the array
373
+ # String:: Puts the entire contents of the Rio into the string
374
+ # Rio:: Depends on the destination. See below.
375
+ #
376
+ # Copy a file to a file
377
+ # rio('src_file') > rio('dst_file')
378
+ #
379
+ # Copy a file to a directory
380
+ # rio('src_file') > rio('dst_dir')
381
+ #
382
+ # Copy a directory to another directory
383
+ # rio('src_dir') > rio('dst_dir')
384
+ #
385
+ # Make an ungizipped copy of a gzipped file
386
+ # rio('src.txt.gz').gzip > rio('dst.txt')
387
+ #
388
+ # Copying to an array
389
+ # rio('afile') > ary # each line of the file becomes an element of the ary
390
+ # rio('afile').chomp > ary # same thing with lines chomped
391
+ # rio('afile.gz').gzip.chomp > ary # same thing from a gzipped file
392
+ #
393
+ # rio('afile').lines(0..9) > ary # ary will contain only the first ten lines of the file
394
+ # rio('afile').chomp.lines(0..9) > ary # same thing with lines chomped
395
+ # rio('afile').gzip.chomp.lines(0..9) > ary # same thing from a gzipped file
396
+ #
397
+ # rio('afile').skiplines(0..9) > ary # ary will contain all but the first ten lines of the file
398
+ #
399
+ # rio('adir') > ary # ary will contain a Rio for each entry in the directory
400
+ # rio('adir').files > ary # same, but only files
401
+ # rio('adir').files('*.rb') >ary # same, but only .rb files
402
+ #
403
+ # Copying to a string
404
+ # rio('afile') > astring # slurp the entire contents of the file into astring
405
+ # astring = rio('afile').contents # same effect
406
+ #
407
+ # Copy the first line *and* every line containing the word Rio into a gzipped file
408
+ # rio('src').lines(1,/Rio/) > rio('dst.gz').gzip
409
+ #
410
+ # Copy lines of a web page into an array with each line chomped
411
+ # rio('http://ruby-doc.org/index.html').chomp > an_array
412
+ #
413
+ # Copy the first and 8th through 10th columns of the first ten rows of a gzipped csv
414
+ # file on a web site into a local gzipped csv file that uses semi-colons as separators
415
+ # rio('http://host/file.csv.gz').columns(0,7..9).gzip.csv[0..9] > rio('localfile.csv.gz').csv(';').gzip
416
+ #
417
+ # See also IF::Grande#>>, IF::Grande#|
418
+ #
419
+ def >(destination)
420
+ RIO::no_warn {
421
+ target > destination;
422
+ }
423
+ self
424
+ end
425
+
426
+ # Alias for IF::Grande#> (copy-to grande operator)
427
+ def copy_to(destination) target.copy_to(destination); self end
428
+
429
+
430
+ # Grande Pipe Operator
431
+ #
432
+ # The Rio pipe operator is actually an alternative syntax for calling the IF::Grande#> (copy-to)
433
+ # operator, designed to
434
+ # allow several copy operation to be performed in one line of code, with behavior that mimics
435
+ # the pipe operator commonly available in shells.
436
+ #
437
+ # If +destination+ is a +cmdio+, a <tt>cmdpipe</tt> Rio is returned, and none of the commands are run.
438
+ #
439
+ # Otherwise the +cmdpipe+ Rio is run with the output of the pipe being copied to the destination.
440
+ # In this case a Rio representing the +destination+ is returned.
441
+ #
442
+ # If destination is not a Rio it is passed to the Rio constructor as is done with the copy-to operator
443
+ # except that if +destination+ is a String it is assumed to be a command instead of a path.
444
+ #
445
+ # rio('afile') | rio(?-,'grep i') | rio(?-) # returns rio(?-)
446
+ # # equivelent to rio(?-, 'grep i') < rio('afile') > rio(?-)
447
+ #
448
+ # rio('infile') | rio(?-, 'acmd') | rio(?-, 'acmd2') | rio('outfile')
449
+ # # same as
450
+ # # acmd = rio(?-,'acmd')
451
+ # # acmd2 = rio(?-,'acmd2')
452
+ # # out = rio('outfile')
453
+ # # acmd < rio('infile')
454
+ # # acmd2 < acmd
455
+ # # out < acmd2
456
+ #
457
+ # rio('afile') | 'acmd' | 'acmd2' | rio('outfile') # same thing
458
+ #
459
+ # acmdpipe = rio(?-,'acmd') | 'acmd2'
460
+ # rio('afile') | acmdpipe | rio('outfile') # same thing
461
+ #
462
+ # acmdpipe1 = rio(?|,'acmd','acmd2')
463
+ # rio('afile') | acmdpipe1 | rio('outfile') # same thing
464
+ #
465
+ # acmdpipe2 = rio('afile') | 'acmd' | 'acmd2'
466
+ # acmdpipe2 | rio('outfile') # same thing
467
+ #
468
+ # The grande pipe operator can not be used to create a +cmdpipe+ Rio that includes a destination.
469
+ # This must be done using a Rio constructor
470
+ # cmd_with_output = rio(?|,'acmd',rio('outfile'))
471
+ # rio('afile') | cmd_with_output # same as above
472
+ #
473
+ def |(destination) target | destination end
474
+
475
+ # Grande Append-To Operator
476
+ #
477
+ # The append-to grande-operator is the same as IF::Grande#> (copy-to) except that it opens the destination
478
+ # for append.
479
+ # The destination can be a kind of:
480
+ # IO:: Each record of the Rio is written to the IO using IO#print. The IO must be opened for writing.
481
+ # Array:: Each record or entry of the Rio is appended to the destination array
482
+ # String:: Appends the entire contents of the Rio to destination
483
+ # Rio:: Just like IF::Grande#> (copy-to) except the unopened object are
484
+ # opened for append. If the destination is already opened for writing or is a
485
+ # directory, this is identical to IF::Grande#> (copy-to)
486
+ #
487
+ # See IF::Grande#> (copy-to)
488
+ #
489
+ # rio('afile') >> rio('anotherfile') # append the contents of 'afile' to 'anotherfile'
490
+ # rio('afile') >> rio('adir') # copies 'afile' to the directory 'adir'
491
+ # rio('adir') >> rio('anotherdir') # copy directory 'adir' recursively to 'anotherdir'
492
+ # rio('adir') >> array # a Rio for each entry in the directory will be appended to ary
493
+ def >>(destination) target >> destination; self end
494
+
495
+
496
+ # Alias for IF::Grande#>> (append-to grande operator)
497
+ def append_to(destination) target.append_to(destination); self end
498
+
499
+
500
+ # Grande Append-From Operator
501
+ #
502
+ # The append-from grande-operator copies a Rio from another Rio or another ruby object. This
503
+ # behaves like IF::Grande#< (copy-from) except unopened Rios are opened for append.
504
+ #
505
+ # The following summarizes how objects are copied:
506
+ # IO:: IO#each is used to iterate through the source with each record appended to the Rio
507
+ # Array:: Each element of the Array is appended individually to the Rio.
508
+ # String:: The string is appended to the Rio using IF::RubyIO#print
509
+ # Rio:: The source Rio is appended using its IF::Grande#>> (append-to) operator
510
+ #
511
+ # See IF::Grande#< (copy-from)
512
+ def <<(source) target << source; self end
513
+
514
+
515
+ # Alias for IF::Grande#<< (append-from grande operator)
516
+ def append_from(source) target.append_from(source); self end
517
+
518
+
519
+ # Grande Copy-From Operator
520
+ #
521
+ # The copy-from grande-operator copies a Rio from another Rio or another ruby object.
522
+ # Its operation is dependent on the the file system objects referenced, the rio
523
+ # options set, and the state of its source and destination. In the broadest of terms
524
+ # it could be described as doing the following:
525
+ # source.each do |entry|
526
+ # destination << entry
527
+ # end
528
+ # That is to say, it iterates through its argument, calling the copy-from operator
529
+ # again for each element. While it is not implemented like this, and the above code would
530
+ # not give the same results, This generalized description is convenient.
531
+ #
532
+ # For example the code:
533
+ #
534
+ # destination < source
535
+ # is like
536
+ # source.each { |element| destination << element }
537
+ #
538
+ # for any of the following definitions of src and dst
539
+ # * copying files
540
+ # src = rio('afile')
541
+ # dst = rio('acopy')
542
+ # * copying parts of files
543
+ # src = rio('afile').lines(0..9)
544
+ # dst = rio('acopy')
545
+ # * copying directories
546
+ # src = rio('srcdir')
547
+ # dst = rio('dstdir')
548
+ # * copy directories selectively
549
+ # src = rio('srcdir').dirs(/^\./).files('*.tmp')
550
+ # dst = rio('dstdir')
551
+ # * copying to a file from an array
552
+ # src = ["line0\n","line1\n"]
553
+ # dst = rio('afile')
554
+ # * copying to a directory from an array
555
+ # array = [rio("file1"),rio("file2")]
556
+ # dst = rio('adir')
557
+ #
558
+ # Arrays are handled differently depending on whether the rio references a file or a directory.
559
+ # * If the destination is a file.
560
+ # dest = rio('afile')
561
+ # dest < array
562
+ # # is roughly equivelent to
563
+ # array.each do |el|
564
+ # case el
565
+ # when ::String then dest.print(el)
566
+ # when ::Rio then dest << el
567
+ # else dest << rio(el)
568
+ # end
569
+ # * If the destination is a directory
570
+ # dest = rio('adir')
571
+ # dest < array
572
+ # # is roughly equivelent to
573
+ # array.each do |el|
574
+ # case el
575
+ # when ::String then rio(el)
576
+ # when ::Rio then dest << el
577
+ # else dest << rio(el)
578
+ # end
579
+ #
580
+ # To improve run-time efficiency, Rio will choose from among several strategies when
581
+ # copying. For instance when no file or directory filtering is specified, FileUtils#cp_r is
582
+ # used to copy directories; and when no line filtering is specified, FileUtils#cp is used to copy
583
+ # files.
584
+ #
585
+ # rio('adir') < rio('anotherdir') # 'anotherdir' is copied to 'adir' using FileUtils#cp_r
586
+ # rio('adir') < rio('anotherdir').files('*.rb') # copy only .rb files
587
+ # rio('afile') < rio('anotherfile') # 'anotherfile' is copied to 'afile' using FileUtils#cp
588
+ # rio('afile') < ios # ios must be an IO object opened for reading
589
+ # rio('afile') < astring # basically the same as rio('afile').print(astring)
590
+ #
591
+ # anarray = [ astring, rio('anotherfile') ]
592
+ # rio('afile') < anarray # copies each element to 'afile' as if one had written
593
+ # ario = rio('afile')
594
+ # anarray.each do |el|
595
+ # ario << el
596
+ # end
597
+ # ario.close
598
+ # rio('skeldir') < rio('adir').dirs # copy only the directory structure
599
+ # rio('destdir') < rio('adir').dirs.files(/^\./) # copy the directory structure and all dot files
600
+ #
601
+ # See also IF::Grande#> (copy-to), IF::Grande#each, IF::Grande#[]
602
+ #
603
+ def <(source)
604
+ RIO::no_warn {
605
+ target < source
606
+ }
607
+ self
608
+ end
609
+
610
+ # Alias for IF::Grande#< (copy-from grande operator)
611
+ def copy_from(source) target.copy_from(source); self end
612
+
613
+
614
+ # Reads and returns the next record or entry from a Rio,
615
+ # honoring the grande selection methods.
616
+ #
617
+ # Returns nil on end of file.
618
+ #
619
+ # See also IF::GrandeStream#records, IF::GrandeStream#lines, IF::Grande#each, IF::Grande#[]
620
+ #
621
+ # ario = rio('afile').lines(10..12)
622
+ # line10 = ario.get
623
+ # line11 = ario.get
624
+ # line12 = ario.get
625
+ # a_nil = ario.get
626
+ #
627
+ # ario = rio('adir').entries('*.txt')
628
+ # ent1 = ario.get
629
+ # ent2 = ario.get
630
+ #
631
+ def get() target.get() end
632
+
633
+ # Grande Exclude method
634
+ #
635
+ # +skip+ can be used in two ways.
636
+ #
637
+ #
638
+ # ==== skip with no arguments
639
+ #
640
+ # If called with no arguments it reverses the polarity of the
641
+ # next non-skip grande selection method that is called. That is,
642
+ # it turns +lines+, +records+, +rows+, +files+, +dirs+ and +entries+
643
+ # into +skiplines+, +skiprecords+, +skiprows+, +skipfiles+,
644
+ # +skipdirs+, and +skipentries+, respectively.
645
+ #
646
+ # rio('afile').skip.lines(0..5) # same as rio('afile').skiplines(0..5)
647
+ # rio('adir').skip.files('*~') # same as rio('adir').skipfiles('*~')
648
+ #
649
+ # Note that it only affects the next selection method seen -- and may be
650
+ # used more than once. If no grande selection method is seen, +skip+ is
651
+ # ignored.
652
+ #
653
+ # ==== skip with arguments
654
+ #
655
+ # When called with arguments it acts like IF::GrandeEntry#skipentries for directory
656
+ # Rios and like IF::GrandeStream#skiprecords for stream Rios.
657
+ #
658
+ # rio('afile').lines(/Rio/).skip[0..4] # lines containg 'Rio' excluding the
659
+ # # first five lines
660
+ #
661
+ # rio('adir').files('*.rb').skip[:symlink?] # .rb files, but not symlinks to
662
+ # # .rb files
663
+ #
664
+ # If a block is given, behaves as if <tt>skip(*args).each(&block)</tt> had been called.
665
+ #
666
+ # Returns the Rio.
667
+ #
668
+ # See IF::GrandeStream#skiplines, IF::GrandeStream#skiprecords, IF::GrandeStream#skiprows,
669
+ # IF::GrandeEntry#skipfiles, IF::GrandeEntry#skipdirs, and IF::GrandeEntry#skipentries.
670
+ #
671
+ def skip(*args,&block) target.skip(*args,&block); self end
672
+
673
+
674
+ # Returns true if the referenced file or directory is empty after honoring the grande
675
+ # selection methods.
676
+ #
677
+ # rio('f0').delete!.touch.empty? #=> true
678
+ # rio('f1').puts!("Not Empty\n").empty? #=> false
679
+ # rio('d0').delete!.mkdir.empty? #=> true
680
+ #
681
+ def empty?() target.empty? end
682
+
683
+ # IF::Grande#split has two distinct behaviors depending on
684
+ # whether or not it is called with an argument.
685
+ #
686
+ # ==== split with no aruments:
687
+ #
688
+ # Returns an array of Rios, one for each path element.
689
+ # (Note that this behavior differs from File#split.)
690
+ #
691
+ # rio('a/b/c').split #=> [rio('a'),rio('b'),rio('c')]
692
+ #
693
+ # The array returned is extended with a +to_rio+ method,
694
+ # which will put the parts back together again.
695
+ #
696
+ # ary = rio('a/b/c').split #=> [rio('a'),rio('b'),rio('c')]
697
+ # ary.to_rio #=> rio('a/b/c')
698
+ #
699
+ # ary = rio('a/b/c').split #=> [rio('a'),rio('b'),rio('c')]
700
+ # ary[1] = rio('d')
701
+ # ary.to_rio #=> rio('a/d/c')
702
+ #
703
+ # See also IF::Path#join, IF::Path#/, IF::Path#splitpath
704
+ #
705
+ # ==== split with an argument:
706
+ #
707
+ # This causes String#split(arg) to be called on every line
708
+ # before it is returned. An array of the split lines is
709
+ # returned when iterating
710
+ #
711
+ # rio('/etc/passwd').split(':').columns(0,2) { |ary|
712
+ # username,uid = ary
713
+ # }
714
+ #
715
+ # rio('/etc/passwd').split(':').columns(0,2).to_a #=> [[user1,uid1],[user2,uid2]]
716
+ #
717
+ #
718
+ def split(*args,&block) target.split(*args,&block) end
719
+
720
+
721
+ end
722
+ end
723
+ end
724
+
725
+ module RIO
726
+ class Rio
727
+ #include RIO::IF::Grande
728
+ end
729
+ end