forerunner 0.1.1
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/MIT-LICENSE +20 -0
- data/README.md +123 -0
- data/Rakefile +34 -0
- data/lib/forerunner.rb +24 -0
- data/lib/forerunner/action_data.rb +39 -0
- data/lib/forerunner/action_data/invalid_action_type_error.rb +23 -0
- data/lib/forerunner/action_data/missing_action_name_error.rb +9 -0
- data/lib/forerunner/analyzer.rb +9 -0
- data/lib/forerunner/builder.rb +43 -0
- data/lib/forerunner/version.rb +3 -0
- data/lib/tasks/forerunner_tasks.rake +4 -0
- metadata +111 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 584c35a67b59024c9d703c5c07ca4ddc5dbef118
|
|
4
|
+
data.tar.gz: 5de3fa5fffaf7e77ab99ca025511853dd17784d9
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 3e6bc59175af7aca43dd00725e96a2688be87a6102b4e828ec4468fd8f56198f3ec3c6991be4cfe3dc44f4cf2a89a5f31d5e775900353951eff873c13905ff6a
|
|
7
|
+
data.tar.gz: f6e74a85fd009a7a05cc4868b8c396bf2617afc461b6ff933c9b65ccad86e50b072c48c4cbcb7d1b7d3011bae9dceadfd885bc7119312215e5925ccc2dd74ee5
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2017 Greg White
|
|
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.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Forerunner
|
|
2
|
+
Forerunner defines a simple, familiar DSL for definining callbacks above
|
|
3
|
+
controller actions instead of defining them at the top of the class using
|
|
4
|
+
`before_action`. Instead of constantly going back to the top of your controllers
|
|
5
|
+
to see which methods should be called before a controller action, just look
|
|
6
|
+
above the controller action's definition!
|
|
7
|
+
|
|
8
|
+
Using `before_action` works well for most cases, but it falls short when you
|
|
9
|
+
have methods that should only be run for one method, or when your controllers
|
|
10
|
+
grow large. It becomes a pain to know exactly what happens before each
|
|
11
|
+
controller action, and that's exactly the problem that `Forerunner` intends to
|
|
12
|
+
solve.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
Add this line to your application's Gemfile:
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
gem 'forerunner'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
And then execute:
|
|
22
|
+
```bash
|
|
23
|
+
$ bundle
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or install it yourself by running:
|
|
27
|
+
```bash
|
|
28
|
+
$ gem install forerunner
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Getting Started
|
|
32
|
+
|
|
33
|
+
Using `Forerunner` is quite easy. In your `ApplicationController`, just `include
|
|
34
|
+
Forerunner`. That's it!
|
|
35
|
+
|
|
36
|
+
Here's a barebones implementation:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
class ApplicationController < ActionController::Base
|
|
40
|
+
include Forerunner
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Now you have the `Forerunner` library available to you in all controllers that
|
|
45
|
+
subclass `ApplicationController`. You can also include this on a controller by
|
|
46
|
+
controller basis, if you don't anticipate needing it everywhere.
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
`Forerunner` provides you with a new method called `precede_with` that defines
|
|
51
|
+
allows you to specify a method to get called before the next defined controller
|
|
52
|
+
action.
|
|
53
|
+
|
|
54
|
+
Essentially, these two things are equivalent:
|
|
55
|
+
```ruby
|
|
56
|
+
# Normal implementation
|
|
57
|
+
class ExampleController < ApplicationController
|
|
58
|
+
before_action :do_a_thing, only: %i(index)
|
|
59
|
+
|
|
60
|
+
def index
|
|
61
|
+
# index logic goes here
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Forerunner implementation
|
|
66
|
+
class ExampleController < ApplicationController
|
|
67
|
+
precede_with :do_a_thing
|
|
68
|
+
def index
|
|
69
|
+
# index logic goes here
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Let's say you have a `PostsController` that allows anyone to view posts, but
|
|
75
|
+
only allows authorized users to create new posts. Here's how your controller
|
|
76
|
+
would likely look:
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
class PostsController < ApplicationController
|
|
80
|
+
before_action :authorize_user, only: %i(create)
|
|
81
|
+
before_action :another_action, only: %i(create)
|
|
82
|
+
|
|
83
|
+
def index
|
|
84
|
+
# index logic goes here
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def create
|
|
88
|
+
# create logic goes here
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The problem with this is that at a glance, you don't know what happens before
|
|
94
|
+
`create` is called. The methods are in two separate lines at the top of the
|
|
95
|
+
class, far away from the actual `create` definition. Instead, what if you could
|
|
96
|
+
know what happens before each action at a glance?
|
|
97
|
+
|
|
98
|
+
Here's how that controller would look if it utilized `Forerunner`:
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
class PostsController < ApplicationController
|
|
102
|
+
def index
|
|
103
|
+
# index logic goes here
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
precede_with :authorize_user, :another_action
|
|
107
|
+
def create
|
|
108
|
+
# create logic goes here
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
In this implementation, you don't have to worry about what happens before
|
|
114
|
+
`create` is called; it's readily apparent! You can immediately tell that
|
|
115
|
+
`authorize_user` is called, immediately followed by `another_action`.
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
119
|
+
|
|
120
|
+
## Coming Soon
|
|
121
|
+
* `after_action`
|
|
122
|
+
* `around_action`
|
|
123
|
+
* Support for `prepend_#{type}_action`
|
data/Rakefile
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'bundler/setup'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require 'rdoc/task'
|
|
8
|
+
|
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
11
|
+
rdoc.title = 'Forerunner'
|
|
12
|
+
rdoc.options << '--line-numbers'
|
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
require 'bundler/gem_tasks'
|
|
23
|
+
|
|
24
|
+
require 'rake/testtask'
|
|
25
|
+
|
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
|
27
|
+
t.libs << 'lib'
|
|
28
|
+
t.libs << 'test'
|
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
|
30
|
+
t.verbose = false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
task default: :test
|
data/lib/forerunner.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require "active_support"
|
|
2
|
+
require "forerunner/analyzer"
|
|
3
|
+
require "forerunner/action_data"
|
|
4
|
+
require "forerunner/action_data/missing_action_name_error"
|
|
5
|
+
require "forerunner/action_data/invalid_action_type_error"
|
|
6
|
+
require "forerunner/builder"
|
|
7
|
+
|
|
8
|
+
module Forerunner
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
class_methods do
|
|
12
|
+
def precede_with(*filter_params, &block)
|
|
13
|
+
forerunner_builder.enqueue_action(:before, filter_params, block)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def method_added(controller_action)
|
|
17
|
+
forerunner_builder.process_actions(controller_action)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def forerunner_builder
|
|
21
|
+
@forerunner_builder ||= Forerunner::Builder.new(self)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Forerunner
|
|
2
|
+
class ActionData
|
|
3
|
+
VALID_ACTION_TYPES = %i(before around after)
|
|
4
|
+
|
|
5
|
+
attr_reader :options, :action_names, :block, :action_type
|
|
6
|
+
|
|
7
|
+
def initialize(action_type:, action_data:, block: nil)
|
|
8
|
+
@action_type = action_type
|
|
9
|
+
@options = action_data.extract_options!
|
|
10
|
+
@action_names = action_data
|
|
11
|
+
@block = block
|
|
12
|
+
|
|
13
|
+
validate_action_type!
|
|
14
|
+
validate_action_names!
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def limit_to_action(action)
|
|
18
|
+
options[:only] = [action]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def params
|
|
22
|
+
action_names + [options]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def validate_action_type!
|
|
28
|
+
return if VALID_ACTION_TYPES.include?(action_type)
|
|
29
|
+
|
|
30
|
+
raise InvalidActionTypeError, action_type
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def validate_action_names!
|
|
34
|
+
return if action_names.present? || block.present?
|
|
35
|
+
|
|
36
|
+
raise MissingActionNameError
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Forerunner
|
|
2
|
+
class ActionData
|
|
3
|
+
class InvalidActionTypeError < StandardError
|
|
4
|
+
attr_reader :action_type
|
|
5
|
+
|
|
6
|
+
def initialize(action_type)
|
|
7
|
+
@action_type = action_type
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_s
|
|
11
|
+
"Invalid action type `#{action_type}`. Valid types include #{valid_types}."
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def valid_types
|
|
17
|
+
Forerunner::ActionData::VALID_ACTION_TYPES.map do |valid_type|
|
|
18
|
+
"`#{valid_type}`"
|
|
19
|
+
end.to_sentence
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Forerunner
|
|
2
|
+
class Builder
|
|
3
|
+
attr_reader :controller
|
|
4
|
+
attr_accessor :actions
|
|
5
|
+
|
|
6
|
+
delegate :_insert_callbacks, :set_callback, to: :controller
|
|
7
|
+
|
|
8
|
+
def initialize(controller)
|
|
9
|
+
@controller = controller
|
|
10
|
+
@actions = []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def enqueue_action(action_type, action_params, block)
|
|
14
|
+
actions << parse_action_data(action_type, action_params, block)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def process_actions(target_action)
|
|
18
|
+
actions.each do |action_data|
|
|
19
|
+
insert_new_filter(target_action, action_data)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
actions.clear
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def insert_new_filter(target_action, action_data)
|
|
28
|
+
action_data.limit_to_action(target_action)
|
|
29
|
+
|
|
30
|
+
_insert_callbacks(action_data.params, action_data.block) do |name, options|
|
|
31
|
+
set_callback(:process_action, action_data.action_type, name, options)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def parse_action_data(action_type, action_params, block)
|
|
36
|
+
ActionData.new(
|
|
37
|
+
action_type: action_type,
|
|
38
|
+
action_data: action_params,
|
|
39
|
+
block: block
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: forerunner
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Greg White
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2017-05-21 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '5.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '5.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rspec-rails
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: pry
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rubocop
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
description: Run before_actions in a more intuitive way.
|
|
70
|
+
email:
|
|
71
|
+
- gkwhite95@gmail.com
|
|
72
|
+
executables: []
|
|
73
|
+
extensions: []
|
|
74
|
+
extra_rdoc_files: []
|
|
75
|
+
files:
|
|
76
|
+
- MIT-LICENSE
|
|
77
|
+
- README.md
|
|
78
|
+
- Rakefile
|
|
79
|
+
- lib/forerunner.rb
|
|
80
|
+
- lib/forerunner/action_data.rb
|
|
81
|
+
- lib/forerunner/action_data/invalid_action_type_error.rb
|
|
82
|
+
- lib/forerunner/action_data/missing_action_name_error.rb
|
|
83
|
+
- lib/forerunner/analyzer.rb
|
|
84
|
+
- lib/forerunner/builder.rb
|
|
85
|
+
- lib/forerunner/version.rb
|
|
86
|
+
- lib/tasks/forerunner_tasks.rake
|
|
87
|
+
homepage:
|
|
88
|
+
licenses:
|
|
89
|
+
- MIT
|
|
90
|
+
metadata: {}
|
|
91
|
+
post_install_message:
|
|
92
|
+
rdoc_options: []
|
|
93
|
+
require_paths:
|
|
94
|
+
- lib
|
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - ">="
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '0'
|
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
|
+
requirements:
|
|
102
|
+
- - ">="
|
|
103
|
+
- !ruby/object:Gem::Version
|
|
104
|
+
version: '0'
|
|
105
|
+
requirements: []
|
|
106
|
+
rubyforge_project:
|
|
107
|
+
rubygems_version: 2.6.3
|
|
108
|
+
signing_key:
|
|
109
|
+
specification_version: 4
|
|
110
|
+
summary: Forerunner 0.1.1
|
|
111
|
+
test_files: []
|