beer_list 0.1.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- beer_list (0.1.2)
5
- mechanize (= 2.6.0)
4
+ beer_list (0.1.3)
5
+ mechanize (~> 2.6.0)
6
+ thor (~> 0.18.1)
6
7
 
7
8
  GEM
8
9
  specs:
@@ -30,6 +31,7 @@ GEM
30
31
  rspec-expectations (2.12.1)
31
32
  diff-lcs (~> 1.1.3)
32
33
  rspec-mocks (2.12.2)
34
+ thor (0.18.1)
33
35
  unf (0.1.1)
34
36
  unf_ext
35
37
  unf_ext (0.0.6)
@@ -41,4 +43,4 @@ PLATFORMS
41
43
  DEPENDENCIES
42
44
  beer_list!
43
45
  bundler (~> 1.3)
44
- rspec
46
+ rspec (~> 2.12.0)
data/README.md CHANGED
@@ -29,6 +29,22 @@ list.to_hash
29
29
  list.to_json
30
30
  ```
31
31
 
32
+ ### Establishments
33
+
34
+ Establishments peddle delicious beers. You're interested in which delicious beers a
35
+ given establishment is peddling. To reconcile this situation, you need one or more
36
+ BeerList::Establishments. BeerList ships with a limited number of establishments,
37
+ but its easy to [extend BeerList](#extending-beerlist-with-more-establishments) with more.
38
+
39
+ First, let's try one out of the box:
40
+
41
+ ```
42
+ bulldog_northeast = BeerList::Establishments::BulldogNortheast.new
43
+
44
+ # Now get the list
45
+ bulldog_northeast.list
46
+ ```
47
+
32
48
  You may want to get lists for more than one establishment at a time. To do so, register
33
49
  the desired establishments in BeerList.establishments:
34
50
 
@@ -47,23 +63,22 @@ BeerList.establishments
47
63
  BeerList.lists
48
64
 
49
65
  # As a hash
50
- BeerList.list_as_hash
66
+ BeerList.lists_as_hash
51
67
 
52
68
  # As JSON
53
- BeerList.list_as_json
69
+ BeerList.lists_as_json
54
70
  ```
55
71
 
56
72
  The Lists will be memoized until the content of BeerList.establishments changes so that
57
- The establishments don't have to be re-scraped each time the list is requested.
73
+ the establishments don't have to be re-scraped each time the list is requested.
58
74
 
59
75
  ### Extending BeerList with More Establishments
60
76
 
61
- BeerList ships with a limited number of establishments, but also includes an executable
62
- to easily create your own.
77
+ BeerList includes an executable to easily create your own establishments.
63
78
 
64
79
  For example:
65
80
 
66
- `beer_list establish Applebirds -u http://applebirds.com/beers -d path/to/establishments`
81
+ `$ beer_list establish Applebirds -u http://applebirds.com/beers -d path/to/establishments`
67
82
 
68
83
  will create the following code in path/to/establishments/applebirds.rb
69
84
 
@@ -92,7 +107,7 @@ end
92
107
 
93
108
  For all options you can pass to beer_list establish, run:
94
109
 
95
- `beer_list --help`
110
+ `$ beer_list help`
96
111
 
97
112
  ### Using Your Generated Establishments
98
113
 
@@ -116,8 +131,54 @@ BeerList.lists
116
131
 
