Module: ComputedModel::ClassMethods
- Defined in:
- lib/computed_model.rb
Overview
A set of class methods for ComputedModel. Automatically included to the singleton class when you include ComputedModel.
Instance Method Summary collapse
-
#bulk_load_and_compute(deps, **options) ⇒ Array<Object>
The core routine for batch-loading.
-
#computed(meth_name) ⇒ Symbol
Declares a computed attribute.
- #computing_plan(deps) ⇒ Plan
-
#define_loader(meth_name, key:) {|keys, subdeps, **options| ... } ⇒ void
Declares a loaded attribute.
-
#define_primary_loader(meth_name) {|**options| ... } ⇒ void
Declares a primary attribute.
-
#delegate_dependency(*methods, to:, allow_nil: nil, prefix: nil, include_subdeps: nil) ⇒ void
A shorthand for simple computed attributes.
-
#dependency(*deps) ⇒ void
Declares the dependency of a computed attribute.
Instance Method Details
#bulk_load_and_compute(deps, **options) ⇒ Array<Object>
The core routine for batch-loading.
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/computed_model.rb', line 227 def bulk_load_and_compute(deps, **) unless @__computed_model_primary_attribute raise ArgumentError, "No primary loader defined" end objs = orig_objs = nil plan = computing_plan(deps) plan.load_order.each do |dep_name| if @__computed_model_primary_attribute == dep_name orig_objs = @__computed_model_primary_loader.call(plan.subdeps_hash[dep_name], **) objs = orig_objs.dup elsif @__computed_model_dependencies.key?(dep_name) raise "Bug: objs is nil" if objs.nil? objs.each do |obj| obj.send(:"compute_#{dep_name}") end elsif @__computed_model_loaders.key?(dep_name) raise "Bug: objs is nil" if objs.nil? l = @__computed_model_loaders[dep_name] keys = objs.map { |o| o.instance_exec(&(l.key_proc)) } subobj_by_key = l.load_proc.call(keys, plan.subdeps_hash[dep_name], **) objs.zip(keys) do |obj, key| obj.send(:"#{dep_name}=", subobj_by_key[key]) end else raise "No dependency info for #{self}##{dep_name}" end objs.reject! { |obj| !obj.computed_model_error.nil? } end orig_objs end |
#computed(meth_name) ⇒ Symbol
Declares a computed attribute. See #dependency too.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/computed_model.rb', line 76 def computed(meth_name) var_name = :"@#{meth_name}" meth_name_orig = :"#{meth_name}_orig" compute_meth_name = :"compute_#{meth_name}" @__computed_model_dependencies[meth_name] = ComputedModel.normalize_dependencies(@__computed_model_next_dependency) remove_instance_variable(:@__computed_model_next_dependency) alias_method meth_name_orig, meth_name define_method(meth_name) do raise NotLoaded, "the field #{meth_name} is not loaded" unless instance_variable_defined?(var_name) instance_variable_get(var_name) end define_method(compute_meth_name) do instance_variable_set(var_name, send(meth_name_orig)) end if public_method_defined?(meth_name_orig) public meth_name elsif protected_method_defined?(meth_name_orig) protected meth_name elsif private_method_defined?(meth_name_orig) private meth_name end meth_name end |
#computing_plan(deps) ⇒ Plan
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/computed_model.rb', line 264 def computing_plan(deps) normalized = ComputedModel.normalize_dependencies(deps) load_order = [] subdeps_hash = {} visiting = Set[] visited = Set[] if @__computed_model_primary_attribute load_order << @__computed_model_primary_attribute visiting.add @__computed_model_primary_attribute visited.add @__computed_model_primary_attribute subdeps_hash[@__computed_model_primary_attribute] ||= [] end normalized.each do |dep_name, dep_subdeps| computing_plan_dfs(dep_name, dep_subdeps, load_order, subdeps_hash, visiting, visited) end Plan.new(load_order, subdeps_hash) end |
#define_loader(meth_name, key:) {|keys, subdeps, **options| ... } ⇒ void
This method returns an undefined value.
Declares a loaded attribute. See #dependency and #define_primary_loader too.
define_loader :foo do ... end generates a reader foo and a writer foo=.
The writer is only meant to be used in the loader.
The responsibility of loader is to call foo= for all the given objects,
or set computed_model_error otherwise.
165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/computed_model.rb', line 165 def define_loader(meth_name, key:, &block) raise ArgumentError, "No block given" unless block var_name = :"@#{meth_name}" @__computed_model_loaders[meth_name] = Loader.new(key, block) define_method(meth_name) do raise NotLoaded, "the field #{meth_name} is not loaded" unless instance_variable_defined?(var_name) instance_variable_get(var_name) end attr_writer meth_name end |
#define_primary_loader(meth_name) {|**options| ... } ⇒ void
This method returns an undefined value.
Declares a primary attribute. See #define_loader and #dependency too.
define_primary_loader :foo do ... end generates a reader foo and
a writer foo=.
The writer is only meant to be used in the loader.
The responsibility of the primary loader is to list up all the relevant
primary models, and initialize instances of the subclass of ComputedModel
with @foo set to the primary model which is just being found.
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/computed_model.rb', line 204 def define_primary_loader(meth_name, &block) raise ArgumentError, "No block given" unless block raise ArgumentError, "Primary loader has already been defined" if @__computed_model_primary_attribute var_name = :"@#{meth_name}" @__computed_model_primary_loader = block @__computed_model_primary_attribute = meth_name define_method(meth_name) do raise NotLoaded, "the field #{meth_name} is not loaded" unless instance_variable_defined?(var_name) instance_variable_get(var_name) end attr_writer meth_name end |
#delegate_dependency(*methods, to:, allow_nil: nil, prefix: nil, include_subdeps: nil) ⇒ void
This method returns an undefined value.
A shorthand for simple computed attributes.
Use #computed for more complex definition.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/computed_model.rb', line 122 def delegate_dependency(*methods, to:, allow_nil: nil, prefix: nil, include_subdeps: nil) method_prefix = prefix ? "#{prefix}_" : "" methods.each do |meth_name| pmeth_name = :"#{method_prefix}#{meth_name}" if include_subdeps dependency to=>meth_name else dependency to end if allow_nil define_method(pmeth_name) do send(to)&.public_send(meth_name) end else define_method(pmeth_name) do send(to).public_send(meth_name) end end computed pmeth_name end end |
#dependency(*deps) ⇒ void
This method returns an undefined value.
Declares the dependency of a computed attribute. See #computed too.
60 61 62 63 |
# File 'lib/computed_model.rb', line 60 def dependency(*deps) @__computed_model_next_dependency ||= [] @__computed_model_next_dependency.push(*deps) end |