darkext 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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