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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d64a92def211dfa2973dcf28108a0e1f5f1b9d8f
4
- data.tar.gz: 232115207e4e7462fc8d8394840eea2aa0fba3f6
3
+ metadata.gz: 7cb1e79765bcce6a50eee8322f40b91f3eb6c07a
4
+ data.tar.gz: 9667fb03ea0a0e3d1fc95b5a87dc5a1244d87a3d
5
5
  SHA512:
6
- metadata.gz: f089bc8915e0158e621392f3d2d748ee3ef42dc4fc98d892e7994e3cf488079de72c897fb809f8d683cca52f8e983aaf8d7c4d4c5ad9c9cd6ce4adf5906d889e
7
- data.tar.gz: 5ec0d6f45dd3071e27dcbc646daba605b053f7443d0ea1f8cb33e354555c7508473ded774bfb71a1ea10c918c106531b95336432b1562ba2ba436d24e34cee7d
6
+ metadata.gz: 0164944250b283f6cb3b3916cd9662bc30db55bf55918dbcb8f1f95edbd8c6af2eed73ce65e5714c121fcf844a3b44a5c129af756b61633574a6f114ed04f9c5
7
+ data.tar.gz: 6e96c4e265af7c09d2a1f60dab253718549c8853a19dfff98332512740ee778ddd8e6ba249f4ceeb96603ffd205bc23a272af075374de64f6cb35cd80faa94fe
data/.gitignore CHANGED
@@ -16,4 +16,6 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  test.rb
19
- .DS_Store
19
+ .DS_Store
20
+ .ruby-version
21
+
data/Gemfile CHANGED
@@ -1,3 +1,2 @@
1
1
  source 'https://rubygems.org'
2
-
3
- gemspec
2
+ gemspec
data/README.md CHANGED
@@ -1,75 +1,111 @@
1
- # WARNING:
1
+ #### WARNING:
2
2
 
3
- SurveyGizmo doesn't test their REST API when they roll out changes. They don't publish a list of active defects, and when you call/email for support it is unlikely you will geto a person that knows anything about programming or the REST API. You can't talk to level 2 support, although they might offer you a discount on their paid consulting rates if the problem persists for more than a few weeks.
3
+ This is version `2.0.0` of the gem, which introduces breaking changes. People who need backwards compatibility can use `1.0.4`.
4
4
 
5
- You might be able to work around an active SurveyGizmo debacle by change which API version you use one of::
5
+ What's fixed/better:
6
+ * Filtering of requests is implemented
7
+ * Requests for the questions in a survey now retrieve ALL of the questions, even the sneaky sub_questions that weren't directly returned to a basic API request.
6
8
 
7
- export GIZMO_URI="https://restapi.surveygizmo.com/v2"
9
+ What broke:
10
+ * SurveyGizmo objects (Survey, SurveyQuestion, etc) no longer track their own state (:new, :zombie, :saved, etc etc) - state tracking was useless anyways because exceptions always were raised on errors.
11
+ * There is no more SurveyGizmo::Collection class... now there are just Arrays.
12
+ * There is no more lazy loading/instantiation.
8
13
 
9
- export GIZMO_URI="https://restapi.surveygizmo.com/head"
14
+ What's different:
15
+ * Variables are not autoloaded. That is to say when you load a Survey, the API request that loads the associated questions is not executed until you ask for them with the #questions method
10
16
 
11
- ...and then your application might work again.
12
-
13
- -chorn@chorn.com 2013-03-15
17
+ Also a past warning from another author:
18
+ > SurveyGizmo doesn't test their REST API when they roll out changes. They don't publish a list of active defects, and when you call/email for support it is unlikely you will geto a person that knows anything about programming or the REST API. You can't talk to level 2 support, although they might offer you a discount on their paid consulting rates if the problem persists for more than a few weeks.
14
19
 
20
+ — chorn@chorn.com 2013-03-15
15
21
 
16
22
  # Survey Gizmo (ruby)
17
23
 
