nuggets 0.9.9 → 1.0.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 (222) hide show
  1. checksums.yaml +4 -4
  2. data/COPYING +663 -0
  3. data/ChangeLog +7 -0
  4. data/README +74 -0
  5. data/Rakefile +50 -0
  6. data/lib/nuggets.rb +73 -0
  7. data/lib/nuggets/all.rb +35 -0
  8. data/lib/nuggets/all_mixins.rb +33 -0
  9. data/lib/nuggets/ansicolor2css.rb +124 -0
  10. data/lib/nuggets/argv/option.rb +3 -0
  11. data/lib/nuggets/argv/option_mixin.rb +84 -0
  12. data/lib/nuggets/array/boost.rb +5 -0
  13. data/lib/nuggets/array/boost_mixin.rb +77 -0
  14. data/lib/nuggets/array/combination.rb +62 -0
  15. data/lib/nuggets/array/correlation.rb +5 -0
  16. data/lib/nuggets/array/correlation_mixin.rb +63 -0
  17. data/lib/nuggets/array/flatten_once.rb +56 -0
  18. data/lib/nuggets/array/flush.rb +5 -0
  19. data/lib/nuggets/array/flush_mixin.rb +46 -0
  20. data/lib/nuggets/array/format.rb +65 -0
  21. data/lib/nuggets/array/hashify.rb +5 -0
  22. data/lib/nuggets/array/hashify_mixin.rb +47 -0
  23. data/lib/nuggets/array/histogram.rb +5 -0
  24. data/lib/nuggets/array/histogram_mixin.rb +169 -0
  25. data/lib/nuggets/array/in_order.rb +50 -0
  26. data/lib/nuggets/array/limit.rb +5 -0
  27. data/lib/nuggets/array/limit_mixin.rb +56 -0
  28. data/lib/nuggets/array/mean.rb +5 -0
  29. data/lib/nuggets/array/mean_mixin.rb +202 -0
  30. data/lib/nuggets/array/median.rb +5 -0
  31. data/lib/nuggets/array/median_mixin.rb +73 -0
  32. data/lib/nuggets/array/mode.rb +5 -0
  33. data/lib/nuggets/array/mode_mixin.rb +69 -0
  34. data/lib/nuggets/array/monotone.rb +83 -0
  35. data/lib/nuggets/array/only.rb +41 -0
  36. data/lib/nuggets/array/rand.rb +44 -0
  37. data/lib/nuggets/array/regression.rb +5 -0
  38. data/lib/nuggets/array/regression_mixin.rb +149 -0
  39. data/lib/nuggets/array/runiq.rb +5 -0
  40. data/lib/nuggets/array/runiq_mixin.rb +52 -0
  41. data/lib/nuggets/array/shuffle.rb +132 -0
  42. data/lib/nuggets/array/standard_deviation.rb +5 -0
  43. data/lib/nuggets/array/standard_deviation_mixin.rb +50 -0
  44. data/lib/nuggets/array/to_hash.rb +64 -0
  45. data/lib/nuggets/array/variance.rb +5 -0
  46. data/lib/nuggets/array/variance_mixin.rb +81 -0
  47. data/lib/nuggets/content_type.rb +97 -0
  48. data/lib/nuggets/dotted_decimal.rb +59 -0
  49. data/lib/nuggets/enumerable/agrep.rb +79 -0
  50. data/lib/nuggets/enumerable/all_any_extended.rb +66 -0
  51. data/lib/nuggets/enumerable/minmax.rb +102 -0
  52. data/lib/nuggets/env/set.rb +3 -0
  53. data/lib/nuggets/env/set_mixin.rb +67 -0
  54. data/lib/nuggets/env/user_encoding.rb +3 -0
  55. data/lib/nuggets/env/user_encoding_mixin.rb +54 -0
  56. data/lib/nuggets/env/user_home.rb +3 -0
  57. data/lib/nuggets/env/user_home_mixin.rb +56 -0
  58. data/lib/nuggets/file/ext.rb +5 -0
  59. data/lib/nuggets/file/ext_mixin.rb +87 -0
  60. data/lib/nuggets/file/replace.rb +5 -0
  61. data/lib/nuggets/file/replace_mixin.rb +55 -0
  62. data/lib/nuggets/file/sub.rb +5 -0
  63. data/lib/nuggets/file/sub_mixin.rb +95 -0
  64. data/lib/nuggets/file/which.rb +5 -0
  65. data/lib/nuggets/file/which_mixin.rb +72 -0
  66. data/lib/nuggets/hash/at.rb +68 -0
  67. data/lib/nuggets/hash/deep_fetch.rb +5 -0
  68. data/lib/nuggets/hash/deep_fetch_mixin.rb +74 -0
  69. data/lib/nuggets/hash/deep_merge.rb +5 -0
  70. data/lib/nuggets/hash/deep_merge_mixin.rb +53 -0
  71. data/lib/nuggets/hash/idmap.rb +5 -0
  72. data/lib/nuggets/hash/idmap_mixin.rb +41 -0
  73. data/lib/nuggets/hash/in_order.rb +43 -0
  74. data/lib/nuggets/hash/insert.rb +53 -0
  75. data/lib/nuggets/hash/nest.rb +5 -0
  76. data/lib/nuggets/hash/nest_mixin.rb +78 -0
  77. data/lib/nuggets/hash/only.rb +52 -0
  78. data/lib/nuggets/hash/seen.rb +5 -0
  79. data/lib/nuggets/hash/seen_mixin.rb +58 -0
  80. data/lib/nuggets/hash/unroll.rb +5 -0
  81. data/lib/nuggets/hash/unroll_mixin.rb +88 -0
  82. data/lib/nuggets/hash/zip.rb +5 -0
  83. data/lib/nuggets/hash/zip_mixin.rb +159 -0
  84. data/lib/nuggets/i18n.rb +155 -0
  85. data/lib/nuggets/integer/factorial.rb +56 -0
  86. data/lib/nuggets/integer/length.rb +5 -0
  87. data/lib/nuggets/integer/length_mixin.rb +49 -0
  88. data/lib/nuggets/integer/map.rb +5 -0
  89. data/lib/nuggets/integer/map_mixin.rb +42 -0
  90. data/lib/nuggets/integer/to_binary_s.rb +38 -0
  91. data/lib/nuggets/io/agrep.rb +43 -0
  92. data/lib/nuggets/io/interact.rb +5 -0
  93. data/lib/nuggets/io/interact_mixin.rb +159 -0
  94. data/lib/nuggets/io/modes.rb +121 -0
  95. data/lib/nuggets/io/null.rb +5 -0
  96. data/lib/nuggets/io/null_mixin.rb +40 -0
  97. data/lib/nuggets/io/redirect.rb +5 -0
  98. data/lib/nuggets/io/redirect_mixin.rb +50 -0
  99. data/lib/nuggets/lazy_attr.rb +44 -0
  100. data/lib/nuggets/log_parser.rb +70 -0
  101. data/lib/nuggets/log_parser/apache.rb +101 -0
  102. data/lib/nuggets/log_parser/rails.rb +219 -0
  103. data/lib/nuggets/net/success.rb +59 -0
  104. data/lib/nuggets/numeric/between.rb +2 -0
  105. data/lib/nuggets/numeric/duration.rb +100 -0
  106. data/lib/nuggets/numeric/limit.rb +62 -0
  107. data/lib/nuggets/numeric/signum.rb +52 -0
  108. data/lib/nuggets/numeric/to_multiple.rb +61 -0
  109. data/lib/nuggets/object/blank.rb +20 -0
  110. data/lib/nuggets/object/blank_mixin.rb +99 -0
  111. data/lib/nuggets/object/boolean.rb +5 -0
  112. data/lib/nuggets/object/boolean_mixin.rb +61 -0
  113. data/lib/nuggets/object/eigenclass.rb +2 -0
  114. data/lib/nuggets/object/ghost_class.rb +2 -0
  115. data/lib/nuggets/object/metaclass.rb +2 -0
  116. data/lib/nuggets/object/msend.rb +5 -0
  117. data/lib/nuggets/object/msend_mixin.rb +43 -0
  118. data/lib/nuggets/object/silence.rb +5 -0
  119. data/lib/nuggets/object/silence_mixin.rb +44 -0
  120. data/lib/nuggets/object/singleton_class.rb +5 -0
  121. data/lib/nuggets/object/singleton_class_mixin.rb +95 -0
  122. data/lib/nuggets/object/uniclass.rb +2 -0
  123. data/lib/nuggets/object/virtual_class.rb +2 -0
  124. data/lib/nuggets/pluggable.rb +91 -0
  125. data/lib/nuggets/proc/bind.rb +5 -0
  126. data/lib/nuggets/proc/bind_mixin.rb +51 -0
  127. data/lib/nuggets/range/quantile.rb +5 -0
  128. data/lib/nuggets/range/quantile_mixin.rb +42 -0
  129. data/lib/nuggets/ruby.rb +235 -0
  130. data/lib/nuggets/statistics.rb +12 -0
  131. data/lib/nuggets/statistics_mixins.rb +12 -0
  132. data/lib/nuggets/string/camelscore.rb +5 -0
  133. data/lib/nuggets/string/camelscore_mixin.rb +116 -0
  134. data/lib/nuggets/string/capitalize_first.rb +46 -0
  135. data/lib/nuggets/string/case.rb +81 -0
  136. data/lib/nuggets/string/evaluate.rb +5 -0
  137. data/lib/nuggets/string/evaluate_mixin.rb +47 -0
  138. data/lib/nuggets/string/msub.rb +84 -0
  139. data/lib/nuggets/string/nsub.rb +65 -0
  140. data/lib/nuggets/string/sub_with_md.rb +111 -0
  141. data/lib/nuggets/string/wc.rb +5 -0
  142. data/lib/nuggets/string/wc_mixin.rb +95 -0
  143. data/lib/nuggets/string/word_wrap.rb +76 -0
  144. data/lib/nuggets/string/xor.rb +5 -0
  145. data/lib/nuggets/string/xor_mixin.rb +59 -0
  146. data/lib/nuggets/tempfile/open.rb +57 -0
  147. data/lib/nuggets/uri/content_type.rb +5 -0
  148. data/lib/nuggets/uri/content_type_mixin.rb +47 -0
  149. data/lib/nuggets/uri/exist.rb +5 -0
  150. data/lib/nuggets/uri/exist_mixin.rb +56 -0
  151. data/lib/nuggets/uri/redirect.rb +5 -0
  152. data/lib/nuggets/uri/redirect_mixin.rb +101 -0
  153. data/lib/nuggets/version.rb +27 -0
  154. data/spec/nuggets/array/boost_spec.rb +50 -0
  155. data/spec/nuggets/array/combination_spec.rb +25 -0
  156. data/spec/nuggets/array/correlation_spec.rb +81 -0
  157. data/spec/nuggets/array/flatten_once_spec.rb +16 -0
  158. data/spec/nuggets/array/flush_spec.rb +43 -0
  159. data/spec/nuggets/array/format_spec.rb +52 -0
  160. data/spec/nuggets/array/hashify_spec.rb +41 -0
  161. data/spec/nuggets/array/histogram_spec.rb +87 -0
  162. data/spec/nuggets/array/in_order_spec.rb +13 -0
  163. data/spec/nuggets/array/limit_spec.rb +62 -0
  164. data/spec/nuggets/array/mean_spec.rb +203 -0
  165. data/spec/nuggets/array/median_spec.rb +77 -0
  166. data/spec/nuggets/array/mode_spec.rb +57 -0
  167. data/spec/nuggets/array/monotone_spec.rb +30 -0
  168. data/spec/nuggets/array/only_spec.rb +26 -0
  169. data/spec/nuggets/array/regression_spec.rb +54 -0
  170. data/spec/nuggets/array/runiq_spec.rb +25 -0
  171. data/spec/nuggets/array/standard_deviation_spec.rb +33 -0
  172. data/spec/nuggets/array/to_hash_spec.rb +28 -0
  173. data/spec/nuggets/array/variance_spec.rb +106 -0
  174. data/spec/nuggets/dotted_decimal_spec.rb +27 -0
  175. data/spec/nuggets/enumerable/all_any_extended_spec.rb +31 -0
  176. data/spec/nuggets/enumerable/minmax_spec.rb +21 -0
  177. data/spec/nuggets/env/set_spec.rb +29 -0
  178. data/spec/nuggets/env/user_encoding_spec.rb +38 -0
  179. data/spec/nuggets/env/user_home_spec.rb +42 -0
  180. data/spec/nuggets/file/ext_spec.rb +38 -0
  181. data/spec/nuggets/file/replace_spec.rb +95 -0
  182. data/spec/nuggets/file/sub_spec.rb +149 -0
  183. data/spec/nuggets/file/which_spec.rb +22 -0
  184. data/spec/nuggets/hash/at_spec.rb +19 -0
  185. data/spec/nuggets/hash/deep_fetch_spec.rb +159 -0
  186. data/spec/nuggets/hash/deep_merge_spec.rb +78 -0
  187. data/spec/nuggets/hash/in_order_spec.rb +12 -0
  188. data/spec/nuggets/hash/insert_spec.rb +13 -0
  189. data/spec/nuggets/hash/nest_spec.rb +102 -0
  190. data/spec/nuggets/hash/only_spec.rb +29 -0
  191. data/spec/nuggets/hash/seen_spec.rb +36 -0
  192. data/spec/nuggets/hash/unroll_spec.rb +68 -0
  193. data/spec/nuggets/i18n_spec.rb +13 -0
  194. data/spec/nuggets/integer/factorial_spec.rb +10 -0
  195. data/spec/nuggets/integer/length_spec.rb +18 -0
  196. data/spec/nuggets/integer/map_spec.rb +19 -0
  197. data/spec/nuggets/integer/to_binary_s_spec.rb +19 -0
  198. data/spec/nuggets/numeric/duration_spec.rb +25 -0
  199. data/spec/nuggets/numeric/limit_spec.rb +16 -0
  200. data/spec/nuggets/numeric/signum_spec.rb +16 -0
  201. data/spec/nuggets/numeric/to_multiple_spec.rb +16 -0
  202. data/spec/nuggets/object/blank_spec.rb +34 -0
  203. data/spec/nuggets/object/boolean_spec.rb +23 -0
  204. data/spec/nuggets/object/msend_spec.rb +25 -0
  205. data/spec/nuggets/object/silence_spec.rb +36 -0
  206. data/spec/nuggets/object/singleton_class_spec.rb +51 -0
  207. data/spec/nuggets/proc/bind_spec.rb +28 -0
  208. data/spec/nuggets/range/quantile_spec.rb +33 -0
  209. data/spec/nuggets/string/camelscore_spec.rb +114 -0
  210. data/spec/nuggets/string/capitalize_first_spec.rb +13 -0
  211. data/spec/nuggets/string/case_spec.rb +31 -0
  212. data/spec/nuggets/string/evaluate_spec.rb +24 -0
  213. data/spec/nuggets/string/msub_spec.rb +20 -0
  214. data/spec/nuggets/string/nsub_spec.rb +13 -0
  215. data/spec/nuggets/string/sub_with_md_spec.rb +25 -0
  216. data/spec/nuggets/string/wc_spec.rb +73 -0
  217. data/spec/nuggets/string/word_wrap_spec.rb +81 -0
  218. data/spec/nuggets/string/xor_spec.rb +57 -0
  219. data/spec/nuggets/uri/content_type_spec.rb +42 -0
  220. data/spec/nuggets/uri/exist_spec.rb +49 -0
  221. data/spec/spec_helper.rb +36 -0
  222. metadata +309 -17
