acts_as_api 0.3.5 → 0.3.6

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.
Files changed (54) hide show
  1. data/Gemfile +1 -1
  2. data/History.txt +5 -0
  3. data/README.rdoc +9 -2
  4. data/Rakefile +15 -1
  5. data/acts_as_api.gemspec +1 -0
  6. data/examples/introduction/index.html +7 -6
  7. data/examples/introduction/index.rb +9 -8
  8. data/lib/acts_as_api.rb +12 -5
  9. data/lib/acts_as_api/adapters.rb +5 -0
  10. data/lib/acts_as_api/adapters/mongoid.rb +11 -0
  11. data/lib/acts_as_api/array.rb +4 -8
  12. data/lib/acts_as_api/responder.rb +40 -0
  13. data/lib/acts_as_api/version.rb +1 -1
  14. data/spec/controllers/respond_with_users_controller_spec.rb +30 -2
  15. data/spec/controllers/users_controller_spec.rb +17 -235
  16. data/spec/models/active_record_spec.rb +28 -0
  17. data/spec/models/mongoid_spec.rb +28 -0
  18. data/spec/rails_app/app/controllers/respond_with_users_controller.rb +19 -8
  19. data/spec/rails_app/app/controllers/users_controller.rb +13 -4
  20. data/spec/rails_app/app/models/mongo_profile.rb +10 -0
  21. data/spec/rails_app/app/models/mongo_task.rb +12 -0
  22. data/spec/rails_app/app/models/mongo_untouched.rb +7 -0
  23. data/spec/rails_app/app/models/mongo_user.rb +149 -0
  24. data/spec/rails_app/app/models/user.rb +6 -6
  25. data/spec/rails_app/config/initializers/acts_as_api_mongoid.rb +6 -0
  26. data/spec/rails_app/config/mongoid.yml +23 -0
  27. data/spec/support/controller_examples.rb +246 -0
  28. data/spec/support/it_supports.rb +3 -0
  29. data/spec/support/model_examples/associations.rb +272 -0
  30. data/spec/support/model_examples/closures.rb +49 -0
  31. data/spec/support/model_examples/conditional_if.rb +165 -0
  32. data/spec/support/model_examples/conditional_unless.rb +165 -0
  33. data/spec/support/model_examples/enabled.rb +10 -0
  34. data/spec/support/model_examples/extending.rb +112 -0
  35. data/spec/support/model_examples/methods.rb +23 -0
  36. data/spec/support/model_examples/renaming.rb +50 -0
  37. data/spec/support/model_examples/simple.rb +23 -0
  38. data/spec/support/model_examples/sub_nodes.rb +105 -0
  39. data/spec/support/model_examples/undefined.rb +7 -0
  40. data/spec/support/model_examples/untouched.rb +13 -0
  41. data/spec/support/simple_fixtures.rb +39 -8
  42. metadata +67 -28
  43. data/spec/models/base/associations_spec.rb +0 -284
  44. data/spec/models/base/closures_spec.rb +0 -62
  45. data/spec/models/base/conditional_if_spec.rb +0 -178
  46. data/spec/models/base/conditional_unless_spec.rb +0 -178
  47. data/spec/models/base/enabled_spec.rb +0 -15
  48. data/spec/models/base/extending_spec.rb +0 -125
  49. data/spec/models/base/methods_spec.rb +0 -33
  50. data/spec/models/base/renaming_spec.rb +0 -63
  51. data/spec/models/base/simple_spec.rb +0 -33
  52. data/spec/models/base/sub_nodes_spec.rb +0 -118
  53. data/spec/models/base/undefined_spec.rb +0 -20
  54. data/spec/models/base/untouched_spec.rb +0 -18
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRecord, :orm => "active_record" do
4
+
5
+ before(:each) do
6
+ setup_active_record_models
7
+ end
8
+
9
+ after(:each) do
10
+ clean_up_active_record_models
11
+ end
12
+
13
+ describe :act_as_api do
14
+ it_supports "including an association in the api template"
15
+ it_supports "calling a closure in the api template"
16
+ it_supports "conditional if statements"
17
+ it_supports "conditional unless statements"
18
+ it_supports "acts_as_api is enabled"
19
+ it_supports "extending a given api template"
20
+ it_supports "calling a method in the api template"
21
+ it_supports "renaming"
22
+ it_supports "listing attributes in the api template"
23
+ it_supports "creating a sub hash in the api template"
24
+ it_supports "trying to render an api template that is not defined"
25
+ it_supports "untouched models"
26
+ end
27
+
28
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid, :orm => "mongoid" do
4
+
5
+ before(:each) do
6
+ setup_mongoid_models
7
+ end
8
+
9
+ after(:each) do
10
+ clean_up_mongoid_models
11
+ end
12
+
13
+ describe :act_as_api do
14
+ it_supports "including an association in the api template"
15
+ it_supports "calling a closure in the api template"
16
+ it_supports "conditional if statements"
17
+ it_supports "conditional unless statements"
18
+ it_supports "acts_as_api is enabled"
19
+ it_supports "extending a given api template"
20
+ it_supports "calling a method in the api template"
21
+ it_supports "renaming"
22
+ it_supports "listing attributes in the api template"
23
+ it_supports "creating a sub hash in the api template"
24
+ it_supports "trying to render an api template that is not defined"
25
+ it_supports "untouched models"
26
+ end
27
+
28
+ end
@@ -1,15 +1,26 @@
1
1
  class RespondWithUsersController < ApplicationController
