Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tsibog::Venues aggregator #2

Open
wants to merge 74 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
97d847a
Initial commit
RichOrElse Nov 16, 2014
7d0d9b4
added Foursquare::Venues#client
RichOrElse Nov 16, 2014
b9456a1
added Foursquare::Venues#options
RichOrElse Nov 16, 2014
062ff9a
added categories
RichOrElse Nov 16, 2014
4658b69
added #with_category
RichOrElse Nov 16, 2014
17b7c11
added Foursquare::Venues#within
RichOrElse Nov 16, 2014
7441694
added Foursquare::Venues#top
RichOrElse Nov 16, 2014
c269abe
added Foursquare::Venues#for
RichOrElse Nov 16, 2014
4ffb5eb
added Foursquare::Venues#above
RichOrElse Nov 16, 2014
97b83fa
corrected #above spec
RichOrElse Nov 16, 2014
872af78
added accuracy to #near and #above
RichOrElse Nov 16, 2014
877c9e0
refactored chaining
RichOrElse Nov 16, 2014
ea481a9
renamed #for argument to checkin_or_match_or_specials
RichOrElse Nov 16, 2014
dc9b57c
chain methods while retaining options
RichOrElse Nov 16, 2014
eed8278
search and enumerate venues
RichOrElse Nov 16, 2014
6ebba77
random selects venue
RichOrElse Nov 16, 2014
8bb8795
fixed accuracy for #near and #above
RichOrElse Nov 16, 2014
61f7a13
refactored #each
RichOrElse Nov 16, 2014
52bb18f
changed accuracy keys to string
RichOrElse Nov 16, 2014
7c666f3
support sub Class
RichOrElse Nov 16, 2014
4c5efdb
added #default_options
RichOrElse Nov 16, 2014
9162fa1
count venues
RichOrElse Nov 16, 2014
7e98282
rewrite sub class spec
RichOrElse Nov 16, 2014
a2a5642
rewrote a context to 'Chain methods'
RichOrElse Nov 16, 2014
ef9e83b
renamed to Foursquare3
RichOrElse Nov 16, 2014
f1c60ff
renamed folder to lib/foursquare3
RichOrElse Nov 16, 2014
a9e6018
moved to subfolder spec/foursquare
RichOrElse Nov 16, 2014
0fde20a
reimplement #chain using duplicate
RichOrElse Nov 18, 2014
d5acd4f
replaced client with request
RichOrElse Nov 18, 2014
5177c31
Refactored #options & removed #default_options for Sub Class
RichOrElse Nov 18, 2014
46f5e4b
Refactored after Chain methods
RichOrElse Nov 18, 2014
85fa304
changed request context
RichOrElse Nov 18, 2014
042a032
request receive options
RichOrElse Nov 18, 2014
c51d2e6
refactored request
RichOrElse Nov 19, 2014
d8bde3f
redescribed instance methods
RichOrElse Nov 19, 2014
d12d7be
changed context to options setters
RichOrElse Nov 19, 2014
3638803
replaced format with doc
RichOrElse Nov 19, 2014
4a574f6
rewrote enumerate descriptions
RichOrElse Nov 19, 2014
56cb009
changed subject for request context
RichOrElse Nov 19, 2014
780d588
refactored instance of options setters
RichOrElse Nov 19, 2014
cb2c304
refactored include category
RichOrElse Nov 19, 2014
06f8b65
redescribe without accuracy
RichOrElse Nov 19, 2014
5eca977
simplified random sample
RichOrElse Nov 19, 2014
ec42323
described when
RichOrElse Nov 19, 2014
0e11473
reworded the request
RichOrElse Nov 19, 2014
0962bae
described when
RichOrElse Nov 19, 2014
5a3b5c1
simplified chain setter methods
RichOrElse Nov 19, 2014
f98da80
simplified #with_category
RichOrElse Nov 19, 2014
9fe0d61
respecify #with_category
RichOrElse Nov 19, 2014
c369895
pluralized food_venue
RichOrElse Nov 19, 2014
09faa9b
expanded report
RichOrElse Nov 19, 2014
d10e9a5
added more options context
RichOrElse Nov 19, 2014
c3e6349
renamed context to returned output
RichOrElse Nov 19, 2014
45ecd35
options retain values
RichOrElse Nov 19, 2014
d6a2fbc
options retain inputs
RichOrElse Nov 19, 2014
0a2984b
refactore when enumerated
RichOrElse Nov 19, 2014
5534ea9
replaced receive options with venues options
RichOrElse Nov 19, 2014
9cb785a
renamed folder to tsibog
RichOrElse Nov 20, 2014
e37f445
renamed module to Tsibog
RichOrElse Nov 20, 2014
2fcec9f
expect venues sample to something
RichOrElse Nov 20, 2014
cf0e2eb
#initialize
RichOrElse Nov 20, 2014
5a522c1
Merge remote-tracking branch 'upstream/master'
RichOrElse Nov 20, 2014
c901fb9
#initialize raise argument error
RichOrElse Nov 20, 2014
9f07e02
added Tsibog::food_venues removed Tsibog::food_places_near, Tsibog::A…
RichOrElse Nov 20, 2014
a4b2404
replaced Tsibog.food_place(id) with Tsibog[id]
RichOrElse Nov 20, 2014
095e414
moved module to lib/tsibog
RichOrElse Nov 20, 2014
f438394
moved Tsibog::FoodPlace code
RichOrElse Nov 20, 2014
2df5f30
renamed to Tsibog::CLI
RichOrElse Nov 20, 2014
7d813ba
renamed coordinates to here
RichOrElse Nov 20, 2014
9d5061a
renamed blank_hash_or to empty_or
RichOrElse Nov 22, 2014
76adc3b
refactored #initialize & receive #options
RichOrElse Nov 22, 2014
e4d2b89
turned to constants: FOOD & HERE
RichOrElse Nov 22, 2014
6b0d1ce
refactored receive #options
RichOrElse Nov 22, 2014
16415ce
refactored values
RichOrElse Nov 22, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
--color
--require spec_helper
--format documentation
21 changes: 21 additions & 0 deletions lib/tsibog.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
require 'foursquare2'

