full_circle 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZjJiNzU3NmY0NGNmMzJmZjgyNDUwYTAxNzFiNjQwOTFkYWFhZjJkNA==
4
+ YTEwOGEyZGIxMWMyODc4Y2M5ZDEyNDZhODEzMTczNTUwN2VhNjJmMg==
5
5
  data.tar.gz: !binary |-
6
- NTA2NTgzNjljNTA1YjlmMDMzMjMxNmUyMzVjZTliZDdlZjQzYWNmMA==
6
+ YmRkNjQ4NjA5MTdmNzUyYjFhOTZjNGQ2YTZkNjU3ZmViMTM3MzVjNQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- ZWNjNjY0NTdiNWRjZWMyZTAzMWJhOTY0ZDFmYjQ5ZjBhNmJlYTIzOTVlNzI2
10
- NzY3MGQ5MzM5NDEwODNmNDk3MmE0NDkxNWYyYzRiNTQ5NThkNmNlMzgxMDll
11
- MjE0OTQ1MGIyYjg1OTM5ZTA4NGNjMTQyMGY0OGQ4MTQ3MTI0MGM=
9
+ NGIyMzMwNDFkOGQxZDk3YjljNjMxYmQ1ZDkzMTcwMDFkYmQ5N2JhNzFhZWJl
10
+ MGNlMzliYmRlNzA3OWNjNDYxYjBiMjRjYzgwZTdkMmM1MDk1ZjA4NjA0ZTFi
11
+ NTIyODM1NTI4ZDRjZjQ2NjhhNDVjNTdhYjc4ZGU5NjZiYjg4Mzk=
12
12
  data.tar.gz: !binary |-
13
- ZjRhNGQ5NWM4ZTEzMmU3MmRiODM3NjNkZDk4NzA5YWYyZWU1MTBjMTY4NDdk
14
- NGIzZTAxNzkyZjFhNTkzY2E0NmIyZTk3MzZjNzcyYmI5NjE2N2JkMzVjY2Mw
15
- MzhjMTA3ZmU1Mzg0ZWRjNzU0YzJkNmFjMjE5NzBjNzhjZDQyZjk=
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 "httparty"
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 'httparty'
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/response_parser'
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
@@ -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
- parser.parse response
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
- parser.parse response
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
- parser.parse response
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
- parser.parse response
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
- def initialize(domain)
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
- HTTParty.get(method_name,base_uri: base_uri, query: query_params)
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
@@ -1,3 +1,3 @@
1
1
  module FullCircle
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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
- it "calls the appropriate method on call_api_method" do
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
- it "calls the appropriate method on call_api_method" do
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
- it "calls the appropriate method on call_api_method" do
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
- it "calls the appropriate method on call_api_method" do
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
 
@@ -1,6 +1,8 @@
1
1
  require "spec_helper"
2
2
 
3
+
3
4
  describe FullCircle::ObjectBuilder do
5
+ it_behaves_like "an object builder"
4
6
 
5
7
  describe "#from_api_hash" do
6
8
  let(:builder) { described_class.new}
@@ -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
@@ -0,0 +1,9 @@
1
+ shared_examples_for "a cacher" do
2
+ it {should respond_to(:fetch).with(1).argument}
3
+
4
+ describe "#store" do
5
+ it "should return the value that is stored" do
6
+ subject.store("key","value").should eq "value"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ shared_examples_for "an event" do
2
+ required_attrs = :id, :date, :time, :title, :all_day_event, :date_mode, :site_id,
3
+ :type, :description
4
+
5
+ for attr in required_attrs
6
+ its(attr){should_not be_blank}
7
+ end
8
+
9
+
10
+ end
@@ -0,0 +1,3 @@
1
+ shared_examples_for "an object builder" do
2
+ it {should respond_to(:from_api_hash).with(1).argument}
3
+ 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.1.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-21 00:00:00.000000000 Z
11
+ date: 2013-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: httparty
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/response_parser.rb
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/response_parser_spec.rb
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/response_parser_spec.rb
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