2
-
2
+
3
3
  respond_to :json, :xml
4
+
5
+ self.responder = ActsAsApi::Responder
4
6
 
7
+ before_filter do
8
+ if params[:orm] == :active_record
9
+ @user_model = User
10
+ elsif params[:orm] == :mongoid
11
+ @user_model = MongoUser
12
+ end
13
+ end
14
+
5
15
  def index
6
- @users = User.all
7
- respond_with @users, :api_template => params[:api_template].to_sym
16
+ @users = @user_model.all
17
+ respond_with @users, :api_template => params[:api_template].to_sym, :root => :users
8
18
  end
9
-
19
+
10
20
  def show
11
- @user = User.find(params[:id])
12
- respond_with @user, :api_template => params[:api_template].to_sym
13
- end
14
-
21
+ @user = @user_model.find(params[:id])
22
+ # :root => :user is only used here because we need it for the node name of the MongoUser model
23
+ respond_with @user, :api_template => params[:api_template].to_sym, :root => :user
24
+ end
25
+
15
26
  end
@@ -1,7 +1,15 @@
1
1
  class UsersController < ApplicationController
2
2
 
3
+ before_filter do
4
+ if params[:orm] == :active_record
5
+ @user_model = User
6
+ elsif params[:orm] == :mongoid
7
+ @user_model = MongoUser
8
+ end
9
+ end
10
+
3
11
  def index
4
- @users = User.all
12
+ @users = @user_model.all
5
13
 
6
14
  respond_to do |format|
7
15
  format.xml { render_for_api params[:api_template].to_sym, :xml => @users, :root => :users }
@@ -10,11 +18,12 @@ class UsersController < ApplicationController
10
18
  end
11
19
 
12
20
  def show
13
- @user = User.find(params[:id])
21
+ @user = @user_model.find(params[:id])
14
22
 
15
23
  respond_to do |format|
16
- format.xml { render_for_api params[:api_template].to_sym, :xml => @user }
17
- format.json { render_for_api params[:api_template].to_sym, :json => @user }
24
+ # :root => :user is only used here because we need it for the node name of the MongoUser model
25
+ format.xml { render_for_api params[:api_template].to_sym, :xml => @user, :root => :user }
26
+ format.json { render_for_api params[:api_template].to_sym, :json => @user, :root => :user }
18
27
  end
19
28
  end
20
29
 
