Skip to content
Browse files

intial copy from rubyforge

  • Loading branch information...
0 parents commit 7d38c055fe37b7c4a666cdd300392ddbb08a4449 Reg Braithwaite committed Nov 1, 2008
Showing with 19,323 additions and 0 deletions.
  1. +2 −0 .svn/README.txt
  2. 0 .svn/empty-file
  3. +97 −0 .svn/entries
  4. +1 −0 .svn/format
  5. +18 −0 .svn/text-base/History.txt.svn-base
  6. +20 −0 .svn/text-base/License.txt.svn-base
  7. +31 −0 .svn/text-base/Manifest.txt.svn-base
  8. +1 −0 .svn/text-base/README.txt.svn-base
  9. +4 −0 .svn/text-base/Rakefile.svn-base
  10. +1,585 −0 .svn/text-base/setup.rb.svn-base
  11. +22 −0 History.txt
  12. +20 −0 License.txt
  13. +41 −0 Manifest.txt
  14. +166 −0 README.textile
  15. +4 −0 Rakefile
  16. +2 −0 config/.svn/README.txt
  17. 0 config/.svn/empty-file
  18. +29 −0 config/.svn/entries
  19. +1 −0 config/.svn/format
  20. +70 −0 config/.svn/text-base/hoe.rb.svn-base
  21. +17 −0 config/.svn/text-base/requirements.rb.svn-base
  22. +72 −0 config/hoe.rb
  23. +17 −0 config/requirements.rb
  24. +186 −0 doc/classes/Ick/Advisor.html
  25. +45 −0 doc/classes/Ick/Advisor.src/M000022.html
  26. +21 −0 doc/classes/Ick/Advisor.src/M000023.html
  27. +21 −0 doc/classes/Ick/Advisor.src/M000024.html
  28. +23 −0 doc/classes/Ick/Advisor.src/M000025.html
  29. +139 −0 doc/classes/Ick/ArrayWrapper.html
  30. +18 −0 doc/classes/Ick/ArrayWrapper.src/M000019.html
  31. +269 −0 doc/classes/Ick/Base.html
  32. +18 −0 doc/classes/Ick/Base.src/M000032.html
  33. +18 −0 doc/classes/Ick/Base.src/M000033.html
  34. +19 −0 doc/classes/Ick/Base.src/M000034.html
  35. +21 −0 doc/classes/Ick/Base.src/M000035.html
  36. +21 −0 doc/classes/Ick/Base.src/M000036.html
  37. +21 −0 doc/classes/Ick/Base.src/M000037.html
  38. +21 −0 doc/classes/Ick/Base.src/M000038.html
  39. +21 −0 doc/classes/Ick/Base.src/M000039.html
  40. +28 −0 doc/classes/Ick/Base.src/M000040.html
  41. +169 −0 doc/classes/Ick/Bizarro.html
  42. +18 −0 doc/classes/Ick/Bizarro.src/M000029.html
  43. +18 −0 doc/classes/Ick/Bizarro.src/M000030.html
  44. +29 −0 doc/classes/Ick/Bizarro.src/M000031.html
  45. +117 −0 doc/classes/Ick/Fork.html
  46. +178 −0 doc/classes/Ick/Guard.html
  47. +18 −0 doc/classes/Ick/Guard.src/M000026.html
  48. +18 −0 doc/classes/Ick/Guard.src/M000027.html
  49. +18 −0 doc/classes/Ick/Guard.src/M000028.html
  50. +171 −0 doc/classes/Ick/GuardWrapper.html
  51. +20 −0 doc/classes/Ick/GuardWrapper.src/M000016.html
  52. +18 −0 doc/classes/Ick/GuardWrapper.src/M000017.html
  53. +18 −0 doc/classes/Ick/GuardWrapper.src/M000018.html
  54. +139 −0 doc/classes/Ick/IdentityWrapper.html
  55. +18 −0 doc/classes/Ick/IdentityWrapper.src/M000048.html
  56. +113 −0 doc/classes/Ick/Inside.html
  57. +154 −0 doc/classes/Ick/Invoker.html
  58. +19 −0 doc/classes/Ick/Invoker.src/M000020.html
  59. +20 −0 doc/classes/Ick/Invoker.src/M000021.html
  60. +113 −0 doc/classes/Ick/Let.html
  61. +113 −0 doc/classes/Ick/Maybe.html
  62. +113 −0 doc/classes/Ick/My.html
  63. +113 −0 doc/classes/Ick/Please.html
  64. +113 −0 doc/classes/Ick/Returning.html
  65. +171 −0 doc/classes/Ick/Split.html
  66. +18 −0 doc/classes/Ick/Split.src/M000041.html
  67. +18 −0 doc/classes/Ick/Split.src/M000042.html
  68. +29 −0 doc/classes/Ick/Split.src/M000043.html
  69. +116 −0 doc/classes/Ick/Syntax.html
  70. +139 −0 doc/classes/Ick/Syntax/Lets.html
  71. +47 −0 doc/classes/Ick/Syntax/Lets.src/M000001.html
  72. +208 −0 doc/classes/Ick/Syntax/Rewritten.html
  73. +18 −0 doc/classes/Ick/Syntax/Rewritten.src/M000002.html
  74. +23 −0 doc/classes/Ick/Syntax/Rewritten.src/M000003.html
  75. +21 −0 doc/classes/Ick/Syntax/Rewritten.src/M000004.html
  76. +20 −0 doc/classes/Ick/Syntax/Rewritten.src/M000005.html
  77. +18 −0 doc/classes/Ick/Syntax/Rewritten.src/M000006.html
  78. +117 −0 doc/classes/Ick/Tee.html
  79. +113 −0 doc/classes/Ick/Try.html
  80. +184 −0 doc/classes/Ick/Wrap.html
  81. +18 −0 doc/classes/Ick/Wrap.src/M000044.html
  82. +18 −0 doc/classes/Ick/Wrap.src/M000045.html
  83. +20 −0 doc/classes/Ick/Wrap.src/M000046.html
  84. +18 −0 doc/classes/Ick/Wrap.src/M000047.html
  85. +292 −0 doc/classes/Ick/Wrapper.html
  86. +18 −0 doc/classes/Ick/Wrapper.src/M000007.html
  87. +18 −0 doc/classes/Ick/Wrapper.src/M000008.html
  88. +18 −0 doc/classes/Ick/Wrapper.src/M000009.html
  89. +18 −0 doc/classes/Ick/Wrapper.src/M000010.html
  90. +18 −0 doc/classes/Ick/Wrapper.src/M000011.html
  91. +18 −0 doc/classes/Ick/Wrapper.src/M000012.html
  92. +18 −0 doc/classes/Ick/Wrapper.src/M000013.html
  93. +20 −0 doc/classes/Ick/Wrapper.src/M000014.html
  94. +18 −0 doc/classes/Ick/Wrapper.src/M000015.html
  95. +1 −0 doc/created.rid
  96. +180 −0 doc/files/History_txt.html
  97. +129 −0 doc/files/License_txt.html
  98. +107 −0 doc/files/README_txt.html
  99. +101 −0 doc/files/lib/ick/advisor_rb.html
  100. +108 −0 doc/files/lib/ick/base_rb.html
  101. +108 −0 doc/files/lib/ick/bizarro_rb.html
  102. +108 −0 doc/files/lib/ick/guard_rb.html
  103. +101 −0 doc/files/lib/ick/sugar_rb.html
  104. +101 −0 doc/files/lib/ick/syntax/let_rb.html
  105. +110 −0 doc/files/lib/ick/syntax/lets_rb.html
  106. +110 −0 doc/files/lib/ick/syntax/rewritten_rb.html
  107. +101 −0 doc/files/lib/ick/tee_rb.html
  108. +101 −0 doc/files/lib/ick/version_rb.html
  109. +101 −0 doc/files/lib/ick/wrap_rb.html
  110. +115 −0 doc/files/lib/ick_rb.html
  111. +351 −0 doc/files/website/180seconds_txt.html
  112. +421 −0 doc/files/website/index_txt.html
  113. +583 −0 doc/files/website/inside_txt.html
  114. +49 −0 doc/fr_class_index.html
  115. +44 −0 doc/fr_file_index.html
  116. +74 −0 doc/fr_method_index.html
  117. +24 −0 doc/index.html
  118. +208 −0 doc/rdoc-style.css
  119. +2 −0 lib/.svn/README.txt
  120. 0 lib/.svn/empty-file
  121. +24 −0 lib/.svn/entries
  122. +1 −0 lib/.svn/format
  123. +8 −0 lib/.svn/text-base/ick.rb.svn-base
  124. +15 −0 lib/ick.rb
  125. +2 −0 lib/ick/.svn/README.txt
  126. 0 lib/ick/.svn/empty-file
  127. +69 −0 lib/ick/.svn/entries
  128. +1 −0 lib/ick/.svn/format
  129. +90 −0 lib/ick/.svn/text-base/advisor.rb.svn-base
  130. +108 −0 lib/ick/.svn/text-base/base.rb.svn-base
  131. +53 −0 lib/ick/.svn/text-base/guard.rb.svn-base
  132. +7 −0 lib/ick/.svn/text-base/sugar.rb.svn-base
  133. +38 −0 lib/ick/.svn/text-base/tee.rb.svn-base
  134. +9 −0 lib/ick/.svn/text-base/version.rb.svn-base
  135. +87 −0 lib/ick/.svn/text-base/wrap.rb.svn-base
  136. +90 −0 lib/ick/advisor.rb
  137. +108 −0 lib/ick/base.rb
  138. +41 −0 lib/ick/bizarro.rb
  139. +53 −0 lib/ick/guard.rb
  140. +7 −0 lib/ick/sugar.rb
  141. +22 −0 lib/ick/syntax.rb
  142. +58 −0 lib/ick/syntax/lets.rb
  143. +60 −0 lib/ick/syntax/rewritten.rb
  144. +38 −0 lib/ick/tee.rb
  145. +9 −0 lib/ick/version.rb
  146. +87 −0 lib/ick/wrap.rb
  147. +2 −0 log/.svn/README.txt
  148. 0 log/.svn/empty-file
  149. +21 −0 log/.svn/entries
  150. +1 −0 log/.svn/format
  151. 0 log/.svn/text-base/debug.log.svn-base
  152. 0 log/debug.log
  153. +24 −0 notes/rewrite.markdown
  154. BIN pkg/ick-0.3.1.gem
  155. BIN pkg/ick-0.3.1.tgz
  156. +22 −0 pkg/ick-0.3.1/History.txt
  157. +20 −0 pkg/ick-0.3.1/License.txt
  158. +41 −0 pkg/ick-0.3.1/Manifest.txt
  159. +1 −0 pkg/ick-0.3.1/README.txt
  160. +4 −0 pkg/ick-0.3.1/Rakefile
  161. +72 −0 pkg/ick-0.3.1/config/hoe.rb
  162. +17 −0 pkg/ick-0.3.1/config/requirements.rb
  163. +15 −0 pkg/ick-0.3.1/lib/ick.rb
  164. +90 −0 pkg/ick-0.3.1/lib/ick/advisor.rb
  165. +108 −0 pkg/ick-0.3.1/lib/ick/base.rb
  166. +41 −0 pkg/ick-0.3.1/lib/ick/bizarro.rb
  167. +53 −0 pkg/ick-0.3.1/lib/ick/guard.rb
  168. +7 −0 pkg/ick-0.3.1/lib/ick/sugar.rb
  169. 0 pkg/ick-0.3.1/lib/ick/syntax/let.rb
  170. +58 −0 pkg/ick-0.3.1/lib/ick/syntax/lets.rb
  171. +60 −0 pkg/ick-0.3.1/lib/ick/syntax/rewritten.rb
  172. +38 −0 pkg/ick-0.3.1/lib/ick/tee.rb
  173. +9 −0 pkg/ick-0.3.1/lib/ick/version.rb
  174. +87 −0 pkg/ick-0.3.1/lib/ick/wrap.rb
  175. 0 pkg/ick-0.3.1/log/debug.log
  176. +14 −0 pkg/ick-0.3.1/script/destroy
  177. +14 −0 pkg/ick-0.3.1/script/generate
  178. +74 −0 pkg/ick-0.3.1/script/txt2html
  179. +1,585 −0 pkg/ick-0.3.1/setup.rb
  180. +34 −0 pkg/ick-0.3.1/tasks/deployment.rake
  181. +7 −0 pkg/ick-0.3.1/tasks/environment.rake
  182. +17 −0 pkg/ick-0.3.1/tasks/website.rake
  183. +100 −0 pkg/ick-0.3.1/test/test_180_seconds.rb
  184. +70 −0 pkg/ick-0.3.1/test/test_advisor.rb
  185. +26 −0 pkg/ick-0.3.1/test/test_helper.rb
  186. +148 −0 pkg/ick-0.3.1/test/test_ick.rb
  187. +56 −0 pkg/ick-0.3.1/test/test_lets.rb
  188. +239 −0 pkg/ick-0.3.1/website/180seconds.html
  189. +159 −0 pkg/ick-0.3.1/website/180seconds.txt
  190. +272 −0 pkg/ick-0.3.1/website/index.html
  191. +166 −0 pkg/ick-0.3.1/website/index.txt
  192. +370 −0 pkg/ick-0.3.1/website/inside.html
  193. +250 −0 pkg/ick-0.3.1/website/inside.txt
  194. +285 −0 pkg/ick-0.3.1/website/javascripts/rounded_corners_lite.inc.js
  195. +138 −0 pkg/ick-0.3.1/website/stylesheets/screen.css
  196. +50 −0 pkg/ick-0.3.1/website/template.rhtml
  197. +2 −0 script/.svn/README.txt
  198. 0 script/.svn/empty-file
  199. +40 −0 script/.svn/entries
  200. +1 −0 script/.svn/format
  201. +5 −0 script/.svn/prop-base/destroy.svn-base
  202. +5 −0 script/.svn/prop-base/generate.svn-base
  203. +5 −0 script/.svn/prop-base/txt2html.svn-base
  204. +5 −0 script/.svn/props/destroy.svn-work
  205. +5 −0 script/.svn/props/generate.svn-work
  206. +5 −0 script/.svn/props/txt2html.svn-work
  207. +14 −0 script/.svn/text-base/destroy.svn-base
  208. +14 −0 script/.svn/text-base/generate.svn-base
  209. +74 −0 script/.svn/text-base/txt2html.svn-base
  210. +14 −0 script/destroy
  211. +14 −0 script/generate
  212. +74 −0 script/txt2html
  213. +1,585 −0 setup.rb
  214. +2 −0 tasks/.svn/README.txt
  215. 0 tasks/.svn/empty-file
  216. +37 −0 tasks/.svn/entries
  217. +1 −0 tasks/.svn/format
  218. +34 −0 tasks/.svn/text-base/deployment.rake.svn-base
  219. +7 −0 tasks/.svn/text-base/environment.rake.svn-base
  220. +17 −0 tasks/.svn/text-base/website.rake.svn-base
  221. +34 −0 tasks/deployment.rake
  222. +7 −0 tasks/environment.rake
  223. +17 −0 tasks/website.rake
  224. +2 −0 test/.svn/README.txt
  225. 0 test/.svn/empty-file
  226. +37 −0 test/.svn/entries
  227. +1 −0 test/.svn/format
  228. +70 −0 test/.svn/text-base/test_advisor.rb.svn-base
  229. +26 −0 test/.svn/text-base/test_helper.rb.svn-base
  230. +148 −0 test/.svn/text-base/test_ick.rb.svn-base
  231. +100 −0 test/test_180_seconds.rb
  232. +70 −0 test/test_advisor.rb
  233. +26 −0 test/test_helper.rb
  234. +148 −0 test/test_ick.rb
  235. +56 −0 test/test_lets.rb
  236. +2 −0 tmp/.svn/README.txt
  237. 0 tmp/.svn/empty-file
  238. +13 −0 tmp/.svn/entries
  239. +1 −0 tmp/.svn/format
  240. +2 −0 website/.svn/README.txt
  241. 0 website/.svn/empty-file
  242. +59 −0 website/.svn/entries
  243. +1 −0 website/.svn/format
  244. +248 −0 website/.svn/text-base/index.html.svn-base
  245. +149 −0 website/.svn/text-base/index.txt.svn-base
