darkext 0.12.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 (51) hide show
  1. data/.gitignore +4 -0
  2. data/History.txt +140 -0
  3. data/LICENSE +21 -0
  4. data/README.md +45 -0
  5. data/Rakefile +45 -0
  6. data/TODO +4 -0
  7. data/VERSION.yml +4 -0
  8. data/app_generators/sinatra_app_generator.rb +57 -0
  9. data/app_generators/templates/app.rb +16 -0
  10. data/app_generators/templates/config.ru +2 -0
  11. data/app_generators/templates/error.rb +8 -0
  12. data/app_generators/templates/gitignore +0 -0
  13. data/app_generators/templates/helpers.rb +12 -0
  14. data/app_generators/templates/http_method.rb +8 -0
  15. data/app_generators/templates/options.rb +9 -0
  16. data/bin/sinatra-app +14 -0
  17. data/darkext.gemspec +105 -0
  18. data/lib/darkext.rb +13 -0
  19. data/lib/darkext/array.rb +52 -0
  20. data/lib/darkext/beagle.rb +88 -0
  21. data/lib/darkext/boolean.rb +17 -0
  22. data/lib/darkext/fiber.rb +48 -0
  23. data/lib/darkext/float.rb +6 -0
  24. data/lib/darkext/hash.rb +38 -0
  25. data/lib/darkext/integer.rb +10 -0
  26. data/lib/darkext/io.rb +37 -0
  27. data/lib/darkext/net.rb +28 -0
  28. data/lib/darkext/numeric.rb +35 -0
  29. data/lib/darkext/object.rb +11 -0
  30. data/lib/darkext/sinatra.rb +70 -0
  31. data/lib/darkext/sitemap_generator.rb +90 -0
  32. data/lib/darkext/statistics.rb +197 -0
  33. data/lib/darkext/string.rb +63 -0
  34. data/lib/darkext/symbol.rb +7 -0
  35. data/spec/array_spec.rb +112 -0
  36. data/spec/beagle_spec.rb +42 -0
  37. data/spec/boolean_spec.rb +53 -0
  38. data/spec/fiber_spec.rb +35 -0
  39. data/spec/float_spec.rb +18 -0
  40. data/spec/hash_spec.rb +26 -0
  41. data/spec/integer_spec.rb +22 -0
  42. data/spec/io_spec.rb +44 -0
  43. data/spec/net_spec.rb +23 -0
  44. data/spec/numeric_spec.rb +52 -0
  45. data/spec/object_spec.rb +28 -0
  46. data/spec/spec.opts +3 -0
  47. data/spec/spec_helper.rb +13 -0
  48. data/spec/statistics_spec.rb +162 -0
  49. data/spec/string_spec.rb +54 -0
  50. data/spec/symbol_spec.rb +16 -0
  51. metadata +119 -0