@@ -0,0 +1,10 @@
1
+ class MongoProfile
2
+ include Mongoid::Document
3
+
4
+ field :avatar, :type => String
5
+ field :homepage, :type => String
6
+ field :created_at, :type => DateTime
7
+ field :updated_at, :type => DateTime
8
+
9
+ embedded_in :user, :class_name => "MongoUser", :inverse_of => :profile
10
+ end
@@ -0,0 +1,12 @@
1
+ class MongoTask
2
+ include Mongoid::Document
3
+
4
+ field :heading, :type => String
5
+ field :description, :type => String
6
+ field :time_spent, :type => Integer
7
+ field :done, :type => Boolean
8
+ field :created_at, :type => DateTime
9
+ field :updated_at, :type => DateTime
10
+
11
+ embedded_in :user, :class_name => "MongoUser", :inverse_of => :task
12
+ end
@@ -0,0 +1,7 @@
1
+ class MongoUntouched
2
+ include Mongoid::Document
3
+
4
+ field :nothing, :type => String
5
+ field :created_at, :type => DateTime
6
+ field :updated_at, :type => DateTime
7
+ end
@@ -0,0 +1,149 @@
1
+ class MongoUser
2
+
3
+ include Mongoid::Document
4
+
5
+ field :first_name, :type => String
6
+ field :last_name, :type => String
7
+ field :age, :type => Integer
8
+ field :active, :type => Boolean
9
+ field :created_at, :type => DateTime
10
+ field :updated_at, :type => DateTime
11
+
12
+ embeds_one :profile, :class_name => "MongoProfile", :inverse_of => :user
13
+ embeds_many :tasks, :class_name => "MongoTask", :inverse_of => :user
14
+
15
+ acts_as_api
16
+
17
+ api_accessible :name_only do |t|
18
+ t.add :first_name
19
+ t.add :last_name
20
+ end
21
+
22
+ api_accessible :only_full_name do |t|
23
+ t.add :full_name
24
+ end
25
+
26
+ api_accessible :rename_last_name do |t|
27
+ t.add :last_name, :as => :family_name
28
+ end
29
+
30
+ api_accessible :rename_full_name do |t|
31
+ t.add :full_name, :as => :other_full_name
32
+ end
33
+
34
+ api_accessible :with_former_value do |t|
35
+ t.add :first_name
36
+ t.add :last_name
37
+ end
38
+
39
+ api_accessible :age_and_first_name, :extend => :with_former_value do |t|
40
+ t.add :age
41
+ t.remove :last_name
42
+ end
43
+
44
+ api_accessible :calling_a_proc do |t|
45
+ t.add Proc.new{|model| model.full_name.upcase }, :as => :all_caps_name
46
+ t.add Proc.new{|model| Time.now.class.to_s }, :as => :without_param
47
+ end
48
+
49
+ api_accessible :calling_a_lambda do |t|
50
+ t.add lambda{|model| model.full_name.upcase }, :as => :all_caps_name
51
+ t.add lambda{|model| Time.now.class.to_s }, :as => :without_param
52
+ end
53
+ api_accessible :include_tasks do |t|
54
+ t.add :tasks
55
+ end
56
+
57
+ api_accessible :include_profile do |t|
58
+ t.add :profile
59
+ end
60
+
61
+ api_accessible :other_sub_template do |t|
62
+ t.add :first_name
63
+ t.add :tasks, :template => :other_template
64
+ end
65
+
66
+ api_accessible :include_completed_tasks do |t|
67
+ t.add "tasks.completed.all", :as => :completed_tasks
68
+ end
69
+
70
+ api_accessible :sub_node do |t|
71
+ t.add Hash[:foo => :say_something], :as => :sub_nodes
72
+ end
73
+
74
+ api_accessible :nested_sub_node do |t|
75
+ t.add Hash[:foo, Hash[:bar, :last_name]], :as => :sub_nodes
76
+ end
77
+
78
+ api_accessible :nested_sub_hash do |t|
79
+ t.add :sub_hash
80
+ end
81
+
82
+ api_accessible :if_over_thirty do |t|
83
+ t.add :first_name
84
+ t.add :last_name, :if => :over_thirty?
85
+ end
86
+
87
+ api_accessible :if_returns_nil do |t|
88
+ t.add :first_name
89
+ t.add :last_name, :if => :return_nil
90
+ end
91
+
92
+ api_accessible :if_over_thirty_proc do |t|
93
+ t.add :first_name
94
+ t.add :last_name, :if => lambda{|u| u.over_thirty? }
95
+ end
96
+
97
+ api_accessible :if_returns_nil_proc do |t|
98
+ t.add :first_name
99
+ t.add :last_name, :if => lambda{|u| nil }
100
+ end
101
+
102
+ api_accessible :unless_under_thirty do |t|
103
+ t.add :first_name
104
+ t.add :last_name, :unless => :under_thirty?
105
+ end
106
+
107
+ api_accessible :unless_returns_nil do |t|
108
+ t.add :first_name
109
+ t.add :last_name, :unless => :return_nil
110
+ end
111
+
112
+ api_accessible :unless_under_thirty_proc do |t|
113
+ t.add :first_name
114
+ t.add :last_name, :unless => lambda{|u| u.under_thirty? }
115
+ end
116
+
117
+ api_accessible :unless_returns_nil_proc do |t|
118
+ t.add :first_name
119
+ t.add :last_name, :unless => lambda{|u| nil }
120
+ end
121
+
122
+ def over_thirty?
123
+ age > 30
124
+ end
125
+
126
+ def under_thirty?
127
+ age < 30
128
+ end
129
+
130
+ def return_nil
131
+ nil
132
+ end
133
+
134
+ def full_name
135
+ '' << first_name.to_s << ' ' << last_name.to_s
136
+ end
137
+
138
+ def say_something
139
+ "something"
140
+ end
141
+
142
+ def sub_hash
143
+ {
144
+ :foo => "bar",
145
+ :hello => "world"
146
+ }
147
+ end
148
+
149
+ end
@@ -35,14 +35,14 @@ class User < ActiveRecord::Base
35
35
 
