upland_mobile_commons_rest 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f34644e11282b6cd0234d4b376ad6b0bec67abb4a0385bef99b56fa1233eea92
4
- data.tar.gz: 47b415580a1fac3855a3b670f10ae3f1651af10908b9c60a0e7bc72a8f8910b3
3
+ metadata.gz: 6af9508f63531c934fab5b8d4129d5132609bf316e846cc7dedc02e255b8f809
4
+ data.tar.gz: 36186a816bdcb8841f48d2f5f9af4c484c0c516af6529b4c255bbac42101b0ea
5
5
  SHA512:
6
- metadata.gz: 5cfbdef2b235b17763688476472694b1e558ea4b900699960c96b1c602ded91b76007ff8370d4ae03ce94e272a6afa1e74b4df65f329b084700a97001f198ae3
7
- data.tar.gz: 0ce777ff7b280913f9ab2100f06c2048136ef47aa920d967cef76013f16b700b81a930487cae603c5379f280965a32bd8427ee7941f1ee22dcd4e25a2b7dfdbc
6
+ metadata.gz: 74ac3b2e39fd5e888c4d0b66097dfab977306a23b353a667a9eb5d51df74ac4945542cfd35ea3e951a928dfa45382ab4e280e18e0257bd92cf5d0c19e4bdb270
7
+ data.tar.gz: 0037b025610ce66dbdb592e8e4b8010085d1c2fc30b9ff0ee3c0cc96b8af00771e04fc5fe0f222dfff756a2061e4eb126eb635238eef967c5c95f67a4f79256b
@@ -0,0 +1,24 @@
1
+ name: CI
2
+ on: [push]
3
+
4
+ jobs:
5
+ test:
6
+ runs-on: ubuntu-latest
7
+ steps:
8
+ - uses: actions/checkout@v2
9
+ - uses: ruby/setup-ruby@477b21f02be01bcb8030d50f37cfec92bfa615b6
10
+ with:
11
+ ruby-version: 2.7
12
+ bundler-cache: true
13
+ - run: bundle install
14
+ - run: bundle exec rspec
15
+ rubocop:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - uses: ruby/setup-ruby@477b21f02be01bcb8030d50f37cfec92bfa615b6
20
+ with:
21
+ ruby-version: 2.7
22
+ bundler-cache: true
23
+ - run: bundle install
24
+ - run: bundle exec rubocop
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ upland_mobile_commons_rest
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.4
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
2
4
  # Add dependencies required to use your gem here.
3
5
  # Example:
4
6
  # gem "activesupport", ">= 2.3.5"
@@ -8,14 +10,14 @@ gem 'vertebrae'
8
10
  # Add dependencies to develop your gem here.
9
11
  # Include everything needed to run rake, tests, features, etc.
10
12
  group :development do
