api_logic 0.0.1
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/Gemfile +4 -0
- data/README.mdown +81 -0
- data/Rakefile +1 -0
- data/lib/api_logic/responder.rb +33 -0
- data/lib/api_logic/version.rb +3 -0
- data/lib/api_logic.rb +129 -0
- metadata +83 -0
data/Gemfile
ADDED
data/README.mdown
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# API Logic
|
2
|
+
|
3
|
+
A lightweight mixin for making API controllers
|
4
|
+
|
5
|
+
# Usage
|
6
|
+
|
7
|
+
Extend a controller with `ApiLogic` and call `exposes_model`
|
8
|
+
to generate the default REST actions.
|
9
|
+
|
10
|
+
class MyApiController < ApplicationController
|
11
|
+
extend ApiLogic
|
12
|
+
exposes_model Widget
|
13
|
+
respond_to :json, :xml
|
14
|
+
end
|
15
|
+
|
16
|
+
or if the controller's name looks like #{resource}ApiController then
|
17
|
+
exposes_model will automatically be called with the resource:
|
18
|
+
|
19
|
+
class CalendarApiController < ApplicationController
|
20
|
+
extend ApiLogic
|
21
|
+
respond_to :json, :xml
|
22
|
+
end
|
23
|
+
|
24
|
+
# Customization
|
25
|
+
|
26
|
+
### Responder
|
27
|
+
|
28
|
+
ApiLogic calls `respond_with` for each REST action, so you can change
|
29
|
+
how it renders by replacing the Responder:
|
30
|
+
|
31
|
+
class CalendarApiController < ApplicationController
|
32
|
+
extend ApiLogic
|
33
|
+
responder = MyResponder
|
34
|
+
respond_to :json, :xml
|
35
|
+
end
|
36
|
+
|
37
|
+
### Templates
|
38
|
+
|
39
|
+
The recommended way of customizing how a model is rendered to JSON or XML
|
40
|
+
is to supply a RABL template for the action.
|
41
|
+
|
42
|
+
### Overriding methods
|
43
|
+
|
44
|
+
You can always override one of ApiLogic's actions by defining your own, but
|
45
|
+
ApiLogic gives a few finer-grained ways of controlling its default behavior.
|
46
|
+
|
47
|
+
You can override the method `find_models` to change how the index action
|
48
|
+
fetches models. By default `find_models` looks like this:
|
49
|
+
|
50
|
+
def find_models
|
51
|
+
model_class.all
|
52
|
+
end
|
53
|
+
|
54
|
+
You can override the method `find_model` to change how the show, update, and
|
55
|
+
destroy actions look up a model for the given URL. By default `find_model` looks
|
56
|
+
like this:
|
57
|
+
|
58
|
+
def find_model
|
59
|
+
@model = model_class.find(params[:id])
|
60
|
+
instance_variable_set "@#{model_singular}", @model
|
61
|
+
end
|
62
|
+
|
63
|
+
`create_attributes` and `update_attributes` return the attributes supplied
|
64
|
+
to `model_class.create` and `@model.update_attributes` in the create and
|
65
|
+
update actions. Their default implementations are:
|
66
|
+
|
67
|
+
def create_attributes
|
68
|
+
model_params
|
69
|
+
end
|
70
|
+
|
71
|
+
def update_attributes
|
72
|
+
model_params
|
73
|
+
end
|
74
|
+
|
75
|
+
And, finally, you can change how a model's attributes are pulled out of params
|
76
|
+
by overriding `model_params`. Its default implementation looks like this:
|
77
|
+
|
78
|
+
def model_params
|
79
|
+
params[model_singular]
|
80
|
+
end
|
81
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'action_controller/metal/responder'
|
2
|
+
|
3
|
+
module ApiLogic
|
4
|
+
class Responder < ActionController::Responder
|
5
|
+
|
6
|
+
|
7
|
+
def respond
|
8
|
+
|
9
|
+
# An API controller might want to tailor its response
|
10
|
+
# with a RABL template. If a template exists, render that.
|
11
|
+
#
|
12
|
+
# Also, if the resource is nil or if it doesn't respond to
|
13
|
+
# :to_#{format}, fall back to the default render functionality.
|
14
|
+
#
|
15
|
+
template_path = File.join(controller.controller_path, controller.action_name)
|
16
|
+
if resource.nil? || !resourceful? || controller.template_exists?(template_path)
|
17
|
+
render
|
18
|
+
else
|
19
|
+
|
20
|
+
# api_behavior takes as a parameter the error it will throw if
|
21
|
+
# the resource does not respond to :to_#{format}. (Since we've
|
22
|
+
# already checked :resourceful?, this error should never be thrown,
|
23
|
+
# but just in case, we'll supply NotImplementedError.)
|
24
|
+
api_behavior(NotImplementedError)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Refer to the source of ActionController::Responder:
|
33
|
+
# https://github.com/rails/rails/blob/v3.0.3/actionpack/lib/action_controller/metal/responder.rb#L155
|
data/lib/api_logic.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
require "api_logic/version"
|
2
|
+
require "api_logic/responder"
|
3
|
+
|
4
|
+
module ApiLogic
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
included do
|
10
|
+
guess_model
|
11
|
+
|
12
|
+
def self.inherited(subclass)
|
13
|
+
super
|
14
|
+
subclass.guess_model
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
|
22
|
+
resonder = ::ApiLogic::Responder
|
23
|
+
|
24
|
+
attr_reader :model_class
|
25
|
+
alias :model :model_class
|
26
|
+
attr_reader :model_collection
|
27
|
+
attr_reader :model_singular
|
28
|
+
|
29
|
+
|
30
|
+
def guess_model
|
31
|
+
# puts "[api_logic] guessing model for #{self.name}"
|
32
|
+
if self.name =~ /(?:.*::)(.*?)ApiController/
|
33
|
+
model_name = $1.singularize
|
34
|
+
begin
|
35
|
+
exposes_model $1.singularize.constantize
|
36
|
+
rescue NameError
|
37
|
+
# puts " there is no model \"#{model_name}\""
|
38
|
+
end
|
39
|
+
else
|
40
|
+
# puts " the controller does not match the pattern /(?:.*::)(.*?)ApiController/"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def exposes_model(model_class)
|
46
|
+
# puts "[api_logic] exposing model #{model_class} on #{self.name}"
|
47
|
+
|
48
|
+
@model_class = model_class
|
49
|
+
@model_collection = model_class.name.tableize
|
50
|
+
@model_singular = @model_collection.singularize
|
51
|
+
|
52
|
+
before_filter :find_model, :only => [:show, :update, :destroy]
|
53
|
+
|
54
|
+
public
|
55
|
+
|
56
|
+
define_method :index do
|
57
|
+
collection = find_models
|
58
|
+
instance_variable_set "@#{model_collection}", collection
|
59
|
+
respond_with collection
|
60
|
+
end
|
61
|
+
|
62
|
+
define_method :show do
|
63
|
+
respond_with @model
|
64
|
+
end
|
65
|
+
|
66
|
+
define_method :create do
|
67
|
+
@model = create_model
|
68
|
+
instance_variable_set "@#{model_singular}", @model
|
69
|
+
respond_with @model
|
70
|
+
end
|
71
|
+
|
72
|
+
define_method :update do
|
73
|
+
@model.update_attributes(update_attributes)
|
74
|
+
respond_with @model
|
75
|
+
end
|
76
|
+
|
77
|
+
define_method :destroy do
|
78
|
+
@model.destroy
|
79
|
+
respond_with @model
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
def find_models
|
89
|
+
model_class.all
|
90
|
+
end
|
91
|
+
|
92
|
+
def find_model
|
93
|
+
@model = model_class.find(params[:id])
|
94
|
+
instance_variable_set "@#{model_singular}", @model
|
95
|
+
end
|
96
|
+
|
97
|
+
def create_model
|
98
|
+
model_class.create(create_attributes)
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
def create_attributes
|
103
|
+
model_params
|
104
|
+
end
|
105
|
+
|
106
|
+
def update_attributes
|
107
|
+
model_params
|
108
|
+
end
|
109
|
+
|
110
|
+
def model_params
|
111
|
+
params[model_singular]
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
def model_class
|
116
|
+
self.class.model
|
117
|
+
end
|
118
|
+
|
119
|
+
def model_collection
|
120
|
+
self.class.model_collection
|
121
|
+
end
|
122
|
+
|
123
|
+
def model_singular
|
124
|
+
self.class.model_singular
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: api_logic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Robert Lail
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-08-18 00:00:00 -05:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: activesupport
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: actionpack
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
description: Mixes in to ActionController and generates default RESTful actions automatically in a highly customizable way.
|
39
|
+
email:
|
40
|
+
- robert.lail@cph.org
|
41
|
+
executables: []
|
42
|
+
|
43
|
+
extensions: []
|
44
|
+
|
45
|
+
extra_rdoc_files: []
|
46
|
+
|
47
|
+
files:
|
48
|
+
- lib/api_logic/responder.rb
|
49
|
+
- lib/api_logic/version.rb
|
50
|
+
- lib/api_logic.rb
|
51
|
+
- Gemfile
|
52
|
+
- Rakefile
|
53
|
+
- README.mdown
|
54
|
+
has_rdoc: true
|
55
|
+
homepage: https://github.com/boblail/api_logic
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: "0"
|
75
|
+
requirements: []
|
76
|
+
|
77
|
+
rubyforge_project: api_logic
|
78
|
+
rubygems_version: 1.6.2
|
79
|
+
signing_key:
|
80
|
+
specification_version: 3
|
81
|
+
summary: A lightweight mixin for making API controllers
|
82
|
+
test_files: []
|
83
|
+
|