shoesgem 0.1424.0

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 (808) hide show
  1. data/LICENSE +30 -0
  2. data/README.rdoc +31 -0
  3. data/lib/shoes.rb +4 -0
  4. data/shoes/CHANGELOG.txt +21 -0
  5. data/shoes/COPYING.txt +30 -0
  6. data/shoes/README.txt +117 -0
  7. data/shoes/VERSION.txt +1 -0
  8. data/shoes/fonts/Coolvetica.ttf +0 -0
  9. data/shoes/fonts/Lacuna.ttf +0 -0
  10. data/shoes/freetype6.dll +0 -0
  11. data/shoes/lib/shoes/cache.rb +54 -0
  12. data/shoes/lib/shoes/data.rb +39 -0
  13. data/shoes/lib/shoes/help.rb +421 -0
  14. data/shoes/lib/shoes/image.rb +25 -0
  15. data/shoes/lib/shoes/inspect.rb +128 -0
  16. data/shoes/lib/shoes/log.rb +48 -0
  17. data/shoes/lib/shoes/minitar.rb +986 -0
  18. data/shoes/lib/shoes/override.rb +38 -0
  19. data/shoes/lib/shoes/pack.rb +503 -0
  20. data/shoes/lib/shoes/search.rb +46 -0
  21. data/shoes/lib/shoes/setup.rb +329 -0
  22. data/shoes/lib/shoes/shy.rb +131 -0
  23. data/shoes/lib/shoes/shybuilder.rb +44 -0
  24. data/shoes/lib/shoes.rb +522 -0
  25. data/shoes/libcairo-2.dll +0 -0
  26. data/shoes/libeay32.dll +0 -0
  27. data/shoes/libexpat-1.dll +0 -0
  28. data/shoes/libfontconfig-1.dll +0 -0
  29. data/shoes/libgio-2.0-0.dll +0 -0
  30. data/shoes/libglib-2.0-0.dll +0 -0
  31. data/shoes/libgmodule-2.0-0.dll +0 -0
  32. data/shoes/libgobject-2.0-0.dll +0 -0
  33. data/shoes/libgthread-2.0-0.dll +0 -0
  34. data/shoes/libiconv2.dll +0 -0
  35. data/shoes/libjpeg-8.dll +0 -0
  36. data/shoes/libpango-1.0-0.dll +0 -0
  37. data/shoes/libpangocairo-1.0-0.dll +0 -0
  38. data/shoes/libpangoft2-1.0-0.dll +0 -0
  39. data/shoes/libpangowin32-1.0-0.dll +0 -0
  40. data/shoes/libpng14-14.dll +0 -0
  41. data/shoes/libportaudio-2.dll +0 -0
  42. data/shoes/libshoes.dll +0 -0
  43. data/shoes/libssl32.dll +0 -0
  44. data/shoes/libungif4.dll +0 -0
  45. data/shoes/msvcrt-ruby191.dll +0 -0
  46. data/shoes/readline5.dll +0 -0
  47. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/fast_xs.so +0 -0
  48. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/blankslate.rb +63 -0
  49. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/builder.rb +216 -0
  50. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/elements.rb +510 -0
  51. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/htmlinfo.rb +691 -0
  52. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/inspect.rb +103 -0
  53. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/modules.rb +40 -0
  54. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/parse.rb +38 -0
  55. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/tag.rb +202 -0
  56. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/tags.rb +164 -0
  57. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/traverse.rb +838 -0
  58. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot/xchar.rb +94 -0
  59. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot.rb +26 -0
  60. data/shoes/ruby/gems/1.9.1/gems/hpricot-0.8.1/lib/hpricot_scan.so +0 -0
  61. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/add/core.rb +135 -0
  62. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/add/rails.rb +58 -0
  63. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/common.rb +354 -0
  64. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/ext/generator.so +0 -0
  65. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/ext/parser.so +0 -0
  66. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/ext.rb +13 -0
  67. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json/version.rb +9 -0
  68. data/shoes/ruby/gems/1.9.1/gems/json-shoes-1.1.3/lib/json.rb +8 -0
  69. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/constants.rb +49 -0
  70. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/database.rb +721 -0
  71. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/driver/dl/api.rb +152 -0
  72. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/driver/dl/driver.rb +307 -0
  73. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/driver/native/driver.rb +219 -0
  74. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/errors.rb +68 -0
  75. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/pragmas.rb +271 -0
  76. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/resultset.rb +180 -0
  77. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/statement.rb +231 -0
  78. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/translator.rb +109 -0
  79. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/value.rb +57 -0
  80. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3/version.rb +16 -0
  81. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3.rb +1 -0
  82. data/shoes/ruby/gems/1.9.1/gems/sqlite3-ruby-1.2.5-x86-mswin32/lib/sqlite3_api.so +0 -0
  83. data/shoes/ruby/gems/1.9.1/specifications/hpricot-0.8.1.gemspec +32 -0
  84. data/shoes/ruby/gems/1.9.1/specifications/json-shoes-1.1.3.gemspec +34 -0
  85. data/shoes/ruby/gems/1.9.1/specifications/sqlite3-ruby-1.2.5-x86-mswin32.gemspec +46 -0
  86. data/shoes/ruby/lib/English.rb +155 -0
  87. data/shoes/ruby/lib/Win32API.rb +28 -0
  88. data/shoes/ruby/lib/abbrev.rb +103 -0
  89. data/shoes/ruby/lib/base64.rb +91 -0
  90. data/shoes/ruby/lib/benchmark.rb +573 -0
  91. data/shoes/ruby/lib/bigdecimal/jacobian.rb +85 -0
  92. data/shoes/ruby/lib/bigdecimal/ludcmp.rb +86 -0
  93. data/shoes/ruby/lib/bigdecimal/math.rb +237 -0
  94. data/shoes/ruby/lib/bigdecimal/newton.rb +77 -0
  95. data/shoes/ruby/lib/bigdecimal/util.rb +53 -0
  96. data/shoes/ruby/lib/cgi/cookie.rb +144 -0
  97. data/shoes/ruby/lib/cgi/core.rb +786 -0
  98. data/shoes/ruby/lib/cgi/html.rb +1021 -0
  99. data/shoes/ruby/lib/cgi/session/pstore.rb +111 -0
  100. data/shoes/ruby/lib/cgi/session.rb +537 -0
  101. data/shoes/ruby/lib/cgi/util.rb +181 -0
  102. data/shoes/ruby/lib/cgi.rb +274 -0
  103. data/shoes/ruby/lib/cmath.rb +233 -0
  104. data/shoes/ruby/lib/complex.rb +24 -0
  105. data/shoes/ruby/lib/csv.rb +2320 -0
  106. data/shoes/ruby/lib/date/format.rb +1313 -0
  107. data/shoes/ruby/lib/date.rb +1834 -0
  108. data/shoes/ruby/lib/debug.rb +907 -0
  109. data/shoes/ruby/lib/delegate.rb +311 -0
  110. data/shoes/ruby/lib/digest/hmac.rb +274 -0
  111. data/shoes/ruby/lib/digest/sha2.rb +74 -0
  112. data/shoes/ruby/lib/digest.rb +50 -0
  113. data/shoes/ruby/lib/dl/callback.rb +69 -0
  114. data/shoes/ruby/lib/dl/cparser.rb +109 -0
  115. data/shoes/ruby/lib/dl/func.rb +153 -0
  116. data/shoes/ruby/lib/dl/import.rb +215 -0
  117. data/shoes/ruby/lib/dl/pack.rb +173 -0
  118. data/shoes/ruby/lib/dl/stack.rb +146 -0
  119. data/shoes/ruby/lib/dl/struct.rb +213 -0
  120. data/shoes/ruby/lib/dl/types.rb +40 -0
  121. data/shoes/ruby/lib/dl/value.rb +112 -0
  122. data/shoes/ruby/lib/drb/acl.rb +146 -0
  123. data/shoes/ruby/lib/drb/drb.rb +1778 -0
  124. data/shoes/ruby/lib/drb/eq.rb +16 -0
  125. data/shoes/ruby/lib/drb/extserv.rb +71 -0
  126. data/shoes/ruby/lib/drb/extservm.rb +85 -0
  127. data/shoes/ruby/lib/drb/gw.rb +122 -0
  128. data/shoes/ruby/lib/drb/invokemethod.rb +34 -0
  129. data/shoes/ruby/lib/drb/observer.rb +22 -0
  130. data/shoes/ruby/lib/drb/ssl.rb +190 -0
  131. data/shoes/ruby/lib/drb/timeridconv.rb +91 -0
  132. data/shoes/ruby/lib/drb/unix.rb +108 -0
  133. data/shoes/ruby/lib/drb.rb +2 -0
  134. data/shoes/ruby/lib/e2mmap.rb +172 -0
  135. data/shoes/ruby/lib/erb.rb +902 -0
  136. data/shoes/ruby/lib/fileutils.rb +1592 -0
  137. data/shoes/ruby/lib/find.rb +81 -0
  138. data/shoes/ruby/lib/forwardable.rb +270 -0
  139. data/shoes/ruby/lib/ftsearch/analysis/analyzer.rb +16 -0
  140. data/shoes/ruby/lib/ftsearch/analysis/simple_identifier_analyzer.rb +23 -0
  141. data/shoes/ruby/lib/ftsearch/analysis/whitespace_analyzer.rb +22 -0
  142. data/shoes/ruby/lib/ftsearch/document_map_reader.rb +106 -0
  143. data/shoes/ruby/lib/ftsearch/document_map_writer.rb +46 -0
  144. data/shoes/ruby/lib/ftsearch/field_infos.rb +46 -0
  145. data/shoes/ruby/lib/ftsearch/fragment_writer.rb +114 -0
  146. data/shoes/ruby/lib/ftsearch/fulltext_reader.rb +52 -0
  147. data/shoes/ruby/lib/ftsearch/fulltext_writer.rb +75 -0
  148. data/shoes/ruby/lib/ftsearch/suffix_array_reader.rb +275 -0
  149. data/shoes/ruby/lib/ftsearch/suffix_array_writer.rb +99 -0
  150. data/shoes/ruby/lib/ftsearch/util.rb +21 -0
  151. data/shoes/ruby/lib/getoptlong.rb +610 -0
  152. data/shoes/ruby/lib/gserver.rb +253 -0
  153. data/shoes/ruby/lib/i386-mingw32/bigdecimal.so +0 -0
  154. data/shoes/ruby/lib/i386-mingw32/binject.so +0 -0
  155. data/shoes/ruby/lib/i386-mingw32/bloops.so +0 -0
  156. data/shoes/ruby/lib/i386-mingw32/continuation.so +0 -0
  157. data/shoes/ruby/lib/i386-mingw32/coverage.so +0 -0
  158. data/shoes/ruby/lib/i386-mingw32/curses.so +0 -0
  159. data/shoes/ruby/lib/i386-mingw32/digest/bubblebabble.so +0 -0
  160. data/shoes/ruby/lib/i386-mingw32/digest/md5.so +0 -0
  161. data/shoes/ruby/lib/i386-mingw32/digest/rmd160.so +0 -0
  162. data/shoes/ruby/lib/i386-mingw32/digest/sha1.so +0 -0
  163. data/shoes/ruby/lib/i386-mingw32/digest/sha2.so +0 -0
  164. data/shoes/ruby/lib/i386-mingw32/digest.so +0 -0
  165. data/shoes/ruby/lib/i386-mingw32/dl.so +0 -0
  166. data/shoes/ruby/lib/i386-mingw32/enc/big5.so +0 -0
  167. data/shoes/ruby/lib/i386-mingw32/enc/cp949.so +0 -0
  168. data/shoes/ruby/lib/i386-mingw32/enc/emacs_mule.so +0 -0
  169. data/shoes/ruby/lib/i386-mingw32/enc/encdb.so +0 -0
  170. data/shoes/ruby/lib/i386-mingw32/enc/euc_jp.so +0 -0
  171. data/shoes/ruby/lib/i386-mingw32/enc/euc_kr.so +0 -0
  172. data/shoes/ruby/lib/i386-mingw32/enc/euc_tw.so +0 -0
  173. data/shoes/ruby/lib/i386-mingw32/enc/gb18030.so +0 -0
  174. data/shoes/ruby/lib/i386-mingw32/enc/gb2312.so +0 -0
  175. data/shoes/ruby/lib/i386-mingw32/enc/gbk.so +0 -0
  176. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_1.so +0 -0
  177. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_10.so +0 -0
  178. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_11.so +0 -0
  179. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_13.so +0 -0
  180. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_14.so +0 -0
  181. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_15.so +0 -0
  182. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_16.so +0 -0
  183. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_2.so +0 -0
  184. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_3.so +0 -0
  185. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_4.so +0 -0
  186. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_5.so +0 -0
  187. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_6.so +0 -0
  188. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_7.so +0 -0
  189. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_8.so +0 -0
  190. data/shoes/ruby/lib/i386-mingw32/enc/iso_8859_9.so +0 -0
  191. data/shoes/ruby/lib/i386-mingw32/enc/koi8_r.so +0 -0
  192. data/shoes/ruby/lib/i386-mingw32/enc/koi8_u.so +0 -0
  193. data/shoes/ruby/lib/i386-mingw32/enc/shift_jis.so +0 -0
  194. data/shoes/ruby/lib/i386-mingw32/enc/trans/big5.so +0 -0
  195. data/shoes/ruby/lib/i386-mingw32/enc/trans/chinese.so +0 -0
  196. data/shoes/ruby/lib/i386-mingw32/enc/trans/escape.so +0 -0
  197. data/shoes/ruby/lib/i386-mingw32/enc/trans/gb18030.so +0 -0
  198. data/shoes/ruby/lib/i386-mingw32/enc/trans/gbk.so +0 -0
  199. data/shoes/ruby/lib/i386-mingw32/enc/trans/iso2022.so +0 -0
  200. data/shoes/ruby/lib/i386-mingw32/enc/trans/japanese.so +0 -0
  201. data/shoes/ruby/lib/i386-mingw32/enc/trans/japanese_euc.so +0 -0
  202. data/shoes/ruby/lib/i386-mingw32/enc/trans/japanese_sjis.so +0 -0
  203. data/shoes/ruby/lib/i386-mingw32/enc/trans/korean.so +0 -0
  204. data/shoes/ruby/lib/i386-mingw32/enc/trans/single_byte.so +0 -0
  205. data/shoes/ruby/lib/i386-mingw32/enc/trans/transdb.so +0 -0
  206. data/shoes/ruby/lib/i386-mingw32/enc/trans/utf_16_32.so +0 -0
  207. data/shoes/ruby/lib/i386-mingw32/enc/utf_16be.so +0 -0
  208. data/shoes/ruby/lib/i386-mingw32/enc/utf_16le.so +0 -0
  209. data/shoes/ruby/lib/i386-mingw32/enc/utf_32be.so +0 -0
  210. data/shoes/ruby/lib/i386-mingw32/enc/utf_32le.so +0 -0
  211. data/shoes/ruby/lib/i386-mingw32/enc/windows_1251.so +0 -0
  212. data/shoes/ruby/lib/i386-mingw32/etc.so +0 -0
  213. data/shoes/ruby/lib/i386-mingw32/fcntl.so +0 -0
  214. data/shoes/ruby/lib/i386-mingw32/fiber.so +0 -0
  215. data/shoes/ruby/lib/i386-mingw32/ftsearchrt.so +0 -0
  216. data/shoes/ruby/lib/i386-mingw32/gdbm.so +0 -0
  217. data/shoes/ruby/lib/i386-mingw32/iconv.so +0 -0
  218. data/shoes/ruby/lib/i386-mingw32/io/wait.so +0 -0
  219. data/shoes/ruby/lib/i386-mingw32/json/ext/generator.so +0 -0
  220. data/shoes/ruby/lib/i386-mingw32/json/ext/parser.so +0 -0
  221. data/shoes/ruby/lib/i386-mingw32/mathn/complex.so +0 -0
  222. data/shoes/ruby/lib/i386-mingw32/mathn/rational.so +0 -0
  223. data/shoes/ruby/lib/i386-mingw32/nkf.so +0 -0
  224. data/shoes/ruby/lib/i386-mingw32/openssl.so +0 -0
  225. data/shoes/ruby/lib/i386-mingw32/racc/cparse.so +0 -0
  226. data/shoes/ruby/lib/i386-mingw32/rbconfig.rb +196 -0
  227. data/shoes/ruby/lib/i386-mingw32/readline.so +0 -0
  228. data/shoes/ruby/lib/i386-mingw32/ripper.so +0 -0
  229. data/shoes/ruby/lib/i386-mingw32/sdbm.so +0 -0
  230. data/shoes/ruby/lib/i386-mingw32/socket.so +0 -0
  231. data/shoes/ruby/lib/i386-mingw32/stringio.so +0 -0
  232. data/shoes/ruby/lib/i386-mingw32/strscan.so +0 -0
  233. data/shoes/ruby/lib/i386-mingw32/syck.so +0 -0
  234. data/shoes/ruby/lib/i386-mingw32/win32ole.so +0 -0
  235. data/shoes/ruby/lib/i386-mingw32/zlib.so +0 -0
  236. data/shoes/ruby/lib/io/nonblock.rb +23 -0
  237. data/shoes/ruby/lib/ipaddr.rb +813 -0
  238. data/shoes/ruby/lib/irb/cmd/chws.rb +32 -0
  239. data/shoes/ruby/lib/irb/cmd/fork.rb +38 -0
  240. data/shoes/ruby/lib/irb/cmd/help.rb +36 -0
  241. data/shoes/ruby/lib/irb/cmd/load.rb +66 -0
  242. data/shoes/ruby/lib/irb/cmd/nop.rb +38 -0
  243. data/shoes/ruby/lib/irb/cmd/pushws.rb +38 -0
  244. data/shoes/ruby/lib/irb/cmd/subirb.rb +42 -0
  245. data/shoes/ruby/lib/irb/completion.rb +207 -0
  246. data/shoes/ruby/lib/irb/context.rb +255 -0
  247. data/shoes/ruby/lib/irb/ext/change-ws.rb +61 -0
  248. data/shoes/ruby/lib/irb/ext/history.rb +109 -0
  249. data/shoes/ruby/lib/irb/ext/loader.rb +119 -0
  250. data/shoes/ruby/lib/irb/ext/math-mode.rb +36 -0
  251. data/shoes/ruby/lib/irb/ext/multi-irb.rb +240 -0
  252. data/shoes/ruby/lib/irb/ext/save-history.rb +100 -0
  253. data/shoes/ruby/lib/irb/ext/tracer.rb +60 -0
  254. data/shoes/ruby/lib/irb/ext/use-loader.rb +64 -0
  255. data/shoes/ruby/lib/irb/ext/workspaces.rb +55 -0
  256. data/shoes/ruby/lib/irb/extend-command.rb +272 -0
  257. data/shoes/ruby/lib/irb/frame.rb +66 -0
  258. data/shoes/ruby/lib/irb/help.rb +35 -0
  259. data/shoes/ruby/lib/irb/init.rb +288 -0
  260. data/shoes/ruby/lib/irb/input-method.rb +142 -0
  261. data/shoes/ruby/lib/irb/lc/error.rb +29 -0
  262. data/shoes/ruby/lib/irb/lc/help-message +38 -0
  263. data/shoes/ruby/lib/irb/lc/ja/encoding_aliases.rb +8 -0
  264. data/shoes/ruby/lib/irb/lc/ja/error.rb +27 -0
  265. data/shoes/ruby/lib/irb/lc/ja/help-message +39 -0
  266. data/shoes/ruby/lib/irb/locale.rb +195 -0
  267. data/shoes/ruby/lib/irb/magic-file.rb +36 -0
  268. data/shoes/ruby/lib/irb/notifier.rb +144 -0
  269. data/shoes/ruby/lib/irb/output-method.rb +69 -0
  270. data/shoes/ruby/lib/irb/ruby-lex.rb +1188 -0
  271. data/shoes/ruby/lib/irb/ruby-token.rb +270 -0
  272. data/shoes/ruby/lib/irb/slex.rb +282 -0
  273. data/shoes/ruby/lib/irb/src_encoding.rb +4 -0
  274. data/shoes/ruby/lib/irb/version.rb +15 -0
  275. data/shoes/ruby/lib/irb/workspace.rb +108 -0
  276. data/shoes/ruby/lib/irb/ws-for-case-2.rb +14 -0
  277. data/shoes/ruby/lib/irb/xmp.rb +97 -0
  278. data/shoes/ruby/lib/irb.rb +354 -0
  279. data/shoes/ruby/lib/json/add/core.rb +135 -0
  280. data/shoes/ruby/lib/json/add/rails.rb +58 -0
  281. data/shoes/ruby/lib/json/common.rb +354 -0
  282. data/shoes/ruby/lib/json/editor.rb +1371 -0
  283. data/shoes/ruby/lib/json/ext.rb +15 -0
  284. data/shoes/ruby/lib/json/version.rb +9 -0
  285. data/shoes/ruby/lib/json.rb +297 -0
  286. data/shoes/ruby/lib/kconv.rb +282 -0
  287. data/shoes/ruby/lib/logger.rb +732 -0
  288. data/shoes/ruby/lib/mathn.rb +206 -0
  289. data/shoes/ruby/lib/matrix.rb +1381 -0
  290. data/shoes/ruby/lib/minitest/autorun.rb +9 -0
  291. data/shoes/ruby/lib/minitest/mock.rb +37 -0
  292. data/shoes/ruby/lib/minitest/spec.rb +89 -0
  293. data/shoes/ruby/lib/minitest/unit.rb +497 -0
  294. data/shoes/ruby/lib/mkmf.rb +1958 -0
  295. data/shoes/ruby/lib/monitor.rb +265 -0
  296. data/shoes/ruby/lib/mutex_m.rb +91 -0
  297. data/shoes/ruby/lib/net/ftp.rb +981 -0
  298. data/shoes/ruby/lib/net/http.rb +2399 -0
  299. data/shoes/ruby/lib/net/https.rb +136 -0
  300. data/shoes/ruby/lib/net/imap.rb +3500 -0
  301. data/shoes/ruby/lib/net/pop.rb +1000 -0
  302. data/shoes/ruby/lib/net/protocol.rb +382 -0
  303. data/shoes/ruby/lib/net/smtp.rb +1014 -0
  304. data/shoes/ruby/lib/net/telnet.rb +759 -0
  305. data/shoes/ruby/lib/observer.rb +193 -0
  306. data/shoes/ruby/lib/open-uri.rb +832 -0
  307. data/shoes/ruby/lib/open3.rb +98 -0
  308. data/shoes/ruby/lib/openssl/bn.rb +35 -0
  309. data/shoes/ruby/lib/openssl/buffering.rb +242 -0
  310. data/shoes/ruby/lib/openssl/cipher.rb +65 -0
  311. data/shoes/ruby/lib/openssl/digest.rb +61 -0
  312. data/shoes/ruby/lib/openssl/ssl.rb +178 -0
  313. data/shoes/ruby/lib/openssl/x509.rb +155 -0
  314. data/shoes/ruby/lib/openssl.rb +24 -0
  315. data/shoes/ruby/lib/optparse/date.rb +17 -0
  316. data/shoes/ruby/lib/optparse/shellwords.rb +6 -0
  317. data/shoes/ruby/lib/optparse/time.rb +10 -0
  318. data/shoes/ruby/lib/optparse/uri.rb +6 -0
  319. data/shoes/ruby/lib/optparse/version.rb +70 -0
  320. data/shoes/ruby/lib/optparse.rb +1810 -0
  321. data/shoes/ruby/lib/ostruct.rb +145 -0
  322. data/shoes/ruby/lib/pathname.rb +1099 -0
  323. data/shoes/ruby/lib/pp.rb +532 -0
  324. data/shoes/ruby/lib/prettyprint.rb +896 -0
  325. data/shoes/ruby/lib/prime.rb +471 -0
  326. data/shoes/ruby/lib/profile.rb +10 -0
  327. data/shoes/ruby/lib/profiler.rb +59 -0
  328. data/shoes/ruby/lib/pstore.rb +543 -0
  329. data/shoes/ruby/lib/racc/parser.rb +441 -0
  330. data/shoes/ruby/lib/rake/classic_namespace.rb +8 -0
  331. data/shoes/ruby/lib/rake/clean.rb +33 -0
  332. data/shoes/ruby/lib/rake/gempackagetask.rb +97 -0
  333. data/shoes/ruby/lib/rake/loaders/makefile.rb +35 -0
  334. data/shoes/ruby/lib/rake/packagetask.rb +185 -0
  335. data/shoes/ruby/lib/rake/rake_test_loader.rb +5 -0
  336. data/shoes/ruby/lib/rake/rdoctask.rb +147 -0
  337. data/shoes/ruby/lib/rake/runtest.rb +23 -0
  338. data/shoes/ruby/lib/rake/tasklib.rb +23 -0
  339. data/shoes/ruby/lib/rake/testtask.rb +161 -0
  340. data/shoes/ruby/lib/rake/win32.rb +34 -0
  341. data/shoes/ruby/lib/rake.rb +2465 -0
  342. data/shoes/ruby/lib/rational.rb +19 -0
  343. data/shoes/ruby/lib/rbconfig/datadir.rb +24 -0
  344. data/shoes/ruby/lib/rdoc/code_objects.rb +1061 -0
  345. data/shoes/ruby/lib/rdoc/diagram.rb +340 -0
  346. data/shoes/ruby/lib/rdoc/dot.rb +249 -0
  347. data/shoes/ruby/lib/rdoc/generator/chm/chm.rb +100 -0
  348. data/shoes/ruby/lib/rdoc/generator/chm.rb +113 -0
  349. data/shoes/ruby/lib/rdoc/generator/html/common.rb +24 -0
  350. data/shoes/ruby/lib/rdoc/generator/html/frameless.rb +92 -0
  351. data/shoes/ruby/lib/rdoc/generator/html/hefss.rb +150 -0
  352. data/shoes/ruby/lib/rdoc/generator/html/html.rb +769 -0
  353. data/shoes/ruby/lib/rdoc/generator/html/kilmer.rb +151 -0
  354. data/shoes/ruby/lib/rdoc/generator/html/kilmerfactory.rb +427 -0
  355. data/shoes/ruby/lib/rdoc/generator/html/one_page_html.rb +122 -0
  356. data/shoes/ruby/lib/rdoc/generator/html.rb +445 -0
  357. data/shoes/ruby/lib/rdoc/generator/ri.rb +226 -0
  358. data/shoes/ruby/lib/rdoc/generator/texinfo/class.texinfo.erb +44 -0
  359. data/shoes/ruby/lib/rdoc/generator/texinfo/file.texinfo.erb +6 -0
  360. data/shoes/ruby/lib/rdoc/generator/texinfo/method.texinfo.erb +6 -0
  361. data/shoes/ruby/lib/rdoc/generator/texinfo/texinfo.erb +28 -0
  362. data/shoes/ruby/lib/rdoc/generator/texinfo.rb +81 -0
  363. data/shoes/ruby/lib/rdoc/generator/xml/rdf.rb +113 -0
  364. data/shoes/ruby/lib/rdoc/generator/xml/xml.rb +123 -0
  365. data/shoes/ruby/lib/rdoc/generator/xml.rb +117 -0
  366. data/shoes/ruby/lib/rdoc/generator.rb +1082 -0
  367. data/shoes/ruby/lib/rdoc/known_classes.rb +68 -0
  368. data/shoes/ruby/lib/rdoc/markup/attribute_manager.rb +265 -0
  369. data/shoes/ruby/lib/rdoc/markup/formatter.rb +14 -0
  370. data/shoes/ruby/lib/rdoc/markup/fragments.rb +337 -0
  371. data/shoes/ruby/lib/rdoc/markup/inline.rb +101 -0
  372. data/shoes/ruby/lib/rdoc/markup/lines.rb +152 -0
  373. data/shoes/ruby/lib/rdoc/markup/preprocess.rb +75 -0
  374. data/shoes/ruby/lib/rdoc/markup/to_flow.rb +185 -0
  375. data/shoes/ruby/lib/rdoc/markup/to_html.rb +403 -0
  376. data/shoes/ruby/lib/rdoc/markup/to_html_crossref.rb +148 -0
  377. data/shoes/ruby/lib/rdoc/markup/to_latex.rb +328 -0
  378. data/shoes/ruby/lib/rdoc/markup/to_test.rb +50 -0
  379. data/shoes/ruby/lib/rdoc/markup/to_texinfo.rb +69 -0
  380. data/shoes/ruby/lib/rdoc/markup.rb +378 -0
  381. data/shoes/ruby/lib/rdoc/options.rb +638 -0
  382. data/shoes/ruby/lib/rdoc/parser/c.rb +661 -0
  383. data/shoes/ruby/lib/rdoc/parser/f95.rb +1835 -0
  384. data/shoes/ruby/lib/rdoc/parser/perl.rb +165 -0
  385. data/shoes/ruby/lib/rdoc/parser/ruby.rb +2829 -0
  386. data/shoes/ruby/lib/rdoc/parser/simple.rb +38 -0
  387. data/shoes/ruby/lib/rdoc/parser.rb +142 -0
  388. data/shoes/ruby/lib/rdoc/rdoc.rb +293 -0
  389. data/shoes/ruby/lib/rdoc/ri/cache.rb +187 -0
  390. data/shoes/ruby/lib/rdoc/ri/descriptions.rb +156 -0
  391. data/shoes/ruby/lib/rdoc/ri/display.rb +392 -0
  392. data/shoes/ruby/lib/rdoc/ri/driver.rb +669 -0
  393. data/shoes/ruby/lib/rdoc/ri/formatter.rb +616 -0
  394. data/shoes/ruby/lib/rdoc/ri/paths.rb +99 -0
  395. data/shoes/ruby/lib/rdoc/ri/reader.rb +106 -0
  396. data/shoes/ruby/lib/rdoc/ri/util.rb +79 -0
  397. data/shoes/ruby/lib/rdoc/ri/writer.rb +68 -0
  398. data/shoes/ruby/lib/rdoc/ri.rb +8 -0
  399. data/shoes/ruby/lib/rdoc/stats.rb +115 -0
  400. data/shoes/ruby/lib/rdoc/template.rb +64 -0
  401. data/shoes/ruby/lib/rdoc/tokenstream.rb +33 -0
  402. data/shoes/ruby/lib/rdoc.rb +395 -0
  403. data/shoes/ruby/lib/resolv-replace.rb +63 -0
  404. data/shoes/ruby/lib/resolv.rb +2262 -0
  405. data/shoes/ruby/lib/rexml/attlistdecl.rb +62 -0
  406. data/shoes/ruby/lib/rexml/attribute.rb +188 -0
  407. data/shoes/ruby/lib/rexml/cdata.rb +67 -0
  408. data/shoes/ruby/lib/rexml/child.rb +96 -0
  409. data/shoes/ruby/lib/rexml/comment.rb +80 -0
  410. data/shoes/ruby/lib/rexml/doctype.rb +270 -0
  411. data/shoes/ruby/lib/rexml/document.rb +231 -0
  412. data/shoes/ruby/lib/rexml/dtd/attlistdecl.rb +10 -0
  413. data/shoes/ruby/lib/rexml/dtd/dtd.rb +51 -0
  414. data/shoes/ruby/lib/rexml/dtd/elementdecl.rb +17 -0
  415. data/shoes/ruby/lib/rexml/dtd/entitydecl.rb +56 -0
  416. data/shoes/ruby/lib/rexml/dtd/notationdecl.rb +39 -0
  417. data/shoes/ruby/lib/rexml/element.rb +1246 -0
  418. data/shoes/ruby/lib/rexml/encoding.rb +71 -0
  419. data/shoes/ruby/lib/rexml/encodings/CP-1252.rb +103 -0
  420. data/shoes/ruby/lib/rexml/encodings/EUC-JP.rb +35 -0
  421. data/shoes/ruby/lib/rexml/encodings/ICONV.rb +22 -0
  422. data/shoes/ruby/lib/rexml/encodings/ISO-8859-1.rb +7 -0
  423. data/shoes/ruby/lib/rexml/encodings/ISO-8859-15.rb +72 -0
  424. data/shoes/ruby/lib/rexml/encodings/SHIFT-JIS.rb +37 -0
  425. data/shoes/ruby/lib/rexml/encodings/SHIFT_JIS.rb +1 -0
  426. data/shoes/ruby/lib/rexml/encodings/UNILE.rb +34 -0
  427. data/shoes/ruby/lib/rexml/encodings/US-ASCII.rb +30 -0
  428. data/shoes/ruby/lib/rexml/encodings/UTF-16.rb +35 -0
  429. data/shoes/ruby/lib/rexml/encodings/UTF-8.rb +18 -0
  430. data/shoes/ruby/lib/rexml/entity.rb +166 -0
  431. data/shoes/ruby/lib/rexml/formatters/default.rb +109 -0
  432. data/shoes/ruby/lib/rexml/formatters/pretty.rb +139 -0
  433. data/shoes/ruby/lib/rexml/formatters/transitive.rb +58 -0
  434. data/shoes/ruby/lib/rexml/functions.rb +388 -0
  435. data/shoes/ruby/lib/rexml/instruction.rb +70 -0
  436. data/shoes/ruby/lib/rexml/light/node.rb +196 -0
  437. data/shoes/ruby/lib/rexml/namespace.rb +47 -0
  438. data/shoes/ruby/lib/rexml/node.rb +75 -0
  439. data/shoes/ruby/lib/rexml/output.rb +24 -0
  440. data/shoes/ruby/lib/rexml/parent.rb +166 -0
  441. data/shoes/ruby/lib/rexml/parseexception.rb +51 -0
  442. data/shoes/ruby/lib/rexml/parsers/baseparser.rb +530 -0
  443. data/shoes/ruby/lib/rexml/parsers/lightparser.rb +58 -0
  444. data/shoes/ruby/lib/rexml/parsers/pullparser.rb +196 -0
  445. data/shoes/ruby/lib/rexml/parsers/sax2parser.rb +247 -0
  446. data/shoes/ruby/lib/rexml/parsers/streamparser.rb +46 -0
  447. data/shoes/ruby/lib/rexml/parsers/treeparser.rb +100 -0
  448. data/shoes/ruby/lib/rexml/parsers/ultralightparser.rb +56 -0
  449. data/shoes/ruby/lib/rexml/parsers/xpathparser.rb +698 -0
  450. data/shoes/ruby/lib/rexml/quickpath.rb +263 -0
  451. data/shoes/ruby/lib/rexml/rexml.rb +31 -0
  452. data/shoes/ruby/lib/rexml/sax2listener.rb +97 -0
  453. data/shoes/ruby/lib/rexml/source.rb +258 -0
  454. data/shoes/ruby/lib/rexml/streamlistener.rb +92 -0
  455. data/shoes/ruby/lib/rexml/syncenumerator.rb +32 -0
  456. data/shoes/ruby/lib/rexml/text.rb +404 -0
  457. data/shoes/ruby/lib/rexml/undefinednamespaceexception.rb +8 -0
  458. data/shoes/ruby/lib/rexml/validation/relaxng.rb +559 -0
  459. data/shoes/ruby/lib/rexml/validation/validation.rb +155 -0
  460. data/shoes/ruby/lib/rexml/validation/validationexception.rb +9 -0
  461. data/shoes/ruby/lib/rexml/xmldecl.rb +119 -0
  462. data/shoes/ruby/lib/rexml/xmltokens.rb +18 -0
  463. data/shoes/ruby/lib/rexml/xpath.rb +77 -0
  464. data/shoes/ruby/lib/rexml/xpath_parser.rb +792 -0
  465. data/shoes/ruby/lib/rinda/rinda.rb +283 -0
  466. data/shoes/ruby/lib/rinda/ring.rb +271 -0
  467. data/shoes/ruby/lib/rinda/tuplespace.rb +642 -0
  468. data/shoes/ruby/lib/ripper/core.rb +70 -0
  469. data/shoes/ruby/lib/ripper/filter.rb +70 -0
  470. data/shoes/ruby/lib/ripper/lexer.rb +179 -0
  471. data/shoes/ruby/lib/ripper/sexp.rb +99 -0
  472. data/shoes/ruby/lib/ripper.rb +4 -0
  473. data/shoes/ruby/lib/rss/0.9.rb +427 -0
  474. data/shoes/ruby/lib/rss/1.0.rb +452 -0
  475. data/shoes/ruby/lib/rss/2.0.rb +111 -0
  476. data/shoes/ruby/lib/rss/atom.rb +748 -0
  477. data/shoes/ruby/lib/rss/content/1.0.rb +10 -0
  478. data/shoes/ruby/lib/rss/content/2.0.rb +12 -0
  479. data/shoes/ruby/lib/rss/content.rb +31 -0
  480. data/shoes/ruby/lib/rss/converter.rb +170 -0
  481. data/shoes/ruby/lib/rss/dublincore/1.0.rb +13 -0
  482. data/shoes/ruby/lib/rss/dublincore/2.0.rb +13 -0
  483. data/shoes/ruby/lib/rss/dublincore/atom.rb +17 -0
  484. data/shoes/ruby/lib/rss/dublincore.rb +161 -0
  485. data/shoes/ruby/lib/rss/image.rb +193 -0
  486. data/shoes/ruby/lib/rss/itunes.rb +410 -0
  487. data/shoes/ruby/lib/rss/maker/0.9.rb +467 -0
  488. data/shoes/ruby/lib/rss/maker/1.0.rb +434 -0
  489. data/shoes/ruby/lib/rss/maker/2.0.rb +223 -0
  490. data/shoes/ruby/lib/rss/maker/atom.rb +172 -0
  491. data/shoes/ruby/lib/rss/maker/base.rb +880 -0
  492. data/shoes/ruby/lib/rss/maker/content.rb +21 -0
  493. data/shoes/ruby/lib/rss/maker/dublincore.rb +124 -0
  494. data/shoes/ruby/lib/rss/maker/entry.rb +163 -0
  495. data/shoes/ruby/lib/rss/maker/feed.rb +430 -0
  496. data/shoes/ruby/lib/rss/maker/image.rb +111 -0
  497. data/shoes/ruby/lib/rss/maker/itunes.rb +242 -0
  498. data/shoes/ruby/lib/rss/maker/slash.rb +33 -0
  499. data/shoes/ruby/lib/rss/maker/syndication.rb +18 -0
  500. data/shoes/ruby/lib/rss/maker/taxonomy.rb +118 -0
  501. data/shoes/ruby/lib/rss/maker/trackback.rb +61 -0
  502. data/shoes/ruby/lib/rss/maker.rb +44 -0
  503. data/shoes/ruby/lib/rss/parser.rb +568 -0
  504. data/shoes/ruby/lib/rss/rexmlparser.rb +54 -0
  505. data/shoes/ruby/lib/rss/rss.rb +1313 -0
  506. data/shoes/ruby/lib/rss/slash.rb +49 -0
  507. data/shoes/ruby/lib/rss/syndication.rb +67 -0
  508. data/shoes/ruby/lib/rss/taxonomy.rb +145 -0
  509. data/shoes/ruby/lib/rss/trackback.rb +288 -0
  510. data/shoes/ruby/lib/rss/utils.rb +111 -0
  511. data/shoes/ruby/lib/rss/xml-stylesheet.rb +105 -0
  512. data/shoes/ruby/lib/rss/xml.rb +71 -0
  513. data/shoes/ruby/lib/rss/xmlparser.rb +93 -0
  514. data/shoes/ruby/lib/rss/xmlscanner.rb +121 -0
  515. data/shoes/ruby/lib/rss.rb +19 -0
  516. data/shoes/ruby/lib/rubygems/builder.rb +88 -0
  517. data/shoes/ruby/lib/rubygems/command.rb +406 -0
  518. data/shoes/ruby/lib/rubygems/command_manager.rb +146 -0
  519. data/shoes/ruby/lib/rubygems/commands/build_command.rb +53 -0
  520. data/shoes/ruby/lib/rubygems/commands/cert_command.rb +86 -0
  521. data/shoes/ruby/lib/rubygems/commands/check_command.rb +75 -0
  522. data/shoes/ruby/lib/rubygems/commands/cleanup_command.rb +91 -0
  523. data/shoes/ruby/lib/rubygems/commands/contents_command.rb +74 -0
  524. data/shoes/ruby/lib/rubygems/commands/dependency_command.rb +188 -0
  525. data/shoes/ruby/lib/rubygems/commands/environment_command.rb +128 -0
  526. data/shoes/ruby/lib/rubygems/commands/fetch_command.rb +62 -0
  527. data/shoes/ruby/lib/rubygems/commands/generate_index_command.rb +57 -0
  528. data/shoes/ruby/lib/rubygems/commands/help_command.rb +172 -0
  529. data/shoes/ruby/lib/rubygems/commands/install_command.rb +148 -0
  530. data/shoes/ruby/lib/rubygems/commands/list_command.rb +35 -0
  531. data/shoes/ruby/lib/rubygems/commands/lock_command.rb +110 -0
  532. data/shoes/ruby/lib/rubygems/commands/mirror_command.rb +111 -0
  533. data/shoes/ruby/lib/rubygems/commands/outdated_command.rb +33 -0
  534. data/shoes/ruby/lib/rubygems/commands/pristine_command.rb +93 -0
  535. data/shoes/ruby/lib/rubygems/commands/query_command.rb +233 -0
  536. data/shoes/ruby/lib/rubygems/commands/rdoc_command.rb +82 -0
  537. data/shoes/ruby/lib/rubygems/commands/search_command.rb +37 -0
  538. data/shoes/ruby/lib/rubygems/commands/server_command.rb +48 -0
  539. data/shoes/ruby/lib/rubygems/commands/sources_command.rb +152 -0
  540. data/shoes/ruby/lib/rubygems/commands/specification_command.rb +77 -0
  541. data/shoes/ruby/lib/rubygems/commands/stale_command.rb +27 -0
  542. data/shoes/ruby/lib/rubygems/commands/uninstall_command.rb +73 -0
  543. data/shoes/ruby/lib/rubygems/commands/unpack_command.rb +95 -0
  544. data/shoes/ruby/lib/rubygems/commands/update_command.rb +181 -0
  545. data/shoes/ruby/lib/rubygems/commands/which_command.rb +87 -0
  546. data/shoes/ruby/lib/rubygems/config_file.rb +266 -0
  547. data/shoes/ruby/lib/rubygems/custom_require.rb +46 -0
  548. data/shoes/ruby/lib/rubygems/defaults.rb +89 -0
  549. data/shoes/ruby/lib/rubygems/dependency.rb +119 -0
  550. data/shoes/ruby/lib/rubygems/dependency_installer.rb +258 -0
  551. data/shoes/ruby/lib/rubygems/dependency_list.rb +165 -0
  552. data/shoes/ruby/lib/rubygems/digest/digest_adapter.rb +40 -0
  553. data/shoes/ruby/lib/rubygems/digest/md5.rb +23 -0
  554. data/shoes/ruby/lib/rubygems/digest/sha1.rb +17 -0
  555. data/shoes/ruby/lib/rubygems/digest/sha2.rb +17 -0
  556. data/shoes/ruby/lib/rubygems/doc_manager.rb +214 -0
  557. data/shoes/ruby/lib/rubygems/exceptions.rb +84 -0
  558. data/shoes/ruby/lib/rubygems/ext/builder.rb +56 -0
  559. data/shoes/ruby/lib/rubygems/ext/configure_builder.rb +24 -0
  560. data/shoes/ruby/lib/rubygems/ext/ext_conf_builder.rb +23 -0
  561. data/shoes/ruby/lib/rubygems/ext/rake_builder.rb +27 -0
  562. data/shoes/ruby/lib/rubygems/ext.rb +18 -0
  563. data/shoes/ruby/lib/rubygems/format.rb +87 -0
  564. data/shoes/ruby/lib/rubygems/gem_openssl.rb +83 -0
  565. data/shoes/ruby/lib/rubygems/gem_path_searcher.rb +100 -0
  566. data/shoes/ruby/lib/rubygems/gem_runner.rb +58 -0
  567. data/shoes/ruby/lib/rubygems/indexer/abstract_index_builder.rb +88 -0
  568. data/shoes/ruby/lib/rubygems/indexer/latest_index_builder.rb +35 -0
  569. data/shoes/ruby/lib/rubygems/indexer/marshal_index_builder.rb +17 -0
  570. data/shoes/ruby/lib/rubygems/indexer/master_index_builder.rb +54 -0
  571. data/shoes/ruby/lib/rubygems/indexer/quick_index_builder.rb +50 -0
  572. data/shoes/ruby/lib/rubygems/indexer.rb +370 -0
  573. data/shoes/ruby/lib/rubygems/install_update_options.rb +113 -0
  574. data/shoes/ruby/lib/rubygems/installer.rb +578 -0
  575. data/shoes/ruby/lib/rubygems/local_remote_options.rb +134 -0
  576. data/shoes/ruby/lib/rubygems/old_format.rb +148 -0
  577. data/shoes/ruby/lib/rubygems/package/f_sync_dir.rb +24 -0
  578. data/shoes/ruby/lib/rubygems/package/tar_header.rb +245 -0
  579. data/shoes/ruby/lib/rubygems/package/tar_input.rb +219 -0
  580. data/shoes/ruby/lib/rubygems/package/tar_output.rb +143 -0
  581. data/shoes/ruby/lib/rubygems/package/tar_reader/entry.rb +99 -0
  582. data/shoes/ruby/lib/rubygems/package/tar_reader.rb +86 -0
  583. data/shoes/ruby/lib/rubygems/package/tar_writer.rb +180 -0
  584. data/shoes/ruby/lib/rubygems/package.rb +95 -0
  585. data/shoes/ruby/lib/rubygems/platform.rb +178 -0
  586. data/shoes/ruby/lib/rubygems/remote_fetcher.rb +344 -0
  587. data/shoes/ruby/lib/rubygems/require_paths_builder.rb +15 -0
  588. data/shoes/ruby/lib/rubygems/requirement.rb +163 -0
  589. data/shoes/ruby/lib/rubygems/rubygems_version.rb +6 -0
  590. data/shoes/ruby/lib/rubygems/security.rb +786 -0
  591. data/shoes/ruby/lib/rubygems/server.rb +629 -0
  592. data/shoes/ruby/lib/rubygems/source_index.rb +559 -0
  593. data/shoes/ruby/lib/rubygems/source_info_cache.rb +393 -0
  594. data/shoes/ruby/lib/rubygems/source_info_cache_entry.rb +56 -0
  595. data/shoes/ruby/lib/rubygems/spec_fetcher.rb +249 -0
  596. data/shoes/ruby/lib/rubygems/specification.rb +1262 -0
  597. data/shoes/ruby/lib/rubygems/test_utilities.rb +131 -0
  598. data/shoes/ruby/lib/rubygems/timer.rb +25 -0
  599. data/shoes/ruby/lib/rubygems/uninstaller.rb +242 -0
  600. data/shoes/ruby/lib/rubygems/user_interaction.rb +360 -0
  601. data/shoes/ruby/lib/rubygems/validator.rb +208 -0
  602. data/shoes/ruby/lib/rubygems/version.rb +167 -0
  603. data/shoes/ruby/lib/rubygems/version_option.rb +48 -0
  604. data/shoes/ruby/lib/rubygems.rb +888 -0
  605. data/shoes/ruby/lib/scanf.rb +703 -0
  606. data/shoes/ruby/lib/securerandom.rb +182 -0
  607. data/shoes/ruby/lib/set.rb +1274 -0
  608. data/shoes/ruby/lib/shell/builtin-command.rb +160 -0
  609. data/shoes/ruby/lib/shell/command-processor.rb +593 -0
  610. data/shoes/ruby/lib/shell/error.rb +25 -0
  611. data/shoes/ruby/lib/shell/filter.rb +109 -0
  612. data/shoes/ruby/lib/shell/process-controller.rb +319 -0
  613. data/shoes/ruby/lib/shell/system-command.rb +159 -0
  614. data/shoes/ruby/lib/shell/version.rb +15 -0
  615. data/shoes/ruby/lib/shell.rb +300 -0
  616. data/shoes/ruby/lib/shellwords.rb +156 -0
  617. data/shoes/ruby/lib/singleton.rb +313 -0
  618. data/shoes/ruby/lib/sync.rb +307 -0
  619. data/shoes/ruby/lib/tempfile.rb +218 -0
  620. data/shoes/ruby/lib/test/unit/assertions.rb +122 -0
  621. data/shoes/ruby/lib/test/unit/testcase.rb +12 -0
  622. data/shoes/ruby/lib/test/unit.rb +66 -0
  623. data/shoes/ruby/lib/thread.rb +367 -0
  624. data/shoes/ruby/lib/thwait.rb +168 -0
  625. data/shoes/ruby/lib/time.rb +869 -0
  626. data/shoes/ruby/lib/timeout.rb +108 -0
  627. data/shoes/ruby/lib/tmpdir.rb +138 -0
  628. data/shoes/ruby/lib/tracer.rb +166 -0
  629. data/shoes/ruby/lib/tsort.rb +290 -0
  630. data/shoes/ruby/lib/ubygems.rb +10 -0
  631. data/shoes/ruby/lib/un.rb +304 -0
  632. data/shoes/ruby/lib/uri/common.rb +727 -0
  633. data/shoes/ruby/lib/uri/ftp.rb +198 -0
  634. data/shoes/ruby/lib/uri/generic.rb +1128 -0
  635. data/shoes/ruby/lib/uri/http.rb +100 -0
  636. data/shoes/ruby/lib/uri/https.rb +20 -0
  637. data/shoes/ruby/lib/uri/ldap.rb +190 -0
  638. data/shoes/ruby/lib/uri/ldaps.rb +12 -0
  639. data/shoes/ruby/lib/uri/mailto.rb +266 -0
  640. data/shoes/ruby/lib/uri.rb +29 -0
  641. data/shoes/ruby/lib/weakref.rb +80 -0
  642. data/shoes/ruby/lib/webrick/accesslog.rb +75 -0
  643. data/shoes/ruby/lib/webrick/cgi.rb +260 -0
  644. data/shoes/ruby/lib/webrick/compat.rb +15 -0
  645. data/shoes/ruby/lib/webrick/config.rb +100 -0
  646. data/shoes/ruby/lib/webrick/cookie.rb +110 -0
  647. data/shoes/ruby/lib/webrick/htmlutils.rb +25 -0
  648. data/shoes/ruby/lib/webrick/httpauth/authenticator.rb +79 -0
  649. data/shoes/ruby/lib/webrick/httpauth/basicauth.rb +65 -0
  650. data/shoes/ruby/lib/webrick/httpauth/digestauth.rb +344 -0
  651. data/shoes/ruby/lib/webrick/httpauth/htdigest.rb +91 -0
  652. data/shoes/ruby/lib/webrick/httpauth/htgroup.rb +61 -0
  653. data/shoes/ruby/lib/webrick/httpauth/htpasswd.rb +83 -0
  654. data/shoes/ruby/lib/webrick/httpauth/userdb.rb +29 -0
  655. data/shoes/ruby/lib/webrick/httpauth.rb +45 -0
  656. data/shoes/ruby/lib/webrick/httpproxy.rb +288 -0
  657. data/shoes/ruby/lib/webrick/httprequest.rb +402 -0
  658. data/shoes/ruby/lib/webrick/httpresponse.rb +326 -0
  659. data/shoes/ruby/lib/webrick/https.rb +63 -0
  660. data/shoes/ruby/lib/webrick/httpserver.rb +217 -0
  661. data/shoes/ruby/lib/webrick/httpservlet/abstract.rb +70 -0
  662. data/shoes/ruby/lib/webrick/httpservlet/cgi_runner.rb +47 -0
  663. data/shoes/ruby/lib/webrick/httpservlet/cgihandler.rb +110 -0
  664. data/shoes/ruby/lib/webrick/httpservlet/erbhandler.rb +54 -0
  665. data/shoes/ruby/lib/webrick/httpservlet/filehandler.rb +435 -0
  666. data/shoes/ruby/lib/webrick/httpservlet/prochandler.rb +33 -0
  667. data/shoes/ruby/lib/webrick/httpservlet.rb +22 -0
  668. data/shoes/ruby/lib/webrick/httpstatus.rb +132 -0
  669. data/shoes/ruby/lib/webrick/httputils.rb +392 -0
  670. data/shoes/ruby/lib/webrick/httpversion.rb +49 -0
  671. data/shoes/ruby/lib/webrick/log.rb +88 -0
  672. data/shoes/ruby/lib/webrick/server.rb +210 -0
  673. data/shoes/ruby/lib/webrick/ssl.rb +126 -0
  674. data/shoes/ruby/lib/webrick/utils.rb +175 -0
  675. data/shoes/ruby/lib/webrick/version.rb +13 -0
  676. data/shoes/ruby/lib/webrick.rb +29 -0
  677. data/shoes/ruby/lib/win32/registry.rb +832 -0
  678. data/shoes/ruby/lib/win32/resolv.rb +370 -0
  679. data/shoes/ruby/lib/win32/sspi.rb +330 -0
  680. data/shoes/ruby/lib/win32ole/property.rb +16 -0
  681. data/shoes/ruby/lib/xmlrpc/base64.rb +81 -0
  682. data/shoes/ruby/lib/xmlrpc/client.rb +625 -0
  683. data/shoes/ruby/lib/xmlrpc/config.rb +40 -0
  684. data/shoes/ruby/lib/xmlrpc/create.rb +290 -0
  685. data/shoes/ruby/lib/xmlrpc/datetime.rb +142 -0
  686. data/shoes/ruby/lib/xmlrpc/httpserver.rb +178 -0
  687. data/shoes/ruby/lib/xmlrpc/marshal.rb +76 -0
  688. data/shoes/ruby/lib/xmlrpc/parser.rb +813 -0
  689. data/shoes/ruby/lib/xmlrpc/server.rb +778 -0
  690. data/shoes/ruby/lib/xmlrpc/utils.rb +165 -0
  691. data/shoes/ruby/lib/yaml/baseemitter.rb +242 -0
  692. data/shoes/ruby/lib/yaml/basenode.rb +216 -0
  693. data/shoes/ruby/lib/yaml/constants.rb +45 -0
  694. data/shoes/ruby/lib/yaml/dbm.rb +111 -0
  695. data/shoes/ruby/lib/yaml/encoding.rb +33 -0
  696. data/shoes/ruby/lib/yaml/error.rb +34 -0
  697. data/shoes/ruby/lib/yaml/loader.rb +14 -0
  698. data/shoes/ruby/lib/yaml/rubytypes.rb +446 -0
  699. data/shoes/ruby/lib/yaml/store.rb +43 -0
  700. data/shoes/ruby/lib/yaml/stream.rb +40 -0
  701. data/shoes/ruby/lib/yaml/stringio.rb +83 -0
  702. data/shoes/ruby/lib/yaml/syck.rb +19 -0
  703. data/shoes/ruby/lib/yaml/tag.rb +91 -0
  704. data/shoes/ruby/lib/yaml/types.rb +192 -0
  705. data/shoes/ruby/lib/yaml/yamlnode.rb +54 -0
  706. data/shoes/ruby/lib/yaml/ypath.rb +52 -0
  707. data/shoes/ruby/lib/yaml.rb +440 -0
  708. data/shoes/samples/class-book.rb +43 -0
  709. data/shoes/samples/class-book.yaml +387 -0
  710. data/shoes/samples/expert-definr.rb +23 -0
  711. data/shoes/samples/expert-funnies.rb +51 -0
  712. data/shoes/samples/expert-irb.rb +112 -0
  713. data/shoes/samples/expert-minesweeper.rb +267 -0
  714. data/shoes/samples/expert-othello.rb +319 -0
  715. data/shoes/samples/expert-pong.rb +62 -0
  716. data/shoes/samples/expert-tankspank.rb +385 -0
  717. data/shoes/samples/good-arc.rb +37 -0
  718. data/shoes/samples/good-clock.rb +51 -0
  719. data/shoes/samples/good-follow.rb +26 -0
  720. data/shoes/samples/good-reminder.rb +174 -0
  721. data/shoes/samples/good-vjot.rb +56 -0
  722. data/shoes/samples/simple-accordion.rb +75 -0
  723. data/shoes/samples/simple-anim-shapes.rb +17 -0
  724. data/shoes/samples/simple-anim-text.rb +13 -0
  725. data/shoes/samples/simple-arc.rb +23 -0
  726. data/shoes/samples/simple-bounce.rb +24 -0
  727. data/shoes/samples/simple-calc.rb +70 -0
  728. data/shoes/samples/simple-control-sizes.rb +24 -0
  729. data/shoes/samples/simple-curve.rb +26 -0
  730. data/shoes/samples/simple-dialogs.rb +29 -0
  731. data/shoes/samples/simple-downloader.rb +27 -0
  732. data/shoes/samples/simple-draw.rb +13 -0
  733. data/shoes/samples/simple-editor.rb +28 -0
  734. data/shoes/samples/simple-form.rb +28 -0
  735. data/shoes/samples/simple-form.shy +0 -0
  736. data/shoes/samples/simple-mask.rb +21 -0
  737. data/shoes/samples/simple-menu.rb +31 -0
  738. data/shoes/samples/simple-menu1.rb +35 -0
  739. data/shoes/samples/simple-rubygems.rb +29 -0
  740. data/shoes/samples/simple-slide.rb +45 -0
  741. data/shoes/samples/simple-sphere.rb +28 -0
  742. data/shoes/samples/simple-timer.rb +13 -0
  743. data/shoes/samples/simple-video.rb +13 -0
  744. data/shoes/shoes +21 -0
  745. data/shoes/shoes.exe +0 -0
  746. data/shoes/shoes.exe.manifest +17 -0
  747. data/shoes/sqlite3.dll +0 -0
  748. data/shoes/static/Shoes.icns +0 -0
  749. data/shoes/static/Thumbs.db +0 -0
  750. data/shoes/static/app-icon.png +0 -0
  751. data/shoes/static/avatar.png +0 -0
  752. data/shoes/static/code_highlighter.js +188 -0
  753. data/shoes/static/code_highlighter_ruby.js +26 -0
  754. data/shoes/static/icon-debug.png +0 -0
  755. data/shoes/static/icon-error.png +0 -0
  756. data/shoes/static/icon-info.png +0 -0
  757. data/shoes/static/icon-warn.png +0 -0
  758. data/shoes/static/listbox_button1.png +0 -0
  759. data/shoes/static/listbox_button2.png +0 -0
  760. data/shoes/static/man-app.png +0 -0
  761. data/shoes/static/man-builds.png +0 -0
  762. data/shoes/static/man-editor-notepad.png +0 -0
  763. data/shoes/static/man-editor-osx.png +0 -0
  764. data/shoes/static/man-ele-background.png +0 -0
  765. data/shoes/static/man-ele-border.png +0 -0
  766. data/shoes/static/man-ele-button.png +0 -0
  767. data/shoes/static/man-ele-check.png +0 -0
  768. data/shoes/static/man-ele-editbox.png +0 -0
  769. data/shoes/static/man-ele-editline.png +0 -0
  770. data/shoes/static/man-ele-image.png +0 -0
  771. data/shoes/static/man-ele-listbox.png +0 -0
  772. data/shoes/static/man-ele-progress.png +0 -0
  773. data/shoes/static/man-ele-radio.png +0 -0
  774. data/shoes/static/man-ele-shape.png +0 -0
  775. data/shoes/static/man-ele-textblock.png +0 -0
  776. data/shoes/static/man-ele-video.png +0 -0
  777. data/shoes/static/man-intro-dmg.png +0 -0
  778. data/shoes/static/man-intro-exe.png +0 -0
  779. data/shoes/static/man-look-tiger.png +0 -0
  780. data/shoes/static/man-look-ubuntu.png +0 -0
  781. data/shoes/static/man-look-vista.png +0 -0
  782. data/shoes/static/man-run-osx.png +0 -0
  783. data/shoes/static/man-run-vista.png +0 -0
  784. data/shoes/static/man-run-xp.png +0 -0
  785. data/shoes/static/man-shot1.png +0 -0
  786. data/shoes/static/manual-en.txt +2783 -0
  787. data/shoes/static/manual-ja.txt +2780 -0
  788. data/shoes/static/manual.css +167 -0
  789. data/shoes/static/menu-corner1.png +0 -0
  790. data/shoes/static/menu-corner2.png +0 -0
  791. data/shoes/static/menu-gray.png +0 -0
  792. data/shoes/static/menu-left.png +0 -0
  793. data/shoes/static/menu-right.png +0 -0
  794. data/shoes/static/menu-top.png +0 -0
  795. data/shoes/static/shoes-dmg.jpg +0 -0
  796. data/shoes/static/shoes-icon-blue.png +0 -0
  797. data/shoes/static/shoes-icon.png +0 -0
  798. data/shoes/static/shoes-manual-apps.gif +0 -0
  799. data/shoes/static/stripe.png +0 -0
  800. data/shoes/static/stubs/blank.exe +0 -0
  801. data/shoes/static/stubs/blank.hfz +0 -0
  802. data/shoes/static/stubs/blank.run +375 -0
  803. data/shoes/static/stubs/cocoa-install +0 -0
  804. data/shoes/static/stubs/sh-install +48 -0
  805. data/shoes/static/tutor-back.png +0 -0
  806. data/shoes/zlib.dll +0 -0
  807. data/shoes/zlib1.dll +0 -0
  808. metadata +887 -0
