beer_list 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- beer_list (0.1.3)
4
+ beer_list (1.1.0)
5
5
  mechanize (~> 2.6.0)
6
6
  thor (~> 0.18.1)
7
7
 
8
8
  GEM
9
9
  specs:
10
10
  diff-lcs (1.1.3)
11
- domain_name (0.5.9)
11
+ domain_name (0.5.11)
12
12
  unf (>= 0.0.5, < 1.0.0)
13
13
  mechanize (2.6.0)
14
14
  domain_name (~> 0.5, >= 0.5.1)
@@ -18,7 +18,7 @@ GEM
18
18
  nokogiri (~> 1.4)
19
19
  ntlm-http (~> 0.1, >= 0.1.1)
20
20
  webrobots (>= 0.0.9, < 0.2)
21
- mime-types (1.22)
21
+ mime-types (1.23)
22
22
  net-http-digest_auth (1.3)
23
23
  net-http-persistent (2.8)
24
24
  nokogiri (1.5.9)
data/README.md CHANGED
@@ -4,6 +4,8 @@ A utility for retrieving the beer list from various establishments
4
4
 
5
5
  ## Usage
6
6
 
7
+ ### Installation
8
+
7
9
  `gem install beer_list`
8
10
 
9
11
  or in your gemfile:
@@ -18,7 +20,7 @@ then require the gem:
18
20
 
19
21
  See what's on tap:
20
22
 
21
- ```
23
+ ```ruby
22
24
  # An array-like object
23
25
  list = BeerList.groveland_tap
24
26
 
