beer_list 0.1.3 → 1.0.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.
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