clean-policy 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: faff212eed58fa49a34fc67bc82c48744e19537fb2f96c66cf0775cbba480b79
4
+ data.tar.gz: 65fe3b90662328845e112e5d1d0044a476429e7301cc54edb363c35f3a892c19
5
+ SHA512:
6
+ metadata.gz: eeea961ffae6212d2d8cf2af530cc862009b4d56976bb57d9cbe607eb91df1c1917de5e05b66e429f1ecedbe438f260bbdd286e25b2a9974a5dbc49ed56e5606
7
+ data.tar.gz: 832a117414d81ab978b724f5aef199ea5c6d5c53047bfa2add622cfe3c2a2bf25deb8c8cd41bdc0dab802ebb75a5b354e2fe3e2ce14b0372bc154a405eef811e
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,5 @@
1
+ require_relative './clean-policy/base'
2
+ require_relative './clean-policy/error'
3
+ require_relative './clean-policy/proxy'
4
+ require_relative './clean-policy/global'
5
+
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ # base caller
4
+ # Policy::User.new(model: @model, user: User.current).can?(:update) -> can current user update @model
5
+
6
+ # block will capture error message and will triggered only if error are present
7
+ # User.can?(:login) { |msg| http_error 401, "Err: #{msg}".red; return 'no access' }
8
+
9
+ class Policy
10
+ attr_reader :model, :user, :action
11
+
12
+ def initialize model:, user:
13
+ @model = model
14
+ @user = user
15
+ end
16
+
17
+ # pass block if you want to handle errors yourself
18
+ # return true if false if block is passed
19
+ def can? action, *args, &block
20
+ @action = action
21
+ .to_s
22
+ .gsub(/[^\w+]/, '')
23
+ .concat('?')
24
+ .to_sym
25
+
26
+ # pre check
27
+ raise RuntimeError, 'Method name not allowed' if %i(can).index(@action)
28
+ raise NoMethodError, %[Policy check "#{@action}" not found in #{self.class}] unless respond_to?(@action)
29
+
30
+ call *args, &block
31
+ end
32
+
33
+ # call has to be isolated because specific of error handling
34
+ def call *args, &block
35
+ raise Error.new 'User is not defined' unless @user
36
+
37
+ return true if before(@action)
38
+ return true if send(@action, *args)
39
+ raise Error.new('Access disabled in policy')
40
+ rescue Policy::Error => e
41
+ error = e.message
42
+ error += " - #{self.class}.#{@action}" if defined?(Lux) && Lux.config(:dump_errors)
43
+
44
+ if block
45
+ block.call(error)
46
+ false
47
+ else
48
+ raise Policy::Error, error
49
+ end
50
+ end
51
+
52
+ def can
53
+ Proxy.new self
54
+ end
55
+
56
+ ###
57
+
58
+ def before action
59
+ false
60
+ end
61
+
62
+ def error message
63
+ raise Policy::Error.new(message)
64
+ end
65
+
66
+ end
@@ -0,0 +1,4 @@
1
+ class Policy
2
+ class Error < StandardError
3
+ end
4
+ end
@@ -0,0 +1,39 @@
1
+ def Policy *args
2
+ opts = args.first.dup
3
+
4
+ unless opts.is_a?(Hash)
5
+ opts = { model: opts }
6
+ opts.merge! args[1] if args[1]
7
+ end
8
+
9
+ raise ArgumentError, 'User not defined' unless opts.key?(:user)
10
+
11
+ model = opts[:model]
12
+
13
+ klass =
14
+ if model
15
+ opts[:class] || ('%s_policy' % model.class).classify.constantize
16
+ else
17
+ ApplicationPolicy
18
+ end
19
+
20
+ klass.new(user: opts[:user], model: model)
21
+ end
22
+
23
+ # "smart" access that will fill current user if possible
24
+ # fell free to overwrite this method
25
+ class Object
26
+ def policy *args
27
+ opts = args.first.dup
28
+
29
+ unless opts.is_a?(Hash)
30
+ opts = { model: opts }
31
+ opts.merge! args[1] if args[1]
32
+ end
33
+
34
+ opts[:user] ||= user_current if respond_to?(:user_current)
35
+ opts[:user] ||= User.current if defined?(User) && User.respond_to?(:current)
36
+
37
+ Policy opts
38
+ end
39
+ end
@@ -0,0 +1,38 @@
1
+ # true / false
2
+ # @model.can.write?
3
+ #
4
+ # raise error or return true
5
+ # @model.can.write!
6
+ #
7
+ # redirect on error or return true
8
+ # @model.can.write! { redirect_to '/login' }
9
+
10
+ class Policy
11
+ class Proxy
12
+ def initialize policy
13
+ @policy = policy
14
+ end
15
+
16
+ def method_missing name, &block
17
+ name = name.to_s.sub(/(.)$/, '')
18
+ action = $1
19
+
20
+ if action == '!'
21
+ @policy.can?(name, &block)
22
+ true
23
+ elsif action == '?'
24
+ raise "Block given, not allowed in boolean (?) policy, use bang .#{name}! { .. }" if block_given?
25
+
26
+ begin
27
+ @policy.can?(name)
28
+ true
29
+ rescue Policy::Error
30
+ yield if block_given?
31
+ false
32
+ end
33
+ else
34
+ raise ArgumentError.new('Bad policy method name')
35
+ end
36
+ end
37
+ end
38
+ end
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clean-policy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Dino Reic
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-10-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Clean, simple explicit and strait-forward policy definitions.
14
+ email: reic.dino@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - "./.version"
20
+ - "./lib/clean-policy.rb"
21
+ - "./lib/clean-policy/base.rb"
22
+ - "./lib/clean-policy/error.rb"
23
+ - "./lib/clean-policy/global.rb"
24
+ - "./lib/clean-policy/proxy.rb"
25
+ homepage: https://github.com/dux/clean-policy
26
+ licenses:
27
+ - MIT
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubygems_version: 3.0.6
45
+ signing_key:
46
+ specification_version: 4
47
+ summary: Ruby access policy library
48
+ test_files: []