36
36
  api_accessible :calling_a_proc do |t|
37
37
  t.add Proc.new{|model| model.full_name.upcase }, :as => :all_caps_name
38
- t.add Proc.new{ Time.now.class.to_s }, :as => :without_param
38
+ t.add Proc.new{|model| Time.now.class.to_s }, :as => :without_param
39
39
  end
40
40
 
41
41
  api_accessible :calling_a_lambda do |t|
42
42
  t.add lambda{|model| model.full_name.upcase }, :as => :all_caps_name
43
- t.add lambda{ Time.now.class.to_s }, :as => :without_param
43
+ t.add lambda{|model| Time.now.class.to_s }, :as => :without_param
44
44
  end
45
- User.api_accessible :include_tasks do |t|
45
+ api_accessible :include_tasks do |t|
46
46
  t.add :tasks
47
47
  end
48
48
 
@@ -88,7 +88,7 @@ class User < ActiveRecord::Base
88
88
 
89
89
  api_accessible :if_returns_nil_proc do |t|
90
90
  t.add :first_name
91
- t.add :last_name, :if => lambda{ nil }
91
+ t.add :last_name, :if => lambda{|u| nil }
92
92
  end
93
93
 
94
94
  api_accessible :unless_under_thirty do |t|
@@ -108,7 +108,7 @@ class User < ActiveRecord::Base
108
108
 
109
109
  api_accessible :unless_returns_nil_proc do |t|
110
110
  t.add :first_name
111
- t.add :last_name, :unless => lambda{ nil }
111
+ t.add :last_name, :unless => lambda{|u| nil }
112
112
  end
113
113
 
114
114
  def over_thirty?
@@ -138,4 +138,4 @@ class User < ActiveRecord::Base
138
138
  }
139
139
  end
140
140
 
