Class: Hyperloop::InternalClassPolicy
- Inherits:
-
Object
- Object
- Hyperloop::InternalClassPolicy
- Defined in:
- lib/hyper-operation/transport/policy.rb
Constant Summary collapse
- EXPOSED_METHODS =
[ :regulate_class_connection, :always_allow_connection, :regulate_instance_connections, :regulate_all_broadcasts, :regulate_broadcast, :dispatch_to, :regulate_dispatches_from, :always_dispatch_from, :allow_change, :allow_create, :allow_read, :allow_update, :allow_destroy ]
- CHANGE_POLICIES =
[:create, :update, :destroy]
Instance Attribute Summary collapse
-
#regulated_klass ⇒ Object
readonly
Returns the value of attribute regulated_klass.
Class Method Summary collapse
- .allow_policy(policy, method) ⇒ Object
- .ar_base_descendants_map_cache ⇒ Object
- .regulated_klasses ⇒ Object
Instance Method Summary collapse
- #allow_change(*args, ®ulation) ⇒ Object
- #always_allow_connection(*args) ⇒ Object
- #always_dispatch_from(*args, ®ulation) ⇒ Object
- #check_valid_on_option(policy) ⇒ Object
- #dispatch_to(*args, ®ulation) ⇒ Object
- #get_ar_model(str) ⇒ Object
-
#initialize(regulated_klass) ⇒ InternalClassPolicy
constructor
A new instance of InternalClassPolicy.
- #process_args(policy, allowed_opts, args, regulation) ⇒ Object
- #process_to_opt(allowed_opts, opts, args) ⇒ Object
- #regulate(regulation_klass, policy, args, ®ulation) ⇒ Object
- #regulate_all_broadcasts(*args, ®ulation) ⇒ Object
- #regulate_broadcast(*args, ®ulation) ⇒ Object
- #regulate_class_connection(*args, ®ulation) ⇒ Object
- #regulate_dispatches_from(*args, ®ulation) ⇒ Object
- #regulate_instance_connections(*args, ®ulation) ⇒ Object
Constructor Details
#initialize(regulated_klass) ⇒ InternalClassPolicy
Returns a new instance of InternalClassPolicy.
5 6 7 8 9 10 11 12 13 14 15 16 17 |
# File 'lib/hyper-operation/transport/policy.rb', line 5 def initialize(regulated_klass) unless regulated_klass.is_a?(Class) # attempt to constantize the class in case eager_loading in production # has loaded the policy before the class. THis will insure that if # there is a class being regulated, it is loaded first. begin regulated_klass.constantize rescue NameError nil end end @regulated_klass = regulated_klass end |
Instance Attribute Details
#regulated_klass ⇒ Object (readonly)
Returns the value of attribute regulated_klass.
19 20 21 |
# File 'lib/hyper-operation/transport/policy.rb', line 19 def regulated_klass @regulated_klass end |
Class Method Details
.allow_policy(policy, method) ⇒ Object
78 79 80 81 82 83 84 |
# File 'lib/hyper-operation/transport/policy.rb', line 78 def self.allow_policy(policy, method) define_method "allow_#{policy}" do |*args, ®ulation| process_args(policy, [], args, regulation) do |model| get_ar_model(model).class_eval { define_method("#{method}_permitted?", ®ulation) } end end end |
.ar_base_descendants_map_cache ⇒ Object
101 102 103 |
# File 'lib/hyper-operation/transport/policy.rb', line 101 def self.ar_base_descendants_map_cache @ar_base_descendants_map_cache ||= ActiveRecord::Base.descendants.map(&:name) end |
.regulated_klasses ⇒ Object
128 129 130 |
# File 'lib/hyper-operation/transport/policy.rb', line 128 def self.regulated_klasses @regulated_klasses ||= Set.new end |
Instance Method Details
#allow_change(*args, ®ulation) ⇒ Object
90 91 92 93 94 95 96 97 98 99 |
# File 'lib/hyper-operation/transport/policy.rb', line 90 def allow_change(*args, ®ulation) process_args('change', [:on], args, regulation) do |model, opts| model = get_ar_model(model) opts[:on] ||= CHANGE_POLICIES opts[:on].each do |policy| check_valid_on_option policy model.class_eval { define_method("#{policy}_permitted?", ®ulation) } end end end |
#always_allow_connection(*args) ⇒ Object
32 33 34 |
# File 'lib/hyper-operation/transport/policy.rb', line 32 def always_allow_connection(*args) regulate(ClassConnectionRegulation, nil, args) { true } end |
#always_dispatch_from(*args, ®ulation) ⇒ Object
57 58 59 |
# File 'lib/hyper-operation/transport/policy.rb', line 57 def always_dispatch_from(*args, ®ulation) regulate_dispatches_from(*args) { true } end |
#check_valid_on_option(policy) ⇒ Object
166 167 168 169 170 171 |
# File 'lib/hyper-operation/transport/policy.rb', line 166 def check_valid_on_option(policy) unless CHANGE_POLICIES.include? policy valid_policies = CHANGE_POLICIES.collect { |s| ":{s}" }.to_sentence raise "only #{valid_policies} are allowed on the regulate_access :on option" end end |
#dispatch_to(*args, ®ulation) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/hyper-operation/transport/policy.rb', line 61 def dispatch_to(*args, ®ulation) actual_klass = if regulated_klass.is_a?(Class) regulated_klass else begin regulated_klass.constantize rescue NameError nil end end raise 'you can only dispatch_to Operation classes' unless actual_klass.respond_to? :dispatch_to actual_klass.dispatch_to(actual_klass) actual_klass.dispatch_to(*args, ®ulation) end |
#get_ar_model(str) ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/hyper-operation/transport/policy.rb', line 105 def get_ar_model(str) if str.is_a?(Class) unless str <= ActiveRecord::Base Hyperloop::InternalPolicy.raise_operation_access_violation(:non_ar_class, "#{str} is not a subclass of ActiveRecord::Base") end str else # we used to cache this here, but during eager loading the cache may get partially filled and never updated # so this guard will fail, now performance will be suckish, as this guard, required for security, takes some ms # def self.ar_base_descendants_map_cache # @ar_base_descendants_map_cache ||= ActiveRecord::Base.descendants.map(&:name) # end # if Rails.env.production? && !Hyperloop::InternalClassPolicy.ar_base_descendants_map_cache.include?(str) if Rails.application.config.eager_load && !ActiveRecord::Base.descendants.map(&:name).include?(str) # AR::Base.descendants is eager loaded in production -> this guard works. # In development it may be empty or partially filled -> this guard may fail. # Thus guarded here only in production. Hyperloop::InternalPolicy.raise_operation_access_violation(:non_ar_class, "#{str} is either not defined or is not a subclass of ActiveRecord::Base") end Object.const_get(str) end end |
#process_args(policy, allowed_opts, args, regulation) ⇒ Object
139 140 141 142 143 144 145 146 147 |
# File 'lib/hyper-operation/transport/policy.rb', line 139 def process_args(policy, allowed_opts, args, regulation) raise "you must provide a block to the regulate_#{policy} method" unless regulation *args, opts = args if args.last.is_a? Hash opts ||= {} args = process_to_opt(allowed_opts, opts, args) args.each do |regulated_klass| yield regulated_klass, opts end end |
#process_to_opt(allowed_opts, opts, args) ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/hyper-operation/transport/policy.rb', line 149 def process_to_opt(allowed_opts, opts, args) opts.each do |opt, value| unless opt == :to || allowed_opts.include?(opt) raise "Unknown ':#{opt} => #{value}' option in policy definition" end end if (to = opts[:to]) raise "option to: :#{to} is not recognized in allow_#{policy}" unless to == :all raise "option to: :all cannot be used with other classes" unless args.empty? [ActiveRecord::Base] elsif args.empty? [@regulated_klass] else args end end |
#regulate(regulation_klass, policy, args, ®ulation) ⇒ Object
132 133 134 135 136 137 |
# File 'lib/hyper-operation/transport/policy.rb', line 132 def regulate(regulation_klass, policy, args, ®ulation) process_args(policy, regulation_klass.allowed_opts, args, regulation) do |regulated_klass, opts| self.class.regulated_klasses << regulated_klass.to_s regulation_klass.add_regulation regulated_klass, opts, ®ulation end end |
#regulate_all_broadcasts(*args, ®ulation) ⇒ Object
40 41 42 |
# File 'lib/hyper-operation/transport/policy.rb', line 40 def regulate_all_broadcasts(*args, ®ulation) regulate(ChannelBroadcastRegulation, :all_broadcasts, args, ®ulation) end |
#regulate_broadcast(*args, ®ulation) ⇒ Object
44 45 46 |
# File 'lib/hyper-operation/transport/policy.rb', line 44 def regulate_broadcast(*args, ®ulation) regulate(InstanceBroadcastRegulation, :broadcast, args, ®ulation) end |
#regulate_class_connection(*args, ®ulation) ⇒ Object
28 29 30 |
# File 'lib/hyper-operation/transport/policy.rb', line 28 def regulate_class_connection(*args, ®ulation) regulate(ClassConnectionRegulation, :class_connection, args, ®ulation) end |
#regulate_dispatches_from(*args, ®ulation) ⇒ Object
48 49 50 51 52 53 54 55 |
# File 'lib/hyper-operation/transport/policy.rb', line 48 def regulate_dispatches_from(*args, ®ulation) args.each do |klass| unless klass.respond_to? :dispatch_to raise 'you can only regulate_dispatches_from Operation classes' end klass._dispatch_to(self) { |sself| sself.regulated_klass if instance_eval(®ulation) } end end |
#regulate_instance_connections(*args, ®ulation) ⇒ Object
36 37 38 |
# File 'lib/hyper-operation/transport/policy.rb', line 36 def regulate_instance_connections(*args, ®ulation) regulate(InstanceConnectionRegulation, :instance_connections, args, ®ulation) end |