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.
@@ -7,10 +7,19 @@ class Bali::MapRulesDsl
7
7
  end
8
8
 
9
9
  # defining rules
10
- def rules_for(target_class, target_alias_hash = {}, &block)
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
- self.current_rule_class.alias_name = target_alias_hash[:as] || target_alias_hash["as"]
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
- 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: symbol, string, nil and hash"
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
- target_class = self.map_rules_dsl.current_rule_class.target_class
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
- subtargets.each do |subtarget|
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, target_alias, subtarget)
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 # mutex synchronize
68
- end # each subtarget
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 process_auth_rules(auth_val, operations)
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 # process_auth_rules
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
- process_auth_rules(:can, operations)
141
+ bali_process_auth_rules(:can, operations)
104
142
  end
105
143
 
106
144
  def cannot(*operations)
107
- process_auth_rules(:cannot, operations)
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
- self.rule_groups[Bali::RuleGroup.canon_name(target_user)] = rule_group
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, alias_tgt, subtarget)
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
- if target.is_a?(Symbol)
10
- class_name = Bali::ALIASED_RULE_CLASS_MAP[target]
11
- return class_name.nil? ? nil : rule_class_for(class_name)
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
@@ -1,4 +1,4 @@
1
- # class that will be included in each instantiated target classes as defined
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
- rule_group = Bali::Integrators::Rule.rule_group_for(self, subtarget)
122
+ klass = self
91
123
  else
92
- rule_group = Bali::Integrators::Rule.rule_group_for(self.class, subtarget)
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
- return false if rule_group.nil?
98
-
99
- # get the specific rule
100
- rule = rule_group.get_rule(:can, operation)
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
- # plan subtarget is not allowed unless spesificly defined
103
- return false if rule_group.plant? && rule.nil?
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 self.cannot?(subtarget, operation, record, cross_check: true)
112
- return false
157
+ if check_val == BALI_TRUE
158
+ return BALI_FALSE
113
159
  else
114
- return true
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
- return false if options[:cross_check]
123
- options[:cross_check] = true
124
- return !self.cannot?(subtarget, operation, record, options)
125
- else
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
- if decider.()
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 true
216
+ return BALI_TRUE
141
217
  else
142
- return false
218
+ return BALI_FALSE
143
219
  end
144
220
  end
145
221
  when 1
146
222
  if rule.decider_type == :if
147
- if decider.(record)
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 true
226
+ return BALI_TRUE
155
227
  else
156
- return false
228
+ return BALI_FALSE
157
229
  end
158
230
  end
159
231
  when 2
160
232
  if rule.decider_type == :if
161
- if decider.(record, original_subtarget)
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 true
236
+ return BALI_TRUE
169
237
  else
170
- return false
238
+ return BALI_FALSE
171
239
  end
172
240
  end
173
241
  end
174
242
  else
175
243
  # rule is properly defined
176
- return true
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
- rule_group = Bali::Integrators::Rule.rule_group_for(self, subtarget)
258
+ klass = self
184
259
  else
185
- rule_group = Bali::Integrators::Rule.rule_group_for(self.class, subtarget)
260
+ klass = self.class
186
261
  end
187
262
 
188
- # default of cannot? is true whenever RuleClass for that class is undefined
189
- # or RuleGroup for that subtarget is not defined
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 = rule_group.get_rule(:cannot, operation)
266
+ rule = nil
193
267
 
194
- # godly subtarget is not to be prohibited in his endeavours
195
- # so long that no specific rule about this operation is defined
196
- return false if rule_group.zeus? && rule.nil?
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
- if self.can?(subtarget, operation, record, cross_check: true)
203
- return false # well, it is defined in can, so it must overwrite this cant_all rule
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 true
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
- return true if options[:cross_check]
216
- options[:cross_check] = true
217
- return !self.can?(subtarget, operation, record, options)
218
- else
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
- if decider.()
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 true
335
+ return BALI_TRUE
233
336
  else
234
- return false
337
+ return BALI_FALSE
235
338
  end
236
339
  end
237
340
  when 1
238
341
  if rule.decider_type == :if
239
- if decider.(record)
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 true
345
+ return BALI_TRUE
247
346
  else
248
- return false
347
+ return BALI_FALSE
249
348
  end
250
349
  end
251
350
  when 2
252
351
  if rule.decider_type == :if
253
- if decider.(record, original_subtarget)
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 true
355
+ return BALI_TRUE
261
356
  else
262
- return false
357
+ return BALI_FALSE
263
358
  end
264
359
  end
265
360
  end
266
361
  else
267
- return true # rule is properly defined
362
+ return BALI_TRUE # rule is properly defined
268
363
  end # if rule has decider
269
364
  end # if rule is nil
270
- end
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 = false
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
- yield options[:original_subtarget], role, can_value if can_value == false && block_given?
287
- can_value
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 == false
414
+ if cant_value == BALI_FALSE
308
415
  role = subtarget
309
416
  if block_given?
310
- yield options[:original_subtarget], role, false
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
- true
422
+ bali_translate_response cant_value
318
423
  rescue => e
319
424
  if e.is_a?(Bali::AuthorizationError)
320
425
  raise e