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/array/histogram_mixin'
2
+
3
+ class Array
4
+ include Nuggets::Array::HistogramMixin
5
+ end
@@ -0,0 +1,169 @@
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 Array
29
+ module HistogramMixin
30
+
31
+ # Provides some default formats for #formatted_histogram.
32
+ #
33
+ # Example:
34
+ #
35
+ # (default) ab [==] 2
36
+ # (percent) xyz [===] 3 (37.50%)
37
+ # (numeric) 42 [==] 2
38
+ # (numeric_percent) 123 [=] 1 (12.50%)
39
+ #
40
+ # The "numeric" variants format the item as a (decimal) number.
41
+ FORMATS = {
42
+ :default => '%-*s [%s]%*s %*d',
43
+ :percent => '%-*s [%s]%*s %*d (%.2f%%)',
44
+ :numeric => '%*d [%s]%*s %*d',
45
+ :numeric_percent => '%*d [%s]%*s %*d (%.2f%%)'
46
+ }
47
+
48
+ # Encapsulates a #histogram item and provides the following attributes (see
49
+ # also #annotated_histogram):
50
+ #
51
+ # item:: The original item
52
+ # freq:: The item's frequency in the collection
53
+ # percentage:: The percentage of the item's frequency in the collection
54
+ # max_freq:: The maximum frequency in the collection
55
+ # max_freq_length:: The maximum frequency's "width"
56
+ # max_item_length:: The maximum item length in the collection
57
+ HistogramItem = ::Struct.new(
58
+ :item, :freq, :max_freq, :max_freq_length, :max_item_length, :percentage
59
+ )
60
+
61
+ # call-seq:
62
+ # array.histogram => aHash
63
+ # array.histogram { |x| ... } => aHash
64
+ #
65
+ # Calculates the {frequency histogram}[http://en.wikipedia.org/wiki/Histogram]
66
+ # of the values in _array_. Returns a Hash that maps any value, or the result
67
+ # of the value yielded to the block, to its frequency.
68
+ def histogram
69
+ hist = ::Hash.new(0)
70
+ each { |x| hist[block_given? ? yield(x) : x] += 1 }
71
+ hist
72
+ end
73
+
74
+ # call-seq:
75
+ # array.probability_mass_function => aHash
76
+ # array.probability_mass_function { |x| ... } => aHash
77
+ #
78
+ # Calculates the {probability mass function}[http://en.wikipedia.org/wiki/Probability_mass_function]
79
+ # (normalized histogram) of the values in _array_. Returns a Hash that
80
+ # maps any value, or the result of the value yielded to the block, to
81
+ # its probability (via #histogram).
82
+ def probability_mass_function(&block)
83
+ hist, n = histogram(&block), size.to_f
84
+ hist.each { |k, v| hist[k] = v / n }
85
+ end
86
+
87
+ alias_method :pmf, :probability_mass_function
88
+
89
+ # call-seq:
90
+ # array.annotated_histogram => anArray
91
+ # array.annotated_histogram { |hist_item| ... } => aHash
92
+ #
93
+ # Calculates the #histogram for _array_ and yields each histogram item
94
+ # (see HistogramItem) to the block or returns an Array of the histogram
95
+ # items.
96
+ def annotated_histogram
97
+ hist, items = histogram, []
98
+
99
+ percentage = size / 100.0
100
+
101
+ max_freq = hist.values.max
102
+ max_freq_length = max_freq.to_s.length
103
+
104
+ max_item_length = hist.keys.map { |item| item.to_s.length }.max
105
+
106
+ # try to sort the histogram hash
107
+ begin
108
+ hist = hist.sort
109
+ rescue ::ArgumentError
110
+ end
111
+
112
+ hist.each { |item, freq|
113
+ hist_item = HistogramItem.new(
114
+ item, freq, max_freq, max_freq_length, max_item_length, freq / percentage
115
+ )
116
+
117
+ block_given? ? yield(hist_item) : items << hist_item
118
+ }
119
+
120
+ block_given? ? hist : items
121
+ end
122
+
123
+ # call-seq:
124
+ # array.formatted_histogram([format[, indicator]]) => aString
125
+ #
126
+ # Returns the #histogram of _array_ as a formatted String according to
127
+ # +format+, using +indicator+ to draw the frequency bar.
128
+ #
129
+ # +format+ may be a Symbol indicating one of the provided default formats
130
+ # (see FORMATS) or a format String (see Kernel#sprintf) that will receive
131
+ # the following arguments (in order):
132
+ #
133
+ # 1. +max_item_length+ (Integer)
134
+ # 1. +item+ (String)
135
+ # 1. "frequency_bar" (String)
136
+ # 1. "padding" (String)
137
+ # 1. +max_freq_length+ (Integer)
138
+ # 1. +freq+ (Integer)
139
+ # 1. +percentage+ (Float, optional)
140
+ #
141
+ # See HistogramItem for further details on the individual arguments.
142
+ def formatted_histogram(format = :default, indicator = '=')
143
+ format = FORMATS[format] if FORMATS.key?(format)
144
+ raise ::TypeError, "String expected, got #{format.class}" unless format.is_a?(::String)
145
+
146
+ include_percentage = format.include?('%%')
147
+ indicator_length = indicator.length
148
+
149
+ lines = []
150
+
151
+ annotated_histogram { |hist|
152
+ arguments = [
153
+ hist.max_item_length, hist.item, # item (padded)
154
+ indicator * hist.freq, # indicator bar
155
+ (hist.max_freq - hist.freq) * indicator_length, '', # indicator padding
156
+ hist.max_freq_length, hist.freq # frequency (padded)
157
+ ]
158
+
159
+ arguments << hist.percentage if include_percentage # percentage (optional)
160
+
161
+ lines << format % arguments
162
+ }
163
+
164
+ lines.join("\n")
165
+ end
166
+
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,50 @@
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 Array
28
+
29
+ # call-seq:
30
+ # array.in_order(*ordered) => new_array
31
+ #
32
+ # Force order, but ignore non-existing and keep remaining.
33
+ #
34
+ # Examples:
35
+ # [:created_at, :email, :login, :updated_at].in_order(:login, :email) #=> [:login, :email, :created_at, :updated_at]
36
+ # [:created_at, :email, :login, :updated_at].in_order(:email, :address) #=> [:email, :created_at, :login, :updated_at]
37
+ def in_order(*ordered)
38
+ ordered &= self
39
+ ordered + (self - ordered)
40
+ end
41
+
42
+ # call-seq:
43
+ # array.in_order!(*ordered) => array
44
+ #
45
+ # Destructive version of #in_order.
46
+ def in_order!(*ordered)
47
+ replace(in_order(*ordered))
48
+ end
49
+
50
+ end
@@ -0,0 +1,5 @@
1
+ require 'nuggets/array/limit_mixin'
2
+
3
+ class Array
4
+ include Nuggets::Array::LimitMixin
5
+ end
@@ -0,0 +1,56 @@
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 Array
29
+ module LimitMixin
30
+
31
+ # call-seq:
32
+ # array.limit(min, max) => anArray
33
+ #
34
+ # Returns a new array of all distinct values in _array_ limited to +min+
35
+ # and +max+ (cf. Numeric#limit). If +uniq+ is +true+, resulting duplicates
36
+ # will be removed.
37
+ def limit(min, max, uniq = true)
38
+ limited = cap(min..max)
39
+ limited.uniq! if uniq
40
+ limited
41
+ end
42
+
43
+ alias_method :between, :limit
44
+
45
+ def cap(max)
46
+ if max.respond_to?(:begin)
47
+ min, max = max.begin, max.end
48
+ map { |item| item.limit(min, max) }
49
+ else
50
+ map { |item| item.max(max) }
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ require 'nuggets/array/mean_mixin'
2
+
3
+ class Array
4
+ include Nuggets::Array::MeanMixin
5
+ end
@@ -0,0 +1,202 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # nuggets -- Extending Ruby #
5
+ # #
6
+ # Copyright (C) 2007-2013 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 Array
29
+ module MeanMixin
30
+
31
+ # call-seq:
32
+ # array.generalized_mean(exponent) => aFloat
33
+ # array.generalized_mean(exponent) { |x| ... } => aFloat
34
+ #
35
+ # Calculates the {generalized mean}[http://en.wikipedia.org/wiki/Generalized_mean]
36
+ # of the values in _array_ for +exponent+. Returns the #geometric_mean if
37
+ # +exponent+ is zero.
38
+ #
39
+ # An optional block may be passed to provide a weight for each value.
40
+ # Defaults to 1. Returns +nil+ if the sum of all weights is zero (this
41
+ # includes _array_ being empty).
42
+ def generalized_mean(exponent, &block)
43
+ return geometric_mean(&block) if exponent.zero?
44
+
45
+ total, weights = 0, 0
46
+
47
+ each { |x|
48
+ weight = block ? block[x] : 1
49
+
50
+ total += weight * x ** exponent
51
+ weights += weight
52
+ }
53
+
54
+ (total / weights.to_f) ** (1.0 / exponent) unless weights.zero?
55
+ end
56
+
57
+ alias_method :power_mean, :generalized_mean
58
+ alias_method :minkowski_mean, :generalized_mean
59
+
60
+ # call-seq:
61
+ # array.arithmetic_mean => aFloat
62
+ # array.arithmetic_mean { |x| ... } => aFloat
63
+ #
64
+ # Calculates the {arithmetic mean}[http://en.wikipedia.org/wiki/Arithmetic_mean]
65
+ # of the values in _array_.
66
+ #
67
+ # An optional block may be passed to provide a weight for each value.
68
+ # Defaults to 1. Returns +nil+ if the sum of all weights is zero (this
69
+ # includes _array_ being empty).
70
+ def arithmetic_mean(&block)
71
+ generalized_mean(1, &block)
72
+ end
73
+
74
+ alias_method :mean, :arithmetic_mean
75
+ alias_method :average, :arithmetic_mean
76
+ alias_method :avg, :arithmetic_mean
77
+
78
+ # call-seq:
79
+ # array.root_mean_square => aFloat
80
+ # array.root_mean_square { |x| ... } => aFloat
81
+ #
82
+ # Calculates the {root mean square}[http://en.wikipedia.org/wiki/Root_mean_square]
83
+ # (quadratic mean) of the values in _array_.
84
+ #
85
+ # An optional block may be passed to provide a weight for each value.
86
+ # Defaults to 1. Returns +nil+ if the sum of all weights is zero (this
87
+ # includes _array_ being empty).
88
+ def root_mean_square(&block)
89
+ generalized_mean(2, &block)
90
+ end
91
+
92
+ alias_method :rms, :root_mean_square
93
+ alias_method :quadratic_mean, :root_mean_square
94
+
95
+ # call-seq:
96
+ # array.harmonic_mean => aFloat
97
+ # array.harmonic_mean { |x| ... } => aFloat
98
+ #
99
+ # Calculates the {harmonic mean}[http://en.wikipedia.org/wiki/Harmonic_mean]
100
+ # of the values in _array_.
101
+ #
102
+ # An optional block may be passed to provide a weight for each value.
103
+ # Defaults to 1. Returns +nil+ if the sum of all weights is zero (this
104
+ # includes _array_ being empty).
105
+ def harmonic_mean(&block)
106
+ generalized_mean(-1, &block)
107
+ end
108
+
109
+ alias_method :harmean, :harmonic_mean
110
+
111
+ # call-seq:
112
+ # array.geometric_mean => aFloat
113
+ # array.geometric_mean { |x| ... } => aFloat
114
+ #
115
+ # Calculates the {geometric mean}[http://en.wikipedia.org/wiki/Geometric_median]
116
+ # of the values in _array_.
117
+ #
118
+ # An optional block may be passed to provide a weight for each value.
119
+ # Defaults to 1. Returns +nil+ if the sum of all weights is zero (this
120
+ # includes _array_ being empty).
121
+ def geometric_mean
122
+ total, weights = 1, 0
123
+
124
+ each { |x|
125
+ weight = block_given? ? yield(x) : 1
126
+
127
+ total *= x ** weight
128
+ weights += weight
129
+ }
130
+
131
+ total ** (1 / weights.to_f) unless weights.zero?
132
+ end
133
+
134
+ alias_method :geomean, :geometric_mean
135
+
136
+ # call-seq:
137
+ # array.report_mean => anArray
138
+ # array.report_mean(method[, precision]) => anArray
139
+ #
140
+ # Expects _array_ to be an array of arrays ("rows") of numeric values;
141
+ # the first "row" may consist of strings (labels) instead. Returns an
142
+ # array of strings with the mean (according to +method+, default #mean)
143
+ # of each "column", prepended with the label, if present, and appended
144
+ # with the standard deviation, if available; all values are subject to
145
+ # +precision+.
146
+ #
147
+ # If _array_ is a flat array of numeric values, it is treated as a single
148
+ # "column".
149
+ #
150
+ # Returns +nil+ if _array_ is empty.
151
+ #
152
+ # Examples (with standard deviation):
153
+ #
154
+ # [[9.4, 34.75], [9.46, 34.68], [9.51, 34.61]].report_mean
155
+ # #=> ["9.4567 +/- 0.0450", "34.6800 +/- 0.0572"]
156
+ #
157
+ # [[9.4, 34.75], [9.46, 34.68], [9.51, 34.61]].report_mean(:harmonic)
158
+ # #=> ["9.4565 +/- 0.0450", "34.6799 +/- 0.0572"]
159
+ #
160
+ # [["a", "b"], [9.4, 34.75], [9.46, 34.68], [9.51, 34.61]].report_mean(nil, 2)
161
+ # #=> ["a 9.46 +/- 0.04", "b 34.68 +/- 0.06"]
162
+ #
163
+ # CSV.read('csv', headers: true, converters: :numeric).to_a.report_mean
164
+ # #=> ["a 9.4567 +/- 0.0450", "b 34.6800 +/- 0.0572"]
165
+ #
166
+ # [9.4, 9.46, 9.51].report_mean
167
+ # #=> ["9.4567 +/- 0.0450"]
168
+ #
169
+ # [34.75, 34.68, 34.61].report_mean
170
+ # #=> ["34.6800 +/- 0.0572"]
171
+ #
172
+ # [].report_mean
173
+ # #=> nil
174
+ def report_mean(method = nil, precision = 4)
175
+ return if empty?
176
+
177
+ return clone.replace(self.class.new.push(self).transpose).
178
+ report_mean(method, precision) unless first.is_a?(self.class)
179
+
180
+ met, sep = [method ||= :mean, 'mean'], ['', '_']
181
+ lab, std = first.first.is_a?(::String), respond_to?(:std)
182
+
183
+ fmt = ["%-#{precision}s", "%.#{precision}f", "+/- %.#{precision}f"]
184
+
185
+ until respond_to?(method) || sep.empty?
186
+ method = met.join(sep.shift)
187
+ end
188
+
189
+ transpose.map! { |x|
190
+ i, a = [], []
191
+
192
+ i << 0 and a << x.shift if lab
193
+ i << 1 and a << x.send(method)
194
+ i << 2 and a << x.std if std
195
+
196
+ fmt.values_at(*i).join(' ') % a
197
+ }
198
+ end
199
+
200
+ end
201
+ end
202
+ end