117
132
  ```
118
133
 
119
- See [Getting A List](https://github.com/DanOlson/beer_list#getting-a-list) for more details.
134
+ See [Getting A List](#getting-a-list) for more details.
120
135
 
121
136
  AND...
122
137
 
123
138
  Checkout [This link](http://mechanize.rubyforge.org/) for more on Mechanize
139
+
140
+ ### Leads
141
+
142
+ If you're out of ideas on what establishments you may want lists for, fear not: BeerList can
143
+ give you some ideas.
144
+
145
+ ```
146
+ # You might be interested in good beer bars located in California:
147
+ cali = BeerList::Leads::CA.new
148
+
149
+ # returns a BeerList::List of URLs for popular beer bars in California
150
+ cali.list
151
+
152
+
153
+ # Maybe you want Wisconsin:
154
+ wi = BeerList::Leads:WI.new
155
+
156
+ wi.list
157
+
158
+ ```
159
+
160
+ So far, support for this feature is limited to the United States. Hopefully, I can expand
161
+ it in the not-too-distant future.
162
+
163
+ ### CLI
164
+
165
+ In addition to the [establish](#extending-beerlist-with-more-establishments) command, which
166
+ generates Establishment files for you, BeerList also offers the `list` command. For example,
167
+ say you have the following two establishments a directory called ~/my_beer_lists:
168
+
169
+ ```
170
+ BeerList::Establishments::Applebirds
171
+ BeerList::Establishments::Thursdays
172
+ ```
173
+
174
+ You can get the beer lists for these places from the command line:
175
+
176
+ ```
177
+ $ beer_list list applebirds -d ~/my_beer_lists
178
+
179
+ # or
180
+ $ beer_list list applebirds thursdays -d ~/my_beer_lists
181
+
182
+ # pass -j for JSON
183
+ $ beer_list list applebirds thursdays -j -d ~/my_beer_lists
184
+ ```
data/beer_list.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = 'beer_list'
3
- spec.version = '0.1.3'
3
+ spec.version = '1.0.0'
4
4
  spec.authors = ['Dan Olson']
5
5
  spec.email = ['olson_dan@yahoo.com']
6
6
  spec.description = 'A utility for retrieving the beer list from various establishments'
@@ -13,7 +13,8 @@ Gem::Specification.new do |spec|
13
13
  spec.test_files = spec.files.grep(%r{^(spec)/})
14
14
  spec.require_paths = ['lib']
15
15
 
16
- spec.add_dependency 'mechanize', '2.6.0'
16
+ spec.add_dependency 'mechanize', '~> 2.6.0'
17
+ spec.add_dependency 'thor', '~> 0.18.1'
17
18
  spec.add_development_dependency 'bundler', '~> 1.3'
18
- spec.add_development_dependency 'rspec'
19
+ spec.add_development_dependency 'rspec', '~> 2.12.0'
19
20
  end
data/lib/beer_list/cli.rb CHANGED
@@ -1,65 +1,59 @@
1
- require 'optparse'
1
+ require 'thor'
2
2
 
3
3
  module BeerList
4
- class CLI
5
- COMMANDS = %w(establish)
6
-
7
- class << self
8
- def start(args)
9
- options = parse ARGV
10
-
11
- msg = ARGV[0]
12
- abort unsupported_command unless COMMANDS.include? msg
13
-
14
- new(options).public_send msg
15
- end
16
-
17
- def parse(args)
18
- options = {}
19
-
20
- opts = OptionParser.new do |opts|
21
- opts.banner = "Usage: beer_list establish [options]"
22
-
23
- opts.on("-u", "--url [URL]", "url of your establishment's beer list") do |url|
24
- options[:url] = url
25
- end
26
-
27
- opts.on("-s", "--selector [SELECTOR]", "selector to use for scraping") do |s|
28
- options[:selector] = s
29
- end
4
+ class CLI < Thor
5
+ option :url,
6
+ aliases: '-u',
7
+ banner: "The URL of your establishment's beer list"
8
+ option :directory,
9
+ required: true,
10
+ aliases: '-d',
11
+ banner: 'The directory in which BeerList will put your establishments'
12
+ option :selector,
13
+ aliases: '-s',
14
+ banner: 'Optional selector to use for scraping'
15
+
16
+ desc 'establish ESTABLISHMENT', 'Generate a subclass of BeerList::Establishments::Establishment in the given directory'
17
+ def establish(klass)
18
+ # Support underscore and camelcase
19
+ klass = klass.split('_').map(&:capitalize).join if klass.match(/_/)
20
+ BeerList::EstablishmentGenerator.new(klass, options)
21
+ end
30
22
 
31
- opts.on("-d", "--directory DIR", "the directory in which BeerList will put your establishments") do |dir|
32
- options[:dir] = dir
33
- end
23
+ option :directory,
24
+ aliases: '-d',
25
+ banner: 'The directory where your establishments are stored'
26
+ option :json,
27
+ aliases: '-j',
28
+ type: :boolean,
29
+ banner: 'Format output as JSON'
30
+
31
+ desc 'list ESTABLISHMENTS', 'Retrieve the beer list at the given establishments'
32
+ def list(*establishments)
33
+ BeerList.establishments_dir = options[:directory]
34
+ BeerList.add_establishments *classify(establishments)
35
+ if options[:json]
36
+ puts BeerList.lists_as_json
37
+ else
38
+ BeerList.lists.each do |list|
39
+ puts '*' * (list.establishment.size + 10)
40
+ puts "**** #{list.establishment} ****"
41
+ puts '*' * (list.establishment.size + 10)
42
+ puts
43
+ puts list
44
+ puts
34
45
  end
35
-
36
- opts.parse! args
37
- options
38
- end
39
-
40
- def unsupported_command
41
- <<-WARN
42
- Command: not supported. Must be one of the following:
43
- #{COMMANDS.join(', ')}
44
- WARN
45
- end
46
-
47
- def no_establishments_dir
48
- <<-WARN
49
- You must supply an establishments directory with -d or --directory
50
- WARN
51
46
  end
52
47
  end
53
48
 
54
- def initialize(args)
55
- @args = args
56
- end
49
+ private
57
50
 
58
- def establish(klass=ARGV[1])
59
- abort self.class.no_establishments_dir unless @args[:dir]
60
- # Support underscore and camelcase
61
- klass = klass.split('_').map(&:capitalize).join if klass.match(/_/)
62
- BeerList::EstablishmentGenerator.new(klass, @args)
51
+ def classify(establishments)
52
+ establishments.map do |est|
53
+ class_name = est.to_s.split('_').map(&:capitalize).join
54
+ klass = BeerList.send(:get_class_with_namespace, class_name)
55
+ klass.new
56
+ end
63
57
  end
64
58
  end
65
59
  end
@@ -0,0 +1,31 @@
1
+ module BeerList
2
+ module Establishments
3
+ class AcadiaCafe < Establishment
4
+ URL = 'http://acadiacafe.com/as_beer-menu-and-happy-hour-specials'
5
+
6
+ def get_list
7
+ base_list
8
+ having_price_and_abv
9
+ match_before_comma
10
+ end
11
+
12
+ def url
13
+ URL
14
+ end
15
+
16
+ private
17
+
18
+ def base_list
19
+ @acadia = page.search('p').map(&:text)
20
+ end
21
+
22
+ def having_price_and_abv
23
+ @acadia = @acadia.select{ |str| str.match(/\d{1,2}\.\d{1,2}%+.*\$+/) }
24
+ end
25
+
26
+ def match_before_comma
27
+ @acadia = @acadia.map{ |b| b.match(/,{1}/); $` }.reject(&:nil?).map(&:strip)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,55 @@
1
+ module BeerList
2
+ module Establishments
3
+ class BlueNile < Establishment
4
+ RESTAURANT_NAME = 'Blue Nile'
5
+ URL = 'http://www.bluenilempls.com/bar-b.html'
6
+
7
+ def get_list
8
+ base_list
9
+ trim
10
+ end
11
+
12
+ def url
13
+ URL
14
+ end
15
+
16
+ private
17
+
18
+ def headers
19
+ @headers ||= remove_carraige_and_strip(page.search('.style5').map(&:text))
20
+ end
21
+
22
+ def base_list
23
+ @beers = remove_carraige_and_strip(page.search('p').map(&:text)).reject{ |b| headers.include? b }
24
+ remove_contact_info
25
+ end
26
+
27
+ def trim
28
+ trim_cost_and_origin
29
+ trim_volume
30
+ reject_non_word_entries
31
+ end
32
+
33
+ def trim_cost_and_origin
34
+ @beers = @beers.map{ |b| b.split('(').first }.map{ |b| b.split(' $').first }
35
+ end
36
+
37
+ def trim_volume
38
+ @beers = @beers.map{ |b| b.match(/,?\s?\d+\s?(ml|oz|0z)/) ? $`.strip : b.strip }
39
+ end
40
+
41
+ def reject_non_word_entries
42
+ @beers = @beers.reject{ |b| b.match /\A\W\z/ }
43
+ end
44
+
45
+ def remove_contact_info
46
+ index = @beers.index(RESTAURANT_NAME)
47
+ @beers.pop @beers.size - index
48
+ end
49
+
50
+ def remove_carraige_and_strip(ary)
51
+ ary.map{ |b| b.split("\r").map(&:strip) }.flatten.reject(&:empty?)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,54 @@
1
+ module BeerList
2
+ module Establishments
3
+ class BustersOn28th < Establishment
4
+ URL = 'http://busterson28th.com/bottles/'
5
+
6
+ def get_list
7
+ base_list
8
+ split_on_newline
9
+ reject_headers
10
+ match_pre_vol
11
+ reject_nils
12
+ end
13
+
14
+ def url
15
+ URL
16
+ end
17
+
18
+ private
19
+
20
+ def base_list
21
+ @busters = page.search('p').map(&:text)
22
+ end
23
+
24
+ def split_on_newline
25
+ @busters = @busters.map{ |beer| beer.split("\n") }.flatten
26
+ end
27
+
28
+ # First, select all entries that have a lowercase letter (headers do not)
29
+ # At that point, there are still some headers mixed with beer names.
30
+ # For example:
31
+ #
32
+ # STOUTSurly Darkness
33
+ #
34
+ # Match group 3 or more capital letters followed by one cap and one lower
35
+ # take the portion of the beer name after the match group
36
+ def reject_headers
37
+ @busters = @busters.select{ |beer| beer.match /[a-z]/ }
38
+ @busters = @busters.map do |beer|
39
+ beer.match(/([A-Z]{3,})[A-Z]{1}[a-z]{1}/) ? beer.split($1).last : beer
40
+ end
41
+ end
42
+
43
+ def match_pre_vol
44
+ @busters = @busters.map do |beer|
45
+ beer.match(/\d{1,2}\.?\d*\s*oz/) ? $`.strip : nil
46
+ end
47
+ end
48
+
49
+ def reject_nils
50
+ @busters = @busters.reject(&:nil?)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,12 +1,7 @@
1
1
  module BeerList
2
2
  module Establishments
3
3
  class Establishment
4
- attr_accessor :scraper, :page
5
-
6
- def list
7
- raise BeerList::NoScraperError unless @scraper
8
- @list ||= BeerList::List.new establishment: short_class_name, array: get_list
9
- end
4
+ include BeerList::Listable
10
5
 
11
6
  def get_list
12
7
  raise "#{__method__} is not implemented in #{self.class.name}"
@@ -0,0 +1,50 @@
1
+ module BeerList
2
+ module Establishments
3
+ class HappyGnome < Establishment
4
+ attr_accessor :url
5
+
6
+ DRAFTS = 'http://thehappygnome.com/menus/drafts/'
7
+ BOTTLES = 'http://thehappygnome.com/menus/bottled-beers/'
8
+
9
+ def initialize
10
+ @url = DRAFTS
11
+ end
12
+
13
+ def get_list
14
+ get_draft_list
15
+ get_bottle_list
16
+ end
17
+
18
+ private
19
+
20
+ def get_the_list
21
+ base_list
22
+ match_before_paren
23
+ reject_empty
24
+ end
25
+
26
+ def get_draft_list
27
+ @beers = []
28
+ @beers += get_the_list
29
+ end
30
+
31
+ def get_bottle_list
32
+ self.url = BOTTLES
33
+ self.page = BeerList.scraper.visit self
34
+ @beers += get_the_list
35
+ end
36
+
37
+ def base_list
38
+ @happy_gnome = page.search('p').map(&:text)
39
+ end
40
+
41
+ def match_before_paren
42
+ @happy_gnome = @happy_gnome.map{ |b| b.match(/\(/); $` }
43
+ end
44
+
45
+ def reject_empty
46
+ @happy_gnome = @happy_gnome.reject(&:nil?).map(&:strip)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,31 @@
1
+ module BeerList
2
+ module Establishments
3
+ class LowryUptown < Establishment
4
+ URL = 'http://www.thelowryuptown.com/drink'
5
+
6
+ def get_list
7
+ base_list
8
+ match_before_abv
9
+ strip
10
+ end
11
+
12
+ def url
13
+ URL
14
+ end
15
+
16
+ private
17
+
18
+ def base_list
19
+ @beers = page.search('div.third_col').first.search('p').map(&:text)
20
+ end
21
+
22
+ def match_before_abv
23
+ @beers = @beers.map{ |beer| beer.match(/\d+\.?\d*%/); $` }.compact
24
+ end
25
+
26
+ def strip
27
+ @beers = @beers.map{ |beer| beer.gsub(/\A\W*|\W*\z/, '') }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ module BeerList
2
+ module Establishments
3
+ class MackenziePub < Establishment
4
+ URL = 'http://mackenziepub.com/drink/beer/'
5
+
6
+ def get_list
7
+ base_list
8
+ strip_leading_star
9
+ end
10
+
11
+ def url
12
+ URL
13
+ end
14
+
15
+ private
16
+
17
+ def base_list
18
+ @beers = page.search('div.menu-container-cell-description h4').map(&:text)
19
+ end
20
+
21
+ def strip_leading_star
22
+ @beers = @beers.map{ |beer| beer.gsub(/\A\*/, '') }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ module BeerList
2
+ module Establishments
3
+ class MacsIndustrial < Establishment
4
+ URL = 'http://www.macsindustrial.com/tap_page.php'
5
+
6
+ def get_list
7
+ build_list
8
+ end
9
+
10
+ def url
11
+ URL
12
+ end
13
+
14
+ private
15
+
16
+ def build_list
17
+ breweries.zip(beers).map{ |b| b.join(' ') }
18
+ end
19
+
20
+ def base_list
21
+ @macs ||= page.search('tr:first-child td:last-child')
22
+ end
23
+
24
+ def breweries
25
+ base_list.search('a strong').children.map(&:text)
26
+ end
27
+
28
+ def beers
29
+ base_list.search('span strong').children.map(&:text).map{ |b| b[1..-1] }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,15 @@
1
+ module BeerList
2
+ module Establishments
3
+ class MuddyPig < Establishment
4
+ URL = 'http://muddypig.com/beer/'
5
+
6
+ def get_list
7
+ page.search('p').last.text.split("\n")
8
+ end
9
+
10
+ def url
11
+ URL
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,52 @@
1
+ module BeerList
2
+ module Establishments
3
+ class NewBohemia < Establishment
4
+ URL = 'http://www.newbohemiausa.com/bier/'
5
+
6
+ def get_list
7
+ base_list
8
+ strip
9
+ end
10
+
11
+ def url
12
+ URL
13
+ end
14
+
15
+ private
16
+
17
+ def base_list
18
+ @beers = [left, right].inject([]) do |ary, collection|
19
+ ary += match_before_slash(collection).compact
20
+ end
21
+ end
22
+
23
+ def strip
24
+ @beers = @beers.map{ |beer| beer.gsub(/\A\W*|\W*\z/, '') }
25
+ end
26
+
27
+ def left
28
+ split_on_newline(left_column).flatten
29
+ end
30
+
31
+ def right
32
+ right_column
33
+ end
34
+
35
+ def left_column
36
+ page.search('div.col-left p').map(&:text)
37
+ end
38
+
39
+ def right_column
40
+ page.search('div.col-right p span').map(&:text)
41
+ end
42
+
43
+ def split_on_newline(beers)
44
+ beers.inject([]) { |ary, string| ary << string.split("\n") }
45
+ end
46
+
47
+ def match_before_slash(beers)
48
+ beers.map{ |beer| beer.match(/\A([^\/]+)\/{1}/); $1 }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,26 @@
1
+ module BeerList
2
+ module Establishments
3
+ class StanleysBarRoom < Establishment
4
+ URL = 'http://www.stanleysbarroom.com/drinks/beer-list/'
5
+
6
+ def get_list
7
+ base_list
8
+ remove_blank
9
+ end
10
+
11
+ def url
12
+ URL
13
+ end
14
+
15
+ private
16
+
17
+ def base_list
18
+ @beers = page.search('td ul li').map(&:text)
19
+ end
20
+
21
+ def remove_blank
22
+ @beers = @beers.map(&:strip).reject{ |beer| beer.empty? }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ module BeerList
2
+ module Establishments
3
+ class WashingtonSquare < Establishment
4
+ URL = 'http://www.washingtonsquareonline.net/as_on-tap'
5
+
6
+ def get_list
7
+ base_list
8
+ remove_facebook_plug
9
+ remove_nbsp
10
+ end
11
+
12
+ def url
13
+ URL
14
+ end
15
+
16
+ private
17
+
18
+ def base_list
19
+ @results = page.search('p strong').map(&:text)
20
+ end
21
+
22
+ def remove_facebook_plug
23
+ @results.shift
24
+ end
25
+
26
+ def remove_nbsp
27
+ @results = @results.map{ |b| b.gsub(/[[:space:]]{2,}/, '') }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,17 +1,11 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
-
3
1
  module BeerList
4
2
  module Establishments
5
- require 'establishments/establishment'
3
+ require 'beer_list/establishments/establishment.rb'
6
4
 
7
- Dir[File.dirname(__FILE__) + '/establishments/*.rb'].each do |f|
8
- require f.split('.rb').first
9
- end
5
+ Dir[File.dirname(__FILE__) + '/establishments/*.rb'].each { |f| require f }
10
6
 
11
7
  if BeerList.establishments_dir
12
- Dir[File.join(BeerList.establishments_dir, '*.rb')].each do |f|
13
- require f.split('.rb').first
14
- end
8
+ Dir[File.join(BeerList.establishments_dir, '*.rb')].each { |f| require f }
15
9
  end
16
10
  end
17
11
  end
@@ -6,11 +6,4 @@ module BeerList
6
6
  super msg
7
7
  end
8
8
  end
9
-
10
- class NoScraperError < StandardError
11
- def initialize(msg=nil)
12
- msg ||= "No scraper is registered"
13
- super msg
14
- end
15
- end
16
9
  end
@@ -0,0 +1,44 @@
1
+ module BeerList
2
+ module Leads
3
+ class BeerAdvocate
4
+ include BeerList::Listable
5
+
6
+ BEERFLY = 'http://beeradvocate.com/beerfly/list'
7
+ LEAD_INDICATOR_TEXT = 'official website'
8
+
9
+ def links
10
+ @links ||= []
11
+ pages
12
+ end
13
+ alias :get_list :links
14
+
15
+ def url
16
+ "#{BEERFLY}?c_id=US&s_id=#{short_class_name}&bar=Y"
17
+ end
18
+
19
+ private
20
+
21
+ def pages
22
+ @links += page.links_with(:text => LEAD_INDICATOR_TEXT).map(&:href)
23
+
24
+ if next_link = page.links_with(:text => /next/).first
25
+ self.page = next_link.click
26
+ pages
27
+ end
28
+ @links
29
+ end
30
+
31
+ def short_class_name
32
+ self.class.name.split('::').last
33
+ end
34
+ end
35
+
36
+ %w{
37
+ AL AK AZ AR CA CO CT DE FL GA HI ID IL IN IA KS KY
38
+ LA ME MD MA MI MN MS MO MT NE NV NH NJ NM NY NC ND
39
+ OH OK OR PA RI SC SD TN TX UT VT VA WA WV WI WY
40
+ }.each do |state|
41
+ const_set state, Class.new(BeerAdvocate)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,24 @@
1
+ module BeerList
2
+ module Listable
3
+ attr_accessor :page
4
+
5
+ def list
6
+ visit_page unless page
7
+ @list ||= BeerList::List.new establishment: short_class_name, array: get_list
8
+ end
9
+
10
+ def short_class_name
11
+ raise NotImplementedError
12
+ end
13
+
14
+ def get_list
15
+ raise NotImplementedError
16
+ end
17
+
18
+ private
19
+
20
+ def visit_page
21
+ BeerList.scraper.visit self
22
+ end
23
+ end
24
+ end
@@ -1,6 +1,8 @@
1
+ require 'singleton'
2
+
1
3
  module BeerList
2
4
  class Scraper
3
- attr_reader :agent, :url, :page
5
+ include Singleton
4
6
 
5
7
  USER_AGENT = 'Mac Safari'
6
8
 
@@ -10,19 +12,18 @@ module BeerList
10
12
  end
11
13
 
12
14
  def beer_list(establishment)
13
- establishment.scraper = self
14
- visit_site establishment
15
+ visit establishment
15
16
  establishment.list
16
17
  end
17
18
 
18
- private
19
-
20
- def visit_site(establishment)
21
- establishment.page = agent.get(establishment.url)
19
+ def visit(visitable)
20
+ visitable.page = @agent.get(visitable.url)
22
21
  end
23
22
 
23
+ private
24
+
24
25
  def set_user_agent
25
- agent.user_agent_alias = USER_AGENT
26
+ @agent.user_agent_alias = USER_AGENT
26
27
  end
27
28
  end
28
29
  end
data/lib/beer_list.rb CHANGED
@@ -8,6 +8,8 @@ module BeerList
8
8
  require 'beer_list/cli'
9
9
  require 'generators/establishment_generator'
10
10
  require 'ext/string'
11
+ require 'beer_list/listable'
12
+ require 'beer_list/leads/beer_advocate'
11
13
  autoload :Establishments, 'beer_list/establishments'
12
14
 
13
15
  class << self
@@ -55,12 +57,12 @@ module BeerList
55
57
  lists_as_hash.to_json
56
58
  end
57
59
 
58
- private
59
-
60
60
  def scraper
61
- @scraper ||= Scraper.new
61
+ @scraper ||= Scraper.instance
62
62
  end
63
63
 
64
+ private
65
+
64
66
  def update_necessary?
65
67
  !@lists || !establishments_eq_lists?
66
68
  end
@@ -76,8 +78,12 @@ module BeerList
76
78
 
77
79
  def method_missing(method, *args, &block)
78
80
  class_name = method.to_s.split('_').map(&:capitalize).join
79
- klass = ['BeerList', 'Establishments', class_name].inject(Object){ |o, name| o.const_get(name) }
81
+ klass = get_class_with_namespace class_name
80
82
  scraper.beer_list klass.new
81
83
  end
84
+
85
+ def get_class_with_namespace(class_name)
86
+ ['BeerList', 'Establishments', class_name].inject(Object){ |o, name| o.const_get(name) }
87
+ end
82
88
  end
83
89
  end
@@ -11,7 +11,7 @@ module BeerList
11
11
  @klass = klass
12
12
  @url = args[:url] || DEFAULT_URL
13
13
  @selector = args[:selector] || '.selector'
14
- @directory = args[:dir] || ESTABLISHMENTS_DIR
14
+ @directory = args[:directory] || ESTABLISHMENTS_DIR
15
15
  write_file
16
16
  end
17
17
 
@@ -4,25 +4,13 @@ module BeerList
4
4
  module Establishments
5
5
 
6
6
  describe Establishment do
7
- let(:establishment){ BeerList::Establishments::Establishment.new }
7
+ let(:establishment){ BeerList::Establishments::MuddyWaters.new }
8
8
 
9
9
  describe '#list' do
10
- context "when it doesn't have a scraper" do
11
- it "raises an exception" do
12
- expect { establishment.list }.to raise_error(NoScraperError)
13
- end
14
- end
15
-
16
- context 'when it has a scraper' do
17
-
18
- before do
19
- establishment.scraper = stub
20
- end
21
-
22
- it 'returns a BeerList::List' do
23
- establishment.stub(:get_list){ [] }
24
- establishment.list.should be_an_instance_of BeerList::List
25
- end
10
+ it 'returns a BeerList::List' do
11
+ establishment.stub(:visit_page)
12
+ establishment.stub(:get_list){ [] }
13
+ establishment.list.should be_an_instance_of BeerList::List
26
14
  end
27
15
  end
28
16
 
@@ -41,8 +29,6 @@ module BeerList
41
29
  end
42
30
 
43
31
  describe '#short_class_name' do
44
- let(:establishment){ BeerList::Establishments::MuddyWaters.new }
45
-
46
32
  it 'returns a usable name' do
47
33
  establishment.short_class_name.should == 'MuddyWaters'
48
34
  end
@@ -83,6 +83,7 @@ describe BeerList do
83
83
  end
84
84
 
85
85
  before do
86
+ establishment.stub(:visit_page)
86
87
  establishment.stub(:get_list){ ['Darkness', 'Pliney the Elder'] }
87
88
  end
88
89
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beer_list
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,14 +9,14 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-11 00:00:00.000000000 Z
12
+ date: 2013-05-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mechanize
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - '='
19
+ - - ~>
20
20
  - !ruby/object:Gem::Version
21
21
  version: 2.6.0
22
22
  type: :runtime
@@ -24,9 +24,25 @@ dependencies:
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
- - - '='
27
+ - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: 2.6.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: thor
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.18.1
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.18.1
30
46
  - !ruby/object:Gem::Dependency
31
47
  name: bundler
32
48
  requirement: !ruby/object:Gem::Requirement
@@ -48,17 +64,17 @@ dependencies:
48
64
  requirement: !ruby/object:Gem::Requirement
49
65
  none: false
50
66
  requirements:
51
- - - ! '>='
67
+ - - ~>
52
68
  - !ruby/object:Gem::Version
53
- version: '0'
69
+ version: 2.12.0
54
70
  type: :development
55
71
  prerelease: false
56
72
  version_requirements: !ruby/object:Gem::Requirement
57
73
  none: false
58
74
  requirements:
59
- - - ! '>='
75
+ - - ~>
60
76
  - !ruby/object:Gem::Version
61
- version: '0'
77
+ version: 2.12.0
62
78
  description: A utility for retrieving the beer list from various establishments
63
79
  email:
64
80
  - olson_dan@yahoo.com
@@ -78,17 +94,30 @@ files:
78
94
  - lib/beer_list.rb
79
95
  - lib/beer_list/cli.rb
80
96
  - lib/beer_list/establishments.rb
97
+ - lib/beer_list/establishments/acadia_cafe.rb
98
+ - lib/beer_list/establishments/blue_nile.rb
81
99
  - lib/beer_list/establishments/bulldog_lowertown.rb
82
100
  - lib/beer_list/establishments/bulldog_northeast.rb
83
101
  - lib/beer_list/establishments/bulldog_uptown.rb
102
+ - lib/beer_list/establishments/busters_on28th.rb
84
103
  - lib/beer_list/establishments/edina_grill.rb
85
104
  - lib/beer_list/establishments/establishment.rb
86
105
  - lib/beer_list/establishments/groveland_tap.rb
106
+ - lib/beer_list/establishments/happy_gnome.rb
87
107
  - lib/beer_list/establishments/longfellow_grill.rb
108
+ - lib/beer_list/establishments/lowry_uptown.rb
109
+ - lib/beer_list/establishments/mackenzie_pub.rb
110
+ - lib/beer_list/establishments/macs_industrial.rb
111
+ - lib/beer_list/establishments/muddy_pig.rb
88
112
  - lib/beer_list/establishments/muddy_waters.rb
113
+ - lib/beer_list/establishments/new_bohemia.rb
114
+ - lib/beer_list/establishments/stanleys_bar_room.rb
89
115
  - lib/beer_list/establishments/three_squares.rb
116
+ - lib/beer_list/establishments/washington_square.rb
90
117
  - lib/beer_list/exceptions.rb
118
+ - lib/beer_list/leads/beer_advocate.rb
91
119
  - lib/beer_list/list.rb
120
+ - lib/beer_list/listable.rb
92
121
  - lib/beer_list/scraper.rb
93
122
  - lib/ext/string.rb
94
123
  - lib/generators/establishment_generator.rb