toast 0.9.5 → 1.0.0

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.
@@ -1,85 +0,0 @@
1
- require 'blockenspiel'
2
- require 'toast/config_dsl'
3
-
4
- module Toast
5
- module ActiveRecordExtensions
6
-
7
- # Configuration DSL
8
- def acts_as_resource &block
9
-
10
- @toast_configs ||= Array.new
11
- @toast_configs << Toast::ConfigDSL::Base.new(self)
12
-
13
- Blockenspiel.invoke( block, @toast_configs.last)
14
-
15
- # add class methods
16
- self.instance_eval do
17
-
18
- def is_resourceful_model?
19
- true
20
- end
21
-
22
- def toast_configs
23
- @toast_configs
24
- end
25
-
26
- # get a config by media type or first one if none matches
27
- def toast_config media_type
28
- @toast_configs.find do |tc|
29
- tc.media_type == media_type || tc.in_collection.media_type == media_type
30
- end || @toast_configs.first
31
- end
32
-
33
- def toast_resource_uri_prefix
34
- @toast_resource_uri_prefix ||= self.to_s.pluralize.underscore
35
- end
36
-
37
- end
38
-
39
- # add instance methods
40
- self.class_eval do
41
- # Return the path segment of the URI of this record
42
- def uri_path
43
- "/" +
44
- self.class.toast_resource_uri_prefix + "/" +
45
- self.id.to_s
46
- end
47
-
48
- # Like ActiveRecord::Base.attributes, but result Hash includes
49
- # only attributes from the list _attr_names_ plus the
50
- # associations _assoc_names_ as links and the 'self' link
51
- def represent attr_names, assoc_names, base_uri, media_type
52
- props = {}
53
-
54
- attr_names.each do |name|
55
- unless self.respond_to?(name)
56
- raise "Toast Error: Connot find instance method '#{self.class}##{name}'"
57
- end
58
- props[name] = self.send(name)
59
- end
60
-
61
- assoc_names.each do |name|
62
- props[name] = "#{base_uri}#{self.uri_path}/#{name}"
63
- end
64
-
65
- props["self"] = base_uri + self.uri_path
66
-
67
- props
68
- end
69
- end
70
- end
71
-
72
- # defaults for non resourceful-models
73
- def is_resourceful_model?
74
- false
75
- end
76
- def resourceful_model_options
77
- nil
78
- end
79
- end
80
-
81
- def self.resourceful_models
82
- Module.constants.select{ |c| (eval c).respond_to?(:toast_config)}.sort.map{|c| c.constantize}
83
- end
84
-
85
- end
@@ -1,219 +0,0 @@
1
- module Toast
2
- class Association < Resource
3
-
4
- attr_reader :model
5
-
6
- def initialize model, id, subresource_name, params, format, config, assoc_model, assoc_config_in, assoc_config_out
7
-
8
- unless config.exposed_associations.include? subresource_name
9
- raise ResourceNotFound
10
- end
11
-
12
- @model = model
13
- @record = model.find(id) rescue raise(ResourceNotFound)
14
- @assoc = subresource_name
15
- @format = format
16
- @is_collection = [:has_many, :has_and_belongs_to_many].include? @model.reflect_on_association(@assoc.to_sym).macro
17
- @config = config
18
- @associate_model = assoc_model
19
- @associate_config_in = assoc_config_in
20
- @associate_config_out = assoc_config_out
21
- @params = params
22
- end
23
-
24
- def get
25
-
26
- unless @record.class.reflect_on_all_associations.detect{|a| a.name.to_s == @assoc}
27
- raise "Toast Error: Association '#{@assoc}' not found in model '#{@record.class}'"
28
- end
29
-
30
- reflection = @model.reflect_on_association(@assoc.to_sym)
31
-
32
- if reflection.collection?
33
-
34
-
35
- if(@config.pass_params_to.include?(@assoc) and
36
- reflection.options[:extend] and
37
- reflection.options[:extend].detect{|e| e.method_defined? :find_by_params} )
38
-
39
- result, pagination_info = paginate_query( @config, @assoc,
40
- @record.send(@assoc).find_by_params(@params), @params)
41
- else
42
-
43
- result, pagination_info = paginate_query( @config, @assoc,
44
- @record.send(@assoc), @params)
45
-
46
- end
47
-
48
- raise ResourceNotFound if result.nil?
49
-
50
- {
51
- :json => result.map{|r|
52
- r.represent( @associate_config_out.in_collection.exposed_attributes,
53
- @associate_config_out.in_collection.exposed_associations,
54
- @base_uri,
55
- @associate_config_out.media_type )
56
- },
57
- :status => :ok,
58
- :content_type => @associate_config_out.in_collection.media_type,
59
- :pagination_info => pagination_info
60
- }
61
-
62
- else
63
-
64
- result =
65
- if(@config.pass_params_to.include?(@assoc) and
66
- reflection.options[:extend] and
67
- reflectin.options[:extend].detect{|e| e.method_defined? :find_by_params} )
68
- @record.send(@assoc).find_by_params(@params)
69
- else
70
- @record.send(@assoc)
71
- end
72
-
73
- raise ResourceNotFound if result.nil?
74
-
75
- {
76
- :json => result.represent( @associate_config_out.exposed_attributes,
77
- @associate_config_out.exposed_associations,
78
- @base_uri,
79
- @associate_config_out.media_type),
80
- :status => :ok,
81
- :content_type => @associate_config_out.media_type
82
- }
83
- end
84
-
85
-
86
- rescue ActiveRecord::RecordNotFound
87
- raise ResourceNotFound
88
- end
89
-
90
- def put payload, media_type
91
- raise MethodNotAllowed
92
- end
93
-
94
- def post payload, media_type
95
- raise MethodNotAllowed unless @config.writables.include? @assoc
96
-
97
- if media_type != @associate_config_in.media_type
98
- raise UnsupportedMediaType
99
- end
100
-
101
- begin
102
- payload = ActiveSupport::JSON.decode(payload).with_indifferent_access
103
- rescue
104
- raise PayloadFormatError
105
- end
106
-
107
- unless payload.is_a? Hash
108
- raise PayloadFormatError
109
- end
110
-
111
- payload.delete_if {|key,value|
112
- !@associate_config_in.writables.include?(key) or
113
- @associate_config_in.exposed_associations.include?(key)
114
- }
115
-
116
- begin
117
- reflection = @model.reflect_on_association(@assoc.to_sym)
118
-
119
- if(@config.pass_params_to.include?(@assoc) and
120
- reflection.options[:extend] and
121
- reflection.options[:extend].detect{|e| e.method_defined? :create!})
122
-
123
- record = @record.send(@assoc).create! payload, @params
124
- else
125
- record = @record.send(@assoc).create! payload
126
- end
127
- {
128
- :json => record.represent( @associate_config_out.exposed_attributes,
129
- @associate_config_out.exposed_associations,
130
- @base_uri,
131
- @associate_config_out.media_type),
132
- :location => self.base_uri + record.uri_path,
133
- :status => :created,
134
- :content_type => @associate_config_out.media_type
135
- }
136
-
137
- rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved, ActiveRecord::RecordNotUnique => e
138
- # model validation failed
139
- raise PayloadInvalid.new(e.message)
140
- end
141
- end
142
-
143
- def delete
144
- raise MethodNotAllowed
145
- end
146
-
147
- def link link_path_info
148
- slash, link_resource_name, link_id = link_path_info.split('/')
149
- link_model = Resource.get_class_by_resource_name(link_resource_name)
150
- link_record = link_model.find(link_id)
151
-
152
- reflection = @model.reflect_on_association(@assoc.to_sym)
153
-
154
- if(reflection.collection? )
155
- # has_many, hbtm
156
- if( @config.pass_params_to.include?(@assoc) and
157
- reflection.options[:extend] and
158
- reflection.options[:extend].detect{|e| e.method_defined? :<<})
159
-
160
- @record.send(@assoc).<<(link_record,@params)
161
- else
162
- @record.send(@assoc) << link_record
163
- end
164
- else
165
- # has_one, belongs_to
166
- @record.send(@assoc+"=",link_record)
167
- @record.save
168
- end
169
-
170
- {
171
- :nothing => true,
172
- :status => :no_content
173
- }
174
-
175
- rescue ActiveRecord::AssociationTypeMismatch
176
- raise Toast::ResourceNotAcceptable
177
- rescue ActiveRecord::RecordNotFound
178
- raise Toast::ResourceNotFound
179
- rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved, ActiveRecord::RecordNotUnique => e
180
- # model validation failed (join model used for linking)
181
- raise PayloadInvalid.new(e.message)
182
- end
183
-
184
- def unlink link_path_info
185
-
186
- slash, link_resource_name, link_id = link_path_info.split('/')
187
- link_model = Resource.get_class_by_resource_name(link_resource_name)
188
- link_record = link_model.find(link_id)
189
-
190
- reflection = @model.reflect_on_association(@assoc.to_sym)
191
-
192
- if @model.reflect_on_association(@assoc.to_sym).collection?
193
- # has_many, hbtm
194
- if( @config.pass_params_to.include?(@assoc) and
195
- reflection.options[:extend] and
196
- reflection.options[:extend].detect{|e| e.method_defined? :delete})
197
-
198
- @record.send(@assoc).delete(link_record,@params)
199
- else
200
- @record.send(@assoc).delete(link_record) unless link_record.nil?
201
- end
202
- else
203
-
204
- # has_one, belongs_to
205
- if @record.send(@assoc) == link_record
206
- @record.send(@assoc+"=",nil)
207
- @record.save!
208
- end
209
- end
210
-
211
- {
212
- :nothing => true,
213
- :status => :no_content
214
- }
215
- rescue ActiveRecord::RecordNotFound
216
- raise ResourceNotFound
217
- end
218
- end
219
- end
@@ -1,139 +0,0 @@
1
- module Toast
2
- class Collection < Resource
3
-
4
- attr_reader :model
5
-
6
- def initialize model, subresource_name, params, config_in, config_out
7
-
8
- subresource_name ||= "all"
9
-
10
- unless config_out.collections.include? subresource_name
11
- if subresource_name == "all"
12
- ToastController.logger.debug "\n\tToast Debug: you may want to declare 'collections :all' in model '#{model}' to enable delivery of the collection '/#{model.to_s.underscore.pluralize}'\n"
13
- end
14
- raise ResourceNotFound
15
- end
16
-
17
- @model = model
18
- @collection = subresource_name
19
- @params = params
20
- @format = params[:format]
21
- @config_out = config_out
22
- @config_in = config_in
23
- end
24
-
25
- def get
26
-
27
- unless @model.respond_to?(@collection)
28
- raise "Toast Error: Cannot find class method '#{@collection}' of model '#{@model}', which is configured in 'acts_as_resource > collections'."
29
- end
30
-
31
- # FIXME: This is a lot of hallooballoo to check if the #send
32
- # will be successful, but if it's not checked the error
33
- # message is not helpful to find the error.
34
-
35
- if @config_out.pass_params_to.include?(@collection)
36
- if @model.method(@collection).arity**2 != 1
37
- raise "Toast Error: Class method '#{@collection}' of model '#{@model}' must accept one parameter, as configured by 'acts_as_resource > pass_params_to'."
38
- end
39
-
40
- # fetch results
41
- #binding.pry if $halt
42
- records, pagination_info = paginate_query( @config_out, @collection,
43
- @model.send(@collection, @params),
44
- @params )
45
- else
46
-
47
- if @model.method(@collection).arity > 0
48
- raise "Toast Error: Class method '#{@collection}' of model '#{@model}' must not accept any parameter, as configured by 'acts_as_resource'"
49
- end
50
-
51
- records, pagination_info = paginate_query( @config_out, @collection,
52
- @model.send(@collection=='all'? 'scoped': @collection), # #scoped ?: #all would trigger query too early
53
- @params )
54
- end
55
-
56
- case @format
57
- when "html"
58
- {
59
- :template => "resources/#{@model.to_s.pluralize.underscore}",
60
- :locals => { @model.to_s.pluralize.underscore.to_sym => records,
61
- :pagination_info => pagination_info }
62
- }
63
- when "json"
64
- {
65
- :json => records.map{|r|
66
- r.represent( @config_out.in_collection.exposed_attributes,
67
- @config_out.in_collection.exposed_associations,
68
- self.base_uri,
69
- @config_out.media_type)
70
- },
71
- :status => :ok,
72
- :content_type => @config_out.in_collection.media_type,
73
- :pagination_info => pagination_info
74
- }
75
- else
76
- raise ResourceNotFound
77
- end
78
- end
79
-
80
- def put
81
- raise MethodNotAllowed
82
- end
83
-
84
- def post payload, media_type
85
- raise MethodNotAllowed unless @config_in.postable?
86
-
87
-
88
- if media_type != @config_in.media_type
89
- raise UnsupportedMediaType
90
- end
91
-
92
- begin
93
- payload = ActiveSupport::JSON.decode(payload).with_indifferent_access
94
- rescue
95
- raise PayloadFormatError
96
- end
97
- unless payload.is_a? Hash
98
- raise PayloadFormatError
99
- end
100
-
101
- payload.delete_if {|key,value|
102
- !@config_in.writables.include?(key) or
103
- @config_in.exposed_associations.include?(key)
104
- }
105
-
106
- begin
107
-
108
- record = @model.create! payload
109
-
110
- {
111
- :json => record.represent( @config_out.exposed_attributes,
112
- @config_out.exposed_associations,
113
- self.base_uri,
114
- @config_out.media_type),
115
- :location => self.base_uri + record.uri_path,
116
- :status => :created,
117
- :content_type => @config_out.media_type
118
- }
119
-
120
- rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved, ActiveRecord::RecordNotUnique => e
121
- # model validation failed
122
- raise PayloadInvalid.new(e.message)
123
- end
124
- end
125
-
126
- def delete
127
- raise MethodNotAllowed
128
- end
129
-
130
- def link l
131
- raise MethodNotAllowed
132
- end
133
-
134
- def unlink l
135
- raise MethodNotAllowed
136
- end
137
-
138
- end
139
- end
data/lib/toast/record.rb DELETED
@@ -1,123 +0,0 @@
1
- module Toast
2
- class Record < Resource
3
-
4
- attr_reader :model
5
-
6
- def initialize model, id, format, params, config_in, config_out
7
- @model = model
8
- @record = model.find(id) rescue raise(ResourceNotFound.new)
9
- @format = format
10
- @config_in = config_in
11
- @config_out = config_out
12
- @params = params
13
- end
14
-
15
- def post payload, media_type
16
- raise MethodNotAllowed
17
- end
18
-
19
- # get, put, delete, post return a Hash that can be used as
20
- # argument for ActionController#render
21
-
22
- def put payload, media_type
23
-
24
- if media_type != @config_in.media_type
25
- raise UnsupportedMediaType
26
- end
27
-
28
- begin
29
- payload = ActiveSupport::JSON.decode(payload).with_indifferent_access
30
- rescue
31
- raise PayloadFormatError
32
- end
33
-
34
- unless payload.is_a? Hash
35
- raise PayloadFormatError
36
- end
37
-
38
- # ignore all not explicitly writable attribute
39
- payload.delete_if {|key,value|
40
- !@config_in.writables.include?(key) or
41
- @config_in.exposed_associations.include?(key)
42
- }
43
-
44
- # set the virtual attributes
45
- (@config_in.writables - @record.attribute_names - @config_in.exposed_associations).each do |vattr|
46
-
47
- unless (@record.respond_to?("#{vattr}=") && @record.method("#{vattr}=").arity == 1)
48
- raise "Toast Error: Connot find setter '#{@record.class}##{vattr}='"
49
- end
50
-
51
- @record.send("#{vattr}=", payload.delete(vattr)) if payload.key?(vattr)
52
- end
53
-
54
- # mass-update for the rest
55
- if @config_in.pass_params_to.include? 'self'
56
- # parameter passing
57
- @record.update_attributes! payload, @params
58
- else
59
- @record.update_attributes! payload
60
- end
61
-
62
- {
63
- :json => @record.represent( @config_out.exposed_attributes,
64
- @config_out.exposed_associations,
65
- @base_uri,
66
- @config_out.media_type ),
67
- :status => :ok,
68
- :location => self.base_uri + @record.uri_path,
69
- :content_type => @config_out.media_type
70
- }
71
-
72
- rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotSaved, ActiveRecord::RecordNotUnique => e
73
- # model validation failed
74
- raise PayloadInvalid.new(e.message)
75
- end
76
-
77
- def get
78
- case @format
79
- when "html", "xml"
80
- {
81
- :template => "resources/#{model.to_s.underscore}",
82
- :locals => { model.to_s.underscore.to_sym => @record } # full record, view should filter
83
- }
84
- when "json"
85
- {
86
- :json => @record.represent( @config_out.exposed_attributes,
87
- @config_out.exposed_associations,
88
- @base_uri,
89
- @config_out.media_type),
90
- :status => :ok,
91
- :content_type => @config_out.media_type
92
- }
93
- else
94
- raise ResourceNotFound
95
- end
96
- end
97
-
98
- def delete
99
- raise MethodNotAllowed unless @config_out.deletable?
100
-
101
- if @record.destroy
102
- {
103
- :nothing => true,
104
- :status => :no_content
105
- }
106
- else
107
- {
108
- :nothing => true,
109
- :status => :conflict
110
- }
111
- end
112
-
113
- end
114
-
115
- def link l
116
- raise MethodNotAllowed
117
- end
118
-
119
- def unlink l
120
- raise MethodNotAllowed
121
- end
122
- end
123
- end