@@ -38,7 +40,7 @@ but its easy to [extend BeerList](#extending-beerlist-with-more-establishments)
38
40
 
39
41
  First, let's try one out of the box:
40
42
 
41
- ```
43
+ ```ruby
42
44
  bulldog_northeast = BeerList::Establishments::BulldogNortheast.new
43
45
 
44
46
  # Now get the list
@@ -48,7 +50,7 @@ bulldog_northeast.list
48
50
  You may want to get lists for more than one establishment at a time. To do so, register
49
51
  the desired establishments in BeerList.establishments:
50
52
 
51
- ```
53
+ ```ruby
52
54
  three_squares = BeerList::Establishments::ThreeSquares.new
53
55
  muddy_waters = BeerList::Establishments::MuddyWaters.new
54
56
 
@@ -82,7 +84,7 @@ For example:
82
84
 
83
85
  will create the following code in path/to/establishments/applebirds.rb
84
86
 
85
- ```
87
+ ```ruby
86
88
  module BeerList
87
89
  module Establishments
88
90
  class Applebirds < Establishment
@@ -107,7 +109,7 @@ end
107
109
 
108
110
  For all options you can pass to beer_list establish, run:
109
111
 
110
- `$ beer_list help`
112
+ `$ beer_list help establish`
111
113
 
112
114
  ### Using Your Generated Establishments
113
115
 
@@ -116,10 +118,15 @@ use the fruit of your labor in a real application. You'll need to tell BeerList
116
118
  about the generated files so that it can require them. If you're using Rails, add
117
119
  the following code in an initializer:
118
120
 
119
- `BeerList.establishments_dir = File.join(Rails.root, 'path/to/establishments')`
121
+ ```ruby
122
+ BeerList.configure do |c|
123
+ c.establishments_dir = File.join(Rails.root, 'path/to/establishments')
124
+ end
125
+ ```
120
126
 
127
+ Then in your app:
121
128
 
122
- ```
129
+ ```ruby
123
130
  # Fetch just the list at Applebirds
124
131
  BeerList.applebirds
125
132
 
@@ -137,12 +144,45 @@ AND...
137
144
 
138
145
  Checkout [This link](http://mechanize.rubyforge.org/) for more on Mechanize
139
146
 
147
+ ### Sending Lists
148
+
149
+ Once you have lists, you can use them locally (obviously), or you can send them elsewhere.
150
+ Configure BeerList with a default URL like this:
151
+
152
+ ```ruby
153
+ BeerList.configure do |c|
154
+ c.default_url = 'https://yourapp.com/some_sweet_beer_route'
155
+ end
156
+ ```
157
+
158
+ Then in your code, send a list!
159
+
160
+ ```ruby
161
+ applebirds = BeerList.applebirds
162
+
163
+ # POSTs your list to your default_url as JSON under the "beer_list" name
164
+ BeerList.send_list(applebirds)
165
+
166
+ # You can also give it an explicit URL
167
+ other_route = 'http://myotherapp.com/another_beer_route'
168
+ BeerList.send_list(applebirds, other_route)
169
+
170
+ # Register some lists and send 'em all at once:
171
+ thursdays = BeerList::Establishments::Thursdays.new
172
+
173
+ BeerList.add_establishments(applebirds, thursdays)
174
+ BeerList.send_lists
175
+ ```
176
+
177
+ Both .send_list and .send_lists accept an optional URL as the last argument. If you don't pass one,
178
+ it will use the default in your configuration. If neither doesn't exist, it will raise an error.
179
+
140
180
  ### Leads
141
181
 
142
182
  If you're out of ideas on what establishments you may want lists for, fear not: BeerList can
143
183
  give you some ideas.
144
184
 
145
- ```
185
+ ```ruby
146
186
  # You might be interested in good beer bars located in California:
147
187
  cali = BeerList::Leads::CA.new
148
188
 
@@ -163,12 +203,14 @@ it in the not-too-distant future.
163
203
  ### CLI
164
204
 
165
205
  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,
206
+ generates Establishment files for you, BeerList also offers a few other commands:
207
+
208
+ There's the `list` command. For example,
167
209
  say you have the following two establishments a directory called ~/my_beer_lists:
168
210
 
169
211
  ```
170
- BeerList::Establishments::Applebirds
171
- BeerList::Establishments::Thursdays
212
+ applebirds.rb
213
+ thursdays.rb
172
214
  ```
173
215
 
174
216
  You can get the beer lists for these places from the command line:
@@ -182,3 +224,9 @@ $ beer_list list applebirds thursdays -d ~/my_beer_lists
182
224
  # pass -j for JSON
183
225
  $ beer_list list applebirds thursdays -j -d ~/my_beer_lists
184
226
  ```
227
+
228
+ There's also the `send` command for [sending your lists](#sending-lists) to a given URL:
229
+
230
+ `$ beer_list send applebirds thursdays -u 'http://mybeerapiendpoint.com/beer_list'`
231
+
232
+ See `$ beer_list help` for all commands
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 = '1.0.0'
3
+ spec.version = '1.1.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'
data/lib/beer_list.rb CHANGED
@@ -2,6 +2,7 @@ require 'mechanize'
2
2
  require 'json'
3
3
 
4
4
  module BeerList
5
+ require 'beer_list/settings'
5
6
  require 'beer_list/scraper'
6
7
  require 'beer_list/list'
7
8
  require 'beer_list/exceptions'
@@ -14,12 +15,30 @@ module BeerList
14
15
 
15
16
  class << self
16
17
 
18
+ def configure
19
+ yield settings
20
+ true
21
+ end
22
+
23
+ def settings
24
+ @settings ||= Settings.new
25
+ end
26
+
27
+ def default_url
28
+ settings.default_url
29
+ end
30
+
17
31
  def establishments_dir
18
- @establishments_dir
32
+ settings.establishments_dir
19
33
  end
20
34
 
35
+ ### DEPRECATED ###
21
36
  def establishments_dir=(directory)
22
- @establishments_dir = directory
37
+ puts <<-dep
38
+ BeerList.establishments_dir= is deprecated and will be removed.
39
+ Please use BeerList.configure instead
40
+ dep
41
+ settings.establishments_dir = directory
23
42
  end
24
43
 
25
44
  def establishments
@@ -57,6 +76,19 @@ module BeerList
57
76
  lists_as_hash.to_json
58
77
  end
59
78
 
79
+ def send_list(list, url=nil)
80
+ url ||= default_url
81
+ raise NoUrlError unless url
82
+ raise NotAListError unless list.is_a? BeerList::List
83
+ scraper.send_json url, list.to_json
84
+ end
85
+
86
+ def send_lists(url=nil)
87
+ url ||= default_url
88
+ raise NoUrlError unless url
89
+ scraper.send_json url, lists_as_json
90
+ end
91
+
60
92
  def scraper
61
93
  @scraper ||= Scraper.instance
62
94
  end
@@ -78,11 +110,19 @@ module BeerList
78
110
 
79
111
  def method_missing(method, *args, &block)
80
112
  class_name = method.to_s.split('_').map(&:capitalize).join
81
- klass = get_class_with_namespace class_name
82
- scraper.beer_list klass.new
113
+ if klass = get_class_with_namespace(class_name)
114
+ scraper.beer_list klass.new
115
+ else
116
+ super
117
+ end
118
+ end
119
+
120
+ def is_establishment?(class_name)
121
+ BeerList::Establishments.constants.include? class_name.to_sym
83
122
  end
84
123
 
85
124
  def get_class_with_namespace(class_name)
125
+ return nil unless is_establishment? class_name
86
126
  ['BeerList', 'Establishments', class_name].inject(Object){ |o, name| o.const_get(name) }
87
127
  end
88
128
  end
data/lib/beer_list/cli.rb CHANGED
@@ -11,7 +11,7 @@ module BeerList
11
11
  banner: 'The directory in which BeerList will put your establishments'
12
12
  option :selector,
13
13
  aliases: '-s',
14
- banner: 'Optional selector to use for scraping'
14
+ banner: 'Optional selector to use for scraping'
15
15
 
16
16
  desc 'establish ESTABLISHMENT', 'Generate a subclass of BeerList::Establishments::Establishment in the given directory'
17
17
  def establish(klass)
@@ -30,8 +30,8 @@ module BeerList
30
30
 
31
31
  desc 'list ESTABLISHMENTS', 'Retrieve the beer list at the given establishments'
32
32
  def list(*establishments)
33
- BeerList.establishments_dir = options[:directory]
34
- BeerList.add_establishments *classify(establishments)
33
+ configure
34
+ add_establishments establishments
35
35
  if options[:json]
36
36
  puts BeerList.lists_as_json
37
37
  else
@@ -46,13 +46,42 @@ module BeerList
46
46
  end
47
47
  end
48
48
 
49
+ option :url,
50
+ aliases: '-u',
51
+ required: true,
52
+ banner: 'the URL to which to post your lists'
53
+ desc 'send ESTABLISHMENTS', 'Send (POST) the lists (as JSON) for the given establishments to the given URL'
54
+ def send(*establishments)
55
+ configure
56
+ add_establishments establishments
57
+ puts "Sent!" if BeerList.send_lists
58
+ end
59
+
49
60
  private
50
61
 
62
+ def add_establishments(establishments)
63
+ BeerList.add_establishments *classify(establishments)
64
+ end
65
+
66
+ def configure
67
+ BeerList.configure do |c|
68
+ c.establishments_dir = options[:directory]
69
+ c.default_url = options[:url]
70
+ end
71
+ end
72
+
51
73
  def classify(establishments)
52
74
  establishments.map do |est|
53
75
  class_name = est.to_s.split('_').map(&:capitalize).join
54
- klass = BeerList.send(:get_class_with_namespace, class_name)
76
+ instantiate_or_die class_name
77
+ end
78
+ end
79
+
80
+ def instantiate_or_die(class_name)
81
+ if klass = BeerList.send(:get_class_with_namespace, class_name)
55
82
  klass.new
83
+ else
84
+ abort "#{class_name} is not recognized. Is it in your BeerList.establishments_dir?"
56
85
  end
57
86
  end
58
87
  end
@@ -0,0 +1,15 @@
1
+ module BeerList
2
+ module Establishments
3
+ class BlueDoorPub < Establishment
4
+ URL = 'http://thebdp.com/?page_id=159'
5
+
6
+ def get_list
7
+ page.search('div.two-columns li a').map(&:text)
8
+ end
9
+
10
+ def url
11
+ URL
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module BeerList
2
+ module Establishments
3
+ class GingerHop < Establishment
4
+ URL = 'http://www.gingerhop.com/beer'
5
+
6
+ def get_list
7
+ page.search('div.left-col h5').map(&:text)
8
+ end
9
+
10
+ def url
11
+ URL
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ module BeerList
2
+ module Establishments
3
+ class McCoysMN < Establishment
4
+ attr_accessor :url
5
+
6
+ DRAFTS = 'http://mccoysmn.com/beer/'
7
+ BOTTLES = 'http://mccoysmn.com/beer/bottles'
8
+
9
+ def initialize
10
+ @url = DRAFTS
11
+ end
12
+
13
+ def get_list
14
+ @beers = []
15
+ get_draft_list
16
+ get_bottle_list
17
+ end
18
+
19
+ private
20
+
21
+ def get_draft_list
22
+ @beers += base_list
23
+ end
24
+
25
+ def get_bottle_list
26
+ self.url = BOTTLES
27
+ self.page = BeerList.scraper.visit self
28
+ @beers += base_list
29
+ end
30
+
31
+ def base_list
32
+ page.search('td.title a').map(&:text)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -6,4 +6,18 @@ module BeerList
6
6
  super msg
7
7
  end
8
8
  end
9
+
10
+ class NoUrlError < StandardError
11
+ def initialize(msg=nil)
12
+ msg ||= "No url was specified and no default_url exists"
13
+ super msg
14
+ end
15
+ end
16
+
17
+ class NotAListError < StandardError
18
+ def initialize(msg=nil)
19
+ msg ||= "That object was not a BeerList::List"
20
+ super msg
21
+ end
22
+ end
9
23
  end
@@ -17,13 +17,23 @@ module BeerList
17
17
  end
18
18
 
19
19
  def visit(visitable)
20
- visitable.page = @agent.get(visitable.url)
20
+ visitable.page = agent.get(visitable.url)
21
+ end
22
+
23
+ def send_json(url, json)
24
+ url = "http://#{url}" unless url.start_with? 'http://'
25
+ agent.post url, "{\"beer_list\": #{json}}", 'Content-Type' => 'application/json'
26
+ true
21
27
  end
22
28
 
23
29
  private
24
30
 
25
31
  def set_user_agent
26
- @agent.user_agent_alias = USER_AGENT
32
+ agent.user_agent_alias = USER_AGENT
33
+ end
34
+
35
+ def agent
36
+ @agent
27
37
  end
28
38
  end
29
39
  end
@@ -0,0 +1,5 @@
1
+ module BeerList
2
+ class Settings
3
+ attr_accessor :establishments_dir, :default_url
4
+ end
5
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ module BeerList
4
+ describe Scraper do
5
+ let(:establishment){ BeerList::Establishments::Establishment.new }
6
+ let(:scraper){ Scraper.instance }
7
+ let(:agent){ stub }
8
+ let(:url){ "http://omg.io" }
9
+
10
+ before do
11
+ scraper.stub(:agent){ agent }
12
+ agent.stub(:user_agent_alias=)
13
+ end
14
+
15
+ describe '#send_json' do
16
+ let(:json){ "{\"foo\":\"bar\"}" }
17
+ let(:headers){ { 'Content-Type' => 'application/json' } }
18
+
19
+ it 'posts to the given url with namespaced parameters' do
20
+ expected_json = "{\"beer_list\": #{json}}"
21
+ agent.should_receive(:post).with url, expected_json, headers
22
+ scraper.send_json url, json
23
+ end
24
+
25
+ it 'prepends a scheme if one is not given' do
26
+ expected_json = "{\"beer_list\": #{json}}"
27
+ no_scheme_url = 'www.foobar.com'
28
+ agent.should_receive(:post).with "http://#{no_scheme_url}", expected_json, headers
29
+ scraper.send_json no_scheme_url, json
30
+ end
31
+ end
32
+
33
+ describe '#beer_list' do
34
+ before do
35
+ scraper.should_receive(:visit).with establishment
36
+ end
37
+
38
+ it "calls the establishment's #list method" do
39
+ establishment.should_receive :list
40
+ scraper.beer_list establishment
41
+ end
42
+ end
43
+
44
+ describe '#visit' do
45
+ before do
46
+ establishment.stub(:url){ url }
47
+ establishment.stub(:list)
48
+ end
49
+
50
+ it "visits the establishment's url" do
51
+ agent.should_receive(:get).with(url){ 'the page' }
52
+ scraper.beer_list establishment
53
+ end
54
+
55
+ it "assigns to establishment.page" do
56
+ agent.stub(:get){ 'the page' }
57
+ establishment.should_receive(:page=).with 'the page'
58
+ scraper.beer_list establishment
59
+ end
60
+ end
61
+ end
62
+ end
@@ -3,6 +3,23 @@ require 'spec_helper'
3
3
  describe BeerList do
4
4
  let(:establishment){ BeerList::Establishments::ThreeSquares.new }
5
5
 
6
+ describe '.configure' do
7
+ before do
8
+ BeerList.configure do |c|
9
+ c.establishments_dir = '/home/foo'
10
+ c.default_url = 'http://omg.io'
11
+ end
12
+ end
13
+
14
+ it 'stores the establishments_dir' do
15
+ BeerList.establishments_dir.should == '/home/foo'
16
+ end
17
+
18
+ it 'stores the default_url' do
19
+ BeerList.default_url.should == 'http://omg.io'
20
+ end
21
+ end
22
+
6
23
  describe '.establishments' do
7
24
 
8
25
  after(:each) do
@@ -109,4 +126,34 @@ describe BeerList do
109
126
  end
110
127
  end
111
128
 
129
+ describe 'sending lists' do
130
+ let(:scraper){ stub }
131
+ let(:url){ 'http://omg.io' }
132
+ let(:json){ "{\"foo\":\"bar\"}" }
133
+ let(:list){ BeerList::List.new }
134
+
135
+ before do
136
+ BeerList.stub(:scraper).and_return scraper
137
+ list.stub(:to_json).and_return json
138
+ end
139
+
140
+ describe '.send_list' do
141
+ it 'delegates to the scraper' do
142
+ scraper.should_receive(:send_json).with(url, json)
143
+ BeerList.send_list list, url
144
+ end
145
+ end
146
+
147
+ describe '.send_lists' do
148
+ before do
149
+ BeerList.stub(:lists).and_return [list]
150
+ list.stub(:to_hash).and_return({ foo: 'bar' })
151
+ end
152
+
153
+ it 'delegates to the scraper' do
154
+ scraper.should_receive(:send_json).with(url, json)
155
+ BeerList.send_lists url
156
+ end
157
+ end
158
+ end
112
159
  end
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: 1.0.0
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-16 00:00:00.000000000 Z
12
+ date: 2013-05-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mechanize
@@ -95,6 +95,7 @@ files:
95
95
  - lib/beer_list/cli.rb
96
96
  - lib/beer_list/establishments.rb
97
97
  - lib/beer_list/establishments/acadia_cafe.rb
98
+ - lib/beer_list/establishments/blue_door_pub.rb
98
99
  - lib/beer_list/establishments/blue_nile.rb
99
100
  - lib/beer_list/establishments/bulldog_lowertown.rb
100
101
  - lib/beer_list/establishments/bulldog_northeast.rb
@@ -102,12 +103,14 @@ files:
102
103
  - lib/beer_list/establishments/busters_on28th.rb
103
104
  - lib/beer_list/establishments/edina_grill.rb
104
105
  - lib/beer_list/establishments/establishment.rb
106
+ - lib/beer_list/establishments/ginger_hop.rb
105
107
  - lib/beer_list/establishments/groveland_tap.rb
106
108
  - lib/beer_list/establishments/happy_gnome.rb
107
109
  - lib/beer_list/establishments/longfellow_grill.rb
108
110
  - lib/beer_list/establishments/lowry_uptown.rb
109
111
  - lib/beer_list/establishments/mackenzie_pub.rb
110
112
  - lib/beer_list/establishments/macs_industrial.rb
113
+ - lib/beer_list/establishments/mc_coys_mn.rb
111
114
  - lib/beer_list/establishments/muddy_pig.rb
112
115
  - lib/beer_list/establishments/muddy_waters.rb
113
116
  - lib/beer_list/establishments/new_bohemia.rb
@@ -119,11 +122,13 @@ files:
119
122
  - lib/beer_list/list.rb
120
123
  - lib/beer_list/listable.rb
121
124
  - lib/beer_list/scraper.rb
125
+ - lib/beer_list/settings.rb
122
126
  - lib/ext/string.rb
123
127
  - lib/generators/establishment_generator.rb
124
128
  - lib/generators/templates/establishment.erb
125
129
  - spec/lib/beer_list/establishments/establishment_spec.rb
126
130
  - spec/lib/beer_list/list_spec.rb
131
+ - spec/lib/beer_list/scraper_spec.rb
127
132
  - spec/lib/beer_list_spec.rb
128
133
  - spec/spec_helper.rb
129
134
  homepage: https://github.com/DanOlson/beer_list
@@ -154,5 +159,6 @@ summary: A beer list scraper
154
159
  test_files:
155
160
  - spec/lib/beer_list/establishments/establishment_spec.rb
156
161
  - spec/lib/beer_list/list_spec.rb
162
+ - spec/lib/beer_list/scraper_spec.rb
157
163
  - spec/lib/beer_list_spec.rb
158
164
  - spec/spec_helper.rb