clean-policy 0.2.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
+ 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: []