growltdf 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/Rakefile +229 -0
  2. data/bin/growltdf +188 -0
  3. data/growltdf.gemspec +27 -0
  4. metadata +85 -0
data/Rakefile ADDED
@@ -0,0 +1,229 @@
1
+
2
+ This.rubyforge_project = 'codeforpeople'
3
+ This.author = "Ara T. Howard"
4
+ This.email = "ara.t.howard@gmail.com"
5
+ This.homepage = "http://github.com/ahoward/#{ This.lib }/tree/master"
6
+
7
+
8
+ task :default do
9
+ puts(Rake::Task.tasks.map{|task| task.name} - ['default'])
10
+ end
11
+
12
+
13
+ task :gemspec do
14
+ ignore_extensions = 'git', 'svn', 'tmp', /sw./, 'bak', 'gem'
15
+ ignore_directories = 'pkg'
16
+ ignore_files = 'test/log'
17
+
18
+ shiteless =
19
+ lambda do |list|
20
+ list.delete_if do |entry|
21
+ next unless test(?e, entry)
22
+ extension = File.basename(entry).split(%r/[.]/).last
23
+ ignore_extensions.any?{|ext| ext === extension}
24
+ end
25
+ list.delete_if do |entry|
26
+ next unless test(?d, entry)
27
+ dirname = File.expand_path(entry)
28
+ ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
29
+ end
30
+ list.delete_if do |entry|
31
+ next unless test(?f, entry)
32
+ filename = File.expand_path(entry)
33
+ ignore_files.any?{|file| File.expand_path(file) == filename}
34
+ end
35
+ end
36
+
37
+ lib = This.lib
38
+ version = This.version
39
+ files = shiteless[Dir::glob("**/**")]
40
+ executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
41
+ has_rdoc = true #File.exist?('doc')
42
+ test_files = "test/#{ lib }.rb" if File.file?("test/#{ lib }.rb")
43
+
44
+ extensions = This.extensions
45
+ if extensions.nil?
46
+ %w( Makefile configure extconf.rb ).each do |ext|
47
+ extensions << ext if File.exists?(ext)
48
+ end
49
+ end
50
+ extensions = [extensions].flatten.compact
51
+
52
+ template =
53
+ if test(?e, 'gemspec.erb')
54
+ Template{ IO.read('gemspec.erb') }
55
+ else
56
+ Template {
57
+ <<-__
58
+ ## #{ lib }.gemspec
59
+ #
60
+
61
+ Gem::Specification::new do |spec|
62
+ spec.name = #{ lib.inspect }
63
+ spec.version = #{ version.inspect }
64
+ spec.platform = Gem::Platform::RUBY
65
+ spec.summary = #{ lib.inspect }
66
+
67
+ spec.files = #{ files.inspect }
68
+ spec.executables = #{ executables.inspect }
69
+
70
+ spec.require_path = "lib"
71
+
72
+ spec.has_rdoc = #{ has_rdoc.inspect }
73
+ spec.test_files = #{ test_files.inspect }
74
+ spec.add_dependency 'main'
75
+ spec.add_dependency 'ruby-growl'
76
+ spec.add_dependency 'nokogiri'
77
+
78
+ spec.extensions.push(*#{ extensions.inspect })
79
+
80
+ spec.rubyforge_project = #{ This.rubyforge_project.inspect }
81
+ spec.author = #{ This.author.inspect }
82
+ spec.email = #{ This.email.inspect }
83
+ spec.homepage = #{ This.homepage.inspect }
84
+ end
85
+ __
86
+ }
87
+ end
88
+
89
+ open("#{ lib }.gemspec", "w"){|fd| fd.puts template}
90
+ This.gemspec = "#{ lib }.gemspec"
91
+ end
92
+
93
+ task :gem => [:clean, :gemspec] do
94
+ Fu.mkdir_p This.pkgdir
95
+ before = Dir['*.gem']
96
+ cmd = "gem build #{ This.gemspec }"
97
+ `#{ cmd }`
98
+ after = Dir['*.gem']
99
+ gem = ((after - before).first || after.first) or abort('no gem!')
100
+ Fu.mv gem, This.pkgdir
101
+ This.gem = File.basename(gem)
102
+ end
103
+
104
+ task :readme do
105
+ samples = ''
106
+ prompt = '~ > '
107
+ lib = This.lib
108
+ version = This.version
109
+
110
+ Dir['sample*/*'].sort.each do |sample|
111
+ samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
112
+
113
+ cmd = "cat #{ sample }"
114
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
115
+ samples << Util.indent(`#{ cmd }`, 4) << "\n"
116
+
117
+ cmd = "ruby #{ sample }"
118
+ samples << Util.indent(prompt + cmd, 2) << "\n\n"
119
+
120
+ cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -Ilib #{ sample })'"
121
+ samples << Util.indent(`#{ cmd } 2>&1`, 4) << "\n"
122
+ end
123
+
124
+ template =
125
+ if test(?e, 'readme.erb')
126
+ Template{ IO.read('readme.erb') }
127
+ else
128
+ Template {
129
+ <<-__
130
+ NAME
131
+ #{ lib }
132
+
133
+ DESCRIPTION
134
+
135
+ INSTALL
136
+ gem install #{ lib }
137
+
138
+ SAMPLES
139
+ #{ samples }
140
+ __
141
+ }
142
+ end
143
+
144
+ open("README", "w"){|fd| fd.puts template}
145
+ end
146
+
147
+
148
+ task :clean do
149
+ Dir[File.join(This.pkgdir, '**/**')].each{|entry| Fu.rm_rf(entry)}
150
+ end
151
+
152
+
153
+ task :release => [:clean, :gemspec, :gem] do
154
+ gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
155
+ raise "which one? : #{ gems.inspect }" if gems.size > 1
156
+ raise "no gems?" if gems.size < 1
157
+ cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.pkgdir }/#{ This.gem }"
158
+ puts cmd
159
+ system cmd
160
+ end
161
+
162
+
163
+
164
+
165
+
166
+ BEGIN {
167
+ $VERBOSE = nil
168
+
169
+ require 'ostruct'
170
+ require 'erb'
171
+ require 'fileutils'
172
+
173
+ Fu = FileUtils
174
+
175
+ This = OpenStruct.new
176
+
177
+ This.file = File.expand_path(__FILE__)
178
+ This.dir = File.dirname(This.file)
179
+ This.pkgdir = File.join(This.dir, 'pkg')
180
+
181
+ lib = ENV['LIB'] || 'growltdf'
182
+ unless lib
183
+ lib = File.basename(Dir.pwd)
184
+ end
185
+ This.lib = lib
186
+
187
+ version = ENV['VERSION'] || '0.4.2'
188
+ unless version
189
+ name = lib.capitalize
190
+ require "./lib/#{ lib }"
191
+ version = eval(name).send(:version)
192
+ end
193
+ This.version = version
194
+
195
+ abort('no lib') unless This.lib
196
+ abort('no version') unless This.version
197
+
198
+ module Util
199
+ def indent(s, n = 2)
200
+ s = unindent(s)
201
+ ws = ' ' * n
202
+ s.gsub(%r/^/, ws)
203
+ end
204
+
205
+ def unindent(s)
206
+ indent = nil
207
+ s.each do |line|
208
+ next if line =~ %r/^\s*$/
209
+ indent = line[%r/^\s*/] and break
210
+ end
211
+ indent ? s.gsub(%r/^#{ indent }/, "") : s
212
+ end
213
+ extend self
214
+ end
215
+
216
+ class Template
217
+ def initialize(&block)
218
+ @block = block
219
+ @template = block.call.to_s
220
+ end
221
+ def expand(b=nil)
222
+ ERB.new(Util.unindent(@template)).result(b||@block)
223
+ end
224
+ alias_method 'to_s', 'expand'
225
+ end
226
+ def Template(*args, &block) Template.new(*args, &block) end
227
+
228
+ Dir.chdir(This.dir)
229
+ }
data/bin/growltdf ADDED
@@ -0,0 +1,188 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ #
4
+ # growltdf is the greatest program evar. it let's you scrape
5
+ # http://cyclingnews.com for TDF updates and dump them into growl to you can
6
+ # keep up with the race while working.
7
+ #
8
+ # . to install this code
9
+ #
10
+ # - sudo gem install growltdf
11
+ #
12
+ # . to run you need to enable your growl prefpane to look like this
13
+ #
14
+ # http://s3.amazonaws.com/drawohara.com.screenshots/growltdf-prefpane.png
15
+ #
16
+ # if you set a password you'll need to supply to the program when run.
17
+ #
18
+ # . to run
19
+ #
20
+ # without password
21
+ #
22
+ # growltdf
23
+ #
24
+ # with password
25
+ #
26
+ # growltdf --growl-password=password
27
+ #
28
+
29
+ Main {
30
+ option('stage'){
31
+ argument :required
32
+ default :latest
33
+ }
34
+
35
+ option('growl-password'){
36
+ argument :required
37
+ }
38
+
39
+ def run
40
+ setup_growl
41
+
42
+ loop do
43
+ determine_the_current_stage
44
+ get_the_latest_live_entries
45
+ get_the_previous_live_entries
46
+ compare_them
47
+ growl_updated_live_entries
48
+ store_updated_live_entires
49
+ wait_a_little_while
50
+ end
51
+ end
52
+
53
+ def setup_growl
54
+ @growl =
55
+ Growl.new(
56
+ 'localhost', 'growltdf', %w[ race stage ],
57
+ default_notifies=nil, params['growl-password'].value
58
+ )
59
+ end
60
+
61
+ def determine_the_current_stage
62
+ @stage ||= nil
63
+ stage = param['stage']
64
+ if stage.given? and stage.value != :latest
65
+ @stage = Integer(stage.value)
66
+ else
67
+ today = Time.now.utc
68
+ if today.month == 7
69
+ stage = today.day - 3
70
+ if (1..21).include?(stage)
71
+ if @stage != stage
72
+ @growl.notify 'stage', "Stage #{ stage }"
73
+ end
74
+ @stage = stage
75
+ end
76
+ end
77
+ end
78
+ abort 'no stage' unless @stage
79
+ end
80
+
81
+ def get_the_latest_live_entries
82
+ stage_url = stage_url_for(@stage)
83
+ dom = dom_for(stage_url)
84
+ live_entries = dom.search('#live_entries')
85
+ @latest_live_entries =
86
+ live_entries.search('li').map do |li|
87
+ title = li.search('h3').inner_text.strip
88
+ content = li.search('p').inner_text.strip
89
+ [title, content]
90
+ end.reverse
91
+ end
92
+
93
+ def get_the_previous_live_entries
94
+ Db.transaction do
95
+ Db[@stage] ||= []
96
+ @previous_live_entries = Db[@stage]
97
+ end
98
+ end
99
+
100
+ def compare_them
101
+ @updated_entries = @latest_live_entries - @previous_live_entries
102
+ end
103
+
104
+ def growl_updated_live_entries
105
+ if @previous_live_entries.empty?
106
+ unless @latest_live_entries.empty?
107
+ @growl.notify 'stage', "TDF", "Stage #{ @stage } has started."
108
+ end
109
+ if @latest_live_entries.size > 10
110
+ @growl.notify 'race', "TDF", "#{ @latest_live_entries.size - 10 } updates..."
111
+ end
112
+ end
113
+ @updated_entries.last(10).each do |update|
114
+ title, content, *ignored = Array(update)
115
+ @growl.notify 'race', title.to_s, content.to_s
116
+ end
117
+ end
118
+
119
+ def store_updated_live_entires
120
+ Db.transaction do
121
+ Db[@stage] = @latest_live_entries
122
+ end
123
+ end
124
+
125
+ def wait_a_little_while
126
+ sleep 3
127
+ end
128
+
129
+ def stage_url_for(stage)
130
+ "http://www.cyclingnews.com/races/96th-tour-de-france-gt/stages/stage-#{ stage }/live-report"
131
+ end
132
+
133
+ def get(url)
134
+ open(url){|socket| socket.read}
135
+ rescue Exception
136
+ nil
137
+ end
138
+
139
+ def dom_for(url)
140
+ html = get(url)
141
+ return nil unless html
142
+ Nokogiri::HTML(html)
143
+ rescue Exception
144
+ nil
145
+ end
146
+
147
+ def head(url)
148
+ uri = URI.parse(url.to_s)
149
+ Net::HTTP.start(uri.host, uri.port){|http| http.head(uri.path)}
150
+ rescue
151
+ return false
152
+ end
153
+ }
154
+
155
+ BEGIN {
156
+ require 'pathname'
157
+ Pn = Pathname
158
+
159
+ require 'fileutils'
160
+ Fu = FileUtils
161
+
162
+ require 'uri'
163
+ require 'net/http'
164
+ require 'open-uri'
165
+
166
+ require 'yaml'
167
+ require 'yaml/store'
168
+
169
+ require 'rubygems'
170
+ begin
171
+ require 'main'
172
+ rescue LoadError
173
+ abort "sudo gem intall main"
174
+ end
175
+ begin
176
+ require 'ruby-growl'
177
+ rescue LoadError
178
+ abort "sudo gem intall ruby-growl"
179
+ end
180
+ begin
181
+ require 'nokogiri'
182
+ rescue LoadError
183
+ abort "sudo gem intall nokogiri"
184
+ end
185
+
186
+ Home = Pn.new('~').expand_path.realpath
187
+ Db = YAML::Store.new(Home.join('.growltdf.yml').to_s)
188
+ }
data/growltdf.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ ## growltdf.gemspec
2
+ #
3
+
4
+ Gem::Specification::new do |spec|
5
+ spec.name = "growltdf"
6
+ spec.version = "0.4.2"
7
+ spec.platform = Gem::Platform::RUBY
8
+ spec.summary = "growltdf"
9
+
10
+ spec.files = ["bin", "bin/growltdf", "growltdf.gemspec", "Rakefile"]
11
+ spec.executables = ["growltdf"]
12
+
13
+ spec.require_path = "lib"
14
+
15
+ spec.has_rdoc = true
16
+ spec.test_files = nil
17
+ spec.add_dependency 'main'
18
+ spec.add_dependency 'ruby-growl'
19
+ spec.add_dependency 'nokogiri'
20
+
21
+ spec.extensions.push(*[])
22
+
23
+ spec.rubyforge_project = "codeforpeople"
24
+ spec.author = "Ara T. Howard"
25
+ spec.email = "ara.t.howard@gmail.com"
26
+ spec.homepage = "http://github.com/ahoward/growltdf/tree/master"
27
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: growltdf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.2
5
+ platform: ruby
6
+ authors:
7
+ - Ara T. Howard
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-06 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: main
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: ruby-growl
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: nokogiri
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ description:
46
+ email: ara.t.howard@gmail.com
47
+ executables:
48
+ - growltdf
49
+ extensions: []
50
+
51
+ extra_rdoc_files: []
52
+
53
+ files:
54
+ - bin
55
+ - bin/growltdf
56
+ - growltdf.gemspec
57
+ - Rakefile
58
+ has_rdoc: true
59
+ homepage: http://github.com/ahoward/growltdf/tree/master
60
+ post_install_message:
61
+ rdoc_options: []
62
+
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: "0"
76
+ version:
77
+ requirements: []
78
+
79
+ rubyforge_project: codeforpeople
80
+ rubygems_version: 1.3.1
81
+ signing_key:
82
+ specification_version: 2
83
+ summary: growltdf
84
+ test_files: []
85
+