openapply 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,399 @@
1
+ module Get
2
+
3
+ # Creates a custom query (non-recursive) to get a list of students summaries
4
+ # matching the allowed attribute's criteria
5
+ #
6
+ # ==== Attributes
7
+ # * +status+ - match status (be sure it is in the list of OpenApply status)
8
+ # * +since_id+ - get all ids matching the criteria LARGER than the given number
9
+ # * +since_date+ - get all records updated after the given date (YYYY-MM-DD) or
10
+ # Date and Time (YYYY-MM-DD HH:MM:SS) - 24 hour clock (not sure about timeszone)
11
+ # * +count+ - return a custom number of records (no more than 1000)
12
+ #
13
+ # ==== Example code
14
+ # @demo = Openapply.new
15
+ # # return: any status (nil), any id greater than 95 updated since 2017-01-01 &
16
+ # # return only 2 records at a time
17
+ # @demo.custom_students_query(nil, since_id=95, since_date=2017-01-01, count=2)
18
+ #
19
+ # ==== Return Format
20
+ # { :students=>
21
+ # [{:id=>96,
22
+ # :serial_number=>86,
23
+ # :custom_id=>"86",
24
+ # :applicant_id=>"00000086",
25
+ # :email=>"Jerry.Patel@eduvo.com",
26
+ # :first_name=>"Jerry",
27
+ # :last_name=>"Patel",
28
+ # ...,
29
+ # :sibling_ids=>[],
30
+ # :updated_at=>"2017-07-11T14:46:44.000+08:00",
31
+ # :...,
32
+ # :parent_ids=>[267, 268]},
33
+ # {:id=>98,
34
+ # :serial_number=>87,
35
+ # :custom_id=>"87",
36
+ # :applicant_id=>"00000087",
37
+ # :email=>"Robin.Barnes@eduvo.com",
38
+ # :first_name=>"Robin",
39
+ # :last_name=>"Barnes",
40
+ # :sibling_ids=>[],
41
+ # :updated_at=>"2017-07-11T14:46:44.000+08:00",
42
+ # ...,
43
+ # :profile_photo=>
44
+ # "https://openapply-sandbox-devel-01.s3.amazonaws.com/uploads/student/avatar/000/000/098/f_rep.jpg?v=1499755604",
45
+ # :profile_photo_updated_at=>"2017-07-11T14:46:44.000+08:00",
46
+ # :parent_ids=>[406, 407]}],
47
+ # :linked=>
48
+ # {:parents=>
49
+ # [{:id=>267,
50
+ # :serial_number=>256,
51
+ # :custom_id=>"256",
52
+ # :name=>"Jane Patel",
53
+ # :first_name=>"Jane",
54
+ # :last_name=>"Patel",
55
+ # ...,
56
+ # :profile_photo=>
57
+ # "https://openapply-sandbox-devel-01.s3.amazonaws.com/uploads/parent/avatar/000/000/267/patel_mom.jpg?v=1499755607",
58
+ # :profile_photo_updated_at=>"2017-07-11T14:46:47.000+08:00",
59
+ # :parent_id=>"256",
60
+ # :custom_fields=>
61
+ # {:title=>"",
62
+ # :treat_parent_as_emergency_contact=>"Yes",
63
+ # :home_telephone=>"",
64
+ # ...,
65
+ # :parent_residency=>"Citizen"}},
66
+ # { ... },
67
+ # {:id=>407,
68
+ # :serial_number=>nil,
69
+ # :custom_id=>nil,
70
+ # :name=>"Boris Barnes",
71
+ # :first_name=>"Boris",
72
+ # :last_name=>"Barnes",
73
+ # ...,
74
+ # :profile_photo=>
75
+ # "https://openapply-sandbox-devel-01.s3.amazonaws.com/uploads/parent/avatar/000/000/407/6e9b4e89-0aa8-413c-8239-2990ea6b0e6d.jpg?v=1499755608",
76
+ # :profile_photo_updated_at=>"2017-07-11T14:46:48.000+08:00",
77
+ # :parent_id=>nil,
78
+ # :custom_fields=>
79
+ # {:title=>nil,
80
+ # :treat_parent_as_emergency_contact=>"Yes",
81
+ # :mobile_phone=>"852 6565 1190",
82
+ # :home_telephone=>"852 4545 1190",
83
+ # ...,
84
+ # :parent_residency=>nil}}]},
85
+ # :meta=>{:pages=>170, :per_page=>"2"}}
86
+ def students_custom_query(status=nil, since_id=nil, since_date=nil, count=api_records)
87
+ return { error: "invalid count" } unless count.to_i >= 1
88
+
89
+ url = students_custom_url(status, since_id, since_date, count)
90
+ answer = oa_answer( url )
91
+ return { error: "nil answer" } if answer.nil?
92
+ return { error: "nil students" } if answer[:students].nil?
93
+ return { student_ids: [] } if answer[:students].empty?
94
+ return answer
95
+ end
96
+
97
+
98
+ # Builds a custom url (with domain) to get a list of students summaries matching
99
+ # the attribute's criteria (but not do a Query) - returns a URL
100
+ #
101
+ # ==== Attributes
102
+ # * +status+ - match status (be sure it is in the list of OpenApply status)
103
+ # * +since_id+ - get all ids matching the criteria LARGER than the given number
104
+ # * +since_date+ - get all records updated after the given date (YYYY-MM-DD) or
105
+ # Date and Time (YYYY-MM-DD HH:MM:SS) - 24 hour clock (not sure about timeszone)
106
+ # * +count+ - return a custom number of records (no more than 1000)
107
+ #
108
+ # ==== Example Code
109
+ # @demo = Openapply.new
110
+ # @demo.custom_students_url(status='applied', since_id=96, since_date='2017-01-25', count=2)
111
+ #
112
+ # ==== Return Format
113
+ # "/api/v1/students/?status=applied&since_id=96&since_date=2017-01-25&count=2&auth_token=319d9axxxxxxx"
114
+ def students_custom_url(status=nil, since_id=nil, since_date=nil, count=api_records)
115
+ url_options = []
116
+ url_options << "status=#{status}" unless status.to_s.eql? ""
117
+ url_options << "since_id=#{since_id}" unless since_id.to_s.eql? ""
118
+ url_options << "since_date=#{since_date}" unless since_date.to_s.eql? ""
119
+ url_options << "count=#{count}"
120
+ url_options << "auth_token=#{api_key}"
121
+
122
+ return "#{api_path}?#{url_options.join('&')}"
123
+ end
124
+
125
+
126
+ # returns a list of student ids that match a give status (this is recursive -
127
+ # so returns the entire list - even if that list is longer than the api_return_count)
128
+ #
129
+ # ==== Attributes
130
+ # * +status+ - match status (be sure it is in the list of OpenApply status)
131
+ #
132
+ # ==== Example code
133
+ # @demo = Openapply.new
134
+ # @demo.student_ids_by_status('applied')
135
+ #
136
+ # ==== Return Format
137
+ # {:student_ids=>[95, 106, 240, ..., 582]}
138
+ def student_ids_by_status(status)
139
+ answer = students_by_status(status)
140
+ return { error: "nil answer" } if answer.nil?
141
+ return { error: "nil students" } if answer[:students].nil?
142
+ return { student_ids: [] } if answer[:students].empty?
143
+
144
+ ids = answer[:students].map{ |l| l[:id] }
145
+ return { student_ids: ids }
146
+ end
147
+ alias_method :all_student_ids_by_status, :student_ids_by_status
148
+
149
+
150
+ # returns a list of student summaries (in OpenApply's format) that
151
+ # match a give status (this is recursive - so returns the entire list -
152
+ # even if that list is longer than the api_return_count)
153
+ #
154
+ # ==== Attributes
155
+ # * +status+ - match status (be sure it is in the list of OpenApply status)
156
+ #
157
+ # ==== Return Format
158
+ # {:students=>
159
+ # [{:id=>95,
160
+ # :serial_number=>85,
161
+ # :custom_id=>"85",
162
+ # :applicant_id=>"00000085",
163
+ # :email=>"Richard.Washington@eduvo.com",
164
+ # :first_name=>"Richard",
165
+ # :last_name=>"Washington",
166
+ # :name=>"Richard Washington",
167
+ # ...,
168
+ # :parent_ids=>[492, 493]},
169
+ # {:id=>106,
170
+ # :serial_number=>90,
171
+ # :custom_id=>"90",
172
+ # :applicant_id=>"00000090",
173
+ # :email=>"Henry.Epelbaum@eduvo.com",
174
+ # :first_name=>"Samuel",
175
+ # :last_name=>"Epelbaum",
176
+ # ...,
177
+ # :parent_ids=>[265, 266]}],
178
+ # :linked=>
179
+ # {:parents=>
180
+ # [{:id=>492,
181
+ # :serial_number=>nil,
182
+ # :custom_id=>nil,
183
+ # :name=>"Philippa Washington",
184
+ # :first_name=>"Philippa",
185
+ # :last_name=>"Washington",
186
+ # ...,
187
+ # :custom_fields=>
188
+ # {:title=>nil,
189
+ # :treat_parent_as_emergency_contact=>nil,
190
+ # :mobile_phone=>"852 6712 1196",
191
+ # :home_telephone=>"+852 9954 1179",
192
+ # ...,
193
+ # :parent_residency=>nil}},
194
+ # {:id=>493,
195
+ # :serial_number=>nil,
196
+ # :custom_id=>nil,
197
+ # :name=>"Fred Washington",
198
+ # :first_name=>"Fred",
199
+ # :last_name=>"Washington",
200
+ # ...,
201
+ # :address=>"High Street 110",
202
+ # :address_ii=>nil,
203
+ # :city=>"Hong Kong",
204
+ # :state=>nil,
205
+ # :postal_code=>nil,
206
+ # :country=>"Hong Kong",
207
+ # :email=>"fredw@eduvo.com",
208
+ # :parent_role=>"Father",
209
+ # :updated_at=>"2017-07-11T14:46:48.000+08:00",
210
+ # ...,
211
+ # :custom_fields=>
212
+ # {:title=>nil,
213
+ # :treat_parent_as_emergency_contact=>nil,
214
+ # :mobile_phone=>"+852 9954 1179",
215
+ # :home_telephone=>"+852 9954 1179",
216
+ # ...,
217
+ # :parent_residency=>nil}}]},
218
+ # :meta=>{:pages=>1, :per_page=>"100"}}
219
+ def students_by_status(status)
220
+ url = students_custom_url(status)
221
+ answer = oa_answer( url )
222
+ return { error: "no students found" } if answer[:students].nil?
223
+ return { students: [] } if answer[:students].empty?
224
+
225
+ page_number = answer[:meta][:pages]
226
+ return answer if page_number == 1
227
+
228
+ # inspect meta data -- loop until page = 1
229
+ all_students = answer[:students]
230
+ while page_number > 1
231
+ last_student = answer[:students].last
232
+ since_id = last_student[:id]
233
+ url = students_custom_url(status,since_id)
234
+ answer = oa_answer( url )
235
+ page_number = answer[:meta][:pages]
236
+ all_students += answer[:students]
237
+ end
238
+ return { students: all_students }
239
+ end
240
+ # alias_method :all_student_summaries_by_status, :students_by_status
241
+ alias_method :students, :students_by_status
242
+
243
+
244
+ # returns a list of student with all details (gaurdians & payments) that
245
+ # match a give status (this is recursive - so returns the entire list - even
246
+ # if that list is longer than the api_return_count)
247
+ #
248
+ # ==== Attributes
249
+ # * +status+ - match status (be sure it is in the list of OpenApply status)
250
+ #
251
+ # ==== Return Format
252
+ # {students: [
253
+ # {
254
+ # id=95,
255
+ # record: {},
256
+ # guardians: [],
257
+ # payments: []
258
+ # },
259
+ # {
260
+ # id=487,
261
+ # record: {},
262
+ # guardians: [],
263
+ # payments: []
264
+ # }
265
+ # ]}
266
+ # for example:
267
+ # :students=>
268
+ # [{:id=>"95",
269
+ # :record=>
270
+ # {:id=>95,
271
+ # :serial_number=>85,
272
+ # ...,
273
+ # :custom_fields=>
274
+ # {:language=>"English",
275
+ # :nationality=>"American (United States)",
276
+ # :referral_source=>"Friends",
277
+ # ...,
278
+ # :siblings_information=>
279
+ # [{:first_name=>"Jerry",
280
+ # :last_name=>"Washington",
281
+ # :gender=>"Male",
282
+ # :birth_date=>"2008-06-04"}],
283
+ # :emergency_contact=>[],
284
+ # :immunization_record=>[],
285
+ # :health_information=>[]},
286
+ # :parent_ids=>[492, 493]},
287
+ # :payments=>[],
288
+ # :guardians=>
289
+ # [{:id=>492,
290
+ # :serial_number=>nil,
291
+ # :custom_id=>nil,
292
+ # :name=>"Philippa Washington",
293
+ # :first_name=>"Philippa",
294
+ # :last_name=>"Washington",
295
+ # ...,
296
+ # :custom_fields=>
297
+ # {:title=>nil,
298
+ # :treat_parent_as_emergency_contact=>nil,
299
+ # :mobile_phone=>"852 6712 1196",
300
+ # :home_telephone=>"+852 9954 1179",
301
+ # ...,
302
+ # :parent_residency=>nil}},
303
+ # {:id=>493,
304
+ # :serial_number=>nil,
305
+ # :custom_id=>nil,
306
+ # :name=>"Fred Washington",
307
+ # :first_name=>"Fred",
308
+ # :last_name=>"Washington",
309
+ # ...,
310
+ # :custom_fields=>
311
+ # {:title=>nil,
312
+ # :treat_parent_as_emergency_contact=>nil,
313
+ # :mobile_phone=>"+852 9954 1179",
314
+ # :home_telephone=>"+852 9954 1179",
315
+ # ...,
316
+ # :parent_residency=>nil}}]},
317
+ # { ... },
318
+ # {:id=>"582",
319
+ # :record=>
320
+ # {:id=>582,
321
+ # :serial_number=>437,
322
+ # :custom_id=>nil,
323
+ # :applicant_id=>"00000437",
324
+ # :email=>"s3@example.com",
325
+ # :first_name=>"Ada",
326
+ # :last_name=>"Junior",
327
+ # ...,
328
+ # :profile_photo=>
329
+ # "https://openapply-sandbox-devel-01.s3.amazonaws.com/uploads/student/avatar/000/000/582/boy-01.jpg?v=1500883583",
330
+ # :profile_photo_updated_at=>"2017-07-24T16:06:23.000+08:00",
331
+ # :custom_fields=>
332
+ # {:language=>nil,
333
+ # :nationality=>nil,
334
+ # :referral_source=>nil,
335
+ # ...,
336
+ # :prior_school_list=>[],
337
+ # :immunization_record=>[],
338
+ # :health_information=>[]},
339
+ # :parent_ids=>[]},
340
+ # :payments=>[],
341
+ # :guardians=>[]}]}
342
+ def students_details_by_status(status)
343
+ ids = all_student_ids_by_status(status)
344
+ return { error: 'answer nil' } if ids.nil?
345
+ return { error: 'ids nil' } if ids[:student_ids].nil?
346
+ return { error: 'ids empty' } if ids[:student_ids].empty?
347
+
348
+ # loop through each student
349
+ error_ids = []
350
+ student_records = []
351
+ ids[:student_ids].each do |id|
352
+ # get each kids details w_billing
353
+ student = student_details_by_id( "#{id}" )
354
+
355
+ error_ids << id if student.nil? or
356
+ student[:student].nil? or
357
+ student[:student].empty?
358
+ student_records << student[:student] unless student.nil? or
359
+ student[:student].nil? or
360
+ student[:student].empty?
361
+ end
362
+
363
+ return { students: [], error_ids: error_ids } if student_records.empty?
364
+ return { students: student_records }
365
+ end
366
+ # alias_method :all_student_records_w_billing_by_status, :students_details_by_status
367
+ # alias_method :all_students_all_data_by_status, :students_details_by_status
368
+ alias_method :students_details, :students_details_by_status
369
+
370
+ def students_details_as_csv_by_status(status,keys)
371
+ # some code
372
+ end
373
+
374
+ # # TODO: build queries that collects changed by date
375
+ # # get summary info with a status (useful to get ids - no custom_fields)
376
+ # def students_by_since_id(since_id, status = nil, date = nil)
377
+ # url = "#{@api_path}?count=#{api_records}&auth_token=#{@api_key}"
378
+ # elsif date.nil? or date == ""
379
+ # url = "#{@api_path}?status=#{status}&count=#{api_records}&auth_token=#{@api_key}"
380
+ # else
381
+ # url = "#{@api_path}?status=#{status}&since_date=#{date}&count=#{api_records}&auth_token=#{@api_key}"
382
+ # end
383
+ # return oa_answer( url, options )
384
+ # end
385
+ #
386
+ #
387
+ # # TODO: build queries that collects changed by date
388
+ # # get summary info with a status (useful to get ids - no custom_fields)
389
+ # def student_summaries_by_since_date(since_date, since_id = nil, status = nil)
390
+ # url = "#{@api_path}?count=#{api_records}&auth_token=#{@api_key}"
391
+ # elsif since_date.nil? or since_date == ""
392
+ # url = "#{@api_path}?status=#{status}&count=#{api_records}&auth_token=#{@api_key}"
393
+ # else
394
+ # url = "#{@api_path}?status=#{status}&since_date=#{since_date}&count=#{@api_records}&auth_token=#{@api_key}"
395
+ # end
396
+ # return oa_answer( url, options )
397
+ # end
398
+
399
+ end
@@ -0,0 +1,3 @@
1
+ module Put
2
+
3
+ end
@@ -0,0 +1,3 @@
1
+ module Openapply
2
+ VERSION = "0.2.0"
3
+ end
data/lib/openapply.rb ADDED
@@ -0,0 +1,125 @@
1
+ require "openapply/get_students"
2
+ require "openapply/get_student"
3
+ require "openapply/version"
4
+ require "openapply/put"
5
+ require 'httparty'
6
+
7
+ module Openapply
8
+
9
+ # OpenApply is a service to manage admissions -
10
+ # this gem allows access to OpenApply API calls via HTTParty
11
+ #
12
+ class Client
13
+
14
+ # Contains the GET api calls
15
+ include Get
16
+ # Contains the PUT api calls
17
+ include Put
18
+ # Library to make the API calls with OpenApply
19
+ include HTTParty
20
+
21
+ # Defines OpenApply domain name from ENV-VARS
22
+ API_URL = (ENV['OA_BASE_URI'] || 'demo.openapply.com')
23
+
24
+ # Defines the OpenApply path from ENV-VARS - default is 5 seconds
25
+ API_TIMEOUT = (ENV['OA_TIMEOUT'].to_i || 5)
26
+
27
+ base_uri API_URL
28
+ default_timeout API_TIMEOUT
29
+
30
+ # Defines OpenApply domain name from ENV-VARS - for example:
31
+ # demo.openapply.com
32
+ def api_url
33
+ API_URL
34
+ end
35
+
36
+ # Defines http timeout from ENV-VARS - 5 sec is the default
37
+ def api_reply_count
38
+ API_TIMEOUT
39
+ end
40
+ alias_method :api_timeout, :api_reply_count
41
+
42
+ # Defines OpenApply secret access key with ENV-VARS
43
+ def api_key
44
+ ENV['OA_AUTH_TOKEN'] || 'demo_site_api_key'
45
+ end
46
+
47
+ # Defines the OpenApply path with ENV-VARS - default is for api_v1
48
+ # /api/v1/students/
49
+ def api_path
50
+ ENV['OA_API_PATH'] || "/api/v1/students/"
51
+ end
52
+ # alias_method :base_path, :api_path
53
+
54
+ # Defines the maximum records OpenApply should return with each api call
55
+ # with ENV-VARS - (code default is 100 - OpenApply default is 10)
56
+ def api_records
57
+ ENV['OA_REPLY_RECORDS'] || '100'
58
+ end
59
+ # alias_method :record_count, :api_max_records
60
+
61
+ # Handles httparty timeout errors - tries 3x before quitting
62
+ # https://stackoverflow.com/questions/26251422/handling-netreadtimeout-error-in-httparty
63
+ # TODO: figure out how to test time outs
64
+ def handle_timeouts
65
+ max_retries = 3
66
+ times_retried = 0
67
+ begin
68
+ yield
69
+ rescue Net::ReadTimeout => error
70
+ if times_retried < max_retries
71
+ times_retried += 1
72
+ # puts "TIMEOUT RETRY: #{times_retried} of #{max_retries} - USING: #{yield.inspect}"
73
+ retry
74
+ else
75
+ # puts "TIME-OUT URI FAILED: #{yield.inspect}"
76
+ { error: "SITE TIMEOUT - 3 FAILURES USING: #{yield.inspect}" }
77
+ end
78
+ end
79
+ end
80
+
81
+ # Does the actual api call to OpenApply
82
+ #
83
+ # ==== Attributes
84
+ # * +url+ - this is the url to do the call
85
+ # /api/v1/students/95?auth_token=demo_site_api_key
86
+ # is the url passed when wanting to do the following cli api call
87
+ # curl http://demo.openapply.com/api/v1/students/95?auth_token=demo_site_api_key
88
+ # * +options+ - see httparty options [http://www.rubydoc.info/github/jnunemaker/httparty]
89
+ def oa_api_call(url, options={})
90
+ self.class.get(url, options)
91
+ end
92
+
93
+ # Does checks the info for validity & unpacks the json retubed to a JS formatt
94
+ #
95
+ # ==== Attributes
96
+ # * +url+ - this is the url to do the call
97
+ # /api/v1/students/95?auth_token=demo_site_api_key
98
+ # is the url passed when wanting to do the following cli api call
99
+ # curl http://demo.openapply.com/api/v1/students/95?auth_token=demo_site_api_key
100
+ # * +options+ - see httparty options [http://www.rubydoc.info/github/jnunemaker/httparty]
101
+ def oa_answer(url, options={})
102
+ # puts
103
+ # puts "GIVEN URL: #{ url.inspect }"
104
+ return { error: 'no url given' } if url.nil? or url.to_s.eql? ""
105
+ return { error: 'bad url - has space' } if url.include? " "
106
+ return { error: 'bad api_path' } unless url.include? "#{api_path}"
107
+ return { error: 'bad auth_token' } unless url.include? "auth_token=#{api_key}"
108
+ api_answer = nil
109
+
110
+ handle_timeouts do
111
+ api_answer = oa_api_call(url, options)
112
+ end
113
+
114
+ # puts "API ANSWER: #{api_answer}"
115
+ # puts "API ANSWER: #{api_answer.inspect}"
116
+ return { error: 'no response' } unless api_answer.respond_to? "response"
117
+ return { error: 'no response' } if api_answer.response.nil?
118
+ return { error: 'no response' } if api_answer.response.to_s.eql? ""
119
+ return JSON.parse(api_answer.response.body, symbolize_names: true)
120
+ end
121
+ # alias_method :openapply_answer, :oa_answer
122
+
123
+ end # Client
124
+
125
+ end # Openapply
data/openapply.gemspec ADDED
@@ -0,0 +1,48 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "openapply/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "openapply"
8
+ spec.version = Openapply::VERSION
9
+ spec.authors = ["Bill Tihen"]
10
+ spec.email = ["btihen@gmail.com"]
11
+
12
+ spec.summary = %q{Access OpenApply's API with Ruby}
13
+ # spec.description = %q{TODO: Write a longer description or delete this line.}
14
+ spec.homepage = "https://github.com/btihen/openapply"
15
+ spec.license = "MIT"
16
+
17
+ # # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata["allowed_push_host"] = "http://rubygems.org"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against " \
23
+ # "public gem pushes."
24
+ # end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_dependency "httparty", "~> 0.15"
34
+ spec.add_dependency "json" , "~> 2.1"
35
+
36
+ spec.add_development_dependency "webmock" , "~> 3.1"
37
+ spec.add_development_dependency "bundler", "~> 1.15"
38
+ spec.add_development_dependency "rake", "~> 10.0"
39
+ spec.add_development_dependency "rspec", "~> 3.7"
40
+ # spec.add_development_dependency "rspec", "~> 3.0"
41
+ spec.add_development_dependency "simplecov", "~> 0.15"
42
+ # spec.add_development_dependency "rspec-nc", "~> 3.0"
43
+ # spec.add_development_dependency "guard", "~> 2.14"
44
+ # spec.add_development_dependency "guard-rspec", "~> 4.7"
45
+ # spec.add_development_dependency "pry", "~> 0.11"
46
+ # spec.add_development_dependency "pry-remote", "~> 0.1"
47
+ # spec.add_development_dependency "pry-nav", "~> 0.2"
48
+ end