module Tsibog
CLIENT = Foursquare2::Client.new(:client_id => 'LQSHZK4YX3P5DTIUPRET2EDJ53SZPQSSCXG5IZXDMMQHRR0L', :client_secret => '11FO21GAOBGCIS3S5JEJADXMRH2IIVTIW4DIZANVR4LAV0JE', api_version: 20140806)
FOOD = '4d4b7105d754a06374d81259'

MAX_RADIUS = 100_000 # meters away
WALKING_DISTANCE = 80 # meters or 1 minute walk
TEN_MINUTES_AWAY = WALKING_DISTANCE * 10 # minutes

def self.food_venues
Venues.new(CLIENT.method :search_venues).with_category(FOOD).within(TEN_MINUTES_AWAY)
end

def self.[](id)
FoodPlace.new CLIENT.venue id
end

require_relative 'tsibog/venues'
require_relative 'tsibog/food_place'
end
47 changes: 47 additions & 0 deletions lib/tsibog/food_place.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module Tsibog
class FoodPlace
def initialize venue
@venue = venue
end

def id
@venue.id
end

def name
@venue.name
end

def address
@venue.location.address
end

def full_address
@venue.location.formattedAddress.join(', ')
end

def operations
timeframes.map {|tf| StoreOperation.new(tf.days, tf.open) }
end

private

def timeframes
hours ? hours.timeframes : []
end

def hours
@venue.hours || @venue.popular
end
end

class StoreOperation < Struct.new(:day, :open_hours)
def to_s
"#{day}: #{hours.join(', ')}"
end

def hours
open_hours.map {|hour| hour['renderedTime'] }
end
end
end
67 changes: 67 additions & 0 deletions lib/tsibog/venues.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
require 'forwardable'

module Tsibog
class Venues
def initialize(request)
raise ArgumentError, ":request must respond to []" unless request.respond_to?(:[])
@request = request
end

def options
@options ||= {}
end

def categories
(options['categoryId'] || '').split(',')
end

def with_category(category)
chain 'categoryId' => (categories << category).join(',')
end

def near(latlng, accuracy_in_meters = nil)
chain empty_or('llAcc', accuracy_in_meters).merge(ll: latlng)
end

def above(meters, accuracy_in_meters = nil) # altitude
chain empty_or('altAcc', accuracy_in_meters).merge(alt: meters)
end

def within(meters)
chain radius: meters
end

def top(quantity)
chain limit: quantity
end

def search(term)
chain query: term
end

def for(checkin_or_match_or_specials)
chain intent: checkin_or_match_or_specials
end

include Enumerable
extend Forwardable

def_delegators :request_venues, :each
def_delegators :to_a, :sample, :length, :size

protected

def request_venues
@request[options]['venues']
end

def chain(new_option)
(duplicate = dup).options.merge! new_option
duplicate
end

