bali 2.0.0 → 2.1.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 +13 -5
- data/CHANGELOG.md +69 -0
- data/README.md +79 -221
- data/bin/console +0 -7
- data/lib/bali.rb +1 -8
- data/lib/bali/dsl/map_rules_dsl.rb +15 -2
- data/lib/bali/dsl/rules_for_dsl.rb +65 -27
- data/lib/bali/foundations/rule/rule.rb +9 -1
- data/lib/bali/foundations/rule/rule_class.rb +34 -3
- data/lib/bali/foundations/rule/rule_group.rb +21 -6
- data/lib/bali/integrators/rules_integrator.rb +3 -25
- data/lib/bali/objector.rb +196 -91
- data/lib/bali/printer.rb +63 -0
- data/lib/bali/version.rb +1 -1
- metadata +19 -18
@@ -7,10 +7,19 @@ class Bali::MapRulesDsl
|
|
7
7
|
end
|
8
8
|
|
9
9
|
# defining rules
|
10
|
-
def rules_for(target_class,
|
10
|
+
def rules_for(target_class, options_hash = {}, &block)
|
11
11
|
@@lock.synchronize do
|
12
|
+
raise Bali::DslError "rules_for must describe a target which is a class" unless target_class.is_a?(Class)
|
12
13
|
self.current_rule_class = Bali::RuleClass.new(target_class)
|
13
|
-
|
14
|
+
|
15
|
+
parent_class = options_hash[:inherits] || options_hash["inherits"]
|
16
|
+
if parent_class
|
17
|
+
# in case there is inherits specification
|
18
|
+
raise Bali::DslError, "inherits must take a class" unless parent_class.is_a?(Class)
|
19
|
+
rule_class_from_parent = Bali::Integrators::Rule.rule_class_for(parent_class)
|
20
|
+
raise Bali::DslError, "not yet defined a rule class for #{parent_class}" if rule_class_from_parent.nil?
|
21
|
+
self.current_rule_class = rule_class_from_parent.clone(target_class: target_class)
|
22
|
+
end
|
14
23
|
|
15
24
|
Bali::RulesForDsl.new(self).instance_eval(&block)
|
16
25
|
|
@@ -50,6 +59,10 @@ class Bali::MapRulesDsl
|
|
50
59
|
raise Bali::DslError, "can_all block must be within describe block"
|
51
60
|
end
|
52
61
|
|
62
|
+
def clear_rules
|
63
|
+
raise Bali::DslError, "clear_rules must be called within describe block"
|
64
|
+
end
|
65
|
+
|
53
66
|
def cant_all(*params)
|
54
67
|
puts "Deprecation Warning: declaring rules with cant_all will be deprecated on major release 3.0, use cannot instead"
|
55
68
|
cannot_all *params
|
@@ -14,32 +14,30 @@ class Bali::RulesForDsl
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def describe(*params)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
17
|
+
@@lock.synchronize do
|
18
|
+
subtargets = []
|
19
|
+
rules = {}
|
20
|
+
|
21
|
+
params.each do |passed_argument|
|
22
|
+
if passed_argument.is_a?(Symbol) || passed_argument.is_a?(String)
|
23
|
+
subtargets << passed_argument
|
24
|
+
elsif passed_argument.is_a?(NilClass)
|
25
|
+
subtargets << passed_argument
|
26
|
+
elsif passed_argument.is_a?(Array)
|
27
|
+
subtargets += passed_argument
|
28
|
+
elsif passed_argument.is_a?(Hash)
|
29
|
+
rules = passed_argument
|
30
|
+
else
|
31
|
+
raise Bali::DslError, "Allowed argument for describe: symbol, string, nil and hash"
|
32
|
+
end
|
32
33
|
end
|
33
|
-
end
|
34
34
|
|
35
|
-
|
36
|
-
target_alias = self.map_rules_dsl.current_rule_class.alias_name
|
35
|
+
target_class = self.map_rules_dsl.current_rule_class.target_class
|
37
36
|
|
38
|
-
|
39
|
-
@@lock.synchronize do
|
37
|
+
subtargets.each do |subtarget|
|
40
38
|
rule_group = self.current_rule_class.rules_for(subtarget)
|
41
39
|
if rule_group.nil?
|
42
|
-
rule_group = Bali::RuleGroup.new(target_class,
|
40
|
+
rule_group = Bali::RuleGroup.new(target_class, subtarget)
|
43
41
|
end
|
44
42
|
|
45
43
|
self.current_rule_group = rule_group
|
@@ -64,12 +62,46 @@ class Bali::RulesForDsl
|
|
64
62
|
|
65
63
|
# add current_rule_group
|
66
64
|
self.map_rules_dsl.current_rule_class.add_rule_group(self.current_rule_group)
|
67
|
-
end #
|
68
|
-
end #
|
65
|
+
end # each subtarget
|
66
|
+
end # sync block
|
69
67
|
end # describe
|
70
68
|
|
69
|
+
# others block
|
70
|
+
def others(*params)
|
71
|
+
@@lock.synchronize do
|
72
|
+
rules = {}
|
73
|
+
|
74
|
+
params.each do |passed_argument|
|
75
|
+
if passed_argument.is_a?(Hash)
|
76
|
+
rules = passed_argument
|
77
|
+
else
|
78
|
+
raise Bali::DslError, "Allowed argument for others: hash"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
self.current_rule_group = self.map_rules_dsl.current_rule_class.others_rule_group
|
83
|
+
|
84
|
+
if block_given?
|
85
|
+
yield
|
86
|
+
else
|
87
|
+
rules.each do |auth_val, operations|
|
88
|
+
if operations.is_a?(Array)
|
89
|
+
operations.each do |op|
|
90
|
+
rule = Bali::Rule.new(auth_val, op)
|
91
|
+
self.current_rule_group.add_rule(rule)
|
92
|
+
end
|
93
|
+
else
|
94
|
+
operation = operations
|
95
|
+
rule = Bali::Rule.new(auth_val, operation)
|
96
|
+
self.current_rule_group.add_rule(rule)
|
97
|
+
end
|
98
|
+
end # each rules
|
99
|
+
end # block_given?
|
100
|
+
end # synchronize
|
101
|
+
end # others
|
102
|
+
|
71
103
|
# to define can and cant is basically using this method
|
72
|
-
def
|
104
|
+
def bali_process_auth_rules(auth_val, operations)
|
73
105
|
conditional_hash = nil
|
74
106
|
|
75
107
|
# scan operations for options
|
@@ -97,14 +129,20 @@ class Bali::RulesForDsl
|
|
97
129
|
self.current_rule_group.add_rule(rule)
|
98
130
|
end
|
99
131
|
end
|
100
|
-
end #
|
132
|
+
end # bali_process_auth_rules
|
133
|
+
|
134
|
+
# clear all defined rules
|
135
|
+
def clear_rules
|
136
|
+
self.current_rule_group.clear_rules
|
137
|
+
true
|
138
|
+
end
|
101
139
|
|
102
140
|
def can(*operations)
|
103
|
-
|
141
|
+
bali_process_auth_rules(:can, operations)
|
104
142
|
end
|
105
143
|
|
106
144
|
def cannot(*operations)
|
107
|
-
|
145
|
+
bali_process_auth_rules(:cannot, operations)
|
108
146
|
end
|
109
147
|
|
110
148
|
def cant(*operations)
|
@@ -17,6 +17,14 @@ class Bali::Rule
|
|
17
17
|
self
|
18
18
|
end
|
19
19
|
|
20
|
+
def clone
|
21
|
+
cloned_rule = Bali::Rule.new(auth_val, operation)
|
22
|
+
cloned_rule.decider = decider if decider
|
23
|
+
cloned_rule.decider_type = decider_type if decider_type
|
24
|
+
|
25
|
+
cloned_rule
|
26
|
+
end
|
27
|
+
|
20
28
|
def auth_val=(aval)
|
21
29
|
# TODO: in version 3 remove :cant
|
22
30
|
if aval == :can || aval == :cannot
|
@@ -32,7 +40,7 @@ class Bali::Rule
|
|
32
40
|
if dectype == :if || dectype == :unless
|
33
41
|
@decider_type = dectype
|
34
42
|
else
|
35
|
-
raise Bali::DslError, "decider type can only be either if or unless"
|
43
|
+
raise Bali::DslError, "decider type can only be either if or unless, got: #{dectype}"
|
36
44
|
end
|
37
45
|
end
|
38
46
|
|
@@ -1,9 +1,16 @@
|
|
1
1
|
# the parent of all Bali::RuleGroup.
|
2
2
|
class Bali::RuleClass
|
3
3
|
attr_reader :target_class
|
4
|
-
attr_accessor :alias_name
|
5
4
|
|
5
|
+
# consist of canonised subtarget and its rule group, eg:
|
6
|
+
# {
|
7
|
+
# general_user: RuleGroup
|
8
|
+
# }
|
6
9
|
attr_accessor :rule_groups
|
10
|
+
|
11
|
+
# rule group for "other" subtargets, always checked the last time
|
12
|
+
# after the "more proper" rule groups are checked
|
13
|
+
attr_accessor :others_rule_group
|
7
14
|
|
8
15
|
def initialize(target_class)
|
9
16
|
if target_class.is_a?(Class)
|
@@ -13,19 +20,43 @@ class Bali::RuleClass
|
|
13
20
|
end
|
14
21
|
|
15
22
|
self.rule_groups = {}
|
23
|
+
self.others_rule_group = Bali::RuleGroup.new(target_class, "__*__")
|
16
24
|
end
|
17
25
|
|
18
26
|
def add_rule_group(rule_group)
|
19
27
|
if rule_group.is_a?(Bali::RuleGroup)
|
20
28
|
target_user = rule_group.subtarget
|
21
|
-
|
29
|
+
if target_user == "__*__" || target_user == :"__*__"
|
30
|
+
raise Bali::DslError, "__*__ is a reserved subtarget used by Bali's internal"
|
31
|
+
end
|
32
|
+
self.rule_groups[rule_group.subtarget] = rule_group
|
22
33
|
else
|
23
|
-
raise Bali::DslError, "Rule group must be an instance of Bali::RuleGroup"
|
34
|
+
raise Bali::DslError, "Rule group must be an instance of Bali::RuleGroup, got: #{rule_group.class.name}"
|
24
35
|
end
|
25
36
|
end
|
26
37
|
|
27
38
|
def rules_for(subtarget)
|
39
|
+
return others_rule_group if subtarget == "__*__"
|
28
40
|
subtarget = Bali::RuleGroup.canon_name(subtarget)
|
29
41
|
self.rule_groups[subtarget]
|
30
42
|
end
|
43
|
+
|
44
|
+
# options can contains:
|
45
|
+
# :target_class => identifying the target class on which the clone will be applied
|
46
|
+
def clone(options = {})
|
47
|
+
target_class = options.fetch(:target_class)
|
48
|
+
cloned_rc = Bali::RuleClass.new(target_class)
|
49
|
+
|
50
|
+
rule_groups.each do |subtarget, rule_group|
|
51
|
+
rule_group_clone = rule_group.clone
|
52
|
+
rule_group_clone.target = target_class
|
53
|
+
cloned_rc.add_rule_group(rule_group_clone)
|
54
|
+
end
|
55
|
+
|
56
|
+
others_rule_group_clone = others_rule_group.clone
|
57
|
+
others_rule_group_clone.target = target_class
|
58
|
+
cloned_rc.others_rule_group = others_rule_group_clone
|
59
|
+
|
60
|
+
cloned_rc
|
61
|
+
end
|
31
62
|
end
|
@@ -2,9 +2,6 @@ class Bali::RuleGroup
|
|
2
2
|
# the target class
|
3
3
|
attr_accessor :target
|
4
4
|
|
5
|
-
# the alias name for the target
|
6
|
-
attr_accessor :alias_tgt
|
7
|
-
|
8
5
|
# the user to which this rule group is applied
|
9
6
|
attr_accessor :subtarget
|
10
7
|
|
@@ -28,17 +25,30 @@ class Bali::RuleGroup
|
|
28
25
|
end
|
29
26
|
end
|
30
27
|
|
31
|
-
def initialize(target,
|
28
|
+
def initialize(target, subtarget)
|
32
29
|
self.target = target
|
33
|
-
self.alias_tgt = alias_tgt
|
34
30
|
self.subtarget = Bali::RuleGroup.canon_name(subtarget)
|
35
31
|
|
36
32
|
self.cans = {}
|
37
33
|
self.cants = {}
|
34
|
+
|
35
|
+
# by default, rule group is neither zeus nor plant
|
36
|
+
self.zeus = false
|
37
|
+
self.plant = false
|
38
|
+
end
|
39
|
+
|
40
|
+
def clone
|
41
|
+
cloned_rg = Bali::RuleGroup.new(target, subtarget)
|
42
|
+
cans.each_value { |can_rule| cloned_rg.add_rule(can_rule.clone) }
|
43
|
+
cants.each_value { |cant_rule| cloned_rg.add_rule(cant_rule.clone) }
|
44
|
+
cloned_rg.zeus = zeus
|
45
|
+
cloned_rg.plant = plant
|
46
|
+
|
47
|
+
cloned_rg
|
38
48
|
end
|
39
49
|
|
40
50
|
def add_rule(rule)
|
41
|
-
raise Bali::DslError, "Rule must be of class Bali::Rule" unless rule.is_a?(Bali::Rule)
|
51
|
+
raise Bali::DslError, "Rule must be of class Bali::Rule, got: #{rule.class.name}" unless rule.is_a?(Bali::Rule)
|
42
52
|
|
43
53
|
# operation cannot be defined twice
|
44
54
|
operation = rule.operation.to_sym
|
@@ -54,6 +64,11 @@ class Bali::RuleGroup
|
|
54
64
|
end
|
55
65
|
end
|
56
66
|
|
67
|
+
def clear_rules
|
68
|
+
self.cans = {}
|
69
|
+
self.cants = {}
|
70
|
+
end
|
71
|
+
|
57
72
|
def get_rule(auth_val, operation)
|
58
73
|
rule = nil
|
59
74
|
case auth_val
|
@@ -6,14 +6,9 @@ module Bali::Integrators::Rule
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def rule_class_for(target)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
else
|
13
|
-
raise Bali::DslError, "Target must be a class" unless target.is_a?(Class)
|
14
|
-
rule_class = Bali::RULE_CLASS_MAP[target.to_s]
|
15
|
-
return rule_class.nil? ? nil : rule_class
|
16
|
-
end
|
9
|
+
raise Bali::DslError, "Target must be a class" unless target.is_a?(Class)
|
10
|
+
rule_class = Bali::RULE_CLASS_MAP[target.to_s]
|
11
|
+
return rule_class.nil? ? nil : rule_class
|
17
12
|
end
|
18
13
|
|
19
14
|
# attempt to search the rule group, but if not exist, will return nil
|
@@ -30,26 +25,9 @@ module Bali::Integrators::Rule
|
|
30
25
|
def add_rule_class(rule_class)
|
31
26
|
if rule_class.is_a?(Bali::RuleClass)
|
32
27
|
target = rule_class.target_class
|
33
|
-
alias_target = rule_class.alias_name
|
34
28
|
|
35
29
|
raise Bali::DslError, "Target must be a class" unless target.is_a?(Class)
|
36
30
|
|
37
|
-
# remove any previous association of rule
|
38
|
-
begin
|
39
|
-
last_associated_alias = Bali::REVERSE_ALIASED_RULE_CLASS_MAP[target]
|
40
|
-
if last_associated_alias
|
41
|
-
Bali::ALIASED_RULE_CLASS_MAP.delete(last_associated_alias)
|
42
|
-
Bali::REVERSE_ALIASED_RULE_CLASS_MAP.delete(target)
|
43
|
-
Bali::RULE_CLASS_MAP.delete(target)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# if "as" is present
|
48
|
-
if alias_target.is_a?(Symbol)
|
49
|
-
Bali::ALIASED_RULE_CLASS_MAP[alias_target] = target
|
50
|
-
Bali::REVERSE_ALIASED_RULE_CLASS_MAP[target] = alias_target
|
51
|
-
end
|
52
|
-
|
53
31
|
Bali::RULE_CLASS_MAP[target.to_s] = rule_class
|
54
32
|
rule_class
|
55
33
|
else
|
data/lib/bali/objector.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# module that will be included in each instantiated target classes as defined
|
2
2
|
# in map_rules
|
3
3
|
module Bali::Objector
|
4
4
|
def self.included(base)
|
@@ -41,6 +41,38 @@ module Bali::Objector
|
|
41
41
|
end
|
42
42
|
|
43
43
|
module Bali::Objector::Statics
|
44
|
+
# FUZY-ed value is happen when it is not really clear, need further cross checking,
|
45
|
+
# whether it is really allowed or not. It happens for example in block with others, such as this:
|
46
|
+
#
|
47
|
+
# describe :finance do
|
48
|
+
# cannot :view
|
49
|
+
# end
|
50
|
+
# others do
|
51
|
+
# can :view
|
52
|
+
# can :index
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# In the example above, objecting cannot view on finance will result in STRONG_FALSE, but
|
56
|
+
# objecting can index on finance will result in FUZY_TRUE.
|
57
|
+
#
|
58
|
+
# Eventually, all FUZY value will be normal TRUE or FALSE if no definite counterpart
|
59
|
+
# is found/defined
|
60
|
+
BALI_FUZY_FALSE = -2
|
61
|
+
BALI_FUZY_TRUE = 2
|
62
|
+
BALI_FALSE = -1
|
63
|
+
BALI_TRUE = 1
|
64
|
+
|
65
|
+
# translate response for value above to traditional true/false
|
66
|
+
def bali_translate_response(bali_bool_value)
|
67
|
+
raise Bali::Error, "Expect bali value to be an integer" unless bali_bool_value.is_a?(Integer)
|
68
|
+
if bali_bool_value < 0
|
69
|
+
return false
|
70
|
+
elsif bali_bool_value > 0
|
71
|
+
return true
|
72
|
+
else
|
73
|
+
raise Bali::Error, "Bali bool value can either be negative or positive integer"
|
74
|
+
end
|
75
|
+
end
|
44
76
|
|
45
77
|
# will return array
|
46
78
|
def bali_translate_subtarget_roles(_subtarget_roles)
|
@@ -61,7 +93,7 @@ module Bali::Objector::Statics
|
|
61
93
|
Bali::TRANSLATED_SUBTARGET_ROLES.each do |subtarget_class, roles_field_name|
|
62
94
|
if _subtarget_class == subtarget_class
|
63
95
|
deducted_roles = _subtarget.send(roles_field_name)
|
64
|
-
if deducted_roles.is_a?(String) || deducted_roles.is_a?(Symbol)
|
96
|
+
if deducted_roles.is_a?(String) || deducted_roles.is_a?(Symbol) || deducted_roles.is_a?(NilClass)
|
65
97
|
deducted_roles = [deducted_roles]
|
66
98
|
break
|
67
99
|
elsif deducted_roles.is_a?(Array)
|
@@ -87,42 +119,90 @@ module Bali::Objector::Statics
|
|
87
119
|
# if performed on a class-level, don't call its class or it will return
|
88
120
|
# Class. That's not what is expected.
|
89
121
|
if self.is_a?(Class)
|
90
|
-
|
122
|
+
klass = self
|
91
123
|
else
|
92
|
-
|
124
|
+
klass = self.class
|
93
125
|
end
|
94
126
|
|
127
|
+
rule_group = Bali::Integrators::Rule.rule_group_for(klass, subtarget)
|
128
|
+
other_rule_group = Bali::Integrators::Rule.rule_group_for(klass, "__*__")
|
129
|
+
|
130
|
+
rule = nil
|
131
|
+
|
95
132
|
# default of can? is false whenever RuleClass for that class is undefined
|
96
133
|
# or RuleGroup for that subtarget is not defined
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
134
|
+
if rule_group.nil?
|
135
|
+
# no more chance for checking
|
136
|
+
return BALI_FALSE if other_rule_group.nil?
|
137
|
+
else
|
138
|
+
# get the specific rule from its own describe block
|
139
|
+
rule = rule_group.get_rule(:can, operation)
|
140
|
+
end
|
101
141
|
|
102
|
-
#
|
103
|
-
|
142
|
+
# retrieve rule from others group
|
143
|
+
otherly_rule = other_rule_group.get_rule(:can, operation)
|
104
144
|
|
105
145
|
# godly subtarget is allowed to do as he wishes
|
106
146
|
# so long that the rule is not specificly defined
|
107
147
|
# or overwritten by subsequent rule
|
108
|
-
if rule_group.zeus?
|
148
|
+
if rule_group && rule_group.zeus?
|
109
149
|
if rule.nil?
|
150
|
+
_options = options.dup
|
151
|
+
_options[:cross_check] = true
|
152
|
+
_options[:original_subtarget] = original_subtarget if _options[:original_subtarget].nil?
|
153
|
+
|
154
|
+
check_val = self.bali_cannot?(subtarget, operation, record, _options)
|
155
|
+
|
110
156
|
# check further whether cant is defined to overwrite this can_all
|
111
|
-
if
|
112
|
-
return
|
157
|
+
if check_val == BALI_TRUE
|
158
|
+
return BALI_FALSE
|
113
159
|
else
|
114
|
-
return
|
160
|
+
return BALI_TRUE
|
115
161
|
end
|
116
162
|
end
|
117
163
|
end
|
118
164
|
|
165
|
+
# do after crosscheck
|
166
|
+
# plan subtarget is not allowed unless spesificly defined
|
167
|
+
return BALI_FALSE if rule_group && rule_group.plant? && rule.nil? && otherly_rule.nil?
|
168
|
+
|
119
169
|
if rule.nil?
|
120
170
|
# default if can? for undefined rule is false, after related clause
|
121
171
|
# cannot be found in cannot?
|
122
|
-
|
123
|
-
options[:cross_check]
|
124
|
-
|
125
|
-
|
172
|
+
|
173
|
+
unless options[:cross_check]
|
174
|
+
options[:cross_check] = true
|
175
|
+
cross_check_value = self.bali_cannot?(subtarget, operation, record, options)
|
176
|
+
end
|
177
|
+
|
178
|
+
# either if rule from others block is defined, and the result so far is fuzy
|
179
|
+
# or, otherly rule is defined, and it is still a cross check
|
180
|
+
# plus, the result is not a definite BALI_TRUE/BALI_FALSE
|
181
|
+
#
|
182
|
+
# rationalisation:
|
183
|
+
# 1. Definite answer such as BALI_TRUE and BALI_FALSE is to be prioritised over
|
184
|
+
# FUZY answer, because definite answer is not gathered from others block where
|
185
|
+
# FUZY answer is. Therefore, it is an intended result
|
186
|
+
# 2. If the answer is FUZY, otherly_rule only be considered if the result
|
187
|
+
# is either FUZY TRUE or FUZY FALSE, or
|
188
|
+
# 3. Or, when already in cross check mode, we cannot retrieve cross_check_value
|
189
|
+
# what we can is instead, if otherly rule is available, just to try the odd
|
190
|
+
if (otherly_rule && cross_check_value && !(cross_check_value == BALI_TRUE || cross_check_value == BALI_FALSE)) ||
|
191
|
+
(otherly_rule && (cross_check_value == BALI_FUZY_FALSE || cross_check_value == BALI_FUZY_TRUE)) ||
|
192
|
+
(otherly_rule && options[:cross_check] && cross_check_value.nil?)
|
193
|
+
# give chance to check at the others block
|
194
|
+
rule = otherly_rule
|
195
|
+
else
|
196
|
+
# either the return is not fuzy, or otherly rule is undefined
|
197
|
+
if cross_check_value == BALI_TRUE
|
198
|
+
return BALI_FALSE
|
199
|
+
elsif cross_check_value == BALI_FALSE
|
200
|
+
return BALI_TRUE
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
if rule
|
126
206
|
if rule.has_decider?
|
127
207
|
# must test first
|
128
208
|
decider = rule.decider
|
@@ -130,161 +210,185 @@ module Bali::Objector::Statics
|
|
130
210
|
case decider.arity
|
131
211
|
when 0
|
132
212
|
if rule.decider_type == :if
|
133
|
-
|
134
|
-
return true
|
135
|
-
else
|
136
|
-
return false
|
137
|
-
end
|
213
|
+
return decider.() ? BALI_TRUE : BALI_FALSE
|
138
214
|
elsif rule.decider_type == :unless
|
139
215
|
unless decider.()
|
140
|
-
return
|
216
|
+
return BALI_TRUE
|
141
217
|
else
|
142
|
-
return
|
218
|
+
return BALI_FALSE
|
143
219
|
end
|
144
220
|
end
|
145
221
|
when 1
|
146
222
|
if rule.decider_type == :if
|
147
|
-
|
148
|
-
return true
|
149
|
-
else
|
150
|
-
return false
|
151
|
-
end
|
223
|
+
return decider.(record) ? BALI_TRUE : BALI_FALSE
|
152
224
|
elsif rule.decider_type == :unless
|
153
225
|
unless decider.(record)
|
154
|
-
return
|
226
|
+
return BALI_TRUE
|
155
227
|
else
|
156
|
-
return
|
228
|
+
return BALI_FALSE
|
157
229
|
end
|
158
230
|
end
|
159
231
|
when 2
|
160
232
|
if rule.decider_type == :if
|
161
|
-
|
162
|
-
return true
|
163
|
-
else
|
164
|
-
return false
|
165
|
-
end
|
233
|
+
return decider.(record, original_subtarget) ? BALI_TRUE : BALI_FALSE
|
166
234
|
elsif rule.decider_type == :unless
|
167
235
|
unless decider.(record, original_subtarget)
|
168
|
-
return
|
236
|
+
return BALI_TRUE
|
169
237
|
else
|
170
|
-
return
|
238
|
+
return BALI_FALSE
|
171
239
|
end
|
172
240
|
end
|
173
241
|
end
|
174
242
|
else
|
175
243
|
# rule is properly defined
|
176
|
-
return
|
244
|
+
return BALI_TRUE
|
177
245
|
end
|
178
246
|
end
|
247
|
+
|
248
|
+
# return fuzy if otherly rule defines contrary to this (can)
|
249
|
+
if other_rule_group.get_rule(:cannot, operation)
|
250
|
+
return BALI_FUZY_FALSE
|
251
|
+
else
|
252
|
+
return BALI_FALSE
|
253
|
+
end
|
179
254
|
end
|
180
255
|
|
181
256
|
def bali_cannot?(subtarget, operation, record = self, options = {})
|
182
257
|
if self.is_a?(Class)
|
183
|
-
|
258
|
+
klass = self
|
184
259
|
else
|
185
|
-
|
260
|
+
klass = self.class
|
186
261
|
end
|
187
262
|
|
188
|
-
|
189
|
-
|
190
|
-
return true if rule_group.nil?
|
263
|
+
rule_group = Bali::Integrators::Rule.rule_group_for(klass, subtarget)
|
264
|
+
other_rule_group = Bali::Integrators::Rule.rule_group_for(klass, "__*__")
|
191
265
|
|
192
|
-
rule =
|
266
|
+
rule = nil
|
193
267
|
|
194
|
-
#
|
195
|
-
#
|
196
|
-
|
268
|
+
# default of cannot? is true whenever RuleClass for that class is undefined
|
269
|
+
# or RuleGroup for that subtarget is not defined
|
270
|
+
if rule_group.nil?
|
271
|
+
return BALI_TRUE if other_rule_group.nil?
|
272
|
+
else
|
273
|
+
# get the specific rule from its own describe block
|
274
|
+
rule = rule_group.get_rule(:cannot, operation)
|
275
|
+
end
|
197
276
|
|
277
|
+
otherly_rule = other_rule_group.get_rule(:cannot, operation)
|
198
278
|
# plant subtarget is not allowed to do things unless specificly defined
|
199
|
-
if rule_group.plant?
|
279
|
+
if rule_group && rule_group.plant?
|
200
280
|
if rule.nil?
|
281
|
+
_options = options.dup
|
282
|
+
_options[:cross_check] = true
|
283
|
+
_options[:original_subtarget] = original_subtarget if _options[:original_subtarget].nil?
|
284
|
+
|
201
285
|
# check further whether defined in can?
|
202
|
-
|
203
|
-
|
286
|
+
check_val = self.bali_can?(subtarget, operation, record, _options)
|
287
|
+
|
288
|
+
if check_val == BALI_TRUE
|
289
|
+
return BALI_FALSE # well, it is defined in can, so it must overwrite this cant_all rule
|
204
290
|
else
|
205
291
|
# plant, and then rule is not defined for further inspection. stright
|
206
292
|
# is not allowed to do this thing
|
207
|
-
return
|
293
|
+
return BALI_TRUE
|
208
294
|
end
|
209
295
|
end
|
210
296
|
end
|
211
297
|
|
212
|
-
# if rule cannot be found, then true is returned for cannot? unless
|
213
|
-
# can? is defined exactly for the same target, and subtarget, and record (if given)
|
214
298
|
if rule.nil?
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
299
|
+
unless options[:cross_check]
|
300
|
+
options[:cross_check] = true
|
301
|
+
cross_check_value = self.bali_can?(subtarget, operation, record, options)
|
302
|
+
end
|
303
|
+
|
304
|
+
if (otherly_rule && cross_check_value && !(cross_check_value == BALI_TRUE || cross_check_value == BALI_FALSE)) ||
|
305
|
+
(otherly_rule && (cross_check_value == BALI_FUZY_FALSE || cross_check_value == BALI_FUZY_TRUE)) ||
|
306
|
+
(otherly_rule && options[:cross_check] && cross_check_value.nil?)
|
307
|
+
rule = otherly_rule
|
308
|
+
else
|
309
|
+
if cross_check_value == BALI_TRUE
|
310
|
+
# from can? because of cross check, then it should be false
|
311
|
+
return BALI_FALSE
|
312
|
+
elsif cross_check_value == BALI_FALSE
|
313
|
+
# from can? because of cross check returning false
|
314
|
+
# then it should be true, that is, cannot
|
315
|
+
return BALI_TRUE
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
# do after cross check
|
321
|
+
# godly subtarget is not to be prohibited in his endeavours
|
322
|
+
# so long that no specific rule about this operation is defined
|
323
|
+
return BALI_FALSE if rule_group && rule_group.zeus? && rule.nil? && otherly_rule.nil?
|
324
|
+
|
325
|
+
if rule
|
219
326
|
if rule.has_decider?
|
220
327
|
decider = rule.decider
|
221
328
|
original_subtarget = options.fetch(:original_subtarget)
|
222
329
|
case decider.arity
|
223
330
|
when 0
|
224
331
|
if rule.decider_type == :if
|
225
|
-
|
226
|
-
return true
|
227
|
-
else
|
228
|
-
return false
|
229
|
-
end
|
332
|
+
return decider.() ? BALI_TRUE : BALI_FALSE
|
230
333
|
elsif rule.decider_type == :unless
|
231
334
|
unless decider.()
|
232
|
-
return
|
335
|
+
return BALI_TRUE
|
233
336
|
else
|
234
|
-
return
|
337
|
+
return BALI_FALSE
|
235
338
|
end
|
236
339
|
end
|
237
340
|
when 1
|
238
341
|
if rule.decider_type == :if
|
239
|
-
|
240
|
-
return true
|
241
|
-
else
|
242
|
-
return false
|
243
|
-
end
|
342
|
+
return decider.(record) ? BALI_TRUE : BALI_FALSE
|
244
343
|
elsif rule.decider_type == :unless
|
245
344
|
unless decider.(record)
|
246
|
-
return
|
345
|
+
return BALI_TRUE
|
247
346
|
else
|
248
|
-
return
|
347
|
+
return BALI_FALSE
|
249
348
|
end
|
250
349
|
end
|
251
350
|
when 2
|
252
351
|
if rule.decider_type == :if
|
253
|
-
|
254
|
-
return true
|
255
|
-
else
|
256
|
-
return false
|
257
|
-
end
|
352
|
+
return decider.(record, original_subtarget) ? BALI_TRUE : BALI_FALSE
|
258
353
|
elsif rule.decider_type == :unless
|
259
354
|
unless decider.(record, original_subtarget)
|
260
|
-
return
|
355
|
+
return BALI_TRUE
|
261
356
|
else
|
262
|
-
return
|
357
|
+
return BALI_FALSE
|
263
358
|
end
|
264
359
|
end
|
265
360
|
end
|
266
361
|
else
|
267
|
-
return
|
362
|
+
return BALI_TRUE # rule is properly defined
|
268
363
|
end # if rule has decider
|
269
364
|
end # if rule is nil
|
270
|
-
|
365
|
+
|
366
|
+
# return fuzy if otherly rule defines contrary to this cannot rule
|
367
|
+
if other_rule_group.get_rule(:can, operation)
|
368
|
+
return BALI_FUZY_TRUE
|
369
|
+
else
|
370
|
+
BALI_TRUE
|
371
|
+
end
|
372
|
+
end # bali cannot
|
271
373
|
|
272
374
|
def can?(subtarget_roles, operation, record = self, options = {})
|
273
375
|
subs = bali_translate_subtarget_roles(subtarget_roles)
|
274
376
|
# well, it is largely not used unless decider's is 2 arity
|
275
377
|
options[:original_subtarget] = options[:original_subtarget].nil? ? subtarget_roles : options[:original_subtarget]
|
276
378
|
|
277
|
-
can_value =
|
379
|
+
can_value = BALI_FALSE
|
278
380
|
role = nil
|
279
381
|
|
280
382
|
subs.each do |subtarget|
|
281
|
-
next if can_value
|
383
|
+
next if can_value == BALI_TRUE
|
282
384
|
role = subtarget
|
283
385
|
can_value = bali_can?(role, operation, record, options)
|
284
386
|
end
|
285
387
|
|
286
|
-
|
287
|
-
|
388
|
+
if can_value == BALI_FALSE && block_given?
|
389
|
+
yield options[:original_subtarget], role, bali_translate_response(can_value)
|
390
|
+
end
|
391
|
+
bali_translate_response can_value
|
288
392
|
rescue => e
|
289
393
|
if e.is_a?(Bali::AuthorizationError)
|
290
394
|
raise e
|
@@ -302,19 +406,20 @@ module Bali::Objector::Statics
|
|
302
406
|
subs = bali_translate_subtarget_roles subtarget_roles
|
303
407
|
options[:original_subtarget] = options[:original_subtarget].nil? ? subtarget_roles : options[:original_subtarget]
|
304
408
|
|
409
|
+
cant_value = BALI_TRUE
|
410
|
+
|
305
411
|
subs.each do |subtarget|
|
412
|
+
next if cant_value == BALI_FALSE
|
306
413
|
cant_value = bali_cannot?(subtarget, operation, record, options)
|
307
|
-
if cant_value ==
|
414
|
+
if cant_value == BALI_FALSE
|
308
415
|
role = subtarget
|
309
416
|
if block_given?
|
310
|
-
yield options[:original_subtarget], role,
|
311
|
-
else
|
312
|
-
return false
|
417
|
+
yield options[:original_subtarget], role, bali_translate_response(cant_value)
|
313
418
|
end
|
314
419
|
end
|
315
420
|
end
|
316
421
|
|
317
|
-
|
422
|
+
bali_translate_response cant_value
|
318
423
|
rescue => e
|
319
424
|
if e.is_a?(Bali::AuthorizationError)
|
320
425
|
raise e
|