beer_in_the_evening 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -9,6 +9,7 @@ Wrong.
9
9
 
10
10
  require 'beer_in_the_evening'
11
11
  search = BeerInTheEvening::Search.new
12
+ search.maximum_results = 10
12
13
  search.tube_station = BeerInTheEvening::Location::Tube::HOLBORN
13
14
  search.minimum_rating = 6
14
15
  search.real_ale = true
@@ -18,6 +19,7 @@ Wrong.
18
19
  random_pub.to_s
19
20
  # => "Lord Clyde, 2.2 miles, 6.7 / 10, http://beerintheevening.com/pubs/s/65/6501/Lord_Clyde/Canonbury"
20
21
 
22
+ There are a few more examples in the `examples/` directory.
21
23
 
22
24
  ## Authors
23
25
 
@@ -19,4 +19,5 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  s.add_runtime_dependency "nokogiri"
22
+ s.add_runtime_dependency "null_logger"
22
23
  end
@@ -0,0 +1,15 @@
1
+ require 'beer_in_the_evening'
2
+ require 'logger'
3
+
4
+ STDOUT.sync = true
5
+ logger = Logger.new STDOUT
6
+ search = BeerInTheEvening::Search.new :logger => logger
7
+ search.tube_station = BeerInTheEvening::Location::Tube::HOLBORN
8
+ search.maximum_results = 5
9
+ search.minimum_rating = 6
10
+ search.real_ale = true
11
+ search.wifi = true
12
+ search.food = true
13
+ search.each do |pub|
14
+ puts pub.to_s
15
+ end
@@ -0,0 +1,13 @@
1
+ require 'beer_in_the_evening'
2
+ require 'logger'
3
+
4
+ STDOUT.sync = true
5
+ logger = Logger.new STDOUT
6
+ search = BeerInTheEvening::Search.new :logger => logger
7
+ search.postcode = 'SE1 1EY'
8
+ search.maximum_results = 5
9
+ search.minimum_rating = 6
10
+ search.wifi = true
11
+ search.each do |pub|
12
+ puts pub.to_s
13
+ end
@@ -1,33 +1,45 @@
1
1
  module BeerInTheEvening
2
2
  class Pub
3
+ attr_accessor :data
4
+ private :data=
5
+
3
6
  def initialize data
4
- @data = data
7
+ self.data = data
8
+ end
9
+
10
+ def distance_known?
11
+ !distance.nil?
5
12
  end
6
13
 
7
14
  def name
8
- @data.css("td b a:first-child")[0].inner_text.to_s
15
+ data.css("td b a:first-child")[0].inner_text.to_s.strip
9
16
  end
10
17
 
11
18
  def url
12
- "http://beerintheevening.com" + @data.css("td b a:first-child")[0]['href'].to_s
19
+ "http://beerintheevening.com" + self.data.css("td b a:first-child")[0]['href'].to_s
13
20
  end
14
21
 
15
- def rating
16
- results = @data.css("td:nth-child(3)")[0].inner_text.scan /Rating:(.*)\/10/
17
- results[0][0].to_f if results[0]
22
+ def rating_column
23
+ distance_known? ? 3 : 2
18
24
  end
19
25
 
20
- def visited?
21
- Meetup.exists? self
26
+ def rating
27
+ results = data.css("td:nth-child(#{rating_column})")[0].inner_text.scan /Rating:(.*)\/10/
28
+ results[0][0].to_f if results[0]
22
29
  end
23
30
 
24
31
  def distance
25
- results = @data.css("td:nth-child(2)")[0].inner_text.scan /Distance:(.*)miles/
32
+ results = data.css("td:nth-child(2)")[0].inner_text.scan /Distance:(.*)miles/
26
33
  results[0][0].to_f if results[0]
34
+ rescue
27
35
  end
28
36
 
29
37
  def to_s
30
- [ name, "#{distance} miles", "#{rating} / 10", url ].join ', '
38
+ if distance_known?
39
+ [ name, "#{distance} miles", "#{rating} / 10", url ]
40
+ else
41
+ [ name, "#{rating} / 10", url ]
42
+ end.join ', '
31
43
  end
32
44
  end
33
45
  end
@@ -1,11 +1,26 @@
1
1
  module BeerInTheEvening
2
2
  class Search
3
+ class << self
4
+ attr_accessor :maximum_cache_ttl
5
+ end
6
+ # Invalidate the cache at least every 28 days
7
+ self.maximum_cache_ttl = 86400 * 28
8
+
9
+ attr_accessor :postcode
3
10
  attr_accessor :tube_station
4
11
  attr_accessor :real_ale
5
12
  attr_accessor :food
6
13
  attr_accessor :wifi
7
14
  attr_accessor :minimum_rating
8
15
 
16
+ attr_accessor :maximum_results
17
+
18
+ attr_accessor :logger
19
+
20
+ def initialize options = {}
21
+ self.logger = options[:logger] || NullLogger.instance
22
+ end
23
+
9
24
  def number_of_results
10
25
  matches = page(0).to_s.scan /showing \d+ to \d+ of (\d+)/
11
26
  matches[0][0].to_i
@@ -13,18 +28,36 @@ module BeerInTheEvening
13
28
 
14
29
  def each &block
15
30
  current_page = 0
