rlocu 0.1.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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rlocu.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Stephen Philp
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,60 @@
1
+ # Rlocu
2
+
3
+ A simple, unoffical, and currently incomplete wrapper for the Locu API (locu.com)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rlocu'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rlocu
18
+
19
+ ## Getting Started
20
+
21
+ When you require Rlocu it runs config! on itself to set api_key and http_base. It reads these values from a YAML .config file in .lib/ exa:
22
+
23
+ API_KEY: 'yourapikeyyourapikeyyourapikey'
24
+ HTTP_BASE: 'https://api.locu.com/v1_0/'
25
+
26
+ ## Usage
27
+
28
+ Right now the only functionality covered is Venue Search to search for venues, and Venue Details which gets you menus, etc.
29
+ Everything is under the Rlocu namespace.
30
+
31
+ Venue Search
32
+ Pass a hash of params to Rlocu::VenueSearch.query()
33
+ Returns an array of venues (Rlocu::Venue)
34
+ Or you can pass it a block to iterate through the venues:
35
+
36
+ Rlocu::VenueSearch.query(postal_code: '90278', cuisine: 'Thai') do |v|
37
+ puts v.name
38
+ end
39
+
40
+ Venue Details
41
+ You can pass an array of up to 5 venues to Rlocu::VenueDetails()
42
+ Returns an array of Rlocu::Venues with the detail data (th venue search and detail search have overlapping attributes).
43
+
44
+ Or you can pass it a block to iterate through the venues:
45
+ Rlocu::VenueDetails.query(array_of_venues) do |v|
46
+ puts v.twitter_id
47
+ end
48
+
49
+ Object Space
50
+ The object space essentially follows the Locu API with two little utility objects:
51
+ RLocu::Location
52
+ Rlocu::Bounds
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it
57
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
58
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
59
+ 4. Push to the branch (`git push origin my-new-feature`)
60
+ 5. Create new Pull Request
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ task default: [:test]
6
+
7
+ Rake::TestTask.new do |t|
8
+ t.libs << 'test'
9
+ t.test_files = FileList['test/test*.rb']
10
+ #t.verbose = true
11
+ end
12
+
@@ -0,0 +1,8 @@
1
+ #require "rlocu/version"
2
+ require_relative 'rlocu/config'
3
+ require_relative 'rlocu/venue'
4
+ require_relative 'rlocu/menu'
5
+ require_relative 'rlocu/venue_search'
6
+ require_relative 'rlocu/venue_details'
7
+ require_relative 'utilities'
8
+
@@ -0,0 +1,23 @@
1
+ require 'yaml'
2
+ module Rlocu
3
+
4
+ class << self
5
+
6
+ def config!(file=File.expand_path("../../../.config", __FILE__))
7
+ configs = YAML::load(File.open(file))
8
+ @api_key = configs['API_KEY']
9
+ @http_base = configs['HTTP_BASE']
10
+ end
11
+
12
+ def api_key
13
+ @api_key
14
+ end
15
+
16
+ def http_base
17
+ @http_base
18
+ end
19
+
20
+ end
21
+
22
+ config!
23
+ end
@@ -0,0 +1,130 @@
1
+ module Rlocu
2
+ class Menu
3
+ attr_accessor :name
4
+ attr_reader :sections
5
+
6
+ def initialize(meta_menu)
7
+ @name = meta_menu['menu_name']
8
+ self.sections = meta_menu['sections']
9
+ end
10
+
11
+ def sections=(meta_sections)
12
+ @sections = []
13
+ meta_sections.each {|h| @sections << Section.new(h)}
14
+ end
15
+
16
+ end
17
+
18
+ class Section
19
+ attr_accessor :name
20
+ attr_reader :subsections
21
+
22
+ def initialize(meta_section)
23
+ @name = meta_section['section_name']
24
+ self.subsections = meta_section['subsections']
25
+ end
26
+
27
+ def subsections=(meta_subsections)
28
+ @subsections = []
29
+ meta_subsections.each {|h| @subsections << Subsection.new(h)}
30
+ end
31
+
32
+ end
33
+
34
+ class Subsection
35
+ attr_accessor :name
36
+ attr_reader :contents
37
+
38
+ def initialize(meta_subsection)
39
+ @name = meta_subsection['subsection_name']
40
+ self.contents = meta_subsection['contents']
41
+ end
42
+
43
+ def contents=(meta_contents)
44
+ @contents = []
45
+ meta_contents.each do |h|
46
+ #TODO: raise error if type is different
47
+ @contents << case h['type']
48
+ when 'SECTION_TEXT'
49
+ SectionText.new(h)
50
+ when 'ITEM'
51
+ MenuItem.new(h)
52
+ end
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ class SectionText
59
+ attr_accessor :type, :text
60
+
61
+ def initialize(meta_section_text)
62
+ @type = meta_section_text['type']
63
+ @text = meta_section_text['text']
64
+ end
65
+
66
+ def to_s
67
+ @text
68
+ end
69
+
70
+ end
71
+
72
+ # create a to_s for each that can be over-ridden by the user
73
+ class MenuItem
74
+ attr_accessor :type, :name, :description, :price
75
+ attr_reader :option_groups
76
+
77
+ def initialize(meta_menu_item)
78
+ @type = meta_menu_item['type']
79
+ @name = meta_menu_item['name']
80
+ @description = meta_menu_item['description']
81
+ @price = meta_menu_item['price']
82
+ self.option_groups = meta_menu_item['option_groups']
83
+ end
84
+
85
+ def option_groups=(meta_option_groups)
86
+ @option_groups = []
87
+ meta_option_groups.each { |h| @option_groups << OptionGroup.new(h) } if meta_option_groups
88
+ end
89
+
90
+ end
91
+
92
+ class OptionGroup
93
+ attr_accessor :type, :text
94
+ attr_reader :options
95
+
96
+ def initialize(meta_option_group)
97
+ @type = meta_option_group['type']
98
+ @text = meta_option_group['text']
99
+ self.options = meta_option_group['options']
100
+ end
101
+
102
+ def options=(meta_options)
103
+ @options = []
104
+ meta_options.each {|h| @options << Option.new(h) } if meta_options
105
+ end
106
+
107
+
108
+ end
109
+
110
+ class Option
111
+ attr_accessor :name
112
+ attr_writer :price
113
+
114
+ def initialize(meta_option)
115
+ @name = meta_option['name']
116
+ @price = meta_option['price']
117
+ end
118
+
119
+ def price
120
+ # price can be relative indicated by a + in the price
121
+ # not currently doing anything w it
122
+ @price
123
+ end
124
+
125
+ def to_s
126
+ "#{name} #{price}"
127
+ end
128
+
129
+ end
130
+ end
@@ -0,0 +1,34 @@
1
+ module Rlocu
2
+ class Venue
3
+ PROPERTIES = [:name, :locality, :street_address,
4
+ :cuisines, :region, :long, :phone, :postal_code,
5
+ :categories, :has_menu, :country, :lat, :id,
6
+ :website_url, :resource_uri]
7
+ # the Venue class encapsulates the venue_details also
8
+ # keeping them separate for maintainability when they eventually change
9
+ VENUE_DETAILS = [:open_hours, :facebook_url, :twitter_id,
10
+ :similar_venues, :redirected_from]
11
+ attr_reader :menus
12
+ (PROPERTIES | VENUE_DETAILS).each {|prop| attr_accessor prop}
13
+
14
+ def initialize(meta_venue)
15
+ @menus = []
16
+ update(meta_venue)
17
+ end
18
+
19
+ def update(meta_venue)
20
+ meta_venue.each {|k,v| self.send("#{k.to_s}=",v) }
21
+ end
22
+
23
+ # override some of the writers
24
+ def menus=(meta_menus)
25
+ # menus is an array of menu hashes
26
+ # don't keep adding and duplicating if there are already menus
27
+ @menus = []
28
+ meta_menus.each do |h|
29
+ @menus << Menu.new(h)
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ require 'open-uri'
2
+ require 'JSON'
3
+
4
+ module Rlocu
5
+ module VenueDetails
6
+
7
+ def self.query(venues, &block)
8
+ response = {}
9
+ open(url(venues)) { |request| response = JSON.parse(request.read) }
10
+ # should we update the venues passed in or should we create new venue
11
+ # objects with the updated info? lets create new ones
12
+
13
+ venues_w_details = []
14
+ response['objects'].each do |object|
15
+ venues_w_details << Venue.new(object)
16
+ end
17
+ venues_w_details.each { |venue| yield venue } if block_given?
18
+ return venues_w_details
19
+ end
20
+
21
+ private
22
+
23
+ def self.url(venues)
24
+ ids = reduce_ids(venues)
25
+ "#{Rlocu.http_base}venue/#{ids}/?#{Rlocu.encode}"
26
+ end
27
+
28
+ def self.reduce_ids(venues)
29
+ raise ArgumentError.new "Only 5 venues can be queried at a time for venue details" if venues.count > 5
30
+ ids = venues.reduce('') {|memo, venue| memo << "#{venue.id};"}
31
+ ids.chop
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,27 @@
1
+ require 'open-uri'
2
+ require 'JSON'
3
+
4
+ module Rlocu
5
+ module VenueSearch
6
+ PARAMETERS = [:name, :has_menu, :category, :cuisine, :website_url, :open_at, :street_address,
7
+ :locality, :region, :postal_code, :country, :location, :radius, :bounds]
8
+
9
+ def self.query(params, &block)
10
+ unsupported = params.keys.reduce([]) {|memo,p| memo << p unless PARAMETERS.include? p; memo }
11
+ raise ArgumentError.new "Unsupported parameter to Rlocu::VenuSearch (#{unsupported})" unless unsupported.empty?
12
+ response = {}
13
+ open(url(params)) {|request| response = JSON.parse(request.read)}
14
+ venues = []
15
+ venues = response['objects'].reduce(venues) {|arr, o| arr << Rlocu::Venue.new(o) ; arr }
16
+ venues.each { |venue| yield venue } if block_given?
17
+ return venues
18
+ end
19
+
20
+ private
21
+
22
+ def self.url(params)
23
+ "#{Rlocu.http_base}venue/search/?#{Rlocu.encode(params)}"
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module Rlocu
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,40 @@
1
+ require 'open-uri'
2
+
3
+ module Rlocu
4
+
5
+ def self.encode(params={})
6
+ s = params.reduce("api_key=#{Rlocu.api_key}&") {|memo,(key,val)| memo << "#{key.to_s}=#{val}&"}
7
+ URI::encode(s.chop)
8
+ end
9
+
10
+ class Location
11
+ attr_accessor :lat, :long
12
+
13
+ def initialize(lat, long)
14
+ if !lat.is_a?(Numeric) || !long.is_a?(Numeric)
15
+ raise ArgumentError.new "Lat and long must be numeric (floats)"
16
+ end
17
+ @lat = lat
18
+ @long = long
19
+ end
20
+
21
+ def to_s
22
+ "#{lat},#{long}"
23
+ end
24
+
25
+ end
26
+
27
+ class Bounds
28
+
29
+ def initialize(loc1, loc2)
30
+ @loc1 = loc1
31
+ @loc2 = loc2
32
+ end
33
+
34
+ def to_s
35
+ "#{@loc1.to_s}|#{@loc2.to_s}"
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rlocu/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "rlocu"
8
+ gem.version = Rlocu::VERSION
9
+ gem.authors = ["Stephen Philp"]
10
+ gem.email = ["stephen@stephenphilp.com"]
11
+ gem.description = %q{A simple ruby wrapper for the Locu API}
12
+ gem.summary = %q{Rlocu is a ruby wrapper for Locu's API. The Locu API gives you access to real-time local business data, from opening hours to price lists, such as restaurant menus.}
13
+ gem.homepage = "https://github.com/swelltrain/rlocu"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,7 @@
1
+ require 'test/unit'
2
+
3
+ class TruthTest < Test::Unit::TestCase
4
+ def test_reality
5
+ assert true, "aye, it is true"
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/rlocu'
3
+
4
+ class UtilitiesTest < Test::Unit::TestCase
5
+ include Rlocu
6
+ def test_location_raises
7
+ assert_raise ArgumentError do Location.new('some','silliness') end
8
+ end
9
+
10
+ def test_location_to_s
11
+ l = Location.new(123.4,678)
12
+ assert_equal '123.4,678', l.to_s
13
+ end
14
+
15
+ def test_encode
16
+ #params = {name: 'bamboo thai', postal_code: '90278'}
17
+ skip "insert your api into .config"
18
+ #assert_equal 'api_key=YOUR_API_HERE&name=bamboo%20thai&postal_code=90278', Rlocu.encode(params)
19
+ end
20
+
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/rlocu'
3
+ require 'JSON'
4
+
5
+ class VenueTest < Test::Unit::TestCase
6
+ include Rlocu
7
+ def test_menu_setter
8
+ params = {name: 'bamboo thai', postal_code: '90278'}
9
+ venues = Rlocu::VenueSearch.query(params)
10
+
11
+ deets = Rlocu::VenueDetails.query(venues)
12
+
13
+
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/rlocu'
3
+
4
+ class VenueDetailsTest < Test::Unit::TestCase
5
+ include Rlocu
6
+ def test_reduce_ids
7
+ venues = Set.new
8
+ 5.times {|n| venues << Venue.new(id: n)}
9
+ assert_equal '0;1;2;3;4', Rlocu::VenueDetails.send(:reduce_ids, venues)
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/rlocu'
3
+
4
+ class VenueSearchTest < Test::Unit::TestCase
5
+ include Rlocu
6
+ def test_bad_arg_throws_error
7
+ assert_raise ArgumentError do VenueSearch.query(bad_param: 'blah') end
8
+ end
9
+
10
+ def test_venue_search
11
+ params = {name: 'bamboo thai', postal_code: '90278'}
12
+ venues = VenueSearch.query(params)
13
+ assert_equal 'Bamboo Thai Bistro', venues[0].name
14
+ end
15
+
16
+ def test_venue_search_block
17
+ params = {postal_code: '90278'}
18
+ # the search will only return 25 so we can be pretty confident this wont change
19
+ str = ''
20
+ VenueSearch.query(params) do |p|
21
+ str << p.region
22
+ end
23
+ assert_equal 'CA'*25, str
24
+ end
25
+ end
26
+
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rlocu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Stephen Philp
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-01-08 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A simple ruby wrapper for the Locu API
15
+ email:
16
+ - stephen@stephenphilp.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - lib/rlocu.rb
27
+ - lib/rlocu/config.rb
28
+ - lib/rlocu/menu.rb
29
+ - lib/rlocu/venue.rb
30
+ - lib/rlocu/venue_details.rb
31
+ - lib/rlocu/venue_search.rb
32
+ - lib/rlocu/version.rb
33
+ - lib/utilities.rb
34
+ - rlocu.gemspec
35
+ - test/test_truth.rb
36
+ - test/test_utilities.rb
37
+ - test/test_venue.rb
38
+ - test/test_venue_details.rb
39
+ - test/test_venue_search.rb
40
+ homepage: https://github.com/swelltrain/rlocu
41
+ licenses: []
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 1.8.23
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: Rlocu is a ruby wrapper for Locu's API. The Locu API gives you access to
64
+ real-time local business data, from opening hours to price lists, such as restaurant
65
+ menus.
66
+ test_files:
67
+ - test/test_truth.rb
68
+ - test/test_utilities.rb
69
+ - test/test_venue.rb
70
+ - test/test_venue_details.rb
71
+ - test/test_venue_search.rb