padrino-responders 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Kriss Kowalik
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,71 @@
1
+ == Padrino responders
2
+
3
+ This component is used to create slim controllers without unnecessery and repetitive code.
4
+
5
+ === Installation
6
+
7
+ You can install Padrino responders via rubygems:
8
+
9
+ gem install padrino-responders
10
+
11
+ Now register responders in your application:
12
+
13
+ class Avaro < Padrino::Application
14
+ register Padrino::Mailer
15
+ register Padrino::Helpers
16
+ register Padrino::Responders
17
+ ....
18
+
19
+ === Getting started
20
+
21
+ Default responder is responsible for exposing a resource to different mime
22
+ requests, usually depending on the HTTP verb. The responder is triggered when
23
+ <code>respond</code> is called. The simplest case to study is a GET request:
24
+
25
+ SampleApp.controllers :examples do
26
+ provides :html, :xml, :json
27
+
28
+ get :index do
29
+ @examples = Example.find(:all)
30
+ respond(@examples)
31
+ end
32
+ end
33
+
34
+ When a request comes in, for example for an XML response, three steps happen:
35
+
36
+ * the responder searches for a template at extensions/index.xml;
37
+ * if the template is not available, it will invoke <code>#to_xml</code> on the given resource;
38
+ * if the responder does not <code>respond_to :to_xml</code>, call <code>#to_format</code> on it.
39
+
40
+ === Builtin HTTP verb semantics
41
+
42
+ Using this responder, a POST request for creating an object could
43
+ be written as:
44
+
45
+ post :create do
46
+ @user = User.new(params[:user])
47
+ @user.save
48
+ respond(@user)
49
+ end
50
+
51
+ Which is exactly the same as:
52
+
53
+ post :create do
54
+ @user = User.new(params[:user])
55
+
56
+ if @user.save
57
+ flash[:notice] = 'User was successfully created.'
58
+ case content_type
59
+ when :html then redirect url(:users, :show, :id => @user.id)
60
+ when :xml then render :xml => @user, :status => :created, :location => url(:users, :show, :id => @user.id)
61
+ end
62
+ else
63
+ case content_type
64
+ when :html then render 'index/new'
65
+ when :xml then render :xml => @user.errors, :status => :unprocessable_entity
66
+ end
67
+ end
68
+ end
69
+
70
+ The same happens for PUT and DELETE requests.
71
+
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gemspec|
8
+ gemspec.name = "padrino-responders"
9
+ gemspec.version = "0.1.2"
10
+ gemspec.summary = "Simplified responders for Padrino framework"
11
+ gemspec.description = "This component is used to create slim controllers
12
+ without unnecessery and repetitive code."
13
+ gemspec.email = "kriss.kowalik@gmail.com"
14
+ gemspec.homepage = "http://github.com/kriss/padrino-responders"
15
+ gemspec.authors = ["Kris Kowalik"]
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler not available. Install it with: gem install jeweler"
19
+ end
20
+
@@ -0,0 +1,32 @@
1
+ require 'padrino-core'
2
+ require 'padrino-gen'
3
+ require 'padrino-helpers'
4
+
5
+ FileSet.glob_require('padrino-responders/*.rb', __FILE__)
6
+ FileSet.glob_require('padrino-responders/{helpers,notifiers}/*.rb', __FILE__)
7
+
8
+ module Padrino
9
+ ##
10
+ # This component is used to create slim controllers without unnecessery
11
+ # and repetitive code.
12
+ #
13
+ module Responders
14
+ ##
15
+ # Method used by Padrino::Application when we register the extension
16
+ #
17
+ class << self
18
+ def registered(app)
19
+ app.set :notifier, Padrino::Responders::Notifiers::FlashNotifier
20
+ app.helpers Padrino::Responders::Helpers::ControllerHelpers
21
+ app.send :include, Padrino::Responders::Default
22
+ end
23
+ alias :included :registered
24
+ end
25
+ end
26
+ end
27
+
28
+ ##
29
+ # Load our Padrino::Responders locales
30
+ #
31
+ I18n.load_path += Dir["#{File.dirname(__FILE__)}/padrino-responders/locale/**/*.yml"]
32
+
@@ -0,0 +1,168 @@
1
+ module Padrino
2
+ module Responders
3
+ # Default responder is responsible for exposing a resource to different mime
4
+ # requests, usually depending on the HTTP verb. The responder is triggered when
5
+ # <code>respond</code> is called. The simplest case to study is a GET request:
6
+ #
7
+ # SampleApp.controllers :examples do
8
+ # provides :html, :xml, :json
9
+ #
10
+ # get :index do
11
+ # @examples = Example.find(:all)
12
+ # respond(@examples)
13
+ # end
14
+ # end
15
+ #
16
+ # When a request comes in, for example for an XML response, three steps happen:
17
+ #
18
+ # 1) the responder searches for a template at extensions/index.xml;
19
+ # 2) if the template is not available, it will invoke <code>#to_xml</code> on the given resource;
20
+ # 3) if the responder does not <code>respond_to :to_xml</code>, call <code>#to_format</code> on it.
21
+ #
22
+ # === Builtin HTTP verb semantics
23
+ #
24
+ # Using this responder, a POST request for creating an object could
25
+ # be written as:
26
+ #
27
+ # post :create do
28
+ # @user = User.new(params[:user])
29
+ # @user.save
30
+ # respond(@user)
31
+ # end
32
+ #
33
+ # Which is exactly the same as:
34
+ #
35
+ # post :create do
36
+ # @user = User.new(params[:user])
37
+ #
38
+ # if @user.save
39
+ # flash[:notice] = 'User was successfully created.'
40
+ # case content_type
41
+ # when :html then redirect url(:users, :show, :id => @user.id)
42
+ # when :xml then render :xml => @user, :status => :created, :location => url(:users, :show, :id => @user.id)
43
+ # end
44
+ # else
45
+ # case content_type
46
+ # when :html then render 'index/new'
47
+ # when :xml then render :xml => @user.errors, :status => :unprocessable_entity
48
+ # end
49
+ # end
50
+ # end
51
+ #
52
+ # The same happens for PUT and DELETE requests.
53
+ #
54
+ module Default
55
+
56
+ def respond(object, location=nil) # :nodoc:
57
+ if request.put?
58
+ default_response_for_save('edit', object, location)
59
+ elsif request.post?
60
+ default_response_for_save('new', object, location)
61
+ elsif request.delete?
62
+ default_response_for_destroy(object, location)
63
+ else
64
+ default_response(object)
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ ##
71
+ # Displays default template, or if it not exists then is trying to display
72
+ # serialized object with specified response params.
73
+ #
74
+ def process_rendering_chain(type, object, params={})
75
+ render "#{controller_name}/#{action_name}"
76
+ rescue
77
+ render params.merge(type.to_sym => object)
78
+ end
79
+
80
+ ##
81
+ # It's default response for GET requests, eg. listing, show, new, edit, etc.
82
+ # This is basic action - when request wants html or js, then will be rendered
83
+ # default template for action, otherwise object will be serialized to
84
+ # needed format.
85
+ #
86
+ def default_response(object)
87
+ if [:html, :js].include?(content_type)
88
+ render "#{controller_name}/#{action_name}"
89
+ else
90
+ render content_type, object
91
+ end
92
+ end
93
+
94
+ ##
95
+ # In this response we can decide where system will redirect us after successfully
96
+ # executed action. Redirections are allowed only for html requests. If
97
+ # location is not specified then by default for html and js we will see
98
+ # template, for other formats serialised object. System also will show flash
99
+ # message about destroyed object.
100
+ #
101
+ def default_response_for_destroy(object, location=nil)
102
+ object_notice = "responder.messages.#{controller_name}.destroy"
103
+ alternative_notice = "responder.messages.default.destroy"
104
+
105
+ if content_type == :html && location
106
+ notify(:notice, t(object_notice,
107
+ :model => human_model_name(object),
108
+ :default => t(alternative_notice, human_model_name(object))
109
+ ))
110
+ redirect location
111
+ else
112
+ if [:html, :js].include?(content_type)
113
+ render "#{controller_name}/destroy"
114
+ else
115
+ render content_type, object, :location => location
116
+ end
117
+ end
118
+ end
119
+
120
+ ##
121
+ # Default response for savings, similar to destroy response allow to store
122
+ # redirection after success and also have automatically generated and translated
123
+ # flash messages. When action is successfully executed then we will see
124
+ # redirection or default views for html and js, and serialized object for
125
+ # other formats. Otherwise we will see default form view or serialized errors.
126
+ #
127
+ def default_response_for_save(kind, object, location=nil)
128
+ valid = false
129
+ valid = object.valid? if object.respond_to?(:valid?)
130
+ current_action = kind == 'new' ? 'create' : 'update'
131
+ default_view = "#{object.class.name.underscore.pluralize}/#{current_action}"
132
+ form_view = "#{object.class.name.underscore.pluralize}/#{kind}"
133
+ object_notice = "responder.messages.#{object.class.name.underscore.pluralize}.#{current_action}"
134
+ alternative_notice = "responder.messages.default.#{current_action}"
135
+
136
+ if valid
137
+ case content_type
138
+ when :html
139
+ if location
140
+ notify(:notice, t(object_notice,
141
+ :model => human_model_name(object),
142
+ :default => t(alternative_notice, human_model_name(object))
143
+ ))
144
+ redirect location
145
+ else
146
+ render default_view
147
+ end
148
+ when :js
149
+ render default_view
150
+ else
151
+ render content_type, object, :location => location
152
+ end
153
+ else
154
+ case content_type
155
+ when :html
156
+ render form_view
157
+ when :js
158
+ render default_view
159
+ else
160
+ errors = false
161
+ errors = object.errors if object.respond_to?(:errors)
162
+ render content_type, errors, :status => :unprocessible_entity
163
+ end
164
+ end
165
+ end
166
+ end # Default
167
+ end # Responders
168
+ end # Padrino
@@ -0,0 +1,43 @@
1
+ module Padrino
2
+ module Responders
3
+ module Helpers
4
+ module ControllerHelpers
5
+ protected
6
+ ##
7
+ # Shortcut for <code>notifier.say</code> method.
8
+ #
9
+ def notify(kind, message, *args, &block)
10
+ self.class.notifier.say(self, kind, message, *args, &block)
11
+ end
12
+
13
+ ##
14
+ # Returns name of current action
15
+ #
16
+ def action_name
17
+ name = request.match.route.instance_variable_get('@name').to_s
18
+ name.gsub!(/^#{controller_name}_?/, '')
19
+ name = 'index' if name == ''
20
+ name
21
+ end
22
+
23
+ ##
24
+ # Returns name of current controller
25
+ #
26
+ def controller_name
27
+ request.match.route.controller.to_s
28
+ end
29
+
30
+ ##
31
+ # Returns translated, human readable name for specified model.
32
+ #
33
+ def human_model_name(object)
34
+ if object.class.respond_to?(:human_name)
35
+ object.class.human_name
36
+ else
37
+ t("models.#{object.class.to_s.underscore}", :default => object.class.to_s.humanize)
38
+ end
39
+ end
40
+ end # ControllerHelpers
41
+ end # Helpers
42
+ end # Responders
43
+ end # Padrino
@@ -0,0 +1,7 @@
1
+ en:
2
+ responder:
3
+ messages:
4
+ default:
5
+ destroy: "%{model} has been successfully deleted."
6
+ create: "%{model} has been successfully created."
7
+ update: "%{model} has been successfully updated."
@@ -0,0 +1,20 @@
1
+ module Padrino
2
+ module Responders
3
+ module Notifiers
4
+ module FlashNotifier
5
+ ##
6
+ # Saves specified message as flash notification with specified type.
7
+ #
8
+ # ==== Examples
9
+ #
10
+ # notifier.say(self, :error, "Something went wrong")
11
+ #
12
+ # ... will save message to <code>flash[:notice]</code>
13
+ #
14
+ def self.say(app, kind, message, *args, &block)
15
+ app.flash[kind.to_sym] = message
16
+ end
17
+ end # FlashNotifier
18
+ end # Notifiers
19
+ end # Responders
20
+ end # Padrino
@@ -0,0 +1,47 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{padrino-responders}
8
+ s.version = "0.1.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kris Kowalik"]
12
+ s.date = %q{2010-07-20}
13
+ s.description = %q{This component is used to create slim controllers
14
+ without unnecessery and repetitive code.}
15
+ s.email = %q{kriss.kowalik@gmail.com}
16
+ s.extra_rdoc_files = [
17
+ "LICENSE",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "lib/padrino-responders.rb",
25
+ "lib/padrino-responders/default.rb",
26
+ "lib/padrino-responders/helpers/controller_helpers.rb",
27
+ "lib/padrino-responders/locale/en.yml",
28
+ "lib/padrino-responders/notifiers/flash_notifier.rb",
29
+ "padrino-responders.gemspec"
30
+ ]
31
+ s.homepage = %q{http://github.com/kriss/padrino-responders}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.6}
35
+ s.summary = %q{Simplified responders for Padrino framework}
36
+
37
+ if s.respond_to? :specification_version then
38
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
42
+ else
43
+ end
44
+ else
45
+ end
46
+ end
47
+
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: padrino-responders
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 2
9
+ version: 0.1.2
10
+ platform: ruby
11
+ authors:
12
+ - Kris Kowalik
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-20 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: |-
22
+ This component is used to create slim controllers
23
+ without unnecessery and repetitive code.
24
+ email: kriss.kowalik@gmail.com
25
+ executables: []
26
+
27
+ extensions: []
28
+
29
+ extra_rdoc_files:
30
+ - LICENSE
31
+ - README.rdoc
32
+ files:
33
+ - LICENSE
34
+ - README.rdoc
35
+ - Rakefile
36
+ - lib/padrino-responders.rb
37
+ - lib/padrino-responders/default.rb
38
+ - lib/padrino-responders/helpers/controller_helpers.rb
39
+ - lib/padrino-responders/locale/en.yml
40
+ - lib/padrino-responders/notifiers/flash_notifier.rb
41
+ - padrino-responders.gemspec
42
+ has_rdoc: true
43
+ homepage: http://github.com/kriss/padrino-responders
44
+ licenses: []
45
+
46
+ post_install_message:
47
+ rdoc_options:
48
+ - --charset=UTF-8
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.3.6
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Simplified responders for Padrino framework
72
+ test_files: []
73
+