module KRLogic module RubyCodeBlocks # TODO: implement stuff for when inside a conditions block class RubyCodeEnvironment module RefIdChainer def method_missing(sym, *args, &block) meth = sym.to_s raise "KR Relation Rule reference #{meth} should not take arguments" if (args.size > 0) raise "KR Relation Rule reference #{meth} should not take a block" if (block) id_parts = [@current_id_parts, sym.to_s].flatten KRRelationRuleRef.new(@env_internals, id_parts) end end class EnvInternals include RJBM::JAccess j_import( 'mx.org.pescador.krmodel.rules.RuleManager', 'mx.org.pescador.krmodel.ruleappliers.KRRelationsManager', 'mx.org.pescador.krmodel.rules.KRRelationSide', 'mx.org.pescador.krmodel.ruleappliers.CompVectorValueManager') attr_reader(:return_type, :can_assign) def initialize(return_type, can_assign, from_doov, lang, fetched_text_bpvs, highlightedDependencies, hlContext) @return_type, @can_assign, @from_doov, @lang, @fetched_text_bpvs, @highlightedDependencies, @hlContext = return_type, can_assign, from_doov, lang, fetched_text_bpvs, highlightedDependencies, hlContext end def rule_set @from_doov.boundToRS end def realm rule_set.definedByRealm end def get_krr_rule(id_parts) RuleManager.getKRRelationRuleFromSplitId(id_parts, rule_set) end def get_node_ref(do_or_val) if (do_or_val.isValue) if (do_or_val.isFundamental) FundamentalVallRef.new(do_or_val, self) else ComplexValRef.new(do_or_val, self) end else DescribableObjectRef.new(do_or_val, self) end end def krr_request(start_node_ref, krr_rule, inv, non_inf) side = get_side(inv) raise "Traversal on non-inferenced triples not yet implemented" if (non_inf) nodes_from_krr = KRRelationsManager.getNodes(start_node_ref.internal_obj.node, side, krr_rule, @lang) KRRRequestResult.new(nodes_from_krr, self, start_node_ref, krr_rule) end def multi_krr_request(req_result_w_start_nodes, krr_rule, inv, non_inf) side = get_side(inv) nodes_from_krr = KRRelationsManager.getNodesFromMany(req_result_w_start_nodes.internal_graph_nodes, side, krr_rule, @lang) KRRRequestResult.new(nodes_from_krr, self, nil, krr_rule) end def comp_v_value(val, comp_v_id) val_i_obj = val.internal_obj comp_v = val_i_obj.getCompVector(comp_v_id) cast(CompVectorValueManager.getValue(val_i_obj, comp_v).valAsString, comp_v.returnType) end def uses_comp_v_func(val, comp_v_id) val_i_obj = val.internal_obj val_i_obj.usesCompVector(comp_v_id) end def non_default_text_bpv(node, func_id) node_i_obj = node.internal_obj text_bpv = node_i_obj.getTextBPV(func_id, @lang) process_text_bpv(text_bpv) end def uses_text_bpv_func(node, func_id) node_i_obj = node.internal_obj node_i_obj.usesTextBPVFunction(func_id) end def get_type_in_code(fund_val_ref) rs = fund_val_ref.internal_obj.boundToRS rs.typeInCode end def get_side(inv) if (inv) side = KRRelationSide.OUT else side = KRRelationSide.IN end end private :get_side def cast(o, compatible_type) # the local variable o is refered in the string evaluated eval(compatible_type.rubyConversionBlock) end def get_default_text_bpv(node_ref) text_bpv = node_ref.internal_obj.getDefaultTextBPV(@lang) process_text_bpv(text_bpv) end def process_text_bpv(text_bpv) @fetched_text_bpvs.add(text_bpv) if (@fetched_text_bpvs) if (@highlightedDependencies) text_bpv = @hlContext.getHighlightedOrNormal(text_bpv, @highlightedDependencies) end text_bpv.val end private :process_text_bpv end class NodeRef def initialize(do_or_val, env_internals) @do_or_val, @env_internals = do_or_val, env_internals end def *(krr_rule_ref) @env_internals.krr_request(self, krr_rule_ref.rule, krr_rule_ref.inv, krr_rule_ref.non_inf) end def node_to_string @do_or_val.nodeToString end def internal_obj @do_or_val end def is_fund_val false end def ==(other_node_ref) # Just compares node_to_string results. This is almost always what is wanted. # Other options: use the equals method on the internal Jena node (only for Resources) # or implement our own equals function in the Java layer. Standard == between # internal node objects doesn't seem to work, perhaps rjb is the reason. if (!other_node_ref.class.ancestors.include?(NodeRef)) raise "Incompatible classes compared using ==" end (node_to_string == other_node_ref.node_to_string) ? true : false end def text_bpv @env_internals.get_default_text_bpv(self) end def get_special_text_bpv(func_id) if (@env_internals.uses_text_bpv_func(self, func_id)) @env_internals.non_default_text_bpv(self, func_id) else raise "No function #{meth} available for #{@do_or_val.nodeToString}" end end private :get_special_text_bpv end class DescribableObjectRef < NodeRef def image_bpv # TODO: here we should get the image bpv # this code is just to test the ruby code block framework "[imageBPV of #{@do_or_val.nodeToString}]" end def val raise "Cannot use .val method on a resource: #{@do_or_val.nodeToString}" end def method_missing(sym, *args, &block) # TODO: rais an error if arguments are sent get_special_text_bpv(sym.to_s) end end class ValueRef < NodeRef def image_bpv raise "Cannot use .image_bpv method on a value: #{@do_or_val.nodeToString}" end def method_missing(sym, *args, &block) # TODO: rais an error if arguments are sent meth = sym.to_s if (@env_internals.uses_comp_v_func(self, meth)) @env_internals.comp_v_value(self, meth) else get_special_text_bpv(sym.to_s) end end end class ComplexValRef < ValueRef def val raise "Cannot use .val method on a complex value: #{@do_or_val.nodeToString}" end end class FundamentalVallRef < ValueRef def val v = @do_or_val.value type = @env_internals.get_type_in_code(self) @env_internals.cast(v, type) end def is_fund_val true end end class KRRelationRuleRef include RefIdChainer attr_reader(:inv, :non_inf) def initialize(env_internals, id_parts) @env_internals, @current_id_parts = env_internals, id_parts @inv, @non_inf = false, false end def rule @env_internals.get_krr_rule(@current_id_parts) end def []*args @inv = args.include?('inv') @non_inf = args.include?('non_inf') self end end class KRRRequestResult def initialize(nodes_from_krr, env_internals, start_node_ref, krr_rule) @nodes_from_krr, @env_internals, @start_node_ref, @krr_rule = nodes_from_krr, env_internals, start_node_ref, krr_rule end def size @nodes_from_krr.size end def [](i) if (i < size) # Note: the following code seems to subvert the Java types of these methods # and allows us to access the real methods of the underlying object. Hmmm. @env_internals.get_node_ref(@nodes_from_krr.get(i).node.wrapper) else raise "Requested out-of-range node: " + @start_node_ref.node_to_string end end def contains(node_ref) if (!node_ref.class.ancestors.include?(NodeRef)) raise "Argument for the method 'contains' must be a node" end @nodes_from_krr.contains(node_ref.internal_obj.node) end def each for i in 0...size yield(self[i]) end end def internal_graph_nodes @nodes_from_krr.getGraphNodes end def text_bpv size_warning self[0].text_bpv end def image_bpv size_warning self[0].image_bpv end def val size_warning self[0].val end def method_missing(sym, *args, &block) size_warning self[0].send(sym, *args, &block) end def size_warning # TODO: make this warning provide more info CustomLogger.info("Using method for single result for query with multiple results:" + self[0].node_to_string + " " + @start_node_ref.node_to_string) if (size > 1) end private :size_warning def *(krr_rule_ref) @env_internals.multi_krr_request(self, krr_rule_ref.rule, krr_rule_ref.inv, krr_rule_ref.non_inf) end # @out, resultado de solicitud de relaciones: # delegates for first result: .text_bpv, .image_bpv y comp vectors # (throws warning if used when there is more than one result) # for accessing result set: .size, .includes(node ref), [], .each end include RefIdChainer def initialize(return_type, can_assign, from_doov, lang, fetched_text_bpvs, highlightedDependencies, hlContext) @env_internals = EnvInternals.new(return_type, can_assign, from_doov, lang, fetched_text_bpvs, highlightedDependencies, hlContext) @current_id_parts = [] from_doov_node_ref = @env_internals.get_node_ref(from_doov) # Node the slight incoherence: sometimes we worry about status in the graphnode # hierarchy, sometimes about status in the DOorVal hierarchy # TODO: clean this up if (from_doov.isLiteral) instance_variable_set(:@lit, from_doov_node_ref) else instance_variable_set(:@root, from_doov_node_ref) end end def get_binding binding end def inv 'inv' end def non_inf 'non_inf' end def nonInf 'non_inf' end private(:inv, :non_inf, :nonInf) end class RubyCodeBlock include RJBM::JAccess j_interface('mx.org.pescador.krmodel.RubyCodeBlockR') def initialize(code, return_type, can_assign) @code = code.gsub('->','*') @return_type, @can_assign = return_type, can_assign j_bind end def executeAndTraceFetches(from_doov, lang, fetched_text_bpvs) # TODO: check for recursive calls to the same Ruby code block? # TODO: Add class checks for various public methods, to help error checking # for people who aren't familiar with these internals executeGen(from_doov, lang, fetched_text_bpvs, nil, nil) end def executeWithHighlighting(from_doov, lang, highlightedDependencies, hlContext) executeGen(from_doov, lang, nil, highlightedDependencies, hlContext) end def execute(from_doov, lang) executeGen(from_doov, lang, nil, nil, nil) end :private def executeGen(from_doov, lang, fetched_text_bpvs, highlightedDependencies, hlContext) begin env = RubyCodeEnvironment.new(@return_type, @can_assign, from_doov, lang, fetched_text_bpvs, highlightedDependencies, hlContext) o = eval(@code, env.get_binding, "Ruby code block", 1) eval(@return_type.javaConversionBlock) rescue Exception CustomLogger.info($!.message) CustomLogger.info(($!.backtrace).join("\n")) raise end end end class RubyCodeBlockFactory include RJBM::JAccess j_interface('mx.org.pescador.krmodel.RubyCodeBlockFactoryR') j_import('mx.org.pescador.krmodel.RubyCodeBlockJ') def initialize j_bind end def newRCodeBlkWReturnVal(code, return_value, can_assign) RubyCodeBlock.new(code, return_value, can_assign).j end def newRCodeBlkNoReturnVal(code, can_assign) RubyCodeBlock.new(code, nil, can_assign).j end RubyCodeBlockJ.setRCodeBlockFactory(RubyCodeBlockFactory.new.j) end end end # @lit: .val, .text_bpv, y comp vectors # @root, general node object: .classes, .text_bpv, .image_bpv y comp vectors # @out, resultado de solicitud de relaciones: # delegates for first result: .text_bpv, .image_bpv y comp vectors # (throws warning if used when there is more than one result) # for accessing result set: .size, .includes(node ref), [], .each # # warnings to include in doc: don't make local varibales named inv, nonInf, non_inf # also don't make local variables the same as local KRRelRules, rulesets or realms