31
+ results_total = 0
16
32
  loop do
33
+ logger.debug "Finding next set of results"
17
34
  results = results_on_page current_page
18
35
  break if results.empty?
36
+ if maximum_results
37
+ while results_total + results.size > maximum_results do
38
+ logger.debug "Trimming results. Max = #{maximum_results}, Current = #{results_total + results.size}"
39
+ results.pop
40
+ end
41
+ end
42
+ logger.debug "Yielding #{results.size} pubs to client"
19
43
  results.each &block
44
+ logger.debug "Client code finished"
20
45
  current_page += 1
46
+ results_total += results.size
47
+ break if maximum_results && results_total >= maximum_results
21
48
  end
22
49
  end
23
50
  include Enumerable
24
51
 
52
+ def escaped_postcode
53
+ CGI.escape postcode
54
+ end
55
+ private :escaped_postcode
56
+
25
57
  def query_string
26
58
  params = []
27
59
  params << "tu=#{tube_station}" if tube_station
60
+ params << "postcode=#{escaped_postcode}" if postcode
28
61
  params << "ra=on" if real_ale
29
62
  params << "f=on" if food
30
63
  params << "wireless=on" if wifi
@@ -35,30 +68,54 @@ module BeerInTheEvening
35
68
 
36
69
  def page n
37
70
  uri = "http://www.beerintheevening.com/pubs/results.shtml?#{query_string}&page=#{n}"
71
+ logger.debug "Page #{n} of results will be at #{uri}"
38
72
  content = read_cache uri do
73
+ logger.debug "Fetching #{uri}"
39
74
  open(uri).read
40
75
  end
76
+ logger.debug "Building document from HTML data"
41
77
  doc = Nokogiri::HTML content
42
78
  end
43
79
  private :page
44
80
 
81
+ def cache_generation
82
+ Time.now.to_i / self.class.maximum_cache_ttl.to_i
83
+ end
84
+ private :cache_generation
85
+
86
+ def cache_prefix
87
+ "beer_in_the_evening-#{BeerInTheEvening::VERSION}-#{self.class.maximum_cache_ttl.to_i}-#{cache_generation}"
88
+ end
89
+ private :cache_prefix
90
+
45
91
  def read_cache uri
46
- cache_dir = Dir.tmpdir + "/beer_in_the_evening-#{BeerInTheEvening::VERSION}"
92
+ cache_dir = Dir.tmpdir + "/#{cache_prefix}"
47
93
  Dir.mkdir cache_dir unless File.exists? cache_dir
48
94
  cache_file_name = "#{cache_dir}/#{Digest::SHA1.hexdigest(uri)}.html"
49
- return File.read(cache_file_name) if File.exists? cache_file_name
95
+ if File.exists? cache_file_name
96
+ logger.debug "Found #{uri} in cache at #{cache_file_name}"
97
+ return File.read cache_file_name
98
+ end
99
+ logger.debug "Did not find #{uri} in cache"
50
100
  data = yield
101
+ logger.debug "Data is #{data.bytesize}b"
102
+ logger.debug "Adding #{uri} to cache as #{cache_file_name}"
51
103
  File.open cache_file_name, 'w+' do |f|
52
104
  f.puts data
53
105
  end
106
+ logger.debug "Returning data"
54
107
  data
55
108
  end
56
109
  private :read_cache
57
110
 
58
111
  def results_on_page n
59
- page(n).css('table.pubtable tr.pubtable').to_a.map { |row|
112
+ rows = page(n).css('table.pubtable tr.pubtable').to_a
113
+ logger.debug "Found #{rows.size} results on page #{n}"
114
+ rows.map! { |row|
60
115
  Pub.new row
61
116
  }
117
+ logger.debug "Returning results as pubs"
118
+ rows
62
119
  end
63
120
  private :results_on_page
64
121
  end
@@ -1,3 +1,3 @@
1
1
  module BeerInTheEvening
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -2,6 +2,8 @@ require "nokogiri"
2
2
  require "open-uri"
3
3
  require "digest/sha1"
4
4
  require "tmpdir"
5
+ require "null_logger"
6
+ require "cgi"
5
7
 
6
8
  require "beer_in_the_evening/version"
7
9
  require "beer_in_the_evening/pub"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beer_in_the_evening
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-01 00:00:00.000000000Z
12
+ date: 2012-09-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
16
- requirement: &70318119693620 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,28 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70318119693620
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: null_logger
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
25
46
  description: Search over the Beer In The Evening site looking for suitable pubs
26
47
  email:
27
48
  - craig@barkingiguana.com
@@ -34,6 +55,8 @@ files:
34
55
  - README.md
35
56
  - Rakefile
36
57
  - beer_in_the_evening.gemspec
58
+ - examples/near_holborn.rb
59
+ - examples/near_postcode.rb
37
60
  - lib/beer_in_the_evening.rb
38
61
  - lib/beer_in_the_evening/location/dlr.rb
39
62
  - lib/beer_in_the_evening/location/tube.rb
@@ -60,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
83
  version: '0'
61
84
  requirements: []
62
85
  rubyforge_project: beer_in_the_evening
63
- rubygems_version: 1.8.10
86
+ rubygems_version: 1.8.24
64
87
  signing_key:
65
88
  specification_version: 3
66
89
  summary: Is it pub time?