populr 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ gem "rest-client", ">= 1.6"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "rdoc", "~> 3.12"
11
+ gem "bundler", "~> 1.3.5"
12
+ gem "jeweler", "~> 1.8.4"
13
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,43 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.2.8)
5
+ i18n (~> 0.6)
6
+ multi_json (~> 1.0)
7
+ bourne (1.4.0)
8
+ mocha (~> 0.13.2)
9
+ git (1.2.5)
10
+ i18n (0.6.1)
11
+ jeweler (1.8.4)
12
+ bundler (~> 1.0)
13
+ git (>= 1.2.5)
14
+ rake
15
+ rdoc
16
+ json (1.7.5)
17
+ metaclass (0.0.1)
18
+ mime-types (1.19)
19
+ mocha (0.13.3)
20
+ metaclass (~> 0.0.1)
21
+ multi_json (1.3.6)
22
+ rake (10.0.3)
23
+ rdoc (3.12)
24
+ json (~> 1.4)
25
+ rest-client (1.6.7)
26
+ mime-types (>= 1.16)
27
+ shoulda (3.4.0)
28
+ shoulda-context (~> 1.0, >= 1.0.1)
29
+ shoulda-matchers (~> 1.0, >= 1.4.1)
30
+ shoulda-context (1.1.1)
31
+ shoulda-matchers (1.5.6)
32
+ activesupport (>= 3.0.0)
33
+ bourne (~> 1.3)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ bundler (~> 1.3.5)
40
+ jeweler (~> 1.8.4)
41
+ rdoc (~> 3.12)
42
+ rest-client (>= 1.6)
43
+ shoulda
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2011- Project 10k, Inc. (https://populr.me)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = Populr.me Ruby Gem
2
+
3
+ A rubygem for interacting with the Populr.me API from Ruby apps.
4
+
5
+ == Contributing to the Populr.me Ruby Gem
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
9
+ * Fork the project.
10
+ * Start a feature/bugfix branch.
11
+ * Commit and push until you are happy with your contribution.
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2013 Project 10K. See LICENSE.md for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "populr"
18
+ gem.homepage = "http://github.com/bengotow/populr"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Gem for interacting with the Populr.me API}
21
+ gem.description = %Q{Gem for interacting with the Populr.me API}
22
+ gem.email = "ben@populr.me"
23
+ gem.authors = ["Ben Gotow"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+
36
+ require 'rdoc/task'
37
+ Rake::RDocTask.new do |rdoc|
38
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
39
+
40
+ rdoc.rdoc_dir = 'rdoc'
41
+ rdoc.title = "populr #{version}"
42
+ rdoc.rdoc_files.include('README*')
43
+ rdoc.rdoc_files.include('lib/**/*.rb')
44
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
data/lib/asset.rb ADDED
@@ -0,0 +1,24 @@
1
+ require 'restful_model'
2
+
3
+ class Asset < RestfulModel
4
+
5
+ attr_accessor :description
6
+ attr_accessor :title
7
+
8
+ # as an alternative to calling Asset.new, you can call populr.images.build
9
+ def initialize(api, file, title = nil, description = nil)
10
+ super(api)
11
+
12
+ @file = file
13
+ self.title = title
14
+ self.description = description
15
+ self.link = link
16
+ end
17
+
18
+ def to_json(options = {})
19
+ hash = super(options)
20
+ hash[:file] = @file if options[:api_representation] && @file
21
+ hash
22
+ end
23
+
24
+ end
@@ -0,0 +1,10 @@
1
+ require 'asset'
2
+
3
+ class DocumentAsset < Asset
4
+
5
+ def self.collection_name
6
+ "documents"
7
+ end
8
+
9
+ end
10
+
data/lib/domain.rb ADDED
@@ -0,0 +1,7 @@
1
+ class Domain < String
2
+
3
+ def self.collection_name
4
+ "domains"
5
+ end
6
+
7
+ end
@@ -0,0 +1,12 @@
1
+ require 'asset'
2
+
3
+ class ImageAsset < Asset
4
+
5
+ attr_accessor :link
6
+
7
+ def self.collection_name
8
+ "images"
9
+ end
10
+
11
+ end
12
+
data/lib/pop.rb ADDED
@@ -0,0 +1,93 @@
1
+ require 'restful_model'
2
+ require 'tracer'
3
+
4
+ class Pop < RestfulModel
5
+
6
+ class TemplateRequired < StandardError; end
7
+
8
+ attr_accessor :template_id
9
+ attr_accessor :name
10
+ attr_accessor :title
11
+ attr_accessor :slug
12
+ attr_accessor :label_names
13
+ attr_accessor :tracers
14
+ attr_accessor :published_pop_url
15
+ attr_accessor :unpopulated_api_regions
16
+ attr_accessor :unpopulated_api_tags
17
+ attr_accessor :domain
18
+ attr_accessor :password
19
+
20
+ attr_reader :newly_populated_regions
21
+ attr_reader :newly_populated_tags
22
+
23
+ def initialize(api_or_template, template = nil)
24
+ template = template || api_or_template
25
+
26
+ if template.is_a?(Template)
27
+ self.template_id = template._id
28
+ @_api = template._api
29
+ else
30
+ @_api = api_or_template
31
+ end
32
+
33
+ @newly_populated_regions = {}
34
+ @newly_populated_tags = {}
35
+ end
36
+
37
+ def inflate(json)
38
+ super(json)
39
+
40
+ collection = RestfulModelCollection.new(Tracer, @_api, self)
41
+ collection.inflate_collection(self.tracers) if self.tracers
42
+ self.tracers = collection
43
+
44
+ @newly_populated_regions = {}
45
+ @newly_populated_tags = {}
46
+ end
47
+
48
+ def as_json(options = {})
49
+ raise TemplateRequired.new unless template_id
50
+
51
+ if options[:api_representation]
52
+ hash = {}
53
+ hash[:pop] = super(options)
54
+ hash[:populate_tags] = @newly_populated_tags
55
+ hash[:populate_regions] = @newly_populated_regions
56
+ hash
57
+ else
58
+ super(options)
59
+ end
60
+ end
61
+
62
+
63
+ def publish!
64
+ update('POST', 'publish')
65
+ end
66
+
67
+ def unpublish!
68
+ update('POST', 'unpublish')
69
+ end
70
+
71
+ def has_unpopulated_region(region_identifier)
72
+ self.unpopulated_api_regions.include?(region_identifier)
73
+ end
74
+
75
+ def populate_region(region_identifier, assets)
76
+ assets = [assets] unless assets.is_a?(Array)
77
+
78
+ @newly_populated_regions[region_identifier] ||= []
79
+ @newly_populated_regions[region_identifier].concat(assets.map {|a| a._id })
80
+ self.unpopulated_api_regions.delete(region_identifier)
81
+ end
82
+
83
+ def has_unpopulated_tag(tag_identifier)
84
+ self.unpopulated_api_tags.include?(tag_identifier)
85
+ end
86
+
87
+ def populate_tag(tag_identifier, tag_contents)
88
+ @newly_populated_tags[tag_identifier] = tag_contents
89
+ self.unpopulated_api_tags.delete(tag_identifier)
90
+ end
91
+
92
+
93
+ end
data/lib/populr.rb ADDED
@@ -0,0 +1,70 @@
1
+ require 'rest-client'
2
+ require 'restful_model_collection'
3
+ require 'template'
4
+ require 'document_asset'
5
+ require 'image_asset'
6
+ require 'json'
7
+ require 'pop'
8
+ require 'domain'
9
+
10
+
11
+ class Populr
12
+
13
+ class AccessDenied < StandardError; end
14
+ class ResourceNotFound < StandardError; end
15
+ class UnexpectedResponse < StandardError; end
16
+
17
+ attr_accessor :api_server
18
+ attr_reader :api_key
19
+
20
+
21
+ def self.interpret_response(result, options = {})
22
+ # Handle HTTP errors and RestClient errors
23
+ raise ResourceNotFound.new if result.code.to_i == 404
24
+ raise AccessDenied.new if result.code.to_i == 403
25
+ raise UnexpectedResponse.new(result.msg) if result.is_a?(Net::HTTPClientError)
26
+
27
+ # Hande content expectation errors
28
+ raise UnexpectedResponse.new if options[:expected_class] && result.body.empty?
29
+ json = JSON.parse(result.body)
30
+ raise UnexpectedResponse.new if options[:expected_class] && !json.is_a?(options[:expected_class])
31
+ json
32
+
33
+ rescue JSON::ParserError => e
34
+ # Handle parsing errors
35
+ raise UnexpectedResponse.new(e.message)
36
+ end
37
+
38
+
39
+
40
+ def initialize(api_key)
41
+ @api_server = "api.lvh.me:3000"
42
+ @api_key = api_key
43
+ end
44
+
45
+ def templates
46
+ RestfulModelCollection.new(Template, self)
47
+ end
48
+
49
+ def pops
50
+ RestfulModelCollection.new(Pop, self)
51
+ end
52
+
53
+ def domains
54
+ RestfulModelCollection.new(Domain, self)
55
+ end
56
+
57
+ def documents
58
+ RestfulModelCollection.new(DocumentAsset, self)
59
+ end
60
+
61
+ def images
62
+ RestfulModelCollection.new(ImageAsset, self)
63
+ end
64
+
65
+ def url_for_path(path)
66
+ "http://#{@api_key}:@#{api_server}#{path}"
67
+ end
68
+
69
+
70
+ end
@@ -0,0 +1,64 @@
1
+ class RestfulModel
2
+
3
+ attr_accessor :_id
4
+ attr_accessor :created_at
5
+
6
+ def self.collection_name
7
+ "#{self.to_s.downcase}s"
8
+ end
9
+
10
+
11
+ def initialize(api)
12
+ @_api = api
13
+ end
14
+
15
+ def ==(comparison_object)
16
+ comparison_object.equal?(self) || (comparison_object.instance_of?(self.class) && comparison_object._id == _id)
17
+ end
18
+
19
+ def inflate(json)
20
+ setters = methods.grep(/^\w+=$/)
21
+ setters.each do |setter|
22
+ property_name = setter.to_s[0..setter.to_s.index('=')-1]
23
+ self.send(setter, json[property_name]) if json.has_key?(property_name)
24
+ end
25
+ self.created_at = Time.new(self.created_at) if self.created_at
26
+ end
27
+
28
+ def save!
29
+ if _id
30
+ update('PUT', '', self.as_json(:api_representation => true))
31
+ else
32
+ update('POST', '', self.as_json(:api_representation => true))
33
+ end
34
+ end
35
+
36
+ def as_json(options = {})
37
+ hash = {}
38
+ setters = methods.grep(/^\w+=$/)
39
+ setters.each do |setter|
40
+ getter = setter.to_s[0..setter.to_s.index('=')-1]
41
+ hash[getter] = self.send(getter)
42
+ end
43
+ hash
44
+ end
45
+
46
+ def update(http_method, action, data = {})
47
+ http_method = http_method.downcase
48
+ action_url = @_api.url_for_path(self.path(action))
49
+
50
+ RestClient.send(http_method, action_url, data){ |response,request,result|
51
+ json = Populr.interpret_response(result, {:expected_class => Object})
52
+ inflate(json)
53
+ }
54
+ self
55
+ end
56
+
57
+ def path(action = "")
58
+ action = "/#{action}" unless action.empty?
59
+ prefix = @_parent ? @_parent.path : ''
60
+ "#{prefix}/#{self.class.collection_name}/#{_id}#{action}"
61
+ end
62
+
63
+
64
+ end
@@ -0,0 +1,85 @@
1
+ require 'restful_model'
2
+
3
+ class RestfulModelCollection
4
+
5
+ def initialize(model_class, api, parent = nil)
6
+ @model_class = model_class
7
+ @_parent = parent
8
+ @_collection = nil
9
+ @_api = api
10
+ end
11
+
12
+ def all
13
+ return @_collection if @_collection
14
+ get_restful_model_collection
15
+ end
16
+
17
+ def first
18
+ all.first
19
+ end
20
+
21
+ def find(id)
22
+ get_restful_model(id)
23
+ end
24
+
25
+ def build(*args)
26
+ @model_class.new(@_api, *args)
27
+ end
28
+
29
+ def as_json(options = {})
30
+ objects = []
31
+ for model in self.all
32
+ objects.push(model.as_json(options))
33
+ end
34
+ objects
35
+ end
36
+
37
+ def inflate_collection(items = [])
38
+ @_collection = []
39
+ items.each do |json|
40
+ if @model_class < RestfulModel
41
+ model = @model_class.new(self)
42
+ model.instance_variable_set(:@_parent, @_parent)
43
+ model.inflate(json)
44
+ else
45
+ model = @model_class.new(json)
46
+ end
47
+ @_collection.push(model)
48
+ end
49
+ @_collection
50
+ end
51
+
52
+ def path(id = "")
53
+ prefix = @_parent ? @_parent.path : ''
54
+ "#{prefix}/#{@model_class.collection_name}/#{id}"
55
+ end
56
+
57
+ private
58
+
59
+ def get_restful_model(id)
60
+ model = nil
61
+ url = @_api.url_for_path(self.path(id))
62
+
63
+ RestClient.get(url){ |response,request,result|
64
+ json = Populr.interpret_response(result, {:expected_class => Object})
65
+ if @model_class < RestfulModel
66
+ model = @model_class.new(self)
67
+ model.inflate(json)
68
+ else
69
+ model = @model_class.new(json)
70
+ end
71
+ }
72
+ model
73
+ end
74
+
75
+ def get_restful_model_collection
76
+ url = @_api.url_for_path(self.path)
77
+
78
+ RestClient.get(url){ |response,request,result|
79
+ items = Populr.interpret_response(result, {:expected_class => Array})
80
+ inflate_collection(items)
81
+ }
82
+ @_collection
83
+ end
84
+
85
+ end
data/lib/template.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'restful_model'
2
+
3
+ class Template < RestfulModel
4
+
5
+ attr_accessor :name
6
+ attr_accessor :label_names
7
+ attr_accessor :api_tags
8
+ attr_accessor :api_regions
9
+
10
+ end
data/lib/tracer.rb ADDED
@@ -0,0 +1,58 @@
1
+ require 'restful_model'
2
+
3
+ class Tracer < RestfulModel
4
+
5
+ class CodeCannotBeModified < StandardError; end
6
+
7
+ attr_accessor :name
8
+ attr_accessor :code
9
+ attr_accessor :notify_on_open
10
+ attr_accessor :notify_webhook
11
+ attr_accessor :analytics
12
+
13
+ def views
14
+ return analytics["views"].to_i
15
+ end
16
+
17
+ def clicks
18
+ return analytics["clicks"].to_i
19
+ end
20
+
21
+ def clicks_for_region(region_id)
22
+ return 0 unless analytics["assets"] && analytics["assets"][region_id]
23
+
24
+ clicks = 0
25
+ for key, asset in analytics["assets"][region_id]
26
+ clicks += asset["clicks"].to_i
27
+ end
28
+ clicks
29
+ end
30
+
31
+ def clicks_for_link(link)
32
+ return 0 unless analytics["links"] && analytics["links"][link]
33
+ return analytics["links"][link]["clicks"].to_i
34
+ end
35
+
36
+ def clicks_for_asset(asset_or_id)
37
+ return 0 unless analytics["assets"]
38
+ asset_id = asset_or_id.is_a?(Asset) ? asset_or_id._id : asset_or_id
39
+
40
+ for region, assets in analytics["assets"]
41
+ for key, asset in assets
42
+ return asset["clicks"].to_i if key == asset_id
43
+ end
44
+ end
45
+ return 0
46
+ end
47
+
48
+ def code=(c)
49
+ raise CodeCannotBeModified.new if self.code && c != self.code
50
+ @code = c
51
+ end
52
+
53
+ def enable_webhook(url)
54
+ self.notify_on_open = true
55
+ self.notify_webhook = url
56
+ end
57
+
58
+ end
data/spec/pop_spec.rb ADDED
@@ -0,0 +1,157 @@
1
+ ::ENV['RACK_ENV'] = 'test'
2
+ require File.join(File.dirname(__FILE__), 'spec_helper')
3
+ require 'rack/test'
4
+
5
+ describe 'Pop' do
6
+ include Rack::Test::Methods
7
+ before (:each) do
8
+ @api = Populr.new('key')
9
+ end
10
+
11
+ describe "#inflate" do
12
+ it "should inflate tracers into embedded tracer objects" do
13
+ pop = Pop.new(@api)
14
+ pop.inflate(JSON.parse("{\"_id\":\"5107089add02dcaecc000003\",\"created_at\":\"2013-01-28T23:24:10Z\",\"domain\":\"generic\",\"name\":\"Untitled\",\"password\":null,\"slug\":\"\",\"tracers\":[{\"_id\":\"5109b5e0dd02dc5976000001\",\"created_at\":\"2013-01-31T00:08:00Z\",\"name\":\"Facebook\"},{\"_id\":\"5109b5f5dd02dc4c43000002\",\"created_at\":\"2013-01-31T00:08:21Z\",\"name\":\"Twitter\"}],\"published_pop_url\":\"http://group3.lvh.me\",\"unpopulated_api_tags\":[],\"unpopulated_api_regions\":[],\"label_names\":[]}"))
15
+ pop.tracers.first.is_a?(Tracer).should == true
16
+ pop.tracers.first.name.should == 'Facebook'
17
+ end
18
+
19
+ it "should set the tracer collection's _parent so the tracer's path returns the full nested path" do
20
+ pop = Pop.new(@api)
21
+ pop.inflate(JSON.parse("{\"_id\":\"5107089add02dcaecc000003\",\"created_at\":\"2013-01-28T23:24:10Z\",\"domain\":\"generic\",\"name\":\"Untitled\",\"password\":null,\"slug\":\"\",\"tracers\":[{\"_id\":\"5109b5e0dd02dc5976000001\",\"created_at\":\"2013-01-31T00:08:00Z\",\"name\":\"Facebook\"},{\"_id\":\"5109b5f5dd02dc4c43000002\",\"created_at\":\"2013-01-31T00:08:21Z\",\"name\":\"Twitter\"}],\"published_pop_url\":\"http://group3.lvh.me\",\"unpopulated_api_tags\":[],\"unpopulated_api_regions\":[],\"label_names\":[]}"))
22
+ pop.tracers.path.should == "/pops/#{pop._id}/tracers/"
23
+ end
24
+ end
25
+
26
+ describe "#path_for_model" do
27
+ it "should lowercase the classname and pluralize it to create the path" do
28
+ pop = Pop.new(@api)
29
+ pop._id = '123'
30
+ pop.path.should == '/pops/123'
31
+ end
32
+ end
33
+
34
+ describe "#publish!" do
35
+ before (:each) do
36
+ @pop = Pop.new(@api)
37
+ @pop.inflate(JSON.parse("{\"_id\":\"5107089add02dcaecc000003\",\"created_at\":\"2013-01-28T23:24:10Z\",\"domain\":\"generic\",\"name\":\"Untitled\",\"password\":null,\"slug\":\"\",\"tracers\":[{\"_id\":\"5109b5e0dd02dc5976000001\",\"created_at\":\"2013-01-31T00:08:00Z\",\"name\":\"Facebook\"},{\"_id\":\"5109b5f5dd02dc4c43000002\",\"created_at\":\"2013-01-31T00:08:21Z\",\"name\":\"Twitter\"}],\"published_pop_url\":\"\",\"unpopulated_api_tags\":[],\"unpopulated_api_regions\":[],\"label_names\":[]}"))
38
+
39
+ @result = double('result')
40
+ @result.stub(:code).and_return(200)
41
+ @result.stub(:body).and_return("{\"_id\":\"5107089add02dcaecc000003\",\"created_at\":\"2013-01-28T23:24:10Z\",\"domain\":\"generic\",\"name\":\"Untitled\",\"password\":null,\"slug\":\"\",\"tracers\":[{\"_id\":\"5109b5e0dd02dc5976000001\",\"created_at\":\"2013-01-31T00:08:00Z\",\"name\":\"Facebook\"},{\"_id\":\"5109b5f5dd02dc4c43000002\",\"created_at\":\"2013-01-31T00:08:21Z\",\"name\":\"Twitter\"}],\"published_pop_url\":\"http://group3.lvh.me\",\"unpopulated_api_tags\":[],\"unpopulated_api_regions\":[],\"label_names\":[]}")
42
+ RestClient.stub(:post).and_yield(nil, nil, @result)
43
+ end
44
+
45
+ it "should call update with the publish action" do
46
+ @pop.should_receive(:update).with('POST', 'publish')
47
+ @pop.publish!
48
+ end
49
+
50
+ it "should return the pop" do
51
+ @pop.publish!.should == @pop
52
+ end
53
+
54
+ it "should set the published_pop_url" do
55
+ @pop.published_pop_url.empty?.should == true
56
+ @pop.publish!
57
+ @pop.published_pop_url.empty?.should == false
58
+ end
59
+ end
60
+
61
+
62
+ describe "#unpublish!" do
63
+ before (:each) do
64
+ @pop = Pop.new(@api)
65
+ @pop.inflate(JSON.parse("{\"_id\":\"5107089add02dcaecc000003\",\"created_at\":\"2013-01-28T23:24:10Z\",\"domain\":\"generic\",\"name\":\"Untitled\",\"password\":null,\"slug\":\"\",\"tracers\":[{\"_id\":\"5109b5e0dd02dc5976000001\",\"created_at\":\"2013-01-31T00:08:00Z\",\"name\":\"Facebook\"},{\"_id\":\"5109b5f5dd02dc4c43000002\",\"created_at\":\"2013-01-31T00:08:21Z\",\"name\":\"Twitter\"}],\"published_pop_url\":\"http://group3.lvh.me\",\"unpopulated_api_tags\":[],\"unpopulated_api_regions\":[],\"label_names\":[]}"))
66
+
67
+ @result = double('result')
68
+ @result.stub(:code).and_return(200)
69
+ @result.stub(:body).and_return("{\"_id\":\"5107089add02dcaecc000003\",\"created_at\":\"2013-01-28T23:24:10Z\",\"domain\":\"generic\",\"name\":\"Untitled\",\"password\":null,\"slug\":\"\",\"tracers\":[{\"_id\":\"5109b5e0dd02dc5976000001\",\"created_at\":\"2013-01-31T00:08:00Z\",\"name\":\"Facebook\"},{\"_id\":\"5109b5f5dd02dc4c43000002\",\"created_at\":\"2013-01-31T00:08:21Z\",\"name\":\"Twitter\"}],\"published_pop_url\":\"\",\"unpopulated_api_tags\":[],\"unpopulated_api_regions\":[],\"label_names\":[]}")
70
+ RestClient.stub(:post).and_yield(nil, nil, @result)
71
+ end
72
+
73
+ it "should call update with the unpublish action" do
74
+ @pop.should_receive(:update).with('POST', 'unpublish')
75
+ @pop.unpublish!
76
+ end
77
+
78
+ it "should return the pop" do
79
+ @pop.unpublish!.should == @pop
80
+ end
81
+
82
+ it "should set the published_pop_url" do
83
+ @pop.published_pop_url.empty?.should == false
84
+ @pop.unpublish!
85
+ @pop.published_pop_url.empty?.should == true
86
+ end
87
+ end
88
+
89
+
90
+ describe "Populating Assets and Regions" do
91
+ before (:each) do
92
+ @pop = Pop.new(@api)
93
+ @pop.inflate(JSON.parse("{\"_id\":\"5107089add02dcaecc000003\",\"created_at\":\"2013-01-28T23:24:10Z\",\"domain\":\"generic\",\"name\":\"Untitled\",\"password\":null,\"slug\":\"\",\"tracers\":[{\"_id\":\"5109b5e0dd02dc5976000001\",\"created_at\":\"2013-01-31T00:08:00Z\",\"name\":\"Facebook\"},{\"_id\":\"5109b5f5dd02dc4c43000002\",\"created_at\":\"2013-01-31T00:08:21Z\",\"name\":\"Twitter\"}],\"published_pop_url\":\"http://group3.lvh.me\",\"unpopulated_api_tags\":[\"tag1\"],\"unpopulated_api_regions\":[\"region1\"],\"label_names\":[]}"))
94
+
95
+ @asset = double('asset')
96
+ @asset.stub(:_id).and_return('asset_id')
97
+ end
98
+
99
+ describe "#populate_region" do
100
+ context "when a single asset is provided" do
101
+ it "should add the ID of the provided asset to the newly_populated_regions hash" do
102
+ @pop.populate_region('region1', @asset)
103
+ @pop.newly_populated_regions['region1'].should == ['asset_id']
104
+ end
105
+ end
106
+
107
+ context "when an array of assets is provided" do
108
+ it "should add the IDs of the provided assets to the newly_populated_regions hash" do
109
+ @pop.populate_region('region1', [@asset])
110
+ @pop.newly_populated_regions['region1'].should == ['asset_id']
111
+ end
112
+ end
113
+
114
+ it "should remove the region identifier from the list of unpopulated regions" do
115
+ @pop.unpopulated_api_regions.include?('region1').should == true
116
+ @pop.populate_region('region1', @asset)
117
+ @pop.unpopulated_api_regions.include?('region1').should == false
118
+ end
119
+ end
120
+
121
+
122
+ describe "#has_unpopulated_region" do
123
+ it "should return true if the region identifier is unpopulated" do
124
+ @pop.has_unpopulated_region('region1').should == true
125
+ end
126
+
127
+ it "should return false otherwise" do
128
+ @pop.has_unpopulated_region('region2').should == false
129
+ end
130
+ end
131
+
132
+
133
+ describe "#populate_tag" do
134
+ it "should add the identifier -> value pair to the newly populated tags array" do
135
+ @pop.populate_tag('tag1', 'content')
136
+ @pop.newly_populated_tags.should == {'tag1' => 'content'}
137
+ end
138
+
139
+ it "should remove the identifier from the unpopulated_api_tags array" do
140
+ @pop.unpopulated_api_tags.include?('tag1').should == true
141
+ @pop.populate_tag('tag1', 'content')
142
+ @pop.unpopulated_api_tags.include?('tag1').should == false
143
+ end
144
+ end
145
+
146
+ describe "#has_unpopulated_tag" do
147
+ it "should return true if the tag identifier is unpopulated" do
148
+ @pop.has_unpopulated_tag('tag1').should == true
149
+ end
150
+
151
+ it "should return false otherwise" do
152
+ @pop.has_unpopulated_tag('tag2').should == false
153
+ end
154
+ end
155
+ end
156
+
157
+ end
@@ -0,0 +1,89 @@
1
+ ::ENV['RACK_ENV'] = 'test'
2
+ require File.join(File.dirname(__FILE__), 'spec_helper')
3
+ require 'rack/test'
4
+
5
+ describe 'Populr' do
6
+ include Rack::Test::Methods
7
+
8
+ before (:each) do
9
+ @api_key = 'UXXMOCJW-BKSLPCFI-UQAQFWLO'
10
+ @populr = Populr.new(@api_key)
11
+ end
12
+
13
+ describe '#templates' do
14
+ it "should return a model collection" do
15
+ @populr.templates.is_a?(RestfulModelCollection).should == true
16
+ end
17
+ end
18
+
19
+
20
+ describe '#pops' do
21
+ it "should return a model collection" do
22
+ @populr.templates.is_a?(RestfulModelCollection).should == true
23
+ end
24
+ end
25
+
26
+ describe "#url_for_path" do
27
+ it "should return the url for a provided path" do
28
+ @populr.url_for_path('/wobble').should == "http://#{@populr.api_key}:@#{@populr.api_server}/wobble"
29
+ end
30
+ end
31
+
32
+ describe "#self.interpret_response" do
33
+ before (:each) do
34
+ @result = double('result')
35
+ @result.stub(:body).and_return("")
36
+ @result.stub(:code).and_return(200)
37
+ end
38
+
39
+ context "when an expected_class is provided" do
40
+ context "when the server responds with a 200 but unknown, invalid body" do
41
+ it "should raise an UnexpectedResponse" do
42
+ @result.stub(:body).and_return("I AM NOT JSON")
43
+ lambda {
44
+ Populr.interpret_response(@result, {:expected_class => Array})
45
+ }.should raise_error(Populr::UnexpectedResponse)
46
+ end
47
+ end
48
+
49
+ context "when the server responds with JSON that does not represent an array" do
50
+ it "should raise an UnexpectedResponse" do
51
+ @result.stub(:body).and_return("{\"_id\":\"5107089add02dcaecc000003\",\"created_at\":\"2013-01-28T23:24:10Z\",\"domain\":\"generic\",\"name\":\"Untitled\",\"password\":null,\"slug\":\"\",\"tracers\":[{\"_id\":\"5109b5e0dd02dc5976000001\",\"created_at\":\"2013-01-31T00:08:00Z\",\"name\":\"Facebook\"},{\"_id\":\"5109b5f5dd02dc4c43000002\",\"created_at\":\"2013-01-31T00:08:21Z\",\"name\":\"Twitter\"}],\"published_pop_url\":\"http://group3.lvh.me\",\"unpopulated_api_tags\":[],\"unpopulated_api_regions\":[],\"label_names\":[]}")
52
+ @result.stub(:code).and_return(500)
53
+ lambda {
54
+ Populr.interpret_response(@result, {:expected_class => Array})
55
+ }.should raise_error(Populr::UnexpectedResponse)
56
+ end
57
+ end
58
+ end
59
+
60
+ context "when the server responds with a 403" do
61
+ it "should raise AccessDenied" do
62
+ @result.stub(:code).and_return(403)
63
+ lambda {
64
+ Populr.interpret_response(@result)
65
+ }.should raise_error(Populr::AccessDenied)
66
+ end
67
+ end
68
+
69
+ context "when the server responds with a 404" do
70
+ it "should raise ResourceNotFound" do
71
+ @result.stub(:code).and_return(404)
72
+ lambda {
73
+ Populr.interpret_response(@result)
74
+ }.should raise_error(Populr::ResourceNotFound)
75
+ end
76
+ end
77
+
78
+ context "when the server responds with another status code" do
79
+ it "should raise an UnexpectedResponse" do
80
+ @result.stub(:code).and_return(500)
81
+ lambda {
82
+ Populr.interpret_response(@result)
83
+ }.should raise_error(Populr::UnexpectedResponse)
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ end
@@ -0,0 +1,119 @@
1
+ ::ENV['RACK_ENV'] = 'test'
2
+ require File.join(File.dirname(__FILE__), 'spec_helper')
3
+ require 'rack/test'
4
+
5
+ describe 'RestfulModelCollection' do
6
+ include Rack::Test::Methods
7
+
8
+ before (:each) do
9
+ @api_key = 'UXXMOCJW-BKSLPCFI-UQAQFWLO'
10
+ @populr = Populr.new(@api_key)
11
+ @collection = @populr.pops
12
+ end
13
+
14
+ describe "#all" do
15
+ it "should call interpret_response to handle standard error cases" do
16
+ Populr.should_receive(:interpret_response).and_return([])
17
+ templates = @populr.templates.all
18
+ end
19
+
20
+ context "when the model class is a RestfulModel" do
21
+ context "when the server responds correctly" do
22
+ before (:each) do
23
+ result = double('result')
24
+ result.stub(:body).and_return("[{\"_id\":\"5107089add02dcaecc000003\",\"created_at\":\"2013-01-28T23:24:10Z\",\"domain\":\"generic\",\"name\":\"Untitled\",\"password\":null,\"slug\":\"\",\"tracers\":[{\"_id\":\"5109b5e0dd02dc5976000001\",\"created_at\":\"2013-01-31T00:08:00Z\",\"name\":\"Facebook\"},{\"_id\":\"5109b5f5dd02dc4c43000002\",\"created_at\":\"2013-01-31T00:08:21Z\",\"name\":\"Twitter\"}],\"published_pop_url\":\"http://group3.lvh.me\",\"unpopulated_api_tags\":[],\"unpopulated_api_regions\":[],\"label_names\":[]}]")
25
+ result.stub(:code).and_return(200)
26
+ RestClient.should_receive(:get).and_yield(nil, nil, result)
27
+ end
28
+
29
+ it "should return an array of model objects" do
30
+ pops = @collection.all
31
+ pops.count.should == 1
32
+ pops.first.is_a?(RestfulModel).should == true
33
+ end
34
+
35
+ it "should call inflate on each model object" do
36
+ Pop.any_instance.should_receive(:inflate)
37
+ pops = @collection.all
38
+ end
39
+ end
40
+ end
41
+
42
+ context "when the model class is not a restfulModel" do
43
+ it "should return the same data type in the JSON" do
44
+ result = double('result')
45
+ result.stub(:body).and_return("[\"a\",\"b\",\"c\"]")
46
+ result.stub(:code).and_return(200)
47
+ RestClient.should_receive(:get).and_yield(nil, nil, result)
48
+ @populr.domains.all.should == ['a','b','c']
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#first" do
54
+ it "should return the first item in the all collection" do
55
+ @collection.first.should == @collection.all.first
56
+ end
57
+ end
58
+
59
+ describe "#find" do
60
+ it "should call interpret_response to handle standard error cases" do
61
+ Populr.should_receive(:interpret_response).and_return({})
62
+ @populr.pops.find('123')
63
+ end
64
+
65
+ context "when the server responds correctly" do
66
+ before (:each) do
67
+ result = double('result')
68
+ result.stub(:body).and_return("{\"_id\":\"5107089add02dcaecc000003\",\"created_at\":\"2013-01-28T23:24:10Z\",\"domain\":\"generic\",\"name\":\"Untitled\",\"password\":null,\"slug\":\"\",\"tracers\":[{\"_id\":\"5109b5e0dd02dc5976000001\",\"created_at\":\"2013-01-31T00:08:00Z\",\"name\":\"Facebook\"},{\"_id\":\"5109b5f5dd02dc4c43000002\",\"created_at\":\"2013-01-31T00:08:21Z\",\"name\":\"Twitter\"}],\"published_pop_url\":\"http://group3.lvh.me\",\"unpopulated_api_tags\":[],\"unpopulated_api_regions\":[],\"label_names\":[]}")
69
+ result.stub(:code).and_return(200)
70
+ RestClient.should_receive(:get).and_yield(nil, nil, result)
71
+ end
72
+
73
+ it "should return a pop" do
74
+ pop = @collection.find('5107089add02dcaecc000003')
75
+ pop.is_a?(Pop).should == true
76
+ pop._id.should == '5107089add02dcaecc000003'
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "#build" do
82
+ it "should create a new instance of the model object" do
83
+ parameter1 = double('parameter1')
84
+ image = @populr.images.build(parameter1)
85
+ image.is_a?(ImageAsset).should == true
86
+ end
87
+
88
+ it "should pass the api reference, and then any provided arguments" do
89
+ parameter1 = double('parameter1')
90
+ ImageAsset.any_instance.should_receive(:initialize).with(@populr, parameter1)
91
+ @populr.images.build(parameter1)
92
+ end
93
+ end
94
+
95
+ describe "#as_json" do
96
+ before (:each) do
97
+ result = double('result')
98
+ result.stub(:body).and_return("[{\"_id\":\"5107089add02dcaecc000003\",\"template_id\":\"5107089add02dcaecc000001\",\"created_at\":\"2013-01-28T23:24:10Z\",\"domain\":\"generic\",\"name\":\"Untitled\",\"password\":null,\"slug\":\"\",\"tracers\":[{\"_id\":\"5109b5e0dd02dc5976000001\",\"created_at\":\"2013-01-31T00:08:00Z\",\"name\":\"Facebook\"},{\"_id\":\"5109b5f5dd02dc4c43000002\",\"created_at\":\"2013-01-31T00:08:21Z\",\"name\":\"Twitter\"}],\"published_pop_url\":\"http://group3.lvh.me\",\"unpopulated_api_tags\":[],\"unpopulated_api_regions\":[],\"label_names\":[]}]")
99
+ result.stub(:code).and_return(200)
100
+ RestClient.should_receive(:get).and_yield(nil, nil, result)
101
+ end
102
+
103
+ it "should call as_json for each model in the collection" do
104
+ Pop.any_instance.should_receive(:as_json)
105
+ @collection.as_json
106
+ end
107
+
108
+ it "should return an array of hashes" do
109
+ @collection.as_json.count.should == 1
110
+ @collection.as_json.first['_id'].should == '5107089add02dcaecc000003'
111
+ end
112
+
113
+ it "should forward options to each model" do
114
+ Pop.any_instance.should_receive(:as_json).with(:bla => true)
115
+ @collection.as_json(:bla => true)
116
+ end
117
+ end
118
+
119
+ end
@@ -0,0 +1,20 @@
1
+ ::ENV['RACK_ENV'] = 'test'
2
+ require File.join(File.dirname(__FILE__), 'spec_helper')
3
+ require 'rack/test'
4
+
5
+ describe 'RestfulModel' do
6
+ include Rack::Test::Methods
7
+ before (:each) do
8
+ @api = Populr.new('key')
9
+ end
10
+
11
+ describe "#as_json" do
12
+ it "should return a hash with the attr_accessor properties" do
13
+ r = RestfulModel.new(@api)
14
+ r._id = '1'
15
+ r.created_at = Time.new
16
+ r.as_json.should == {"_id" => "1", "created_at" => r.created_at}
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'pry'
5
+ require 'pry-nav'
6
+ require 'pry-stack_explorer'
7
+ require 'populr'
8
+
9
+ # Requires supporting files with custom matchers and macros, etc,
10
+ # in ./support/ and its subdirectories.
11
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
12
+
13
+ RSpec.configure do |config|
14
+
15
+ end
@@ -0,0 +1,107 @@
1
+ ::ENV['RACK_ENV'] = 'test'
2
+ require File.join(File.dirname(__FILE__), 'spec_helper')
3
+ require 'rack/test'
4
+
5
+ describe 'Pop' do
6
+ include Rack::Test::Methods
7
+ before (:each) do
8
+ @api = Populr.new('key')
9
+ @tracer = Tracer.new(@api)
10
+ @tracer.inflate(JSON.parse("{\"code\":\"tc\",\"name\":\"Twitter\",\"notify_on_open\":false,\"analytics\":{\"views\":6,\"clicks\":24,\"links\":{\"http://www.populr.me/\":{\"clicks\":4}},\"assets\":{\"empty_region\":{},\"unnamed_region_0\":{\"132213ae12bc1312\":{\"clicks\":10}},\"my_image_region\":{\"132213ae21f4812f\":{\"clicks\":10},\"f48121f48121f421\":{\"clicks\":3}}}}}"))
11
+ end
12
+
13
+
14
+ describe "#views" do
15
+ it "should retrieve the total views from analytics" do
16
+ @tracer.views.should == 6
17
+ end
18
+ end
19
+
20
+ describe "#clicks" do
21
+ it "should retrieve the total clicks from analytics" do
22
+ @tracer.clicks.should == 24
23
+ end
24
+ end
25
+
26
+ describe "#clicks_for_region" do
27
+ it "should sum the clicks for all assets in the region" do
28
+ @tracer.clicks_for_region('my_image_region').should == 13
29
+ end
30
+
31
+ it "should return 0 if the region does not exist" do
32
+ @tracer.clicks_for_region('nonexistent_region').should == 0
33
+ end
34
+
35
+ it "shoud return 0 if the region has no assets" do
36
+ @tracer.clicks_for_region('empty_region').should == 0
37
+ end
38
+
39
+ it "should return 0 if the assets section of analytics is not present" do
40
+ @tracer.inflate(JSON.parse("{\"code\":\"tc\",\"name\":\"Twitter\",\"notify_on_open\":false,\"analytics\":{\"views\":6,\"clicks\":24,\"links\":{\"http://www.populr.me/\":{\"clicks\":4}}}}"))
41
+ @tracer.clicks_for_region('my_image_region').should == 0
42
+ end
43
+ end
44
+
45
+ describe "#clicks_for_link" do
46
+ it "should return the analytics clicks value if the link exists" do
47
+ @tracer.clicks_for_link('http://www.populr.me/').should == 4
48
+ end
49
+
50
+ it "should return 0 if the link does not exist" do
51
+ @tracer.clicks_for_link('http://www.nonexistent.com/').should == 0
52
+ end
53
+
54
+ it "should return 0 if the link hash is not present" do
55
+ @tracer.inflate(JSON.parse("{\"code\":\"tc\",\"name\":\"Twitter\",\"notify_on_open\":false,\"analytics\":{\"views\":6,\"clicks\":24}}"))
56
+ @tracer.clicks_for_link('http://www.populr.com/').should == 0
57
+ end
58
+ end
59
+
60
+ describe "#clicks_for_asset" do
61
+ it "should scan through the regions in the analytics hash and return the asset clicks" do
62
+ @tracer.clicks_for_asset('132213ae21f4812f').should == 10
63
+ end
64
+
65
+ it "should return 0 if the assets section of analytics is not present" do
66
+ @tracer.inflate(JSON.parse("{\"code\":\"tc\",\"name\":\"Twitter\",\"notify_on_open\":false,\"analytics\":{\"views\":6,\"clicks\":24,\"links\":{\"http://www.populr.me/\":{\"clicks\":4}}}}"))
67
+ @tracer.clicks_for_asset('132213ae21f4812f').should == 0
68
+ end
69
+
70
+ it "should return 0 if there is no matching asset" do
71
+ @tracer.clicks_for_asset('asd').should == 0
72
+ end
73
+
74
+ it "should accept an asset object as a parameter" do
75
+ asset = ImageAsset.new(@api, nil)
76
+ asset._id = '132213ae21f4812f'
77
+ @tracer.clicks_for_asset(asset).should == 10
78
+ end
79
+
80
+ it "should accept an asset id as a parameter" do
81
+ @tracer.clicks_for_asset('132213ae21f4812f').should == 10
82
+ end
83
+ end
84
+
85
+ describe "#enable_webhook" do
86
+ it "should set the webhook and enable notify_on_open" do
87
+ @webhook = 'http://mycallback.com'
88
+
89
+ @tracer.notify_on_open.should == false
90
+ @tracer.enable_webhook(@webhook)
91
+ @tracer.notify_on_open.should == true
92
+ @tracer.notify_webhook.should == @webhook
93
+ end
94
+ end
95
+
96
+ describe "#code=" do
97
+ it "should only allow the tracer code to be set if there isn't a value" do
98
+ @tracer = Tracer.new(@api)
99
+ @tracer.code.should == nil
100
+ @tracer.code = 'as'
101
+
102
+ lambda {
103
+ @tracer.code = 'bb'
104
+ }.should raise_error(Tracer::CodeCannotBeModified)
105
+ end
106
+ end
107
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: populr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ben Gotow
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '1.6'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '1.6'
30
+ - !ruby/object:Gem::Dependency
31
+ name: shoulda
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rdoc
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '3.12'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '3.12'
62
+ - !ruby/object:Gem::Dependency
63
+ name: bundler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 1.3.5
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 1.3.5
78
+ - !ruby/object:Gem::Dependency
79
+ name: jeweler
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 1.8.4
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 1.8.4
94
+ description: Gem for interacting with the Populr.me API
95
+ email: ben@populr.me
96
+ executables: []
97
+ extensions: []
98
+ extra_rdoc_files:
99
+ - LICENSE.md
100
+ - README.rdoc
101
+ files:
102
+ - .document
103
+ - Gemfile
104
+ - Gemfile.lock
105
+ - LICENSE.md
106
+ - README.rdoc
107
+ - Rakefile
108
+ - VERSION
109
+ - lib/asset.rb
110
+ - lib/document_asset.rb
111
+ - lib/domain.rb
112
+ - lib/image_asset.rb
113
+ - lib/pop.rb
114
+ - lib/populr.rb
115
+ - lib/restful_model.rb
116
+ - lib/restful_model_collection.rb
117
+ - lib/template.rb
118
+ - lib/tracer.rb
119
+ - spec/pop_spec.rb
120
+ - spec/populr_spec.rb
121
+ - spec/restful_model_collection_spec.rb
122
+ - spec/restful_model_spec.rb
123
+ - spec/spec_helper.rb
124
+ - spec/tracer_spec.rb
125
+ homepage: http://github.com/bengotow/populr
126
+ licenses:
127
+ - MIT
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ! '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ segments:
139
+ - 0
140
+ hash: -1796578390559359755
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ none: false
143
+ requirements:
144
+ - - ! '>='
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 1.8.24
150
+ signing_key:
151
+ specification_version: 3
152
+ summary: Gem for interacting with the Populr.me API
153
+ test_files: []