acts_as_api 0.3.2 → 0.3.3
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.
- data/History.txt +15 -1
- data/README.rdoc +3 -0
- data/lib/acts_as_api/api_template.rb +118 -12
- data/lib/acts_as_api/array.rb +1 -1
- data/lib/acts_as_api/base.rb +8 -67
- data/lib/acts_as_api/config.rb +4 -0
- data/lib/acts_as_api/rails_renderer.rb +3 -1
- data/lib/acts_as_api/version.rb +1 -2
- data/lib/acts_as_api.rb +2 -3
- data/spec/controllers/users_controller_spec.rb +4 -5
- data/spec/models/base/associations_spec.rb +284 -0
- data/spec/models/base/closures_spec.rb +62 -0
- data/spec/models/base/conditional_if_spec.rb +178 -0
- data/spec/models/base/conditional_unless_spec.rb +178 -0
- data/spec/models/base/enabled_spec.rb +15 -0
- data/spec/models/base/extending_spec.rb +74 -0
- data/spec/models/base/methods_spec.rb +33 -0
- data/spec/models/base/renaming_spec.rb +63 -0
- data/spec/models/base/simple_spec.rb +33 -0
- data/spec/models/base/sub_nodes_spec.rb +118 -0
- data/spec/models/base/undefined_spec.rb +20 -0
- data/spec/models/base/untouched_spec.rb +18 -0
- data/spec/rails_app/app/models/user.rb +52 -0
- data/spec/support/simple_fixtures.rb +26 -0
- metadata +30 -6
- data/spec/models/base_spec.rb +0 -635
data/History.txt
CHANGED
@@ -1,4 +1,18 @@
|
|
1
|
-
=== 0.3.
|
1
|
+
=== 0.3.3 2011-04-24
|
2
|
+
|
3
|
+
* Added support for :if and :unless options
|
4
|
+
|
5
|
+
=== 0.3.2 2011-04-20
|
6
|
+
|
7
|
+
* Raise an exception if a specified api template is not found
|
8
|
+
|
9
|
+
=== 0.3.1 2011-04-08
|
10
|
+
|
11
|
+
* Added the :template option to specify sub templates
|
12
|
+
|
13
|
+
* Fixed a bug concerning extended api templates
|
14
|
+
|
15
|
+
=== 0.3.0 2011-02-22
|
2
16
|
|
3
17
|
* Added bundler support
|
4
18
|
|
data/README.rdoc
CHANGED
@@ -1,27 +1,133 @@
|
|
1
1
|
module ActsAsApi
|
2
|
-
#
|
2
|
+
# Represents an api template for a model.
|
3
|
+
# This class should not be initiated by yourself, api templates
|
4
|
+
# are created by defining them in the model by calling: +api_accessible+.
|
5
|
+
#
|
6
|
+
# The api template is configured in the block passed to +api_accessible+.
|
7
|
+
#
|
8
|
+
# Please note that +ApiTemplate+ inherits from +Hash+ so you can use all
|
9
|
+
# kind of +Hash+ and +Enumerable+ methods to manipulate the template.
|
3
10
|
class ApiTemplate < Hash
|
4
11
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
12
|
+
# The name of the api template as a Symbol.
|
13
|
+
attr_accessor :api_template
|
14
|
+
|
15
|
+
# Returns a new ApiTemplate with the api template name
|
16
|
+
# set to the passed template.
|
17
|
+
def self.create(template)
|
18
|
+
t = ApiTemplate.new
|
19
|
+
t.api_template = template
|
20
|
+
return t
|
11
21
|
end
|
12
22
|
|
23
|
+
# Adds an item to the api template
|
24
|
+
#
|
25
|
+
# The value passed can be one of the following:
|
26
|
+
# * Symbol - the method with the same name will be called on the model when rendering.
|
27
|
+
# * String - must be in the form "method1.method2.method3", will call this method chain.
|
28
|
+
# * Hash - will be added as a sub hash and all its items will be resolved the way described above.
|
29
|
+
#
|
30
|
+
# Possible options to pass:
|
31
|
+
# * :template - Determine the template that should be used to render the item if it is
|
32
|
+
# +api_accessible+ itself.
|
13
33
|
def add(val, options = {})
|
14
34
|
item_key = (options[:as] || val).to_sym
|
15
|
-
|
35
|
+
|
16
36
|
self[item_key] = val
|
17
|
-
|
37
|
+
|
18
38
|
@options ||= {}
|
19
39
|
@options[item_key] = options
|
20
40
|
end
|
21
41
|
|
22
|
-
|
23
|
-
|
42
|
+
# Removes an item from the template
|
43
|
+
def remove(item)
|
44
|
+
self.delete(item)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the options of an item in the api template
|
48
|
+
def options_for(item)
|
49
|
+
@options[item]
|
24
50
|
end
|
25
51
|
|
52
|
+
# Returns the passed option of an item in the api template
|
53
|
+
def option_for(item, option)
|
54
|
+
@options[item][option] if @options[item]
|
55
|
+
end
|
56
|
+
|
57
|
+
# If a special template name for the passed item is specified
|
58
|
+
# it will be returned, if not the original api template.
|
59
|
+
def api_template_for(parent, item)
|
60
|
+
return api_template unless parent.is_a? ActsAsApi::ApiTemplate
|
61
|
+
parent.option_for(item, :template) || api_template
|
62
|
+
end
|
63
|
+
|
64
|
+
# Decides if the passed item should be added to
|
65
|
+
# the response.
|
66
|
+
def allowed_to_render?(parent, item, model)
|
67
|
+
return true unless parent.is_a? ActsAsApi::ApiTemplate
|
68
|
+
allowed = true
|
69
|
+
allowed = condition_fulfilled?(model, parent.option_for(item, :if)) if parent.option_for(item, :if)
|
70
|
+
allowed = !(condition_fulfilled?(model, parent.option_for(item, :unless))) if parent.option_for(item, :unless)
|
71
|
+
return allowed
|
72
|
+
end
|
73
|
+
|
74
|
+
def condition_fulfilled?(model, condition)
|
75
|
+
case condition
|
76
|
+
when Symbol
|
77
|
+
result = model.send(condition)
|
78
|
+
when Proc
|
79
|
+
result = condition.call(model)
|
80
|
+
end
|
81
|
+
!result.nil? && !result.is_a?(FalseClass)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Generates a hash that represents the api response based on this
|
85
|
+
# template for the passed model instance.
|
86
|
+
def to_response_hash(model)
|
87
|
+
queue = []
|
88
|
+
api_output = {}
|
89
|
+
queue << { :parent => api_output, :item => self }
|
90
|
+
|
91
|
+
until queue.empty? do
|
92
|
+
leaf = queue.pop
|
93
|
+
|
94
|
+
leaf[:item].each do |k,v|
|
95
|
+
|
96
|
+
next unless allowed_to_render?(leaf[:item], k, model)
|
97
|
+
|
98
|
+
case v
|
99
|
+
when Symbol
|
100
|
+
if model.respond_to?(v)
|
101
|
+
out = model.send v
|
102
|
+
end
|
103
|
+
|
104
|
+
when Proc
|
105
|
+
out = v.call(model)
|
106
|
+
|
107
|
+
when String
|
108
|
+
# go up the call chain
|
109
|
+
out = model
|
110
|
+
v.split(".").each do |method|
|
111
|
+
out = out.send(method.to_sym)
|
112
|
+
end
|
113
|
+
|
114
|
+
when Hash
|
115
|
+
leaf[:parent][k] ||= {}
|
116
|
+
queue << { :parent => leaf[:parent][k], :item => v}
|
117
|
+
next
|
118
|
+
end
|
119
|
+
|
120
|
+
if out.respond_to?(:as_api_response)
|
121
|
+
sub_template = api_template_for(leaf[:item], k)
|
122
|
+
out = out.send(:as_api_response, sub_template)
|
123
|
+
end
|
124
|
+
|
125
|
+
leaf[:parent][k] = out
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
api_output
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
26
133
|
end
|
27
|
-
end
|
data/lib/acts_as_api/array.rb
CHANGED
data/lib/acts_as_api/base.rb
CHANGED
@@ -32,15 +32,9 @@ module ActsAsApi
|
|
32
32
|
# *Note*: There is only whitelisting for api accessible attributes.
|
33
33
|
# So once the model acts as api, you have to determine all attributes here that should
|
34
34
|
# be contained in the api responses.
|
35
|
-
def api_accessible_deprecated(api_templates)
|
36
|
-
api_templates.each do |api_template, attributes|
|
37
|
-
write_inheritable_attribute("api_accessible_#{api_template}".to_sym, Set.new(attributes) + (api_accessible_attributes(api_template) || []))
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
35
|
def api_accessible(api_template, options = {}, &block)
|
42
36
|
|
43
|
-
attributes = api_accessible_attributes(api_template) || ApiTemplate.
|
37
|
+
attributes = api_accessible_attributes(api_template) || ApiTemplate.create(api_template)
|
44
38
|
|
45
39
|
attributes.merge!(api_accessible_attributes(options[:extend])) if options[:extend]
|
46
40
|
|
@@ -55,75 +49,22 @@ module ActsAsApi
|
|
55
49
|
def api_accessible_attributes(api_template)
|
56
50
|
read_inheritable_attribute("api_accessible_#{api_template}".to_sym)
|
57
51
|
end
|
58
|
-
|
59
52
|
end
|
60
53
|
|
61
54
|
module InstanceMethods
|
62
55
|
|
63
56
|
# Creates the api response of the model and returns it as a Hash.
|
57
|
+
# Will raise an exception if the passed api template is not defined for the model
|
64
58
|
def as_api_response(api_template)
|
65
59
|
api_attributes = self.class.api_accessible_attributes(api_template)
|
66
|
-
|
60
|
+
|
67
61
|
raise "acts_as_api template :#{api_template.to_s} was not found for model #{self.class}" if api_attributes.nil?
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
return api_output if api_attributes.nil?
|
72
|
-
|
73
|
-
queue = []
|
74
|
-
queue << { :parent => api_output, :item => api_attributes}
|
75
|
-
|
76
|
-
until queue.empty? do
|
77
|
-
|
78
|
-
leaf = queue.pop
|
79
|
-
|
80
|
-
leaf[:item].each do |k,v|
|
81
|
-
|
82
|
-
if leaf[:item].respond_to?(:option_for)
|
83
|
-
sub_template = leaf[:item].option_for(k, :template) || api_template
|
84
|
-
else
|
85
|
-
sub_template = api_template
|
86
|
-
end
|
87
|
-
|
88
|
-
case v
|
89
|
-
when Symbol
|
90
|
-
|
91
|
-
if self.respond_to?(v)
|
92
|
-
out = send v
|
93
|
-
end
|
94
|
-
|
95
|
-
when Proc
|
96
|
-
out = v.call(self)
|
97
|
-
|
98
|
-
when String
|
99
|
-
# go up the call chain
|
100
|
-
out = self
|
101
|
-
v.split(".").each do |method|
|
102
|
-
out = out.send(method.to_sym)
|
103
|
-
end
|
104
|
-
|
105
|
-
when Hash
|
106
|
-
leaf[:parent][k] ||= {}
|
107
|
-
queue << { :parent => leaf[:parent][k], :item => v}
|
108
|
-
next
|
109
|
-
end
|
110
|
-
|
111
|
-
if out.respond_to?(:as_api_response)
|
112
|
-
out = out.send(:as_api_response, sub_template)
|
113
|
-
end
|
114
|
-
|
115
|
-
leaf[:parent][k] = out
|
116
|
-
|
117
|
-
end
|
118
|
-
|
119
|
-
end
|
120
|
-
|
121
|
-
api_output
|
122
|
-
|
123
|
-
end
|
124
|
-
|
62
|
+
|
63
|
+
api_attributes.to_response_hash(self)
|
125
64
|
end
|
126
65
|
|
127
66
|
end
|
128
|
-
|
67
|
+
|
129
68
|
end
|
69
|
+
|
70
|
+
end
|
data/lib/acts_as_api/config.rb
CHANGED
@@ -23,8 +23,12 @@ module ActsAsApi
|
|
23
23
|
# automatically
|
24
24
|
attr_accessor_with_default :default_root, :record
|
25
25
|
|
26
|
+
# If true a json response will be automatically wrapped into
|
27
|
+
# a JavaScript function call in case a :callback param is passed.
|
26
28
|
attr_accessor_with_default :allow_jsonp_callback, false
|
27
29
|
|
30
|
+
# If true the jsonp function call will get the http status passed
|
31
|
+
# as a second parameter
|
28
32
|
attr_accessor_with_default :add_http_status_to_jsonp_response, true
|
29
33
|
|
30
34
|
end
|
data/lib/acts_as_api/version.rb
CHANGED
data/lib/acts_as_api.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
require 'set'
|
2
1
|
require 'active_model'
|
3
2
|
require 'active_support/core_ext/class'
|
4
3
|
|
5
4
|
$:.unshift(File.dirname(__FILE__)) unless
|
6
5
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
7
6
|
|
8
|
-
|
9
|
-
|
7
|
+
require "acts_as_api/array"
|
8
|
+
require "acts_as_api/rails_renderer"
|
10
9
|
|
11
10
|
# acts_as_api is a gem that aims to make the construction of JSON and XML
|
12
11
|
# responses in rails 3 easy and fun.
|
@@ -67,7 +67,7 @@ describe UsersController, :orm => :active_record do
|
|
67
67
|
get :index, :format => 'json', :api_template => :name_only
|
68
68
|
end
|
69
69
|
|
70
|
-
it "should have a root node named users" do
|
70
|
+
it "should have a root node named users" do
|
71
71
|
response_body_json.should have_key("users")
|
72
72
|
end
|
73
73
|
|
@@ -93,7 +93,7 @@ describe UsersController, :orm => :active_record do
|
|
93
93
|
get :show, :format => 'json', :api_template => :name_only, :id => @luke.id
|
94
94
|
end
|
95
95
|
|
96
|
-
it "should have a root node named user" do
|
96
|
+
it "should have a root node named user" do
|
97
97
|
response_body_json.should have_key("user")
|
98
98
|
end
|
99
99
|
|
@@ -163,7 +163,7 @@ describe UsersController, :orm => :active_record do
|
|
163
163
|
get :index, :format => 'json', :api_template => :name_only, :callback => @callback
|
164
164
|
end
|
165
165
|
|
166
|
-
it "should wrap the response in the callback" do
|
166
|
+
it "should wrap the response in the callback" do
|
167
167
|
response_body_jsonp(@callback).should_not be_nil
|
168
168
|
end
|
169
169
|
|
@@ -175,7 +175,7 @@ describe UsersController, :orm => :active_record do
|
|
175
175
|
get :show, :format => 'json', :api_template => :name_only, :id => @luke.id, :callback => @callback
|
176
176
|
end
|
177
177
|
|
178
|
-
it "should wrap the response in the callback" do
|
178
|
+
it "should wrap the response in the callback" do
|
179
179
|
response_body_jsonp(@callback).should_not be_nil
|
180
180
|
end
|
181
181
|
|
@@ -184,5 +184,4 @@ describe UsersController, :orm => :active_record do
|
|
184
184
|
end
|
185
185
|
end
|
186
186
|
|
187
|
-
|
188
187
|
end
|
@@ -0,0 +1,284 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
2
|
+
|
3
|
+
describe ActsAsApi::Base do
|
4
|
+
|
5
|
+
describe "including an association in the api template", :orm => :active_record do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
setup_models
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:each) do
|
12
|
+
clean_up
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "which doesn't acts_as_api" do
|
16
|
+
|
17
|
+
before(:each) do
|
18
|
+
@response = @luke.as_api_response(:include_tasks)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns a hash" do
|
22
|
+
@response.should be_kind_of(Hash)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns the correct number of fields" do
|
26
|
+
@response.should have(1).key
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns all specified fields" do
|
30
|
+
@response.keys.should include(:tasks)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "returns the correct values for the specified fields" do
|
34
|
+
@response[:tasks].should be_an Array
|
35
|
+
@response[:tasks].should have(3).tasks
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should contain the associated sub models" do
|
39
|
+
@response[:tasks].should include(@destroy_deathstar, @study_with_yoda, @win_rebellion)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "which does acts_as_api" do
|
44
|
+
|
45
|
+
context "has_many" do
|
46
|
+
|
47
|
+
before(:each) do
|
48
|
+
Task.acts_as_api
|
49
|
+
Task.api_accessible :include_tasks do |t|
|
50
|
+
t.add :heading
|
51
|
+
t.add :done
|
52
|
+
end
|
53
|
+
@response = @luke.as_api_response(:include_tasks)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "returns a hash" do
|
57
|
+
@response.should be_kind_of(Hash)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "returns the correct number of fields" do
|
61
|
+
@response.should have(1).key
|
62
|
+
end
|
63
|
+
|
64
|
+
it "returns all specified fields" do
|
65
|
+
@response.keys.should include(:tasks)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "returns the correct values for the specified fields" do
|
69
|
+
@response[:tasks].should be_an Array
|
70
|
+
@response[:tasks].should have(3).tasks
|
71
|
+
end
|
72
|
+
|
73
|
+
it "contains the associated child models with the determined api template" do
|
74
|
+
@response[:tasks].each do |task|
|
75
|
+
task.keys.should include(:heading, :done)
|
76
|
+
task.keys.should have(2).attributes
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "contains the correct data of the child models" do
|
81
|
+
task_hash = [ @destroy_deathstar, @study_with_yoda, @win_rebellion ].collect{|t| { :done => t.done, :heading => t.heading } }
|
82
|
+
@response[:tasks].should eql task_hash
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "has_one" do
|
87
|
+
|
88
|
+
before(:each) do
|
89
|
+
Profile.acts_as_api
|
90
|
+
Profile.api_accessible :include_profile do |t|
|
91
|
+
t.add :avatar
|
92
|
+
t.add :homepage
|
93
|
+
end
|
94
|
+
@response = @luke.as_api_response(:include_profile)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "returns a hash" do
|
98
|
+
@response.should be_kind_of(Hash)
|
99
|
+
end
|
100
|
+
|
101
|
+
it "returns the correct number of fields" do
|
102
|
+
@response.should have(1).key
|
103
|
+
end
|
104
|
+
|
105
|
+
it "returns all specified fields" do
|
106
|
+
@response.keys.should include(:profile)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "returns the correct values for the specified fields" do
|
110
|
+
@response[:profile].should be_a Hash
|
111
|
+
@response[:profile].should have(2).attributes
|
112
|
+
end
|
113
|
+
|
114
|
+
it "contains the associated child models with the determined api template" do
|
115
|
+
@response[:profile].keys.should include(:avatar, :homepage)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "contains the correct data of the child models" do
|
119
|
+
profile_hash = { :avatar => @luke.profile.avatar, :homepage => @luke.profile.homepage }
|
120
|
+
@response[:profile].should eql profile_hash
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "which does acts_as_api, but with using another template name" do
|
127
|
+
|
128
|
+
before(:each) do
|
129
|
+
Task.acts_as_api
|
130
|
+
Task.api_accessible :other_template do |t|
|
131
|
+
t.add :description
|
132
|
+
t.add :time_spent
|
133
|
+
end
|
134
|
+
@response = @luke.as_api_response(:other_sub_template)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "returns a hash" do
|
138
|
+
@response.should be_kind_of(Hash)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "returns the correct number of fields" do
|
142
|
+
@response.should have(2).keys
|
143
|
+
end
|
144
|
+
|
145
|
+
it "returns all specified fields" do
|
146
|
+
@response.keys.should include(:first_name)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "returns the correct values for the specified fields" do
|
150
|
+
@response.values.should include(@luke.first_name)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "returns all specified fields" do
|
154
|
+
@response.keys.should include(:tasks)
|
155
|
+
end
|
156
|
+
|
157
|
+
it "returns the correct values for the specified fields" do
|
158
|
+
@response[:tasks].should be_an Array
|
159
|
+
@response[:tasks].should have(3).tasks
|
160
|
+
end
|
161
|
+
|
162
|
+
it "contains the associated child models with the determined api template" do
|
163
|
+
@response[:tasks].each do |task|
|
164
|
+
task.keys.should include(:description, :time_spent)
|
165
|
+
task.keys.should have(2).attributes
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it "contains the correct data of the child models" do
|
170
|
+
task_hash = [ @destroy_deathstar, @study_with_yoda, @win_rebellion ].collect{|t| { :description => t.description, :time_spent => t.time_spent } }
|
171
|
+
@response[:tasks].should eql task_hash
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "that is scoped" do
|
176
|
+
|
177
|
+
before(:each) do
|
178
|
+
# extend task model with scope
|
179
|
+
class Task < ActiveRecord::Base
|
180
|
+
scope :completed, where(:done => true)
|
181
|
+
end
|
182
|
+
Task.acts_as_api
|
183
|
+
Task.api_accessible :include_completed_tasks do |t|
|
184
|
+
t.add :heading
|
185
|
+
t.add :done
|
186
|
+
end
|
187
|
+
|
188
|
+
@response = @luke.as_api_response(:include_completed_tasks)
|
189
|
+
end
|
190
|
+
|
191
|
+
it "returns a hash" do
|
192
|
+
@response.should be_kind_of(Hash)
|
193
|
+
end
|
194
|
+
|
195
|
+
it "returns the correct number of fields" do
|
196
|
+
@response.should have(1).key
|
197
|
+
end
|
198
|
+
|
199
|
+
it "returns all specified fields" do
|
200
|
+
@response.keys.should include(:completed_tasks)
|
201
|
+
end
|
202
|
+
|
203
|
+
it "returns the correct values for the specified fields" do
|
204
|
+
@response[:completed_tasks].should be_an Array
|
205
|
+
@response[:completed_tasks].should have(2).tasks
|
206
|
+
end
|
207
|
+
|
208
|
+
it "contains the associated child models with the determined api template" do
|
209
|
+
@response[:completed_tasks].each do |task|
|
210
|
+
task.keys.should include(:heading, :done)
|
211
|
+
task.keys.should have(2).attributes
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
it "contains the correct data of the child models" do
|
216
|
+
task_hash = [ @destroy_deathstar, @study_with_yoda ].collect{|t| { :done => t.done, :heading => t.heading } }
|
217
|
+
@response[:completed_tasks].should eql task_hash
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "handling nil values" do
|
222
|
+
|
223
|
+
context "has_many" do
|
224
|
+
|
225
|
+
before(:each) do
|
226
|
+
Task.acts_as_api
|
227
|
+
Task.api_accessible :include_tasks do |t|
|
228
|
+
t.add :heading
|
229
|
+
t.add :done
|
230
|
+
end
|
231
|
+
@response = @han.as_api_response(:include_tasks)
|
232
|
+
end
|
233
|
+
|
234
|
+
it "returns a hash" do
|
235
|
+
@response.should be_kind_of(Hash)
|
236
|
+
end
|
237
|
+
|
238
|
+
it "returns the correct number of fields" do
|
239
|
+
@response.should have(1).key
|
240
|
+
end
|
241
|
+
|
242
|
+
it "returns all specified fields" do
|
243
|
+
@response.keys.should include(:tasks)
|
244
|
+
end
|
245
|
+
|
246
|
+
it "returns the correct values for the specified fields" do
|
247
|
+
@response[:tasks].should be_kind_of(Array)
|
248
|
+
end
|
249
|
+
|
250
|
+
it "contains no associated child models" do
|
251
|
+
@response[:tasks].should have(0).items
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|
256
|
+
context "has one" do
|
257
|
+
before(:each) do
|
258
|
+
Profile.acts_as_api
|
259
|
+
Profile.api_accessible :include_profile do |t|
|
260
|
+
t.add :avatar
|
261
|
+
t.add :homepage
|
262
|
+
end
|
263
|
+
@response = @han.as_api_response(:include_profile)
|
264
|
+
end
|
265
|
+
|
266
|
+
it "returns a hash" do
|
267
|
+
@response.should be_kind_of(Hash)
|
268
|
+
end
|
269
|
+
|
270
|
+
it "returns the correct number of fields" do
|
271
|
+
@response.should have(1).key
|
272
|
+
end
|
273
|
+
|
274
|
+
it "returns all specified fields" do
|
275
|
+
@response.keys.should include(:profile)
|
276
|
+
end
|
277
|
+
|
278
|
+
it "returns nil for the association" do
|
279
|
+
@response[:profile].should be_nil
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|