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.
@@ -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
@@ -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.
@@ -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`
@@ -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
@@ -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,9 @@
1
+ module Forerunner
2
+ class ActionData
3
+ class MissingActionNameError < StandardError
4
+ def to_s
5
+ "Forerunner filter must have at least one action name"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Forerunner
2
+ class Analyzer
3
+ attr_reader :controller
4
+
5
+ def initialize(controller)
6
+ @controller = controller
7
+ end
8
+ end
9
+ 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
@@ -0,0 +1,3 @@
1
+ module Forerunner
2
+ VERSION = '0.1.1'
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :forerunner do
3
+ # # Task goes here
4
+ # 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: []