Sorry, we could not display the entire diff because it was too big.
2 .svn/README.txt
@@ -0,0 +1,2 @@
+This is a Subversion working copy administrative directory.
+Visit http://subversion.tigris.org/ for more information.
0 .svn/empty-file
No changes.
97 .svn/entries
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wc-entries
+ xmlns="svn:">
+<entry
+ committed-rev="0"
+ name=""
+ committed-date="2008-03-07T13:46:10.631799Z"
+ url="svn+ssh://raganwald@rubyforge.org/var/svn/ick"
+ kind="dir"
+ uuid="be80e314-ce3b-4dd1-ab14-25665a6ab324"
+ repos="svn+ssh://raganwald@rubyforge.org/var/svn/ick"
+ revision="0"/>
+<entry
+ name="test"
+ kind="dir"/>
+<entry
+ committed-rev="1"
+ name="History.txt"
+ text-time="2008-03-10T04:46:40.000000Z"
+ committed-date="2008-03-10T04:57:06.697106Z"
+ checksum="f32037b3801833cbea54ddbf0717baf4"
+ last-author="raganwald"
+ kind="file"
+ revision="1"/>
+<entry
+ name="pkg"
+ kind="dir"/>
+<entry
+ name="log"
+ kind="dir"/>
+<entry
+ committed-rev="1"
+ name="Rakefile"
+ text-time="2008-03-07T21:30:30.000000Z"
+ committed-date="2008-03-10T04:57:06.697106Z"
+ checksum="120b066d386a523afe7f5613c386710e"
+ last-author="raganwald"
+ kind="file"
+ revision="1"/>
+<entry
+ committed-rev="1"
+ name="Manifest.txt"
+ text-time="2008-03-09T15:38:47.000000Z"
+ committed-date="2008-03-10T04:57:06.697106Z"
+ checksum="d857aef65c95d86db917db216f1cfcd8"
+ last-author="raganwald"
+ kind="file"
+ revision="1"/>
+<entry
+ name="tasks"
+ kind="dir"/>
+<entry
+ name="tmp"
+ kind="dir"/>
+<entry
+ committed-rev="1"
+ name="License.txt"
+ text-time="2008-03-07T22:24:17.000000Z"
+ committed-date="2008-03-10T04:57:06.697106Z"
+ checksum="4062dbd4427ce141cd6d26b5e1af9bff"
+ last-author="raganwald"
+ kind="file"
+ revision="1"/>
+<entry
+ name="website"
+ kind="dir"/>
+<entry
+ committed-rev="1"
+ name="setup.rb"
+ text-time="2008-03-07T21:30:30.000000Z"
+ committed-date="2008-03-10T04:57:06.697106Z"
+ checksum="f3e96d4b9eeb3d0c4d841c7c7ea6259c"
+ last-author="raganwald"
+ kind="file"
+ revision="1"/>
+<entry
+ name="script"
+ kind="dir"/>
+<entry
+ name="doc"
+ kind="dir"/>
+<entry
+ name="config"
+ kind="dir"/>
+<entry
+ name="lib"
+ kind="dir"/>
+<entry
+ committed-rev="1"
+ name="README.txt"
+ text-time="2008-03-07T21:30:30.000000Z"
+ committed-date="2008-03-10T04:57:06.697106Z"
+ checksum="c47c7c7383225ab55ff591cb59c41e6b"
+ last-author="raganwald"
+ kind="file"
+ revision="1"/>
+</wc-entries>
1 .svn/format
@@ -0,0 +1 @@
+4
18 .svn/text-base/History.txt.svn-base
@@ -0,0 +1,18 @@
+== 0.0.1 2008-03-07
+
+* 1 major enhancement:
+ * Initial super-alpha release
+ * Not particularly good at nesting
+* 2 minor enhancement:
+ * Changed #with to #inside avoid confusion with Object#with
+* 3 minor enhancement:
+ * refactored Wrapped into Wrap with runtime options
+ * added ArrayWrapper and Tee classes
+* 4 tiny enhancement
+ * fixed manifest.txt
+ * TODO: build the manifest algorithmically!
+* 5 tiny enhancement
+ * #fork
+* 6 tiny enhancement
+ * work in progress on Advisor
+
20 .svn/text-base/License.txt.svn-base
@@ -0,0 +1,20 @@
+Copyright (c) 2008 Reginald Braithwaite
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 .svn/text-base/Manifest.txt.svn-base
@@ -0,0 +1,31 @@
+History.txt
+License.txt
+Manifest.txt
+README.txt
+Rakefile
+config/hoe.rb
+config/requirements.rb
+lib/ick.rb
+lib/ick/advisor.rb
+lib/ick/base.rb
+lib/ick/guard.rb
+lib/ick/sugar.rb
+lib/ick/tee.rb
+lib/ick/version.rb
+lib/ick/wrap.rb
+log/debug.log
+script/destroy
+script/generate
+script/txt2html
+setup.rb
+tasks/deployment.rake
+tasks/environment.rake
+tasks/website.rake
+test/test_helper.rb
+test/test_ick.rb
+test/test_advisor.rb
+website/index.html
+website/index.txt
+website/javascripts/rounded_corners_lite.inc.js
+website/stylesheets/screen.css
+website/template.rhtml
1 .svn/text-base/README.txt.svn-base
@@ -0,0 +1 @@
+README
4 .svn/text-base/Rakefile.svn-base
@@ -0,0 +1,4 @@
+require 'config/requirements'
+require 'config/hoe' # setup Hoe + all gem configuration
+
+Dir['tasks/**/*.rake'].each { |rake| load rake }
1,585 .svn/text-base/setup.rb.svn-base
@@ -0,0 +1,1585 @@
+#
+# setup.rb
+#
+# Copyright (c) 2000-2005 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+#
+
+unless Enumerable.method_defined?(:map) # Ruby 1.4.6
+ module Enumerable
+ alias map collect
+ end
+end
+
+unless File.respond_to?(:read) # Ruby 1.6
+ def File.read(fname)
+ open(fname) {|f|
+ return f.read
+ }
+ end
+end
+
+unless Errno.const_defined?(:ENOTEMPTY) # Windows?
+ module Errno
+ class ENOTEMPTY
+ # We do not raise this exception, implementation is not needed.
+ end
+ end
+end
+
+def File.binread(fname)
+ open(fname, 'rb') {|f|
+ return f.read
+ }
+end
+
+# for corrupted Windows' stat(2)
+def File.dir?(path)
+ File.directory?((path[-1,1] == '/') ? path : path + '/')
+end
+
+
+class ConfigTable
+
+ include Enumerable
+
+ def initialize(rbconfig)
+ @rbconfig = rbconfig
+ @items = []
+ @table = {}
+ # options
+ @install_prefix = nil
+ @config_opt = nil
+ @verbose = true
+ @no_harm = false
+ end
+
+ attr_accessor :install_prefix
+ attr_accessor :config_opt
+
+ attr_writer :verbose
+
+ def verbose?
+ @verbose
+ end
+
+ attr_writer :no_harm
+
+ def no_harm?
+ @no_harm
+ end
+
+ def [](key)
+ lookup(key).resolve(self)
+ end
+
+ def []=(key, val)
+ lookup(key).set val
+ end
+
+ def names
+ @items.map {|i| i.name }
+ end
+
+ def each(&block)
+ @items.each(&block)
+ end
+
+ def key?(name)
+ @table.key?(name)
+ end
+
+ def lookup(name)
+ @table[name] or setup_rb_error "no such config item: #{name}"
+ end
+
+ def add(item)
+ @items.push item
+ @table[item.name] = item
+ end
+
+ def remove(name)
+ item = lookup(name)
+ @items.delete_if {|i| i.name == name }
+ @table.delete_if {|name, i| i.name == name }
+ item
+ end
+
+ def load_script(path, inst = nil)
+ if File.file?(path)
+ MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
+ end
+ end
+
+ def savefile
+ '.config'
+ end
+
+ def load_savefile
+ begin
+ File.foreach(savefile()) do |line|
+ k, v = *line.split(/=/, 2)
+ self[k] = v.strip
+ end
+ rescue Errno::ENOENT
+ setup_rb_error $!.message + "\n#{File.basename($0)} config first"
+ end
+ end
+
+ def save
+ @items.each {|i| i.value }
+ File.open(savefile(), 'w') {|f|
+ @items.each do |i|
+ f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
+ end
+ }
+ end
+
+ def load_standard_entries
+ standard_entries(@rbconfig).each do |ent|
+ add ent
+ end
+ end
+
+ def standard_entries(rbconfig)
+ c = rbconfig
+
+ rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
+
+ major = c['MAJOR'].to_i
+ minor = c['MINOR'].to_i
+ teeny = c['TEENY'].to_i
+ version = "#{major}.#{minor}"
+
+ # ruby ver. >= 1.4.4?
+ newpath_p = ((major >= 2) or
+ ((major == 1) and
+ ((minor >= 5) or
+ ((minor == 4) and (teeny >= 4)))))
+
+ if c['rubylibdir']
+ # V > 1.6.3
+ libruby = "#{c['prefix']}/lib/ruby"
+ librubyver = c['rubylibdir']
+ librubyverarch = c['archdir']
+ siteruby = c['sitedir']
+ siterubyver = c['sitelibdir']
+ siterubyverarch = c['sitearchdir']
+ elsif newpath_p
+ # 1.4.4 <= V <= 1.6.3
+ libruby = "#{c['prefix']}/lib/ruby"
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
+ siteruby = c['sitedir']
+ siterubyver = "$siteruby/#{version}"
+ siterubyverarch = "$siterubyver/#{c['arch']}"
+ else
+ # V < 1.4.4
+ libruby = "#{c['prefix']}/lib/ruby"
+ librubyver = "#{c['prefix']}/lib/ruby/#{version}"
+ librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
+ siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
+ siterubyver = siteruby
+ siterubyverarch = "$siterubyver/#{c['arch']}"
+ end
+ parameterize = lambda {|path|
+ path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
+ }
+
+ if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
+ makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
+ else
+ makeprog = 'make'
+ end
+
+ [
+ ExecItem.new('installdirs', 'std/site/home',
+ 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
+ {|val, table|
+ case val
+ when 'std'
+ table['rbdir'] = '$librubyver'
+ table['sodir'] = '$librubyverarch'
+ when 'site'
+ table['rbdir'] = '$siterubyver'
+ table['sodir'] = '$siterubyverarch'
+ when 'home'
+ setup_rb_error '$HOME was not set' unless ENV['HOME']
+ table['prefix'] = ENV['HOME']
+ table['rbdir'] = '$libdir/ruby'
+ table['sodir'] = '$libdir/ruby'
+ end
+ },
+ PathItem.new('prefix', 'path', c['prefix'],
+ 'path prefix of target environment'),
+ PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
+ 'the directory for commands'),
+ PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
+ 'the directory for libraries'),
+ PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
+ 'the directory for shared data'),
+ PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
+ 'the directory for man pages'),
+ PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
+ 'the directory for system configuration files'),
+ PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
+ 'the directory for local state data'),
+ PathItem.new('libruby', 'path', libruby,
+ 'the directory for ruby libraries'),
+ PathItem.new('librubyver', 'path', librubyver,
+ 'the directory for standard ruby libraries'),
+ PathItem.new('librubyverarch', 'path', librubyverarch,
+ 'the directory for standard ruby extensions'),
+ PathItem.new('siteruby', 'path', siteruby,
+ 'the directory for version-independent aux ruby libraries'),
+ PathItem.new('siterubyver', 'path', siterubyver,
+ 'the directory for aux ruby libraries'),
+ PathItem.new('siterubyverarch', 'path', siterubyverarch,
+ 'the directory for aux ruby binaries'),
+ PathItem.new('rbdir', 'path', '$siterubyver',
+ 'the directory for ruby scripts'),
+ PathItem.new('sodir', 'path', '$siterubyverarch',
+ 'the directory for ruby extentions'),
+ PathItem.new('rubypath', 'path', rubypath,
+ 'the path to set to #! line'),
+ ProgramItem.new('rubyprog', 'name', rubypath,
+ 'the ruby program using for installation'),
+ ProgramItem.new('makeprog', 'name', makeprog,
+ 'the make program to compile ruby extentions'),
+ SelectItem.new('shebang', 'all/ruby/never', 'ruby',
+ 'shebang line (#!) editing mode'),
+ BoolItem.new('without-ext', 'yes/no', 'no',
+ 'does not compile/install ruby extentions')
+ ]
+ end
+ private :standard_entries
+
+ def load_multipackage_entries
+ multipackage_entries().each do |ent|
+ add ent
+ end
+ end
+
+ def multipackage_entries
+ [
+ PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
+ 'package names that you want to install'),
+ PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
+ 'package names that you do not want to install')
+ ]
+ end
+ private :multipackage_entries
+
+ ALIASES = {
+ 'std-ruby' => 'librubyver',
+ 'stdruby' => 'librubyver',
+ 'rubylibdir' => 'librubyver',
+ 'archdir' => 'librubyverarch',
+ 'site-ruby-common' => 'siteruby', # For backward compatibility
+ 'site-ruby' => 'siterubyver', # For backward compatibility
+ 'bin-dir' => 'bindir',
+ 'bin-dir' => 'bindir',
+ 'rb-dir' => 'rbdir',
+ 'so-dir' => 'sodir',
+ 'data-dir' => 'datadir',
+ 'ruby-path' => 'rubypath',
+ 'ruby-prog' => 'rubyprog',
+ 'ruby' => 'rubyprog',
+ 'make-prog' => 'makeprog',
+ 'make' => 'makeprog'
+ }
+
+ def fixup
+ ALIASES.each do |ali, name|
+ @table[ali] = @table[name]
+ end
+ @items.freeze
+ @table.freeze
+ @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
+ end
+
+ def parse_opt(opt)
+ m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
+ m.to_a[1,2]
+ end
+
+ def dllext
+ @rbconfig['DLEXT']
+ end
+
+ def value_config?(name)
+ lookup(name).value?
+ end
+
+ class Item
+ def initialize(name, template, default, desc)
+ @name = name.freeze
+ @template = template
+ @value = default
+ @default = default
+ @description = desc
+ end
+
+ attr_reader :name
+ attr_reader :description
+
+ attr_accessor :default
+ alias help_default default
+
+ def help_opt
+ "--#{@name}=#{@template}"
+ end
+
+ def value?
+ true
+ end
+
+ def value
+ @value
+ end
+
+ def resolve(table)
+ @value.gsub(%r<\$([^/]+)>) { table[$1] }
+ end
+
+ def set(val)
+ @value = check(val)
+ end
+
+ private
+
+ def check(val)
+ setup_rb_error "config: --#{name} requires argument" unless val
+ val
+ end
+ end
+
+ class BoolItem < Item
+ def config_type
+ 'bool'
+ end
+
+ def help_opt
+ "--#{@name}"
+ end
+
+ private
+
+ def check(val)
+ return 'yes' unless val
+ case val
+ when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
+ when /\An(o)?\z/i, /\Af(alse)\z/i then 'no'
+ else
+ setup_rb_error "config: --#{@name} accepts only yes/no for argument"
+ end
+ end
+ end
+
+ class PathItem < Item
+ def config_type
+ 'path'
+ end
+
+ private
+
+ def check(path)
+ setup_rb_error "config: --#{@name} requires argument" unless path
+ path[0,1] == '$' ? path : File.expand_path(path)
+ end
+ end
+
+ class ProgramItem < Item
+ def config_type
+ 'program'
+ end
+ end
+
+ class SelectItem < Item
+ def initialize(name, selection, default, desc)
+ super
+ @ok = selection.split('/')
+ end
+
+ def config_type
+ 'select'
+ end
+
+ private
+
+ def check(val)
+ unless @ok.include?(val.strip)
+ setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
+ end
+ val.strip
+ end
+ end
+
+ class ExecItem < Item
+ def initialize(name, selection, desc, &block)
+ super name, selection, nil, desc
+ @ok = selection.split('/')
+ @action = block
+ end
+
+ def config_type
+ 'exec'
+ end
+
+ def value?
+ false
+ end
+
+ def resolve(table)
+ setup_rb_error "$#{name()} wrongly used as option value"
+ end
+
+ undef set
+
+ def evaluate(val, table)
+ v = val.strip.downcase
+ unless @ok.include?(v)
+ setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
+ end
+ @action.call v, table
+ end
+ end
+
+ class PackageSelectionItem < Item
+ def initialize(name, template, default, help_default, desc)
+ super name, template, default, desc
+ @help_default = help_default
+ end
+
+ attr_reader :help_default
+
+ def config_type
+ 'package'
+ end
+
+ private
+
+ def check(val)
+ unless File.dir?("packages/#{val}")
+ setup_rb_error "config: no such package: #{val}"
+ end
+ val
+ end
+ end
+
+ class MetaConfigEnvironment
+ def initialize(config, installer)
+ @config = config
+ @installer = installer
+ end
+
+ def config_names
+ @config.names
+ end
+
+ def config?(name)
+ @config.key?(name)
+ end
+
+ def bool_config?(name)
+ @config.lookup(name).config_type == 'bool'
+ end
+
+ def path_config?(name)
+ @config.lookup(name).config_type == 'path'
+ end
+
+ def value_config?(name)
+ @config.lookup(name).config_type != 'exec'
+ end
+
+ def add_config(item)
+ @config.add item
+ end
+
+ def add_bool_config(name, default, desc)
+ @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
+ end
+
+ def add_path_config(name, default, desc)
+ @config.add PathItem.new(name, 'path', default, desc)
+ end
+
+ def set_config_default(name, default)
+ @config.lookup(name).default = default
+ end
+
+ def remove_config(name)
+ @config.remove(name)
+ end
+
+ # For only multipackage
+ def packages
+ raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
+ @installer.packages
+ end
+
+ # For only multipackage
+ def declare_packages(list)
+ raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
+ @installer.packages = list
+ end
+ end
+
+end # class ConfigTable
+
+
+# This module requires: #verbose?, #no_harm?
+module FileOperations
+
+ def mkdir_p(dirname, prefix = nil)
+ dirname = prefix + File.expand_path(dirname) if prefix
+ $stderr.puts "mkdir -p #{dirname}" if verbose?
+ return if no_harm?
+
+ # Does not check '/', it's too abnormal.
+ dirs = File.expand_path(dirname).split(%r<(?=/)>)
+ if /\A[a-z]:\z/i =~ dirs[0]
+ disk = dirs.shift
+ dirs[0] = disk + dirs[0]
+ end
+ dirs.each_index do |idx|
+ path = dirs[0..idx].join('')
+ Dir.mkdir path unless File.dir?(path)
+ end
+ end
+
+ def rm_f(path)
+ $stderr.puts "rm -f #{path}" if verbose?
+ return if no_harm?
+ force_remove_file path
+ end
+
+ def rm_rf(path)
+ $stderr.puts "rm -rf #{path}" if verbose?
+ return if no_harm?
+ remove_tree path
+ end
+
+ def remove_tree(path)
+ if File.symlink?(path)
+ remove_file path
+ elsif File.dir?(path)
+ remove_tree0 path
+ else
+ force_remove_file path
+ end
+ end
+
+ def remove_tree0(path)
+ Dir.foreach(path) do |ent|
+ next if ent == '.'
+ next if ent == '..'
+ entpath = "#{path}/#{ent}"
+ if File.symlink?(entpath)
+ remove_file entpath
+ elsif File.dir?(entpath)
+ remove_tree0 entpath
+ else
+ force_remove_file entpath
+ end
+ end
+ begin
+ Dir.rmdir path
+ rescue Errno::ENOTEMPTY
+ # directory may not be empty
+ end
+ end
+
+ def move_file(src, dest)
+ force_remove_file dest
+ begin
+ File.rename src, dest
+ rescue
+ File.open(dest, 'wb') {|f|
+ f.write File.binread(src)
+ }
+ File.chmod File.stat(src).mode, dest
+ File.unlink src
+ end
+ end
+
+ def force_remove_file(path)
+ begin
+ remove_file path
+ rescue
+ end
+ end
+
+ def remove_file(path)
+ File.chmod 0777, path
+ File.unlink path
+ end
+
+ def install(from, dest, mode, prefix = nil)
+ $stderr.puts "install #{from} #{dest}" if verbose?
+ return if no_harm?
+
+ realdest = prefix ? prefix + File.expand_path(dest) : dest
+ realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
+ str = File.binread(from)
+ if diff?(str, realdest)
+ verbose_off {
+ rm_f realdest if File.exist?(realdest)
+ }
+ File.open(realdest, 'wb') {|f|
+ f.write str
+ }
+ File.chmod mode, realdest
+
+ File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
+ if prefix
+ f.puts realdest.sub(prefix, '')
+ else
+ f.puts realdest
+ end
+ }
+ end
+ end
+
+ def diff?(new_content, path)
+ return true unless File.exist?(path)
+ new_content != File.binread(path)
+ end
+
+ def command(*args)
+ $stderr.puts args.join(' ') if verbose?
+ system(*args) or raise RuntimeError,
+ "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
+ end
+
+ def ruby(*args)
+ command config('rubyprog'), *args
+ end
+
+ def make(task = nil)
+ command(*[config('makeprog'), task].compact)
+ end
+
+ def extdir?(dir)
+ File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
+ end
+
+ def files_of(dir)
+ Dir.open(dir) {|d|
+ return d.select {|ent| File.file?("#{dir}/#{ent}") }
+ }
+ end
+
+ DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
+
+ def directories_of(dir)
+ Dir.open(dir) {|d|
+ return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
+ }
+ end
+
+end
+
+
+# This module requires: #srcdir_root, #objdir_root, #relpath
+module HookScriptAPI
+
+ def get_config(key)
+ @config[key]
+ end
+
+ alias config get_config
+
+ # obsolete: use metaconfig to change configuration
+ def set_config(key, val)
+ @config[key] = val
+ end
+
+ #
+ # srcdir/objdir (works only in the package directory)
+ #
+
+ def curr_srcdir
+ "#{srcdir_root()}/#{relpath()}"
+ end
+
+ def curr_objdir
+ "#{objdir_root()}/#{relpath()}"
+ end
+
+ def srcfile(path)
+ "#{curr_srcdir()}/#{path}"
+ end
+
+ def srcexist?(path)
+ File.exist?(srcfile(path))
+ end
+
+ def srcdirectory?(path)
+ File.dir?(srcfile(path))
+ end
+
+ def srcfile?(path)
+ File.file?(srcfile(path))
+ end
+
+ def srcentries(path = '.')
+ Dir.open("#{curr_srcdir()}/#{path}") {|d|
+ return d.to_a - %w(. ..)
+ }
+ end
+
+ def srcfiles(path = '.')
+ srcentries(path).select {|fname|
+ File.file?(File.join(curr_srcdir(), path, fname))
+ }
+ end
+
+ def srcdirectories(path = '.')
+ srcentries(path).select {|fname|
+ File.dir?(File.join(curr_srcdir(), path, fname))
+ }
+ end
+
+end
+
+
+class ToplevelInstaller
+
+ Version = '3.4.1'
+ Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
+
+ TASKS = [
+ [ 'all', 'do config, setup, then install' ],
+ [ 'config', 'saves your configurations' ],
+ [ 'show', 'shows current configuration' ],
+ [ 'setup', 'compiles ruby extentions and others' ],
+ [ 'install', 'installs files' ],
+ [ 'test', 'run all tests in test/' ],
+ [ 'clean', "does `make clean' for each extention" ],
+ [ 'distclean',"does `make distclean' for each extention" ]
+ ]
+
+ def ToplevelInstaller.invoke
+ config = ConfigTable.new(load_rbconfig())
+ config.load_standard_entries
+ config.load_multipackage_entries if multipackage?
+ config.fixup
+ klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
+ klass.new(File.dirname($0), config).invoke
+ end
+
+ def ToplevelInstaller.multipackage?
+ File.dir?(File.dirname($0) + '/packages')
+ end
+
+ def ToplevelInstaller.load_rbconfig
+ if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
+ ARGV.delete(arg)
+ load File.expand_path(arg.split(/=/, 2)[1])
+ $".push 'rbconfig.rb'
+ else
+ require 'rbconfig'
+ end
+ ::Config::CONFIG
+ end
+
+ def initialize(ardir_root, config)
+ @ardir = File.expand_path(ardir_root)
+ @config = config
+ # cache
+ @valid_task_re = nil
+ end
+
+ def config(key)
+ @config[key]
+ end
+
+ def inspect
+ "#<#{self.class} #{__id__()}>"
+ end
+
+ def invoke
+ run_metaconfigs
+ case task = parsearg_global()
+ when nil, 'all'
+ parsearg_config
+ init_installers
+ exec_config
+ exec_setup
+ exec_install
+ else
+ case task
+ when 'config', 'test'
+ ;
+ when 'clean', 'distclean'
+ @config.load_savefile if File.exist?(@config.savefile)
+ else
+ @config.load_savefile
+ end
+ __send__ "parsearg_#{task}"
+ init_installers
+ __send__ "exec_#{task}"
+ end
+ end
+
+ def run_metaconfigs
+ @config.load_script "#{@ardir}/metaconfig"
+ end
+
+ def init_installers
+ @installer = Installer.new(@config, @ardir, File.expand_path('.'))
+ end
+
+ #
+ # Hook Script API bases
+ #
+
+ def srcdir_root
+ @ardir
+ end
+
+ def objdir_root
+ '.'
+ end
+
+ def relpath
+ '.'
+ end
+
+ #
+ # Option Parsing
+ #
+
+ def parsearg_global
+ while arg = ARGV.shift
+ case arg
+ when /\A\w+\z/
+ setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
+ return arg
+ when '-q', '--quiet'
+ @config.verbose = false
+ when '--verbose'
+ @config.verbose = true
+ when '--help'
+ print_usage $stdout
+ exit 0
+ when '--version'
+ puts "#{File.basename($0)} version #{Version}"
+ exit 0
+ when '--copyright'
+ puts Copyright
+ exit 0
+ else
+ setup_rb_error "unknown global option '#{arg}'"
+ end
+ end
+ nil
+ end
+
+ def valid_task?(t)
+ valid_task_re() =~ t
+ end
+
+ def valid_task_re
+ @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
+ end
+
+ def parsearg_no_options
+ unless ARGV.empty?
+ task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
+ setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
+ end
+ end
+
+ alias parsearg_show parsearg_no_options
+ alias parsearg_setup parsearg_no_options
+ alias parsearg_test parsearg_no_options
+ alias parsearg_clean parsearg_no_options
+ alias parsearg_distclean parsearg_no_options
+
+ def parsearg_config
+ evalopt = []
+ set = []
+ @config.config_opt = []
+ while i = ARGV.shift
+ if /\A--?\z/ =~ i
+ @config.config_opt = ARGV.dup
+ break
+ end
+ name, value = *@config.parse_opt(i)
+ if @config.value_config?(name)
+ @config[name] = value
+ else
+ evalopt.push [name, value]
+ end
+ set.push name
+ end
+ evalopt.each do |name, value|
+ @config.lookup(name).evaluate value, @config
+ end
+ # Check if configuration is valid
+ set.each do |n|
+ @config[n] if @config.value_config?(n)
+ end
+ end
+
+ def parsearg_install
+ @config.no_harm = false
+ @config.install_prefix = ''
+ while a = ARGV.shift
+ case a
+ when '--no-harm'
+ @config.no_harm = true
+ when /\A--prefix=/
+ path = a.split(/=/, 2)[1]
+ path = File.expand_path(path) unless path[0,1] == '/'
+ @config.install_prefix = path
+ else
+ setup_rb_error "install: unknown option #{a}"
+ end
+ end
+ end
+
+ def print_usage(out)
+ out.puts 'Typical Installation Procedure:'
+ out.puts " $ ruby #{File.basename $0} config"
+ out.puts " $ ruby #{File.basename $0} setup"
+ out.puts " # ruby #{File.basename $0} install (may require root privilege)"
+ out.puts
+ out.puts 'Detailed Usage:'
+ out.puts " ruby #{File.basename $0} <global option>"
+ out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
+
+ fmt = " %-24s %s\n"
+ out.puts
+ out.puts 'Global options:'
+ out.printf fmt, '-q,--quiet', 'suppress message outputs'
+ out.printf fmt, ' --verbose', 'output messages verbosely'
+ out.printf fmt, ' --help', 'print this message'
+ out.printf fmt, ' --version', 'print version and quit'
+ out.printf fmt, ' --copyright', 'print copyright and quit'
+ out.puts
+ out.puts 'Tasks:'
+ TASKS.each do |name, desc|
+ out.printf fmt, name, desc
+ end
+
+ fmt = " %-24s %s [%s]\n"
+ out.puts
+ out.puts 'Options for CONFIG or ALL:'
+ @config.each do |item|
+ out.printf fmt, item.help_opt, item.description, item.help_default
+ end
+ out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
+ out.puts
+ out.puts 'Options for INSTALL:'
+ out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
+ out.printf fmt, '--prefix=path', 'install path prefix', ''
+ out.puts
+ end
+
+ #
+ # Task Handlers
+ #
+
+ def exec_config
+ @installer.exec_config
+ @config.save # must be final
+ end
+
+ def exec_setup
+ @installer.exec_setup
+ end
+
+ def exec_install
+ @installer.exec_install
+ end
+
+ def exec_test
+ @installer.exec_test
+ end
+
+ def exec_show
+ @config.each do |i|
+ printf "%-20s %s\n", i.name, i.value if i.value?
+ end
+ end
+
+ def exec_clean
+ @installer.exec_clean
+ end
+
+ def exec_distclean
+ @installer.exec_distclean
+ end
+
+end # class ToplevelInstaller
+
+
+class ToplevelInstallerMulti < ToplevelInstaller
+
+ include FileOperations
+
+ def initialize(ardir_root, config)
+ super
+ @packages = directories_of("#{@ardir}/packages")
+ raise 'no package exists' if @packages.empty?
+ @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
+ end
+
+ def run_metaconfigs
+ @config.load_script "#{@ardir}/metaconfig", self
+ @packages.each do |name|
+ @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
+ end
+ end
+
+ attr_reader :packages
+
+ def packages=(list)
+ raise 'package list is empty' if list.empty?
+ list.each do |name|
+ raise "directory packages/#{name} does not exist"\
+ unless File.dir?("#{@ardir}/packages/#{name}")
+ end
+ @packages = list
+ end
+
+ def init_installers
+ @installers = {}
+ @packages.each do |pack|
+ @installers[pack] = Installer.new(@config,
+ "#{@ardir}/packages/#{pack}",
+ "packages/#{pack}")
+ end
+ with = extract_selection(config('with'))
+ without = extract_selection(config('without'))
+ @selected = @installers.keys.select {|name|
+ (with.empty? or with.include?(name)) \
+ and not without.include?(name)
+ }
+ end
+
+ def extract_selection(list)
+ a = list.split(/,/)
+ a.each do |name|
+ setup_rb_error "no such package: #{name}" unless @installers.key?(name)
+ end
+ a
+ end
+
+ def print_usage(f)
+ super
+ f.puts 'Inluded packages:'
+ f.puts ' ' + @packages.sort.join(' ')
+ f.puts
+ end
+
+ #
+ # Task Handlers
+ #
+
+ def exec_config
+ run_hook 'pre-config'
+ each_selected_installers {|inst| inst.exec_config }
+ run_hook 'post-config'
+ @config.save # must be final
+ end
+
+ def exec_setup
+ run_hook 'pre-setup'
+ each_selected_installers {|inst| inst.exec_setup }
+ run_hook 'post-setup'
+ end
+
+ def exec_install
+ run_hook 'pre-install'
+ each_selected_installers {|inst| inst.exec_install }
+ run_hook 'post-install'
+ end
+
+ def exec_test
+ run_hook 'pre-test'
+ each_selected_installers {|inst| inst.exec_test }
+ run_hook 'post-test'
+ end
+
+ def exec_clean
+ rm_f @config.savefile
+ run_hook 'pre-clean'
+ each_selected_installers {|inst| inst.exec_clean }
+ run_hook 'post-clean'
+ end
+
+ def exec_distclean
+ rm_f @config.savefile
+ run_hook 'pre-distclean'
+ each_selected_installers {|inst| inst.exec_distclean }
+ run_hook 'post-distclean'
+ end
+
+ #
+ # lib
+ #
+
+ def each_selected_installers
+ Dir.mkdir 'packages' unless File.dir?('packages')
+ @selected.each do |pack|
+ $stderr.puts "Processing the package `#{pack}' ..." if verbose?
+ Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
+ Dir.chdir "packages/#{pack}"
+ yield @installers[pack]
+ Dir.chdir '../..'
+ end
+ end
+
+ def run_hook(id)
+ @root_installer.run_hook id
+ end
+
+ # module FileOperations requires this
+ def verbose?
+ @config.verbose?
+ end
+
+ # module FileOperations requires this
+ def no_harm?
+ @config.no_harm?
+ end
+
+end # class ToplevelInstallerMulti
+
+
+class Installer
+
+ FILETYPES = %w( bin lib ext data conf man )
+
+ include FileOperations
+ include HookScriptAPI
+
+ def initialize(config, srcroot, objroot)
+ @config = config
+ @srcdir = File.expand_path(srcroot)
+ @objdir = File.expand_path(objroot)
+ @currdir = '.'
+ end
+
+ def inspect
+ "#<#{self.class} #{File.basename(@srcdir)}>"
+ end
+
+ def noop(rel)
+ end
+
+ #
+ # Hook Script API base methods
+ #
+
+ def srcdir_root
+ @srcdir
+ end
+
+ def objdir_root
+ @objdir
+ end
+
+ def relpath
+ @currdir
+ end
+
+ #
+ # Config Access
+ #
+
+ # module FileOperations requires this
+ def verbose?
+ @config.verbose?
+ end
+
+ # module FileOperations requires this
+ def no_harm?
+ @config.no_harm?
+ end
+
+ def verbose_off
+ begin
+ save, @config.verbose = @config.verbose?, false
+ yield
+ ensure
+ @config.verbose = save
+ end
+ end
+
+ #
+ # TASK config
+ #
+
+ def exec_config
+ exec_task_traverse 'config'
+ end
+
+ alias config_dir_bin noop
+ alias config_dir_lib noop
+
+ def config_dir_ext(rel)
+ extconf if extdir?(curr_srcdir())
+ end
+
+ alias config_dir_data noop
+ alias config_dir_conf noop
+ alias config_dir_man noop
+
+ def extconf
+ ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
+ end
+
+ #
+ # TASK setup
+ #
+
+ def exec_setup
+ exec_task_traverse 'setup'
+ end
+
+ def setup_dir_bin(rel)
+ files_of(curr_srcdir()).each do |fname|
+ update_shebang_line "#{curr_srcdir()}/#{fname}"
+ end
+ end
+
+ alias setup_dir_lib noop
+
+ def setup_dir_ext(rel)
+ make if extdir?(curr_srcdir())
+ end
+
+ alias setup_dir_data noop
+ alias setup_dir_conf noop
+ alias setup_dir_man noop
+
+ def update_shebang_line(path)
+ return if no_harm?
+ return if config('shebang') == 'never'
+ old = Shebang.load(path)
+ if old
+ $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1
+ new = new_shebang(old)
+ return if new.to_s == old.to_s
+ else
+ return unless config('shebang') == 'all'
+ new = Shebang.new(config('rubypath'))
+ end
+ $stderr.puts "updating shebang: #{File.basename(path)}" if verbose?
+ open_atomic_writer(path) {|output|
+ File.open(path, 'rb') {|f|
+ f.gets if old # discard
+ output.puts new.to_s
+ output.print f.read
+ }
+ }
+ end
+
+ def new_shebang(old)
+ if /\Aruby/ =~ File.basename(old.cmd)
+ Shebang.new(config('rubypath'), old.args)
+ elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
+ Shebang.new(config('rubypath'), old.args[1..-1])
+ else
+ return old unless config('shebang') == 'all'
+ Shebang.new(config('rubypath'))
+ end
+ end
+
+ def open_atomic_writer(path, &block)
+ tmpfile = File.basename(path) + '.tmp'
+ begin
+ File.open(tmpfile, 'wb', &block)
+ File.rename tmpfile, File.basename(path)
+ ensure
+ File.unlink tmpfile if File.exist?(tmpfile)
+ end
+ end
+
+ class Shebang
+ def Shebang.load(path)
+ line = nil
+ File.open(path) {|f|
+ line = f.gets
+ }
+ return nil unless /\A#!/ =~ line
+ parse(line)
+ end
+
+ def Shebang.parse(line)
+ cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
+ new(cmd, args)
+ end
+
+ def initialize(cmd, args = [])
+ @cmd = cmd
+ @args = args
+ end
+
+ attr_reader :cmd
+ attr_reader :args
+
+ def to_s
+ "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
+ end
+ end
+
+ #
+ # TASK install
+ #
+
+ def exec_install
+ rm_f 'InstalledFiles'
+ exec_task_traverse 'install'
+ end
+
+ def install_dir_bin(rel)
+ install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
+ end
+
+ def install_dir_lib(rel)
+ install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644
+ end
+
+ def install_dir_ext(rel)
+ return unless extdir?(curr_srcdir())
+ install_files rubyextentions('.'),
+ "#{config('sodir')}/#{File.dirname(rel)}",
+ 0555
+ end
+
+ def install_dir_data(rel)
+ install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
+ end
+
+ def install_dir_conf(rel)
+ # FIXME: should not remove current config files
+ # (rename previous file to .old/.org)
+ install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
+ end
+
+ def install_dir_man(rel)
+ install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
+ end
+
+ def install_files(list, dest, mode)
+ mkdir_p dest, @config.install_prefix
+ list.each do |fname|
+ install fname, dest, mode, @config.install_prefix
+ end
+ end
+
+ def libfiles
+ glob_reject(%w(*.y *.output), targetfiles())
+ end
+
+ def rubyextentions(dir)
+ ents = glob_select("*.#{@config.dllext}", targetfiles())
+ if ents.empty?
+ setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
+ end
+ ents
+ end
+
+ def targetfiles
+ mapdir(existfiles() - hookfiles())
+ end
+
+ def mapdir(ents)
+ ents.map {|ent|
+ if File.exist?(ent)
+ then ent # objdir
+ else "#{curr_srcdir()}/#{ent}" # srcdir
+ end
+ }
+ end
+
+ # picked up many entries from cvs-1.11.1/src/ignore.c
+ JUNK_FILES = %w(
+ core RCSLOG tags TAGS .make.state
+ .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
+ *~ *.old *.bak *.BAK *.orig *.rej _$* *$
+
+ *.org *.in .*
+ )
+
+ def existfiles
+ glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
+ end
+
+ def hookfiles
+ %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
+ %w( config setup install clean ).map {|t| sprintf(fmt, t) }
+ }.flatten
+ end
+
+ def glob_select(pat, ents)
+ re = globs2re([pat])
+ ents.select {|ent| re =~ ent }
+ end
+
+ def glob_reject(pats, ents)
+ re = globs2re(pats)
+ ents.reject {|ent| re =~ ent }
+ end
+
+ GLOB2REGEX = {
+ '.' => '\.',
+ '$' => '\$',
+ '#' => '\#',
+ '*' => '.*'
+ }
+
+ def globs2re(pats)
+ /\A(?:#{
+ pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
+ })\z/
+ end
+
+ #
+ # TASK test
+ #
+
+ TESTDIR = 'test'
+
+ def exec_test
+ unless File.directory?('test')
+ $stderr.puts 'no test in this package' if verbose?
+ return
+ end
+ $stderr.puts 'Running tests...' if verbose?
+ begin
+ require 'test/unit'
+ rescue LoadError
+ setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.'
+ end
+ runner = Test::Unit::AutoRunner.new(true)
+ runner.to_run << TESTDIR
+ runner.run
+ end
+
+ #
+ # TASK clean
+ #
+
+ def exec_clean
+ exec_task_traverse 'clean'
+ rm_f @config.savefile
+ rm_f 'InstalledFiles'
+ end
+
+ alias clean_dir_bin noop
+ alias clean_dir_lib noop
+ alias clean_dir_data noop
+ alias clean_dir_conf noop
+ alias clean_dir_man noop
+
+ def clean_dir_ext(rel)
+ return unless extdir?(curr_srcdir())
+ make 'clean' if File.file?('Makefile')
+ end
+
+ #
+ # TASK distclean
+ #
+
+ def exec_distclean
+ exec_task_traverse 'distclean'
+ rm_f @config.savefile
+ rm_f 'InstalledFiles'
+ end
+
+ alias distclean_dir_bin noop
+ alias distclean_dir_lib noop
+
+ def distclean_dir_ext(rel)
+ return unless extdir?(curr_srcdir())
+ make 'distclean' if File.file?('Makefile')
+ end
+
+ alias distclean_dir_data noop
+ alias distclean_dir_conf noop
+ alias distclean_dir_man noop
+
+ #
+ # Traversing
+ #
+
+ def exec_task_traverse(task)
+ run_hook "pre-#{task}"
+ FILETYPES.each do |type|
+ if type == 'ext' and config('without-ext') == 'yes'
+ $stderr.puts 'skipping ext/* by user option' if verbose?
+ next
+ end
+ traverse task, type, "#{task}_dir_#{type}"
+ end
+ run_hook "post-#{task}"
+ end
+
+ def traverse(task, rel, mid)
+ dive_into(rel) {
+ run_hook "pre-#{task}"
+ __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
+ directories_of(curr_srcdir()).each do |d|
+ traverse task, "#{rel}/#{d}", mid
+ end
+ run_hook "post-#{task}"
+ }
+ end
+
+ def dive_into(rel)
+ return unless File.dir?("#{@srcdir}/#{rel}")
+
+ dir = File.basename(rel)
+ Dir.mkdir dir unless File.dir?(dir)
+ prevdir = Dir.pwd
+ Dir.chdir dir
+ $stderr.puts '---> ' + rel if verbose?
+ @currdir = rel
+ yield
+ Dir.chdir prevdir
+ $stderr.puts '<--- ' + rel if verbose?
+ @currdir = File.dirname(rel)
+ end
+
+ def run_hook(id)
+ path = [ "#{curr_srcdir()}/#{id}",
+ "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
+ return unless path
+ begin
+ instance_eval File.read(path), path, 1
+ rescue
+ raise if $DEBUG
+ setup_rb_error "hook #{path} failed:\n" + $!.message
+ end
+ end
+
+end # class Installer
+
+
+class SetupError < StandardError; end
+
+def setup_rb_error(msg)
+ raise SetupError, msg
+end
+
+if $0 == __FILE__
+ begin
+ ToplevelInstaller.invoke
+ rescue SetupError
+ raise if $DEBUG
+ $stderr.puts $!.message
+ $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
+ exit 1
+ end
+end
22 History.txt
@@ -0,0 +1,22 @@
+== 0.0.1 2008-03-07
+
+* 1 major enhancement:
+ * Initial super-alpha release
+ * Not particularly good at nesting
+* 2 minor enhancement:
+ * Changed #with to #inside avoid confusion with Object#with
+* 3 minor enhancement:
+ * refactored Wrapped into Wrap with runtime options
+ * added ArrayWrapper and Tee classes
+* 4 tiny enhancement
+ * fixed manifest.txt
+ * TODO: build the manifest algorithmically!
+* 5 tiny enhancement
+ * #fork
+* 6 tiny enhancement
+ * work in progress on Advisor
+* 7 minor enhancement
+ * letn added experimentally
+* 8 minor enhancement
+ * letn changed to lets and now uses sexp rewriting
+
20 License.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2008 Reginald Braithwaite
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 Manifest.txt
@@ -0,0 +1,41 @@
+History.txt
+License.txt
+Manifest.txt
+README.txt
+Rakefile
+config/hoe.rb
+config/requirements.rb
+lib/ick.rb
+lib/ick/advisor.rb
+lib/ick/base.rb
+lib/ick/bizarro.rb
+lib/ick/guard.rb
+lib/ick/sugar.rb
+lib/ick/syntax/let.rb
+lib/ick/syntax/lets.rb
+lib/ick/syntax/rewritten.rb
+lib/ick/tee.rb
+lib/ick/version.rb
+lib/ick/wrap.rb
+log/debug.log
+script/destroy
+script/generate
+script/txt2html
+setup.rb
+tasks/deployment.rake
+tasks/environment.rake
+tasks/website.rake
+test/test_180_seconds.rb
+test/test_advisor.rb
+test/test_helper.rb
+test/test_ick.rb
+test/test_lets.rb
+website/180seconds.html
+website/180seconds.txt
+website/index.html
+website/index.txt
+website/inside.html
+website/inside.txt
+website/javascripts/rounded_corners_lite.inc.js
+website/stylesheets/screen.css
+website/template.rhtml
166 README.textile
@@ -0,0 +1,166 @@
+h1. Invocation Construction Kit
+
+h1. &#x2192; 'ick'
+
+h2. What
+
+The Generalized Greenspun Rule: _Any sufficiently complicated platform contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of a functional programming language._
+
+While Ruby provides an ad hoc, informally-specified, bug-ridden, slow implementation of half of higher-order functional programming, it lacks an ad hoc, informally-specified, bug-ridden, slow implementation of half of Monads.
+
+Thus, the *Invocation Construction Kit*, or "Ick!" Ick provides the tools needed to easily build your own execution abstractions like the "Maybe" monad or the four canonical block evaluators, as well as providing some sugar so you can write things like:
+
+<pre syntax="ruby">
+please(sir) { may.i.have.some.more }
+</pre>
+
+h2. Getting Started
+
+<pre>sudo gem install ick</pre>
+
+h2. Block Structured Ruby
+
+Although Ruby borrows many of its features from Lisp and its syntax from Algol, it does not have block-local variables. In other words, if you declare a variable anywhere inside of a method, that variable is visible everywhere in that method. This is a problem, because it encourages writing methods where the instance variables create lot of dependencies between different expressions. Those methods can be hard to understand and refactor.
+
+Ick solves this problem by providing a block structure method: #let. #let takes an expression and binds it to a variable inside of a block. For example, if you want someone's phone number only if they are a friend:
+
+<pre syntax="ruby">
+let(Person.find(:first, ...)) { |person| person.phone_number if person.friend? }
+</pre>
+
+This code makes it clear that you only need the @person@ variable inside the block. If you want to refactor this code, you know that the entire expression can move without breaking another piece of code. Ick provides three other block structure methods (#returning, #my, and #inside) that are detailed on the "Inside Ick":inside.html page.
+
+h2. Guarded Evaluation
+
+The example above is a common one. Sometimes we want to evaluate a chain of method calls without throwing a _NoMethodError_ if one of the recipients is nil. Sometimes we want to send something a message if and only if it handles the method. There are lots of ad-hoc solutions, including "Object#andand":http://andand.rubyforge.org. What if you don't want to install lots of different gems, one for each use?
+
+Ick solves this problem by providing a structure for rolling your own guarded evaluation. You can check for nil, #respond_to?, custom permissions, whatever you like. It looks like this:
+
+<pre syntax="ruby">
+class Try < Ick::Guard
+ guard_with { |value, sym| value.respond_to?(sym) == true }
+ evaluates_in_calling_environment and returns_result
+ belongs_to Object
+end
+
+try(...) { |sir| sir.may.i.have.some.more }
+</pre>
+
+(Try is built into Ick and was inspired by Chris Wanstrath's "try()":http://ozmm.org/posts/try.html and Chalain's "Turtles":http://chalain.livejournal.com/66798.html)
+
+Maybe does exactly the same thing with checking nil rather than whether an object responds to a message:
+
+<pre syntax="ruby">
+maybe(...) { |person| person.manager.authority_level.permissions }
+</pre>
+
+Both #try and #maybe are _contagious_: everything in the chain inside the block is guarded.
+
+h2. More sugar!
+
+If you just want to call a method by name without parameters, the existing blocks work well with Symbol#to_proc:
+
+<pre syntax="ruby">
+maybe(Person.find(:first, ...), &:manager)
+</pre>
+
+But you can also use these methods the way Object#andand works:
+
+<pre syntax="ruby">
+Person.find(:first, ...).
+ maybe.time_cards.
+ maybe.map(&:hours_worked).
+ maybe.inject(0, &:+)
+</pre>
+
+When you do that, you have to keep calling the method in order to chain them all together, so you might prefer:
+
+<pre syntax="ruby">
+maybe(Person.find(:first, ...)) { |p|
+ p.time_cards.map(&:hours_worked).inject(0, &:+)
+}
+</pre>
+
+The Object#andand-style syntax is most useful when you're just using it for a single method invocation, such as:
+
+<pre syntax="ruby">
+Person.find(:first, ...).maybe.salary = 42,000
+</pre>
+
+h3. New in Version 0.3!
+
+Ick version 0.3 includes an experiemental form of let, @lets@, that allows you to bind multiple variables:
+
+<pre syntax="ruby">
+lets(
+ :person => Person.find(:first, ...),
+ :place => City.select { ... },
+ :thing => %w(ever loving blue eyed)) {
+ "#{person.name} lives in #{place} where he is known as the '#{thing} thing.'"
+}
+</pre>
+
+h3. (But I heard that Ick is destroying Ruby&#8253;)
+
+Have no fear of that. Ick will not modify any classes without permission. Out of the box, you cannot call any of Ick's built in methods the way you see them in these examples. Instead of @please(sir) {...}@ you actually have to call @Ick::Please.instance.invoke(sir) {...}@. If you want to install one or more of the built-in methods in to the Object class, you call #belongs_to. For example, to install the Maybe and Let methods but no others:
+
+<pre syntax="ruby">
+Ick::Maybe.belongs_to Object
+Ick::Let.belongs_to Object
+</pre>
+
+You could also install some or all of the methods into a single class where you think you'll be using them a lot but nowhere else:
+
+<pre syntax="ruby">
+class MyAwesomeImplementationOfAsteroids
+ [Ick::Let, Ick::Returning, Ick::My, Ick::Inside].each do |clazz|
+ clazz.belongs_to self
+ end
+end
+</pre>
+
+If you simply want everything you see here working exactly as it's shown, simply call @Ick.sugarize@ once and all of the built-in methods will be installed into Object for you. You can put that in your environment.rb file if you're using Rails.
+
+The point is, @try(program) { responsibly }@. You choose which classes to open and which methods to add. "All I’m saying is this: before re-opening a class, did you go through the rest of your toolbox first?":http://avdi.org/devblog/2008/02/25/full-disclosure/
+
+h2. Is Ick for me?
+
+Ick does provide a number of very convenient methods for abstracting evaluation. If you adopt them for your project, your code will be more readable, more succinct, and easier to refactor. That being said, it will not make your teeth whiter or help you sleep if you have a newborn.
+
+_Every programming problem can be solved with another layer of abstraction, except the problem of too many layers of abstraction_
+
+The important caveat about Ick is that its implementation adds abstraction. If all you want are two or three specific methods, writing them as simply and as directly as possible makes for a very simple implementation. Ick uses classes and templates instead of simple methods so that when you are ready to start writing your own abstractions, you can easily use the pieces that Ick has built-in. If Ick was written as a collection of cool methods, you would not be able to extend it without copying and pasting.
+
+Ick raises how you handle things to the level of first-class objects in Ruby, so you can mix and match and separate concerns as you see fit. Logging, permissions, error handling... These are some of the places you can take Ick. Have fun.
+
+h2. Where can I read about what's going on inside Ick?
+
+"Inside Ick":inside.html
+
+h2. That's cool, but&hellip;
+
+No problem, I get that Ick isn't exactly what you need. Why not have a look at "andand":http://andand.rubyforge.org? The andand gem gives you a very specialized version of Object#maybe and an enhanced Object#tap: it does a lot less but tries to do it very, very well. Have a look and let me know what you think.
+
+h2. Administrivia
+
+h3. Home Sweet Home
+
+"ick.rubyforge.org":http://ick.rubyforge.org
+
+h3. How to submit patches
+
+Read the "8 steps for fixing other people's code":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/.
+
+The trunk repository is @svn://rubyforge.org/var/svn/ick/trunk@ for anonymous access.
+
+h3. License
+
+This code is free to use under the terms of the "MIT license":http://en.wikipedia.org/wiki/MIT_License.
+
+h3. Shout Out
+
+"Mobile Commons":http://mcommons.com/. Still Huge After All These Years.
+
+h3. Contact
+
+Comments are welcome. Send an email to "Reginald Braithwaite":mailto:raganwald+rubyforge@gmail.com. And you can always visit "weblog.raganwald.com":http://weblog.raganwald.com/ to see what's cooking.
4 Rakefile
@@ -0,0 +1,4 @@
+require 'config/requirements'
+require 'config/hoe' # setup Hoe + all gem configuration
+
+Dir['tasks/**/*.rake'].each { |rake| load rake }
2 config/.svn/README.txt
@@ -0,0 +1,2 @@
+This is a Subversion working copy administrative directory.
+Visit http://subversion.tigris.org/ for more information.
0 config/.svn/empty-file
No changes.
29 config/.svn/entries
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wc-entries
+ xmlns="svn:">
+<entry
+ committed-rev="1"
+ name=""
+ committed-date="2008-03-10T04:57:06.697106Z"
+ url="svn+ssh://raganwald@rubyforge.org/var/svn/ick/config"
+ last-author="raganwald"
+ kind="dir"
+ repos="svn+ssh://raganwald@rubyforge.org/var/svn/ick"
+ revision="1"/>
+<entry
+ committed-rev="1"
+ name="requirements.rb"
+ text-time="2008-03-07T21:30:30.000000Z"
+ committed-date="2008-03-10T04:57:06.697106Z"
+ checksum="7ea63f2817dffa772ea3f3d9d3675725"
+ last-author="raganwald"
+ kind="file"/>
+<entry
+ committed-rev="1"
+ name="hoe.rb"
+ text-time="2008-03-07T21:31:53.000000Z"
+ committed-date="2008-03-10T04:57:06.697106Z"
+ checksum="184730ede00b6a6d53b335517feb161d"
+ last-author="raganwald"
+ kind="file"/>
+</wc-entries>
1 config/.svn/format
@@ -0,0 +1 @@
+4
70 config/.svn/text-base/hoe.rb.svn-base
@@ -0,0 +1,70 @@
+require 'ick/version'
+
+AUTHOR = 'Reginald Braithwaite' # can also be an array of Authors
+EMAIL = "raganwald+rubyforge@gmail.com"
+DESCRIPTION = "Invocation Construction Kit"
+GEM_NAME = 'ick' # what ppl will type to install your gem
+RUBYFORGE_PROJECT = 'ick' # The unix name for your project
+HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
+DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
+
+@config_file = "~/.rubyforge/user-config.yml"
+@config = nil
+RUBYFORGE_USERNAME = "unknown"
+def rubyforge_username
+ unless @config
+ begin
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
+ rescue
+ puts <<-EOS
+ERROR: No rubyforge config file found: #{@config_file}
+Run 'rubyforge setup' to prepare your env for access to Rubyforge
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
+ EOS
+ exit
+ end
+ end
+ RUBYFORGE_USERNAME.replace @config["username"]
+end
+
+
+REV = nil
+# UNCOMMENT IF REQUIRED:
+# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
+VERS = Ick::VERSION::STRING + (REV ? ".#{REV}" : "")
+RDOC_OPTS = ['--quiet', '--title', 'ick documentation',
+ "--opname", "index.html",
+ "--line-numbers",
+ "--main", "README",
+ "--inline-source"]
+
+class Hoe
+ def extra_deps
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
+ @extra_deps
+ end
+end
+
+# Generate all the Rake tasks
+# Run 'rake -T' to see list of generated tasks (from gem root directory)
+hoe = Hoe.new(GEM_NAME, VERS) do |p|
+ p.developer(AUTHOR, EMAIL)
+ p.description = DESCRIPTION
+ p.summary = DESCRIPTION
+ p.url = HOMEPATH
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
+ p.test_globs = ["test/**/test_*.rb"]
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
+
+ # == Optional
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
+
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
+
+end
+
+CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
+PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
+hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
+hoe.rsync_args = '-av --delete --ignore-errors'
17 config/.svn/text-base/requirements.rb.svn-base
@@ -0,0 +1,17 @@
+require 'fileutils'
+include FileUtils
+
+require 'rubygems'
+%w[rake hoe newgem rubigen].each do |req_gem|
+ begin
+ require req_gem
+ rescue LoadError
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
+ puts "Installation: gem install #{req_gem} -y"
+ exit
+ end
+end
+
+$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
+