@@ -0,0 +1,2320 @@
1
+ # encoding: US-ASCII
2
+ # = csv.rb -- CSV Reading and Writing
3
+ #
4
+ # Created by James Edward Gray II on 2005-10-31.
5
+ # Copyright 2005 James Edward Gray II. You can redistribute or modify this code
6
+ # under the terms of Ruby's license.
7
+ #
8
+ # See CSV for documentation.
9
+ #
10
+ # == Description
11
+ #
12
+ # Welcome to the new and improved CSV.
13
+ #
14
+ # This version of the CSV library began its life as FasterCSV. FasterCSV was
15
+ # intended as a replacement to Ruby's then standard CSV library. It was
16
+ # designed to address concerns users of that library had and it had three
17
+ # primary goals:
18
+ #
19
+ # 1. Be significantly faster than CSV while remaining a pure Ruby library.
20
+ # 2. Use a smaller and easier to maintain code base. (FasterCSV eventually
21
+ # grew larger, was also but considerably richer in features. The parsing
22
+ # core remains quite small.)
23
+ # 3. Improve on the CSV interface.
24
+ #
25
+ # Obviously, the last one is subjective. I did try to defer to the original
26
+ # interface whenever I didn't have a compelling reason to change it though, so
27
+ # hopefully this won't be too radically different.
28
+ #
29
+ # We must have met our goals because FasterCSV was renamed to CSV and replaced
30
+ # the original library.
31
+ #
32
+ # == What's Different From the Old CSV?
33
+ #
34
+ # I'm sure I'll miss something, but I'll try to mention most of the major
35
+ # differences I am aware of, to help others quickly get up to speed:
36
+ #
37
+ # === CSV Parsing
38
+ #
39
+ # * This parser is m17n aware. See CSV for full details.
40
+ # * This library has a stricter parser and will throw MalformedCSVErrors on
41
+ # problematic data.
42
+ # * This library has a less liberal idea of a line ending than CSV. What you
43
+ # set as the <tt>:row_sep</tt> is law. It can auto-detect your line endings
44
+ # though.
45
+ # * The old library returned empty lines as <tt>[nil]</tt>. This library calls
46
+ # them <tt>[]</tt>.
47
+ # * This library has a much faster parser.
48
+ #
49
+ # === Interface
50
+ #
51
+ # * CSV now uses Hash-style parameters to set options.
52
+ # * CSV no longer has generate_row() or parse_row().
53
+ # * The old CSV's Reader and Writer classes have been dropped.
54
+ # * CSV::open() is now more like Ruby's open().
55
+ # * CSV objects now support most standard IO methods.
56
+ # * CSV now has a new() method used to wrap objects like String and IO for
57
+ # reading and writing.
58
+ # * CSV::generate() is different from the old method.
59
+ # * CSV no longer supports partial reads. It works line-by-line.
60
+ # * CSV no longer allows the instance methods to override the separators for
61
+ # performance reasons. They must be set in the constructor.
62
+ #
63
+ # If you use this library and find yourself missing any functionality I have
64
+ # trimmed, please {let me know}[mailto:james@grayproductions.net].
65
+ #
66
+ # == Documentation
67
+ #
68
+ # See CSV for documentation.
69
+ #
70
+ # == What is CSV, really?
71
+ #
72
+ # CSV maintains a pretty strict definition of CSV taken directly from
73
+ # {the RFC}[http://www.ietf.org/rfc/rfc4180.txt]. I relax the rules in only one
74
+ # place and that is to make using this library easier. CSV will parse all valid
75
+ # CSV.
76
+ #
77
+ # What you don't want to do is feed CSV invalid data. Because of the way the
78
+ # CSV format works, it's common for a parser to need to read until the end of
79
+ # the file to be sure a field is invalid. This eats a lot of time and memory.
80
+ #
81
+ # Luckily, when working with invalid CSV, Ruby's built-in methods will almost
82
+ # always be superior in every way. For example, parsing non-quoted fields is as
83
+ # easy as:
84
+ #
85
+ # data.split(",")
86
+ #
87
+ # == Questions and/or Comments
88
+ #
89
+ # Feel free to email {James Edward Gray II}[mailto:james@grayproductions.net]
90
+ # with any questions.
91
+
92
+ require "forwardable"
93
+ require "English"
94
+ require "date"
95
+ require "stringio"
96
+
97
+ #
98
+ # This class provides a complete interface to CSV files and data. It offers
99
+ # tools to enable you to read and write to and from Strings or IO objects, as
100
+ # needed.
101
+ #
102
+ # == Reading
103
+ #
104
+ # === From a File
105
+ #
106
+ # ==== A Line at a Time
107
+ #
108
+ # CSV.foreach("path/to/file.csv") do |row|
109
+ # # use row here...
110
+ # end
111
+ #
112
+ # ==== All at Once
113
+ #
114
+ # arr_of_arrs = CSV.read("path/to/file.csv")
115
+ #
116
+ # === From a String
117
+ #
118
+ # ==== A Line at a Time
119
+ #
120
+ # CSV.parse("CSV,data,String") do |row|
121
+ # # use row here...
122
+ # end
123
+ #
124
+ # ==== All at Once
125
+ #
126
+ # arr_of_arrs = CSV.parse("CSV,data,String")
127
+ #
128
+ # == Writing
129
+ #
130
+ # === To a File
131
+ #
132
+ # CSV.open("path/to/file.csv", "wb") do |csv|
133
+ # csv << ["row", "of", "CSV", "data"]
134
+ # csv << ["another", "row"]
135
+ # # ...
136
+ # end
137
+ #
138
+ # === To a String
139
+ #
140
+ # csv_string = CSV.generate do |csv|
141
+ # csv << ["row", "of", "CSV", "data"]
142
+ # csv << ["another", "row"]
143
+ # # ...
144
+ # end
145
+ #
146
+ # == Convert a Single Line
147
+ #
148
+ # csv_string = ["CSV", "data"].to_csv # to CSV
149
+ # csv_array = "CSV,String".parse_csv # from CSV
150
+ #
151
+ # == Shortcut Interface
152
+ #
153
+ # CSV { |csv_out| csv_out << %w{my data here} } # to $stdout
154
+ # CSV(csv = "") { |csv_str| csv_str << %w{my data here} } # to a String
155
+ # CSV($stderr) { |csv_err| csv_err << %w{my data here} } # to $stderr
156
+ #
157
+ # == CSV and Character Encodings (M17n or Multilingualization)
158
+ #
159
+ # This new CSV parser is m17n savvy. The parser works in the Encoding of the IO
160
+ # or String object being read from or written to. Your data is never transcoded
161
+ # (unless you ask Ruby to transcode it for you) and will literally be parsed in
162
+ # the Encoding it is in. Thus CSV will return Arrays or Rows of Strings in the
163
+ # Encoding of your data. This is accomplished by transcoding the parser itself
164
+ # into your Encoding.
165
+ #
166
+ # Some transcoding must take place, of course, to accomplish this multiencoding
167
+ # support. For example, <tt>:col_sep</tt>, <tt>:row_sep</tt>, and
168
+ # <tt>:quote_char</tt> must be transcoded to match your data. Hopefully this
169
+ # makes the entire process feel transparent, since CSV's defaults should just
170
+ # magically work for you data. However, you can set these values manually in
171
+ # the target Encoding to avoid the translation.
172
+ #
173
+ # It's also important to note that while all of CSV's core parser is now
174
+ # Encoding agnostic, some features are not. For example, the built-in
175
+ # converters will try to transcode data to UTF-8 before making conversions.
176
+ # Again, you can provide custom converters that are aware of your Encodings to
177
+ # avoid this translation. It's just too hard for me to support native
178
+ # conversions in all of Ruby's Encodings.
179
+ #
180
+ # Anyway, the practical side of this is simple: make sure IO and String objects
181
+ # passed into CSV have the proper Encoding set and everything should just work.
182
+ # CSV methods that allow you to open IO objects (CSV::foreach(), CSV::open(),
183
+ # CSV::read(), and CSV::readlines()) do allow you to specify the Encoding.
184
+ #
185
+ # One minor exception comes when generating CSV into a String with an Encoding
186
+ # that is not ASCII compatible. There's no existing data for CSV to use to
187
+ # prepare itself and thus you will probably need to manually specify the desired
188
+ # Encoding for most of those cases. It will try to guess using the fields in a
189
+ # row of output though, when using CSV::generate_line() or Array#to_csv().
190
+ #
191
+ # I try to point out any other Encoding issues in the documentation of methods
192
+ # as they come up.
193
+ #
194
+ # This has been tested to the best of my ability with all non-"dummy" Encodings
195
+ # Ruby ships with. However, it is brave new code and may have some bugs.
196
+ # Please feel free to {report}[mailto:james@grayproductions.net] any issues you
197
+ # find with it.
198
+ #
199
+ class CSV
200
+ # The version of the installed library.
201
+ VERSION = "2.4.5".freeze
202
+
203
+ #
204
+ # A CSV::Row is part Array and part Hash. It retains an order for the fields
205
+ # and allows duplicates just as an Array would, but also allows you to access
206
+ # fields by name just as you could if they were in a Hash.
207
+ #
208
+ # All rows returned by CSV will be constructed from this class, if header row
209
+ # processing is activated.
210
+ #
211
+ class Row
212
+ #
213
+ # Construct a new CSV::Row from +headers+ and +fields+, which are expected
214
+ # to be Arrays. If one Array is shorter than the other, it will be padded
215
+ # with +nil+ objects.
216
+ #
217
+ # The optional +header_row+ parameter can be set to +true+ to indicate, via
218
+ # CSV::Row.header_row?() and CSV::Row.field_row?(), that this is a header
219
+ # row. Otherwise, the row is assumes to be a field row.
220
+ #
221
+ # A CSV::Row object supports the following Array methods through delegation:
222
+ #
223
+ # * empty?()
224
+ # * length()
225
+ # * size()
226
+ #
227
+ def initialize(headers, fields, header_row = false)
228
+ @header_row = header_row
229
+
230
+ # handle extra headers or fields
231
+ @row = if headers.size > fields.size
232
+ headers.zip(fields)
233
+ else
234
+ fields.zip(headers).map { |pair| pair.reverse }
235
+ end
236
+ end
237
+
238
+ # Internal data format used to compare equality.
239
+ attr_reader :row
240
+ protected :row
241
+
242
+ ### Array Delegation ###
243
+
244
+ extend Forwardable
245
+ def_delegators :@row, :empty?, :length, :size
246
+
247
+ # Returns +true+ if this is a header row.
248
+ def header_row?
249
+ @header_row
250
+ end
251
+
252
+ # Returns +true+ if this is a field row.
253
+ def field_row?
254
+ not header_row?
255
+ end
256
+
257
+ # Returns the headers of this row.
258
+ def headers
259
+ @row.map { |pair| pair.first }
260
+ end
261
+
262
+ #
263
+ # :call-seq:
264
+ # field( header )
265
+ # field( header, offset )
266
+ # field( index )
267
+ #
268
+ # This method will fetch the field value by +header+ or +index+. If a field
269
+ # is not found, +nil+ is returned.
270
+ #
271
+ # When provided, +offset+ ensures that a header match occurrs on or later
272
+ # than the +offset+ index. You can use this to find duplicate headers,
273
+ # without resorting to hard-coding exact indices.
274
+ #
275
+ def field(header_or_index, minimum_index = 0)
276
+ # locate the pair
277
+ finder = header_or_index.is_a?(Integer) ? :[] : :assoc
278
+ pair = @row[minimum_index..-1].send(finder, header_or_index)
279
+
280
+ # return the field if we have a pair
281
+ pair.nil? ? nil : pair.last
282
+ end
283
+ alias_method :[], :field
284
+
285
+ #
286
+ # :call-seq:
287
+ # []=( header, value )
288
+ # []=( header, offset, value )
289
+ # []=( index, value )
290
+ #
291
+ # Looks up the field by the semantics described in CSV::Row.field() and
292
+ # assigns the +value+.
293
+ #
294
+ # Assigning past the end of the row with an index will set all pairs between
295
+ # to <tt>[nil, nil]</tt>. Assigning to an unused header appends the new
296
+ # pair.
297
+ #
298
+ def []=(*args)
299
+ value = args.pop
300
+
301
+ if args.first.is_a? Integer
302
+ if @row[args.first].nil? # extending past the end with index
303
+ @row[args.first] = [nil, value]
304
+ @row.map! { |pair| pair.nil? ? [nil, nil] : pair }
305
+ else # normal index assignment
306
+ @row[args.first][1] = value
307
+ end
308
+ else
309
+ index = index(*args)
310
+ if index.nil? # appending a field
311
+ self << [args.first, value]
312
+ else # normal header assignment
313
+ @row[index][1] = value
314
+ end
315
+ end
316
+ end
317
+
318
+ #
319
+ # :call-seq:
320
+ # <<( field )
321
+ # <<( header_and_field_array )
322
+ # <<( header_and_field_hash )
323
+ #
324
+ # If a two-element Array is provided, it is assumed to be a header and field
325
+ # and the pair is appended. A Hash works the same way with the key being
326
+ # the header and the value being the field. Anything else is assumed to be
327
+ # a lone field which is appended with a +nil+ header.
328
+ #
329
+ # This method returns the row for chaining.
330
+ #
331
+ def <<(arg)
332
+ if arg.is_a?(Array) and arg.size == 2 # appending a header and name
333
+ @row << arg
334
+ elsif arg.is_a?(Hash) # append header and name pairs
335
+ arg.each { |pair| @row << pair }
336
+ else # append field value
337
+ @row << [nil, arg]
338
+ end
339
+
340
+ self # for chaining
341
+ end
342
+
343
+ #
344
+ # A shortcut for appending multiple fields. Equivalent to:
345
+ #
346
+ # args.each { |arg| csv_row << arg }
347
+ #
348
+ # This method returns the row for chaining.
349
+ #
350
+ def push(*args)
351
+ args.each { |arg| self << arg }
352
+
353
+ self # for chaining
354
+ end
355
+
356
+ #
357
+ # :call-seq:
358
+ # delete( header )
359
+ # delete( header, offset )
360
+ # delete( index )
361
+ #
362
+ # Used to remove a pair from the row by +header+ or +index+. The pair is
363
+ # located as described in CSV::Row.field(). The deleted pair is returned,
364
+ # or +nil+ if a pair could not be found.
365
+ #
366
+ def delete(header_or_index, minimum_index = 0)
367
+ if header_or_index.is_a? Integer # by index
368
+ @row.delete_at(header_or_index)
369
+ else # by header
370
+ @row.delete_at(index(header_or_index, minimum_index))
371
+ end
372
+ end
373
+
374
+ #
375
+ # The provided +block+ is passed a header and field for each pair in the row
376
+ # and expected to return +true+ or +false+, depending on whether the pair
377
+ # should be deleted.
378
+ #
379
+ # This method returns the row for chaining.
380
+ #
381
+ def delete_if(&block)
382
+ @row.delete_if(&block)
383
+
384
+ self # for chaining
385
+ end
386
+
387
+ #
388
+ # This method accepts any number of arguments which can be headers, indices,
389
+ # Ranges of either, or two-element Arrays containing a header and offset.
390
+ # Each argument will be replaced with a field lookup as described in
391
+ # CSV::Row.field().
392
+ #
393
+ # If called with no arguments, all fields are returned.
394
+ #
395
+ def fields(*headers_and_or_indices)
396
+ if headers_and_or_indices.empty? # return all fields--no arguments
397
+ @row.map { |pair| pair.last }
398
+ else # or work like values_at()
399
+ headers_and_or_indices.inject(Array.new) do |all, h_or_i|
400
+ all + if h_or_i.is_a? Range
401
+ index_begin = h_or_i.begin.is_a?(Integer) ? h_or_i.begin :
402
+ index(h_or_i.begin)
403
+ index_end = h_or_i.end.is_a?(Integer) ? h_or_i.end :
404
+ index(h_or_i.end)
405
+ new_range = h_or_i.exclude_end? ? (index_begin...index_end) :
406
+ (index_begin..index_end)
407
+ fields.values_at(new_range)
408
+ else
409
+ [field(*Array(h_or_i))]
410
+ end
411
+ end
412
+ end
413
+ end
414
+ alias_method :values_at, :fields
415
+
416
+ #
417
+ # :call-seq:
418
+ # index( header )
419
+ # index( header, offset )
420
+ #
421
+ # This method will return the index of a field with the provided +header+.
422
+ # The +offset+ can be used to locate duplicate header names, as described in
423
+ # CSV::Row.field().
424
+ #
425
+ def index(header, minimum_index = 0)
426
+ # find the pair
427
+ index = headers[minimum_index..-1].index(header)
428
+ # return the index at the right offset, if we found one
429
+ index.nil? ? nil : index + minimum_index
430
+ end
431
+
432
+ # Returns +true+ if +name+ is a header for this row, and +false+ otherwise.
433
+ def header?(name)
434
+ headers.include? name
435
+ end
436
+ alias_method :include?, :header?
437
+
438
+ #
439
+ # Returns +true+ if +data+ matches a field in this row, and +false+
440
+ # otherwise.
441
+ #
442
+ def field?(data)
443
+ fields.include? data
444
+ end
445
+
446
+ include Enumerable
447
+
448
+ #
449
+ # Yields each pair of the row as header and field tuples (much like
450
+ # iterating over a Hash).
451
+ #
452
+ # Support for Enumerable.
453
+ #
454
+ # This method returns the row for chaining.
455
+ #
456
+ def each(&block)
457
+ @row.each(&block)
458
+
459
+ self # for chaining
460
+ end
461
+
462
+ #
463
+ # Returns +true+ if this row contains the same headers and fields in the
464
+ # same order as +other+.
465
+ #
466
+ def ==(other)
467
+ @row == other.row
468
+ end
469
+
470
+ #
471
+ # Collapses the row into a simple Hash. Be warning that this discards field
472
+ # order and clobbers duplicate fields.
473
+ #
474
+ def to_hash
475
+ # flatten just one level of the internal Array
476
+ Hash[*@row.inject(Array.new) { |ary, pair| ary.push(*pair) }]
477
+ end
478
+
479
+ #
480
+ # Returns the row as a CSV String. Headers are not used. Equivalent to:
481
+ #
482
+ # csv_row.fields.to_csv( options )
483
+ #
484
+ def to_csv(options = Hash.new)
485
+ fields.to_csv(options)
486
+ end
487
+ alias_method :to_s, :to_csv
488
+
489
+ # A summary of fields, by header, in an ASCII compatible String.
490
+ def inspect
491
+ str = ["#<", self.class.to_s]
492
+ each do |header, field|
493
+ str << " " << (header.is_a?(Symbol) ? header.to_s : header.inspect) <<
494
+ ":" << field.inspect
495
+ end
496
+ str << ">"
497
+ begin
498
+ str.join
499
+ rescue # any encoding error
500
+ str.map do |s|
501
+ e = Encoding::Converter.asciicompat_encoding(s.encoding)
502
+ e ? s.encode(e) : s.force_encoding("ASCII-8BIT")
503
+ end.join
504
+ end
505
+ end
506
+ end
507
+
508
+ #
509
+ # A CSV::Table is a two-dimensional data structure for representing CSV
510
+ # documents. Tables allow you to work with the data by row or column,
511
+ # manipulate the data, and even convert the results back to CSV, if needed.
512
+ #
513
+ # All tables returned by CSV will be constructed from this class, if header
514
+ # row processing is activated.
515
+ #
516
+ class Table
517
+ #
518
+ # Construct a new CSV::Table from +array_of_rows+, which are expected
519
+ # to be CSV::Row objects. All rows are assumed to have the same headers.
520
+ #
521
+ # A CSV::Table object supports the following Array methods through
522
+ # delegation:
523
+ #
524
+ # * empty?()
525
+ # * length()
526
+ # * size()
527
+ #
528
+ def initialize(array_of_rows)
529
+ @table = array_of_rows
530
+ @mode = :col_or_row
531
+ end
532
+
533
+ # The current access mode for indexing and iteration.
534
+ attr_reader :mode
535
+
536
+ # Internal data format used to compare equality.
537
+ attr_reader :table
538
+ protected :table
539
+
540
+ ### Array Delegation ###
541
+
542
+ extend Forwardable
543
+ def_delegators :@table, :empty?, :length, :size
544
+
545
+ #
546
+ # Returns a duplicate table object, in column mode. This is handy for
547
+ # chaining in a single call without changing the table mode, but be aware
548
+ # that this method can consume a fair amount of memory for bigger data sets.
549
+ #
550
+ # This method returns the duplicate table for chaining. Don't chain
551
+ # destructive methods (like []=()) this way though, since you are working
552
+ # with a duplicate.
553
+ #
554
+ def by_col
555
+ self.class.new(@table.dup).by_col!
556
+ end
557
+
558
+ #
559
+ # Switches the mode of this table to column mode. All calls to indexing and
560
+ # iteration methods will work with columns until the mode is changed again.
561
+ #
562
+ # This method returns the table and is safe to chain.
563
+ #
564
+ def by_col!
565
+ @mode = :col
566
+
567
+ self
568
+ end
569
+
570
+ #
571
+ # Returns a duplicate table object, in mixed mode. This is handy for
572
+ # chaining in a single call without changing the table mode, but be aware
573
+ # that this method can consume a fair amount of memory for bigger data sets.
574
+ #
575
+ # This method returns the duplicate table for chaining. Don't chain
576
+ # destructive methods (like []=()) this way though, since you are working
577
+ # with a duplicate.
578
+ #
579
+ def by_col_or_row
580
+ self.class.new(@table.dup).by_col_or_row!
581
+ end
582
+
583
+ #
584
+ # Switches the mode of this table to mixed mode. All calls to indexing and
585
+ # iteration methods will use the default intelligent indexing system until
586
+ # the mode is changed again. In mixed mode an index is assumed to be a row
587
+ # reference while anything else is assumed to be column access by headers.
588
+ #
589
+ # This method returns the table and is safe to chain.
590
+ #
591
+ def by_col_or_row!
592
+ @mode = :col_or_row
593
+
594
+ self
595
+ end
596
+
597
+ #
598
+ # Returns a duplicate table object, in row mode. This is handy for chaining
599
+ # in a single call without changing the table mode, but be aware that this
600
+ # method can consume a fair amount of memory for bigger data sets.
601
+ #
602
+ # This method returns the duplicate table for chaining. Don't chain
603
+ # destructive methods (like []=()) this way though, since you are working
604
+ # with a duplicate.
605
+ #
606
+ def by_row
607
+ self.class.new(@table.dup).by_row!
608
+ end
609
+
610
+ #
611
+ # Switches the mode of this table to row mode. All calls to indexing and
612
+ # iteration methods will work with rows until the mode is changed again.
613
+ #
614
+ # This method returns the table and is safe to chain.
615
+ #
616
+ def by_row!
617
+ @mode = :row
618
+
619
+ self
620
+ end
621
+
622
+ #
623
+ # Returns the headers for the first row of this table (assumed to match all
624
+ # other rows). An empty Array is returned for empty tables.
625
+ #
626
+ def headers
627
+ if @table.empty?
628
+ Array.new
629
+ else
630
+ @table.first.headers
631
+ end
632
+ end
633
+
634
+ #
635
+ # In the default mixed mode, this method returns rows for index access and
636
+ # columns for header access. You can force the index association by first
637
+ # calling by_col!() or by_row!().
638
+ #
639
+ # Columns are returned as an Array of values. Altering that Array has no
640
+ # effect on the table.
641
+ #
642
+ def [](index_or_header)
643
+ if @mode == :row or # by index
644
+ (@mode == :col_or_row and index_or_header.is_a? Integer)
645
+ @table[index_or_header]
646
+ else # by header
647
+ @table.map { |row| row[index_or_header] }
648
+ end
649
+ end
650
+
651
+ #
652
+ # In the default mixed mode, this method assigns rows for index access and
653
+ # columns for header access. You can force the index association by first
654
+ # calling by_col!() or by_row!().
655
+ #
656
+ # Rows may be set to an Array of values (which will inherit the table's
657
+ # headers()) or a CSV::Row.
658
+ #
659
+ # Columns may be set to a single value, which is copied to each row of the
660
+ # column, or an Array of values. Arrays of values are assigned to rows top
661
+ # to bottom in row major order. Excess values are ignored and if the Array
662
+ # does not have a value for each row the extra rows will receive a +nil+.
663
+ #
664
+ # Assigning to an existing column or row clobbers the data. Assigning to
665
+ # new columns creates them at the right end of the table.
666
+ #
667
+ def []=(index_or_header, value)
668
+ if @mode == :row or # by index
669
+ (@mode == :col_or_row and index_or_header.is_a? Integer)
670
+ if value.is_a? Array
671
+ @table[index_or_header] = Row.new(headers, value)
672
+ else
673
+ @table[index_or_header] = value
674
+ end
675
+ else # set column
676
+ if value.is_a? Array # multiple values
677
+ @table.each_with_index do |row, i|
678
+ if row.header_row?
679
+ row[index_or_header] = index_or_header
680
+ else
681
+ row[index_or_header] = value[i]
682
+ end
683
+ end
684
+ else # repeated value
685
+ @table.each do |row|
686
+ if row.header_row?
687
+ row[index_or_header] = index_or_header
688
+ else
689
+ row[index_or_header] = value
690
+ end
691
+ end
692
+ end
693
+ end
694
+ end
695
+
696
+ #
697
+ # The mixed mode default is to treat a list of indices as row access,
698
+ # returning the rows indicated. Anything else is considered columnar
699
+ # access. For columnar access, the return set has an Array for each row
700
+ # with the values indicated by the headers in each Array. You can force
701
+ # column or row mode using by_col!() or by_row!().
702
+ #
703
+ # You cannot mix column and row access.
704
+ #
705
+ def values_at(*indices_or_headers)
706
+ if @mode == :row or # by indices
707
+ ( @mode == :col_or_row and indices_or_headers.all? do |index|
708
+ index.is_a?(Integer) or
709
+ ( index.is_a?(Range) and
710
+ index.first.is_a?(Integer) and
711
+ index.last.is_a?(Integer) )
712
+ end )
713
+ @table.values_at(*indices_or_headers)
714
+ else # by headers
715
+ @table.map { |row| row.values_at(*indices_or_headers) }
716
+ end
717
+ end
718
+
719
+ #
720
+ # Adds a new row to the bottom end of this table. You can provide an Array,
721
+ # which will be converted to a CSV::Row (inheriting the table's headers()),
722
+ # or a CSV::Row.
723
+ #
724
+ # This method returns the table for chaining.
725
+ #
726
+ def <<(row_or_array)
727
+ if row_or_array.is_a? Array # append Array
728
+ @table << Row.new(headers, row_or_array)
729
+ else # append Row
730
+ @table << row_or_array
731
+ end
732
+
733
+ self # for chaining
734
+ end
735
+
736
+ #
737
+ # A shortcut for appending multiple rows. Equivalent to:
738
+ #
739
+ # rows.each { |row| self << row }
740
+ #
741
+ # This method returns the table for chaining.
742
+ #
743
+ def push(*rows)
744
+ rows.each { |row| self << row }
745
+
746
+ self # for chaining
747
+ end
748
+
749
+ #
750
+ # Removes and returns the indicated column or row. In the default mixed
751
+ # mode indices refer to rows and everything else is assumed to be a column
752
+ # header. Use by_col!() or by_row!() to force the lookup.
753
+ #
754
+ def delete(index_or_header)
755
+ if @mode == :row or # by index
756
+ (@mode == :col_or_row and index_or_header.is_a? Integer)
757
+ @table.delete_at(index_or_header)
758
+ else # by header
759
+ @table.map { |row| row.delete(index_or_header).last }
760
+ end
761
+ end
762
+
763
+ #
764
+ # Removes any column or row for which the block returns +true+. In the
765
+ # default mixed mode or row mode, iteration is the standard row major
766
+ # walking of rows. In column mode, interation will +yield+ two element
767
+ # tuples containing the column name and an Array of values for that column.
768
+ #
769
+ # This method returns the table for chaining.
770
+ #
771
+ def delete_if(&block)
772
+ if @mode == :row or @mode == :col_or_row # by index
773
+ @table.delete_if(&block)
774
+ else # by header
775
+ to_delete = Array.new
776
+ headers.each_with_index do |header, i|
777
+ to_delete << header if block[[header, self[header]]]
778
+ end
779
+ to_delete.map { |header| delete(header) }
780
+ end
781
+
782
+ self # for chaining
783
+ end
784
+
785
+ include Enumerable
786
+
787
+ #
788
+ # In the default mixed mode or row mode, iteration is the standard row major
789
+ # walking of rows. In column mode, interation will +yield+ two element
790
+ # tuples containing the column name and an Array of values for that column.
791
+ #
792
+ # This method returns the table for chaining.
793
+ #
794
+ def each(&block)
795
+ if @mode == :col
796
+ headers.each { |header| block[[header, self[header]]] }
797
+ else
798
+ @table.each(&block)
799
+ end
800
+
801
+ self # for chaining
802
+ end
803
+
804
+ # Returns +true+ if all rows of this table ==() +other+'s rows.
805
+ def ==(other)
806
+ @table == other.table
807
+ end
808
+
809
+ #
810
+ # Returns the table as an Array of Arrays. Headers will be the first row,
811
+ # then all of the field rows will follow.
812
+ #
813
+ def to_a
814
+ @table.inject([headers]) do |array, row|
815
+ if row.header_row?
816
+ array
817
+ else
818
+ array + [row.fields]
819
+ end
820
+ end
821
+ end
822
+
823
+ #
824
+ # Returns the table as a complete CSV String. Headers will be listed first,
825
+ # then all of the field rows.
826
+ #
827
+ def to_csv(options = Hash.new)
828
+ @table.inject([headers.to_csv(options)]) do |rows, row|
829
+ if row.header_row?
830
+ rows
831
+ else
832
+ rows + [row.fields.to_csv(options)]
833
+ end
834
+ end.join
835
+ end
836
+ alias_method :to_s, :to_csv
837
+
838
+ # Shows the mode and size of this table in a US-ASCII String.
839
+ def inspect
840
+ "#<#{self.class} mode:#{@mode} row_count:#{to_a.size}>".encode("US-ASCII")
841
+ end
842
+ end
843
+
844
+ # The error thrown when the parser encounters illegal CSV formatting.
845
+ class MalformedCSVError < RuntimeError; end
846
+
847
+ #
848
+ # A FieldInfo Struct contains details about a field's position in the data
849
+ # source it was read from. CSV will pass this Struct to some blocks that make
850
+ # decisions based on field structure. See CSV.convert_fields() for an
851
+ # example.
852
+ #
853
+ # <b><tt>index</tt></b>:: The zero-based index of the field in its row.
854
+ # <b><tt>line</tt></b>:: The line of the data source this row is from.
855
+ # <b><tt>header</tt></b>:: The header for the column, when available.
856
+ #
857
+ FieldInfo = Struct.new(:index, :line, :header)
858
+
859
+ # A Regexp used to find and convert some common Date formats.
860
+ DateMatcher = / \A(?: (\w+,?\s+)?\w+\s+\d{1,2},?\s+\d{2,4} |
861
+ \d{4}-\d{2}-\d{2} )\z /x
862
+ # A Regexp used to find and convert some common DateTime formats.
863
+ DateTimeMatcher =
864
+ / \A(?: (\w+,?\s+)?\w+\s+\d{1,2}\s+\d{1,2}:\d{1,2}:\d{1,2},?\s+\d{2,4} |
865
+ \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2} )\z /x
866
+
867
+ # The encoding used by all converters.
868
+ ConverterEncoding = Encoding.find("UTF-8")
869
+
870
+ #
871
+ # This Hash holds the built-in converters of CSV that can be accessed by name.
872
+ # You can select Converters with CSV.convert() or through the +options+ Hash
873
+ # passed to CSV::new().
874
+ #
875
+ # <b><tt>:integer</tt></b>:: Converts any field Integer() accepts.
876
+ # <b><tt>:float</tt></b>:: Converts any field Float() accepts.
877
+ # <b><tt>:numeric</tt></b>:: A combination of <tt>:integer</tt>
878
+ # and <tt>:float</tt>.
879
+ # <b><tt>:date</tt></b>:: Converts any field Date::parse() accepts.
880
+ # <b><tt>:date_time</tt></b>:: Converts any field DateTime::parse() accepts.
881
+ # <b><tt>:all</tt></b>:: All built-in converters. A combination of
882
+ # <tt>:date_time</tt> and <tt>:numeric</tt>.
883
+ #
884
+ # All built-in converters transcode field data to UTF-8 before attempting a
885
+ # conversion. If your data cannot be transcoded to UTF-8 the conversion will
886
+ # fail and the field will remain unchanged.
887
+ #
888
+ # This Hash is intentionally left unfrozen and users should feel free to add
889
+ # values to it that can be accessed by all CSV objects.
890
+ #
891
+ # To add a combo field, the value should be an Array of names. Combo fields
892
+ # can be nested with other combo fields.
893
+ #
894
+ Converters = { integer: lambda { |f|
895
+ Integer(f.encode(ConverterEncoding)) rescue f
896
+ },
897
+ float: lambda { |f|
898
+ Float(f.encode(ConverterEncoding)) rescue f
899
+ },
900
+ numeric: [:integer, :float],
901
+ date: lambda { |f|
902
+ begin
903
+ e = f.encode(ConverterEncoding)
904
+ e =~ DateMatcher ? Date.parse(e) : f
905
+ rescue # encoding conversion or date parse errors
906
+ f
907
+ end
908
+ },
909
+ date_time: lambda { |f|
910
+ begin
911
+ e = f.encode(ConverterEncoding)
912
+ e =~ DateTimeMatcher ? DateTime.parse(e) : f
913
+ rescue # encoding conversion or date parse errors
914
+ f
915
+ end
916
+ },
917
+ all: [:date_time, :numeric] }
918
+
919
+ #
920
+ # This Hash holds the built-in header converters of CSV that can be accessed
921
+ # by name. You can select HeaderConverters with CSV.header_convert() or
922
+ # through the +options+ Hash passed to CSV::new().
923
+ #
924
+ # <b><tt>:downcase</tt></b>:: Calls downcase() on the header String.
925
+ # <b><tt>:symbol</tt></b>:: The header String is downcased, spaces are
926
+ # replaced with underscores, non-word characters
927
+ # are dropped, and finally to_sym() is called.
928
+ #
929
+ # All built-in header converters transcode header data to UTF-8 before
930
+ # attempting a conversion. If your data cannot be transcoded to UTF-8 the
931
+ # conversion will fail and the header will remain unchanged.
932
+ #
933
+ # This Hash is intetionally left unfrozen and users should feel free to add
934
+ # values to it that can be accessed by all CSV objects.
935
+ #
936
+ # To add a combo field, the value should be an Array of names. Combo fields
937
+ # can be nested with other combo fields.
938
+ #
939
+ HeaderConverters = {
940
+ downcase: lambda { |h| h.encode(ConverterEncoding).downcase },
941
+ symbol: lambda { |h|
942
+ h.encode(ConverterEncoding).downcase.gsub(/\s+/, "_").
943
+ gsub(/\W+/, "").to_sym
944
+ }
945
+ }
946
+
947
+ #
948
+ # The options used when no overrides are given by calling code. They are:
949
+ #
950
+ # <b><tt>:col_sep</tt></b>:: <tt>","</tt>
951
+ # <b><tt>:row_sep</tt></b>:: <tt>:auto</tt>
952
+ # <b><tt>:quote_char</tt></b>:: <tt>'"'</tt>
953
+ # <b><tt>:field_size_limit</tt></b>:: +nil+
954
+ # <b><tt>:converters</tt></b>:: +nil+
955
+ # <b><tt>:unconverted_fields</tt></b>:: +nil+
956
+ # <b><tt>:headers</tt></b>:: +false+
957
+ # <b><tt>:return_headers</tt></b>:: +false+
958
+ # <b><tt>:header_converters</tt></b>:: +nil+
959
+ # <b><tt>:skip_blanks</tt></b>:: +false+
960
+ # <b><tt>:force_quotes</tt></b>:: +false+
961
+ #
962
+ DEFAULT_OPTIONS = { col_sep: ",",
963
+ row_sep: :auto,
964
+ quote_char: '"',
965
+ field_size_limit: nil,
966
+ converters: nil,
967
+ unconverted_fields: nil,
968
+ headers: false,
969
+ return_headers: false,
970
+ header_converters: nil,
971
+ skip_blanks: false,
972
+ force_quotes: false }.freeze
973
+
974
+ #
975
+ # This method will return a CSV instance, just like CSV::new(), but the
976
+ # instance will be cached and returned for all future calls to this method for
977
+ # the same +data+ object (tested by Object#object_id()) with the same
978
+ # +options+.
979
+ #
980
+ # If a block is given, the instance is passed to the block and the return
981
+ # value becomes the return value of the block.
982
+ #
983
+ def self.instance(data = $stdout, options = Hash.new)
984
+ # create a _signature_ for this method call, data object and options
985
+ sig = [data.object_id] +
986
+ options.values_at(*DEFAULT_OPTIONS.keys.sort_by { |sym| sym.to_s })
987
+
988
+ # fetch or create the instance for this signature
989
+ @@instances ||= Hash.new
990
+ instance = (@@instances[sig] ||= new(data, options))
991
+
992
+ if block_given?
993
+ yield instance # run block, if given, returning result
994
+ else
995
+ instance # or return the instance
996
+ end
997
+ end
998
+
999
+ #
1000
+ # This method allows you to serialize an Array of Ruby objects to a String or
1001
+ # File of CSV data. This is not as powerful as Marshal or YAML, but perhaps
1002
+ # useful for spreadsheet and database interaction.
1003
+ #
1004
+ # Out of the box, this method is intended to work with simple data objects or
1005
+ # Structs. It will serialize a list of instance variables and/or
1006
+ # Struct.members().
1007
+ #
1008
+ # If you need need more complicated serialization, you can control the process
1009
+ # by adding methods to the class to be serialized.
1010
+ #
1011
+ # A class method csv_meta() is responsible for returning the first row of the
1012
+ # document (as an Array). This row is considered to be a Hash of the form
1013
+ # key_1,value_1,key_2,value_2,... CSV::load() expects to find a class key
1014
+ # with a value of the stringified class name and CSV::dump() will create this,
1015
+ # if you do not define this method. This method is only called on the first
1016
+ # object of the Array.
1017
+ #
1018
+ # The next method you can provide is an instance method called csv_headers().
1019
+ # This method is expected to return the second line of the document (again as
1020
+ # an Array), which is to be used to give each column a header. By default,
1021
+ # CSV::load() will set an instance variable if the field header starts with an
1022
+ # @ character or call send() passing the header as the method name and
1023
+ # the field value as an argument. This method is only called on the first
1024
+ # object of the Array.
1025
+ #
1026
+ # Finally, you can provide an instance method called csv_dump(), which will
1027
+ # be passed the headers. This should return an Array of fields that can be
1028
+ # serialized for this object. This method is called once for every object in
1029
+ # the Array.
1030
+ #
1031
+ # The +io+ parameter can be used to serialize to a File, and +options+ can be
1032
+ # anything CSV::new() accepts.
1033
+ #
1034
+ def self.dump(ary_of_objs, io = "", options = Hash.new)
1035
+ obj_template = ary_of_objs.first
1036
+
1037
+ csv = new(io, options)
1038
+
1039
+ # write meta information
1040
+ begin
1041
+ csv << obj_template.class.csv_meta
1042
+ rescue NoMethodError
1043
+ csv << [:class, obj_template.class]
1044
+ end
1045
+
1046
+ # write headers
1047
+ begin
1048
+ headers = obj_template.csv_headers
1049
+ rescue NoMethodError
1050
+ headers = obj_template.instance_variables.sort
1051
+ if obj_template.class.ancestors.find { |cls| cls.to_s =~ /\AStruct\b/ }
1052
+ headers += obj_template.members.map { |mem| "#{mem}=" }.sort
1053
+ end
1054
+ end
1055
+ csv << headers
1056
+
1057
+ # serialize each object
1058
+ ary_of_objs.each do |obj|
1059
+ begin
1060
+ csv << obj.csv_dump(headers)
1061
+ rescue NoMethodError
1062
+ csv << headers.map do |var|
1063
+ if var[0] == ?@
1064
+ obj.instance_variable_get(var)
1065
+ else
1066
+ obj[var[0..-2]]
1067
+ end
1068
+ end
1069
+ end
1070
+ end
1071
+
1072
+ if io.is_a? String
1073
+ csv.string
1074
+ else
1075
+ csv.close
1076
+ end
1077
+ end
1078
+
1079
+ #
1080
+ # This method is the reading counterpart to CSV::dump(). See that method for
1081
+ # a detailed description of the process.
1082
+ #
1083
+ # You can customize loading by adding a class method called csv_load() which
1084
+ # will be passed a Hash of meta information, an Array of headers, and an Array
1085
+ # of fields for the object the method is expected to return.
1086
+ #
1087
+ # Remember that all fields will be Strings after this load. If you need
1088
+ # something else, use +options+ to setup converters or provide a custom
1089
+ # csv_load() implementation.
1090
+ #
1091
+ def self.load(io_or_str, options = Hash.new)
1092
+ csv = new(io_or_str, options)
1093
+
1094
+ # load meta information
1095
+ meta = Hash[*csv.shift]
1096
+ cls = meta["class".encode(csv.encoding)].split("::".encode(csv.encoding)).
1097
+ inject(Object) do |c, const|
1098
+ c.const_get(const)
1099
+ end
1100
+
1101
+ # load headers
1102
+ headers = csv.shift
1103
+
1104
+ # unserialize each object stored in the file
1105
+ results = csv.inject(Array.new) do |all, row|
1106
+ begin
1107
+ obj = cls.csv_load(meta, headers, row)
1108
+ rescue NoMethodError
1109
+ obj = cls.allocate
1110
+ headers.zip(row) do |name, value|
1111
+ if name[0] == ?@
1112
+ obj.instance_variable_set(name, value)
1113
+ else
1114
+ obj.send(name, value)
1115
+ end
1116
+ end
1117
+ end
1118
+ all << obj
1119
+ end
1120
+
1121
+ csv.close unless io_or_str.is_a? String
1122
+
1123
+ results
1124
+ end
1125
+
1126
+ #
1127
+ # :call-seq:
1128
+ # filter( options = Hash.new ) { |row| ... }
1129
+ # filter( input, options = Hash.new ) { |row| ... }
1130
+ # filter( input, output, options = Hash.new ) { |row| ... }
1131
+ #
1132
+ # This method is a convenience for building Unix-like filters for CSV data.
1133
+ # Each row is yielded to the provided block which can alter it as needed.
1134
+ # After the block returns, the row is appended to +output+ altered or not.
1135
+ #
1136
+ # The +input+ and +output+ arguments can be anything CSV::new() accepts
1137
+ # (generally String or IO objects). If not given, they default to
1138
+ # <tt>ARGF</tt> and <tt>$stdout</tt>.
1139
+ #
1140
+ # The +options+ parameter is also filtered down to CSV::new() after some
1141
+ # clever key parsing. Any key beginning with <tt>:in_</tt> or
1142
+ # <tt>:input_</tt> will have that leading identifier stripped and will only
1143
+ # be used in the +options+ Hash for the +input+ object. Keys starting with
1144
+ # <tt>:out_</tt> or <tt>:output_</tt> affect only +output+. All other keys
1145
+ # are assigned to both objects.
1146
+ #
1147
+ # The <tt>:output_row_sep</tt> +option+ defaults to
1148
+ # <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>).
1149
+ #
1150
+ def self.filter(*args)
1151
+ # parse options for input, output, or both
1152
+ in_options, out_options = Hash.new, {row_sep: $INPUT_RECORD_SEPARATOR}
1153
+ if args.last.is_a? Hash
1154
+ args.pop.each do |key, value|
1155
+ case key.to_s
1156
+ when /\Ain(?:put)?_(.+)\Z/
1157
+ in_options[$1.to_sym] = value
1158
+ when /\Aout(?:put)?_(.+)\Z/
1159
+ out_options[$1.to_sym] = value
1160
+ else
1161
+ in_options[key] = value
1162
+ out_options[key] = value
1163
+ end
1164
+ end
1165
+ end
1166
+ # build input and output wrappers
1167
+ input = new(args.shift || ARGF, in_options)
1168
+ output = new(args.shift || $stdout, out_options)
1169
+
1170
+ # read, yield, write
1171
+ input.each do |row|
1172
+ yield row
1173
+ output << row
1174
+ end
1175
+ end
1176
+
1177
+ #
1178
+ # This method is intended as the primary interface for reading CSV files. You
1179
+ # pass a +path+ and any +options+ you wish to set for the read. Each row of
1180
+ # file will be passed to the provided +block+ in turn.
1181
+ #
1182
+ # The +options+ parameter can be anything CSV::new() understands. This method
1183
+ # also understands an additional <tt>:encoding</tt> parameter that you can use
1184
+ # to specify the Encoding of the data in the file to be read. You must provide
1185
+ # this unless your data is in Encoding::default_external(). CSV will use this
1186
+ # to deterime how to parse the data. You may provide a second Encoding to
1187
+ # have the data transcoded as it is read. For example,
1188
+ # <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
1189
+ # but transcode it to UTF-8 before CSV parses it.
1190
+ #
1191
+ def self.foreach(path, options = Hash.new, &block)
1192
+ encoding = options.delete(:encoding)
1193
+ mode = "rb"
1194
+ mode << ":#{encoding}" if encoding
1195
+ open(path, mode, options) do |csv|
1196
+ csv.each(&block)
1197
+ end
1198
+ end
1199
+
1200
+ #
1201
+ # :call-seq:
1202
+ # generate( str, options = Hash.new ) { |csv| ... }
1203
+ # generate( options = Hash.new ) { |csv| ... }
1204
+ #
1205
+ # This method wraps a String you provide, or an empty default String, in a
1206
+ # CSV object which is passed to the provided block. You can use the block to
1207
+ # append CSV rows to the String and when the block exits, the final String
1208
+ # will be returned.
1209
+ #
1210
+ # Note that a passed String *is* modfied by this method. Call dup() before
1211
+ # passing if you need a new String.
1212
+ #
1213
+ # The +options+ parameter can be anthing CSV::new() understands. This method
1214
+ # understands an additional <tt>:encoding</tt> parameter when not passed a
1215
+ # String to set the base Encoding for the output. CSV needs this hint if you
1216
+ # plan to output non-ASCII compatible data.
1217
+ #
1218
+ def self.generate(*args)
1219
+ # add a default empty String, if none was given
1220
+ if args.first.is_a? String
1221
+ io = StringIO.new(args.shift)
1222
+ io.seek(0, IO::SEEK_END)
1223
+ args.unshift(io)
1224
+ else
1225
+ encoding = args.last.is_a?(Hash) ? args.last.delete(:encoding) : nil
1226
+ str = ""
1227
+ str.encode!(encoding) if encoding
1228
+ args.unshift(str)
1229
+ end
1230
+ csv = new(*args) # wrap
1231
+ yield csv # yield for appending
1232
+ csv.string # return final String
1233
+ end
1234
+
1235
+ #
1236
+ # This method is a shortcut for converting a single row (Array) into a CSV
1237
+ # String.
1238
+ #
1239
+ # The +options+ parameter can be anthing CSV::new() understands. This method
1240
+ # understands an additional <tt>:encoding</tt> parameter to set the base
1241
+ # Encoding for the output. This method will try to guess your Encoding from
1242
+ # the first non-+nil+ field in +row+, if possible, but you may need to use
1243
+ # this parameter as a backup plan.
1244
+ #
1245
+ # The <tt>:row_sep</tt> +option+ defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>
1246
+ # (<tt>$/</tt>) when calling this method.
1247
+ #
1248
+ def self.generate_line(row, options = Hash.new)
1249
+ options = {row_sep: $INPUT_RECORD_SEPARATOR}.merge(options)
1250
+ encoding = options.delete(:encoding)
1251
+ str = ""
1252
+ if encoding
1253
+ str.force_encoding(encoding)
1254
+ elsif field = row.find { |f| not f.nil? }
1255
+ str.force_encoding(String(field).encoding)
1256
+ end
1257
+ (new(str, options) << row).string
1258
+ end
1259
+
1260
+ #
1261
+ # :call-seq:
1262
+ # open( filename, mode = "rb", options = Hash.new ) { |faster_csv| ... }
1263
+ # open( filename, options = Hash.new ) { |faster_csv| ... }
1264
+ # open( filename, mode = "rb", options = Hash.new )
1265
+ # open( filename, options = Hash.new )
1266
+ #
1267
+ # This method opens an IO object, and wraps that with CSV. This is intended
1268
+ # as the primary interface for writing a CSV file.
1269
+ #
1270
+ # You must pass a +filename+ and may optionally add a +mode+ for Ruby's
1271
+ # open(). You may also pass an optional Hash containing any +options+
1272
+ # CSV::new() understands as the final argument.
1273
+ #
1274
+ # This method works like Ruby's open() call, in that it will pass a CSV object
1275
+ # to a provided block and close it when the block terminates, or it will
1276
+ # return the CSV object when no block is provided. (*Note*: This is different
1277
+ # from the Ruby 1.8 CSV library which passed rows to the block. Use
1278
+ # CSV::foreach() for that behavior.)
1279
+ #
1280
+ # You must provide a +mode+ with an embedded Encoding designator unless your
1281
+ # data is in Encoding::default_external(). CSV will check the Encoding of the
1282
+ # underlying IO object (set by the +mode+ you pass) to deterime how to parse
1283
+ # the data. You may provide a second Encoding to have the data transcoded as
1284
+ # it is read just as you can with a normal call to IO::open(). For example,
1285
+ # <tt>"rb:UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file but
1286
+ # transcode it to UTF-8 before CSV parses it.
1287
+ #
1288
+ # An opened CSV object will delegate to many IO methods for convenience. You
1289
+ # may call:
1290
+ #
1291
+ # * binmode()
1292
+ # * binmode?()
1293
+ # * close()
1294
+ # * close_read()
1295
+ # * close_write()
1296
+ # * closed?()
1297
+ # * eof()
1298
+ # * eof?()
1299
+ # * external_encoding()
1300
+ # * fcntl()
1301
+ # * fileno()
1302
+ # * flock()
1303
+ # * flush()
1304
+ # * fsync()
1305
+ # * internal_encoding()
1306
+ # * ioctl()
1307
+ # * isatty()
1308
+ # * path()
1309
+ # * pid()
1310
+ # * pos()
1311
+ # * pos=()
1312
+ # * reopen()
1313
+ # * seek()
1314
+ # * stat()
1315
+ # * sync()
1316
+ # * sync=()
1317
+ # * tell()
1318
+ # * to_i()
1319
+ # * to_io()
1320
+ # * truncate()
1321
+ # * tty?()
1322
+ #
1323
+ def self.open(*args)
1324
+ # find the +options+ Hash
1325
+ options = if args.last.is_a? Hash then args.pop else Hash.new end
1326
+ # default to a binary open mode
1327
+ args << "rb" if args.size == 1
1328
+ # wrap a File opened with the remaining +args+
1329
+ csv = new(File.open(*args), options)
1330
+
1331
+ # handle blocks like Ruby's open(), not like the CSV library
1332
+ if block_given?
1333
+ begin
1334
+ yield csv
1335
+ ensure
1336
+ csv.close
1337
+ end
1338
+ else
1339
+ csv
1340
+ end
1341
+ end
1342
+
1343
+ #
1344
+ # :call-seq:
1345
+ # parse( str, options = Hash.new ) { |row| ... }
1346
+ # parse( str, options = Hash.new )
1347
+ #
1348
+ # This method can be used to easily parse CSV out of a String. You may either
1349
+ # provide a +block+ which will be called with each row of the String in turn,
1350
+ # or just use the returned Array of Arrays (when no +block+ is given).
1351
+ #
1352
+ # You pass your +str+ to read from, and an optional +options+ Hash containing
1353
+ # anything CSV::new() understands.
1354
+ #
1355
+ def self.parse(*args, &block)
1356
+ csv = new(*args)
1357
+ if block.nil? # slurp contents, if no block is given
1358
+ begin
1359
+ csv.read
1360
+ ensure
1361
+ csv.close
1362
+ end
1363
+ else # or pass each row to a provided block
1364
+ csv.each(&block)
1365
+ end
1366
+ end
1367
+
1368
+ #
1369
+ # This method is a shortcut for converting a single line of a CSV String into
1370
+ # a into an Array. Note that if +line+ contains multiple rows, anything
1371
+ # beyond the first row is ignored.
1372
+ #
1373
+ # The +options+ parameter can be anthing CSV::new() understands.
1374
+ #
1375
+ def self.parse_line(line, options = Hash.new)
1376
+ new(line, options).shift
1377
+ end
1378
+
1379
+ #
1380
+ # Use to slurp a CSV file into an Array of Arrays. Pass the +path+ to the
1381
+ # file and any +options+ CSV::new() understands. This method also understands
1382
+ # an additional <tt>:encoding</tt> parameter that you can use to specify the
1383
+ # Encoding of the data in the file to be read. You must provide this unless
1384
+ # your data is in Encoding::default_external(). CSV will use this to deterime
1385
+ # how to parse the data. You may provide a second Encoding to have the data
1386
+ # transcoded as it is read. For example,
1387
+ # <tt>encoding: "UTF-32BE:UTF-8"</tt> would read UTF-32BE data from the file
1388
+ # but transcode it to UTF-8 before CSV parses it.
1389
+ #
1390
+ def self.read(path, options = Hash.new)
1391
+ encoding = options.delete(:encoding)
1392
+ mode = "rb"
1393
+ mode << ":#{encoding}" if encoding
1394
+ open(path, mode, options) { |csv| csv.read }
1395
+ end
1396
+
1397
+ # Alias for CSV::read().
1398
+ def self.readlines(*args)
1399
+ read(*args)
1400
+ end
1401
+
1402
+ #
1403
+ # A shortcut for:
1404
+ #
1405
+ # CSV.read( path, { headers: true,
1406
+ # converters: :numeric,
1407
+ # header_converters: :symbol }.merge(options) )
1408
+ #
1409
+ def self.table(path, options = Hash.new)
1410
+ read( path, { headers: true,
1411
+ converters: :numeric,
1412
+ header_converters: :symbol }.merge(options) )
1413
+ end
1414
+
1415
+ #
1416
+ # This constructor will wrap either a String or IO object passed in +data+ for
1417
+ # reading and/or writing. In addition to the CSV instance methods, several IO
1418
+ # methods are delegated. (See CSV::open() for a complete list.) If you pass
1419
+ # a String for +data+, you can later retrieve it (after writing to it, for
1420
+ # example) with CSV.string().
1421
+ #
1422
+ # Note that a wrapped String will be positioned at at the beginning (for
1423
+ # reading). If you want it at the end (for writing), use CSV::generate().
1424
+ # If you want any other positioning, pass a preset StringIO object instead.
1425
+ #
1426
+ # You may set any reading and/or writing preferences in the +options+ Hash.
1427
+ # Available options are:
1428
+ #
1429
+ # <b><tt>:col_sep</tt></b>:: The String placed between each field.
1430
+ # This String will be transcoded into
1431
+ # the data's Encoding before parsing.
1432
+ # <b><tt>:row_sep</tt></b>:: The String appended to the end of each
1433
+ # row. This can be set to the special
1434
+ # <tt>:auto</tt> setting, which requests
1435
+ # that CSV automatically discover this
1436
+ # from the data. Auto-discovery reads
1437
+ # ahead in the data looking for the next
1438
+ # <tt>"\r\n"</tt>, <tt>"\n"</tt>, or
1439
+ # <tt>"\r"</tt> sequence. A sequence
1440
+ # will be selected even if it occurs in
1441
+ # a quoted field, assuming that you
1442
+ # would have the same line endings
1443
+ # there. If none of those sequences is
1444
+ # found, +data+ is <tt>ARGF</tt>,
1445
+ # <tt>STDIN</tt>, <tt>STDOUT</tt>, or
1446
+ # <tt>STDERR</tt>, or the stream is only
1447
+ # available for output, the default
1448
+ # <tt>$INPUT_RECORD_SEPARATOR</tt>
1449
+ # (<tt>$/</tt>) is used. Obviously,
1450
+ # discovery takes a little time. Set
1451
+ # manually if speed is important. Also
1452
+ # note that IO objects should be opened
1453
+ # in binary mode on Windows if this
1454
+ # feature will be used as the
1455
+ # line-ending translation can cause
1456
+ # problems with resetting the document
1457
+ # position to where it was before the
1458
+ # read ahead. This String will be
1459
+ # transcoded into the data's Encoding
1460
+ # before parsing.
1461
+ # <b><tt>:quote_char</tt></b>:: The character used to quote fields.
1462
+ # This has to be a single character
1463
+ # String. This is useful for
1464
+ # application that incorrectly use
1465
+ # <tt>'</tt> as the quote character
1466
+ # instead of the correct <tt>"</tt>.
1467
+ # CSV will always consider a double
1468
+ # sequence this character to be an
1469
+ # escaped quote. This String will be
1470
+ # transcoded into the data's Encoding
1471
+ # before parsing.
1472
+ # <b><tt>:field_size_limit</tt></b>:: This is a maximum size CSV will read
1473
+ # ahead looking for the closing quote
1474
+ # for a field. (In truth, it reads to
1475
+ # the first line ending beyond this
1476
+ # size.) If a quote cannot be found
1477
+ # within the limit CSV will raise a
1478
+ # MalformedCSVError, assuming the data
1479
+ # is faulty. You can use this limit to
1480
+ # prevent what are effectively DoS
1481
+ # attacks on the parser. However, this
1482
+ # limit can cause a legitimate parse to
1483
+ # fail and thus is set to +nil+, or off,
1484
+ # by default.
1485
+ # <b><tt>:converters</tt></b>:: An Array of names from the Converters
1486
+ # Hash and/or lambdas that handle custom
1487
+ # conversion. A single converter
1488
+ # doesn't have to be in an Array. All
1489
+ # built-in converters try to transcode
1490
+ # fields to UTF-8 before converting.
1491
+ # The conversion will fail if the data
1492
+ # cannot be transcoded, leaving the
1493
+ # field unchanged.
1494
+ # <b><tt>:unconverted_fields</tt></b>:: If set to +true+, an
1495
+ # unconverted_fields() method will be
1496
+ # added to all returned rows (Array or
1497
+ # CSV::Row) that will return the fields
1498
+ # as they were before conversion. Note
1499
+ # that <tt>:headers</tt> supplied by
1500
+ # Array or String were not fields of the
1501
+ # document and thus will have an empty
1502
+ # Array attached.
1503
+ # <b><tt>:headers</tt></b>:: If set to <tt>:first_row</tt> or
1504
+ # +true+, the initial row of the CSV
1505
+ # file will be treated as a row of
1506
+ # headers. If set to an Array, the
1507
+ # contents will be used as the headers.
1508
+ # If set to a String, the String is run
1509
+ # through a call of CSV::parse_line()
1510
+ # with the same <tt>:col_sep</tt>,
1511
+ # <tt>:row_sep</tt>, and
1512
+ # <tt>:quote_char</tt> as this instance
1513
+ # to produce an Array of headers. This
1514
+ # setting causes CSV#shift() to return
1515
+ # rows as CSV::Row objects instead of
1516
+ # Arrays and CSV#read() to return
1517
+ # CSV::Table objects instead of an Array
1518
+ # of Arrays.
1519
+ # <b><tt>:return_headers</tt></b>:: When +false+, header rows are silently
1520
+ # swallowed. If set to +true+, header
1521
+ # rows are returned in a CSV::Row object
1522
+ # with identical headers and
1523
+ # fields (save that the fields do not go
1524
+ # through the converters).
1525
+ # <b><tt>:write_headers</tt></b>:: When +true+ and <tt>:headers</tt> is
1526
+ # set, a header row will be added to the
1527
+ # output.
1528
+ # <b><tt>:header_converters</tt></b>:: Identical in functionality to
1529
+ # <tt>:converters</tt> save that the
1530
+ # conversions are only made to header
1531
+ # rows. All built-in converters try to
1532
+ # transcode headers to UTF-8 before
1533
+ # converting. The conversion will fail
1534
+ # if the data cannot be transcoded,
1535
+ # leaving the header unchanged.
1536
+ # <b><tt>:skip_blanks</tt></b>:: When set to a +true+ value, CSV will
1537
+ # skip over any rows with no content.
1538
+ # <b><tt>:force_quotes</tt></b>:: When set to a +true+ value, CSV will
1539
+ # quote all CSV fields it creates.
1540
+ #
1541
+ # See CSV::DEFAULT_OPTIONS for the default settings.
1542
+ #
1543
+ # Options cannot be overriden in the instance methods for performance reasons,
1544
+ # so be sure to set what you want here.
1545
+ #
1546
+ def initialize(data, options = Hash.new)
1547
+ # build the options for this read/write
1548
+ options = DEFAULT_OPTIONS.merge(options)
1549
+
1550
+ # create the IO object we will read from
1551
+ @io = if data.is_a? String then StringIO.new(data) else data end
1552
+ # honor the IO encoding if we can, otherwise default to ASCII-8BIT
1553
+ @encoding = raw_encoding || Encoding.default_internal || Encoding.default_external
1554
+ #
1555
+ # prepare for building safe regular expressions in the target encoding,
1556
+ # if we can transcode the needed characters
1557
+ #
1558
+ @re_esc = "\\".encode(@encoding) rescue ""
1559
+ @re_chars = %w[ \\ . [ ] - ^ $ ?
1560
+ * + { } ( ) | #
1561
+ \ \r \n \t \f \v ].
1562
+ map { |s| s.encode(@encoding) rescue nil }.compact
1563
+
1564
+ init_separators(options)
1565
+ init_parsers(options)
1566
+ init_converters(options)
1567
+ init_headers(options)
1568
+
1569
+ unless options.empty?
1570
+ raise ArgumentError, "Unknown options: #{options.keys.join(', ')}."
1571
+ end
1572
+
1573
+ # track our own lineno since IO gets confused about line-ends is CSV fields
1574
+ @lineno = 0
1575
+ end
1576
+
1577
+ #
1578
+ # The encoded <tt>:col_sep</tt> used in parsing and writing. See CSV::new
1579
+ # for details.
1580
+ #
1581
+ attr_reader :col_sep
1582
+ #
1583
+ # The encoded <tt>:row_sep</tt> used in parsing and writing. See CSV::new
1584
+ # for details.
1585
+ #
1586
+ attr_reader :row_sep
1587
+ #
1588
+ # The encoded <tt>:quote_char</tt> used in parsing and writing. See CSV::new
1589
+ # for details.
1590
+ #
1591
+ attr_reader :quote_char
1592
+ # The limit for field size, if any. See CSV::new for details.
1593
+ attr_reader :field_size_limit
1594
+ #
1595
+ # Returns the current list of converters in effect. See CSV::new for details.
1596
+ # Built-in converters will be returned by name, while others will be returned
1597
+ # as is.
1598
+ #
1599
+ def converters
1600
+ @converters.map do |converter|
1601
+ name = Converters.rassoc(converter)
1602
+ name ? name.first : converter
1603
+ end
1604
+ end
1605
+ #
1606
+ # Returns +true+ if unconverted_fields() to parsed results. See CSV::new
1607
+ # for details.
1608
+ #
1609
+ def unconverted_fields?() @unconverted_fields end
1610
+ #
1611
+ # Returns +nil+ if headers will not be used, +true+ if they will but have not
1612
+ # yet been read, or the actual headers after they have been read. See
1613
+ # CSV::new for details.
1614
+ #
1615
+ def headers
1616
+ @headers || true if @use_headers
1617
+ end
1618
+ #
1619
+ # Returns +true+ if headers will be returned as a row of results.
1620
+ # See CSV::new for details.
1621
+ #
1622
+ def return_headers?() @return_headers end
1623
+ # Returns +true+ if headers are written in output. See CSV::new for details.
1624
+ def write_headers?() @write_headers end
1625
+ #
1626
+ # Returns the current list of converters in effect for headers. See CSV::new
1627
+ # for details. Built-in converters will be returned by name, while others
1628
+ # will be returned as is.
1629
+ #
1630
+ def header_converters
1631
+ @header_converters.map do |converter|
1632
+ name = HeaderConverters.rassoc(converter)
1633
+ name ? name.first : converter
1634
+ end
1635
+ end
1636
+ #
1637
+ # Returns +true+ blank lines are skipped by the parser. See CSV::new
1638
+ # for details.
1639
+ #
1640
+ def skip_blanks?() @skip_blanks end
1641
+ # Returns +true+ if all output fields are quoted. See CSV::new for details.
1642
+ def force_quotes?() @force_quotes end
1643
+
1644
+ #
1645
+ # The Encoding CSV is parsing or writing in. This will be the Encoding you
1646
+ # receive parsed data in and/or the Encoding data will be written in.
1647
+ #
1648
+ attr_reader :encoding
1649
+
1650
+ #
1651
+ # The line number of the last row read from this file. Fields with nested
1652
+ # line-end characters will not affect this count.
1653
+ #
1654
+ attr_reader :lineno
1655
+
1656
+ ### IO and StringIO Delegation ###
1657
+
1658
+ extend Forwardable
1659
+ def_delegators :@io, :binmode, :binmode?, :close, :close_read, :close_write,
1660
+ :closed?, :eof, :eof?, :external_encoding, :fcntl,
1661
+ :fileno, :flock, :flush, :fsync, :internal_encoding,
1662
+ :ioctl, :isatty, :path, :pid, :pos, :pos=, :reopen,
1663
+ :seek, :stat, :string, :sync, :sync=, :tell, :to_i,
1664
+ :to_io, :truncate, :tty?
1665
+
1666
+ # Rewinds the underlying IO object and resets CSV's lineno() counter.
1667
+ def rewind
1668
+ @headers = nil
1669
+ @lineno = 0
1670
+
1671
+ @io.rewind
1672
+ end
1673
+
1674
+ ### End Delegation ###
1675
+
1676
+ #
1677
+ # The primary write method for wrapped Strings and IOs, +row+ (an Array or
1678
+ # CSV::Row) is converted to CSV and appended to the data source. When a
1679
+ # CSV::Row is passed, only the row's fields() are appended to the output.
1680
+ #
1681
+ # The data source must be open for writing.
1682
+ #
1683
+ def <<(row)
1684
+ # make sure headers have been assigned
1685
+ if header_row? and [Array, String].include? @use_headers.class
1686
+ parse_headers # won't read data for Array or String
1687
+ self << @headers if @write_headers
1688
+ end
1689
+
1690
+ # handle CSV::Row objects and Hashes
1691
+ row = case row
1692
+ when self.class::Row then row.fields
1693
+ when Hash then @headers.map { |header| row[header] }
1694
+ else row
1695
+ end
1696
+
1697
+ @headers = row if header_row?
1698
+ @lineno += 1
1699
+
1700
+ @io << row.map(&@quote).join(@col_sep) + @row_sep # quote and separate
1701
+
1702
+ self # for chaining
1703
+ end
1704
+ alias_method :add_row, :<<
1705
+ alias_method :puts, :<<
1706
+
1707
+ #
1708
+ # :call-seq:
1709
+ # convert( name )
1710
+ # convert { |field| ... }
1711
+ # convert { |field, field_info| ... }
1712
+ #
1713
+ # You can use this method to install a CSV::Converters built-in, or provide a
1714
+ # block that handles a custom conversion.
1715
+ #
1716
+ # If you provide a block that takes one argument, it will be passed the field
1717
+ # and is expected to return the converted value or the field itself. If your
1718
+ # block takes two arguments, it will also be passed a CSV::FieldInfo Struct,
1719
+ # containing details about the field. Again, the block should return a
1720
+ # converted field or the field itself.
1721
+ #
1722
+ def convert(name = nil, &converter)
1723
+ add_converter(:converters, self.class::Converters, name, &converter)
1724
+ end
1725
+
1726
+ #
1727
+ # :call-seq:
1728
+ # header_convert( name )
1729
+ # header_convert { |field| ... }
1730
+ # header_convert { |field, field_info| ... }
1731
+ #
1732
+ # Identical to CSV#convert(), but for header rows.
1733
+ #
1734
+ # Note that this method must be called before header rows are read to have any
1735
+ # effect.
1736
+ #
1737
+ def header_convert(name = nil, &converter)
1738
+ add_converter( :header_converters,
1739
+ self.class::HeaderConverters,
1740
+ name,
1741
+ &converter )
1742
+ end
1743
+
1744
+ include Enumerable
1745
+
1746
+ #
1747
+ # Yields each row of the data source in turn.
1748
+ #
1749
+ # Support for Enumerable.
1750
+ #
1751
+ # The data source must be open for reading.
1752
+ #
1753
+ def each
1754
+ while row = shift
1755
+ yield row
1756
+ end
1757
+ end
1758
+
1759
+ #
1760
+ # Slurps the remaining rows and returns an Array of Arrays.
1761
+ #
1762
+ # The data source must be open for reading.
1763
+ #
1764
+ def read
1765
+ rows = to_a
1766
+ if @use_headers
1767
+ Table.new(rows)
1768
+ else
1769
+ rows
1770
+ end
1771
+ end
1772
+ alias_method :readlines, :read
1773
+
1774
+ # Returns +true+ if the next row read will be a header row.
1775
+ def header_row?
1776
+ @use_headers and @headers.nil?
1777
+ end
1778
+
1779
+ #
1780
+ # The primary read method for wrapped Strings and IOs, a single row is pulled
1781
+ # from the data source, parsed and returned as an Array of fields (if header
1782
+ # rows are not used) or a CSV::Row (when header rows are used).
1783
+ #
1784
+ # The data source must be open for reading.
1785
+ #
1786
+ def shift
1787
+ #########################################################################
1788
+ ### This method is purposefully kept a bit long as simple conditional ###
1789
+ ### checks are faster than numerous (expensive) method calls. ###
1790
+ #########################################################################
1791
+
1792
+ # handle headers not based on document content
1793
+ if header_row? and @return_headers and
1794
+ [Array, String].include? @use_headers.class
1795
+ if @unconverted_fields
1796
+ return add_unconverted_fields(parse_headers, Array.new)
1797
+ else
1798
+ return parse_headers
1799
+ end
1800
+ end
1801
+
1802
+ # begin with a blank line, so we can always add to it
1803
+ line = ""
1804
+
1805
+ #
1806
+ # it can take multiple calls to <tt>@io.gets()</tt> to get a full line,
1807
+ # because of \r and/or \n characters embedded in quoted fields
1808
+ #
1809
+ loop do
1810
+ # add another read to the line
1811
+ (line += @io.gets(@row_sep)) rescue return nil
1812
+ # copy the line so we can chop it up in parsing
1813
+ parse = line.dup
1814
+ parse.sub!(@parsers[:line_end], "")
1815
+
1816
+ #
1817
+ # I believe a blank line should be an <tt>Array.new</tt>, not Ruby 1.8
1818
+ # CSV's <tt>[nil]</tt>
1819
+ #
1820
+ if parse.empty?
1821
+ @lineno += 1
1822
+ if @skip_blanks
1823
+ line = ""
1824
+ next
1825
+ elsif @unconverted_fields
1826
+ return add_unconverted_fields(Array.new, Array.new)
1827
+ elsif @use_headers
1828
+ return self.class::Row.new(Array.new, Array.new)
1829
+ else
1830
+ return Array.new
1831
+ end
1832
+ end
1833
+
1834
+ #
1835
+ # shave leading empty fields if needed, because the main parser chokes
1836
+ # on these
1837
+ #
1838
+ csv = if parse.sub!(@parsers[:leading_fields], "")
1839
+ [nil] * ($&.length / @col_sep.length)
1840
+ else
1841
+ Array.new
1842
+ end
1843
+ #
1844
+ # then parse the main fields with a hyper-tuned Regexp from
1845
+ # Mastering Regular Expressions, Second Edition
1846
+ #
1847
+ parse.gsub!(@parsers[:csv_row]) do
1848
+ csv << if $1.nil? # we found an unquoted field
1849
+ if $2.empty? # switch empty unquoted fields to +nil+...
1850
+ nil # for Ruby 1.8 CSV compatibility
1851
+ else
1852
+ # I decided to take a strict approach to CSV parsing...
1853
+ if $2.count(@parsers[:return_newline]).zero? # verify correctness
1854
+ $2
1855
+ else
1856
+ # or throw an Exception
1857
+ raise MalformedCSVError, "Unquoted fields do not allow " +
1858
+ "\\r or \\n (line #{lineno + 1})."
1859
+ end
1860
+ end
1861
+ else # we found a quoted field...
1862
+ $1.gsub(@quote_char * 2, @quote_char) # unescape contents
1863
+ end
1864
+ "" # gsub!'s replacement, clear the field
1865
+ end
1866
+
1867
+ # if parse is empty?(), we found all the fields on the line...
1868
+ if parse.empty?
1869
+ @lineno += 1
1870
+
1871
+ # save fields unconverted fields, if needed...
1872
+ unconverted = csv.dup if @unconverted_fields
1873
+
1874
+ # convert fields, if needed...
1875
+ csv = convert_fields(csv) unless @use_headers or @converters.empty?
1876
+ # parse out header rows and handle CSV::Row conversions...
1877
+ csv = parse_headers(csv) if @use_headers
1878
+
1879
+ # inject unconverted fields and accessor, if requested...
1880
+ if @unconverted_fields and not csv.respond_to? :unconverted_fields
1881
+ add_unconverted_fields(csv, unconverted)
1882
+ end
1883
+
1884
+ # return the results
1885
+ break csv
1886
+ end
1887
+ # if we're not empty?() but at eof?(), a quoted field wasn't closed...
1888
+ if @io.eof?
1889
+ raise MalformedCSVError, "Unclosed quoted field on line #{lineno + 1}."
1890
+ elsif parse =~ @parsers[:bad_field]
1891
+ raise MalformedCSVError, "Illegal quoting on line #{lineno + 1}."
1892
+ elsif @field_size_limit and parse.length >= @field_size_limit
1893
+ raise MalformedCSVError, "Field size exceeded on line #{lineno + 1}."
1894
+ end
1895
+ # otherwise, we need to loop and pull some more data to complete the row
1896
+ end
1897
+ end
1898
+ alias_method :gets, :shift
1899
+ alias_method :readline, :shift
1900
+
1901
+ #
1902
+ # Returns a simplified description of the key FasterCSV attributes in an
1903
+ # ASCII compatible String.
1904
+ #
1905
+ def inspect
1906
+ str = ["<#", self.class.to_s, " io_type:"]
1907
+ # show type of wrapped IO
1908
+ if @io == $stdout then str << "$stdout"
1909
+ elsif @io == $stdin then str << "$stdin"
1910
+ elsif @io == $stderr then str << "$stderr"
1911
+ else str << @io.class.to_s
1912
+ end
1913
+ # show IO.path(), if available
1914
+ if @io.respond_to?(:path) and (p = @io.path)
1915
+ str << " io_path:" << p.inspect
1916
+ end
1917
+ # show encoding
1918
+ str << " encoding:" << @encoding.name
1919
+ # show other attributes
1920
+ %w[ lineno col_sep row_sep
1921
+ quote_char skip_blanks ].each do |attr_name|
1922
+ if a = instance_variable_get("@#{attr_name}")
1923
+ str << " " << attr_name << ":" << a.inspect
1924
+ end
1925
+ end
1926
+ if @use_headers
1927
+ str << " headers:" << headers.inspect
1928
+ end
1929
+ str << ">"
1930
+ begin
1931
+ str.join
1932
+ rescue # any encoding error
1933
+ str.map do |s|
1934
+ e = Encoding::Converter.asciicompat_encoding(s.encoding)
1935
+ e ? s.encode(e) : s.force_encoding("ASCII-8BIT")
1936
+ end.join
1937
+ end
1938
+ end
1939
+
1940
+ private
1941
+
1942
+ #
1943
+ # Stores the indicated separators for later use.
1944
+ #
1945
+ # If auto-discovery was requested for <tt>@row_sep</tt>, this method will read
1946
+ # ahead in the <tt>@io</tt> and try to find one. +ARGF+, +STDIN+, +STDOUT+,
1947
+ # +STDERR+ and any stream open for output only with a default
1948
+ # <tt>@row_sep</tt> of <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>).
1949
+ #
1950
+ # This method also establishes the quoting rules used for CSV output.
1951
+ #
1952
+ def init_separators(options)
1953
+ # store the selected separators
1954
+ @col_sep = options.delete(:col_sep).to_s.encode(@encoding)
1955
+ @row_sep = options.delete(:row_sep) # encode after resolving :auto
1956
+ @quote_char = options.delete(:quote_char).to_s.encode(@encoding)
1957
+
1958
+ if @quote_char.length != 1
1959
+ raise ArgumentError, ":quote_char has to be a single character String"
1960
+ end
1961
+
1962
+ #
1963
+ # automatically discover row separator when requested
1964
+ # (not fully encoding safe)
1965
+ #
1966
+ if @row_sep == :auto
1967
+ if [ARGF, STDIN, STDOUT, STDERR].include?(@io) or
1968
+ (defined?(Zlib) and @io.class == Zlib::GzipWriter)
1969
+ @row_sep = $INPUT_RECORD_SEPARATOR
1970
+ else
1971
+ begin
1972
+ saved_pos = @io.pos # remember where we were
1973
+ while @row_sep == :auto
1974
+ #
1975
+ # if we run out of data, it's probably a single line
1976
+ # (use a sensible default)
1977
+ #
1978
+ if @io.eof?
1979
+ @row_sep = $INPUT_RECORD_SEPARATOR
1980
+ break
1981
+ end
1982
+
1983
+ # read ahead a bit
1984
+ sample = read_to_char(1024)
1985
+ sample += read_to_char(1) if sample[-1..-1] == encode_str("\r") and
1986
+ not @io.eof?
1987
+ # try to find a standard separator
1988
+ if sample =~ encode_re("\r\n?|\n")
1989
+ @row_sep = $&
1990
+ break
1991
+ end
1992
+ end
1993
+ # tricky seek() clone to work around GzipReader's lack of seek()
1994
+ @io.rewind
1995
+ # reset back to the remembered position
1996
+ while saved_pos > 1024 # avoid loading a lot of data into memory
1997
+ @io.read(1024)
1998
+ saved_pos -= 1024
1999
+ end
2000
+ @io.read(saved_pos) if saved_pos.nonzero?
2001
+ rescue IOError # stream not opened for reading
2002
+ @row_sep = $INPUT_RECORD_SEPARATOR
2003
+ end
2004
+ end
2005
+ end
2006
+ @row_sep = @row_sep.to_s.encode(@encoding)
2007
+
2008
+ # establish quoting rules
2009
+ @force_quotes = options.delete(:force_quotes)
2010
+ do_quote = lambda do |field|
2011
+ @quote_char +
2012
+ String(field).gsub(@quote_char, @quote_char * 2) +
2013
+ @quote_char
2014
+ end
2015
+ quotable_chars = encode_str("\r\n", @col_sep, @quote_char)
2016
+ @quote = if @force_quotes
2017
+ do_quote
2018
+ else
2019
+ lambda do |field|
2020
+ if field.nil? # represent +nil+ fields as empty unquoted fields
2021
+ ""
2022
+ else
2023
+ field = String(field) # Stringify fields
2024
+ # represent empty fields as empty quoted fields
2025
+ if field.empty? or
2026
+ field.count(quotable_chars).nonzero?
2027
+ do_quote.call(field)
2028
+ else
2029
+ field # unquoted field
2030
+ end
2031
+ end
2032
+ end
2033
+ end
2034
+ end
2035
+
2036
+ # Pre-compiles parsers and stores them by name for access during reads.
2037
+ def init_parsers(options)
2038
+ # store the parser behaviors
2039
+ @skip_blanks = options.delete(:skip_blanks)
2040
+ @field_size_limit = options.delete(:field_size_limit)
2041
+
2042
+ # prebuild Regexps for faster parsing
2043
+ esc_col_sep = escape_re(@col_sep)
2044
+ esc_row_sep = escape_re(@row_sep)
2045
+ esc_quote = escape_re(@quote_char)
2046
+ @parsers = {
2047
+ # for empty leading fields
2048
+ leading_fields: encode_re("\\A(?:", esc_col_sep, ")+"),
2049
+ # The Primary Parser
2050
+ csv_row: encode_re(
2051
+ "\\G(?:\\A|", esc_col_sep, ")", # anchor the match
2052
+ "(?:", esc_quote, # find quoted fields
2053
+ "((?>[^", esc_quote, "]*)", # "unrolling the loop"
2054
+ "(?>", esc_quote * 2, # double for escaping
2055
+ "[^", esc_quote, "]*)*)",
2056
+ esc_quote,
2057
+ "|", # ... or ...
2058
+ "([^", esc_quote, esc_col_sep, "]*))", # unquoted fields
2059
+ "(?=", esc_col_sep, "|\\z)" # ensure field is ended
2060
+ ),
2061
+ # a test for unescaped quotes
2062
+ bad_field: encode_re(
2063
+ "\\A", esc_col_sep, "?", # an optional comma
2064
+ "(?:", esc_quote, # a quoted field
2065
+ "(?>[^", esc_quote, "]*)", # "unrolling the loop"
2066
+ "(?>", esc_quote * 2, # double for escaping
2067
+ "[^", esc_quote, "]*)*",
2068
+ esc_quote, # the closing quote
2069
+ "[^", esc_quote, "]", # an extra character
2070
+ "|", # ... or ...
2071
+ "[^", esc_quote, esc_col_sep, "]+", # an unquoted field
2072
+ esc_quote, ")" # an extra quote
2073
+ ),
2074
+ # safer than chomp!()
2075
+ line_end: encode_re(esc_row_sep, "\\z"),
2076
+ # illegal unquoted characters
2077
+ return_newline: encode_str("\r\n")
2078
+ }
2079
+ end
2080
+
2081
+ #
2082
+ # Loads any converters requested during construction.
2083
+ #
2084
+ # If +field_name+ is set <tt>:converters</tt> (the default) field converters
2085
+ # are set. When +field_name+ is <tt>:header_converters</tt> header converters
2086
+ # are added instead.
2087
+ #
2088
+ # The <tt>:unconverted_fields</tt> option is also actived for
2089
+ # <tt>:converters</tt> calls, if requested.
2090
+ #
2091
+ def init_converters(options, field_name = :converters)
2092
+ if field_name == :converters
2093
+ @unconverted_fields = options.delete(:unconverted_fields)
2094
+ end
2095
+
2096
+ instance_variable_set("@#{field_name}", Array.new)
2097
+
2098
+ # find the correct method to add the converters
2099
+ convert = method(field_name.to_s.sub(/ers\Z/, ""))
2100
+
2101
+ # load converters
2102
+ unless options[field_name].nil?
2103
+ # allow a single converter not wrapped in an Array
2104
+ unless options[field_name].is_a? Array
2105
+ options[field_name] = [options[field_name]]
2106
+ end
2107
+ # load each converter...
2108
+ options[field_name].each do |converter|
2109
+ if converter.is_a? Proc # custom code block
2110
+ convert.call(&converter)
2111
+ else # by name
2112
+ convert.call(converter)
2113
+ end
2114
+ end
2115
+ end
2116
+
2117
+ options.delete(field_name)
2118
+ end
2119
+
2120
+ # Stores header row settings and loads header converters, if needed.
2121
+ def init_headers(options)
2122
+ @use_headers = options.delete(:headers)
2123
+ @return_headers = options.delete(:return_headers)
2124
+ @write_headers = options.delete(:write_headers)
2125
+
2126
+ # headers must be delayed until shift(), in case they need a row of content
2127
+ @headers = nil
2128
+
2129
+ init_converters(options, :header_converters)
2130
+ end
2131
+
2132
+ #
2133
+ # The actual work method for adding converters, used by both CSV.convert() and
2134
+ # CSV.header_convert().
2135
+ #
2136
+ # This method requires the +var_name+ of the instance variable to place the
2137
+ # converters in, the +const+ Hash to lookup named converters in, and the
2138
+ # normal parameters of the CSV.convert() and CSV.header_convert() methods.
2139
+ #
2140
+ def add_converter(var_name, const, name = nil, &converter)
2141
+ if name.nil? # custom converter
2142
+ instance_variable_get("@#{var_name}") << converter
2143
+ else # named converter
2144
+ combo = const[name]
2145
+ case combo
2146
+ when Array # combo converter
2147
+ combo.each do |converter_name|
2148
+ add_converter(var_name, const, converter_name)
2149
+ end
2150
+ else # individual named converter
2151
+ instance_variable_get("@#{var_name}") << combo
2152
+ end
2153
+ end
2154
+ end
2155
+
2156
+ #
2157
+ # Processes +fields+ with <tt>@converters</tt>, or <tt>@header_converters</tt>
2158
+ # if +headers+ is passed as +true+, returning the converted field set. Any
2159
+ # converter that changes the field into something other than a String halts
2160
+ # the pipeline of conversion for that field. This is primarily an efficiency
2161
+ # shortcut.
2162
+ #
2163
+ def convert_fields(fields, headers = false)
2164
+ # see if we are converting headers or fields
2165
+ converters = headers ? @header_converters : @converters
2166
+
2167
+ fields.map.with_index do |field, index|
2168
+ converters.each do |converter|
2169
+ field = if converter.arity == 1 # straight field converter
2170
+ converter[field]
2171
+ else # FieldInfo converter
2172
+ header = @use_headers && !headers ? @headers[index] : nil
2173
+ converter[field, FieldInfo.new(index, lineno, header)]
2174
+ end
2175
+ break unless field.is_a? String # short-curcuit pipeline for speed
2176
+ end
2177
+ field # final state of each field, converted or original
2178
+ end
2179
+ end
2180
+
2181
+ #
2182
+ # This methods is used to turn a finished +row+ into a CSV::Row. Header rows
2183
+ # are also dealt with here, either by returning a CSV::Row with identical
2184
+ # headers and fields (save that the fields do not go through the converters)
2185
+ # or by reading past them to return a field row. Headers are also saved in
2186
+ # <tt>@headers</tt> for use in future rows.
2187
+ #
2188
+ # When +nil+, +row+ is assumed to be a header row not based on an actual row
2189
+ # of the stream.
2190
+ #
2191
+ def parse_headers(row = nil)
2192
+ if @headers.nil? # header row
2193
+ @headers = case @use_headers # save headers
2194
+ # Array of headers
2195
+ when Array then @use_headers
2196
+ # CSV header String
2197
+ when String
2198
+ self.class.parse_line( @use_headers,
2199
+ col_sep: @col_sep,
2200
+ row_sep: @row_sep,
2201
+ quote_char: @quote_char )
2202
+ # first row is headers
2203
+ else row
2204
+ end
2205
+
2206
+ # prepare converted and unconverted copies
2207
+ row = @headers if row.nil?
2208
+ @headers = convert_fields(@headers, true)
2209
+
2210
+ if @return_headers # return headers
2211
+ return self.class::Row.new(@headers, row, true)
2212
+ elsif not [Array, String].include? @use_headers.class # skip to field row
2213
+ return shift
2214
+ end
2215
+ end
2216
+
2217
+ self.class::Row.new(@headers, convert_fields(row)) # field row
2218
+ end
2219
+
2220
+ #
2221
+ # Thiw methods injects an instance variable <tt>unconverted_fields</tt> into
2222
+ # +row+ and an accessor method for it called unconverted_fields(). The
2223
+ # variable is set to the contents of +fields+.
2224
+ #
2225
+ def add_unconverted_fields(row, fields)
2226
+ class << row
2227
+ attr_reader :unconverted_fields
2228
+ end
2229
+ row.instance_eval { @unconverted_fields = fields }
2230
+ row
2231
+ end
2232
+
2233
+ #
2234
+ # This method is an encoding safe version of Regexp::escape(). It will escape
2235
+ # any characters that would change the meaning of a regular expression in the
2236
+ # encoding of +str+. Regular expression characters that cannot be transcoded
2237
+ # to the target encoding will be skipped and no escaping will be performed if
2238
+ # a backslash cannot be transcoded.
2239
+ #
2240
+ def escape_re(str)
2241
+ str.chars.map { |c| @re_chars.include?(c) ? @re_esc + c : c }.join
2242
+ end
2243
+
2244
+ #
2245
+ # Builds a regular expression in <tt>@encoding</tt>. All +chunks+ will be
2246
+ # transcoded to that encoding.
2247
+ #
2248
+ def encode_re(*chunks)
2249
+ Regexp.new(encode_str(*chunks))
2250
+ end
2251
+
2252
+ #
2253
+ # Builds a String in <tt>@encoding</tt>. All +chunks+ will be transcoded to
2254
+ # that encoding.
2255
+ #
2256
+ def encode_str(*chunks)
2257
+ chunks.map { |chunk| chunk.encode(@encoding.name) }.join
2258
+ end
2259
+
2260
+ #
2261
+ # Reads at least +bytes+ from <tt>@io</tt>, but will read up 10 bytes ahead if
2262
+ # needed to ensure the data read is valid in the ecoding of that data. This
2263
+ # should ensure that it is safe to use regular expressions on the read data,
2264
+ # unless it is actually a broken encoding. The read data will be returned in
2265
+ # <tt>@encoding</tt>.
2266
+ #
2267
+ def read_to_char(bytes)
2268
+ return "" if @io.eof?
2269
+ data = read_io(bytes)
2270
+ begin
2271
+ raise unless data.valid_encoding?
2272
+ encoded = encode_str(data)
2273
+ raise unless encoded.valid_encoding?
2274
+ return encoded
2275
+ rescue # encoding error or my invalid data raise
2276
+ if @io.eof? or data.size >= bytes + 10
2277
+ return data
2278
+ else
2279
+ data += read_io(1)
2280
+ retry
2281
+ end
2282
+ end
2283
+ end
2284
+
2285
+ private
2286
+ def raw_encoding
2287
+ if @io.respond_to? :internal_encoding
2288
+ @io.internal_encoding || @io.external_encoding
2289
+ elsif @io.is_a? StringIO
2290
+ @io.string.encoding
2291
+ elsif @io.respond_to? :encoding
2292
+ @io.encoding
2293
+ else
2294
+ Encoding::ASCII_8BIT
2295
+ end
2296
+ end
2297
+
2298
+ def read_io(bytes)
2299
+ @io.read(bytes).force_encoding(raw_encoding)
2300
+ end
2301
+ end
2302
+
2303
+ # Another name for CSV::instance().
2304
+ def CSV(*args, &block)
2305
+ CSV.instance(*args, &block)
2306
+ end
2307
+
2308
+ class Array
2309
+ # Equivalent to <tt>CSV::generate_line(self, options)</tt>.
2310
+ def to_csv(options = Hash.new)
2311
+ CSV.generate_line(self, options)
2312
+ end
2313
+ end
2314
+
2315
+ class String
2316
+ # Equivalent to <tt>CSV::parse_line(self, options)</tt>.
2317
+ def parse_csv(options = Hash.new)
2318
+ CSV.parse_line(self, options)
2319
+ end
2320
+ end