def empty_or(key, value)
value.nil? ? {} : {key => value}
end
end
end
89 changes: 89 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# This file was generated by the `rspec --init` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# The generated `.rspec` file contains `--require spec_helper` which will cause this
# file to always be loaded, without a need to explicitly require it in any files.
#
# Given that it is always loaded, you are encouraged to keep this file as
# light-weight as possible. Requiring heavyweight dependencies from this file
# will add to the boot time of your test suite on EVERY test run, even for an
# individual file that may not need all of that loaded. Instead, consider making
# a separate helper file that requires the additional dependencies and performs
# the additional setup, and require it from the spec files that actually need it.
#
# The `.rspec` file also contains a few flags that are not defaults but that
# users commonly want.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end

# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end

# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
=begin
# These two settings work together to allow you to limit a spec run
# to individual examples or groups you care about by tagging them with
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
# get run.
config.filter_run :focus
config.run_all_when_everything_filtered = true
# Limits the available syntax to the non-monkey patched syntax that is recommended.
# For more details, see:
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
config.disable_monkey_patching!
# This setting enables warnings. It's recommended, but in some cases may
# be too noisy due to issues in dependencies.
config.warnings = true
# Many RSpec users commonly either run the entire suite or an individual
# file, and it's useful to allow more verbose output when running an
# individual spec file.
if config.files_to_run.one?
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
config.default_formatter = 'doc'
end
# Print the 10 slowest examples and example groups at the
# end of the spec run, to help surface which specs are running
# particularly slow.
config.profile_examples = 10
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = :random
# Seed global randomization in this process using the `--seed` CLI option.
# Setting this allows you to use `--seed` to deterministically reproduce
# test failures related to randomization by passing the same `--seed` value
# as the one that triggered the failure.
Kernel.srand config.seed
=end
end
111 changes: 111 additions & 0 deletions spec/tsibog/venues_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
require 'tsibog/venues'

describe Tsibog::Venues do
subject { Tsibog::Venues.new(request) }

let(:request) { Hash.new('venues' => fetched_data) }
let(:fetched_data) { [{id: 1, name: 'Jollibee'}, {id: 2, name: 'Chowking'}, {id: 3, name: 'Mang inasal'}] }

FOOD = '4d4b7105d754a06374d81259'
HERE = '14.6371574,121.073077'

describe "#initialize" do
context :options do
it { expect(subject.options).to be_empty }
end

context :categories do
it { expect(subject.categories).to be_empty }
end

context "when argument doesn't support []" do
let(:request) { nil }

it { expect{subject}.to raise_error(ArgumentError) }
end
end

describe "#with_category" do
let(:food_venues) { subject.with_category(FOOD) }

context :categories do
it { expect(food_venues.categories).to include(FOOD) }
end

context :options do
it { expect(food_venues.options).to eq('categoryId' => FOOD) }
end
end

describe "#near" do
context :options do
it { expect(subject.near(HERE).options).to eq(ll: HERE) }

describe "with accuracy in meters" do
it { expect(subject.near(HERE, 10).options).to eq(:ll => HERE, 'llAcc' => 10) }
end
end
end

describe "#above" do
context :options do
it { expect(subject.above(100).options).to eq(alt: 100) }

describe "with accuracy in meters" do
it { expect(subject.above(100, 1).options).to eq(alt: 100, 'altAcc' => 1) }
end
end
end

describe "#within" do
context :options do
it { expect(subject.within(80).options).to eq(radius: 80) }
end
end

describe "#top" do
context :options do
it { expect(subject.top(20).options).to eq(limit: 20) }
end
end

describe "#search" do
context :options do
it { expect(subject.search('pizza').options).to eq(query: 'pizza') }
end
end

describe "#for" do
context :options do
it { expect(subject.for('checkin').options).to eq(intent: 'checkin') }
end
end

describe "when methods chained" do
context "returned output" do
let(:returned_output) { subject.with_category(FOOD).near(HERE).above(100).top(20).search('coffee').for('specials') }

context :options do
it "retain inputs" do
expect(returned_output.options).to eq('categoryId' => FOOD, :ll => HERE, :alt => 100, :limit => 20, :query => 'coffee', :intent => 'specials')
end
end

it { expect(returned_output).to be_instance_of(subject.class) }
end
end

describe "when enumerated" do
let(:venues) { subject.within(800).near(HERE, 10).above(100, 1).top(20).search('restaurant').for('match') }

context :request do
it "receive #options" do
expect(request).to receive(:[]).with(venues.options).and_return('venues' => ['somewhere'])
end
end

after do
expect(venues.sample).to eq('somewhere')
end
end
end
Loading