banken-dsl 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: 3edb938e54606119cee460e75f0e7f11aa4e4a52
4
+ data.tar.gz: 2ed831955290e554210e0fbf43b354fa5256c895
5
+ SHA512:
6
+ metadata.gz: 733797495d20baa17cca40b315c843b71d3210cca2c4e6d4817d8255a105355134985fdee1ff6f22ded7d211de9c08ec2370e69f9b460eb9b1264a120889d849
7
+ data.tar.gz: 80cd6bb91b1797aa171a5e330a3d783002e02bc18e94e83b593936909ee4f1382ab4afded6ea0edbbbd38da07c39105656aa8ad1fabdf9e7fb5855dc9ab5c601
@@ -0,0 +1,86 @@
1
+ # Banken::DSL
2
+
3
+ This plugin gives directly define query methods to the controller for a Banken loyalty class by DSL
4
+
5
+ ## Installation
6
+
7
+ ``` ruby
8
+ gem "banken-dsl"
9
+ ```
10
+
11
+ Include Banken in your application controller:
12
+
13
+ ``` ruby
14
+ # app/controllers/application_controller.rb
15
+ class ApplicationController < ActionController::Base
16
+ include Banken
17
+ protect_from_forgery
18
+ end
19
+ ```
20
+
21
+ Optionally, you can run the generator, which will set up an application loyalty
22
+ with some useful defaults for you:
23
+
24
+ ``` sh
25
+ rails g banken:install
26
+ ```
27
+
28
+ After generating your application loyalty, restart the Rails server so that Rails
29
+ can pick up any classes in the new `app/loyalties/` directory.
30
+
31
+ ## Usage
32
+
33
+ This plugin provides DSL to define query methods to the Controller without creating a loyalty class:
34
+
35
+ ``` ruby
36
+ # app/controllers/posts_controller.rb
37
+ class PostsController < ApplicationController
38
+ authorization_policy do
39
+ index { true }
40
+ show { true }
41
+ create { user.admin? }
42
+ update { user.admin? && record.unpublished? }
43
+ destroy { user.admin? && record.unpublished? }
44
+ end
45
+
46
+ before_action :set_post, only: [:show, :edit, :update, :destroy]
47
+
48
+ def index
49
+ @posts = Post.all
50
+ end
51
+
52
+ def show
53
+ end
54
+ end
55
+ ```
56
+
57
+ You can define the loyalty class by `authorization_policy` method as same as this code:
58
+
59
+ ```ruby
60
+ # app/loyalties/posts_loyalty.rb
61
+ class PostsLoyalty < ApplicationLoyalty
62
+ def index?
63
+ true
64
+ end
65
+
66
+ def show?
67
+ true
68
+ end
69
+
70
+ def create?
71
+ user.admin?
72
+ end
73
+
74
+ def update?
75
+ user.admin? && record.unpublished?
76
+ end
77
+
78
+ def destroy?
79
+ user.admin? && record.unpublished?
80
+ end
81
+ end
82
+ ```
83
+
84
+ ## License
85
+
86
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,31 @@
1
+ require "banken"
2
+
3
+ module Banken
4
+ module DSL
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ def authorization_policy(&block)
9
+ banken_dsl_proxy.instance_eval(&block)
10
+ end
11
+
12
+ def define_banken_query_method_for(action_name, &block)
13
+ banken_dsl_proxy.define_banken_query_method_for(action_name, &block)
14
+ end
15
+
16
+ private
17
+
18
+ def banken_dsl_proxy
19
+ @_banken_dsl_proxy ||= ::Banken::DSL::Proxy.new(self)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ require "banken/dsl/base_loyalty"
26
+ require "banken/dsl/error"
27
+ require "banken/dsl/factory"
28
+ require "banken/dsl/proxy"
29
+ require "banken/dsl/version"
30
+
31
+ Banken.send(:include, ::Banken::DSL)
@@ -0,0 +1,40 @@
1
+ module Banken
2
+ module DSL
3
+ class BaseLoyalty
4
+ attr_reader :user, :record
5
+
6
+ def initialize(user, record)
7
+ @user = user
8
+ @record = record
9
+ end
10
+
11
+ def index?
12
+ false
13
+ end
14
+
15
+ def show?
16
+ false
17
+ end
18
+
19
+ def create?
20
+ false
21
+ end
22
+
23
+ def new?
24
+ create?
25
+ end
26
+
27
+ def update?
28
+ false
29
+ end
30
+
31
+ def edit?
32
+ update?
33
+ end
34
+
35
+ def destroy?
36
+ false
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,5 @@
1
+ module Banken
2
+ module DSL
3
+ UndefinedAction = Class.new(NameError)
4
+ end
5
+ end
@@ -0,0 +1,42 @@
1
+ module Banken
2
+ module DSL
3
+ class Factory
4
+ SUFFIX = "Loyalty".freeze
5
+
6
+ attr_reader :controller_name, :base_controller_name
7
+
8
+ def initialize(controller)
9
+ @controller_name = extract_controller_name(controller)
10
+ @base_controller_name = extract_controller_name(controller.superclass)
11
+ end
12
+
13
+ def create
14
+ Object.const_set(loyalty_name, loyalty_klass)
15
+ end
16
+
17
+ private
18
+
19
+ def extract_controller_name(controller)
20
+ controller.controller_path if controller.to_s.end_with?("Controller")
21
+ end
22
+
23
+ def loyalty_name
24
+ "#{controller_name.camelize}#{SUFFIX}"
25
+ end
26
+
27
+ def loyalty_klass
28
+ if base_controller_name
29
+ Class.new(base_loyalty)
30
+ else
31
+ Class.new(::Banken::DSL::BaseLoyalty)
32
+ end
33
+ end
34
+
35
+ def base_loyalty
36
+ ::Banken::LoyaltyFinder.new(base_controller_name).loyalty!
37
+ rescue ::Banken::NotDefinedError
38
+ ::Banken::DSL::BaseLoyalty
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,59 @@
1
+ module Banken
2
+ module DSL
3
+ class Proxy
4
+ PERMIT_ATTRIBUTES_METHOD_NAME = "permitted_attributes".freeze
5
+
6
+ attr_reader :controller
7
+
8
+ def initialize(controller)
9
+ @controller = controller
10
+ end
11
+
12
+ def define_banken_query_method_for(action_name, &block)
13
+ banken_loyalty.class_eval do
14
+ define_method("#{action_name}?", &block)
15
+ end
16
+ end
17
+
18
+ def define_banken_permit_attributes_method(&block)
19
+ banken_loyalty.class_eval do
20
+ define_method(PERMIT_ATTRIBUTES_METHOD_NAME, &block)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def banken_loyalty
27
+ ::Banken::LoyaltyFinder.new(banken_controller_name).loyalty!
28
+ rescue ::Banken::NotDefinedError
29
+ ::Banken::DSL::Factory.new(controller).create
30
+ end
31
+
32
+ def banken_controller_name
33
+ controller.controller_path
34
+ end
35
+
36
+ def method_missing(method_name, *arguments, &block)
37
+ if action_method?(method_name)
38
+ define_banken_query_method_for(method_name, &block)
39
+ elsif permit_attributes_method?(method_name)
40
+ define_banken_permit_attributes_method(&block)
41
+ else
42
+ raise ::Banken::DSL::UndefinedAction, "#{controller}##{method_name} is undefined"
43
+ end
44
+ end
45
+
46
+ def respond_to_missing?(method_name, include_private = false)
47
+ action_method?(method_name) || permit_attributes_method?(method_name) || super
48
+ end
49
+
50
+ def action_method?(method_name)
51
+ controller.action_methods.include?(method_name.to_s)
52
+ end
53
+
54
+ def permit_attributes_method?(method_name)
55
+ method_name.to_s == PERMIT_ATTRIBUTES_METHOD_NAME
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,5 @@
1
+ module Banken
2
+ module DSL
3
+ VERSION = "0.1.0".freeze
4
+ end
5
+ end
@@ -0,0 +1,151 @@
1
+ require "spec_helper"
2
+
3
+ describe Banken do
4
+ let(:user) { double }
5
+ let(:post) { Post.new(user, 1) }
6
+ let(:post2) { Post.new(user, 2) }
7
+ let(:comment) { Comment.new }
8
+ let(:article) { Article.new }
9
+ let(:posts_controller) { PostsController.new(user, { :action => 'update', :controller => 'posts' }) }
10
+ let(:users_controller) { UsersController.new(user, { :action => 'index', :controller => 'users' }) }
11
+
12
+ describe ".loyalty!" do
13
+ it "returns an instantiated loyalty given a controller name" do
14
+ loyalty = Banken.loyalty!('posts', user, post)
15
+ expect(loyalty.user).to eq user
16
+ expect(loyalty.record).to eq post
17
+ expect(loyalty.class.name).to eq 'PostsLoyalty'
18
+ end
19
+
20
+ it "returns an instantiated loyalty given a controller name of symbol" do
21
+ loyalty = Banken.loyalty!(:posts, user, post)
22
+ expect(loyalty.user).to eq user
23
+ expect(loyalty.record).to eq post
24
+ expect(loyalty.class.name).to eq 'PostsLoyalty'
25
+ end
26
+
27
+ it "returns an instantiated loyalty given record is nil" do
28
+ loyalty = Banken.loyalty!(:posts, user)
29
+ expect(loyalty.user).to eq user
30
+ expect(loyalty.record).to eq nil
31
+ expect(loyalty.class.name).to eq 'PostsLoyalty'
32
+ end
33
+
34
+ it "throws an exception if the given loyalty can't be found" do
35
+ expect { Banken.loyalty!('articles', user, article) }.to raise_error(Banken::NotDefinedError)
36
+ end
37
+ end
38
+
39
+ describe ".define_banken_query_method_for" do
40
+ it "defines banken query method to the loyalty class with the same name as the Controller" do
41
+ UsersController.define_banken_query_method_for(:index) { true }
42
+ loyalty = Banken.loyalty!('users', user)
43
+ expect(loyalty.class.name).to eq 'UsersLoyalty'
44
+ expect(loyalty.class.superclass.name).to eq 'Banken::DSL::BaseLoyalty'
45
+ expect(users_controller.authorize!).to be true
46
+ end
47
+ end
48
+
49
+ describe "#verify_authorized" do
50
+ it "does nothing when authorized" do
51
+ posts_controller.authorize!(post)
52
+ posts_controller.verify_authorized
53
+ end
54
+
55
+ it "raises an exception when not authorized" do
56
+ expect { posts_controller.verify_authorized }.to raise_error(Banken::AuthorizationNotPerformedError)
57
+ end
58
+ end
59
+
60
+ describe "#banken_loyalty_authorized?" do
61
+ it "is true when authorized!" do
62
+ posts_controller.authorize!(post)
63
+ expect(posts_controller.banken_loyalty_authorized?).to be true
64
+ end
65
+
66
+ it "is false when not authorized!" do
67
+ expect(posts_controller.banken_loyalty_authorized?).to be false
68
+ end
69
+ end
70
+
71
+ describe "#skip_authorization" do
72
+ it "disables authorization verification" do
73
+ posts_controller.skip_authorization
74
+ expect { posts_controller.verify_authorized }.not_to raise_error
75
+ end
76
+ end
77
+
78
+ describe "#authorize!" do
79
+ context 'with action returning true' do
80
+ it "infers the loyalty name and authorizes based on it" do
81
+ expect(posts_controller.authorize!(post)).to be true
82
+ end
83
+ end
84
+
85
+ context 'with action returning false' do
86
+ before { posts_controller.params[:action] = 'destroy' }
87
+
88
+ it "throws an exception of Banken::NotAuthorizedError" do
89
+ expect { posts_controller.authorize!(post) }.to raise_error(Banken::NotAuthorizedError)
90
+ end
91
+ end
92
+
93
+ context 'with nothing loyalty' do
94
+ before { posts_controller.params[:controller] = 'articles' }
95
+
96
+ it "throws an exception of Banken::NotDefinedError" do
97
+ expect { posts_controller.authorize!(article) }.to raise_error(Banken::NotDefinedError)
98
+ end
99
+ end
100
+
101
+ context 'with nothing action in loyalty' do
102
+ before { posts_controller.params[:action] = 'update_all' }
103
+
104
+ it "throws an exception of NoMethodError" do
105
+ expect { posts_controller.authorize!(post) }.to raise_error(NoMethodError)
106
+ end
107
+ end
108
+ end
109
+
110
+ describe "#banken_user" do
111
+ it 'returns the same thing as current_user' do
112
+ expect(posts_controller.banken_user).to eq posts_controller.current_user
113
+ end
114
+ end
115
+
116
+ describe "#loyalty" do
117
+ it "returns an instantiated loyalty" do
118
+ loyalty = posts_controller.loyalty(post, 'posts')
119
+ expect(loyalty.user).to eq user
120
+ expect(loyalty.record).to eq post
121
+ end
122
+
123
+ it "returns an different loyalty each record" do
124
+ loyalty = posts_controller.loyalty(post, 'posts')
125
+ loyalty2 = posts_controller.loyalty(post2, 'posts')
126
+
127
+ expect(loyalty).not_to eq loyalty2
128
+ end
129
+
130
+
131
+ it "throws an exception if the given loyalty can't be found" do
132
+ expect { posts_controller.loyalty('articles', article) }.to raise_error(Banken::NotDefinedError)
133
+ end
134
+ end
135
+
136
+ describe "#permitted_attributes" do
137
+ it "checks loyalty for permitted attributes" do
138
+ params = ActionController::Parameters.new({ controller: 'posts', action: 'update', post: { title: 'Hello', votes: 5, admin: true } })
139
+
140
+ expect(PostsController.new(user, params).permitted_attributes(post)).to eq({ 'title' => 'Hello', 'votes' => 5 })
141
+ expect(PostsController.new(double, params).permitted_attributes(post)).to eq({ 'votes' => 5 })
142
+ end
143
+ end
144
+
145
+ describe "Banken::NotAuthorizedError" do
146
+ it "can be initialized with a string as message" do
147
+ error = Banken::NotAuthorizedError.new("must be logged in")
148
+ expect(error.message).to eq "must be logged in"
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,16 @@
1
+ require "bundler/setup"
2
+
3
+ require "banken/dsl"
4
+
5
+ require "rack"
6
+ require "rack/test"
7
+ require "active_support"
8
+ require "active_support/core_ext"
9
+ require "action_controller/metal/strong_parameters"
10
+
11
+ require "pry"
12
+
13
+ I18n.enforce_available_locales = false
14
+
15
+ $:.unshift File.expand_path('../support', __FILE__)
16
+ Dir["#{File.dirname(__FILE__)}/support/**/**/*.rb"].each { |f| require f }
@@ -0,0 +1,26 @@
1
+ class ApplicationController
2
+ include Banken
3
+
4
+ attr_accessor :current_user, :params
5
+
6
+ def initialize(current_user, params={})
7
+ @current_user = current_user
8
+ @params = params
9
+ end
10
+
11
+ def show; end
12
+
13
+ def update; end
14
+
15
+ def destroy; end
16
+
17
+ class << self
18
+ def controller_path
19
+ name.sub(/Controller$/, '').underscore
20
+ end
21
+
22
+ def action_methods
23
+ @_action_methods ||= public_instance_methods(true).map(&:to_s) - [Banken::DSL::Proxy::PERMIT_ATTRIBUTES_METHOD_NAME]
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ class PostsController < ApplicationController
2
+ authorization_policy do
3
+ update { record.user == user }
4
+ destroy { false }
5
+ show { true }
6
+
7
+ permitted_attributes do
8
+ if record.user == user
9
+ [:title, :votes]
10
+ else
11
+ [:votes]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ class UsersController < ApplicationController; end
@@ -0,0 +1 @@
1
+ class Article; end
@@ -0,0 +1,7 @@
1
+ class Post < Struct.new(:user, :id)
2
+ def self.published
3
+ :published
4
+ end
5
+ def to_s; "Post"; end
6
+ def inspect; "#<Post>"; end
7
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: banken-dsl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yoshiyuki Hirano
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: banken
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.2
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.15'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.15'
41
+ description: This plugin gives directly define query methods to the controller for
42
+ a Banken loyalty class by DSL
43
+ email:
44
+ - yhirano@me.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - README.md
50
+ - Rakefile
51
+ - lib/banken/dsl.rb
52
+ - lib/banken/dsl/base_loyalty.rb
53
+ - lib/banken/dsl/error.rb
54
+ - lib/banken/dsl/factory.rb
55
+ - lib/banken/dsl/proxy.rb
56
+ - lib/banken/dsl/version.rb
57
+ - spec/banken_spec.rb
58
+ - spec/spec_helper.rb
59
+ - spec/support/controllers/application_controller.rb
60
+ - spec/support/controllers/posts_controller.rb
61
+ - spec/support/controllers/users_controller.rb
62
+ - spec/support/models/article.rb
63
+ - spec/support/models/post.rb
64
+ homepage: https://github.com/yhirano55/banken-dsl
65
+ licenses:
66
+ - MIT
67
+ metadata: {}
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 2.2.0
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project:
84
+ rubygems_version: 2.6.10
85
+ signing_key:
86
+ specification_version: 4
87
+ summary: DSL for Banken
88
+ test_files:
89
+ - spec/banken_spec.rb
90
+ - spec/spec_helper.rb
91
+ - spec/support/controllers/application_controller.rb
92
+ - spec/support/controllers/posts_controller.rb
93
+ - spec/support/controllers/users_controller.rb
94
+ - spec/support/models/article.rb
95
+ - spec/support/models/post.rb