11
- gem "shoulda", ">= 0"
12
- gem "rdoc", "> 3.12"
13
- gem "bundler", "> 2.0"
14
- gem "juwelier", git: 'https://github.com/flajann2/juwelier.git'
15
- gem "simplecov", ">= 0"
16
- gem "dotenv"
17
- gem "byebug"
18
- gem "rubocop"
19
- gem "rspec"
20
- gem "webmock"
13
+ gem 'bundler', '> 2.0'
14
+ gem 'byebug'
15
+ gem 'dotenv'
16
+ gem 'juwelier', git: 'https://github.com/flajann2/juwelier.git'
17
+ gem 'rdoc', '> 3.12'
18
+ gem 'rspec'
19
+ gem 'rubocop'
20
+ gem 'shoulda', '>= 0'
21
+ gem 'simplecov', '>= 0'
22
+ gem 'webmock'
21
23
  end
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Upland Mobile Commons Ruby Gem
2
- [![Build Status](https://travis-ci.org/controlshift/upland_mobile_commons_rest.svg?branch=master)](https://travis-ci.org/controlshift/upland_mobile_commons_rest)
2
+ [![CI Status](https://github.com/controlshift/upland_mobile_commons_rest/actions/workflows/ci.yml/badge.svg)](https://github.com/controlshift/upland_mobile_commons_rest/actions/workflows/ci.yml)
3
3
 
4
4
  A ruby gem for interacting with the Upland Mobile Commons API.
5
5
 
data/Rakefile CHANGED
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  require 'rubygems'
@@ -6,42 +5,40 @@ require 'bundler'
6
5
  begin
7
6
  Bundler.setup(:default, :development)
8
7
  rescue Bundler::BundlerError => e
9
- $stderr.puts e.message
10
- $stderr.puts "Run `bundle install` to install missing gems"
8
+ warn e.message
9
+ warn 'Run `bundle install` to install missing gems'
11
10
  exit e.status_code
12
11
  end
13
12
  require 'rake'
14
13
  require 'juwelier'
15
14
  Juwelier::Tasks.new do |gem|
16
15
  # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17
- gem.name = "upland_mobile_commons_rest"
18
- gem.homepage = "http://github.com/controlshift/upland_mobile_commons_rest"
19
- gem.license = "MIT"
20
- gem.summary = %Q{API client gem for Upland Mobile Commons}
21
- gem.description = %Q{A simple ruby API client gem for the Upland Mobile Commons REST API}
22
- gem.email = "nathan@controlshiftlabs.com"
23
- gem.authors = ["Nathan Woodhull"]
16
+ gem.name = 'upland_mobile_commons_rest'
17
+ gem.homepage = 'http://github.com/controlshift/upland_mobile_commons_rest'
18
+ gem.license = 'MIT'
19
+ gem.summary = %(API client gem for Upland Mobile Commons)
20
+ gem.description = %(A simple ruby API client gem for the Upland Mobile Commons REST API)
21
+ gem.email = 'team@controlshiftlabs.com'
22
+ gem.authors = ['Kathy Lu', 'Diego Marcet', 'Grey Moore', 'Nathan Woodhull']
24
23
 
25
24
  # dependencies defined in Gemfile
26
25
  end
27
26
  Juwelier::RubygemsDotOrgTasks.new
28
27
 
29
- desc "Code coverage detail"
28
+ desc 'Code coverage detail'
30
29
  task :simplecov do
31
- ENV['COVERAGE'] = "true"
30
+ ENV['COVERAGE'] = 'true'
32
31
  Rake::Task['test'].execute
33
32
  end
34
33
 
35
-
36
34
  require 'rspec/core/rake_task'
37
35
  RSpec::Core::RakeTask.new(:spec)
38
36
 
39
-
40
- task :default => :spec
37
+ task default: :spec
41
38
 
42
39
  require 'rdoc/task'
43
40
  Rake::RDocTask.new do |rdoc|
44
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
+ version = File.exist?('VERSION') ? File.read('VERSION') : ''
45
42
 
46
43
  rdoc.rdoc_dir = 'rdoc'
47
44
  rdoc.title = "upland_mobile_commons_rest #{version}"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.3.0
data/example.rb CHANGED
@@ -1,4 +1,5 @@
1
-
1
+ # frozen_string_literal: true
2
+
2
3
  $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
3
4
 
4
5
  require 'upland_mobile_commons_rest'
@@ -7,9 +8,9 @@ require 'byebug'
7
8
 
8
9
  Dotenv.load('.env')
9
10
 
10
- client = UplandMobileCommonsRest.new(username: ENV['USERNAME'], password: ENV['PASSWORD'] ) # rubocop:disable Lint/UselessAssignment
11
+ client = UplandMobileCommonsRest.new(username: ENV['USERNAME'], password: ENV['PASSWORD']) # rubocop:disable Lint/UselessAssignment
11
12
 
12
13
  puts "Ready to call MobileCommons API using 'client' object"
13
14
  byebug # rubocop:disable Lint/Debugger
14
15
 
15
- puts "Bye!"
16
+ puts 'Bye!'
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module UplandMobileCommonsRest
2
4
  class Base < Vertebrae::Model
3
5
  def url_escape(string)
4
6
  CGI.escape(string.to_s)
5
7
  end
6
-
7
8
  end
8
9
  end
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module UplandMobileCommonsRest
2
4
  class Campaigns < Base
3
-
4
5
  def base_path
5
6
  'campaigns'
6
7
  end
@@ -4,7 +4,7 @@ module UplandMobileCommonsRest
4
4
  class Client < Vertebrae::API
5
5
  attr_accessor :username, :password, :company_key
6
6
 
7
- def initialize(options={}, &block)
7
+ def initialize(options = {}, &block)
8
8
  self.username = options[:username]
9
9
  self.password = options[:password]
10
10
  self.company_key = options[:company_key]
@@ -25,15 +25,19 @@ module UplandMobileCommonsRest
25
25
 
26
26
  def setup
27
27
  connection.stack do |builder|
28
+ # Request middlewares, in the order they should run
28
29
  builder.use Faraday::Request::Multipart
29
30
  builder.use Faraday::Request::UrlEncoded
30
31
  if connection.configuration.authenticated?
31
- builder.use Faraday::Request::BasicAuthentication, connection.configuration.username, connection.configuration.password
32
+ builder.use Faraday::Request::BasicAuthentication, connection.configuration.username,
33
+ connection.configuration.password
32
34
  end
33
35
 
36
+ # Response middlewares, in the *reverse* order they should run
34
37
  builder.use UplandMobileCommonsRest::TypedErrorMiddleware
35
38
  builder.use Faraday::Response::Logger if ENV['DEBUG']
36
39
  builder.use FaradayMiddleware::ParseXml
40
+ builder.use UplandMobileCommonsRest::HttpErrorMiddleware
37
41
 
38
42
  builder.adapter connection.configuration.adapter
39
43
  end
@@ -1,47 +1,137 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module UplandMobileCommonsRest
4
+ class NetworkError < StandardError
5
+ attr_accessor :status, :body
6
+
7
+ def initialize(params)
8
+ self.status = params[:status]
9
+ self.body = params[:body]
10
+
11
+ # Including the parentheses means we call #super with no arguments,
12
+ # rather than passing params along. We do this to avoid the params being
13
+ # treated as the "message" of the exception.
14
+ super()
15
+ end
16
+
17
+ def to_s
18
+ "#{super}\n status: #{status}\n body: #{body}"
19
+ end
20
+ end
21
+
22
+ class BadGatewayError < NetworkError; end
23
+ class GatewayTimeoutError < NetworkError; end
24
+
25
+ # This middleware runs *before* XML parsing, so we can include the raw response body in the exception.
26
+ class HttpErrorMiddleware < Faraday::Response::Middleware
27
+ def on_complete(response)
28
+ status_code = response[:status].to_i
29
+
30
+ # Raise an exception for 5xx errors.
31
+ # Q: Shouldn't we also raise for 4xx errors?
32
+ # A: We let TypedErrorMiddleware handle those, in case they have useful info.
33
+ case status_code
34
+ when 502
35
+ raise BadGatewayError.new(response)
36
+ when 503
37
+ if /This website is under heavy load/.match?(response.body)
38
+ raise HeavyLoadError, response.body
39
+ else
40
+ raise UnknownError, response.body
41
+ end
42
+ when 504
43
+ raise GatewayTimeoutError.new(response)
44
+ when 500...600
45
+ # Just in case we get other 5xx errors, raise something for those
46
+ # This has not happened that we know of, but better safe than sorry!
47
+ raise UnknownError, response.inspect
48
+ end
49
+ end
50
+ end
51
+
2
52
  class MobileCommonsError < StandardError
3
53
  attr_accessor :code, :raw_message
4
54
  end
5
55
 
56
+ class HeavyLoadError < MobileCommonsError; end
57
+
6
58
  class UnknownError < MobileCommonsError; end
59
+
7
60
  class InvalidCampaignId < MobileCommonsError; end
61
+
8
62
  class InvalidBroadcastTime < MobileCommonsError; end
63
+
9
64
  class InvalidMessageBody < MobileCommonsError; end
65
+
10
66
  class InvalidCompanyId < MobileCommonsError; end
67
+
11
68
  class InvalidPhoneNumber < MobileCommonsError; end
69
+
12
70
  class InvalidGroupId < MobileCommonsError; end
71
+
13
72
  class InvalidStartTime < MobileCommonsError; end
73
+
14
74
  class InvalidEndTime < MobileCommonsError; end
75
+
15
76
  class InvalidMdataId < MobileCommonsError; end
77
+
16
78
  class InvalidKey < MobileCommonsError; end
79
+
17
80
  class PhoneIsNotOptedIntoThisCampaign < MobileCommonsError; end
81
+
18
82
  class InvalidFundraisingId < MobileCommonsError; end
83
+
19
84
  class InvalidMessageTemplate < MobileCommonsError; end
85
+
20
86
  class PhoneIsNotTextable < MobileCommonsError; end
87
+
21
88
  class InvalidMconnectId < MobileCommonsError; end
89
+
22
90
  class InvalidQueryParameters < MobileCommonsError; end
91
+
23
92
  class TooManyMessages < MobileCommonsError; end
93
+
24
94
  class InvalidName < MobileCommonsError; end
95
+
25
96
  class InvalidOptInPath < MobileCommonsError; end
97
+
26
98
  class InvalidUrl < MobileCommonsError; end
99
+
27
100
  class InvalidAttachment < MobileCommonsError; end
101
+
28
102
  class InvalidBroadcastId < MobileCommonsError; end
103
+
29
104
  class InvalidBroadcastStateChange < MobileCommonsError; end
105
+
30
106
  class BroadcastHasNotBeenSent < MobileCommonsError; end
107
+
31
108
  class MessageTemplateInvalid < MobileCommonsError; end
109
+
32
110
  class InvalidUserId < MobileCommonsError; end
111
+
33
112
  class APIRateLimitExceeded < MobileCommonsError; end
113
+
34
114
  class MissingPhoneNumberParameter < MobileCommonsError; end
115
+
35
116
  class InvalidProfileSaveItemBehavior < MobileCommonsError; end
117
+
36
118
  class InvalidProfileAttributes < MobileCommonsError; end
119
+
37
120
  class InvalidPreviousId < MobileCommonsError; end
121
+
38
122
  class InvalidTagName < MobileCommonsError; end
123
+
39
124
  class InvalidTagParameters < MobileCommonsError; end
125
+
40
126
  class InvalidShortcodeId < MobileCommonsError; end
127
+
41
128
  class InvalidDateRange < MobileCommonsError; end
129
+
42
130
  class InvalidScheduledMessageId < MobileCommonsError; end
131
+
43
132
  class MessageHasAlreadyBeenSent < MobileCommonsError; end
44
133
 
134
+ # This middleware runs *after* XML parsing, because it uses information extracted from the body
45
135
  class TypedErrorMiddleware < Faraday::Response::Middleware
46
136
  POSSIBLE_ERRORS = {
47
137
  '0' => UnknownError,
@@ -82,17 +172,15 @@ module UplandMobileCommonsRest
82
172
  '35' => InvalidDateRange,
83
173
  '36' => InvalidScheduledMessageId,
84
174
  '37' => MessageHasAlreadyBeenSent
85
- }
175
+ }.freeze
86
176
 
87
177
  def on_complete(response)
88
178
  # First ensure responses without the expected format are correctly handled
89
- if response.body.nil? || response.body['response'].nil?
90
- raise UnknownError.new(response.inspect)
91
- end
179
+ raise UnknownError, response.inspect if response.body.nil? || response.body['response'].nil?
92
180
 
93
181
  # Now verify that response was successful or raise a corresponding exception otherwise
94
182
  if response.body['response']['success'] == 'false'
95
- raise POSSIBLE_ERRORS[response.body['response']['error']['id']].new(response.body['response']['error']['message'])
183
+ raise POSSIBLE_ERRORS[response.body['response']['error']['id']], response.body['response']['error']['message']
96
184
  end
97
185
  end
98
186
  end
@@ -1,12 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module UplandMobileCommonsRest
2
4
  class Groups < Base
3
-
4
5
  def base_path
5
6
  'groups'
6
7
  end
7
8
 
8
- def list
9
- resp = client.get_request(base_path)
9
+ def list(page: nil, limit: nil)
10
+ params = []
11
+
12
+ params << "page=#{url_escape(page)}" if page
13
+
14
+ params << "limit=#{url_escape(limit)}" if limit
15
+
16
+ request_path = base_path
17
+ request_path += "?#{params.join('&')}" if params.any?
18
+
19
+ resp = client.get_request(request_path)
10
20
  resp.body['response']['groups']['group']
11
21
  end
12
22
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module UplandMobileCommonsRest
2
4
  class Profiles < Base
3
5
  def base_path
@@ -17,4 +17,4 @@ require 'upland_mobile_commons_rest/base'
17
17
  require 'upland_mobile_commons_rest/campaigns'
18
18
  require 'upland_mobile_commons_rest/groups'
19
19
  require 'upland_mobile_commons_rest/profiles'
20
- require 'upland_mobile_commons_rest/errors'
20
+ require 'upland_mobile_commons_rest/errors'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe UplandMobileCommonsRest::Campaigns do
@@ -26,4 +28,4 @@ describe UplandMobileCommonsRest::Campaigns do
26
28
  end
27
29
  end
28
30
  end
29
- end
31
+ end
data/spec/client_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe UplandMobileCommonsRest::Client do
@@ -15,4 +17,122 @@ describe UplandMobileCommonsRest::Client do
15
17
  expect(campaigns.client).to eq(subject)
16
18
  end
17
19
  end
20
+
21
+ describe 'error handling' do
22
+ let(:request_params) { {example: 'data'} }
23
+
24
+ subject { UplandMobileCommonsRest::Client.new(username: 'foo', password: 'bar') }
25
+
26
+ before :each do
27
+ stub_request(:post, 'https://secure.mcommons.com/api/do_something')
28
+ .to_return(status: response_status, body: response_body)
29
+ end
30
+
31
+ shared_examples_for 'error code parsing' do
32
+ UplandMobileCommonsRest::TypedErrorMiddleware::POSSIBLE_ERRORS.each do |code, ex_type|
33
+ context "response body with success=false and error code #{code}" do
34
+ let(:response_body) do
35
+ <<~XML
36
+ <response success="false">
37
+ <error id="#{code}" message="This is not correct!"/>
38
+ </response>
39
+ XML
40
+ end
41
+
42
+ it "should raise #{ex_type}" do
43
+ expect{ subject.post_request('do_something', request_params) }.to raise_error(ex_type)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ context '200 status response' do
50
+ let(:response_status) { 200 }
51
+
52
+ context 'no response body' do
53
+ let(:response_body) { nil }
54
+
55
+ it 'should raise an UnknownError' do
56
+ expect{ subject.post_request('do_something', request_params) }.to raise_error(UplandMobileCommonsRest::UnknownError)
57
+ end
58
+ end
59
+
60
+ context 'response body without <response> tag' do
61
+ let(:response_body) { '<body>Well, this is unexpected!</body>' }
62
+
63
+ it 'should raise an UnknownError' do
64
+ expect{ subject.post_request('do_something', request_params) }.to raise_error(UplandMobileCommonsRest::UnknownError)
65
+ end
66
+ end
67
+
68
+ context 'response body with success=true' do
69
+ let(:response_body) { '<response success="true">hurray!</response>' }
70
+
71
+ it 'should not raise' do
72
+ expect{ subject.post_request('do_something', request_params) }.not_to raise_error
73
+ end
74
+ end
75
+
76
+ include_examples 'error code parsing'
77
+ end
78
+
79
+ context '400 status response' do
80
+ let(:response_status) { 400 }
81
+
82
+ include_examples 'error code parsing'
83
+ end
84
+
85
+ context '502 status response' do
86
+ let(:response_status) { 502 }
87
+ let(:response_body) { '<html><head><title>502 Bad Gateway</title></head><body><center><h1>502 Bad Gateway</h1></center></body></html>' }
88
+
89
+ it 'should raise an BadGatewayError' do
90
+ expect do
91
+ subject.post_request('do_something', request_params)
92
+ end.to raise_error(UplandMobileCommonsRest::BadGatewayError) do |error|
93
+ expect(error.body).to eq response_body
94
+ expect(error.to_s).to include(response_body)
95
+ end
96
+ end
97
+ end
98
+
99
+ context '503 status response' do
100
+ let(:response_status) { 503 }
101
+ let(:response_body) { '<html><head><title>503 Internal Server Error</title></head><body><center><h1>503 Internal Server Error</h1></center></body></html>' }
102
+
103
+ it 'should raise an UnknownError' do
104
+ expect do
105
+ subject.post_request('do_something', request_params)
106
+ end.to raise_error(UplandMobileCommonsRest::UnknownError) do |error|
107
+ expect(error.to_s).to include(response_body)
108
+ end
109
+ end
110
+
111
+ context 'with Heavy Load message' do
112
+ let(:response_body) { "<h2>This website is under heavy load (queue full)</h2><p>We're sorry, too many people are accessing this website at the same time. We're working on this problem. Please try again later.</p>" }
113
+
114
+ it 'should raise a HeavyLoadError' do
115
+ expect do
116
+ subject.post_request('do_something', request_params)
117
+ end.to raise_error(UplandMobileCommonsRest::HeavyLoadError) do |error|
118
+ expect(error.to_s).to include(response_body)
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ context '504 status response' do
125
+ let(:response_status) { 504 }
126
+ let(:response_body) { '<html><head><title>504 Gateway Time-out</title></head><body><center><h1>504 Gateway Time-out</h1></center></body></html>' }
127
+
128
+ it 'should raise an GatewayTimeoutError' do
129
+ expect do
130
+ subject.post_request('do_something', request_params)
131
+ end.to raise_error(UplandMobileCommonsRest::GatewayTimeoutError) do |error|
132
+ expect(error.body).to eq response_body
133
+ expect(error.to_s).to include(response_body)
134
+ end
135
+ end
136
+ end
137
+ end
18
138
  end
@@ -0,0 +1,3 @@
1
+ <response success="false">
2
+ <error id="5" message="Invalid phone number" />
3
+ </response>
@@ -0,0 +1,42 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <response success="true">
3
+ <profile id="34xxxxxxx">
4
+ <first_name>John</first_name>
5
+ <last_name>Doe</last_name>
6
+ <phone_number>12025551234</phone_number>
7
+ <email />
8
+ <status>Active subscriber</status>
9
+ <created_at>2019-06-21 14:49:40 UTC</created_at>
10
+ <updated_at>2019-06-21 14:49:40 UTC</updated_at>
11
+ <opted_out_at />
12
+ <opted_out_source />
13
+ <source type="API" name="User1" email="user1@domain.com" />
14
+ <address>
15
+ <street1 />
16
+ <street2 />
17
+ <city />
18
+ <state />
19
+ <postal_code />
20
+ <country>US</country>
21
+ </address>
22
+ <last_saved_location>
23
+ <latitude>38.906639</latitude>
24
+ <longitude>-77.016577</longitude>
25
+ <precision>state</precision>
26
+ <city />
27
+ <state>DC</state>
28
+ <postal_code />
29
+ <country>US</country>
30
+ </last_saved_location>
31
+ <custom_columns>
32
+ <custom_column name="Age" />
33
+ <custom_column name="Favorite animal" />
34
+ <custom_column name="Yes/NO" />
35
+ </custom_columns>
36
+ <subscriptions>
37
+ <subscription campaign_id="162xxx" campaign_name="MC_test2" campaign_description="" opt_in_path_id="" status="Active" opt_in_source="User1" created_at="2019-06-21T14:49:40Z" activated_at="2019-06-22T20:24:36Z" opted_out_at="" opt_out_source="" />
38
+ </subscriptions>
39
+ <integrations></integrations>
40
+ <clicks></clicks>
41
+ </profile>
42
+ </response>
data/spec/group_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe UplandMobileCommonsRest::Groups do
@@ -16,15 +18,55 @@ describe UplandMobileCommonsRest::Groups do
16
18
  describe 'list' do
17
19
  let(:response_body) { fixture('groups/list.xml') }
18
20
 
19
- before(:each) do
20
- stub_upland_mobile_commons_request('groups', method: :get).to_return(status: 200, body: response_body)
21
+ context 'unpaginated request' do
22
+ before(:each) do
23
+ stub_upland_mobile_commons_request('groups', method: :get).to_return(status: 200, body: response_body)
24
+ end
25
+
26
+ it 'should return a list of groups' do
27
+ list = subject.list
28
+ expect(list).to be_a(Enumerable)
29
+ expect(list).to eq([{ 'id' => '14', 'name' => 'Group One', 'size' => '2', 'status' => 'active', 'type' => 'FilteredGroup' },
30
+ { 'id' => '91', 'name' => 'Group Two', 'size' => '1', 'status' => 'active',
31
+ 'type' => 'UploadedGroup' }])
32
+ end
21
33
  end
22
34
 
23
- it 'should return a list of groups' do
24
- list = subject.list
25
- expect(list).to be_a(Enumerable)
26
- expect(list).to eq([{"id"=>"14", "name"=>"Group One", "size"=>"2", "status"=>"active", "type"=>"FilteredGroup"},
27
- {"id"=>"91", "name"=>"Group Two", "size"=>"1", "status"=>"active", "type"=>"UploadedGroup"}])
35
+ context 'paginated request' do
36
+ it 'should return a list of groups when both parameters provided' do
37
+ stub_upland_mobile_commons_request('groups?limit=50&page=35', method: :get).to_return(status: 200,
38
+ body: response_body)
39
+
40
+ list = subject.list(page: 35, limit: 50)
41
+
42
+ expect(list).to be_a(Enumerable)
43
+ expect(list).to eq([{ 'id' => '14', 'name' => 'Group One', 'size' => '2', 'status' => 'active', 'type' => 'FilteredGroup' },
44
+ { 'id' => '91', 'name' => 'Group Two', 'size' => '1', 'status' => 'active',
45
+ 'type' => 'UploadedGroup' }])
46
+ end
47
+
48
+ it 'should return a list of groups when only limit parameter provided' do
49
+ stub_upland_mobile_commons_request('groups?limit=50', method: :get).to_return(status: 200,
50
+ body: response_body)
51
+
52
+ list = subject.list(limit: 50)
53
+
54
+ expect(list).to be_a(Enumerable)
55
+ expect(list).to eq([{ 'id' => '14', 'name' => 'Group One', 'size' => '2', 'status' => 'active', 'type' => 'FilteredGroup' },
56
+ { 'id' => '91', 'name' => 'Group Two', 'size' => '1', 'status' => 'active',
57
+ 'type' => 'UploadedGroup' }])
58
+ end
59
+
60
+ it 'should return a list of groups when only page parameter provided' do
61
+ stub_upland_mobile_commons_request('groups?page=35', method: :get).to_return(status: 200, body: response_body)
62
+
63
+ list = subject.list(page: 35)
64
+
65
+ expect(list).to be_a(Enumerable)
66
+ expect(list).to eq([{ 'id' => '14', 'name' => 'Group One', 'size' => '2', 'status' => 'active', 'type' => 'FilteredGroup' },
67
+ { 'id' => '91', 'name' => 'Group Two', 'size' => '1', 'status' => 'active',
68
+ 'type' => 'UploadedGroup' }])
69
+ end
28
70
  end
29
71
  end
30
72
 
@@ -32,7 +74,9 @@ describe UplandMobileCommonsRest::Groups do
32
74
  let(:response_body) { fixture('groups/create.xml') }
33
75
 
34
76
  before(:each) do
35
- stub_upland_mobile_commons_request('create_group?name=Chocolate%20Lovers', method: :get).to_return(status: 200, body: response_body)
77
+ stub_upland_mobile_commons_request('create_group?name=Chocolate%20Lovers', method: :get).to_return(
78
+ status: 200, body: response_body
79
+ )
36
80
  end
37
81
 
38
82
  it 'should return success' do
@@ -41,4 +85,4 @@ describe UplandMobileCommonsRest::Groups do
41
85
  end
42
86
  end
43
87
  end
44
- end
88
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe UplandMobileCommonsRest::Profiles do
@@ -16,8 +18,8 @@ describe UplandMobileCommonsRest::Profiles do
16
18
 
17
19
  describe 'get' do
18
20
  before(:each) do
19
- stub_upland_mobile_commons_request("profile?phone_number=#{phone_number}", method: :get).
20
- to_return(status: 200, body: response_body)
21
+ stub_upland_mobile_commons_request("profile?phone_number=#{phone_number}", method: :get)
22
+ .to_return(status: 200, body: response_body)
21
23
  end
22
24
 
23
25
  context 'success' do
@@ -45,8 +47,8 @@ describe UplandMobileCommonsRest::Profiles do
45
47
 
46
48
  describe 'update' do
47
49
  before(:each) do
48
- stub_upland_mobile_commons_request('profile_update', method: :post, body: "phone_number=#{phone_number}").
49
- to_return(status: 200, body: response_body)
50
+ stub_upland_mobile_commons_request('profile_update', method: :post, body: "phone_number=#{phone_number}")
51
+ .to_return(status: 200, body: response_body)
50
52
  end
51
53
 
52
54
  context 'success' do
@@ -55,6 +57,10 @@ describe UplandMobileCommonsRest::Profiles do
55
57
  it 'should succeed' do
56
58
  resp = subject.update(phone_number: phone_number)
57
59
  expect(resp).to_not be_nil
60
+
61
+ expect(resp.body['response']['profile']['id']).to eq('34xxxxxxx')
62
+ expect(resp.body['response']['profile']['first_name']).to eq('John')
63
+ expect(resp.body['response']['profile']['last_name']).to eq('Doe')
58
64
  end
59
65
  end
60
66
 
@@ -62,7 +68,9 @@ describe UplandMobileCommonsRest::Profiles do
62
68
  let(:response_body) { fixture('error.xml') }
63
69
 
64
70
  it 'should raise' do
65
- expect { subject.update(phone_number: phone_number) }.to raise_error(UplandMobileCommonsRest::InvalidMessageBody)
71
+ expect do
72
+ subject.update(phone_number: phone_number)
73
+ end.to raise_error(UplandMobileCommonsRest::InvalidMessageBody)
66
74
  end
67
75
  end
68
76
  end
data/spec/spec_helper.rb CHANGED
@@ -5,11 +5,11 @@ require 'upland_mobile_commons_rest'
5
5
  require 'webmock/rspec'
6
6
 
7
7
  # Require everything in the `support` directory
8
- Dir[File.join(File.dirname(__FILE__), 'support', '**', '*.rb')].sort.each {|f| require f}
8
+ Dir[File.join(File.dirname(__FILE__), 'support', '**', '*.rb')].sort.each { |f| require f }
9
9
 
10
10
  RSpec.configure do |config|
11
11
  # Enable flags like --only-failures and --next-failure
12
- config.example_status_persistence_file_path = ".rspec_status"
12
+ config.example_status_persistence_file_path = '.rspec_status'
13
13
 
14
14
  # Disable RSpec exposing methods globally on `Module` and `main`
15
15
  config.disable_monkey_patching!
@@ -20,4 +20,4 @@ RSpec.configure do |config|
20
20
  config.expect_with :rspec do |c|
21
21
  c.syntax = :expect
22
22
  end
23
- end
23
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  def fixture(name)
2
- File.read(File.join(File.dirname(__FILE__), '..','fixtures', name))
4
+ File.read(File.join(File.dirname(__FILE__), '..', 'fixtures', name))
3
5
  end
@@ -1,4 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  def stub_upland_mobile_commons_request(path, method:, body: nil)
2
4
  stub_request(method, "https://secure.mcommons.com/api/#{path}")
3
- .with(body: body, basic_auth: [username, password])
5
+ .with(body: body, basic_auth: [username, password])
4
6
  end
@@ -9,4 +9,4 @@ describe UplandMobileCommonsRest do
9
9
  expect(client.username).to eq('foo')
10
10
  expect(client.password).to eq('bar')
11
11
  end
12
- end
12
+ end
@@ -2,29 +2,30 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: upland_mobile_commons_rest 0.1.0 ruby lib
5
+ # stub: upland_mobile_commons_rest 0.3.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "upland_mobile_commons_rest".freeze
9
- s.version = "0.1.1"
9
+ s.version = "0.3.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
- s.authors = ["Nathan Woodhull".freeze]
14
- s.date = "2020-06-25"
13
+ s.authors = ["Kathy Lu".freeze, "Diego Marcet".freeze, "Grey Moore".freeze, "Nathan Woodhull".freeze]
14
+ s.date = "2022-07-05"
15
15
  s.description = "A simple ruby API client gem for the Upland Mobile Commons REST API".freeze
16
- s.email = "nathan@controlshiftlabs.com".freeze
16
+ s.email = "team@controlshiftlabs.com".freeze
17
17
  s.extra_rdoc_files = [
18
18
  "LICENSE.txt",
19
19
  "README.md"
20
20
  ]
21
21
  s.files = [
22
22
  ".document",
23
+ ".github/workflows/ci.yml",
23
24
  ".rubocop.yml",
24
- ".travis.yml",
25
+ ".ruby-gemset",
26
+ ".ruby-version",
25
27
  "CODE_OF_CONDUCT.md",
26
28
  "Gemfile",
27
- "Gemfile.lock",
28
29
  "LICENSE.txt",
29
30
  "README.md",
30
31
  "Rakefile",
@@ -41,8 +42,10 @@ Gem::Specification.new do |s|
41
42
  "spec/client_spec.rb",
42
43
  "spec/fixtures/campaigns/list.xml",
43
44
  "spec/fixtures/error.xml",
45
+ "spec/fixtures/error_profile_not_found.xml",
44
46
  "spec/fixtures/groups/create.xml",
45
47
  "spec/fixtures/groups/list.xml",
48
+ "spec/fixtures/profiles/get.xml",
46
49
  "spec/fixtures/profiles/update.xml",
47
50
  "spec/group_spec.rb",
48
51
  "spec/profiles_spec.rb",
@@ -54,48 +57,36 @@ Gem::Specification.new do |s|
54
57
  ]
55
58
  s.homepage = "http://github.com/controlshift/upland_mobile_commons_rest".freeze
56
59
  s.licenses = ["MIT".freeze]
57
- s.rubygems_version = "3.0.8".freeze
60
+ s.rubygems_version = "3.1.6".freeze
58
61
  s.summary = "API client gem for Upland Mobile Commons".freeze
59
62
 
60
63
  if s.respond_to? :specification_version then
61
64
  s.specification_version = 4
65
+ end
62
66
 
63
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
64
- s.add_runtime_dependency(%q<vertebrae>.freeze, [">= 0"])
65
- s.add_development_dependency(%q<shoulda>.freeze, [">= 0"])
66
- s.add_development_dependency(%q<rdoc>.freeze, ["> 3.12"])
67
- s.add_development_dependency(%q<bundler>.freeze, ["> 2.0"])
68
- s.add_development_dependency(%q<juwelier>.freeze, [">= 0"])
69
- s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
70
- s.add_development_dependency(%q<dotenv>.freeze, [">= 0"])
71
- s.add_development_dependency(%q<byebug>.freeze, [">= 0"])
72
- s.add_development_dependency(%q<rubocop>.freeze, [">= 0"])
73
- s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
74
- s.add_development_dependency(%q<webmock>.freeze, [">= 0"])
75
- else
76
- s.add_dependency(%q<vertebrae>.freeze, [">= 0"])
77
- s.add_dependency(%q<shoulda>.freeze, [">= 0"])
78
- s.add_dependency(%q<rdoc>.freeze, ["> 3.12"])
79
- s.add_dependency(%q<bundler>.freeze, ["> 2.0"])
80
- s.add_dependency(%q<juwelier>.freeze, [">= 0"])
81
- s.add_dependency(%q<simplecov>.freeze, [">= 0"])
82
- s.add_dependency(%q<dotenv>.freeze, [">= 0"])
83
- s.add_dependency(%q<byebug>.freeze, [">= 0"])
84
- s.add_dependency(%q<rubocop>.freeze, [">= 0"])
85
- s.add_dependency(%q<rspec>.freeze, [">= 0"])
86
- s.add_dependency(%q<webmock>.freeze, [">= 0"])
87
- end
67
+ if s.respond_to? :add_runtime_dependency then
68
+ s.add_runtime_dependency(%q<vertebrae>.freeze, [">= 0"])
69
+ s.add_development_dependency(%q<bundler>.freeze, ["> 2.0"])
70
+ s.add_development_dependency(%q<byebug>.freeze, [">= 0"])
71
+ s.add_development_dependency(%q<dotenv>.freeze, [">= 0"])
72
+ s.add_development_dependency(%q<juwelier>.freeze, [">= 0"])
73
+ s.add_development_dependency(%q<rdoc>.freeze, ["> 3.12"])
74
+ s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
75
+ s.add_development_dependency(%q<rubocop>.freeze, [">= 0"])
76
+ s.add_development_dependency(%q<shoulda>.freeze, [">= 0"])
77
+ s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
78
+ s.add_development_dependency(%q<webmock>.freeze, [">= 0"])
88
79
  else
89
80
  s.add_dependency(%q<vertebrae>.freeze, [">= 0"])
90
- s.add_dependency(%q<shoulda>.freeze, [">= 0"])
91
- s.add_dependency(%q<rdoc>.freeze, ["> 3.12"])
92
81
  s.add_dependency(%q<bundler>.freeze, ["> 2.0"])
93
- s.add_dependency(%q<juwelier>.freeze, [">= 0"])
94
- s.add_dependency(%q<simplecov>.freeze, [">= 0"])
95
- s.add_dependency(%q<dotenv>.freeze, [">= 0"])
96
82
  s.add_dependency(%q<byebug>.freeze, [">= 0"])
97
- s.add_dependency(%q<rubocop>.freeze, [">= 0"])
83
+ s.add_dependency(%q<dotenv>.freeze, [">= 0"])
84
+ s.add_dependency(%q<juwelier>.freeze, [">= 0"])
85
+ s.add_dependency(%q<rdoc>.freeze, ["> 3.12"])
98
86
  s.add_dependency(%q<rspec>.freeze, [">= 0"])
87
+ s.add_dependency(%q<rubocop>.freeze, [">= 0"])
88
+ s.add_dependency(%q<shoulda>.freeze, [">= 0"])
89
+ s.add_dependency(%q<simplecov>.freeze, [">= 0"])
99
90
  s.add_dependency(%q<webmock>.freeze, [">= 0"])
100
91
  end
101
92
  end
metadata CHANGED
@@ -1,14 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: upland_mobile_commons_rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
+ - Kathy Lu
8
+ - Diego Marcet
9
+ - Grey Moore
7
10
  - Nathan Woodhull
8
11
  autorequire:
9
12
  bindir: bin
10
13
  cert_chain: []
11
- date: 2020-06-25 00:00:00.000000000 Z
14
+ date: 2022-07-05 00:00:00.000000000 Z
12
15
  dependencies:
13
16
  - !ruby/object:Gem::Dependency
14
17
  name: vertebrae
@@ -25,47 +28,47 @@ dependencies:
25
28
  - !ruby/object:Gem::Version
26
29
  version: '0'
27
30
  - !ruby/object:Gem::Dependency
28
- name: shoulda
31
+ name: bundler
29
32
  requirement: !ruby/object:Gem::Requirement
30
33
  requirements:
31
- - - ">="
34
+ - - ">"
32
35
  - !ruby/object:Gem::Version
33
- version: '0'
36
+ version: '2.0'
34
37
  type: :development
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
- - - ">="
41
+ - - ">"
39
42
  - !ruby/object:Gem::Version
40
- version: '0'
43
+ version: '2.0'
41
44
  - !ruby/object:Gem::Dependency
42
- name: rdoc
45
+ name: byebug
43
46
  requirement: !ruby/object:Gem::Requirement
44
47
  requirements:
45
- - - ">"
48
+ - - ">="
46
49
  - !ruby/object:Gem::Version
47
- version: '3.12'
50
+ version: '0'
48
51
  type: :development
49
52
  prerelease: false
50
53
  version_requirements: !ruby/object:Gem::Requirement
51
54
  requirements:
52
- - - ">"
55
+ - - ">="
53
56
  - !ruby/object:Gem::Version
54
- version: '3.12'
57
+ version: '0'
55
58
  - !ruby/object:Gem::Dependency
56
- name: bundler
59
+ name: dotenv
57
60
  requirement: !ruby/object:Gem::Requirement
58
61
  requirements:
59
- - - ">"
62
+ - - ">="
60
63
  - !ruby/object:Gem::Version
61
- version: '2.0'
64
+ version: '0'
62
65
  type: :development
63
66
  prerelease: false
64
67
  version_requirements: !ruby/object:Gem::Requirement
65
68
  requirements:
66
- - - ">"
69
+ - - ">="
67
70
  - !ruby/object:Gem::Version
68
- version: '2.0'
71
+ version: '0'
69
72
  - !ruby/object:Gem::Dependency
70
73
  name: juwelier
71
74
  requirement: !ruby/object:Gem::Requirement
@@ -81,21 +84,21 @@ dependencies:
81
84
  - !ruby/object:Gem::Version
82
85
  version: '0'
83
86
  - !ruby/object:Gem::Dependency
84
- name: simplecov
87
+ name: rdoc
85
88
  requirement: !ruby/object:Gem::Requirement
86
89
  requirements:
87
- - - ">="
90
+ - - ">"
88
91
  - !ruby/object:Gem::Version
89
- version: '0'
92
+ version: '3.12'
90
93
  type: :development
91
94
  prerelease: false
92
95
  version_requirements: !ruby/object:Gem::Requirement
93
96
  requirements:
94
- - - ">="
97
+ - - ">"
95
98
  - !ruby/object:Gem::Version
96
- version: '0'
99
+ version: '3.12'
97
100
  - !ruby/object:Gem::Dependency
98
- name: dotenv
101
+ name: rspec
99
102
  requirement: !ruby/object:Gem::Requirement
100
103
  requirements:
101
104
  - - ">="
@@ -109,7 +112,7 @@ dependencies:
109
112
  - !ruby/object:Gem::Version
110
113
  version: '0'
111
114
  - !ruby/object:Gem::Dependency
112
- name: byebug
115
+ name: rubocop
113
116
  requirement: !ruby/object:Gem::Requirement
114
117
  requirements:
115
118
  - - ">="
@@ -123,7 +126,7 @@ dependencies:
123
126
  - !ruby/object:Gem::Version
124
127
  version: '0'
125
128
  - !ruby/object:Gem::Dependency
126
- name: rubocop
129
+ name: shoulda
127
130
  requirement: !ruby/object:Gem::Requirement
128
131
  requirements:
129
132
  - - ">="
@@ -137,7 +140,7 @@ dependencies:
137
140
  - !ruby/object:Gem::Version
138
141
  version: '0'
139
142
  - !ruby/object:Gem::Dependency
140
- name: rspec
143
+ name: simplecov
141
144
  requirement: !ruby/object:Gem::Requirement
142
145
  requirements:
143
146
  - - ">="
@@ -165,7 +168,7 @@ dependencies:
165
168
  - !ruby/object:Gem::Version
166
169
  version: '0'
167
170
  description: A simple ruby API client gem for the Upland Mobile Commons REST API
168
- email: nathan@controlshiftlabs.com
171
+ email: team@controlshiftlabs.com
169
172
  executables: []
170
173
  extensions: []
171
174
  extra_rdoc_files:
@@ -173,11 +176,12 @@ extra_rdoc_files:
173
176
  - README.md
174
177
  files:
175
178
  - ".document"
179
+ - ".github/workflows/ci.yml"
176
180
  - ".rubocop.yml"
177
- - ".travis.yml"
181
+ - ".ruby-gemset"
182
+ - ".ruby-version"
178
183
  - CODE_OF_CONDUCT.md
179
184
  - Gemfile
180
- - Gemfile.lock
181
185
  - LICENSE.txt
182
186
  - README.md
183
187
  - Rakefile
@@ -194,8 +198,10 @@ files:
194
198
  - spec/client_spec.rb
195
199
  - spec/fixtures/campaigns/list.xml
196
200
  - spec/fixtures/error.xml
201
+ - spec/fixtures/error_profile_not_found.xml
197
202
  - spec/fixtures/groups/create.xml
198
203
  - spec/fixtures/groups/list.xml
204
+ - spec/fixtures/profiles/get.xml
199
205
  - spec/fixtures/profiles/update.xml
200
206
  - spec/group_spec.rb
201
207
  - spec/profiles_spec.rb
@@ -223,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
223
229
  - !ruby/object:Gem::Version
224
230
  version: '0'
225
231
  requirements: []
226
- rubygems_version: 3.0.8
232
+ rubygems_version: 3.1.6
227
233
  signing_key:
228
234
  specification_version: 4
229
235
  summary: API client gem for Upland Mobile Commons
data/.travis.yml DELETED
@@ -1,9 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.6
4
- cache: bundler
5
- before_install:
6
- - gem install bundler
7
- script:
8
- - bundle exec rspec
9
- - bundle exec rubocop
data/Gemfile.lock DELETED
@@ -1,154 +0,0 @@
1
- GIT
2
- remote: https://github.com/flajann2/juwelier.git
3
- revision: de59d5a2ddea00c1f18957ab62129c1c141acce1
4
- specs:
5
- juwelier (2.4.9)
6
- builder
7
- bundler
8
- git
9
- github_api
10
- highline
11
- kamelcase (~> 0)
12
- nokogiri
13
- psych
14
- rake
15
- rdoc
16
- semver2
17
-
18
- GEM
19
- remote: https://rubygems.org/
20
- specs:
21
- activesupport (6.0.3.1)
22
- concurrent-ruby (~> 1.0, >= 1.0.2)
23
- i18n (>= 0.7, < 2)
24
- minitest (~> 5.1)
25
- tzinfo (~> 1.1)
26
- zeitwerk (~> 2.2, >= 2.2.2)
27
- addressable (2.7.0)
28
- public_suffix (>= 2.0.2, < 5.0)
29
- ast (2.4.0)
30
- builder (3.2.4)
31
- byebug (11.1.3)
32
- concurrent-ruby (1.1.6)
33
- crack (0.4.3)
34
- safe_yaml (~> 1.0.0)
35
- descendants_tracker (0.0.4)
36
- thread_safe (~> 0.3, >= 0.3.1)
37
- diff-lcs (1.3)
38
- docile (1.3.2)
39
- dotenv (2.7.5)
40
- faraday (0.17.3)
41
- multipart-post (>= 1.2, < 3)
42
- faraday_middleware (0.14.0)
43
- faraday (>= 0.7.4, < 1.0)
44
- git (1.7.0)
45
- rchardet (~> 1.8)
46
- github_api (0.18.2)
47
- addressable (~> 2.4)
48
- descendants_tracker (~> 0.0.4)
49
- faraday (~> 0.8)
50
- hashie (~> 3.5, >= 3.5.2)
51
- oauth2 (~> 1.0)
52
- hashdiff (1.0.1)
53
- hashie (3.6.0)
54
- highline (2.0.3)
55
- i18n (1.8.3)
56
- concurrent-ruby (~> 1.0)
57
- jwt (2.2.1)
58
- kamelcase (0.0.2)
59
- semver2 (~> 3)
60
- mini_portile2 (2.4.0)
61
- minitest (5.14.1)
62
- multi_json (1.14.1)
63
- multi_xml (0.6.0)
64
- multipart-post (2.1.1)
65
- nokogiri (1.10.9)
66
- mini_portile2 (~> 2.4.0)
67
- oauth2 (1.4.4)
68
- faraday (>= 0.8, < 2.0)
69
- jwt (>= 1.0, < 3.0)
70
- multi_json (~> 1.3)
71
- multi_xml (~> 0.5)
72
- rack (>= 1.2, < 3)
73
- parallel (1.19.1)
74
- parser (2.7.1.3)
75
- ast (~> 2.4.0)
76
- psych (3.1.0)
77
- public_suffix (4.0.5)
78
- rack (2.2.3)
79
- rainbow (3.0.0)
80
- rake (13.0.1)
81
- rchardet (1.8.0)
82
- rdoc (6.2.1)
83
- regexp_parser (1.7.0)
84
- rexml (3.2.4)
85
- rspec (3.9.0)
86
- rspec-core (~> 3.9.0)
87
- rspec-expectations (~> 3.9.0)
88
- rspec-mocks (~> 3.9.0)
89
- rspec-core (3.9.2)
90
- rspec-support (~> 3.9.3)
91
- rspec-expectations (3.9.2)
92
- diff-lcs (>= 1.2.0, < 2.0)
93
- rspec-support (~> 3.9.0)
94
- rspec-mocks (3.9.1)
95
- diff-lcs (>= 1.2.0, < 2.0)
96
- rspec-support (~> 3.9.0)
97
- rspec-support (3.9.3)
98
- rubocop (0.85.0)
99
- parallel (~> 1.10)
100
- parser (>= 2.7.0.1)
101
- rainbow (>= 2.2.2, < 4.0)
102
- regexp_parser (>= 1.7)
103
- rexml
104
- rubocop-ast (>= 0.0.3)
105
- ruby-progressbar (~> 1.7)
106
- unicode-display_width (>= 1.4.0, < 2.0)
107
- rubocop-ast (0.0.3)
108
- parser (>= 2.7.0.1)
109
- ruby-progressbar (1.10.1)
110
- safe_yaml (1.0.5)
111
- semver2 (3.4.2)
112
- shoulda (3.6.0)
113
- shoulda-context (~> 1.0, >= 1.0.1)
114
- shoulda-matchers (~> 3.0)
115
- shoulda-context (1.2.2)
116
- shoulda-matchers (3.1.3)
117
- activesupport (>= 4.0.0)
118
- simplecov (0.18.5)
119
- docile (~> 1.1)
120
- simplecov-html (~> 0.11)
121
- simplecov-html (0.12.2)
122
- thread_safe (0.3.6)
123
- tzinfo (1.2.7)
124
- thread_safe (~> 0.1)
125
- unicode-display_width (1.7.0)
126
- vertebrae (0.6.2)
127
- activesupport (>= 5.1.4)
128
- faraday (> 0.9.2)
129
- faraday_middleware (> 0.12.2)
130
- hashie (> 3.5.7)
131
- webmock (3.8.3)
132
- addressable (>= 2.3.6)
133
- crack (>= 0.3.2)
134
- hashdiff (>= 0.4.0, < 2.0.0)
135
- zeitwerk (2.3.0)
136
-
137
- PLATFORMS
138
- ruby
139
-
140
- DEPENDENCIES
141
- bundler (> 2.0)
142
- byebug
143
- dotenv
144
- juwelier!
145
- rdoc (> 3.12)
146
- rspec
147
- rubocop
148
- shoulda
149
- simplecov
150
- vertebrae
151
- webmock
152
-
153
- BUNDLED WITH
154
- 2.1.4