18
- Integrate with the [Survey Gizmo API](http://developer.surveygizmo.com/resources/rest-api-documentation-version-1-01/) using an ActiveModel style interface. We currently support rest API **v3**. If you want to use version 1 of the API, please use gem version ~0.7.0
24
+ Integrate with the [Survey Gizmo API](http://apisurveygizmo.helpgizmo.com/help) using an ActiveModel style interface. We currently support rest API **v3**. If you want to use version 1 of the API, please use gem version ~0.7.0
19
25
 
20
26
  ## Installation
21
27
 
22
- gem install survey-gizmo-ruby
28
+ ```ruby
29
+ gem 'survey-gizmo-ruby'
30
+ ```
23
31
 
24
32
  ## Basic Usage
25
33
 
26
- require 'survey-gizmo-ruby'
27
-
28
- # somewhere in your app define your survey gizmo login credentials.
29
- SurveyGizmo.setup(:user => 'you@somewhere.com', :password => 'mypassword')
30
-
31
- survey = SurveyGizmo::API::Survey.first(:id => 12345)
32
- survey.title # => My Title
33
- survey.pages # => [page1, page2,...]
34
-
35
- question = SurveyGizmo::API::Question.create(:survey_id => survey.id, :title => 'Do you like ruby?', :type => 'checkbox')
36
- question.title = "Do you LOVE Ruby?"
37
- question.save # => true
38
- question.saved? # => true
39
-
40
- # Error handling
41
- question.save # => false
42
- question.errors # => ['There was an error']
43
-
34
+ ```ruby
35
+ require 'survey-gizmo-ruby'
36
+
37
+ # somewhere in your app define your survey gizmo login credentials.
38
+ SurveyGizmo.setup(user: 'you@somewhere.com', password: 'mypassword')
39
+
40
+ # Retrieve the survey with id: 12345
41
+ survey = SurveyGizmo::API::Survey.first(id: 12345)
42
+ survey.title # => My Title
43
+ survey.pages # => [page1, page2,...]
44
+
45
+ # Create a question for your survey
46
+ question = SurveyGizmo::API::Question.create(survey_id: survey.id, title: 'Do you like ruby?', type: 'checkbox')
47
+ question.title = "Do you LOVE Ruby?"
48
+ question.save # => question # (but now with the id assigned by SurveyGizmo as the :id property)
49
+
50
+ # Error handling
51
+ question.save # => false
52
+ question.errors # => ['There was an error']
53
+
54
+ # Retrieving Questions for a given survey. Note that page_id is a required parameter.
55
+ questions = SurveyGizmo::API::Question.all(survey_id: survey.id, page_id: 1)
56
+ # Or just retrieve all questions for all pages of this survey
57
+ questions = survey.questions
58
+
59
+ # Retrieving SurveyResponses for a given survey.
60
+ # Note that because of both options being hashes, you need to enclose them both in braces to page successfully!
61
+ responses = SurveyGizmo::API::Response.all({survey_id: survey.id}, {page: 1})
62
+
63
+ # Retrieving page 2 of non test data SurveyResponses
64
+ filters = {page: 2, filters: [{field: 'istestdata', operator: '<>', value: 1}] }
65
+ responses = SurveyGizmo::API::Response.all({survey_id: survey_id}, filters)
66
+ ```
67
+
68
+ ## Debugging
69
+
70
+ The GIZMO_DEBUG environment variable will trigger full printouts of SurveyGizmo's HTTP responses and variable introspection for almost everything
71
+
72
+ ```bash
73
+ cd /my/app
74
+ export GIZMO_DEBUG=true
75
+ bundle exec rails whatever
76
+ ```
77
+
44
78
  ## Adding API Objects
45
79
 
46
80
  Currently, the following API objects are included in the gem: `Survey`, `Question`, `Option`, `Page`, `Response`, `EmailMessage`, `SurveyCampaign`, `Contact`. If you want to use something that isn't included you can easily write a class that handles it. Here's an example of the how to do so:
47
81
 
48
- class SomeObject
49
- # the base where most of the methods for handling the API are stored
50
- include SurveyGizmo::Resource
51
-
52
- # the attribtues the object should respond to
53
- attribute :id, Integer
54
- attribute :title, String
55
- attribute :status, String
56
- attribute :type, String
57
- attribute :created_on, DateTime
58
-
59
- # defing the paths used to retrieve/set info
60
- route '/something/:id', :via => [:get, :update, :delete]
61
- route '/something', :via => :create
62
-
63
- # this must be defined with the params that would be included in any route
64
- def to_param_options
65
- {:id => self.id}
66
- end
67
- end
82
+ ```ruby
83
+ class SomeObject
84
+ # the base where most of the methods for handling the API are stored
85
+ include SurveyGizmo::Resource
86
+
87
+ # the attribtues the object should respond to
88
+ attribute :id, Integer
89
+ attribute :title, String
90
+ attribute :status, String
91
+ attribute :type, String
92
+ attribute :created_on, DateTime
93
+
94
+ # defing the paths used to retrieve/set info
95
+ route '/something/:id', :via => [:get, :update, :delete]
96
+ route '/something', :via => :create
97
+
98
+ # this must be defined with the params that would be included in any route
99
+ def to_param_options
100
+ {:id => self.id}
101
+ end
102
+ end
103
+ ```
68
104
 
69
105
  The [Virtus](https://github.com/solnic/virtus) gem is included to handle the attributes, so please check their documentation as well.
70
106
 
71
107
  # Contributing to survey-gizmo-ruby
72
-
108
+
73
109
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
74
110
  * Take a gander at the github issues beforehand
75
111
  * Fork the project
@@ -80,7 +116,9 @@ The [Virtus](https://github.com/solnic/virtus) gem is included to handle the att
80
116
 
81
117
  ## Missing Features
82
118
 
83
- There are several API objects that are available and not included in this gem. It is also missing OAuth authentication ability. Also, the error notification isn't intuitive. It'd be great if someone could help tackle those!
119
+ * It would be nice to implement enumerable on the Question and (especially) Response objects so people don't have to implement their own paging
120
+ * There are several API objects that are available and not included in this gem.
121
+ * It is also missing OAuth authentication ability.
84
122
 
85
123
 
86
124
  # Copyright
data/Rakefile CHANGED
@@ -1,7 +1,8 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
+
3
4
  RSpec::Core::RakeTask.new(:spec) do |spec|
4
5
  spec.pattern = FileList['spec/**/*_spec.rb']
5
6
  end
6
7
 
7
- task :default => :spec
8
+ task :default => :spec
@@ -1 +1 @@
1
- require "survey_gizmo/survey_gizmo"
1
+ require 'survey_gizmo/survey_gizmo'
@@ -38,12 +38,12 @@ module SurveyGizmo; module API
38
38
  attribute :scustomfield9, String
39
39
  attribute :scustomfield10, String
40
40
 
41
- route '/survey/:survey_id/surveycampaign/:campaign_id/contact/:id', :via => [:get, :update, :delete]
42
- route '/survey/:survey_id/surveycampaign/:campaign_id/contact', :via => :create
41
+ route '/survey/:survey_id/surveycampaign/:campaign_id/contact/:id', via: [:get, :update, :delete]
42
+ route '/survey/:survey_id/surveycampaign/:campaign_id/contact', via: :create
43
43
 
44
44
  # @see SurveyGizmo::Resource#to_param_options
45
45
  def to_param_options
46
- {:id => self.id, :survey_id => self.survey_id, :campaign_id => self.campaign_id}
46
+ {id: self.id, survey_id: self.survey_id, campaign_id: self.campaign_id}
47
47
  end
48
48
  end
49
49
  end; end
@@ -14,8 +14,8 @@ module SurveyGizmo; module API
14
14
  attribute :properties, Hash
15
15
 
16
16
  # routing
17
- route '/survey/:survey_id/surveypage/:page_id/surveyquestion/:question_id/surveyoption', :via => :create
18
- route '/survey/:survey_id/surveypage/:page_id/surveyquestion/:question_id/surveyoption/:id', :via => [:get, :update, :delete]
17
+ route '/survey/:survey_id/surveypage/:page_id/surveyquestion/:question_id/surveyoption', via: :create
18
+ route '/survey/:survey_id/surveypage/:page_id/surveyquestion/:question_id/surveyoption/:id', via: [:get, :update, :delete]
19
19
 
20
20
  # survey gizmo sends a hash back for :title
21
21
  # @private
@@ -27,8 +27,7 @@ module SurveyGizmo; module API
27
27
 
28
28
  # @see SurveyGizmo::Resource#to_param_options
29
29
  def to_param_options
30
- {:id => self.id, :survey_id => self.survey_id, :page_id => self.page_id, :question_id => self.question_id}
30
+ {id: self.id, survey_id: self.survey_id, page_id: self.page_id, question_id: self.question_id}
31
31
  end
32
-
33
32
  end
34
33
  end; end
@@ -12,25 +12,29 @@ module SurveyGizmo; module API
12
12
  attribute :after, Integer
13
13
  attribute :survey_id, Integer
14
14
 
15
-
16
15
  # routing
17
16
  route '/survey/:survey_id/surveypage', :via => :create
18
17
  route '/survey/:survey_id/surveypage/:id', :via => [:get, :update, :delete]
19
18
 
20
- # @macro collection
21
- collection :questions
19
+ def survey
20
+ @survey ||= SurveyGizmo::API::Survey.first(id: survey_id)
21
+ end
22
+
23
+ def questions
24
+ @questions ||= SurveyGizmo::API::Question.all(survey_id: survey_id, page_id: id)
25
+ end
22
26
 
23
27
  # survey gizmo sends a hash back for :title
24
28
  # @private
25
29
  def title_with_multilingual=(val)
26
- self.title_without_multilingual = val.is_a?(Hash) ? val : { "English" => val }
30
+ self.title_without_multilingual = val.is_a?(Hash) ? val : { 'English' => val }
27
31
  end
28
32
 
29
33
  alias_method_chain :title=, :multilingual
30
34
 
31
35
  # @see SurveyGizmo::Resource#to_param_options
32
36
  def to_param_options
33
- {:id => self.id, :survey_id => self.survey_id}
37
+ {id: self.id, survey_id: self.survey_id}
34
38
  end
35
39
  end
36
40
  end; end
@@ -5,26 +5,40 @@ module SurveyGizmo; module API
5
5
 
6
6
  # @macro [attach] virtus_attribute
7
7
  # @return [$2]
8
- attribute :id, Integer
9
- attribute :title, String
10
- attribute :type, String
11
- attribute :description, String
12
- attribute :shortname, String
13
- attribute :properties, Hash
14
- attribute :after, Integer
15
- attribute :survey_id, Integer
16
- attribute :page_id, Integer, :default => 1
8
+ attribute :id, Integer
9
+ attribute :title, String
10
+ attribute :type, String
11
+ attribute :description, String
12
+ attribute :shortname, String
13
+ attribute :properties, Hash
14
+ attribute :after, Integer
15
+ attribute :survey_id, Integer
16
+ attribute :page_id, Integer, :default => 1
17
+ attribute :sub_question_skus, Array
18
+ attribute :parent_question_id, Integer
17
19
 
18
20
  alias_attribute :_subtype, :type
19
21
 
20
- route '/survey/:survey_id/surveyquestion/:id', :via => :get
21
- route '/survey/:survey_id/surveypage/:page_id/surveyquestion', :via => :create
22
- route '/survey/:survey_id/surveypage/:page_id/surveyquestion/:id', :via => [:update, :delete]
22
+ route '/survey/:survey_id/surveyquestion/:id', via: :get
23
+ route '/survey/:survey_id/surveypage/:page_id/surveyquestion', via: :create
24
+ route '/survey/:survey_id/surveypage/:page_id/surveyquestion/:id', via: [:update, :delete]
23
25
 
24
- # @macro collection
25
- collection :options
26
- collection :sub_question_skus
26
+ def survey
27
+ @survey ||= SurveyGizmo::API::Survey.first(id: survey_id)
28
+ end
29
+
30
+ def options
31
+ @options ||= SurveyGizmo::API::Option.all(survey_id: survey_id, page_id: page_id, question_id: id)
32
+ end
27
33
 
34
+ def parent_question
35
+ @parent_question ||= parent_question_id ? SurveyGizmo::API::Question.first(survey_id: survey_id, id: parent_question_id) : nil
36
+ end
37
+
38
+ def sub_questions
39
+ @sub_questions ||= sub_question_skus.map {|subquestion_id| SurveyGizmo::API::Question.first(survey_id: survey_id, id: subquestion_id)}
40
+ .each {|subquestion| subquestion.parent_question_id = id}
41
+ end
28
42
  # survey gizmo sends a hash back for :title
29
43
  # @private
30
44
  def title_with_multilingual=(val)
@@ -35,7 +49,7 @@ module SurveyGizmo; module API
35
49
 
36
50
  # @see SurveyGizmo::Resource#to_param_options
37
51
  def to_param_options
38
- {:id => self.id, :survey_id => self.survey_id, :page_id => self.page_id}
52
+ {id: self.id, survey_id: self.survey_id, page_id: self.page_id}
39
53
  end
40
54
  end
41
- end; end
55
+ end; end
@@ -10,7 +10,7 @@ module SurveyGizmo; module API
10
10
  attribute :contact_id, Integer
11
11
  attribute :data, String
12
12
  attribute :status, String
13
- attribute :date_submitted, DateTime
13
+ attribute :datesubmitted, DateTime
14
14
  attribute :is_test_data, Boolean
15
15
  attribute :sResponseComment, String
16
16
  attribute :variable, Hash # READ-ONLY
@@ -20,17 +20,16 @@ module SurveyGizmo; module API
20
20
  attribute :answers, Hash # READ-ONLY
21
21
 
22
22
  # routing
23
- route '/survey/:survey_id/surveyresponse', :via => :create
24
- route '/survey/:survey_id/surveyresponse/:id', :via => [:get, :update, :delete]
23
+ route '/survey/:survey_id/surveyresponse', via: :create
24
+ route '/survey/:survey_id/surveyresponse/:id', via: [:get, :update, :delete]
25
25
 
26
- # @see SurveyGizmo::Resource#to_param_options
27
- def to_param_options
28
- {:id => self.id, :survey_id => self.survey_id}
26
+ def survey
27
+ @survey ||= SurveyGizmo::API::Survey.first(id: survey_id)
29
28
  end
30
29
 
31
- def datesubmitted=(value)
32
- self.date_submitted = value
30
+ # @see SurveyGizmo::Resource#to_param_options
31
+ def to_param_options
32
+ {id: self.id, survey_id: self.survey_id}
33
33
  end
34
-
35
34
  end
36
35
  end; end
@@ -7,7 +7,7 @@ module SurveyGizmo; module API
7
7
  # @return [$2]
8
8
  attribute :id, Integer
9
9
  attribute :team, Integer
10
- attribute :type, String
10
+ attribute :type, String
11
11
  attribute :_subtype, String
12
12
  attribute :status, String
13
13
  attribute :forward_only, Boolean
@@ -23,15 +23,30 @@ module SurveyGizmo; module API
23
23
  attribute :modified_on, DateTime
24
24
  attribute :copy, Boolean
25
25
 
26
- route '/survey/:id', :via => [:get, :update, :delete]
27
- route '/survey', :via => :create
26
+ route '/survey/:id', via: [:get, :update, :delete]
27
+ route '/survey', via: :create
28
28
 
29
- # @macro collection
30
- collection :pages
29
+ def pages
30
+ @pages ||= SurveyGizmo::API::Page.all(survey_id: id)
31
+ end
32
+
33
+ def questions
34
+ @questions ||= pages.map {|p| SurveyGizmo::API::Question.all(survey_id: id, page_id: p.id)}.flatten
35
+ end
36
+
37
+ # Statistics array of arrays looks like:
38
+ # [["Partial", 2], ["Disqualified", 28], ["Complete", 15]]
39
+ def number_of_completed_responses
40
+ if statistics && !statistics.empty? && (completed_data = statistics.find {|a| a[0] == 'Complete'})
41
+ completed_data[1]
42
+ else
43
+ 0
44
+ end
45
+ end
31
46
 
32
47
  # @see SurveyGizmo::Resource#to_param_options
33
48
  def to_param_options
34
- {:id => self.id}
49
+ {id: self.id}
35
50
  end
36
51
  end
37
52
  end; end
@@ -1,5 +1,5 @@
1
- require "set"
2
- require "addressable/uri"
1
+ require 'set'
2
+ require 'addressable/uri'
3
3
 
4
4
  module SurveyGizmo
5
5
  module Resource
@@ -8,7 +8,6 @@ module SurveyGizmo
8
8
  included do
9
9
  include Virtus.model
10
10
  instance_variable_set('@paths', {})
11
- instance_variable_set('@collections', {})
12
11
  SurveyGizmo::Resource.descendants << self
13
12
  end
14
13
 
@@ -22,24 +21,58 @@ module SurveyGizmo
22
21
  module ClassMethods
23
22
 
24
23
  # Convert a [Hash] of filters into a query string
25
- # @param [Hash] filters
24
+ # @param [Hash] filters - simple pagination or other options at the top level, and surveygizmo "filters" at the :filters key
26
25
  # @return [String]
26
+ #
27
+ # example input: {page: 2, filters: [{:field=>"istestdata", :operator=>"<>", :value=>1}]}
28
+ # The top level keys (e.g. page, resultsperpage) get simply encoded in the url, while the contents of the array of hashes
29
+ # passed at filters[:filters] gets turned into the format surveygizmo expects for its internal filtering, for example:
30
+ #
31
+ # filter[field][0]=istestdata&filter[operator][0]=<>&filter[value][0]=1
27
32
  def convert_filters_into_query_string(filters = nil)
28
- "" unless filters && filters.size > 0
29
- uri = Addressable::URI.new
30
- uri.query_values = filters
31
- "?#{uri.query}"
33
+ if filters && filters.size > 0
34
+ output_filters = filters[:filters] || []
35
+ filter_hash = {}
36
+ output_filters.each_with_index do |filter,i|
37
+ filter_hash.merge!({
38
+ "filter[field][#{i}]".to_sym => "#{filter[:field]}",
39
+ "filter[operator][#{i}]".to_sym => "#{filter[:operator]}",
40
+ "filter[value][#{i}]".to_sym => "#{filter[:value]}",
41
+ })
42
+ end
43
+ simple_filters = filters.reject {|k,v| k == :filters}
44
+ filter_hash.merge!(simple_filters)
45
+
46
+ uri = Addressable::URI.new
47
+ uri.query_values = filter_hash
48
+ "?#{uri.query}"
49
+ else
50
+ ''
51
+ end
32
52
  end
33
53
 
34
54
  # Get a list of resources
35
55
  # @param [Hash] conditions
36
56
  # @param [Hash] filters
37
- # @return [SurveyGizmo::Collection, Array]
57
+ # @return [Array] of objects of this class
38
58
  def all(conditions = {}, filters = nil)
39
- response = Response.new SurveyGizmo.get(handle_route(:create, conditions) + convert_filters_into_query_string(filters))
59
+ response = RestResponse.new(SurveyGizmo.get(handle_route(:create, conditions) + convert_filters_into_query_string(filters)))
40
60
  if response.ok?
41
- _collection = SurveyGizmo::Collection.new(self, nil, response.data)
42
- _collection.send(:options=, {:target => self, :parent => self})
61
+ _collection = response.data.map {|datum| datum.is_a?(Hash) ? self.new(datum) : datum}
62
+
63
+ # Add in the properties from the conditions hash because many of the important ones (like survey_id) are
64
+ # not often part of the SurveyGizmo returned data
65
+ conditions.keys.each do |k|
66
+ if conditions[k] && instance_methods.include?(k)
67
+ _collection.each { |c| c[k] ||= conditions[k] }
68
+ end
69
+ end
70
+
71
+ # Sub questions are not pulled by default so we have to retrieve them
72
+ if self == SurveyGizmo::API::Question
73
+ _collection += _collection.map {|question| question.sub_questions}.flatten
74
+ end
75
+
43
76
  _collection
44
77
  else
45
78
  []
@@ -51,8 +84,10 @@ module SurveyGizmo
51
84
  # @param [Hash] filters
52
85
  # @return [Object, nil]
53
86
  def first(conditions = {}, filters = nil)
54
- response = Response.new SurveyGizmo.get(handle_route(:get, conditions) + convert_filters_into_query_string(filters))
55
- response.ok? ? load(conditions.merge(response.data)) : nil
87
+ response = RestResponse.new(SurveyGizmo.get(handle_route(:get, conditions) + convert_filters_into_query_string(filters)))
88
+ # Add in the properties from the conditions hash because many of the important ones (like survey_id) are
89
+ # not often part of the SurveyGizmo's returned data
90
+ response.ok? ? new(conditions.merge(response.data)) : nil
56
91
  end
57
92
 
58
93
  # Create a new resource
@@ -61,7 +96,7 @@ module SurveyGizmo
61
96
  # The newly created Resource instance
62
97
  def create(attributes = {})
63
98
  resource = new(attributes)
64
- resource.__send__(:_create)
99
+ resource.create_record_in_surveygizmo
65
100
  resource
66
101
  end
67
102
 
@@ -81,8 +116,7 @@ module SurveyGizmo
81
116
  # @param [Hash] conditions
82
117
  # @return [Boolean]
83
118
  def destroy(conditions)
84
- response = Response.new SurveyGizmo.delete(handle_route(:delete, conditions))
85
- response.ok?
119
+ RestResponse.new(SurveyGizmo.delete(handle_route(:delete, conditions))).ok?
86
120
  end
87
121
 
88
122
  # Define the path where a resource is located
@@ -95,76 +129,32 @@ module SurveyGizmo
95
129
  def route(path, options)
96
130
  methods = options[:via]
97
131
  methods = [:get, :create, :update, :delete] if methods == :any
98
- methods.is_a?(Array) ? methods.each{|m| @paths[m] = path } : (@paths[methods] = path)
132
+ methods.is_a?(Array) ? methods.each { |m| @paths[m] = path } : (@paths[methods] = path)
99
133
  nil
100
134
  end
101
135
 
136
+ # This method replaces the :page_id, :survey_id, etc strings defined in each model's URI routes with the
137
+ # values being passed in interpolation hash with the same keys.
102
138
  # @api private
103
- def load(attributes = {})
104
- resource = new(attributes)
105
- resource.__send__(:clean!)
106
- resource
107
- end
108
-
109
- # Defines a new collection. These are child objects of the resource.
110
- # @macro [new] collection
111
- # @param [Symbol] resource_name the name of the collection, pluralized
112
- # @param [Class] model and optional class name if the class name does not match the resource_name
113
- # @return [Collection]
114
- # the $1 collection
115
- # @scope instance
116
- def collection(resource_name, model = nil)
117
- @collections[resource_name] = {:parent => self, :target => (model ? model : resource_name)} # workaround for weird bug with passing a class to Collection
118
- class_eval(<<-EOS)
119
- def #{resource_name}
120
- @#{resource_name} ||= []
121
- end
122
-
123
- def #{resource_name}=(array)
124
- @#{resource_name} = SurveyGizmo::Collection.new(#{self}, :#{resource_name}, array)
125
- end
126
- EOS
127
- end
128
-
129
- # @api private
130
- def collections
131
- @collections.dup.freeze
132
- end
133
-
134
- # @api private
135
- def handle_route(key, *interp)
139
+ def handle_route(key, interpolation_hash)
136
140
  path = @paths[key]
137
141
  raise "No routes defined for `#{key}` in #{self.name}" unless path
138
- options = interp.last.is_a?(Hash) ? interp.pop : path.scan(/:(\w+)/).inject({}){|hash, k| hash.merge(k.to_sym => interp.shift) }
142
+ raise "User/password hash not setup!" if SurveyGizmo.default_params.empty?
143
+
139
144
  path.gsub(/:(\w+)/) do |m|
140
- options[$1.to_sym].tap{ |result| raise(SurveyGizmo::URLError, "Missing parameters in request: `#{m}`") unless result }
145
+ raise(SurveyGizmo::URLError, "Missing RESTful parameters in request: `#{m}`") unless interpolation_hash[$1.to_sym]
146
+ interpolation_hash[$1.to_sym]
141
147
  end
142
148
  end
143
149
  end
144
150
 
145
- # Updates attributes and saves this Resource instance
146
- #
147
- # @param [Hash] attributes
148
- # attributes to be updated
149
- #
150
- # @return [Boolean]
151
- # true if resource is saved
152
- def update(attributes = {})
153
- self.attributes = attributes
154
- self.save
155
- end
156
-
157
151
  # Save the instance to Survey Gizmo
158
- #
159
- # @return [Boolean]
160
- # true if Resource instance is saved
161
152
  def save
162
- if new?
163
- _create
153
+ if id #Then it's an update
154
+ handle_response(SurveyGizmo.post(handle_route(:update), query: self.attributes_without_blanks))
155
+ @latest_response.ok?
164
156
  else
165
- handle_response SurveyGizmo.post(handle_route(:update), :query => self.attributes_without_blanks) do
166
- _response.ok? ? saved! : false
167
- end
157
+ create_record_in_surveygizmo
168
158
  end
169
159
  end
170
160
 
@@ -172,50 +162,24 @@ module SurveyGizmo
172
162
  # @return [self, false]
173
163
  # Returns the object, if saved. Otherwise returns false.
174
164
  def reload
175
- handle_response SurveyGizmo.get(handle_route(:get)) do
176
- if _response.ok?
177
- self.attributes = _response.data
178
- clean!
179
- else
180
- false
181
- end
165
+ handle_response(SurveyGizmo.get(handle_route(:get)))
166
+ if @latest_response.ok?
167
+ self.attributes = @latest_response['data']
168
+ self
169
+ else
170
+ false
182
171
  end
183
172
  end
184
173
 
185
174
  # Deleted the Resource from Survey Gizmo
186
175
  # @return [Boolean]
187
176
  def destroy
188
- return false if new? || destroyed?
189
- handle_response SurveyGizmo.delete(handle_route(:delete)) do
190
- _response.ok? ? destroyed! : false
191
- end
192
- end
193
-
194
- # The state of the current Resource
195
- # @api private
196
- def new?
197
- @_state.nil?
198
- end
199
-
200
- # @todo This seemed like a good way to prevent accidently trying to perform an action
201
- # on a record at a point when it would fail. Not sure if it's really necessary though.
202
- [:clean, # stored and not dirty
203
- :saved, # stored and not modified
204
- :destroyed, # duh!
205
- :zombie # needs to be stored
206
- ].each do |state|
207
- # Change the method state to $1
208
- define_method("#{state}!") do
209
- @_state = state
210
- true
211
- end
212
-
213
- # Inquire about the method state if $1
214
- define_method("#{state}?") do
215
- @_state == state
177
+ if id
178
+ handle_response(SurveyGizmo.delete(handle_route(:delete)))
179
+ @latest_response.ok?
180
+ else
181
+ false
216
182
  end
217
-
218
- private "#{state}!"
219
183
  end
220
184
 
221
185
  # Sets the hash that will be used to interpolate values in routes. It needs to be defined per model.
@@ -230,88 +194,41 @@ module SurveyGizmo
230
194
  @errors ||= []
231
195
  end
232
196
 
233
- # @return [Hash] The raw JSON returned by Survey Gizmo
234
- def raw_response
235
- _response.response if _response
236
- end
237
-
238
197
  # @visibility private
239
198
  def inspect
240
- attrs = self.class.attribute_set.map do |attrib|
241
- value = attrib.get!(self).inspect
242
-
243
- "@#{attrib.name}=#{value}" if attrib.respond_to?(:name)
199
+ if ENV['GIZMO_DEBUG']
200
+ ap "CLASS: #{self.class}"
244
201
  end
245
202
 
246
- "#<#{self.class.name}:#{self.object_id} #{attrs.join(' ')}>"
247
- end
248
-
249
- # This class normalizes the response returned by Survey Gizmo
250
- class Response
251
- def ok?
252
- @response && @response['result_ok']
253
- end
254
-
255
- # The parsed JSON data of the response
256
- def data
257
- @_data ||= (@response['data'] || {})
258
- end
259
-
260
- # The error message if there is one
261
- def message
262
- @_message ||= @response['message']
263
- end
264
-
265
- attr_reader :response
266
-
267
- private
268
- def cleanup_attribute_name(attr)
269
- attr.downcase.gsub(/[^[:alnum:]]+/,'_').gsub(/(url|variable|standard|shown)/,'').gsub(/_+/,'_').gsub(/^_/,'').gsub(/_$/,'')
270
- end
203
+ attribute_strings = self.class.attribute_set.map do |attrib|
204
+ if ENV['GIZMO_DEBUG']
205
+ ap attrib
206
+ ap attrib.name
207
+ ap self.send(attrib.name)
208
+ ap self.send(attrib.name).class
209
+ end
271
210
 
272
- def find_attribute_parent(attr)
273
- case attr.downcase
274
- when /url/
275
- "url"
276
- when /variable.*standard/
277
- "meta"
278
- when /variable.*shown/
279
- "shown"
280
- when /variable/
281
- "variable"
282
- when /question/
283
- "answers"
211
+ if self.send(attrib.name).class == Hash
212
+ value = self.send(attrib.name).inspect
213
+ else
214
+ value = self.send(attrib.name).to_s
284
215
  end
285
- end
286
216
 
287
- def initialize(response)
288
- @response = response.parsed_response
289
- return if @response.nil? or not ok?
290
- @_data = @response['data']
291
-
292
- # Handle really crappy [] notation in SG API, so far just in SurveyResponse
293
- items = (@_data.is_a?(Array) ? @_data : [@_data]).compact
294
- items.each do |data_item|
295
- data_item.keys.grep(/^\[/).each do |key|
296
- next if data_item[key].nil? || data_item[key].length == 0
297
-
298
- parent = find_attribute_parent(key)
299
- data_item[parent] = {} unless data_item[parent]
300
-
301
- case key.downcase
302
- when /(url|variable.*standard)/
303
- data_item[parent][cleanup_attribute_name(key).to_sym] = data_item[key]
304
- when /variable.*shown/
305
- data_item[parent][cleanup_attribute_name(key).to_i] = data_item[key].include?("1")
306
- when /variable/
307
- data_item[parent][cleanup_attribute_name(key).to_i] = data_item[key].to_i
308
- when /question/
309
- data_item[parent][key] = data_item[key]
310
- end
217
+ " \"#{attrib.name}\" => \"#{value}\"\n" unless value.strip.blank?
218
+ end.compact
311
219
 
312
- data_item.delete(key)
313
- end
314
- end unless items.blank?
220
+ "#<#{self.class.name}:#{self.object_id}>\n#{attribute_strings.join()}"
221
+ end
222
+
223
+ # Returns itself if successfully saved, but with attributes added by SurveyGizmo
224
+ def create_record_in_surveygizmo(attributes = {})
225
+ http = RestResponse.new(SurveyGizmo.put(handle_route(:create), query: self.attributes_without_blanks))
226
+ handle_response(http)
227
+ if http.ok?
228
+ self.attributes = http.data
229
+ self
230
+ else
231
+ false
315
232
  end
316
233
  end
317
234
 
@@ -319,51 +236,34 @@ module SurveyGizmo
319
236
  protected
320
237
 
321
238
  def attributes_without_blanks
322
- self.attributes.reject{|k,v| v.blank? }
239
+ self.attributes.reject { |k,v| v.blank? }
323
240
  end
324
241
 
325
242
  private
326
- # The response object from SurveyGizmo. Useful for viewing the raw data returned
327
- attr_reader :_response
328
-
329
- def set_response(http)
330
- @_response = Response.new(http)
331
- end
332
-
333
243
  def handle_route(key)
334
244
  self.class.handle_route(key, to_param_options)
335
245
  end
336
246
 
337
- def handle_response(resp, &block)
338
- set_response(resp)
339
- (self.errors << _response.message) unless _response.ok?
340
- self.errors.clear if !self.errors.empty? && _response.ok?
341
- instance_eval(&block)
342
- end
343
-
344
- def _create(attributes = {})
345
- http = SurveyGizmo.put(handle_route(:create), :query => self.attributes_without_blanks)
346
- handle_response http do
347
- if _response.ok?
348
- self.attributes = _response.data
349
- saved!
350
- else
351
- false
352
- end
247
+ def handle_response(rest_response, &block)
248
+ @latest_response = rest_response
249
+ if @latest_response.ok?
250
+ self.errors.clear
251
+ true
252
+ else
253
+ errors << @latest_response.message
254
+ false
353
255
  end
354
256
  end
355
257
 
356
258
  def _copy(attributes = {})
357
- http = SurveyGizmo.post(handle_route(:update), :query => self.attributes_without_blanks)
358
- handle_response http do
359
- if _response.ok?
360
- self.attributes = _response.data
361
- saved!
259
+ http = RestResponse.new(SurveyGizmo.post(handle_route(:update), query: self.attributes_without_blanks))
260
+ handle_response(http) do
261
+ if http.ok?
262
+ self.attributes = http.data
362
263
  else
363
264
  false
364
265
  end
365
266
  end
366
267
  end
367
-
368
268
  end
369
269
  end