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
@@ -1,17 +0,0 @@
|
|
1
|
-
# ./exceptions
|
2
|
-
require_relative "exceptions/bali_error"
|
3
|
-
require_relative "exceptions/dsl_error"
|
4
|
-
require_relative "exceptions/objection_error"
|
5
|
-
require_relative "exceptions/authorization_error"
|
6
|
-
|
7
|
-
# rule
|
8
|
-
require_relative "rule/rule"
|
9
|
-
require_relative "rule/rule_class"
|
10
|
-
require_relative "rule/rule_group"
|
11
|
-
|
12
|
-
# role extractor
|
13
|
-
require_relative "role_extractor"
|
14
|
-
|
15
|
-
require_relative "judger/judge"
|
16
|
-
require_relative "judger/negative_judge"
|
17
|
-
require_relative "judger/positive_judge"
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# Error that will be raised when subtarget cannot do something he wanted to do,
|
2
|
-
# or when subtarget do something he should not be allowed to do.
|
3
|
-
class Bali::AuthorizationError < Bali::Error
|
4
|
-
attr_accessor :operation
|
5
|
-
attr_accessor :auth_level
|
6
|
-
attr_accessor :role
|
7
|
-
|
8
|
-
# it may be nil, depends on whether rule checking is using symbol/user
|
9
|
-
attr_accessor :subtarget
|
10
|
-
|
11
|
-
# whether a class or an object
|
12
|
-
attr_accessor :target
|
13
|
-
|
14
|
-
def target_proper_class
|
15
|
-
if target.is_a?(Class)
|
16
|
-
target
|
17
|
-
else
|
18
|
-
target.class
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_s
|
23
|
-
role = humanise_value(self.role)
|
24
|
-
operation = humanise_value(self.operation)
|
25
|
-
auth_level = humanise_value(self.auth_level)
|
26
|
-
|
27
|
-
if auth_level == :can
|
28
|
-
"Role #{role} is not allowed to perform operation `#{operation}` on #{target_proper_class}"
|
29
|
-
else
|
30
|
-
"Role #{role} is allowed to perform operation `#{operation}` on #{target_proper_class}"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
def humanise_value(val)
|
36
|
-
val.nil? ? "<nil>" : val
|
37
|
-
end
|
38
|
-
end
|
@@ -1,329 +0,0 @@
|
|
1
|
-
module Bali::Judger
|
2
|
-
# FUZY-ed value is happen when it is not really clear, need further cross checking,
|
3
|
-
# whether it is really allowed or not. It happens for example in block with others, such as this:
|
4
|
-
#
|
5
|
-
# role :finance do
|
6
|
-
# cannot :view
|
7
|
-
# end
|
8
|
-
# others do
|
9
|
-
# can :view
|
10
|
-
# can :index
|
11
|
-
# end
|
12
|
-
#
|
13
|
-
# In the example above, objecting cannot view on finance will result in STRONG_FALSE, but
|
14
|
-
# objecting can index on finance will result in FUZY_TRUE.
|
15
|
-
#
|
16
|
-
# Eventually, all FUZY value will be normal TRUE or FALSE if no definite counterpart
|
17
|
-
# is found/defined
|
18
|
-
BALI_FUZY_FALSE = -2
|
19
|
-
BALI_FUZY_TRUE = 2
|
20
|
-
BALI_FALSE = -1
|
21
|
-
BALI_TRUE = 1
|
22
|
-
|
23
|
-
class Judge
|
24
|
-
attr_accessor :original_subtarget
|
25
|
-
attr_accessor :subtarget
|
26
|
-
attr_accessor :operation
|
27
|
-
# record can be the class, or an instance of a class
|
28
|
-
attr_accessor :record
|
29
|
-
|
30
|
-
# determine if this judger should not call other judger
|
31
|
-
attr_accessor :cross_checking
|
32
|
-
|
33
|
-
# this class is abstract, shouldn't be initialized
|
34
|
-
def initialize(unconstructable = true)
|
35
|
-
if unconstructable
|
36
|
-
raise Bali::Error, "Bali::Judge::Judger is unconstructable, properly construct by using build to get a concrete class!"
|
37
|
-
end
|
38
|
-
self
|
39
|
-
end
|
40
|
-
|
41
|
-
def self.build(auth_level, options = {})
|
42
|
-
judge = nil
|
43
|
-
if auth_level == :can
|
44
|
-
judge = Bali::Judger::PositiveJudge.new
|
45
|
-
elsif auth_level == :cannot
|
46
|
-
judge = Bali::Judger::NegativeJudge.new
|
47
|
-
else
|
48
|
-
raise Bali::Error, "Unable to find judge for `#{auth_level}` case"
|
49
|
-
end
|
50
|
-
|
51
|
-
judge.original_subtarget = options[:original_subtarget]
|
52
|
-
judge.subtarget = options[:subtarget]
|
53
|
-
judge.operation = options[:operation]
|
54
|
-
judge.record = options[:record]
|
55
|
-
judge.cross_checking = false
|
56
|
-
|
57
|
-
judge
|
58
|
-
end
|
59
|
-
|
60
|
-
def clone(options = {})
|
61
|
-
if options[:reverse]
|
62
|
-
new_judge = Bali::Judger::Judge.build(self.reverse_auth_level)
|
63
|
-
else
|
64
|
-
new_judge = Bali::Judger::Judge.build(self.auth_level)
|
65
|
-
end
|
66
|
-
|
67
|
-
new_judge.subtarget = subtarget
|
68
|
-
new_judge.operation = operation
|
69
|
-
new_judge.record = record
|
70
|
-
new_judge.cross_checking = cross_checking
|
71
|
-
new_judge.original_subtarget = original_subtarget
|
72
|
-
|
73
|
-
new_judge
|
74
|
-
end
|
75
|
-
|
76
|
-
def record_class
|
77
|
-
record.is_a?(Class) ? record : record.class
|
78
|
-
end
|
79
|
-
|
80
|
-
def rule_group
|
81
|
-
unless @rule_group_checked
|
82
|
-
@rule_group = Bali::Integrator::RuleGroup.for(record_class, subtarget)
|
83
|
-
@rule_group_checked = true
|
84
|
-
end
|
85
|
-
@rule_group
|
86
|
-
end
|
87
|
-
|
88
|
-
def other_rule_group
|
89
|
-
unless @other_rule_group_checked
|
90
|
-
@other_rule_group = Bali::Integrator::RuleGroup.for(record_class, "__*__")
|
91
|
-
@other_rule_group_checked = true
|
92
|
-
end
|
93
|
-
@other_rule_group
|
94
|
-
end
|
95
|
-
|
96
|
-
def rule
|
97
|
-
unless @rule_checked
|
98
|
-
# rule group may be nil, for when user checking for undefined rule group
|
99
|
-
if rule_group
|
100
|
-
@rule = rule_group.get_rule(auth_level, operation)
|
101
|
-
else
|
102
|
-
self.rule = nil
|
103
|
-
end
|
104
|
-
end
|
105
|
-
@rule
|
106
|
-
end
|
107
|
-
|
108
|
-
def rule=(the_rule)
|
109
|
-
@rule = the_rule
|
110
|
-
@rule_checked = true
|
111
|
-
@rule
|
112
|
-
end
|
113
|
-
|
114
|
-
def otherly_rule
|
115
|
-
unless @otherly_rule_checked
|
116
|
-
if other_rule_group
|
117
|
-
# retrieve rule from others group
|
118
|
-
@otherly_rule = other_rule_group.get_rule(auth_level, operation)
|
119
|
-
@otherly_rule_checked = true
|
120
|
-
end
|
121
|
-
end
|
122
|
-
@otherly_rule
|
123
|
-
end
|
124
|
-
|
125
|
-
# return either true or false
|
126
|
-
# options can specify if returning raw, by specifying holy: true
|
127
|
-
def judgement(options = {})
|
128
|
-
# the divine judgement will come to thee, O Thou
|
129
|
-
# the doer of truth. return raw, untranslated to true/false.
|
130
|
-
our_holy_judgement = nil
|
131
|
-
|
132
|
-
# default of can? is false whenever RuleClass for that class is undefined
|
133
|
-
# or RuleGroup for that subtarget is not defined
|
134
|
-
if rule_group.nil?
|
135
|
-
if other_rule_group.nil?
|
136
|
-
# no more chance for checking
|
137
|
-
our_holy_judgement = natural_value
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
if our_holy_judgement.nil? && need_to_check_for_intervention?
|
142
|
-
our_holy_judgement = check_intervention
|
143
|
-
end
|
144
|
-
|
145
|
-
if our_holy_judgement.nil? &&
|
146
|
-
rule_group && rule_group.plant? &&
|
147
|
-
rule.nil? && otherly_rule.nil?
|
148
|
-
our_holy_judgement = natural_value
|
149
|
-
end
|
150
|
-
|
151
|
-
if our_holy_judgement.nil? && rule.nil?
|
152
|
-
cross_check_value = nil
|
153
|
-
# default if can? for undefined rule is false, after related clause
|
154
|
-
# cannot be found in cannot?
|
155
|
-
unless cross_checking
|
156
|
-
reversed_self = self.clone reverse: true
|
157
|
-
reversed_self.cross_checking = true
|
158
|
-
cross_check_value = reversed_self.judgement holy: true
|
159
|
-
end
|
160
|
-
|
161
|
-
# if cross check value nil, then the reverse rule is not defined,
|
162
|
-
# let's determine whether he is zeus or plant
|
163
|
-
if cross_check_value.nil?
|
164
|
-
# rule_group can be nil for when user checking under undefined rule-group
|
165
|
-
if rule_group
|
166
|
-
if rule_group.plant?
|
167
|
-
our_holy_judgement = plant_return_value
|
168
|
-
end
|
169
|
-
|
170
|
-
if rule_group.zeus?
|
171
|
-
our_holy_judgement = zeus_return_value
|
172
|
-
end
|
173
|
-
end # if rule_group exist
|
174
|
-
else
|
175
|
-
# process value from cross checking
|
176
|
-
|
177
|
-
if can_use_otherly_rule?(cross_check_value, cross_checking)
|
178
|
-
# give chance to check at others block
|
179
|
-
self.rule = otherly_rule
|
180
|
-
else
|
181
|
-
our_holy_judgement = cross_check_reverse_value(cross_check_value)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end # if our judgement nil and rule is nil
|
185
|
-
|
186
|
-
# if our holy judgement is still nil, but rule is defined
|
187
|
-
if our_holy_judgement.nil? && rule
|
188
|
-
if rule.has_decider?
|
189
|
-
our_holy_judgement = get_decider_result(rule, original_subtarget, record)
|
190
|
-
else
|
191
|
-
our_holy_judgement = default_positive_return_value
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
# return fuzy if otherly rule defines contrary to this auth_level
|
196
|
-
if our_holy_judgement.nil? && rule.nil? && (other_rule_group && other_rule_group.get_rule(reverse_auth_level, operation))
|
197
|
-
if rule_group && (rule_group.zeus? || rule_group.plant?)
|
198
|
-
# don't overwrite our holy judgement with fuzy value if rule group
|
199
|
-
# zeus/plant, because zeus/plant is more definite than any fuzy values
|
200
|
-
# eventhough the rule is abstractly defined
|
201
|
-
else
|
202
|
-
our_holy_judgement = default_negative_fuzy_return_value
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
# if at this point still nil, well,
|
207
|
-
# return the natural value for this judge
|
208
|
-
if our_holy_judgement.nil?
|
209
|
-
if otherly_rule
|
210
|
-
our_holy_judgement = BALI_FUZY_TRUE
|
211
|
-
else
|
212
|
-
our_holy_judgement = natural_value
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
holy = !!options[:holy]
|
217
|
-
return holy ? our_holy_judgement : translate_holy_judgement(our_holy_judgement)
|
218
|
-
end
|
219
|
-
|
220
|
-
private
|
221
|
-
# translate response for value above to traditional true/false
|
222
|
-
# holy judgement refer to non-standard true/false being used inside Bali
|
223
|
-
# which need to be translated from other beings to know
|
224
|
-
def translate_holy_judgement(bali_bool_value)
|
225
|
-
unless bali_bool_value.is_a?(Integer)
|
226
|
-
raise Bali::Error, "Expect bali value to be an Integer, got: `#{bali_bool_value}`"
|
227
|
-
end
|
228
|
-
if bali_bool_value < 0
|
229
|
-
return false
|
230
|
-
elsif bali_bool_value > 0
|
231
|
-
return true
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
def can_use_otherly_rule?(cross_check_value, is_cross_checking)
|
236
|
-
# either if rule from others block is defined, and the result so far is fuzy
|
237
|
-
# or, otherly rule is defined, and it is still a cross check
|
238
|
-
# plus, the result is not a definite BALI_TRUE/BALI_FALSE
|
239
|
-
#
|
240
|
-
# rationalisation:
|
241
|
-
# 1. Definite answer such as BALI_TRUE and BALI_FALSE is to be prioritised over
|
242
|
-
# FUZY answer, because definite answer is not gathered from others block where
|
243
|
-
# FUZY answer is. Therefore, it is an intended result
|
244
|
-
# 2. If the answer is FUZY, otherly_rule only be considered if the result
|
245
|
-
# is either FUZY TRUE or FUZY FALSE, or
|
246
|
-
# 3. Or, when already in cross check mode, we cannot retrieve cross_check_value
|
247
|
-
# what we can is instead, if otherly rule is available, just to try the odd
|
248
|
-
(!otherly_rule.nil? && cross_check_value && !(cross_check_value == BALI_TRUE || cross_check_value == BALI_FALSE)) ||
|
249
|
-
(!otherly_rule.nil? && (cross_check_value == BALI_FUZY_FALSE || cross_check_value == BALI_FUZY_TRUE)) ||
|
250
|
-
(!otherly_rule.nil? && is_cross_checking && cross_check_value.nil?)
|
251
|
-
end
|
252
|
-
|
253
|
-
# if after cross check (checking for cannot) the return is false,
|
254
|
-
# meaning for us, (checking for can), the return have to be true
|
255
|
-
def cross_check_reverse_value(cross_check_value)
|
256
|
-
# either the return is not fuzy, or otherly rule is undefined
|
257
|
-
if cross_check_value == BALI_TRUE
|
258
|
-
return BALI_FALSE
|
259
|
-
elsif cross_check_value == BALI_FALSE
|
260
|
-
return BALI_TRUE
|
261
|
-
elsif cross_check_value == BALI_FUZY_FALSE
|
262
|
-
return BALI_FUZY_TRUE
|
263
|
-
elsif cross_check_value == BALI_FUZY_TRUE
|
264
|
-
return BALI_FUZY_FALSE
|
265
|
-
else
|
266
|
-
raise Bali::Error, "Unknown how to process cross check value: `#{cross_check_value}`"
|
267
|
-
end
|
268
|
-
end # cross_check_reverse_value
|
269
|
-
|
270
|
-
def check_intervention
|
271
|
-
if rule.nil?
|
272
|
-
self_clone = self.clone reverse: true
|
273
|
-
self_clone.cross_checking = true
|
274
|
-
|
275
|
-
check_val = self_clone.judgement holy: true
|
276
|
-
|
277
|
-
# check further whether contradicting rule is defined to overwrite this
|
278
|
-
# super-power either can_all or cannot_all rule
|
279
|
-
if check_val == BALI_TRUE
|
280
|
-
# it is defined, must overwrite
|
281
|
-
return BALI_FALSE
|
282
|
-
else
|
283
|
-
# futher inspection said no such overwriting value is exist
|
284
|
-
return BALI_TRUE
|
285
|
-
end # check_val
|
286
|
-
end # if rule nil
|
287
|
-
end # check intervention
|
288
|
-
|
289
|
-
# what is the result when decider is executed
|
290
|
-
# rule: the rule object
|
291
|
-
# original subtarget: raw, unprocessed arugment passed as subtarget
|
292
|
-
def get_decider_result(rule, original_subtarget, record)
|
293
|
-
# must test first
|
294
|
-
decider = rule.decider
|
295
|
-
case decider.arity
|
296
|
-
when 0
|
297
|
-
if rule.decider_type == :if
|
298
|
-
return decider.() ? BALI_TRUE : BALI_FALSE
|
299
|
-
elsif rule.decider_type == :unless
|
300
|
-
unless decider.()
|
301
|
-
return BALI_TRUE
|
302
|
-
else
|
303
|
-
return BALI_FALSE
|
304
|
-
end
|
305
|
-
end
|
306
|
-
when 1
|
307
|
-
if rule.decider_type == :if
|
308
|
-
return decider.(record) ? BALI_TRUE : BALI_FALSE
|
309
|
-
elsif rule.decider_type == :unless
|
310
|
-
unless decider.(record)
|
311
|
-
return BALI_TRUE
|
312
|
-
else
|
313
|
-
return BALI_FALSE
|
314
|
-
end
|
315
|
-
end
|
316
|
-
when 2
|
317
|
-
if rule.decider_type == :if
|
318
|
-
return decider.(record, original_subtarget) ? BALI_TRUE : BALI_FALSE
|
319
|
-
elsif rule.decider_type == :unless
|
320
|
-
unless decider.(record, original_subtarget)
|
321
|
-
return BALI_TRUE
|
322
|
-
else
|
323
|
-
return BALI_FALSE
|
324
|
-
end
|
325
|
-
end
|
326
|
-
end
|
327
|
-
end
|
328
|
-
end # class
|
329
|
-
end # module
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module Bali::Judger
|
2
|
-
class NegativeJudge < Judge
|
3
|
-
def initialize
|
4
|
-
super(false)
|
5
|
-
end
|
6
|
-
|
7
|
-
def auth_level
|
8
|
-
:cannot
|
9
|
-
end
|
10
|
-
|
11
|
-
def reverse_auth_level
|
12
|
-
:can
|
13
|
-
end
|
14
|
-
|
15
|
-
def zeus_return_value
|
16
|
-
BALI_FALSE
|
17
|
-
end
|
18
|
-
|
19
|
-
def plant_return_value
|
20
|
-
BALI_TRUE
|
21
|
-
end
|
22
|
-
|
23
|
-
def default_positive_return_value
|
24
|
-
BALI_TRUE
|
25
|
-
end
|
26
|
-
|
27
|
-
def default_negative_fuzy_return_value
|
28
|
-
BALI_FUZY_TRUE
|
29
|
-
end
|
30
|
-
|
31
|
-
# cannot? by default return true when
|
32
|
-
def natural_value
|
33
|
-
BALI_TRUE
|
34
|
-
end
|
35
|
-
|
36
|
-
def need_to_check_for_intervention?
|
37
|
-
rule_group && rule_group.plant?
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module Bali::Judger
|
2
|
-
class PositiveJudge < Judge
|
3
|
-
def initialize
|
4
|
-
super(false)
|
5
|
-
end
|
6
|
-
|
7
|
-
def auth_level
|
8
|
-
:can
|
9
|
-
end
|
10
|
-
|
11
|
-
def reverse_auth_level
|
12
|
-
:cannot
|
13
|
-
end
|
14
|
-
|
15
|
-
def zeus_return_value
|
16
|
-
BALI_TRUE
|
17
|
-
end
|
18
|
-
|
19
|
-
def plant_return_value
|
20
|
-
BALI_FALSE
|
21
|
-
end
|
22
|
-
|
23
|
-
def default_positive_return_value
|
24
|
-
BALI_TRUE
|
25
|
-
end
|
26
|
-
|
27
|
-
def default_negative_fuzy_return_value
|
28
|
-
BALI_FUZY_FALSE
|
29
|
-
end
|
30
|
-
|
31
|
-
# value that is natural to be returned by the jury
|
32
|
-
# can? by default return false
|
33
|
-
def natural_value
|
34
|
-
BALI_FALSE
|
35
|
-
end
|
36
|
-
|
37
|
-
def need_to_check_for_intervention?
|
38
|
-
rule_group && rule_group.zeus?
|
39
|
-
end
|
40
|
-
end # positive judger
|
41
|
-
end # module judger
|