@@ -0,0 +1,5 @@
1
+ require 'nuggets/integer/length_mixin'
2
+
3
+ class Integer
4
+ include Nuggets::Integer::LengthMixin
5
+ end
@@ -0,0 +1,49 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # nuggets -- Extending Ruby #
5
+ # #
6
+ # Copyright (C) 2007-2011 Jens Wille #
7
+ # #
8
+ # Authors: #
9
+ # Jens Wille <jens.wille@gmail.com> #
10
+ # #
11
+ # nuggets is free software; you can redistribute it and/or modify it under #
12
+ # the terms of the GNU Affero General Public License as published by the Free #
13
+ # Software Foundation; either version 3 of the License, or (at your option) #
14
+ # any later version. #
15
+ # #
16
+ # nuggets is distributed in the hope that it will be useful, but WITHOUT ANY #
17
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
18
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for #
19
+ # more details. #
20
+ # #
21
+ # You should have received a copy of the GNU Affero General Public License #
22
+ # along with nuggets. If not, see <http://www.gnu.org/licenses/>. #
23
+ # #
24
+ ###############################################################################
25
+ #++
26
+
27
+ module Nuggets
28
+ class Integer
29
+ module LengthMixin
30
+
31
+ # call-seq:
32
+ # int.length => anInteger
33
+ #
34
+ # Returns the length of _int_.
35
+ def length
36
+ to_s.length
37
+ end
38
+
39
+ # call-seq:
40
+ # int.digit_count => anInteger
41
+ #
42
+ # Returns the digit count of _int_. [ruby-core:22383]
43
+ def digit_count
44
+ abs.length
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,5 @@
1
+ require 'nuggets/integer/map_mixin'
2
+
3
+ class Integer
4
+ include Nuggets::Integer::MapMixin
5
+ end
@@ -0,0 +1,42 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # nuggets -- Extending Ruby #
5
+ # #
6
+ # Copyright (C) 2007-2011 Jens Wille #
7
+ # #
8
+ # Authors: #
9
+ # Jens Wille <jens.wille@gmail.com> #
10
+ # #
11
+ # nuggets is free software; you can redistribute it and/or modify it under #
12
+ # the terms of the GNU Affero General Public License as published by the Free #
13
+ # Software Foundation; either version 3 of the License, or (at your option) #
14
+ # any later version. #
15
+ # #
16
+ # nuggets is distributed in the hope that it will be useful, but WITHOUT ANY #
17
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
18
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for #
19
+ # more details. #
20
+ # #
21
+ # You should have received a copy of the GNU Affero General Public License #
22
+ # along with nuggets. If not, see <http://www.gnu.org/licenses/>. #
23
+ # #
24
+ ###############################################################################
25
+ #++
26
+
27
+ module Nuggets
28
+ class Integer
29
+ module MapMixin
30
+
31
+ # call-seq:
32
+ # int.map_positive => anInteger
33
+ #
34
+ # Creates a bijection from *Z* to *N*, i.e., it maps _int_ to a positive
35
+ # integer.
36
+ def map_positive
37
+ 2 * abs + (self > 0 ? 0 : 1)
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # nuggets -- Extending Ruby #
5
+ # #
6
+ # Copyright (C) 2007-2011 Jens Wille #
7
+ # #
8
+ # Authors: #
9
+ # Jens Wille <jens.wille@gmail.com> #
10
+ # #
11
+ # nuggets is free software; you can redistribute it and/or modify it under #
12
+ # the terms of the GNU Affero General Public License as published by the Free #
13
+ # Software Foundation; either version 3 of the License, or (at your option) #
14
+ # any later version. #
15
+ # #
16
+ # nuggets is distributed in the hope that it will be useful, but WITHOUT ANY #
17
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
18
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for #
19
+ # more details. #
20
+ # #
21
+ # You should have received a copy of the GNU Affero General Public License #
22
+ # along with nuggets. If not, see <http://www.gnu.org/licenses/>. #
23
+ # #
24
+ ###############################################################################
25
+ #++
26
+
27
+ class Integer
28
+
29
+ # call-seq:
30
+ # int.to_binary_s => aString
31
+ # int.to_binary_s(length) => aString
32
+ #
33
+ # Returns _int_ as binary number string; optionally zero-padded to +length+.
34
+ def to_binary_s(length = nil)
35
+ "%0#{length}d" % to_s(2)
36
+ end
37
+
38
+ end
@@ -0,0 +1,43 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # nuggets -- Extending Ruby #
5
+ # #
6
+ # Copyright (C) 2007-2011 Jens Wille #
7
+ # #
8
+ # Authors: #
9
+ # Jens Wille <jens.wille@gmail.com> #
10
+ # #
11
+ # nuggets is free software; you can redistribute it and/or modify it under #
12
+ # the terms of the GNU Affero General Public License as published by the Free #
13
+ # Software Foundation; either version 3 of the License, or (at your option) #
14
+ # any later version. #
15
+ # #
16
+ # nuggets is distributed in the hope that it will be useful, but WITHOUT ANY #
17
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
18
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for #
19
+ # more details. #
20
+ # #
21
+ # You should have received a copy of the GNU Affero General Public License #
22
+ # along with nuggets. If not, see <http://www.gnu.org/licenses/>. #
23
+ # #
24
+ ###############################################################################
25
+ #++
26
+
27
+ require 'nuggets/enumerable/agrep'
28
+
29
+ class IO
30
+
31
+ # call-seq:
32
+ # IO.agrep(fd, pattern[, distance]) -> anArray
33
+ # IO.agrep(fd, pattern[, distance]) { |line| ... } -> io
34
+ #
35
+ def self.agrep(fd, pattern, distance = 0, &block)
36
+ open(fd) { |io| io.agrep(pattern, distance, &block) }
37
+ end
38
+
39
+ end
40
+
41
+ if $0 == __FILE__
42
+ puts ::File.agrep(__FILE__, /calls/, 2)
43
+ end
@@ -0,0 +1,5 @@
1
+ require 'nuggets/io/interact_mixin'
2
+
3
+ class IO
4
+ extend Nuggets::IO::InteractMixin
5
+ end
@@ -0,0 +1,159 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # nuggets -- Extending Ruby #
5
+ # #
6
+ # Copyright (C) 2007-2011 Jens Wille #
7
+ # #
8
+ # Authors: #
9
+ # Jens Wille <jens.wille@gmail.com> #
10
+ # #
11
+ # nuggets is free software; you can redistribute it and/or modify it under #
12
+ # the terms of the GNU Affero General Public License as published by the Free #
13
+ # Software Foundation; either version 3 of the License, or (at your option) #
14
+ # any later version. #
15
+ # #
16
+ # nuggets is distributed in the hope that it will be useful, but WITHOUT ANY #
17
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
18
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for #
19
+ # more details. #
20
+ # #
21
+ # You should have received a copy of the GNU Affero General Public License #
22
+ # along with nuggets. If not, see <http://www.gnu.org/licenses/>. #
23
+ # #
24
+ ###############################################################################
25
+ #++
26
+
27
+ module Nuggets
28
+ class IO
29
+ module InteractMixin
30
+
31
+ # call-seq:
32
+ # IO.interact(input, output[, timeout[, maxlen]]) -> anArray | nil
33
+ #
34
+ # Interact with both ends of a pipe in a non-blocking manner.
35
+ #
36
+ # +input+ represents the sending end and is a mapping from the actual
37
+ # input IO (to send into the pipe) to the pipe's input handle (_stdin_).
38
+ # The input IO must support +read_nonblock+. If it's a StringIO it will
39
+ # be extended appropriately. If it's a String it will be converted to
40
+ # a StringIO.
41
+ #
42
+ # +output+ represents the receiving end and is a mapping from the pipe's
43
+ # output handle (_stdout_) to the designated output IO (to receive data
44
+ # from the pipe), and, optionally, from the pipe's error handle (_stderr_)
45
+ # to the designated error IO. The output and error IO must support <tt><<</tt>
46
+ # with a string argument. If either of them is a Proc it will be extended such
47
+ # that <tt><<</tt> delegates to +call+.
48
+ #
49
+ # +timeout+, if given, will be passed to IO::select and +nil+ is returned
50
+ # if the select call times out; in all other cases an empty array is returned.
51
+ #
52
+ # +maxlen+ is the chunk size for +read_nonblock+.
53
+ #
54
+ # Examples:
55
+ #
56
+ # require 'open3'
57
+ #
58
+ # # simply prints 'input string' on STDOUT, ignores +stderr+
59
+ # Open3.popen3('cat') { |stdin, stdout, stderr|
60
+ # IO.interact({ "input string\n" => stdin }, { stdout => STDOUT })
61
+ # }
62
+ #
63
+ # # prints lines you type in reverse order to a string
64
+ # str = ''
65
+ # Open3.popen3('tac') { |stdin, stdout, stderr|
66
+ # IO.interact({ STDIN => stdin }, { stdout => str })
67
+ # }
68
+ # puts str
69
+ #
70
+ # # prints the IP adresses from /etc/hosts on STDOUT and their lengths
71
+ # # on STDERR
72
+ # cmd = %q{ruby -ne 'i = $_.split.first or next; warn i.length; puts i'}
73
+ # Open3.popen3(cmd) { |stdin, stdout, stderr|
74
+ # File.open('/etc/hosts') { |f|
75
+ # IO.interact({ f => stdin }, { stdout => STDOUT, stderr => STDERR })
76
+ # }
77
+ # }
78
+ def interact(input, output, timeout = nil, maxlen = 2 ** 16)
79
+ readers, writers = {}, {}
80
+
81
+ output.each { |key, val|
82
+ if val.is_a?(::Proc) && !val.respond_to?(:<<)
83
+ class << val; alias_method :<<, :call; end
84
+ end
85
+
86
+ readers[key] = val
87
+ }
88
+
89
+ input.each { |key, val|
90
+ if key.is_a?(::String)
91
+ require 'stringio'
92
+ key = ::StringIO.new(key)
93
+ end
94
+
95
+ unless key.respond_to?(:read_nonblock)
96
+ def key.read_nonblock(*args)
97
+ read(*args) or raise ::EOFError, 'end of string reached'
98
+ end
99
+ end
100
+
101
+ writers[val] = [key, '']
102
+ }
103
+
104
+ close = lambda { |*args|
105
+ container, item, read = args
106
+
107
+ container.delete(item)
108
+ read ? item.close_read : item.close_write
109
+ }
110
+
111
+ read = lambda { |*args|
112
+ reader, buffer, writer = args
113
+
114
+ container = writer ? writers : readers
115
+ buffer ||= container[reader]
116
+
117
+ begin
118
+ buffer << reader.read_nonblock(maxlen)
119
+ rescue ::Errno::EAGAIN
120
+ rescue ::EOFError
121
+ buffer.force_encoding(
122
+ reader.internal_encoding ||
123
+ reader.external_encoding ||
124
+ Encoding.default_internal ||
125
+ Encoding.default_external
126
+ ) if buffer.respond_to?(:force_encoding)
127
+
128
+ close[container, writer || reader, !writer]
129
+ end
130
+ }
131
+
132
+ until readers.empty? && writers.empty?
133
+ fhs = select(readers.keys, writers.keys, nil, timeout) or return
134
+
135
+ fhs[0].each { |reader| read[reader] }
136
+
137
+ fhs[1].each { |writer|
138
+ reader, buffer = writers[writer]
139
+ read[reader, buffer, writer] or next if buffer.empty?
140
+
141
+ begin
142
+ bytes = writer.write_nonblock(buffer)
143
+ rescue ::Errno::EPIPE
144
+ close[writers, writer]
145
+ end
146
+
147
+ if bytes
148
+ buffer.force_encoding('BINARY') if buffer.respond_to?(:force_encoding)
149
+ buffer.slice!(0, bytes)
150
+ end
151
+ }
152
+ end
153
+
154
+ []
155
+ end
156
+
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,121 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # nuggets -- Extending Ruby #
5
+ # #
6
+ # Copyright (C) 2007-2011 Jens Wille #
7
+ # #
8
+ # Authors: #
9
+ # Jens Wille <jens.wille@gmail.com> #
10
+ # #
11
+ # nuggets is free software; you can redistribute it and/or modify it under #
12
+ # the terms of the GNU Affero General Public License as published by the Free #
13
+ # Software Foundation; either version 3 of the License, or (at your option) #
14
+ # any later version. #
15
+ # #
16
+ # nuggets is distributed in the hope that it will be useful, but WITHOUT ANY #
17
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
18
+ # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for #
19
+ # more details. #
20
+ # #
21
+ # You should have received a copy of the GNU Affero General Public License #
22
+ # along with nuggets. If not, see <http://www.gnu.org/licenses/>. #
23
+ # #
24
+ ###############################################################################
25
+ #++
26
+
27
+ class IO
28
+
29
+ # Inspired by Martin DeMello, [ruby-talk:307782] -- thx ;-)
30
+
31
+ class << self
32
+
33
+ alias_method :_nuggets_original_read, :read
34
+
35
+ # call-seq:
36
+ # IO.read(name[, length[, offset]]]) => aString
37
+ # IO.read(name[, binary]) { |io| ... } => anObject
38
+ #
39
+ # Opens +name+ with mode +r+. NOTE: With no associated block,
40
+ # acts like the original IO::read, not like IO::new.
41
+ def read(name, *args)
42
+ return _nuggets_original_read(name, *args) unless block_given?
43
+
44
+ case args.size
45
+ when 0
46
+ # ok
47
+ when 1
48
+ case binary = args.first
49
+ when true, false, nil
50
+ # ok
51
+ else
52
+ raise ::TypeError, "wrong argument type #{binary.class} (expected boolean)"
53
+ end
54
+ else
55
+ raise ::ArgumentError, "wrong number of arguments (#{args.size + 1} for 1-2)"
56
+ end
57
+
58
+ open_with_mode(name, 'r', binary, &::Proc.new)
59
+ end
60
+
61
+ # call-seq:
62
+ # IO.write(name[, binary]) => anIO
63
+ # IO.write(name[, binary]) { |io| ... } => anObject
64
+ #
65
+ # Opens +name+ with mode +w+.
66
+ def write(name, binary = false)
67
+ open_with_mode(name, 'w', binary, &block_given? ? ::Proc.new : nil)
68
+ end
69
+
70
+ # call-seq:
71
+ # IO.append(name[, binary]) => anIO
72
+ # IO.append(name[, binary]) { |io| ... } => anObject
73
+ #
74
+ # Opens +name+ with mode +a+.
75
+ def append(name, binary = false)
76
+ open_with_mode(name, 'a', binary, &block_given? ? ::Proc.new : nil)
77
+ end
78
+
79
+ # call-seq:
80
+ # IO.read_write(name[, binary]) => anIO
81
+ # IO.read_write(name[, binary]) { |io| ... } => anObject
82
+ #
83
+ # Opens +name+ with mode <tt>r+</tt>.
84
+ def read_write(name, binary = false)
85
+ open_with_mode(name, 'r+', binary, &block_given? ? ::Proc.new : nil)
86
+ end
87
+
88
+ # call-seq:
89
+ # IO.write_read(name[, binary]) => anIO
90
+ # IO.write_read(name[, binary]) { |io| ... } => anObject
91
+ #
92
+ # Opens +name+ with mode <tt>w+</tt>.
93
+ def write_read(name, binary = false)
94
+ open_with_mode(name, 'w+', binary, &block_given? ? ::Proc.new : nil)
95
+ end
96
+
97
+ # call-seq:
98
+ # IO.append_read(name[, binary]) => anIO
99
+ # IO.append_read(name[, binary]) { |io| ... } => anObject
100
+ #
101
+ # Opens +name+ with mode <tt>a+</tt>.
102
+ def append_read(name, binary = false)
103
+ open_with_mode(name, 'a+', binary, &block_given? ? ::Proc.new : nil)
104
+ end
105
+
106
+ private
107
+
108
+ # Just a helper to DRY things up.
109
+ def open_with_mode(name, mode, binary = false)
110
+ open(name, "#{mode}#{'b' if binary}", &block_given? ? ::Proc.new : nil)
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+
117
+ if $0 == __FILE__
118
+ # ::File.read(__FILE__) { |f| ... }
119
+ # ::File.write(__FILE__) { |f| ... }
120
+ # ::File.append(__FILE__) { |f| ... }
121
+ end