141
- end
141
+ end
@@ -0,0 +1,6 @@
1
+ # At the moment we need to include the Mongoid adapter here
2
+ # in the initializers, as it doesn't get recognized in the
3
+ # lib itself!
4
+ if defined?(Mongoid::Document)
5
+ Mongoid::Document.send :include, ActsAsApi::Adapters::Mongoid
6
+ end
@@ -0,0 +1,23 @@
1
+ defaults: &defaults
2
+ host: localhost
3
+ # slaves:
4
+ # - host: slave1.local
5
+ # port: 27018
6
+ # - host: slave2.local
7
+ # port: 27019
8
+
9
+ development:
10
+ <<: *defaults
11
+ database: acts_as_api_example_development
12
+
13
+ test:
14
+ <<: *defaults
15
+ database: acts_as_api_example_test
16
+
17
+ # set these environment variables on your prod server
18
+ production:
19
+ host: <%= ENV['MONGOID_HOST'] %>
20
+ port: <%= ENV['MONGOID_PORT'] %>
21
+ username: <%= ENV['MONGOID_USERNAME'] %>
22
+ password: <%= ENV['MONGOID_PASSWORD'] %>
23
+ database: <%= ENV['MONGOID_DATABASE'] %>
@@ -0,0 +1,246 @@
1
+ shared_examples_for "a controller with ActsAsApi responses" do
2
+
3
+ include ApiTestHelpers
4
+
5
+ describe 'xml responses' do
6
+
7
+ describe 'get all users' do
8
+
9
+ before(:each) do
10
+ get :index, :format => 'xml', :api_template => :name_only, :orm => @orm_for_testing
11
+ end
12
+
13
+ it "should have a root node named users" do
14
+ response_body.should have_selector("users")
15
+ end
16
+
17
+ it "should contain all users" do
18
+ response_body.should have_selector("users > user") do |users|
19
+ users.size.should eql(3)
20
+ end
21
+ end
22
+
23
+ it "should contain the specified attributes" do
24
+ response_body.should have_selector("users > user > first-name")
25
+ response_body.should have_selector("users > user > last-name")
26
+ end
27
+
28
+ end
29
+
30
+ describe 'get a single user' do
31
+
32
+ before(:each) do
33
+ get :show, :format => 'xml', :api_template => :name_only, :id => @luke.id, :orm => @orm_for_testing
34
+ end
35
+
36
+ it "should have a root node named user" do
37
+ response_body.should have_selector("user")
38
+ end
39
+
40
+ it "should contain the specified attributes" do
41
+ response_body.should have_selector("user > first-name")
42
+ response_body.should have_selector("user > last-name")
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+
49
+
50
+ describe 'json responses' do
51
+
52
+ describe 'get all users' do
53
+
54
+ before(:each) do
55
+ get :index, :format => 'json', :api_template => :name_only, :orm => @orm_for_testing
56
+ end
57
+
58
+ it "should have a root node named users" do
59
+ response_body_json.should have_key("users")
60
+ end
61
+
62
+ it "should contain all users" do
63
+ response_body_json["users"].should be_a(Array)
64
+ end
65
+
66
+ it "should contain the specified attributes" do
67
+ response_body_json["users"].first.should have_key("first_name")
68
+ response_body_json["users"].first.should have_key("last_name")
69
+ end
70
+
71
+ it "should contain the specified values" do
72
+ response_body_json["users"].first["first_name"].should eql("Luke")
73
+ response_body_json["users"].first["last_name"].should eql("Skywalker")
74
+ end
75
+
76
+ end
77
+
78
+ describe 'get a single user' do
79
+
80
+ before(:each) do
81
+ get :show, :format => 'json', :api_template => :name_only, :id => @luke.id, :orm => @orm_for_testing
82
+ end
83
+
84
+ it "should have a root node named user" do
85
+ response_body_json.should have_key("user")
86
+ end
87
+
88
+ it "should contain the specified attributes" do
89
+ response_body_json["user"].should have_key("first_name")
90
+ response_body_json["user"].should have_key("last_name")
91
+ end
92
+
93
+ it "should contain the specified values" do
94
+ response_body_json["user"]["first_name"].should eql("Luke")
95
+ response_body_json["user"]["last_name"].should eql("Skywalker")
96
+ end
97
+
98
+ end
99
+
100
+ describe 'get a single user with a nil profile' do
101
+
102
+ before(:each) do
103
+ @profile_model.acts_as_api
104
+ @profile_model.api_accessible :include_profile do |t|
105
+ t.add :avatar
106
+ t.add :homepage
107
+ end
108
+
109
+ get :show, :format => 'json', :api_template => :include_profile, :id => @han.id, :orm => @orm_for_testing
110
+ end
111
+
112
+ it "should have a root node named user" do
113
+ response_body_json.should have_key("user")
114
+ end
115
+
116
+ it "should contain the specified attributes" do
117
+ response_body_json["user"].should have(1).keys
118
+ response_body_json["user"].should have_key("profile")
119
+ end
120
+
121
+ it "should contain the specified values" do
122
+ response_body_json["user"]["profile"].should be_nil
123
+ end
124
+
125
+ end
126
+
127
+ end
128
+
129
+ describe 'Rails 3 default style json responses' do
130
+
131
+ before(:each) do
132
+ @org_include_root_in_json_collections = ActsAsApi::Config.include_root_in_json_collections
133
+ ActsAsApi::Config.include_root_in_json_collections = true
134
+ end
135
+
136
+ after(:each) do
137
+ ActsAsApi::Config.include_root_in_json_collections = @org_include_root_in_json_collections
138
+ end
139
+
140
+ describe 'get all users' do
141
+
142
+ before(:each) do
143
+ get :index, :format => 'json', :api_template => :name_only, :orm => @orm_for_testing
144
+ end
145
+
146
+ it "should have a root node named users" do
147
+ response_body_json.should have_key("users")
148
+ end
149
+
150
+ it "should contain all users" do
151
+ response_body_json["users"].should be_a(Array)
152
+ end
153
+
154
+ it "should contain the specified attributes" do
155
+ response_body_json["users"].first["user"].should have_key("first_name")
156
+ response_body_json["users"].first["user"].should have_key("last_name")
157
+ end
158
+
159
+ it "contains the user root nodes" do
160
+ response_body_json["users"].collect(&:keys).flatten.uniq.should eql(["user"])
161
+ end
162
+
163
+ it "should contain the specified values" do
164
+ response_body_json["users"].first["user"]["first_name"].should eql("Luke")
165
+ response_body_json["users"].first["user"]["last_name"].should eql("Skywalker")
166
+ end
167
+
168
+ end
169
+
170
+ describe 'get a single user' do
171
+
172
+ before(:each) do
173
+ get :show, :format => 'json', :api_template => :name_only, :id => @luke.id, :orm => @orm_for_testing
174
+ end
175
+
176
+ it "should have a root node named user" do
177
+ response_body_json.should have_key("user")
178
+ end
179
+
180
+ it "should contain the specified attributes" do
181
+ response_body_json["user"].should have_key("first_name")
182
+ response_body_json["user"].should have_key("last_name")
183
+ end
184
+
185
+ it "should contain the specified values" do
186
+ response_body_json["user"]["first_name"].should eql("Luke")
187
+ response_body_json["user"]["last_name"].should eql("Skywalker")
188
+ end
189
+ end
190
+
191
+ end
192
+
193
+ describe 'jsonp responses with callback' do
194
+
195
+ it "should be disabled by default" do
196
+ @callback = "mycallback"
197
+ get :index, :format => 'json', :api_template => :name_only, :callback => @callback, :orm => @orm_for_testing
198
+ response_body_jsonp(@callback).should be_nil
199
+ end
200
+
201
+ describe "enabled jsonp callbacks" do
202
+
203
+ before(:each) do
204
+ @callback = "mycallback"
205
+
206
+ @user_model.acts_as_api do |config|
207
+ config.allow_jsonp_callback = true
208
+ end
209
+ end
210
+
211
+ after(:each) do
212
+ # put things back to the way they were
213
+ @user_model.acts_as_api do |config|
214
+ config.allow_jsonp_callback = false
215
+ end
216
+ end
217
+
218
+ describe 'get all users' do
219
+
220
+ before(:each) do
221
+ get :index, :format => 'json', :api_template => :name_only, :callback => @callback, :orm => @orm_for_testing
222
+ end
223
+
224
+ it "should wrap the response in the callback" do
225
+ response_body_jsonp(@callback).should_not be_nil
226
+ end
227
+
228
+ end
229
+
230
+ describe 'get a single user' do
231
+
232
+ before(:each) do
233
+ get :show, :format => 'json', :api_template => :name_only, :id => @luke.id, :callback => @callback, :orm => @orm_for_testing
234
+ end
235
+
236
+ it "should wrap the response in the callback" do
237
+ response_body_jsonp(@callback).should_not be_nil
238
+ end
239
+
240
+ end
241
+
242
+ end
243
+ end
244
+
245
+
246
+ end