@@ -0,0 +1,90 @@
1
+ require 'hpricot'
2
+ require 'open-uri'
3
+ require 'builder'
4
+ require 'darkext/hash'
5
+
6
+ module Darkext
7
+ class Darkext::SitemapBuilder
8
+ FORUM_CLASS_DEFAULT = 'forumtitle'
9
+ TOPIC_CLASS_DEFAULT = 'topictitle'
10
+ FORUM_PRIORITY_DEFAULT = 0.8
11
+ TOPIC_PRIORITY_DEFAULT = 0.5
12
+ PAGE_PRIORITY_DEFAULT = 0.1
13
+ FORUM_CHANGE_FREQ_DEFAULT = 'daily'
14
+ TOPIC_CHANGE_FREQ_DEFAULT = 'hourly'
15
+ PAGE_CHANGE_FREQ_DEFAULT = 'monthly'
16
+
17
+ def initialize(opts={})
18
+ defaults = {
19
+ :forum => {
20
+ :class => FORUM_CLASS_DEFAULT,
21
+ :priority => FORUM_PRIORITY_DEFAULT,
22
+ :change_freq => FORUM_CHANGE_FREQ_DEFAULT
23
+ },
24
+ :topic => {
25
+ :class => TOPIC_CLASS_DEFAULT,
26
+ :priority => TOPIC_PRIORITY_DEFAULT,
27
+ :change_freq => TOPIC_CHANGE_FREQ_DEFAULT
28
+ },
29
+ :page => {
30
+ :priority => PAGE_PRIORITY_DEFAULT,
31
+ :change_freq => PAGE_CHANGE_FREQ_DEFAULT
32
+ }
33
+ }
34
+ defaults.deep_merge!(opts)
35
+
36
+ @options = defaults
37
+
38
+ @forums = Array.new
39
+ @topics = Array.new
40
+ @pages = Array.new
41
+ end
42
+
43
+ def index(url, target = $stdout)
44
+ @pages << url
45
+
46
+ root = Hpricot(open(url))
47
+ (root/"a.#{@options.nested_find(:forum,:class)}").each do |link|
48
+ index_forum(link.attributes['href'].to_s)
49
+ end
50
+
51
+ xml = Builder::XmlMarkup.new(:target => $stdout, :indent => 1)
52
+ xml.instruct!
53
+ xml.urlset "xmlns" => "http://www.sitemaps.org/schemas/sitemap/0.9" do
54
+ @pages.each do |page|
55
+ xml.url do
56
+ xml.loc(page)
57
+ xml.changefreq(@options.nested_find(:page,:change_freq))
58
+ xml.priority(@options.nested_find(:page,:priority))
59
+ end
60
+ end
61
+ @forums.each do |forum|
62
+ xml.url do
63
+ xml.loc(forum)
64
+ xml.changefreq(@options.nested_find(:forum,:change_freq))
65
+ xml.priority(@options.nested_find(:forum,:priority))
66
+ end
67
+ end
68
+ @topics.each do |topic|
69
+ xml.url do
70
+ xml.loc(topic)
71
+ xml.changefreq(@options.nested_find(:topic,:change_freq))
72
+ xml.priority(@options.nested_find(:topic,:priority))
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ private
79
+ def index_forum(href)
80
+ root = Hpricot(open(href))
81
+ (root/"a.#{@options.nested_find(:forum,:class)}").each do |link|
82
+ index_forum(link.attributes['href'].to_s)
83
+ end
84
+ (root/"a.#{@options.nested_find(:topic,:class)}").each do |link|
85
+ @topics << link.attributes['href'].to_s
86
+ end
87
+ @forums << href
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,197 @@
1
+ require 'mathn'
2
+
3
+ require 'darkext/array'
4
+ require 'darkext/numeric'
5
+ require 'darkext/symbol'
6
+
7
+ class Array
8
+ # Finds the mean of the array
9
+ def mean
10
+ raise ArgumentError.new('Array size must be > 0') if self.size.zero?
11
+ self.sum / self.size.to_f
12
+ end
13
+ alias :average :mean
14
+ alias :ave :mean
15
+
16
+ def harmonic_mean
17
+ raise ArgumentError.new('Array size must be > 0') if self.size.zero?
18
+ self.size.to_f / self.map { |i| 1 / i.to_f }.sum
19
+ end
20
+ alias :h_mean :harmonic_mean
21
+
22
+ def geometric_mean
23
+ raise ArgumentError.new('Array size must be > 0') if self.size.zero?
24
+ self.product.root(self.size)
25
+ end
26
+ alias :g_mean :geometric_mean
27
+
28
+ # Finds the median of the array
29
+ def median
30
+ raise ArgumentError.new('Array size must be > 0') if self.size.zero?
31
+ case self.size % 2
32
+ when 0
33
+ return self.sort[(self.size / 2) - 1, 2].mean
34
+ when 1
35
+ return self.sort[self.size / 2]
36
+ end
37
+ end
38
+
39
+ # Generates a histogram hash for the array
40
+ def histogram
41
+ self.sort.inject({}) do |a,x|
42
+ a[x] = a[x].to_i + 1
43
+ a
44
+ end
45
+ end
46
+
47
+ # Finds the mode of the array
48
+ def mode
49
+ raise ArgumentError.new('Array size must be > 0') if self.size.zero?
50
+ map = self.histogram
51
+ max = map.values.max
52
+ map.keys.select { |x| map[x] == max }
53
+ end
54
+
55
+ # Variance
56
+ def variance
57
+ raise ArgumentError.new('Array size must be > 0') if self.size.zero?
58
+ self.sum_of_squares.to_f / (self.size).to_f
59
+ end
60
+
61
+ # Standard deviation
62
+ def standard_deviation
63
+ raise ArgumentError.new('Array size must be > 0') if self.size.zero?
64
+ self.variance.abs.sqrt
65
+ end
66
+ alias :stddev :standard_deviation
67
+
68
+ # Randomly samples n elements
69
+ def sample(n = 1)
70
+ (1..n).collect { self[rand(self.size)] }
71
+ end
72
+
73
+ # Generates a confidence interval
74
+ def ci(opts = { })
75
+ raise ArgumentError.new('Array size must be > 0') if self.size.zero?
76
+ opts = { :percent => 0.95, :rho => 1, :type => :center }.merge(opts)
77
+ percent = opts[:percent]
78
+ rho = opts[:rho]
79
+ m = self.mean
80
+ ret = Array.new
81
+ div = (opts[:type] == :center ? 2 : 1)
82
+ i = ((Darkext::Statistics::zscore((1 - percent) / div) * rho) /
83
+ self.size.sqrt).abs
84
+ case opts[:type]
85
+ when :center
86
+ ret << m - i
87
+ ret << m + i
88
+ when :upper
89
+ ret << m + i
90
+ when :lower
91
+ ret << m - i
92
+ end
93
+ return ret
94
+ end
95
+
96
+ # Standardizes the array
97
+ def standardize
98
+ self.clone.standardize!
99
+ end
100
+
101
+ # Destructive standardize
102
+ def standardize!
103
+ m = self.mean.to_f
104
+ rho = self.standard_deviation.to_f
105
+ self.map! { |v| (v.to_f - m) / rho }
106
+ end
107
+
108
+ def sum_of_squares
109
+ raise ArgumentError.new('Array size must be > 0') if self.size.zero?
110
+ m = self.mean
111
+ self.map { |v| v - m }.squares.sum
112
+ end
113
+ end
114
+
115
+ module Darkext
116
+ module Darkext::Statistics
117
+ # Finds the probability of a z-score
118
+ def self.prob(z)
119
+ p = Math::erf(z.abs/2.sqrt) / 2
120
+ return 0.5 + p if 0 < z
121
+ return 0.5 - p
122
+ end
123
+
124
+ # Finds the zscore of a probability
125
+ def self.zscore(p, epsilon = 0.00000000000001)
126
+ return -1 if (1 < p || 0 > p)
127
+ minz, maxz = -6, 6
128
+ zscore = 0.5
129
+ prob = 0
130
+ while (maxz - minz) > epsilon
131
+ prob = prob(zscore)
132
+ prob > p ? maxz = zscore : minz = zscore
133
+ zscore = (maxz + minz) * 0.5
134
+ end
135
+ return zscore
136
+ end
137
+
138
+ # Finds a two tail p-val for a high/low array
139
+ # can't remember how to use this
140
+ =begin
141
+ def self.p_val(r, n = 30, rho = 1, mu = r.mean)
142
+ probs = r.map do |x|
143
+ (x - mu) / (rho / n.sqrt)
144
+ end.map do |x|
145
+ Statistics::prob(x)
146
+ end
147
+ return 1 - (probs[1] - probs[0])
148
+ end
149
+ =end
150
+
151
+ module Darkext::Statistics::Regression
152
+ # Do a least squares linear regression on the two sets of x's and y's
153
+ # Returns a hash containing many relevant values
154
+ # * n (:n)
155
+ # * B_1 (:b_1)
156
+ # * B_0 (:b_0)
157
+ # * predicted values (:predicted)
158
+ # * residuals (:residuals)
159
+ # * SSE (:ss_e)
160
+ # * SST (:ss_t)
161
+ # * R^2 (:r_2)
162
+ # * R (:r)
163
+ # * unbiased estimator (:estimator)
164
+ # * the equation as a lambda (:equation)
165
+ # Raises an argument error if the arguments are not the same size or either is zero
166
+ def self.least_squares(xs,ys)
167
+ raise ArgumentError.new('Arrays must have size > 0') if xs.size.zero? || ys.size.zero?
168
+ raise ArgumentError.new('Arrays must be of equal size') if xs.size != ys.size
169
+ n = xs.size
170
+ b_1 = (xs.zip(ys).map(&:product).sum - ((ys.sum * xs.sum)/n))/(xs.map(&:square).sum - (xs.sum.square/n))
171
+ b_0 = ys.mean - b_1 * xs.mean
172
+ equation = lambda { |x| b_0 + b_1 * x }
173
+ predicted = xs.map(&equation)
174
+ residuals = ys.zip(predicted).map { |y| y.shift - y.shift }
175
+ ss_e = residuals.map(&:square).sum
176
+ ss_t = ys.sum_of_squares
177
+ estimator = ss_e/(n - 2)
178
+ r_2 = 1 - (ss_e/ss_t)
179
+ r = r_2.sqrt
180
+ reg = {
181
+ :n => n,
182
+ :b_1 => b_1,
183
+ :b_0 => b_0,
184
+ :predicted => predicted,
185
+ :residuals => residuals,
186
+ :ss_e => ss_e,
187
+ :ss_t => ss_t,
188
+ :estimator => estimator,
189
+ :equation => equation,
190
+ :r_2 => r_2,
191
+ :r => r
192
+ }
193
+ return reg
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,63 @@
1
+ require 'darkext/hash'
2
+
3
+ class String
4
+ # Parses a string like "1..10" to a Range
5
+ def to_range
6
+ case self.count('.')
7
+ when 2
8
+ elements = self.split('..')
9
+ if elements[0] == elements[0].to_i.to_s
10
+ return Range.new(elements[0].to_i, elements[1].to_i)
11
+ else
12
+ return Range.new(elements[0], elements[1])
13
+ end
14
+ when 3
15
+ elements = self.split('...')
16
+ if elements[0] == elements[0].to_i.to_s
17
+ return Range.new(elements[0].to_i, elements[1].to_i, true)
18
+ else
19
+ return Range.new(elements[0], elements[1], true)
20
+ end
21
+ end
22
+ raise ArgumentError.new('Could not parse range')
23
+ end
24
+
25
+ # Executes the string with system
26
+ # * :background => true to run command in the background using & (currently only works on *nix systems)
27
+ # * :capture => true to capture the output. If :capture => true, background is voided
28
+ def exec(opts = {})
29
+ opts.with_defaults!(:background => false, :capture => false)
30
+ return `#{self}` if opts[:capture]
31
+ return fork { system(self) } if opts[:background]
32
+ return system(self)
33
+ end
34
+
35
+ # Prints the String using print
36
+ def print
37
+ Kernel.print(self)
38
+ end
39
+
40
+ def printn
41
+ Kernel.print(self + "\n")
42
+ end
43
+
44
+ def true?
45
+ self.downcase == 'true'
46
+ end
47
+
48
+ def false?
49
+ self.downcase == 'false'
50
+ end
51
+
52
+ def starts_with?(str)
53
+ str = str.to_s
54
+ str == self[0, str.length]
55
+ end
56
+
57
+ def ends_with?(str)
58
+ str = str.to_s
59
+ str == self[-str.length, str.length]
60
+ end
61
+
62
+ alias :/ :split
63
+ end
@@ -0,0 +1,7 @@
1
+ class Symbol
2
+ # Does exactly what the activesupport version does,
3
+ # with pretty much the same code.
4
+ def to_proc
5
+ Proc.new { |*args| args.shift.__send__(self, *args) }
6
+ end
7
+ end
@@ -0,0 +1,112 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Array do
4
+ before(:each) do
5
+ @a = (1..5).to_a
6
+ end
7
+
8
+ it 'should respond to all the new methods' do
9
+ %w(rotate rotate_reverse sum product squares squares! random pick randomize randomize!).each { |method| [1].methods.include?(method).should == true }
10
+ end
11
+
12
+ it 'should not remove or add elements when randomizing' do
13
+ @a.randomize.size.should == @a.size
14
+ end
15
+
16
+ it 'should rotate back to normal' do
17
+ b = @a.clone
18
+ b.rotate(b.size)
19
+ b.should == @a
20
+ end
21
+
22
+ it 'should rotate reverse back to normal' do
23
+ b = @a.clone
24
+ b.rotate_reverse(b.size)
25
+ b.should == @a
26
+ end
27
+
28
+ it 'should return a Numeric from sum and sum' do
29
+ @a.sum.should be_a_kind_of(Numeric)
30
+ @a.product.should be_a_kind_of(Numeric)
31
+ end
32
+
33
+ it 'should return an array of equal size from squares' do
34
+ squares = @a.squares
35
+ squares.should be_a_kind_of(Array)
36
+ squares.size.should == @a.size
37
+ end
38
+
39
+ it 'should destructively collect squares' do
40
+ b = @a.clone
41
+ b.squares!.should == @a.squares
42
+ end
43
+
44
+ it 'should pick randomly' do
45
+ counts = [0,0,0,0,0]
46
+ count = 1000000
47
+ count.times do
48
+ r = @a.random
49
+ counts[r - 1] += 1
50
+ end
51
+ counts.each do |v|
52
+ (v/count.to_f).should be_close(1/counts.size.to_f,0.001)
53
+ end
54
+
55
+ @a.include?(@a.random).should be_true
56
+ end
57
+
58
+ it 'should return an Array from randomize' do
59
+ @a.randomize.should be_a_kind_of(Array)
60
+ end
61
+
62
+ it 'should return nil from sum, product and random if size == 0' do
63
+ %w(sum product random).each do |method|
64
+ Array.new.send(method.intern).should be_nil
65
+ end
66
+ end
67
+
68
+ it 'should rotate properly' do
69
+ @a.rotate
70
+ @a.should == [2,3,4,5,1]
71
+ @a.rotate
72
+ @a.should == [3,4,5,1,2]
73
+ @a.rotate(@a.size)
74
+ @a.should == [3,4,5,1,2]
75
+ end
76
+
77
+ it 'should rotate reverse properly' do
78
+ @a.rotate_reverse
79
+ @a.should == [5,1,2,3,4]
80
+ @a.rotate_reverse
81
+ @a.should == [4,5,1,2,3]
82
+ @a.rotate_reverse(@a.size)
83
+ @a.should == [4,5,1,2,3]
84
+ end
85
+
86
+ it 'should sum properly' do
87
+ @a.sum.should == 15
88
+ [1].sum.should == 1
89
+ %w(a b c).sum.should == 'abc'
90
+ [1.0,0.1,0.01].sum.should == 1.11
91
+ end
92
+
93
+ it 'should do product properly' do
94
+ @a.product.should == 120
95
+ [1].product.should == 1
96
+ ['a',3].product.should == 'aaa'
97
+ end
98
+
99
+ it 'should do squares properly' do
100
+ @a.squares.should == [1,4,9,16,25]
101
+ [1].squares.should == [1]
102
+ @a.squares!
103
+ @a.should == [1,4,9,16,25]
104
+ end
105
+
106
+ it 'should randomize' do
107
+ @a.randomize.should_not == @a
108
+ a = @a.clone
109
+ @a.randomize!
110
+ @a.should_not == a
111
+ end
112
+ end