full_circle 0.1.0 → 0.2.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.
- checksums.yaml +8 -8
- data/full_circle.gemspec +1 -1
- data/lib/full_circle.rb +5 -2
- data/lib/full_circle/api.rb +12 -8
- data/lib/full_circle/connection.rb +35 -3
- data/lib/full_circle/parsed_response.rb +58 -0
- data/lib/full_circle/response.rb +14 -0
- data/lib/full_circle/response_builder.rb +26 -0
- data/lib/full_circle/upcoming_event_builder.rb +44 -0
- data/lib/full_circle/version.rb +1 -1
- data/spec/full_circle/api_spec.rb +24 -5
- data/spec/full_circle/connection_spec.rb +36 -2
- data/spec/full_circle/object_builder_spec.rb +2 -0
- data/spec/full_circle/parsed_response_spec.rb +136 -0
- data/spec/full_circle/response_builder_spec.rb +50 -0
- data/spec/full_circle/response_spec.rb +29 -0
- data/spec/full_circle/upcoming_event_builder_spec.rb +51 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/shared/cacher_spec.rb +9 -0
- data/spec/support/shared/event_spec.rb +10 -0
- data/spec/support/shared/object_builder_spec.rb +3 -0
- metadata +21 -6
- data/lib/full_circle/response_parser.rb +0 -44
- data/spec/full_circle/response_parser_spec.rb +0 -187
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YTEwOGEyZGIxMWMyODc4Y2M5ZDEyNDZhODEzMTczNTUwN2VhNjJmMg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YmRkNjQ4NjA5MTdmNzUyYjFhOTZjNGQ2YTZkNjU3ZmViMTM3MzVjNQ==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NGIyMzMwNDFkOGQxZDk3YjljNjMxYmQ1ZDkzMTcwMDFkYmQ5N2JhNzFhZWJl
|
10
|
+
MGNlMzliYmRlNzA3OWNjNDYxYjBiMjRjYzgwZTdkMmM1MDk1ZjA4NjA0ZTFi
|
11
|
+
NTIyODM1NTI4ZDRjZjQ2NjhhNDVjNTdhYjc4ZGU5NjZiYjg4Mzk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
Zjk0YTY1YWY4ODA5NzA3Yjc1ODJkMTQ2ZDhiMDIxZmRjNGY2MmEzMjI1NTY4
|
14
|
+
OWRiNTFlOWEyZmNjZjE2MTZjZTI4YTZmZmExMzNlNzhmZGM2N2VmMTY1NDAz
|
15
|
+
NWFiODg1NDE0ZTY2OGJiY2NmMGI2Njc5MmVlYWM5OTY2YTc0ZmY=
|
data/full_circle.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
|
21
|
-
gem.add_dependency "
|
21
|
+
gem.add_dependency "multi_xml"
|
22
22
|
gem.add_dependency "activesupport", "~>3.2.12"
|
23
23
|
gem.add_development_dependency "rspec"
|
24
24
|
gem.add_development_dependency "vcr"
|
data/lib/full_circle.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
|
-
require '
|
1
|
+
require 'multi_xml'
|
2
2
|
require "active_support/core_ext"
|
3
3
|
|
4
4
|
require_relative 'full_circle/version'
|
5
5
|
require_relative 'full_circle/connection'
|
6
6
|
require_relative 'full_circle/object_builder'
|
7
|
-
require_relative 'full_circle/
|
7
|
+
require_relative 'full_circle/upcoming_event_builder'
|
8
|
+
require_relative 'full_circle/parsed_response'
|
9
|
+
require_relative 'full_circle/response_builder'
|
10
|
+
require_relative 'full_circle/response'
|
8
11
|
require_relative 'full_circle/api'
|
9
12
|
|
10
13
|
module FullCircle
|
data/lib/full_circle/api.rb
CHANGED
@@ -8,27 +8,31 @@ module FullCircle
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def fetch_events_for_ad(id)
|
11
|
-
parser = ResponseParser.new "ad.getEvents", "event"
|
12
11
|
response = connection.call_api_method("ad.getEvents", adId: id)
|
13
|
-
|
12
|
+
pr = ParsedResponse.new(response.body)
|
13
|
+
builder = ResponseBuilder.new pr.results, metadata: pr.metadata
|
14
|
+
builder.build.results
|
14
15
|
end
|
15
16
|
|
16
17
|
def fetch_coupons_for_ad(id)
|
17
|
-
parser = ResponseParser.new "ad.getCoupons", "coupon"
|
18
18
|
response = connection.call_api_method("ad.getCoupons", adId: id)
|
19
|
-
|
19
|
+
pr = ParsedResponse.new(response.body)
|
20
|
+
builder = ResponseBuilder.new pr.results, metadata: pr.metadata
|
21
|
+
builder.build.results
|
20
22
|
end
|
21
23
|
|
22
24
|
def fetch_event_areas()
|
23
|
-
parser = ResponseParser.new "city.getEventAreas", "eventArea"
|
24
25
|
response = connection.call_api_method("city.getEventAreas")
|
25
|
-
|
26
|
+
pr = ParsedResponse.new(response.body)
|
27
|
+
builder = ResponseBuilder.new pr.results, metadata: pr.metadata
|
28
|
+
builder.build.results
|
26
29
|
end
|
27
30
|
|
28
31
|
def fetch_upcoming_events(params={})
|
29
|
-
parser = ResponseParser.new "city.getUpcomingEvents", "event"
|
30
32
|
response = connection.call_api_method("city.getUpcomingEvents", params)
|
31
|
-
|
33
|
+
pr = ParsedResponse.new(response.body)
|
34
|
+
builder = ResponseBuilder.new pr.results, metadata: pr.metadata, object_builder: UpcomingEventBuilder.new
|
35
|
+
builder.build.results
|
32
36
|
end
|
33
37
|
end
|
34
38
|
end
|
@@ -1,10 +1,15 @@
|
|
1
|
+
require "net/http"
|
1
2
|
module FullCircle
|
2
3
|
class Connection
|
3
4
|
|
4
|
-
attr_reader :domain
|
5
|
+
attr_reader :domain, :cache
|
5
6
|
|
6
|
-
|
7
|
+
# domain - domain of directory (ex. 360durango.com)
|
8
|
+
# args
|
9
|
+
# - cache - Caching object to use
|
10
|
+
def initialize(domain, args={})
|
7
11
|
@domain = domain
|
12
|
+
@cache = args.fetch(:cache){NullCache.new}
|
8
13
|
end
|
9
14
|
|
10
15
|
def base_uri
|
@@ -12,7 +17,34 @@ module FullCircle
|
|
12
17
|
end
|
13
18
|
|
14
19
|
def call_api_method(method_name, query_params={})
|
15
|
-
|
20
|
+
uri_str = uri_string(method_name, query_params)
|
21
|
+
uri = URI(uri_str)
|
22
|
+
|
23
|
+
body = cache.fetch(uri_str) do
|
24
|
+
response_text = Net::HTTP.get(uri)
|
25
|
+
cache.store(uri_str, response_text)
|
26
|
+
end
|
27
|
+
|
28
|
+
Response.new body
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
NullCache = Class.new do
|
33
|
+
def fetch(key)
|
34
|
+
yield
|
35
|
+
end
|
36
|
+
|
37
|
+
def store(key, value)
|
38
|
+
value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
Response = Struct.new(:body)
|
44
|
+
|
45
|
+
|
46
|
+
def uri_string(method_name, query_params)
|
47
|
+
"#{base_uri}#{method_name}?#{query_params.to_query}"
|
16
48
|
end
|
17
49
|
end
|
18
50
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'multi_xml'
|
3
|
+
|
4
|
+
module FullCircle
|
5
|
+
class ParsedResponse
|
6
|
+
|
7
|
+
attr_reader :raw_xml
|
8
|
+
|
9
|
+
def initialize(raw_xml)
|
10
|
+
@raw_xml = raw_xml
|
11
|
+
end
|
12
|
+
|
13
|
+
def metadata
|
14
|
+
@metadata ||= build_metadata
|
15
|
+
end
|
16
|
+
|
17
|
+
def results
|
18
|
+
collection_array
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def response_hash
|
25
|
+
@response_hash ||= parsed_xml.fetch(parsed_xml.keys.first)
|
26
|
+
end
|
27
|
+
|
28
|
+
def collection_array
|
29
|
+
if @collection_array.nil?
|
30
|
+
result = collection_wrapper_hash.fetch(sub_enumerable_key_names(collection_wrapper_hash).first){[]}
|
31
|
+
@collection_array = Array.wrap(result);
|
32
|
+
end
|
33
|
+
@collection_array
|
34
|
+
end
|
35
|
+
|
36
|
+
def collection_wrapper_hash
|
37
|
+
@wrapped_collection ||= response_hash.fetch(sub_enumerable_key_names(response_hash).first){{}}
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def parsed_xml
|
42
|
+
@parsed_xml ||= MultiXml.parse(raw_xml)
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_metadata
|
46
|
+
{
|
47
|
+
page: Integer(response_hash.fetch("page"){1}),
|
48
|
+
total_pages: Integer(response_hash.fetch("totalPages"){1}),
|
49
|
+
total_results: Integer(response_hash.fetch("totalResults"){results.length}),
|
50
|
+
results_per_page: Integer(response_hash.fetch("resultsPerPage"){results.length})
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def sub_enumerable_key_names(hash)
|
55
|
+
hash.map {|k,v| k if v.kind_of? Enumerable }.reject{|k| k.nil?}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module FullCircle
|
2
|
+
class Response
|
3
|
+
attr_reader :results, :page, :total_pages, :total_results, :results_per_page
|
4
|
+
|
5
|
+
def initialize(results, metadata)
|
6
|
+
@results = results
|
7
|
+
@page = metadata.fetch(:page){1}
|
8
|
+
@total_pages = metadata.fetch(:total_pages){1}
|
9
|
+
@total_results = metadata.fetch(:total_results){results.length}
|
10
|
+
@results_per_page = metadata.fetch(:results_per_page){results.length}
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module FullCircle
|
2
|
+
class ResponseBuilder
|
3
|
+
|
4
|
+
attr_reader :api_results, :metadata, :object_builder
|
5
|
+
|
6
|
+
# Creates a new response builder
|
7
|
+
# api_results - collection of objects to be built into the response
|
8
|
+
# args
|
9
|
+
# metadata: hash of metadata
|
10
|
+
# object_builder: The object builder to use for building api objects
|
11
|
+
def initialize(api_results, args={})
|
12
|
+
@api_results = api_results
|
13
|
+
@metadata = args.fetch(:metadata){{}}
|
14
|
+
@object_builder = args.fetch(:object_builder){ObjectBuilder.new}
|
15
|
+
end
|
16
|
+
|
17
|
+
def build
|
18
|
+
objects = api_results.map do |result|
|
19
|
+
object_builder.from_api_hash(result)
|
20
|
+
end
|
21
|
+
|
22
|
+
Response.new(objects,metadata)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module FullCircle
|
4
|
+
class UpcomingEventBuilder
|
5
|
+
def initialize
|
6
|
+
@domain = "360durango.com"
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_api_hash(hash)
|
10
|
+
@hash = hash
|
11
|
+
result = OpenStruct.new({
|
12
|
+
id: hash.fetch("id"),
|
13
|
+
date: hash.fetch("date"),
|
14
|
+
title: hash.fetch("title"),
|
15
|
+
time: hash.fetch("time"),
|
16
|
+
all_day_event: hash.fetch("allDayEvent"),
|
17
|
+
date_mode: hash.fetch("dateMode"),
|
18
|
+
site_id: hash.fetch("siteId"),
|
19
|
+
type: hash.fetch("type"),
|
20
|
+
|
21
|
+
image_url: hash.fetch("ad"){{}}.fetch("logoImage"){{}}["url"],
|
22
|
+
end_date: hash["endDate"],
|
23
|
+
expire_date: hash["expireDate"],
|
24
|
+
end_time: hash["endTime"],
|
25
|
+
description: hash["__content__"],
|
26
|
+
ad_id: ad_id,
|
27
|
+
})
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
private
|
32
|
+
attr_reader :hash
|
33
|
+
attr_reader :domain
|
34
|
+
|
35
|
+
def event_id
|
36
|
+
hash.fetch("id")
|
37
|
+
end
|
38
|
+
|
39
|
+
def ad_id
|
40
|
+
hash.fetch("ad"){{}}["id"]
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
data/lib/full_circle/version.rb
CHANGED
@@ -6,13 +6,25 @@ describe FullCircle::API do
|
|
6
6
|
let!(:api){FullCircle::API.new(FullCircle::Connection.new("360durango.com"))}
|
7
7
|
|
8
8
|
describe "#fetch_events_for_ad" do
|
9
|
-
|
9
|
+
pending "calls the appropriate method on call_api_method" do
|
10
10
|
mock_connection = double()
|
11
|
-
mock_connection.should_receive(:call_api_method).with("ad.getEvents",{adId: "1"})
|
11
|
+
mock_connection.should_receive(:call_api_method).with("ad.getEvents",{adId: "1"}) do
|
12
|
+
class ResponseDouble
|
13
|
+
def body
|
14
|
+
end
|
15
|
+
end
|
16
|
+
ResponseDouble.new
|
17
|
+
end
|
12
18
|
|
13
19
|
described_class.new(mock_connection).fetch_events_for_ad("1")
|
14
20
|
end
|
15
21
|
|
22
|
+
describe "event object" do
|
23
|
+
use_vcr_cassette "single_get_events_response"
|
24
|
+
subject {api.fetch_events_for_ad("81213").first}
|
25
|
+
it_behaves_like "an event"
|
26
|
+
end
|
27
|
+
|
16
28
|
context "with one event" do
|
17
29
|
it "returns an array of one event" do
|
18
30
|
VCR.use_cassette "single_get_events_response" do
|
@@ -48,7 +60,7 @@ describe FullCircle::API do
|
|
48
60
|
|
49
61
|
describe "#fetch_coupons_for_ad" do
|
50
62
|
|
51
|
-
|
63
|
+
pending "calls the appropriate method on call_api_method" do
|
52
64
|
mock_connection = double()
|
53
65
|
mock_connection.should_receive(:call_api_method).with("ad.getCoupons",{adId: "1"})
|
54
66
|
|
@@ -86,7 +98,7 @@ describe FullCircle::API do
|
|
86
98
|
end
|
87
99
|
|
88
100
|
describe "#fetch_event_areas" do
|
89
|
-
|
101
|
+
pending "calls the appropriate method on call_api_method" do
|
90
102
|
mock_connection = double()
|
91
103
|
mock_connection.should_receive(:call_api_method).with("city.getEventAreas")
|
92
104
|
|
@@ -127,13 +139,20 @@ describe FullCircle::API do
|
|
127
139
|
|
128
140
|
describe "#fetch_upcoming_events" do
|
129
141
|
|
130
|
-
|
142
|
+
pending "calls the appropriate method on call_api_method" do
|
131
143
|
mock_connection = double()
|
132
144
|
mock_connection.should_receive(:call_api_method).with("city.getUpcomingEvents",{})
|
133
145
|
|
134
146
|
described_class.new(mock_connection).fetch_upcoming_events
|
135
147
|
end
|
136
148
|
|
149
|
+
describe "event object" do
|
150
|
+
use_vcr_cassette "single_get_upcoming_events_response"
|
151
|
+
|
152
|
+
subject {api.fetch_upcoming_events(areaId:"592").first}
|
153
|
+
it_behaves_like "an event"
|
154
|
+
end
|
155
|
+
|
137
156
|
context "with one event" do
|
138
157
|
it "returns an array of one event" do
|
139
158
|
VCR.use_cassette "single_get_upcoming_events_response" do
|
@@ -7,14 +7,48 @@ describe FullCircle::Connection do
|
|
7
7
|
its(:domain) {should == "360durango.com"}
|
8
8
|
its(:base_uri) {should == "http://api.360durango.com/1.0/"}
|
9
9
|
|
10
|
+
let!(:req_stub) {stub_http_request(:get, "api.360durango.com/1.0/ad.getCoupons").with(query: {adId: "81304"})
|
11
|
+
.to_return(body: "abc")
|
12
|
+
}
|
13
|
+
|
10
14
|
describe ".call_api_method" do
|
11
|
-
it "should call HTTParty.get with the correct arguments" do
|
12
|
-
HTTParty.should_receive(:get).with("ad.getCoupons",base_uri: subject.base_uri, query: {adId: "81304"})
|
13
15
|
|
16
|
+
it "should request the correct uri" do
|
14
17
|
subject.call_api_method "ad.getCoupons", adId: "81304"
|
18
|
+
|
19
|
+
req_stub.should have_been_requested
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return the correct data" do
|
23
|
+
response = subject.call_api_method "ad.getCoupons", adId: "81304"
|
24
|
+
response.body.should eq("abc")
|
25
|
+
end
|
26
|
+
|
27
|
+
context "without cache" do
|
28
|
+
it "should make the http request each time" do
|
29
|
+
subject.call_api_method "ad.getCoupons", adId: "81304"
|
30
|
+
subject.call_api_method "ad.getCoupons", adId: "81304"
|
31
|
+
|
32
|
+
req_stub.should have_been_requested.twice
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "with cache" do
|
37
|
+
subject {FullCircle::Connection.new "360durango.com", cache: {}}
|
38
|
+
|
39
|
+
it "should make the http request each time" do
|
40
|
+
subject.call_api_method "ad.getCoupons", adId: "81304"
|
41
|
+
subject.call_api_method "ad.getCoupons", adId: "81304"
|
42
|
+
|
43
|
+
req_stub.should have_been_requested.once
|
44
|
+
end
|
15
45
|
end
|
16
46
|
|
47
|
+
end
|
17
48
|
|
49
|
+
describe FullCircle::Connection::NullCache do
|
50
|
+
subject {FullCircle::Connection::NullCache.new}
|
51
|
+
it_behaves_like "a cacher"
|
18
52
|
end
|
19
53
|
|
20
54
|
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FullCircle::ParsedResponse do
|
4
|
+
|
5
|
+
describe "#metadata" do
|
6
|
+
context "with provided metadata" do
|
7
|
+
let(:xml) do
|
8
|
+
<<"EOS"
|
9
|
+
<?xml version="1.0"?>
|
10
|
+
<ad-getListResponse page="2" resultsPerPage="2" totalPages="541" totalResults="1081">
|
11
|
+
<ads>
|
12
|
+
<ad id="81009" name="4Core" url="http://360Durango.com/Environmental/4core.html"
|
13
|
+
eventCount="0" couponCount="0" jobCount="0" locationCount="1" popupCount="0"
|
14
|
+
slideshowCount="0" linkCount="0">
|
15
|
+
<address addr1="949 E 2ND AV" city="DURANGO" state="CO" zipCode="81301"></address>
|
16
|
+
</ad>
|
17
|
+
<ad id="123760" name="4x4 Auto " url="http://360Durango.com/Automotive/4x4Auto.html"
|
18
|
+
description="Used Car Dealership Cortez 360Durango Colorado" eventCount="0"
|
19
|
+
couponCount="0" jobCount="0" locationCount="0" popupCount="0" slideshowCount="0"
|
20
|
+
linkCount="0">
|
21
|
+
</ad>
|
22
|
+
</ads>
|
23
|
+
</ad-getListResponse>
|
24
|
+
EOS
|
25
|
+
end
|
26
|
+
|
27
|
+
subject { described_class.new(xml).metadata }
|
28
|
+
|
29
|
+
its([:page]){should eq 2}
|
30
|
+
its([:results_per_page]){should eq 2}
|
31
|
+
its([ :total_pages ]){should eq 541 }
|
32
|
+
its([ :total_results ]){should eq 1081}
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
context "with no provided metadata" do
|
39
|
+
let (:xml) do
|
40
|
+
<<"EOS"
|
41
|
+
<?xml version="1.0"?>
|
42
|
+
<ad-getCouponsResponse>
|
43
|
+
<coupons>
|
44
|
+
<coupon id="32025" name="90 for 90!" begin="2013-04-04"
|
45
|
+
expire="2013-04-30" accept_offline="1" accept_online="0" acceptMobile="1" acceptPrint="1">
|
46
|
+
<offer>Get a relaxing and restorative 90 minute massage for just $90!</offer>
|
47
|
+
<restrictions>Service must be booked in the month of April.</restrictions>
|
48
|
+
</coupon>
|
49
|
+
<coupon id="32025" name="90 for 90!" begin="2013-04-04"
|
50
|
+
expire="2013-04-30" accept_offline="1" accept_online="0" acceptMobile="1" acceptPrint="1">
|
51
|
+
<offer>Get a relaxing and restorative 90 minute massage for just $90!</offer>
|
52
|
+
<restrictions>Service must be booked in the month of April.</restrictions>
|
53
|
+
</coupon>
|
54
|
+
</coupons>
|
55
|
+
</ad-getCouponsResponse>
|
56
|
+
EOS
|
57
|
+
end
|
58
|
+
|
59
|
+
subject { described_class.new(xml).metadata }
|
60
|
+
|
61
|
+
its([ :page ]){should eq 1}
|
62
|
+
its([ :total_pages ]){should eq 1 }
|
63
|
+
its([ :total_results ]) {should eq 2}
|
64
|
+
its([ :results_per_page ]) {should eq 2 }
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
describe "#results" do
|
71
|
+
|
72
|
+
context "with no results" do
|
73
|
+
let(:xml) do
|
74
|
+
<<"EOS"
|
75
|
+
<?xml version="1.0"?>
|
76
|
+
<ad-getCouponsResponse>
|
77
|
+
<coupons></coupons>
|
78
|
+
</ad-getCouponsResponse>
|
79
|
+
EOS
|
80
|
+
end
|
81
|
+
|
82
|
+
subject{described_class.new(xml).results}
|
83
|
+
it { should eq [] }
|
84
|
+
end
|
85
|
+
|
86
|
+
context "with one result" do
|
87
|
+
|
88
|
+
let (:xml) do
|
89
|
+
<<"EOS"
|
90
|
+
<?xml version="1.0"?>
|
91
|
+
<ad-getCouponsResponse>
|
92
|
+
<coupons>
|
93
|
+
<coupon id="32025" name="90 for 90!" begin="2013-04-04"
|
94
|
+
expire="2013-04-30" accept_offline="1" accept_online="0" acceptMobile="1" acceptPrint="1">
|
95
|
+
<offer>Get a relaxing and restorative 90 minute massage for just $90!</offer>
|
96
|
+
<restrictions>Service must be booked in the month of April.</restrictions>
|
97
|
+
</coupon>
|
98
|
+
</coupons>
|
99
|
+
</ad-getCouponsResponse>
|
100
|
+
EOS
|
101
|
+
end
|
102
|
+
|
103
|
+
subject{described_class.new(xml).results}
|
104
|
+
its(:length){should eq 1 }
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
context "with multiple results" do
|
109
|
+
let(:xml) do
|
110
|
+
<<"EOS"
|
111
|
+
<?xml version="1.0"?>
|
112
|
+
<ad-getListResponse page="2" resultsPerPage="2" totalPages="541" totalResults="1081">
|
113
|
+
<ads>
|
114
|
+
<ad id="81009" name="4Core" url="http://360Durango.com/Environmental/4core.html"
|
115
|
+
eventCount="0" couponCount="0" jobCount="0" locationCount="1" popupCount="0"
|
116
|
+
slideshowCount="0" linkCount="0">
|
117
|
+
<address addr1="949 E 2ND AV" city="DURANGO" state="CO" zipCode="81301"></address>
|
118
|
+
</ad>
|
119
|
+
<ad id="123760" name="4x4 Auto " url="http://360Durango.com/Automotive/4x4Auto.html"
|
120
|
+
description="Used Car Dealership Cortez 360Durango Colorado" eventCount="0"
|
121
|
+
couponCount="0" jobCount="0" locationCount="0" popupCount="0" slideshowCount="0"
|
122
|
+
linkCount="0">
|
123
|
+
</ad>
|
124
|
+
</ads>
|
125
|
+
</ad-getListResponse>
|
126
|
+
EOS
|
127
|
+
end
|
128
|
+
|
129
|
+
subject { described_class.new(xml).results }
|
130
|
+
|
131
|
+
its(:length){should eq 2}
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe FullCircle::ResponseBuilder do
|
5
|
+
let(:object_builder_double) do
|
6
|
+
class ObjectBuilderDouble
|
7
|
+
def from_api_hash(arg)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
ObjectBuilderDouble.new
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "object_builder_double" do
|
14
|
+
subject {object_builder_double}
|
15
|
+
it_behaves_like "an object builder"
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#build" do
|
19
|
+
context "with empty array of api_results" do
|
20
|
+
subject{ described_class.new [], object_builder: object_builder_double }
|
21
|
+
|
22
|
+
it "calls object_builder.from_api_hash" do
|
23
|
+
object_builder_double.should_not_receive(:from_api_hash)
|
24
|
+
subject.build
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
context "with an array of multiple api_results" do
|
30
|
+
subject{ described_class.new [{},{}], object_builder: object_builder_double }
|
31
|
+
|
32
|
+
it "calls object_builder.from_api_hash" do
|
33
|
+
object_builder_double.should_receive(:from_api_hash).with({}).exactly(2).times
|
34
|
+
subject.build
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "response outgoing messages" do
|
39
|
+
subject{ described_class.new [{},{}], object_builder: object_builder_double }
|
40
|
+
|
41
|
+
it "should create a response with the correct arguments" do
|
42
|
+
FullCircle::Response.should_receive(:new).with([nil,nil],{})
|
43
|
+
|
44
|
+
subject.build
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FullCircle::Response do
|
4
|
+
|
5
|
+
describe "defaults" do
|
6
|
+
subject{described_class.new([],{})}
|
7
|
+
|
8
|
+
its(:results){should eq []}
|
9
|
+
its(:page){should eq 1}
|
10
|
+
its(:total_pages){should eq 1}
|
11
|
+
its(:results_per_page){should eq 0 }
|
12
|
+
its(:total_results){should eq 0 }
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "with metadata" do
|
17
|
+
subject{described_class.new([],{page: 2, total_pages:5, results_per_page: 5, total_results: 25})}
|
18
|
+
|
19
|
+
its(:results){should eq []}
|
20
|
+
its(:page){should eq 2}
|
21
|
+
its(:total_pages){should eq 5}
|
22
|
+
its(:results_per_page){should eq 5 }
|
23
|
+
its(:total_results){should eq 25 }
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe FullCircle::UpcomingEventBuilder do
|
4
|
+
it_behaves_like "an object builder"
|
5
|
+
|
6
|
+
describe "event output" do
|
7
|
+
let(:api_hash) do
|
8
|
+
{
|
9
|
+
"id" => "51019",
|
10
|
+
"date" => "2013-04-22",
|
11
|
+
"expireDate" => "2013-06-24",
|
12
|
+
"time" => "16:00:00",
|
13
|
+
"endTime" => "22:00:00",
|
14
|
+
"title" => "Burger Nite",
|
15
|
+
"allDayEvent" => "0",
|
16
|
+
"type" => "Food Special",
|
17
|
+
"dateMode" => "4",
|
18
|
+
"siteId" => "77",
|
19
|
+
"price" => "$4.95",
|
20
|
+
"linkText" => "Like us on Facebook!",
|
21
|
+
"linkUrl" => "https://www.facebook.com/pages/Olde-Tymers-Cafe/107138292687599",
|
22
|
+
"featured" => "1",
|
23
|
+
"ad" => {
|
24
|
+
"id" => "81277",
|
25
|
+
"name" => "Olde Tymers Cafe",
|
26
|
+
"url" => "http://360Durango.com/Attractions/oldetymerscafe.html",
|
27
|
+
"description" => "Downtown Durango's Best Burger Cafe with Outdoor Patio!",
|
28
|
+
"eventCount" => "6",
|
29
|
+
"couponCount" => "0",
|
30
|
+
"jobCount" => "0",
|
31
|
+
"locationCount" => "1",
|
32
|
+
"popupCount" => "0",
|
33
|
+
"slideshowCount" => "2",
|
34
|
+
"linkCount" => "2",
|
35
|
+
"address" => {
|
36
|
+
"addr1" => "1000 Main Avenue",
|
37
|
+
"city" => "Durango",
|
38
|
+
"state" => "CO",
|
39
|
+
"zipCode" => "81301",
|
40
|
+
"phone" => "970.259.2990"
|
41
|
+
}
|
42
|
+
},
|
43
|
+
"__content__" => "Since 1981 Olde Tymers Cafe has been bringing people together with a relaxing atmosphere, great food, and libations."
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
subject {described_class.new.from_api_hash(api_hash)}
|
48
|
+
|
49
|
+
it_behaves_like "an event"
|
50
|
+
end
|
51
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -2,10 +2,16 @@
|
|
2
2
|
$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
3
3
|
|
4
4
|
require 'rspec'
|
5
|
+
require 'webmock/rspec'
|
5
6
|
require 'vcr'
|
6
7
|
require 'full_circle'
|
8
|
+
Dir["./spec/support/**/*.rb"].sort.each {|f| require f}
|
7
9
|
|
8
10
|
VCR.configure do |c|
|
9
11
|
c.cassette_library_dir = "spec/fixtures/vcr_cassettes"
|
10
12
|
c.hook_into :webmock
|
11
13
|
end
|
14
|
+
|
15
|
+
RSpec.configure do |c|
|
16
|
+
c.extend VCR::RSpec::Macros
|
17
|
+
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: full_circle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Renner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-04-
|
11
|
+
date: 2013-04-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: multi_xml
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ! '>='
|
@@ -140,7 +140,10 @@ files:
|
|
140
140
|
- lib/full_circle/api.rb
|
141
141
|
- lib/full_circle/connection.rb
|
142
142
|
- lib/full_circle/object_builder.rb
|
143
|
-
- lib/full_circle/
|
143
|
+
- lib/full_circle/parsed_response.rb
|
144
|
+
- lib/full_circle/response.rb
|
145
|
+
- lib/full_circle/response_builder.rb
|
146
|
+
- lib/full_circle/upcoming_event_builder.rb
|
144
147
|
- lib/full_circle/version.rb
|
145
148
|
- spec/fixtures/vcr_cassettes/empty_event_area_response.yml
|
146
149
|
- spec/fixtures/vcr_cassettes/empty_get_coupons_response.yml
|
@@ -157,8 +160,14 @@ files:
|
|
157
160
|
- spec/full_circle/api_spec.rb
|
158
161
|
- spec/full_circle/connection_spec.rb
|
159
162
|
- spec/full_circle/object_builder_spec.rb
|
160
|
-
- spec/full_circle/
|
163
|
+
- spec/full_circle/parsed_response_spec.rb
|
164
|
+
- spec/full_circle/response_builder_spec.rb
|
165
|
+
- spec/full_circle/response_spec.rb
|
166
|
+
- spec/full_circle/upcoming_event_builder_spec.rb
|
161
167
|
- spec/spec_helper.rb
|
168
|
+
- spec/support/shared/cacher_spec.rb
|
169
|
+
- spec/support/shared/event_spec.rb
|
170
|
+
- spec/support/shared/object_builder_spec.rb
|
162
171
|
homepage: https://github.com/aaronrenner/full_circle
|
163
172
|
licenses: []
|
164
173
|
metadata: {}
|
@@ -198,5 +207,11 @@ test_files:
|
|
198
207
|
- spec/full_circle/api_spec.rb
|
199
208
|
- spec/full_circle/connection_spec.rb
|
200
209
|
- spec/full_circle/object_builder_spec.rb
|
201
|
-
- spec/full_circle/
|
210
|
+
- spec/full_circle/parsed_response_spec.rb
|
211
|
+
- spec/full_circle/response_builder_spec.rb
|
212
|
+
- spec/full_circle/response_spec.rb
|
213
|
+
- spec/full_circle/upcoming_event_builder_spec.rb
|
202
214
|
- spec/spec_helper.rb
|
215
|
+
- spec/support/shared/cacher_spec.rb
|
216
|
+
- spec/support/shared/event_spec.rb
|
217
|
+
- spec/support/shared/object_builder_spec.rb
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module FullCircle
|
2
|
-
class ResponseParser
|
3
|
-
|
4
|
-
attr_reader :api_method_name, :object_name
|
5
|
-
|
6
|
-
def initialize(api_method_name, object_name)
|
7
|
-
@api_method_name= api_method_name
|
8
|
-
@object_name = object_name
|
9
|
-
end
|
10
|
-
|
11
|
-
def parse(response)
|
12
|
-
if response
|
13
|
-
attrs = response.parsed_response
|
14
|
-
|
15
|
-
parse_response(attrs, response_name, object_name)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
# example
|
25
|
-
# parseResponse(attrs, "city_getEventAreasResponse", "eventArea")
|
26
|
-
def parse_response(attrs, response_name, object_name)
|
27
|
-
if attrs[response_name][object_name.pluralize].nil?
|
28
|
-
[]
|
29
|
-
else
|
30
|
-
response_attrs = Array.wrap(attrs[response_name][object_name.pluralize][object_name])
|
31
|
-
|
32
|
-
builder = ObjectBuilder.new
|
33
|
-
response_attrs.collect do |response_attr_set|
|
34
|
-
builder.from_api_hash(response_attr_set)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def response_name
|
40
|
-
@response_name ||= "#{api_method_name.gsub(/\./,'_')}Response"
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
@@ -1,187 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe FullCircle::ResponseParser do
|
4
|
-
|
5
|
-
describe "#parse" do
|
6
|
-
|
7
|
-
|
8
|
-
context "parsing coupons" do
|
9
|
-
|
10
|
-
let(:parser) {described_class.new "ad.getCoupons","coupon"}
|
11
|
-
|
12
|
-
context "with one coupon" do
|
13
|
-
it "returns an array of one coupon" do
|
14
|
-
response_double = double("response")
|
15
|
-
response_double.stub(:parsed_response) do
|
16
|
-
{"ad_getCouponsResponse" => {"coupons" => {"coupon" =>
|
17
|
-
{"id" => "58794", :name => "Early Bird Discount"}
|
18
|
-
}}}
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
results = parser.parse response_double
|
23
|
-
|
24
|
-
results.should be_a Array
|
25
|
-
results.length.should == 1
|
26
|
-
coupon = results.first
|
27
|
-
coupon.id.should eq "58794"
|
28
|
-
coupon.name.should eq "Early Bird Discount"
|
29
|
-
|
30
|
-
#TODO Test command message is sent to object builder
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
context "with multiple coupons" do
|
36
|
-
it "returns an array of multiple coupons" do
|
37
|
-
response_double = double("response")
|
38
|
-
response_double.stub(:parsed_response) do
|
39
|
-
{"ad_getCouponsResponse" => {"coupons" => {"coupon" =>[
|
40
|
-
{"id" => "58794", :name => "TWO FOR ONE ENTREES"},
|
41
|
-
{"id" => "12345", :name => "Three FOR ONE ENTREES"}
|
42
|
-
]}}}
|
43
|
-
end
|
44
|
-
|
45
|
-
results = parser.parse response_double
|
46
|
-
|
47
|
-
results.should be_a Array
|
48
|
-
results.length.should == 2
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context "with no coupons" do
|
53
|
-
it "returns an empty array" do
|
54
|
-
response_double = double("response")
|
55
|
-
response_double.stub(:parsed_response) do
|
56
|
-
{"ad_getCouponsResponse" => {"coupons" => nil}}
|
57
|
-
end
|
58
|
-
|
59
|
-
results = parser.parse response_double
|
60
|
-
|
61
|
-
results.should eq []
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context "parsing events" do
|
67
|
-
|
68
|
-
let(:parser) {described_class.new "ad.getEvents","event"}
|
69
|
-
|
70
|
-
context "with one event" do
|
71
|
-
|
72
|
-
it "returns an array of one event" do
|
73
|
-
response_double = double("response")
|
74
|
-
response_double.stub(:parsed_response) do
|
75
|
-
{"ad_getEventsResponse" => {"events" => {"event" =>
|
76
|
-
{"id" => "58794", :title => "TWO FOR ONE ENTREES"}
|
77
|
-
}}}
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
results = parser.parse response_double
|
82
|
-
|
83
|
-
results.should be_a Array
|
84
|
-
results.length.should == 1
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
89
|
-
|
90
|
-
context "with multiple events" do
|
91
|
-
|
92
|
-
it "returns an array of multiple events" do
|
93
|
-
response_double = double("response")
|
94
|
-
response_double.stub(:parsed_response) do
|
95
|
-
{"ad_getEventsResponse" => {"events" => {"event" =>[
|
96
|
-
{"id" => "58794", :title => "TWO FOR ONE ENTREES"},
|
97
|
-
{"id" => "12345", :title => "Three FOR ONE ENTREES"}
|
98
|
-
]}}}
|
99
|
-
end
|
100
|
-
|
101
|
-
results = parser.parse response_double
|
102
|
-
|
103
|
-
results.should be_a Array
|
104
|
-
results.length.should == 2
|
105
|
-
end
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
context "with no events" do
|
110
|
-
it "returns an emtpy array" do
|
111
|
-
|
112
|
-
response_double = double("response")
|
113
|
-
response_double.stub(:parsed_response) do
|
114
|
-
{"ad_getEventsResponse" => {"events" => nil}}
|
115
|
-
end
|
116
|
-
|
117
|
-
results = parser.parse response_double
|
118
|
-
|
119
|
-
results.should eq []
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
context "parsing event areas" do
|
126
|
-
|
127
|
-
let(:parser) {described_class.new "city.getEventAreas","eventArea"}
|
128
|
-
|
129
|
-
context "with one event areas" do
|
130
|
-
|
131
|
-
it "returns an array of one event area" do
|
132
|
-
response_double = double("response")
|
133
|
-
response_double.stub(:parsed_response) do
|
134
|
-
{"city_getEventAreasResponse" => {"eventAreas" => {"eventArea" =>
|
135
|
-
{"id" => "736", :title => "Bayfield"}
|
136
|
-
}}}
|
137
|
-
end
|
138
|
-
|
139
|
-
|
140
|
-
results = parser.parse response_double
|
141
|
-
|
142
|
-
results.should be_a Array
|
143
|
-
results.length.should == 1
|
144
|
-
|
145
|
-
|
146
|
-
end
|
147
|
-
|
148
|
-
end
|
149
|
-
|
150
|
-
context "with multiple event areas" do
|
151
|
-
|
152
|
-
it "returns an array of multiple event areas" do
|
153
|
-
response_double = double("response")
|
154
|
-
response_double.stub(:parsed_response) do
|
155
|
-
{"city_getEventAreasResponse" => {"eventAreas" => {"eventArea" =>[
|
156
|
-
{"id" => "58794", :title => "Bayfield"},
|
157
|
-
{"id" => "12345", :title => "Vallecito"}
|
158
|
-
]}}}
|
159
|
-
end
|
160
|
-
|
161
|
-
results = parser.parse response_double
|
162
|
-
|
163
|
-
results.should be_a Array
|
164
|
-
results.length.should == 2
|
165
|
-
end
|
166
|
-
|
167
|
-
end
|
168
|
-
|
169
|
-
context "with no event areas" do
|
170
|
-
it "returns an emtpy array" do
|
171
|
-
|
172
|
-
response_double = double("response")
|
173
|
-
response_double.stub(:parsed_response) do
|
174
|
-
{"city_getEventAreasResponse" => {"eventAreas" => nil}}
|
175
|
-
end
|
176
|
-
|
177
|
-
results = parser.parse response_double
|
178
|
-
|
179
|
-
results.should eq []
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
end
|
184
|
-
|
185
|
-
end
|
186
|
-
|
187
|
-
end
|