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.
@@ -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
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -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.
@@ -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).
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task default: :spec
@@ -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,7 @@
1
+ require 'roda'
2
+
3
+ module Roda::RodaPlugins
4
+ module Controller
5
+ VERSION = "0.1.0"
6
+ end
7
+ 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: []