three-sixty 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3357b6f308efd6f848d6c5cee39547780b32dc2b
4
+ data.tar.gz: 3ad95ad642210362e42b440278ec98d7d9f8b75f
5
+ SHA512:
6
+ metadata.gz: 97e80e12364c3a079c33c5f6e07abf23d2056eeacf6b60490d8341f5f339c825880779a42950024d4acc974e73aa4b90944cc9e3c18e3d0a15df1480afa8f670
7
+ data.tar.gz: 9385af23b6f6187947b989fc1e0d2feed8b99b678cf629b8f21416b3468ff08699439fa3c6c93e6d73caf408fada0c5e54d3718d9734fb257cc513d081bd8f5e
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ documentation/*
2
+ Gemfile*
3
+ .bundle/*
4
+ .ruby*
data/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # 360
2
+ A Ruby gem for connecting to the 360 Dianjing AD system, using the Open API Platform
3
+
4
+ ## Install
5
+
6
+ gem 'three-sixty', github: 'forward3d/three-sixty'
7
+
8
+
9
+ ## Configuration
10
+
11
+ require 'three-sixty'
12
+ ThreeSixty.configure(logger: Logger.new($stdout))
13
+
14
+
15
+ ## Authenticate
16
+
17
+ require 'three-sixty'
18
+
19
+ client = ThreeSixty::Client.new(api_key, api_secret)
20
+ client.authenticate!(username, password)
21
+
22
+ You can specify a hash of optional parameters when initializing the client. These include
23
+
24
+ :endpoint - The 360 api endpoint (This is unlikely to change)
25
+ :version - The 360 api version number
26
+ :format - The api reponse format (Currently JSON or XML and is only useful when using the core library)
27
+ :logger - The client logger
28
+
29
+
30
+ ## Get Campaign Ids
31
+
32
+ require 'three-sixty'
33
+
34
+ client = ThreeSixty::Client.new(api_key, api_secret)
35
+ client.authenticate!(username, password)
36
+
37
+ account = ThreeSixty::Account.new(client, opts)
38
+ campaign_ids = account.download_campaign_ids
39
+
40
+ You can specify a hash of optional parameters when initializing the account. These include
41
+
42
+ :logger - Attach a local logger
43
+ :report_generating_backoff - Create a lambda for your backoff strategy when polling the report generate e.g. lambda { |retry_number| [1 30 60 300].index(retry_number) }
44
+
45
+ ## Streaming Campaign Ids to a File
46
+
47
+ File.open('campaign_ids.csv', 'w') do |file|
48
+ account.download_campaigns(campaign_ids) do |content|
49
+ file.write content
50
+ end
51
+ end
52
+
53
+ ## Download Campaign Ids to a File
54
+
55
+ file = account.download_campaigns_to_file(campaign_ids, opts)
56
+
57
+ You can specify a hash of optional parameters, which includes
58
+
59
+ :download_dir - The directory to download the file
60
+ :filename - The full path of the file you wish to create
61
+ :encoding - The encoding used when downloading the file
62
+
63
+ ## Download Campaign Info
64
+
65
+ campaign = ThreeSixty::Campaign.new(client)
66
+ campaign_info = campaign.download_all_campaigns
67
+
68
+
69
+ ## Download All Ad Groups for a Campaign
70
+
71
+ group = ThreeSixty::Group.new(client)
72
+ group_info = group.download_campaign_all_ad_groups(campaigns_id)
73
+
74
+ ## Download All Creatives for a Campaign
75
+
76
+ group = ThreeSixty::Group.new(client)
77
+ ad_group_ids = group.download_campaign_ad_group_ids(campaign_id)
78
+
79
+ creatives = []
80
+ creative = ThreeSixty::Creative.new(client)
81
+ ad_group_ids.each do |ad_group_id|
82
+ creatives += creative.download_ad_group_all_creatives(ad_group_id)
83
+ end
84
+
85
+
86
+ ## Downlod All Keywords for a Campaign
87
+
88
+ group = ThreeSixty::Group.new(client)
89
+ ad_group_ids = group.download_campaign_ad_group_ids(campaign_id)
90
+
91
+ keywords = []
92
+ keyword = ThreeSixty::Keyword.new(client)
93
+ ad_group_ids.each do |ad_group_id|
94
+ keywords += keyword.download_ad_group_all_keywords(ad_group_id)
95
+ end
@@ -0,0 +1,90 @@
1
+ require 'net/http'
2
+ require 'securerandom'
3
+
4
+ require_relative 'core/account'
5
+
6
+ module ThreeSixty
7
+ class Account < ThreeSixty::Core::Account
8
+
9
+ attr_reader :report_generating_backoff, :logger
10
+
11
+ def initialize(client, opts = {})
12
+ opts = default_options.update(opts)
13
+
14
+ @report_generating_backoff = opts[:report_generating_backoff]
15
+ @logger = opts[:logger] || client.logger
16
+
17
+ super(client)
18
+ end
19
+
20
+ def download_campaign_ids
21
+ get_campaign_id_list["campaignIdList"]
22
+ end
23
+
24
+ def download_campaigns(campaign_ids)
25
+ file_id = get_all_objects(campaign_ids)['fileId']
26
+
27
+ retry_number = 0
28
+ file_state = get_file_state(file_id)
29
+ while report_generating?(file_state["isGenerated"])
30
+ begin
31
+ @logger.debug "Waiting for report #{file_id} on retry number #{retry_number}"
32
+ sleep report_generating_backoff.call(retry_number)
33
+ retry_number += 1
34
+ file_state = get_file_state(file_id)
35
+ rescue TypeError => e
36
+ e.message = "Waiting too long to generate the report #{file_id}" # Re-raise with a better error message
37
+ raise e
38
+ end
39
+ end
40
+
41
+ @logger.info "Found file #{file_state["filePath"]} with size #{"%.2f" % (file_state["fileSize"] / 2**20)} MB"
42
+ download_filestream(file_state["filePath"]) { |chunk| yield chunk }
43
+ @logger.info "Finished downloading file #{file_state["filePath"]}"
44
+ end
45
+
46
+ def download_campaigns_to_file(campaign_ids, opts = {})
47
+ download_dir = opts[:download_dir] || "/tmp"
48
+ file = opts[:filename] || File.join(download_dir, "306_campaigns_" << SecureRandom.uuid << ".csv")
49
+
50
+ filemode = opts[:encoding].nil? ? 'w' : "w:#{opts[:encoding]}"
51
+
52
+ @logger.debug "Creating file #{file} with filemode #{filemode}"
53
+ File.open(file, filemode) do |fs|
54
+ download_campaigns(campaign_ids) do |content|
55
+ fs.write content
56
+ end
57
+ end
58
+
59
+ @logger.info "Finished downloading file to #{file}"
60
+ file
61
+ end
62
+
63
+ def exclude_ip_list
64
+ get_exclude_ip["excludeIpList"]
65
+ end
66
+
67
+
68
+ private
69
+
70
+ def report_generating?(status)
71
+ [ 'pending', 'process'].include?(status)
72
+ end
73
+
74
+ def download_filestream(file)
75
+ uri = URI(file)
76
+ Net::HTTP.start(uri.host, uri.port) do |http|
77
+ http.request_get(file) do |response|
78
+ response.read_body { |chunk| yield chunk }
79
+ end
80
+ end
81
+ end
82
+
83
+ def default_options
84
+ {
85
+ report_generating_backoff: lambda { |retry_number| retry_number < 5 ? 2**retry_number : nil }
86
+ }
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,14 @@
1
+ require_relative 'core/campaign'
2
+ require_relative 'account'
3
+
4
+ module ThreeSixty
5
+ class Campaign < ThreeSixty::Core::Campaign
6
+
7
+ def download_all_campaigns
8
+ account = ThreeSixty::Account.new(@client)
9
+ campaign_ids = account.download_campaign_ids
10
+ get_info_by_id_list(campaign_ids)["campaignList"]
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,105 @@
1
+ require 'openssl'
2
+ require 'digest'
3
+ require 'base64'
4
+ require 'json'
5
+
6
+ require_relative 'core/account'
7
+
8
+ module ThreeSixty
9
+ class Client
10
+
11
+ attr_reader :api_key, :endpoint, :version, :logger
12
+ attr_reader :access_token, :session_token
13
+
14
+ def initialize(api_key, api_secret, opts = {})
15
+ opts = default_options.update(opts)
16
+
17
+ @api_key = api_key
18
+ @api_secret = api_secret
19
+ @endpoint = opts[:endpoint]
20
+ @version = opts[:version]
21
+ @format = opts[:format]
22
+ @logger = opts[:logger]
23
+ end
24
+
25
+ def authenticate!(username, password)
26
+ account = ThreeSixty::Core::Account.new(self)
27
+ tokens = account.client_login(username, generate_passwd(password))
28
+ @access_token = tokens['accessToken']
29
+ @session_token = tokens['sessionToken']
30
+ end
31
+
32
+ def request(resource_url, params = {})
33
+ params[:format] = @format
34
+ uri = URI(generate_url(resource_url, params))
35
+ @logger.debug "Resquest url #{uri.to_s}"
36
+ req = Net::HTTP::Post.new(uri, headers = generate_headers)
37
+ @logger.debug "Sending headers #{headers}"
38
+ res = Net::HTTP.start(uri.host) do |http|
39
+ http.request(req)
40
+ end
41
+ process_response(res)
42
+ end
43
+
44
+ private
45
+
46
+ def default_options
47
+ {
48
+ endpoint: ThreeSixty.configuration[:endpoint],
49
+ version: ThreeSixty.configuration[:version],
50
+ format: ThreeSixty.configuration[:format],
51
+ logger: ThreeSixty.configuration[:logger]
52
+ }
53
+ end
54
+
55
+ def serveToken
56
+ DateTime.now.strftime("%Y%m%d%H%M%S%L")
57
+ end
58
+
59
+ def process_response(res)
60
+ case res.content_type
61
+ when 'application/json'
62
+ process_json_response(res.body)
63
+ else
64
+ # raise "Unable to process response of type #{res.content_type}"
65
+ res.body
66
+ end
67
+ end
68
+
69
+ def process_json_response(content)
70
+ JSON.parse(content)
71
+ end
72
+
73
+ def generate_headers
74
+ headers = { 'serveToken' => serveToken, 'apiKey' => @api_key }
75
+ headers['accessToken'] = @access_token unless @access_token.nil?
76
+ headers['sessionToken'] = @session_token unless @session_token.nil?
77
+ headers
78
+ end
79
+
80
+ def generate_passwd(password)
81
+ encrypt(password).unpack("H2"*32).join
82
+ end
83
+
84
+ def encrypt(password)
85
+ cipher = OpenSSL::Cipher::AES128.new(:CBC)
86
+ cipher.encrypt
87
+ cipher.key, cipher.iv = generate_key_and_vector(@api_secret)
88
+ cipher.update(Digest::MD5.hexdigest(password)) + cipher.final
89
+ end
90
+
91
+ def generate_key_and_vector(secret)
92
+ secret.scan(/.{16}/m).map { |s| Base64.decode64(Base64.encode64(s)) }
93
+ end
94
+
95
+ def generate_url(resource_url, query_params = {})
96
+ endpoint = @endpoint + (resource_url.split("/")[1] == 'clientLogin' ? '/' : '/' << version) # client login doesn't contain version in the url
97
+ [endpoint, resource_url].join('/') << '?' << querystring(query_params)
98
+ end
99
+
100
+ def querystring(query_params)
101
+ query_params.map { |key, value| key.to_s << '=' << URI.escape(value.to_s) }.join('&')
102
+ end
103
+
104
+ end
105
+ end
@@ -0,0 +1,21 @@
1
+ require 'logger'
2
+
3
+ module ThreeSixty
4
+
5
+ DEFAULT_ENDPOINT = "https://api.e.360.cn"
6
+ DEFAULT_VERSION = "1.6"
7
+ DEFAULT_FORMAT = 'json'
8
+
9
+ @@configuration = {}
10
+
11
+ def self.configure(opts = {})
12
+ @@configuration[:endpoint] = opts[:endpoint] || DEFAULT_ENDPOINT
13
+ @@configuration[:version] = opts[:version] || DEFAULT_VERSION
14
+ @@configuration[:format] = opts[:format] || DEFAULT_FORMAT
15
+ @@configuration[:logger] = opts[:logger] || Logger.new(nil)
16
+ end
17
+
18
+ def self.configuration
19
+ @@configuration
20
+ end
21
+ end
@@ -0,0 +1,43 @@
1
+ module ThreeSixty
2
+ module Core
3
+ class Account
4
+
5
+ SERVICE_URL = 'account'
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def client_login(username, password)
12
+ @client.request(resource_url("clientLogin"), username: username, passwd: password)
13
+ end
14
+
15
+ def get_campaign_id_list
16
+ @client.request(resource_url("getCampaignIdList"))
17
+ end
18
+
19
+ def get_info
20
+ @client.request(resource_url("getInfo"))
21
+ end
22
+
23
+ def get_all_objects(campaign_ids)
24
+ @client.request(resource_url("getAllObjects"), idList: campaign_ids)
25
+ end
26
+
27
+ def get_file_state(file_id)
28
+ @client.request(resource_url("getFileState"), fileId: file_id)
29
+ end
30
+
31
+ def get_exclude_ip
32
+ @client.request(resource_url("getExcludeIp"))
33
+ end
34
+
35
+ private
36
+
37
+ def resource_url(service)
38
+ [SERVICE_URL, service].join("/")
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,27 @@
1
+ module ThreeSixty
2
+ module Core
3
+ class Campaign
4
+
5
+ SERVICE_URL = 'campaign'
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def get_info_by_id(campaign_id)
12
+ @client.request(resource_url("getInfoById"), id: campaign_id)
13
+ end
14
+
15
+ def get_info_by_id_list(campaign_ids)
16
+ @client.request(resource_url("getInfoByIdList"), idList: campaign_ids)
17
+ end
18
+
19
+ private
20
+
21
+ def resource_url(service)
22
+ [SERVICE_URL, service].join("/")
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,40 @@
1
+ module ThreeSixty
2
+ module Core
3
+ class Creative
4
+
5
+ SERVICE_URL = 'creative'
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def get_id_list_by_group_id(ad_group_id, opts = {})
12
+ opts.merge!(groupId: ad_group_id)
13
+ @client.request(resource_url("getIdListByGroupId"), opts)
14
+ end
15
+
16
+ def get_info_by_id(creative_id)
17
+ @client.request(resource_url("getInfoById"), id: creative_id)
18
+ end
19
+
20
+ def get_info_by_id_list(creative_ids)
21
+ @client.request(resource_url("getInfoByIdList"), idList: creative_ids)
22
+ end
23
+
24
+ def get_status_by_id_list(creative_ids)
25
+ @client.request(resource_url("getStatusByIdList"), idList: creative_ids)
26
+ end
27
+
28
+ def get_changed_id_list(from_time)
29
+ @client.request(resource_url("getChangedIdList"), fromTime: from_time)
30
+ end
31
+
32
+ private
33
+
34
+ def resource_url(service)
35
+ [SERVICE_URL, service].join("/")
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,32 @@
1
+ module ThreeSixty
2
+ module Core
3
+ class Group
4
+
5
+ SERVICE_URL = 'group'
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def get_id_list_by_campaign_id(campaign_id, opts = {})
12
+ opts.merge!(campaignId: campaign_id)
13
+ @client.request(resource_url("getIdListByCampaignId"), opts)
14
+ end
15
+
16
+ def get_info_by_id(adgroup_id)
17
+ @client.request(resource_url("getInfoById"), id: adgroup_id)
18
+ end
19
+
20
+ def get_info_by_id_list(adgroup_ids)
21
+ @client.request(resource_url("getInfoByIdList"), idList: adgroup_ids)
22
+ end
23
+
24
+ private
25
+
26
+ def resource_url(service)
27
+ [SERVICE_URL, service].join("/")
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,40 @@
1
+ module ThreeSixty
2
+ module Core
3
+ class Keyword
4
+
5
+ SERVICE_URL = 'keyword'
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def get_id_list_by_group_id(ad_group_id, opts = {})
12
+ opts.merge!(groupId: ad_group_id)
13
+ @client.request(resource_url("getIdListByGroupId"), opts)
14
+ end
15
+
16
+ def get_info_by_id(keyword_id)
17
+ @client.request(resource_url("getInfoById"), id: keyword_id)
18
+ end
19
+
20
+ def get_status_by_id_list(keyword_ids)
21
+ @client.request(resource_url("getStatusByIdList"), idList: keyword_ids)
22
+ end
23
+
24
+ def get_info_by_id_list(keyword_ids)
25
+ @client.request(resource_url("getInfoByIdList"), idList: keyword_ids)
26
+ end
27
+
28
+ def get_changed_id_list(from_time)
29
+ @client.request(resource_url("getChangedIdList"), fromTime: from_time)
30
+ end
31
+
32
+ private
33
+
34
+ def resource_url(service)
35
+ [SERVICE_URL, service].join("/")
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,49 @@
1
+ module ThreeSixty
2
+ module Core
3
+ class Report
4
+
5
+ SERVICE_URL = 'report'
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def keyword_count(start_date, level, opts = {})
12
+ opts.merge!({startDate: start_date, level: level})
13
+ @client.request(resource_url("keywordCount"), opts)
14
+ end
15
+
16
+ def keyword(start_date, level, opts = {})
17
+ opts.merge!({startDate: start_date, level: level})
18
+ @client.request(resource_url("keyword"), opts)
19
+ end
20
+
21
+ def creative_count(start_date, level, opts = {})
22
+ opts.merge!({startDate: start_date, level: level})
23
+ @client.request(resource_url("creativeCount"), opts)
24
+ end
25
+
26
+ def creative(start_date, level, opts = {})
27
+ opts.merge!({startDate: start_date, level: level})
28
+ @client.request(resource_url("creative"), opts)
29
+ end
30
+
31
+ def region_count(start_date, level, opts = {})
32
+ opts.merge!({startDate: start_date, level: level})
33
+ @client.request(resource_url("regionCount"), opts)
34
+ end
35
+
36
+ def region(start_date, level, opts = {})
37
+ opts.merge!({startDate: start_date, level: level})
38
+ @client.request(resource_url("region"), opts)
39
+ end
40
+
41
+ private
42
+
43
+ def resource_url(service)
44
+ [SERVICE_URL, service].join("/")
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'core/creative'
2
+
3
+ module ThreeSixty
4
+ class Creative < ThreeSixty::Core::Creative
5
+
6
+ def download_ad_group_creative_ids(ad_group_id, opts = {})
7
+ get_id_list_by_group_id(ad_group_id, opts)["creativeIdList"]
8
+ end
9
+
10
+ def download_ad_group_all_creatives(ad_group_id, opts = {})
11
+ creative_ids = download_ad_group_creative_ids(ad_group_id, opts = {})
12
+ return [] if creative_ids.empty?
13
+ get_info_by_id_list(creative_ids)["creativeList"]
14
+ end
15
+
16
+ def download_ad_group_all_creative_statuses(ad_group_id, opts = {})
17
+ creative_ids = download_ad_group_creative_ids(ad_group_id, opts = {})
18
+ return [] if creative_ids.empty?
19
+ get_status_by_id_list(creative_ids)["creativeList"]
20
+ end
21
+
22
+ def download_changed_creative_ids(from_time)
23
+ get_changed_id_list(from_time)["creativeIdList"]
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'core/group'
2
+ require_relative 'account'
3
+
4
+ module ThreeSixty
5
+ class Group < ThreeSixty::Core::Group
6
+
7
+ def download_campaign_ad_group_ids(campaign_id, opts = {})
8
+ get_id_list_by_campaign_id(campaign_id, opts)["groupIdList"]
9
+ end
10
+
11
+ def download_campaign_all_ad_groups(campaign_id, opts = {})
12
+ ad_group_ids = download_campaign_ad_group_ids(campaign_id)
13
+ get_info_by_id_list(ad_group_ids)["groupList"]
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'core/keyword'
2
+
3
+ module ThreeSixty
4
+ class Keyword < ThreeSixty::Core::Keyword
5
+
6
+ def download_ad_group_keyword_ids(ad_group_id, opts = {})
7
+ get_id_list_by_group_id(ad_group_id, opts)["keywordIdList"]
8
+ end
9
+
10
+ def download_ad_group_all_keywords(ad_group_id, opts = {})
11
+ keyword_ids = download_ad_group_keyword_ids(ad_group_id)
12
+ return [] if keyword_ids.empty?
13
+ get_info_by_id_list(keyword_ids)["keywordList"]
14
+ end
15
+
16
+ def download_ad_group_all_keyword_statuses(ad_group_id, opts = {})
17
+ keyword_ids = download_ad_group_keyword_ids(ad_group_id)
18
+ return [] if keyword_ids.empty?
19
+ get_status_by_id_list(keyword_ids)["keywordList"]
20
+ end
21
+
22
+ def download_changed_keyword_ids(from_time)
23
+ get_changed_id_list(from_time)["keywordIdList"]
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ module ThreeSixty
2
+ module Level
3
+
4
+ ACCOUNT = :account
5
+ PLAN = :plan
6
+ GROUP = :group
7
+
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ require_relative 'core/report'
2
+
3
+ module ThreeSixty
4
+ class Report < ThreeSixty::Core::Report
5
+
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module ThreeSixty
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,13 @@
1
+ require_relative 'three-sixty/level'
2
+ require_relative 'three-sixty/configuration'
3
+ require_relative 'three-sixty/campaign'
4
+ require_relative 'three-sixty/account'
5
+ require_relative 'three-sixty/client'
6
+ require_relative 'three-sixty/group'
7
+ require_relative 'three-sixty/creative'
8
+ require_relative 'three-sixty/keyword'
9
+ require_relative 'three-sixty/report'
10
+
11
+ module ThreeSixty
12
+ ThreeSixty.configure
13
+ end
@@ -0,0 +1,17 @@
1
+ require File.join(File.expand_path('../lib', __FILE__), 'three-sixty', 'version')
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "three-sixty"
5
+ gem.version = ThreeSixty::VERSION
6
+ gem.authors = ["Daniel Padden"]
7
+ gem.email = ["daniel.padden@forward3d.com"]
8
+ gem.description = %q{Connecting to the 360 api}
9
+ gem.summary = %q{Gathering data from the 360 api}
10
+ gem.homepage = ""
11
+
12
+ gem.files = `git ls-files -z`.split("\x0")
13
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.require_paths = ["lib"]
16
+
17
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: three-sixty
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Padden
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-17 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Connecting to the 360 api
14
+ email:
15
+ - daniel.padden@forward3d.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - .gitignore
21
+ - README.md
22
+ - lib/three-sixty.rb
23
+ - lib/three-sixty/account.rb
24
+ - lib/three-sixty/campaign.rb
25
+ - lib/three-sixty/client.rb
26
+ - lib/three-sixty/configuration.rb
27
+ - lib/three-sixty/core/account.rb
28
+ - lib/three-sixty/core/campaign.rb
29
+ - lib/three-sixty/core/creative.rb
30
+ - lib/three-sixty/core/group.rb
31
+ - lib/three-sixty/core/keyword.rb
32
+ - lib/three-sixty/core/report.rb
33
+ - lib/three-sixty/creative.rb
34
+ - lib/three-sixty/group.rb
35
+ - lib/three-sixty/keyword.rb
36
+ - lib/three-sixty/level.rb
37
+ - lib/three-sixty/report.rb
38
+ - lib/three-sixty/version.rb
39
+ - three-sixty.gemspec
40
+ homepage: ''
41
+ licenses: []
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.2.1
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Gathering data from the 360 api
63
+ test_files: []