roda-controller 0.1.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.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +226 -0
- data/Rakefile +2 -0
- data/lib/roda/plugins/controller.rb +108 -0
- data/lib/roda/plugins/controller/version.rb +7 -0
- data/roda-controller.gemspec +27 -0
- metadata +93 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 58cf1d688a6323bd7062c3561f6fd52a47d7fe96
|
4
|
+
data.tar.gz: cfcc8845a0a6955cded710ddb2fd6aa2625a6bcb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8aecd480e38e2287c1344dc84d36b11c6247ac80d02956838767e2a1f50728a7d9cbb43c70623910b695db69b426c2e12cb5dc71ba9c0ffea741333c216895db
|
7
|
+
data.tar.gz: a74e9ab398dadd0b6d6c0f1a95b85947d2ae66e4a7627258fff72075481ce22c79f9644f3c2bb42bc6516495fdb397c7e46829d2cb1d82e0463809e7ef801d7f
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Amadeus Folego
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
# Roda Controller
|
2
|
+
|
3
|
+
Adds controller functionality to Roda
|
4
|
+
|
5
|
+
## Configuration
|
6
|
+
|
7
|
+
Configure your Roda application to use this plugin:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
plugin :controller
|
11
|
+
```
|
12
|
+
|
13
|
+
You can already register your controllers:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
plugin :controller, controllers: { users: UsersController }
|
17
|
+
|
18
|
+
# Infer controller key to 'users'
|
19
|
+
plugin :controller, controllers: [UsersController]
|
20
|
+
|
21
|
+
# Infer controller key to 'users_handler'
|
22
|
+
plugin :controller, controllers: [UsersHandler]
|
23
|
+
```
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
|
27
|
+
You may also register controllers later, inside your application class
|
28
|
+
declaration:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
register_controller UsersController
|
32
|
+
register_controller MoviesController
|
33
|
+
|
34
|
+
# Passing a list of controllers
|
35
|
+
register_controller [UsersController, MoviesController]
|
36
|
+
|
37
|
+
# Explicitly declaring the controller key
|
38
|
+
register_controller :users, UsersHandler
|
39
|
+
register_controller :movies, MoviesHandler
|
40
|
+
```
|
41
|
+
|
42
|
+
## Usage
|
43
|
+
|
44
|
+
### Controller Naming
|
45
|
+
|
46
|
+
The controller class is not required to follow any naming convention,
|
47
|
+
specially if you specify explicitly the controller key when registered.
|
48
|
+
|
49
|
+
However if it ends with `Controller` this will be stripped from the
|
50
|
+
controller key if it is inferred. I.E. `UsersController => 'users'` and
|
51
|
+
`UsersHandler => 'users_handler'`
|
52
|
+
|
53
|
+
### Controller Definition
|
54
|
+
|
55
|
+
You just need to implement the methods with the action names you are going to
|
56
|
+
use:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
class UsersController
|
60
|
+
def index
|
61
|
+
"User Index"
|
62
|
+
end
|
63
|
+
|
64
|
+
def show(user_id)
|
65
|
+
"User Show ##{user_id}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
### Dispatching to controllers
|
71
|
+
|
72
|
+
Call `#dispatch` whenever you want to receive the result of the
|
73
|
+
controller action, this is a textbook RESTful routing definition:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
r.on("users") do
|
77
|
+
r.is do
|
78
|
+
r.get do
|
79
|
+
dispatch('users#index')
|
80
|
+
end
|
81
|
+
|
82
|
+
r.post do
|
83
|
+
dispatch('users#create', args: r.params)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
r.on(:id) do |user_id|
|
88
|
+
r.is do
|
89
|
+
r.get do
|
90
|
+
dispatch('users#show', args: user_id)
|
91
|
+
end
|
92
|
+
|
93
|
+
r.patch do # requires all_verbs plugin to be loaded
|
94
|
+
dispatch('users#update', args: [user_id, r.params])
|
95
|
+
end
|
96
|
+
|
97
|
+
r.delete do # requires all_verbs plugin to be loaded
|
98
|
+
dispatch('users#destroy', args: user_id)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
### Receiving dispatched responses
|
106
|
+
|
107
|
+
You may expose the controller responses using the `@responds_with` variable:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
# users_controller.rb
|
111
|
+
class UsersController
|
112
|
+
def show(user_id)
|
113
|
+
user = user: User.find(user_id)
|
114
|
+
|
115
|
+
@responds_with = { user: user, best_movie: Movie.best_for(user) }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# app.rb
|
120
|
+
r.get do
|
121
|
+
dispatch('users#show', args: user_id)
|
122
|
+
|
123
|
+
# Do stuff with @user and @best_movie, or access @responds_with directly
|
124
|
+
# if the instance variable cannot be overwritten
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
### Rendering Views
|
129
|
+
|
130
|
+
If you are using the render plugin you can use the `#controller` method instead
|
131
|
+
of `#dispatch`. It receives the same parameters but will call the `#view`
|
132
|
+
method with the following convention:
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
controller('users#show', args: user_id) # will call view('users/show')
|
136
|
+
```
|
137
|
+
|
138
|
+
### Initializing Controllers
|
139
|
+
|
140
|
+
You may specify parameters for controller initialization, to provide
|
141
|
+
context to your actions without polluting the method arguments:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
# users_controller.rb
|
145
|
+
class UsersController
|
146
|
+
attr_reader :request, :response
|
147
|
+
|
148
|
+
def initialize(request, response)
|
149
|
+
@request = request
|
150
|
+
@response = response
|
151
|
+
end
|
152
|
+
|
153
|
+
# be able to access the request and response inside actions
|
154
|
+
|
155
|
+
# app.rb
|
156
|
+
## inside routes
|
157
|
+
dispatch('users#update', args: [user_id, r.params], inject: [request, response])
|
158
|
+
## registering controller
|
159
|
+
register_controller(:users, -> { |req, res| UsersController.new(req, res) }
|
160
|
+
```
|
161
|
+
|
162
|
+
### Advanced Configuration
|
163
|
+
|
164
|
+
You can setup default arguments for the `#dispatch` and `#controller` methods:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
# Will always initialize controllers with request and response args
|
168
|
+
plugin :controller, inject: ->{ [request, response] }
|
169
|
+
```
|
170
|
+
|
171
|
+
### DRYing up
|
172
|
+
|
173
|
+
By following conventions you may dry everything up.
|
174
|
+
|
175
|
+
This:
|
176
|
+
|
177
|
+
- Creates a `RodaController` class to be inherited on your controllers
|
178
|
+
- Exposes request and response variables inside actions
|
179
|
+
- Adds helper methods to your actions
|
180
|
+
- Automatically loads all controllers inside `controllers` folder
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
# roda_controller.rb
|
184
|
+
class RodaController
|
185
|
+
attr_reader :request, :response
|
186
|
+
|
187
|
+
# Access request and response methods
|
188
|
+
def initialize(request, response)
|
189
|
+
@request = request
|
190
|
+
@response = response
|
191
|
+
end
|
192
|
+
|
193
|
+
# Enables respond_with exposed_variable: local_variable
|
194
|
+
def respond_with(opts)
|
195
|
+
@responds_with ||= {}
|
196
|
+
@responds_with.merge!(opts)
|
197
|
+
end
|
198
|
+
|
199
|
+
# Get list of all controllers
|
200
|
+
def self.descendants
|
201
|
+
ObjectSpace.each_object(Class).select { |klass| klass < self }
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# app.rb
|
206
|
+
## configuring the plugin
|
207
|
+
plugin :controller, inject: ->{ [request, response] }
|
208
|
+
|
209
|
+
## automatically registering all controllers inside controllers folder
|
210
|
+
Dir["controllers/*.rb"].each { |file| require_relative file }
|
211
|
+
|
212
|
+
RodaController.descendants.each do |controller|
|
213
|
+
controller_key = Roda::RodaPlugins::Controller.underscore(controller.name)
|
214
|
+
controller_proc = -> (req, res) { controller.new(req, res) }
|
215
|
+
|
216
|
+
register_controller(controller_key, controller_proc)
|
217
|
+
end
|
218
|
+
```
|
219
|
+
|
220
|
+
## Contributing
|
221
|
+
|
222
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/badosu/roda-controller
|
223
|
+
|
224
|
+
## License
|
225
|
+
|
226
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "roda/plugins/controller/version"
|
4
|
+
|
5
|
+
class Roda
|
6
|
+
module RodaPlugins
|
7
|
+
module Controller
|
8
|
+
DEFAULTS = {
|
9
|
+
registered_controllers: {},
|
10
|
+
inject: nil,
|
11
|
+
args: nil
|
12
|
+
}
|
13
|
+
|
14
|
+
def self.configure(app, opts={}, &block)
|
15
|
+
plugin_opts = (app.opts[:controller] ||= DEFAULTS)
|
16
|
+
|
17
|
+
app.opts[:controller] = plugin_opts.merge(opts)
|
18
|
+
|
19
|
+
app.register_controller(opts[:controllers]) if opts[:controllers]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.underscore(name, acronym_regex: /(?=a)b/)
|
23
|
+
return name unless name =~ /[A-Z-]|::/
|
24
|
+
|
25
|
+
name.gsub!(/Controller$/, "")
|
26
|
+
|
27
|
+
word = name.to_s.gsub("::", "/")
|
28
|
+
word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_' }#{$2.downcase}" }
|
29
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
30
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
31
|
+
word.tr!("-", "_")
|
32
|
+
word.downcase!
|
33
|
+
word
|
34
|
+
end
|
35
|
+
|
36
|
+
module ClassMethods
|
37
|
+
def register_controller(*args)
|
38
|
+
controllers = opts[:controller][:registered_controllers]
|
39
|
+
|
40
|
+
if args.size == 2
|
41
|
+
controller_key, controller = args
|
42
|
+
|
43
|
+
controllers.merge! controller_key.to_sym => controller
|
44
|
+
elsif args.size == 1
|
45
|
+
controller = args[0]
|
46
|
+
|
47
|
+
if controller.kind_of? Hash
|
48
|
+
controllers.merge!(controller)
|
49
|
+
elsif controller.kind_of? Array
|
50
|
+
controller.each {|c| register_controller(c) }
|
51
|
+
elsif controller.kind_of? Class
|
52
|
+
register_controller(Controller.underscore(controller.name), controller)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module InstanceMethods
|
59
|
+
def dispatch(to, args: nil, inject: nil)
|
60
|
+
controller_key, action = to.to_s.split('#')
|
61
|
+
controllers = opts[:controller][:registered_controllers]
|
62
|
+
controller = controllers[controller_key.to_sym]
|
63
|
+
|
64
|
+
inject ||= opts[:controller][:inject]
|
65
|
+
|
66
|
+
if inject.respond_to?(:to_proc)
|
67
|
+
controller_args = Array(instance_exec(&inject))
|
68
|
+
else
|
69
|
+
controller_args = Array(inject)
|
70
|
+
end
|
71
|
+
|
72
|
+
if controller.respond_to?(:to_proc)
|
73
|
+
controller = controller.to_proc.call(*controller_args)
|
74
|
+
elsif controller.kind_of?(Class)
|
75
|
+
controller = controller.new(*controller_args)
|
76
|
+
end
|
77
|
+
|
78
|
+
response = controller.send(action, *Array(args))
|
79
|
+
|
80
|
+
responds_with = controller.instance_variable_get(:@responds_with)
|
81
|
+
responds_with ||= {}
|
82
|
+
|
83
|
+
responds_with.each do |var, val|
|
84
|
+
ivar = :"@#{var}"
|
85
|
+
|
86
|
+
if !instance_variable_defined?(ivar)
|
87
|
+
instance_variable_set(ivar, val)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
response
|
92
|
+
end
|
93
|
+
|
94
|
+
def controller(to, args: nil, inject: nil)
|
95
|
+
controller_key, action = to.to_s.split('#')
|
96
|
+
|
97
|
+
result = dispatch(to, args: args, inject: inject)
|
98
|
+
|
99
|
+
view("#{controller_key}/#{action}")
|
100
|
+
|
101
|
+
result
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
register_plugin(:controller, Controller)
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'roda/plugins/controller/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = "roda-controller"
|
10
|
+
spec.version = Roda::RodaPlugins::Controller::VERSION
|
11
|
+
spec.authors = ["Amadeus Folego"]
|
12
|
+
spec.email = ["amadeusfolego@gmail.com"]
|
13
|
+
|
14
|
+
spec.summary = %q{Adds controller functionality to Roda}
|
15
|
+
spec.description = %q{Adds controller functionality to Roda}
|
16
|
+
spec.homepage = "https://github.com/badosu/roda-controller"
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_dependency "roda", "~> 2.0"
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: roda-controller
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Amadeus Folego
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: roda
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.11'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.11'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
description: Adds controller functionality to Roda
|
56
|
+
email:
|
57
|
+
- amadeusfolego@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- Gemfile
|
63
|
+
- LICENSE.txt
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- lib/roda/plugins/controller.rb
|
67
|
+
- lib/roda/plugins/controller/version.rb
|
68
|
+
- roda-controller.gemspec
|
69
|
+
homepage: https://github.com/badosu/roda-controller
|
70
|
+
licenses:
|
71
|
+
- MIT
|
72
|
+
metadata: {}
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options: []
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubyforge_project:
|
89
|
+
rubygems_version: 2.5.1
|
90
|
+
signing_key:
|
91
|
+
specification_version: 4
|
92
|
+
summary: Adds controller functionality to Roda
|
93
|
+
test_files: []
|