bali 2.4.0 → 6.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +5 -13
  2. data/.gitignore +2 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +44 -2
  5. data/gemfiles/Gemfile-rails.5.0.x +7 -0
  6. data/gemfiles/Gemfile-rails.5.1.x +6 -0
  7. data/gemfiles/Gemfile-rails.5.2.x +6 -0
  8. data/gemfiles/Gemfile-rails.6.0.x +5 -0
  9. data/gemfiles/Gemfile-rails.edge +14 -0
  10. data/lib/bali.rb +33 -22
  11. data/lib/bali/config.rb +12 -0
  12. data/lib/bali/dsl_error.rb +3 -0
  13. data/lib/bali/{foundations/exceptions/bali_error.rb → error.rb} +0 -0
  14. data/lib/bali/judge.rb +221 -0
  15. data/lib/bali/printer.rb +42 -31
  16. data/lib/bali/rails/action_controller.rb +17 -0
  17. data/lib/bali/rails/action_view.rb +12 -0
  18. data/lib/bali/rails/active_record.rb +11 -0
  19. data/lib/bali/railtie.rb +13 -0
  20. data/lib/bali/role.rb +110 -0
  21. data/lib/bali/rspec/able_to_matcher.rb +39 -0
  22. data/lib/bali/rule.rb +17 -0
  23. data/lib/bali/ruler.rb +38 -0
  24. data/lib/bali/rules.rb +51 -0
  25. data/lib/bali/statics/active_record.rb +2 -0
  26. data/lib/bali/statics/authorizer.rb +65 -0
  27. data/lib/bali/statics/record.rb +13 -0
  28. data/lib/bali/statics/scope_ruler.rb +39 -0
  29. data/lib/bali/tasks/bali/print_rules.rake +9 -0
  30. data/lib/bali/version.rb +1 -1
  31. data/lib/generators/rails/USAGE +8 -0
  32. data/lib/generators/rails/rules_generator.rb +17 -0
  33. data/lib/generators/rails/templates/rules.rb +4 -0
  34. data/lib/generators/rspec/rules_generator.rb +12 -0
  35. data/lib/generators/rspec/templates/rules_spec.rb +7 -0
  36. metadata +131 -49
  37. data/lib/bali/dsl/map_rules_dsl.rb +0 -75
  38. data/lib/bali/dsl/rules_for_dsl.rb +0 -130
  39. data/lib/bali/foundations/all_foundations.rb +0 -17
  40. data/lib/bali/foundations/exceptions/authorization_error.rb +0 -38
  41. data/lib/bali/foundations/exceptions/dsl_error.rb +0 -3
  42. data/lib/bali/foundations/exceptions/objection_error.rb +0 -3
  43. data/lib/bali/foundations/judger/judge.rb +0 -329
  44. data/lib/bali/foundations/judger/negative_judge.rb +0 -40
  45. data/lib/bali/foundations/judger/positive_judge.rb +0 -41
  46. data/lib/bali/foundations/role_extractor.rb +0 -61
  47. data/lib/bali/foundations/rule/rule.rb +0 -55
  48. data/lib/bali/foundations/rule/rule_class.rb +0 -54
  49. data/lib/bali/foundations/rule/rule_group.rb +0 -91
  50. data/lib/bali/integrators/all_integrators.rb +0 -8
  51. data/lib/bali/integrators/rule_class_integrator.rb +0 -27
  52. data/lib/bali/integrators/rule_group_integrator.rb +0 -29
  53. data/lib/bali/integrators/rule_integrator.rb +0 -56
  54. 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,3 +0,0 @@
1
- # this error is thrown when there is incorrect syntax in the DSL
2
- class Bali::DslError < Bali::Error
3
- end
@@ -1,3 +0,0 @@
1
- # this error is thrown when objection is cannot be executed
2
- class Bali::ObjectionError < Bali::Error
3
- 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