bali 2.4.0 → 6.0.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 +5 -13
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/.travis.yml +44 -2
- data/gemfiles/Gemfile-rails.5.0.x +7 -0
- data/gemfiles/Gemfile-rails.5.1.x +6 -0
- data/gemfiles/Gemfile-rails.5.2.x +6 -0
- data/gemfiles/Gemfile-rails.6.0.x +5 -0
- data/gemfiles/Gemfile-rails.edge +14 -0
- data/lib/bali.rb +33 -22
- data/lib/bali/config.rb +12 -0
- data/lib/bali/dsl_error.rb +3 -0
- data/lib/bali/{foundations/exceptions/bali_error.rb → error.rb} +0 -0
- data/lib/bali/judge.rb +221 -0
- data/lib/bali/printer.rb +42 -31
- data/lib/bali/rails/action_controller.rb +17 -0
- data/lib/bali/rails/action_view.rb +12 -0
- data/lib/bali/rails/active_record.rb +11 -0
- data/lib/bali/railtie.rb +13 -0
- data/lib/bali/role.rb +110 -0
- data/lib/bali/rspec/able_to_matcher.rb +39 -0
- data/lib/bali/rule.rb +17 -0
- data/lib/bali/ruler.rb +38 -0
- data/lib/bali/rules.rb +51 -0
- data/lib/bali/statics/active_record.rb +2 -0
- data/lib/bali/statics/authorizer.rb +65 -0
- data/lib/bali/statics/record.rb +13 -0
- data/lib/bali/statics/scope_ruler.rb +39 -0
- data/lib/bali/tasks/bali/print_rules.rake +9 -0
- data/lib/bali/version.rb +1 -1
- data/lib/generators/rails/USAGE +8 -0
- data/lib/generators/rails/rules_generator.rb +17 -0
- data/lib/generators/rails/templates/rules.rb +4 -0
- data/lib/generators/rspec/rules_generator.rb +12 -0
- data/lib/generators/rspec/templates/rules_spec.rb +7 -0
- metadata +131 -49
- data/lib/bali/dsl/map_rules_dsl.rb +0 -75
- data/lib/bali/dsl/rules_for_dsl.rb +0 -130
- data/lib/bali/foundations/all_foundations.rb +0 -17
- data/lib/bali/foundations/exceptions/authorization_error.rb +0 -38
- data/lib/bali/foundations/exceptions/dsl_error.rb +0 -3
- data/lib/bali/foundations/exceptions/objection_error.rb +0 -3
- data/lib/bali/foundations/judger/judge.rb +0 -329
- data/lib/bali/foundations/judger/negative_judge.rb +0 -40
- data/lib/bali/foundations/judger/positive_judge.rb +0 -41
- data/lib/bali/foundations/role_extractor.rb +0 -61
- data/lib/bali/foundations/rule/rule.rb +0 -55
- data/lib/bali/foundations/rule/rule_class.rb +0 -54
- data/lib/bali/foundations/rule/rule_group.rb +0 -91
- data/lib/bali/integrators/all_integrators.rb +0 -8
- data/lib/bali/integrators/rule_class_integrator.rb +0 -27
- data/lib/bali/integrators/rule_group_integrator.rb +0 -29
- data/lib/bali/integrators/rule_integrator.rb +0 -56
- data/lib/bali/objector.rb +0 -173
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
MzhkMjlhYzA4NDU3M2M4ODE1ODkxZTU0ZDA3NDJjZGUwODNmOTZhYg==
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5f2c3170fb8da9fc0a76becddae855901f97cef723cd9db86073e0e2c15d177c
|
4
|
+
data.tar.gz: e9555504164bfb3155d281cfbf4d40629c347d178b76b7eaed2c83caacdcfc4a
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
YWViMDExYzMyZjI5Y2YyOTYxNDdhZWJmYWU5YTVlNDYwODgwZDA1NDhhZWRm
|
11
|
-
NTliMTI1ZGEyMjNjY2QyNGEwNTM5YjNjNDc5OGIxYjk2MTYyNTI=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NTMzMzBjNTczZmM2MDE1YmI0NjA0ZjY1MDRhZGZmNWRiNTRjZGYzMDRmMWI4
|
14
|
-
Zjk4ZTEzNGZkZDg0NzFmZjg0YjYwNDQ2OGVlYjgwNzkwNTY4MGFlZDE1NjI3
|
15
|
-
ZDI1ZjlhNmFhODA4OGQzZDFhMjBkNjdjMjk1ZTI0YTkzZmQ4MTY=
|
6
|
+
metadata.gz: d2241cfc888b7b1c3ea4210c6a0dfc26ba790e8c190631b86d616000fbe4e927bea425f73b1547025c849f9ffc6b01c9f5389129ba9707258c79bf6a31c2c248
|
7
|
+
data.tar.gz: 472f04be142d2e7c42549f2927218c3ca57e880c11c86f2a6d409d0682ea76303299a33f065e070fa8ab38821a408a5ad37507f5d7189210d5baf68c231d4be4
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/.travis.yml
CHANGED
@@ -1,4 +1,46 @@
|
|
1
1
|
language: ruby
|
2
|
+
|
3
|
+
env:
|
4
|
+
global:
|
5
|
+
- CC_TEST_REPORTER_ID=76cedf4d3aa437009b269ff68b901102ca24baeb46245eb94fca42e21bba20a7
|
6
|
+
|
2
7
|
rvm:
|
3
|
-
|
4
|
-
|
8
|
+
- 2.6.5
|
9
|
+
|
10
|
+
before_install:
|
11
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
12
|
+
- chmod +x ./cc-test-reporter
|
13
|
+
- ./cc-test-reporter before-build
|
14
|
+
- sudo apt update -qq
|
15
|
+
- gem i bundler -v '<2'
|
16
|
+
|
17
|
+
cache: bundler
|
18
|
+
|
19
|
+
script:
|
20
|
+
- bundle exec rspec
|
21
|
+
|
22
|
+
after_script:
|
23
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
24
|
+
|
25
|
+
matrix:
|
26
|
+
include:
|
27
|
+
- rvm: 2.7.0
|
28
|
+
gemfile: gemfiles/Gemfile-rails.6.0.x
|
29
|
+
- rvm: 2.6.3
|
30
|
+
gemfile: gemfiles/Gemfile-rails.6.0.x
|
31
|
+
- rvm: 2.6.3
|
32
|
+
gemfile: gemfiles/Gemfile-rails.5.2.x
|
33
|
+
- rvm: 2.4.4
|
34
|
+
gemfile: gemfiles/Gemfile-rails.5.2.x
|
35
|
+
- rvm: 2.6.3
|
36
|
+
gemfile: gemfiles/Gemfile-rails.5.1.x
|
37
|
+
- rvm: 2.6.3
|
38
|
+
gemfile: gemfiles/Gemfile-rails.5.0.x
|
39
|
+
- rvm: 2.4.4
|
40
|
+
gemfile: gemfiles/Gemfile-rails.5.0.x
|
41
|
+
- rvm: ruby-head
|
42
|
+
gemfile: gemfiles/Gemfile-rails.edge
|
43
|
+
|
44
|
+
allow_failures:
|
45
|
+
- rvm: ruby-head
|
46
|
+
- gemfile: gemfiles/Gemfile-rails.edge
|
@@ -0,0 +1,14 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec path: '..'
|
4
|
+
|
5
|
+
git_source(:github) do |repo_name|
|
6
|
+
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
|
7
|
+
"https://github.com/#{repo_name}.git"
|
8
|
+
end
|
9
|
+
|
10
|
+
github 'rails/rails' do
|
11
|
+
gem 'rails'
|
12
|
+
end
|
13
|
+
|
14
|
+
gem 'rspec-rails', '~> 4.0'
|
data/lib/bali.rb
CHANGED
@@ -1,33 +1,44 @@
|
|
1
1
|
require_relative "bali/version"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
begin
|
4
|
+
require "rails"
|
5
|
+
require "rails/generators"
|
6
|
+
rescue LoadError => e
|
7
|
+
# ignores
|
8
|
+
end
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
require "zeitwerk"
|
11
|
+
loader = Zeitwerk::Loader.for_gem
|
12
|
+
loader.ignore("#{__dir__}/generators")
|
13
|
+
loader.ignore("#{__dir__}/bali/rails")
|
14
|
+
loader.ignore("#{__dir__}/bali/rspec")
|
15
|
+
loader.setup
|
12
16
|
|
13
17
|
module Bali
|
14
|
-
|
15
|
-
|
18
|
+
extend self
|
19
|
+
|
20
|
+
def config
|
21
|
+
@config ||= Bali::Config.new
|
22
|
+
end
|
16
23
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# }
|
21
|
-
TRANSLATED_SUBTARGET_ROLES = {}
|
24
|
+
def configure
|
25
|
+
yield config
|
26
|
+
end
|
22
27
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
28
|
+
if defined? Rails
|
29
|
+
require "bali/railtie"
|
30
|
+
require "bali/rails/action_controller"
|
31
|
+
require "bali/rails/action_view"
|
32
|
+
require "bali/rails/active_record"
|
27
33
|
end
|
28
34
|
|
29
|
-
|
30
|
-
|
31
|
-
|
35
|
+
if defined? RSpec
|
36
|
+
begin
|
37
|
+
require "rspec/matchers"
|
38
|
+
require "bali/rspec/able_to_matcher"
|
39
|
+
rescue LoadError => e
|
40
|
+
end
|
32
41
|
end
|
33
42
|
end
|
43
|
+
|
44
|
+
loader.eager_load
|
data/lib/bali/config.rb
ADDED
File without changes
|
data/lib/bali/judge.rb
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
class Bali::Judge
|
2
|
+
# Fuzy value is possible when the evaluation is not yet clear cut, for example in this case:
|
3
|
+
#
|
4
|
+
# role :finance do
|
5
|
+
# cant :view
|
6
|
+
# end
|
7
|
+
#
|
8
|
+
# others do
|
9
|
+
# can :view
|
10
|
+
# can :index
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# Checking cant view for finance role results in a definite false, but
|
14
|
+
# checking on index for the same role results in FUZY_TRUE. Eventually, all FUZY value will be
|
15
|
+
# normal TRUE or FALSE if no definite counterpart is found.
|
16
|
+
|
17
|
+
FUZY_FALSE = -2
|
18
|
+
FUZY_TRUE = 2
|
19
|
+
DEFINITE_FALSE = -1
|
20
|
+
DEFINITE_TRUE = 1
|
21
|
+
|
22
|
+
attr_accessor :term,
|
23
|
+
:actor,
|
24
|
+
:role,
|
25
|
+
:operation,
|
26
|
+
:record,
|
27
|
+
:should_cross_check
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def default_judgement_value(term)
|
31
|
+
case term
|
32
|
+
when :can then false
|
33
|
+
when :cant then true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def check(term, actor_or_roles, operation, record)
|
38
|
+
if operation.nil?
|
39
|
+
# eg: user.can? :sign_in
|
40
|
+
operation = actor_or_roles
|
41
|
+
actor_or_roles = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
judgement_value = default_value = default_judgement_value(term)
|
45
|
+
roles = Bali::Role.formalize actor_or_roles
|
46
|
+
|
47
|
+
roles.each do |role|
|
48
|
+
judge = Bali::Judge.new(
|
49
|
+
term: term,
|
50
|
+
role: role,
|
51
|
+
actor: actor_or_roles,
|
52
|
+
operation: operation,
|
53
|
+
record: record
|
54
|
+
)
|
55
|
+
|
56
|
+
judgement_value = judge.judgement
|
57
|
+
break if judgement_value != default_value
|
58
|
+
end
|
59
|
+
|
60
|
+
judgement_value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize(term:,
|
65
|
+
actor:,
|
66
|
+
role:,
|
67
|
+
operation:,
|
68
|
+
record:,
|
69
|
+
should_cross_check: true)
|
70
|
+
|
71
|
+
@term = term
|
72
|
+
@role = role
|
73
|
+
@actor = actor
|
74
|
+
@operation = operation
|
75
|
+
@record = record
|
76
|
+
@should_cross_check = should_cross_check
|
77
|
+
end
|
78
|
+
|
79
|
+
def judgement
|
80
|
+
judgement = natural_value if no_rule_group?
|
81
|
+
|
82
|
+
if judgement.nil? && rule.nil?
|
83
|
+
cross_check_value = nil
|
84
|
+
# default if can? for undefined rule is false, after related clause
|
85
|
+
# cant be found in cant?
|
86
|
+
cross_check_value = cross_check_judge.judgement if should_cross_check
|
87
|
+
|
88
|
+
# if cross check value nil, then the reverse rule is not defined,
|
89
|
+
# let's determine whether they can do anything or not
|
90
|
+
if cross_check_value.nil?
|
91
|
+
judgement = deduce_from_defined_disposition
|
92
|
+
else
|
93
|
+
# process value from cross checking
|
94
|
+
if otherly_rule && (cross_check_value == FUZY_FALSE || cross_check_value == FUZY_TRUE)
|
95
|
+
# give chance to check at others block
|
96
|
+
@rule = otherly_rule
|
97
|
+
else
|
98
|
+
judgement = reverse_value(cross_check_value)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
judgement ||= deduce_by_evaluation ||
|
104
|
+
deduce_from_fuzy_rules ||
|
105
|
+
natural_value
|
106
|
+
|
107
|
+
return !should_cross_check ?
|
108
|
+
judgement :
|
109
|
+
|
110
|
+
# translate response for value above to traditional true/false
|
111
|
+
# holy judgement refer to non-standard true/false being used inside Bali
|
112
|
+
# which need to be translated from other beings to know
|
113
|
+
judgement > 0
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def record_class
|
119
|
+
record.is_a?(Class) ? record : record.class
|
120
|
+
end
|
121
|
+
|
122
|
+
def ruler
|
123
|
+
@ruler ||= Bali::Ruler.for record_class
|
124
|
+
end
|
125
|
+
|
126
|
+
def rule_group_for(role)
|
127
|
+
ruler.nil? ? nil : ruler[role]
|
128
|
+
end
|
129
|
+
|
130
|
+
def rule_group
|
131
|
+
@rule_group ||= rule_group_for role
|
132
|
+
end
|
133
|
+
|
134
|
+
def other_rule_group
|
135
|
+
@other_rule_group ||= rule_group_for nil
|
136
|
+
end
|
137
|
+
|
138
|
+
def no_rule_group?
|
139
|
+
rule_group.nil? && other_rule_group.nil?
|
140
|
+
end
|
141
|
+
|
142
|
+
def rule
|
143
|
+
# rule group may be nil, for when user checking for undefined rule group
|
144
|
+
@rule ||= rule_group ? rule_group.find_rule(term, operation) : nil
|
145
|
+
end
|
146
|
+
|
147
|
+
def otherly_rule
|
148
|
+
@otherly_rule ||= other_rule_group ? other_rule_group.find_rule(term, operation) : nil
|
149
|
+
end
|
150
|
+
|
151
|
+
def cross_check_judge
|
152
|
+
@cross_check_judge ||= begin
|
153
|
+
Bali::Judge.new(
|
154
|
+
term: reversed_term,
|
155
|
+
role: role,
|
156
|
+
operation: operation,
|
157
|
+
record: record,
|
158
|
+
should_cross_check: false,
|
159
|
+
actor: actor
|
160
|
+
)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def reversed_term
|
165
|
+
case term
|
166
|
+
when :can then :cant
|
167
|
+
when :cant then :can
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def natural_value
|
172
|
+
term == :cant ? DEFINITE_TRUE : DEFINITE_FALSE
|
173
|
+
end
|
174
|
+
|
175
|
+
def reverse_value(value)
|
176
|
+
case value
|
177
|
+
when DEFINITE_TRUE then DEFINITE_FALSE
|
178
|
+
when DEFINITE_FALSE then DEFINITE_TRUE
|
179
|
+
when FUZY_FALSE then FUZY_TRUE
|
180
|
+
when FUZY_TRUE then FUZY_FALSE
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def evaluate(rule, actor, record)
|
185
|
+
conditional = rule.conditional
|
186
|
+
evaluation = case conditional.arity
|
187
|
+
when 0 then conditional.()
|
188
|
+
when 1 then conditional.(record)
|
189
|
+
when 2 then conditional.(record, actor)
|
190
|
+
end
|
191
|
+
|
192
|
+
evaluation ? DEFINITE_TRUE : DEFINITE_FALSE
|
193
|
+
end
|
194
|
+
|
195
|
+
def deduce_by_evaluation
|
196
|
+
return unless rule
|
197
|
+
|
198
|
+
rule.conditional? ?
|
199
|
+
evaluate(rule, actor, record) :
|
200
|
+
judgement = DEFINITE_TRUE
|
201
|
+
end
|
202
|
+
|
203
|
+
def deduce_from_defined_disposition
|
204
|
+
return unless rule_group
|
205
|
+
|
206
|
+
if rule_group.can_all?
|
207
|
+
reverse_value(natural_value)
|
208
|
+
elsif rule_group.cant_all?
|
209
|
+
natural_value
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def deduce_from_fuzy_rules
|
214
|
+
reversed_otherly_rule = other_rule_group.find_rule(reversed_term, operation)
|
215
|
+
|
216
|
+
if reversed_otherly_rule
|
217
|
+
term == :cant ? FUZY_TRUE : FUZY_FALSE
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
data/lib/bali/printer.rb
CHANGED
@@ -2,62 +2,73 @@ require "stringio"
|
|
2
2
|
require "date"
|
3
3
|
|
4
4
|
# module that would allow all defined rules to be printed for check
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
class Bali::Printer
|
6
|
+
include Singleton
|
7
|
+
|
8
8
|
SEPARATOR = " " * 6
|
9
9
|
SUBTARGET_TITLE_SEPARATOR = SEPARATOR + ("-" * 80) + "\n"
|
10
10
|
|
11
|
-
def
|
11
|
+
def self.printable
|
12
|
+
instance.printable
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.pretty_print
|
16
|
+
printable
|
17
|
+
end
|
18
|
+
|
19
|
+
def load_rule_classes
|
20
|
+
return unless Bali.config.rules_path.present?
|
21
|
+
|
22
|
+
Dir["#{Bali.config.rules_path}/**/*.rb"].each do |rule_class_path|
|
23
|
+
require rule_class_path
|
24
|
+
end
|
25
|
+
rescue LoadError
|
26
|
+
# ignore
|
27
|
+
end
|
28
|
+
|
29
|
+
def printable
|
30
|
+
load_rule_classes
|
12
31
|
output = StringIO.new
|
13
32
|
|
14
33
|
# build up the string for pretty printing rules
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
rule_class.
|
19
|
-
print_rule_group(rule_group, output)
|
20
|
-
end
|
34
|
+
rule_classes = ObjectSpace.each_object(Class).select { |cls| cls < Bali::Rules }
|
35
|
+
rule_classes.sort! { |a, b| a.to_s <=> b.to_s }
|
36
|
+
rule_classes.each do |rule_class|
|
37
|
+
output << "===== #{rule_class.model_class} =====\n\n"
|
21
38
|
|
22
|
-
|
23
|
-
|
39
|
+
rule_class.ruler.roles.each do |subtarget, role|
|
40
|
+
print_role role, output
|
24
41
|
end
|
42
|
+
|
25
43
|
output << "\n\n"
|
26
44
|
end
|
27
45
|
|
28
|
-
output << "
|
29
|
-
output << DateTime.now.strftime("Printed at %d-%m-%Y %I:%M%p %Z")
|
46
|
+
output << DateTime.now.strftime("Printed at %Y-%m-%d %I:%M%p %Z")
|
30
47
|
|
31
48
|
output.string
|
32
49
|
end
|
33
50
|
|
34
|
-
def
|
35
|
-
|
36
|
-
subtarget =
|
37
|
-
|
38
|
-
is_zeus = rule_group.zeus?
|
39
|
-
is_plant = rule_group.plant?
|
51
|
+
def print_role role, target_io
|
52
|
+
subtarget = role.name.to_s.capitalize
|
53
|
+
subtarget = "By default" if subtarget.blank?
|
54
|
+
can_all = role.can_all?
|
40
55
|
counter = 0
|
41
56
|
|
42
|
-
target_io << "#{SEPARATOR}#{subtarget}
|
57
|
+
target_io << "#{SEPARATOR}#{subtarget}\n"
|
43
58
|
target_io << SUBTARGET_TITLE_SEPARATOR
|
44
|
-
|
45
|
-
if
|
59
|
+
|
60
|
+
if can_all
|
46
61
|
target_io << "#{SEPARATOR} #{counter+=1}. #{subtarget} can do anything except if explicitly stated otherwise\n"
|
47
|
-
elsif is_plant
|
48
|
-
target_io << "#{SEPARATOR} #{counter+=1}. #{subtarget} cannot do anything except if explicitly stated otherwise\n"
|
49
62
|
end
|
50
|
-
|
51
|
-
|
63
|
+
|
64
|
+
role.rules.each do |rule|
|
52
65
|
written_rule = StringIO.new
|
53
|
-
written_rule << "#{SEPARATOR} #{counter+=1}. #{subtarget} #{rule.
|
54
|
-
if rule.
|
66
|
+
written_rule << "#{SEPARATOR} #{counter+=1}. #{subtarget} #{rule.term} #{rule.operation}"
|
67
|
+
if rule.conditional?
|
55
68
|
written_rule << ", with condition"
|
56
69
|
end
|
57
70
|
written_rule << "\n"
|
58
71
|
target_io << written_rule.string
|
59
72
|
end
|
60
|
-
|
61
|
-
target_io << "\n"
|
62
73
|
end
|
63
74
|
end
|