eac-resourcify 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/resourcify.rb +26 -0
- data/lib/resourcify/actions.rb +56 -0
- data/lib/resourcify/controller.rb +14 -0
- data/lib/resourcify/data_mapper/parents.rb +25 -0
- data/lib/resourcify/data_mapper/serialize_errors.rb +11 -0
- data/lib/resourcify/parent_relationship.rb +72 -0
- data/lib/resourcify/resource.rb +104 -0
- data/lib/resourcify/responses.rb +50 -0
- metadata +60 -0
data/lib/resourcify.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# make sure we're running inside Merb
|
2
|
+
if defined?(Merb::Plugins)
|
3
|
+
require 'extlib'
|
4
|
+
|
5
|
+
Merb::BootLoader.before_app_loads do
|
6
|
+
# require code that must be loaded before the application
|
7
|
+
require 'resourcify/data_mapper/parents'
|
8
|
+
require 'resourcify/data_mapper/serialize_errors'
|
9
|
+
::DataMapper::Model.append_extensions(Resourcify::DataMapper::Parents)
|
10
|
+
::DataMapper::Resource.append_inclusions(Resourcify::DataMapper::SerializeErrors)
|
11
|
+
|
12
|
+
require 'resourcify/controller'
|
13
|
+
require 'resourcify/resource'
|
14
|
+
require 'resourcify/actions'
|
15
|
+
require 'resourcify/responses'
|
16
|
+
require 'resourcify/parent_relationship'
|
17
|
+
Merb::Controller.send(:extend, Resourcify::Controller)
|
18
|
+
end
|
19
|
+
|
20
|
+
Merb::BootLoader.after_app_loads do
|
21
|
+
# code that can be required after the application loads
|
22
|
+
end
|
23
|
+
|
24
|
+
# Merb::Plugins.add_rakefiles "resourcify/merbtasks"
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Resourcify
|
2
|
+
module Actions
|
3
|
+
|
4
|
+
protected
|
5
|
+
|
6
|
+
# UI Actions
|
7
|
+
def new
|
8
|
+
only_provides :html
|
9
|
+
resource
|
10
|
+
render
|
11
|
+
end
|
12
|
+
|
13
|
+
def edit
|
14
|
+
only_provides :html
|
15
|
+
resource
|
16
|
+
render
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Verbs
|
22
|
+
|
23
|
+
def get
|
24
|
+
display resource
|
25
|
+
end
|
26
|
+
|
27
|
+
def put
|
28
|
+
if resource.save
|
29
|
+
put_successful
|
30
|
+
else
|
31
|
+
put_failed
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def post
|
36
|
+
if resource.save
|
37
|
+
post_successful
|
38
|
+
else
|
39
|
+
post_failed
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete
|
44
|
+
resource.destroy || raise(StandardError.new("Failed to destroy resource: #{resource.inspect}"))
|
45
|
+
delete_successful
|
46
|
+
end
|
47
|
+
|
48
|
+
# Quick compatiblity with Resourceful Routes
|
49
|
+
alias_method :index, :get
|
50
|
+
alias_method :show, :get
|
51
|
+
alias_method :destroy, :delete
|
52
|
+
alias_method :update, :put
|
53
|
+
alias_method :create, :post
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Resourcify
|
2
|
+
module DataMapper
|
3
|
+
module Parents
|
4
|
+
|
5
|
+
# FIXME Only works for single-field foreign keys
|
6
|
+
def parent_keys
|
7
|
+
parent_relationships.keys
|
8
|
+
end
|
9
|
+
|
10
|
+
# FIXME Not grabbing proper relationships
|
11
|
+
def parent_relationships
|
12
|
+
parent_relationships = {}
|
13
|
+
relationships.each do |relationship_name, relationship|
|
14
|
+
if relationship.child_model == self
|
15
|
+
parent_key = relationship.child_key.entries.first.field.to_sym
|
16
|
+
parent_relationships[parent_key] = relationship
|
17
|
+
end
|
18
|
+
end
|
19
|
+
parent_relationships
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Resourcify
|
2
|
+
module ParentRelationship
|
3
|
+
|
4
|
+
|
5
|
+
# e.g.
|
6
|
+
# class Person
|
7
|
+
# belongs_to :location
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# class Location
|
11
|
+
# has n, :people
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# access_by :location
|
15
|
+
#
|
16
|
+
# (Options)
|
17
|
+
# :collection => :person
|
18
|
+
#
|
19
|
+
def self.included(base)
|
20
|
+
base.class_eval do
|
21
|
+
class_inheritable_accessor :relationship_collections
|
22
|
+
self.relationship_collections = {}
|
23
|
+
|
24
|
+
def self.access_by(relationship, options = {})
|
25
|
+
options[:collection] ||= Extlib::Inflection.tableize(model_name_parts.last).to_sym
|
26
|
+
|
27
|
+
relationship_collections[relationship] = options[:collection]
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def owner
|
35
|
+
collection || model
|
36
|
+
end
|
37
|
+
|
38
|
+
def parent
|
39
|
+
@parent ||= parent_relationship.parent_model.get!(params[parent_key]) if parent_relationship?
|
40
|
+
end
|
41
|
+
|
42
|
+
def collection(query = {})
|
43
|
+
if parent_relationship?
|
44
|
+
if association_name = relationship_collections[parent_relationship.name]
|
45
|
+
parent.send(association_name, query)
|
46
|
+
else
|
47
|
+
raise(ArgumentError.new(
|
48
|
+
"Parent relationship #{parent_relationship.name} found, but not marked as accessible.
|
49
|
+
Specify `access_by :#{parent_relationship.name}` for this controller."
|
50
|
+
))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def relationship_collections
|
56
|
+
self.class.relationship_collections
|
57
|
+
end
|
58
|
+
|
59
|
+
def parent_relationship?
|
60
|
+
!parent_relationship.nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
def parent_relationship
|
64
|
+
@parent_relationship ||= model.parent_relationships[parent_key]
|
65
|
+
end
|
66
|
+
|
67
|
+
def parent_key
|
68
|
+
@parent_key ||= model.parent_keys.detect { |parent_key| params[parent_key] }
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Resourcify
|
2
|
+
module Resource
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
|
6
|
+
base.class_eval do
|
7
|
+
def self.model
|
8
|
+
Extlib::Inflection.constantize(model_name)
|
9
|
+
rescue NameError
|
10
|
+
raise NameError.new(
|
11
|
+
"Could not find a model named #{model_name}. Override #{self.name}.model_name with an existing class."
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def self.model_name
|
18
|
+
model_name_parts.join('::')
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.model_name_parts
|
22
|
+
name_parts = name.split('::')
|
23
|
+
model_name = name_parts.pop.singular
|
24
|
+
name_parts << model_name
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.resources_path
|
28
|
+
Extlib::Inflection.tableize(model_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
# def self.inherited(subclass)
|
36
|
+
# subclass.model = Kernel.const_get(subclass.name.singular)
|
37
|
+
# end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
# Resources
|
42
|
+
|
43
|
+
def model
|
44
|
+
self.class.model
|
45
|
+
end
|
46
|
+
|
47
|
+
def resource_url
|
48
|
+
url(self.class.resources_path.singular.to_sym, resource.key)
|
49
|
+
end
|
50
|
+
|
51
|
+
def resource_collection_url
|
52
|
+
url(self.class.resources_path.to_sym)
|
53
|
+
end
|
54
|
+
|
55
|
+
def resource
|
56
|
+
@resource ||= assign_resource_instance_variable
|
57
|
+
end
|
58
|
+
|
59
|
+
def fetch_resource
|
60
|
+
case params[:action]
|
61
|
+
when *self.class.load_actions then load_resource
|
62
|
+
when *self.class.build_actions then build_resource
|
63
|
+
else
|
64
|
+
raise ArgumentError, "Unknown resource action #{params[:action].inspect}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def build_resource
|
69
|
+
parent ? owner.build(resource_params || {}) : owner.new(resource_params || {})
|
70
|
+
end
|
71
|
+
|
72
|
+
def load_resource
|
73
|
+
params[:id] ? owner.get!(params[:id]) : owner.all
|
74
|
+
end
|
75
|
+
|
76
|
+
def resource_params
|
77
|
+
params[model.name.snake_case]
|
78
|
+
end
|
79
|
+
|
80
|
+
# ParentRelationships overrides this method.
|
81
|
+
def owner
|
82
|
+
model
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
# FIXME Rewrite
|
88
|
+
# Equivelent to @users = User.all or @user = User.get!(id)
|
89
|
+
# TODO Dynamically create method?
|
90
|
+
# def resource #{singular_name} = fetch_resource end
|
91
|
+
# def resources #{plural_name} = fetch_resource end
|
92
|
+
def assign_resource_instance_variable
|
93
|
+
fetched_resource = fetch_resource
|
94
|
+
base_name = Extlib::Inflection.underscore(
|
95
|
+
Extlib::Inflection.demodulize(self.class.name)
|
96
|
+
).downcase
|
97
|
+
instance_variable_name = fetched_resource.is_a?(Array) ? "@#{base_name}" : "@#{base_name.singular}"
|
98
|
+
instance_variable_set(instance_variable_name, fetched_resource)
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Resourcify
|
2
|
+
module Responses
|
3
|
+
|
4
|
+
# Responses
|
5
|
+
# Success
|
6
|
+
def put_successful
|
7
|
+
case content_type
|
8
|
+
when :html then redirect(resource_url)
|
9
|
+
else
|
10
|
+
self.status = 204 # No Content
|
11
|
+
''
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete_successful
|
16
|
+
case content_type
|
17
|
+
when :html then redirect(resource_collection_url)
|
18
|
+
else
|
19
|
+
self.status = 204 # No Content
|
20
|
+
''
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def post_successful
|
25
|
+
case content_type
|
26
|
+
when :html then redirect(resource_url)
|
27
|
+
else
|
28
|
+
display(resource, :status => 201, :location => resource_url) # 201 Created
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Failure 422 Unproccessable entity
|
33
|
+
def post_failed
|
34
|
+
case content_type
|
35
|
+
when :html then render(:new, :status => 422)
|
36
|
+
else
|
37
|
+
display(resource, :status => 422)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def put_failed
|
42
|
+
case content_type
|
43
|
+
when :html then render(:edit, :status => 422)
|
44
|
+
else
|
45
|
+
display(resource, :status => 422)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: eac-resourcify
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eric Chapweske
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-09-29 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Basic enhancements for making Merb controllers more resourceful. Provides reduced code duplication, nested resource support, and aims for RFC2616 compliant responses.
|
17
|
+
email: eric@slantwisedesign.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/resourcify.rb
|
26
|
+
- lib/resourcify/controller.rb
|
27
|
+
- lib/resourcify/actions.rb
|
28
|
+
- lib/resourcify/parent_relationship.rb
|
29
|
+
- lib/resourcify/resource.rb
|
30
|
+
- lib/resourcify/responses.rb
|
31
|
+
- lib/resourcify/data_mapper/parents.rb
|
32
|
+
- lib/resourcify/data_mapper/serialize_errors.rb
|
33
|
+
has_rdoc: true
|
34
|
+
homepage:
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 1.8.6
|
45
|
+
version:
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
requirements:
|
53
|
+
- Install datamapper to get full functionality out of the box.
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 1.2.0
|
56
|
+
signing_key:
|
57
|
+
specification_version: 2
|
58
|
+
summary: Resourceful merb controllers.
|
59
|
+
test_files: []
|
60
|
+
|