survey-gizmo-ruby 1.0.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,82 @@
1
+ # This class normalizes the response returned by Survey Gizmo
2
+ class RestResponse
3
+ attr_accessor :raw_response
4
+ attr_accessor :parsed_response
5
+
6
+ def initialize(rest_response)
7
+ @raw_response = rest_response
8
+ @parsed_response = rest_response.parsed_response
9
+ return unless data
10
+
11
+ # Handle really crappy [] notation in SG API, so far just in SurveyResponse
12
+ (data.is_a?(Array) ? data : [data]).each do |datum|
13
+ datum.keys.grep(/^\[/).each do |key|
14
+ next if datum[key].nil? || datum[key].length == 0
15
+
16
+ parent = find_attribute_parent(key)
17
+ datum[parent] ||= {}
18
+
19
+ case key.downcase
20
+ when /(url|variable.*standard)/
21
+ datum[parent][cleanup_attribute_name(key).to_sym] = datum[key]
22
+ when /variable.*shown/
23
+ datum[parent][cleanup_attribute_name(key).to_i] = datum[key].include?('1')
24
+ when /variable/
25
+ datum[parent][cleanup_attribute_name(key).to_i] = datum[key].to_i
26
+ when /question/
27
+ datum[parent][key] = datum[key]
28
+ end
29
+
30
+ datum.delete(key)
31
+ end
32
+ end
33
+ end
34
+
35
+ def ok?
36
+ if ENV['GIZMO_DEBUG']
37
+ ap 'SG Response: '
38
+ ap @parsed_response
39
+ end
40
+
41
+ if @parsed_response['result_ok'] && @parsed_response['result_ok'].to_s.downcase == 'false' && @parsed_response['message'] && @parsed_response['code'] && @parsed_response['message'] =~ /service/i
42
+ raise Exception, "#{@parsed_response['message']}: #{@parsed_response['code']}"
43
+ end
44
+ @parsed_response['result_ok'] && @parsed_response['result_ok'].to_s.downcase == 'true'
45
+ end
46
+
47
+ # The parsed JSON data of the response
48
+ def data
49
+ @_data ||= @parsed_response['data'] #|| {'id' => @parsed_response['id']}
50
+ end
51
+
52
+ # The error message if there is one
53
+ def message
54
+ @_message ||= @parsed_response['message']
55
+ end
56
+
57
+
58
+ private
59
+
60
+ def cleanup_attribute_name(attr)
61
+ attr.downcase.gsub(/[^[:alnum:]]+/, '_')
62
+ .gsub(/(url|variable|standard|shown)/, '')
63
+ .gsub(/_+/, '_')
64
+ .gsub(/^_/, '')
65
+ .gsub(/_$/, '')
66
+ end
67
+
68
+ def find_attribute_parent(attr)
69
+ case attr.downcase
70
+ when /url/
71
+ 'url'
72
+ when /variable.*standard/
73
+ 'meta'
74
+ when /variable.*shown/
75
+ 'shown'
76
+ when /variable/
77
+ 'variable'
78
+ when /question/
79
+ 'answers'
80
+ end
81
+ end
82
+ end
@@ -1,23 +1,24 @@
1
- require "active_support/core_ext/string"
2
- require "active_support/core_ext/module"
3
- require "active_support/core_ext/hash"
4
- require "active_support/core_ext/object/blank"
5
- require "active_support/concern"
6
- require "virtus"
7
- require "httparty"
8
- require "digest/md5"
9
-
10
- require "survey_gizmo/resource"
11
- require "survey_gizmo/collection"
12
-
13
- require "survey_gizmo/api/survey"
14
- require "survey_gizmo/api/survey_campaign"
15
- require "survey_gizmo/api/question"
16
- require "survey_gizmo/api/option"
17
- require "survey_gizmo/api/page"
18
- require "survey_gizmo/api/contact"
19
- require "survey_gizmo/api/response"
20
- require "survey_gizmo/api/email_message"
1
+ require 'active_support/core_ext/string'
2
+ require 'active_support/core_ext/module'
3
+ require 'active_support/core_ext/hash'
4
+ require 'active_support/core_ext/object/blank'
5
+ require 'active_support/concern'
6
+ require 'awesome_print'
7
+ require 'virtus'
8
+ require 'httparty'
9
+ require 'digest/md5'
10
+
11
+ require 'survey_gizmo/resource'
12
+ require 'survey_gizmo/rest_response'
13
+
14
+ require 'survey_gizmo/api/survey'
15
+ require 'survey_gizmo/api/survey_campaign'
16
+ require 'survey_gizmo/api/question'
17
+ require 'survey_gizmo/api/option'
18
+ require 'survey_gizmo/api/page'
19
+ require 'survey_gizmo/api/contact'
20
+ require 'survey_gizmo/api/response'
21
+ require 'survey_gizmo/api/email_message'
21
22
 
22
23
  module SurveyGizmo
23
24
  include HTTParty
@@ -42,7 +43,11 @@ module SurveyGizmo
42
43
  # The account password
43
44
  def self.setup(opts = {})
44
45
  self.options = opts
45
- default_params({ "user:md5" => "#{opts[:user]}:#{Digest::MD5.hexdigest(opts[:password])}" })
46
+ default_params({ 'user:md5' => "#{opts[:user]}:#{Digest::MD5.hexdigest(opts[:password])}" })
46
47
  end
47
48
 
48
- end
49
+ def self.reset
50
+ @@options = {}
51
+ default_params({})
52
+ end
53
+ end
@@ -1,56 +1,61 @@
1
- require "spec_helper"
2
- describe "Survey Gizmo Resource" do
1
+ require 'spec_helper'
2
+ describe 'Survey Gizmo Resource' do
3
3
 
4
4
  describe SurveyGizmo::Resource do
5
5
  before(:each) do
6
- SurveyGizmo.setup(:user => 'test@test.com', :password => 'password')
6
+ SurveyGizmo.setup(user: 'test@test.com', password: 'password')
7
7
  end
8
8
 
9
- let(:described_class) { SurveyGizmoSpec::ResourceTest }
10
-
11
- let(:create_attributes){ {:title => 'Spec', :test_id => 5} }
12
- let(:get_attributes) { create_attributes.merge(:id => 1) }
13
- let(:update_attributes){ {:title => 'Updated'} }
14
- let(:first_params){ {:id => 1, :test_id => 5} }
9
+ let(:described_class) { SurveyGizmoSpec::ResourceTest }
10
+ let(:create_attributes) { {title: 'Spec', test_id: 5} }
11
+ let(:update_attributes) { {title: 'Updated'} }
12
+ let(:first_params) { {id: 1, test_id: 5} }
13
+ let(:get_attributes) { create_attributes.merge(id: 1) }
15
14
  let(:uri_paths){
16
15
  {
17
- :get => '/test/1',
18
- :create => '/test/5/resource',
19
- :update => '/test/5/resource/1',
20
- :delete => '/test/5/resource/1'
16
+ get: '/test/1',
17
+ create: '/test/5/resource',
18
+ update: '/test/5/resource/1',
19
+ delete: '/test/5/resource/1'
21
20
  }
22
21
  }
23
22
 
24
- it "#new?" do
25
- described_class.new.should be_new
26
- end
27
-
28
-
29
23
  it '#reload' do
30
24
  stub_request(:get, /#{@base}/).to_return(json_response(true, get_attributes))
31
25
  obj = described_class.new(get_attributes.merge(update_attributes))
32
- obj.attributes.reject{|k,v| v.blank? }.should == get_attributes.merge(update_attributes)
26
+ obj.attributes.reject {|k,v| v.blank? }.should == get_attributes.merge(update_attributes)
33
27
  obj.reload
34
- obj.attributes.reject{|k,v| v.blank? }.should == get_attributes
28
+ obj.attributes.reject {|k,v| v.blank? }.should == get_attributes
35
29
  end
36
30
 
37
- it '#valid?'
38
-
39
- it "should raise an error if params are missing" do
31
+ it 'should raise an error if params are missing' do
40
32
  lambda {
41
- SurveyGizmoSpec::ResourceTest.destroy(:test_id => 5)
42
- }.should raise_error(SurveyGizmo::URLError, 'Missing parameters in request: `:id`')
33
+ SurveyGizmoSpec::ResourceTest.destroy(test_id: 5)
34
+ }.should raise_error(SurveyGizmo::URLError, 'Missing RESTful parameters in request: `:id`')
43
35
  end
44
36
 
45
37
  it_should_behave_like 'an API object'
46
38
  it_should_behave_like 'an object with errors'
39
+
40
+ context '#convert_filters_into_query_string' do
41
+ let(:page) { 2 }
42
+ let(:filters) { {page: page, filters: [{field: 'istestdata', operator: '<>', value: 1}] }}
43
+
44
+ it 'should generate the correct page request' do
45
+ expect(SurveyGizmoSpec::ResourceTest.convert_filters_into_query_string(page: page)).to eq("?page=#{page}")
46
+ end
47
+
48
+ it 'should generate the correct filter fragment' do
49
+ expect(SurveyGizmoSpec::ResourceTest.convert_filters_into_query_string(filters)).to eq("?filter%5Bfield%5D%5B0%5D=istestdata&filter%5Boperator%5D%5B0%5D=%3C%3E&filter%5Bvalue%5D%5B0%5D=1&page=#{page}")
50
+ end
51
+ end
47
52
  end
48
53
 
49
54
  describe SurveyGizmo::API::Survey do
50
- let(:create_attributes){ {:title => 'Spec', :type => 'survey', :status => 'In Design'} }
51
- let(:get_attributes) { create_attributes.merge(:id => 1234) }
52
- let(:update_attributes){ {:title => 'Updated'} }
53
- let(:first_params){ {:id => 1234} }
55
+ let(:create_attributes) { { title: 'Spec', type: 'survey', status: 'In Design' } }
56
+ let(:get_attributes) { create_attributes.merge(first_params) }
57
+ let(:update_attributes) { { title: 'Updated'} }
58
+ let(:first_params) { { id: 1234} }
54
59
  let(:uri_paths){
55
60
  h = { :create => '/survey' }
56
61
  h.default = '/survey/1234'
@@ -59,16 +64,20 @@ describe "Survey Gizmo Resource" do
59
64
 
60
65
  it_should_behave_like 'an API object'
61
66
  it_should_behave_like 'an object with errors'
67
+
68
+ it 'should parse the number of completed records correctly' do
69
+ survey = described_class.new('statistics' => [['Partial', 2], ['Disqualified', 28], ['Complete', 15]])
70
+ expect(survey.number_of_completed_responses).to eq(15)
71
+ end
62
72
  end
63
73
 
64
74
  describe SurveyGizmo::API::Question do
65
- let(:create_attributes){ {:survey_id => 1234, :page_id => 1, :title => 'Spec Question', :type => 'radio', :properties => {"required" => true, "option_sort" => false} } }
66
- let(:get_attributes) {
67
- create_attributes.merge(:id => 1)
68
- }
69
- let(:update_attributes){ {:survey_id => 1234, :page_id => 1, :title => 'Updated'} }
70
- let(:first_params){ {:id => 1, :survey_id => 1234, :page_id => 1} }
71
- let(:uri_paths){
75
+ let(:base_params) { {survey_id: 1234, page_id: 1} }
76
+ let(:create_attributes) { base_params.merge(title: 'Spec Question', type: 'radio', properties: {'required' => true, 'option_sort' => false}) }
77
+ let(:update_attributes) { base_params.merge(title: 'Updated') }
78
+ let(:first_params) { base_params.merge(id: 1) }
79
+ let(:get_attributes) { create_attributes.merge(id: 1) }
80
+ let(:uri_paths) {
72
81
  { :get => '/survey/1234/surveyquestion/1',
73
82
  :create => '/survey/1234/surveypage/1/surveyquestion',
74
83
  :update => '/survey/1234/surveypage/1/surveyquestion/1',
@@ -79,25 +88,44 @@ describe "Survey Gizmo Resource" do
79
88
  it_should_behave_like 'an API object'
80
89
  it_should_behave_like 'an object with errors'
81
90
 
82
- it "should handle the title hash returned from the API" do
83
- @question = described_class.new('title' => {'English' => 'Some title'})
84
- @question.title.should == 'Some title'
91
+ it 'should handle the title hash returned from the API' do
92
+ expect(described_class.new('title' => {'English' => 'Some title'}).title).to eq('Some title')
93
+ end
94
+
95
+ it 'should handle the _subtype key' do
96
+ described_class.new(:_subtype => 'radio').type.should == 'radio'
85
97
  end
86
98
 
87
- it "should handle the _subtype key" do
88
- @question = described_class.new(:_subtype => 'radio')
89
- @question.type.should == 'radio'
99
+ it 'should have no subquestions' do
100
+ expect(described_class.new().sub_questions).to eq([])
101
+ end
102
+
103
+ it 'should find the survey' do
104
+ stub_request(:get, /#{@base}\/survey\/1234/).to_return(json_response(true, get_attributes))
105
+ described_class.new(base_params).survey
106
+ a_request(:get, /#{@base}\/survey\/1234/).should have_been_made
107
+ end
108
+
109
+ context 'with subquestions' do
110
+ let(:parent_id) { 33 }
111
+ let(:question_with_subquestions) { described_class.new(id: parent_id, survey_id: 1234, sub_question_skus: [1, 2])}
112
+ it 'should have 2 subquestions and they should have the right parent question' do
113
+ stub_request(:get, /#{@base}/).to_return(json_response(true, get_attributes))
114
+ expect(question_with_subquestions.sub_questions.size).to eq(2)
115
+
116
+ question_with_subquestions.sub_questions.first.parent_question
117
+ a_request(:get, /#{@base}\/survey\/1234\/surveyquestion\/#{parent_id}/).should have_been_made
118
+ end
90
119
  end
91
120
  end
92
121
 
93
122
  describe SurveyGizmo::API::Option do
94
- let(:create_attributes){ {:survey_id => 1234, :page_id => 1, :question_id => 1, :title => 'Spec Question', :value => 'Spec Answer'} }
95
- let(:get_attributes) {
96
- create_attributes.merge(:id => 1)
97
- }
98
- let(:update_attributes){ {:survey_id => 1234, :page_id => 1, :question_id => 1, :title => 'Updated'} }
99
- let(:first_params){ {:id => 1, :survey_id => 1234, :page_id => 1, :question_id => 1} }
100
- let(:uri_paths){
123
+ let(:survey_and_page) { {survey_id: 1234, page_id: 1} }
124
+ let(:create_attributes) { survey_and_page.merge(question_id: 1, title: 'Spec Question', value: 'Spec Answer') }
125
+ let(:update_attributes) { survey_and_page.merge(question_id: 1, title: 'Updated') }
126
+ let(:first_params) { survey_and_page.merge(id: 1, question_id: 1) }
127
+ let(:get_attributes) { create_attributes.merge(id: 1) }
128
+ let(:uri_paths) {
101
129
  h = { :create => '/survey/1234/surveypage/1/surveyquestion/1/surveyoption' }
102
130
  h.default = '/survey/1234/surveypage/1/surveyquestion/1/surveyoption/1'
103
131
  h
@@ -108,12 +136,10 @@ describe "Survey Gizmo Resource" do
108
136
  end
109
137
 
110
138
  describe SurveyGizmo::API::Page do
111
- let(:create_attributes){ {:survey_id => 1234, :title => {'English' => 'Spec Page'}} }
112
- let(:get_attributes) {
113
- create_attributes.merge(:id => 1)
114
- }
115
- let(:update_attributes){ {:survey_id => 1234, :title => 'Updated'} }
116
- let(:first_params){ {:id => 1, :survey_id => 1234 } }
139
+ let(:create_attributes) { {:survey_id => 1234, :title => {'English' => 'Spec Page'}} }
140
+ let(:get_attributes) { create_attributes.merge(:id => 1) }
141
+ let(:update_attributes) { {:survey_id => 1234, :title => 'Updated'} }
142
+ let(:first_params) { {:id => 1, :survey_id => 1234 } }
117
143
  let(:uri_paths){
118
144
  h = { :create => '/survey/1234/surveypage' }
119
145
  h.default = '/survey/1234/surveypage/1'
@@ -5,13 +5,16 @@ module SurveyGizmoSpec
5
5
  end
6
6
 
7
7
  def request_params(opts = {})
8
- {"user:pass" => 'test@test.com:password'}.merge(opts)
8
+ {'user:pass' => 'test@test.com:password'}.merge(opts)
9
9
  end
10
10
 
11
11
  def json_response(result, data)
12
- body = {:result_ok => result}
13
- result ? body.merge!(:data => data) : body.merge!(:message => data)
14
- {:headers => {'Content-Type' => 'application/json'}, :body => body.to_json}
12
+ body = {result_ok: result}
13
+ result ? body.merge!(data: data) : body.merge!(message: data)
14
+ {
15
+ headers: {'Content-Type' => 'application/json'},
16
+ body: body.to_json
17
+ }
15
18
  end
16
19
  end
17
20
  end
@@ -1,126 +1,81 @@
1
1
  shared_examples_for 'an API object' do
2
- before(:each) do
3
- SurveyGizmo.setup(:user => 'test@test.com', :password => 'password')
2
+ before(:all) do
3
+ SurveyGizmo.setup(user: 'test@test.com', password: 'password')
4
4
  end
5
-
5
+
6
6
  it "should be descendant of SurveyGizmo::Resource" do
7
7
  SurveyGizmo::Resource.descendants.should include(described_class)
8
8
  end
9
-
10
-
9
+
11
10
  context "#create" do
12
11
  it "should make a request" do
13
12
  stub_api_call(:put)
14
13
  described_class.create(create_attributes)
15
14
  a_request(:put, /#{@base}#{uri_paths[:create]}/).should have_been_made
16
15
  end
17
-
16
+
18
17
  it "should return a new instance" do
19
18
  stub_api_call(:put)
20
19
  obj = described_class.create(create_attributes)
21
20
  obj.should be_instance_of(described_class)
22
21
  end
23
-
22
+
24
23
  it "should set the attributes" do
25
24
  stub_request(:put, /#{@base}/).to_return(json_response(true, create_attributes))
26
25
  obj = described_class.create(create_attributes)
27
26
  obj.attributes.reject{|k,v| v.blank? }.should == create_attributes
28
27
  end
29
28
  end
30
-
29
+
31
30
  context "#get" do
32
31
  it "should make a request" do
33
32
  stub_request(:get, /#{@base}/).to_return(json_response(true, get_attributes))
34
33
  described_class.first(first_params)
35
34
  a_request(:get, /#{@base}#{uri_paths[:get]}/).should have_been_made
36
35
  end
37
-
36
+
38
37
  it "should set the attributes" do
39
38
  stub_request(:get, /#{@base}/).to_return(json_response(true, get_attributes))
40
39
  obj = described_class.first(first_params)
41
40
  obj.attributes.reject{|k,v| v.blank? }.should == get_attributes
42
41
  end
43
-
42
+
44
43
  it "should return false if the request fails" do
45
44
  stub_request(:get, /#{@base}/).to_return(json_response(false, "something is wrong"))
46
45
  described_class.first(first_params).should == nil
47
46
  end
48
47
  end
49
-
50
- context "instance#update" do
51
- before(:each) do
52
- @obj = described_class.new(get_attributes)
53
- @obj.__send__(:clean!)
54
- end
55
-
56
- it "should make a request" do
57
- stub_api_call(:post)
58
- @obj.update
59
- a_request(:post, /#{@base}#{uri_paths[:update]}/).should have_been_made
60
- end
61
-
62
- it 'should change object state to saved' do
63
- stub_api_call(:post)
64
- @obj.update(update_attributes)
65
- @obj.should be_saved
66
- end
67
-
68
- it "should not be marked saved if the request fails" do
69
- stub_api_call(:post, false)
70
- @obj.update
71
- @obj.should_not be_saved
72
- end
73
-
74
- xit "cannot be updated if new" do
75
- @obj.instance_variable_set('@_state', nil)
76
- @obj.update(update_attributes).should be_false
77
- end
78
-
79
- end
80
-
48
+
81
49
  context "instance#destroy" do
82
50
  before(:each) do
83
51
  @obj = described_class.new(get_attributes)
84
- @obj.__send__(:clean!)
85
52
  end
86
-
53
+
87
54
  it "should make a request" do
88
55
  stub_api_call(:delete)
89
56
  @obj.destroy
90
57
  a_request(:delete, /#{@base}#{uri_paths[:delete]}/).should have_been_made
91
58
  end
92
-
93
- it 'should change object state to destroyed' do
94
- stub_api_call(:delete)
95
- @obj.destroy
96
- @obj.should be_destroyed
97
- end
98
-
99
- it "should not be marked destroyed if the request fails" do
100
- stub_api_call(:delete, false)
101
- @obj.destroy
102
- @obj.should_not be_destroyed
103
- end
104
-
59
+
105
60
  it "cannot be destroyed if new" do
106
- @obj.instance_variable_set('@_state', nil)
61
+ @obj.id = nil
107
62
  @obj.destroy.should be_false
108
63
  end
109
64
  end
110
-
65
+
111
66
  context '#destroy', :focused => true do
112
67
  it "should make a request" do
113
68
  stub_api_call(:delete)
114
69
  described_class.destroy(first_params)
115
70
  a_request(:delete, /#{@base}#{uri_paths[:delete]}/).should have_been_made
116
71
  end
117
-
72
+
118
73
  it "should return result" do
119
74
  stub_api_call(:delete)
120
75
  described_class.destroy(first_params).should be_true
121
76
  end
122
77
  end
123
-
78
+
124
79
  context 'instance#save' do
125
80
  it "should call create on a new resource" do
126
81
  stub_api_call(:put)
@@ -128,16 +83,15 @@ shared_examples_for 'an API object' do
128
83
  obj.save
129
84
  a_request(:put, /#{@base}#{uri_paths[:create]}/).should have_been_made
130
85
  end
131
-
86
+
132
87
  it "should call update on a created resource" do
133
88
  obj = described_class.new(get_attributes)
134
- obj.__send__(:clean!)
135
89
  stub_api_call(:post)
136
90
  obj.save
137
91
  a_request(:post, /#{@base}#{uri_paths[:update]}/).should have_been_made
138
92
  end
139
93
  end
140
-
94
+
141
95
  context '#all' do
142
96
  before(:all) do
143
97
  @array = [
@@ -146,30 +100,30 @@ shared_examples_for 'an API object' do
146
100
  {:id => 3, :title => 'resource 3'}
147
101
  ]
148
102
  end
149
-
103
+
150
104
  it "should make a get request" do
151
105
  stub_request(:get, /#{@base}/).to_return(json_response(true, []))
152
106
  described_class.all(get_attributes)
153
107
  a_request(:get, /#{@base}#{uri_paths[:create]}/).should have_been_made
154
108
  end
155
-
109
+
156
110
  it "should create a collection using the class" do
157
111
  stub_request(:get, /#{@base}/).to_return(json_response(true, @array))
158
112
  collection = described_class.all(get_attributes)
159
- collection.should be_instance_of(SurveyGizmo::Collection)
160
- end
161
-
113
+ collection.should be_instance_of(Array)
114
+ end
115
+
162
116
  it "should return instances of the class" do
163
117
  stub_request(:get, /#{@base}/).to_return(json_response(true, @array))
164
118
  collection = described_class.all(get_attributes)
165
119
  collection.first.should be_instance_of(described_class)
166
120
  end
167
-
121
+
168
122
  it "should include all elements" do
169
123
  stub_request(:get, /#{@base}/).to_return(json_response(true, @array))
170
124
  collection = described_class.all(get_attributes)
171
125
  collection.length.should == 3
172
126
  end
173
127
  end
174
-
128
+
175
129
  end