class Flor::Node

Constants

PROC_VAR_CONTAINER
TASKER_VAR_CONTAINER

Attributes

message[R]

Public Class Methods

new(executor, node, message) click to toggle source
# File lib/flor/core/node.rb, line 59
def initialize(executor, node, message)

  @executor, @execution =
    case executor
    when nil then [ nil, nil ] # for some tests
    when Hash then [ nil, executor ] # from some other tests
    else [ executor, executor.execution ] # vanilla case
    end

  @node =
    if node
      node
    elsif message
      @execution['nodes'][message['nid']]
    else
      nil
    end

  @message = message
end

Public Instance Methods

child_id() click to toggle source
# File lib/flor/core/node.rb, line 86
def child_id; Flor.child_id(@node['nid']); end
cnodes() click to toggle source
# File lib/flor/core/node.rb, line 93
def cnodes; @node['cnodes']; end
cnodes_any?() click to toggle source
# File lib/flor/core/node.rb, line 94
def cnodes_any?; cnodes && cnodes.any?; end
cnodes_empty?() click to toggle source
# File lib/flor/core/node.rb, line 95
def cnodes_empty?; cnodes.nil? || cnodes.empty?; end
deref(s) click to toggle source

Returns the referenced tree. Returns nil if not found.

# File lib/flor/core/node.rb, line 202
def deref(s)

  v = lookup_value(s)

  if Flor.is_tree?(v)

    ref =
      case v[0]
      when '_func' then true
      when '_proc' then v[1]['proc'] != s
      when '_tasker' then v[1]['tasker'] != s
      else false
      end

    v[1]['oref'] ||= v[1]['ref'] if ref && v[1]['ref']
    v[1]['ref'] = s if ref

    v

  else

    [ '_val', v, tree[2] ]
  end

rescue KeyError => ke

  nil
end
descendant_of?(nid, on_self=true) click to toggle source
# File lib/flor/core/node.rb, line 258
def descendant_of?(nid, on_self=true)

  return on_self if self.nid == nid && on_self != nil

  i = self.nid

  loop do
    node = @executor.node(i)
    break unless node
    i = node['parent']
    return true if i == nid
  end

  false
end
domain() click to toggle source
# File lib/flor/core/node.rb, line 88
def domain; Flor.domain(@execution['exid']); end
exid() click to toggle source
# File lib/flor/core/node.rb, line 82
def exid; @execution['exid']; end
fei() click to toggle source
# File lib/flor/core/node.rb, line 248
def fei

  "#{exid}-#{nid}"
end
from() click to toggle source
# File lib/flor/core/node.rb, line 91
def from; @from || @message['from']; end
h() click to toggle source
# File lib/flor/core/node.rb, line 80
def h; @node; end
lookup_tree(nid) click to toggle source
# File lib/flor/core/node.rb, line 132
def lookup_tree(nid)

  return nil unless nid

  node = @execution['nodes'][nid]

  tree = node && node['tree']
  return tree if tree

  par = node && node['parent']
  cid = Flor.child_id(nid)

  tree = par && lookup_tree(par)
  return subtree(tree, par, nid) if tree

  return nil if node

  tree = lookup_tree(Flor.parent_nid(nid))
  return tree[1][cid] if tree

  #tree = lookup_tree(Flor.parent_nid(nid, remove_subnid=true))
  #return tree[1][cid] if tree
    #
    # might become necessary at some point

  nil
end
lookup_value(path) click to toggle source
# File lib/flor/core/node.rb, line 160
def lookup_value(path)

  original_path = path

  path =
    case path
    when '*' then [ path ]
    when String then Dense::Path.make(path).to_a
    else path
    end

  path.unshift('v') \
    if path.length < 2

  case path.first
  when /\Af(?:ld|ield)?\z/
    lookup_field(nil, path[1..-1]) # mod -> nil...
  when /\At(?:ag)?\z/
    lookup_tag(nil, path[1])
  when /\A([lgd]?)v(?:ar|ariable)?\z/
    return @message['__head'][1] if path[1] == '__head'
    lookup_var(@node, $1, path[1], path[2..-1])
  when 'node'
    lookup_in_node(path[1..-1])
  when 'exe', 'execution'
    lookup_in_execution(path[1..-1])
  else
    lookup_var(@node, '', path[0], path[1..-1])
  end

rescue KeyError => ke

  class << ke; attr_accessor :original_path, :work_path; end
  ke.original_path = original_path
  ke.work_path = path

  raise
end
message_or_node_payload() click to toggle source
# File lib/flor/core/node.rb, line 128
def message_or_node_payload
  payload.current ? payload : node_payload
end
nid() click to toggle source
# File lib/flor/core/node.rb, line 83
def nid; @node['nid']; end
node_closed?() click to toggle source
# File lib/flor/core/node.rb, line 107
def node_closed?
  node_status['status'] == 'closed'
end
node_ended?() click to toggle source
# File lib/flor/core/node.rb, line 110
def node_ended?
  node_status['status'] == 'ended'
end
node_open?() click to toggle source
# File lib/flor/core/node.rb, line 113
def node_open?
  node_status['status'] == nil
end
node_payload() click to toggle source
# File lib/flor/core/node.rb, line 117
def node_payload
  @node_payload ||= Payload.new(self)
end
node_payload_ret() click to toggle source
# File lib/flor/core/node.rb, line 120
def node_payload_ret
  Flor.dup(node_payload['ret'])
end
node_status() click to toggle source
# File lib/flor/core/node.rb, line 101
def node_status
  @node['status'].last
end
node_status_flavour() click to toggle source
# File lib/flor/core/node.rb, line 104
def node_status_flavour
  node_status['flavour']
end
on_error_parent(skip=false) click to toggle source
# File lib/flor/core/node.rb, line 274
def on_error_parent(skip=false)

  if @node['in_on_error'] # prevent loop when error in on_error:
    skip = true
  end

  if (@node['on_error'] || []).find { |criteria, _| match_on?(criteria) }
    return self unless skip
    skip = false
  end

  if pn = parent_node
    return Flor::Node.new(@executor, pn, @message).on_error_parent(skip)
  end

  nil
end
parent() click to toggle source
# File lib/flor/core/node.rb, line 84
def parent; @node['parent']; end
payload() click to toggle source
# File lib/flor/core/node.rb, line 97
def payload
  @message_payload ||= Payload.new(self, :message)
end
payload_ret() click to toggle source
# File lib/flor/core/node.rb, line 124
def payload_ret
  message['payload']['ret']
end
point() click to toggle source
# File lib/flor/core/node.rb, line 90
def point; @message['point']; end
reheap(tree, heat) click to toggle source
# File lib/flor/core/node.rb, line 231
def reheap(tree, heat)

  case
  when ! heat.is_a?(Array) then '_val'
  when tree && tree[1] == [] then '_val'
  when heat[0] == '_proc' then heat[1]['proc']
  when heat[0] == '_func' then 'apply'
  when heat[0] == '_tasker' then 'task'
  else '_val'
  end
end
to_procedure_node() click to toggle source
# File lib/flor/core/node.rb, line 253
def to_procedure_node

  Flor::Procedure.new(@executor, @node, @message)
end
tree() click to toggle source
# File lib/flor/core/node.rb, line 243
def tree

  lookup_tree(nid)
end

Protected Instance Methods

escape(k) click to toggle source
# File lib/flor/core/node.rb, line 374
def escape(k)

  case k
  when '*', '.' then "\\#{k}"
  else k
  end
end
extract_on_info() click to toggle source
# File lib/flor/core/node.rb, line 531
def extract_on_info

  kla = @message['error']['kla']
  msg = @message['error']['msg']
  la = kla.split('::').last

  [ kla, la, msg ]
end
is_ancestor_node?(node_or_nid, node=@node) click to toggle source

Returns true if the current node has the node identified with nid as an ancestor. Returns false else.

# File lib/flor/core/node.rb, line 330
def is_ancestor_node?(node_or_nid, node=@node)

  nid = node_or_nid

  return false unless nid

  nid = node_or_nid['nid'] unless nid.is_a?(String)

  return false unless node
  return true if node['nid'] == nid

  is_ancestor_node?(nid, parent_node(node))
end
lookup_arg_container(key) click to toggle source
# File lib/flor/core/node.rb, line 483
def lookup_arg_container(key)

  vars = lookup_var_container(@node, '', 'arguments')
  return {} unless vars

  args = vars['arguments']
  return {} unless args

  val =
    case key
    when 'arga', 'args', 'argv' then args.collect(&:last)
    else args.inject({}) { |h, (k, v)| h[k] = v if k; h }
    end

  { key => val }
end
lookup_dvar_container(mod, key) click to toggle source
# File lib/flor/core/node.rb, line 462
def lookup_dvar_container(mod, key)

  if mod != 'd' && Flor::Procedure[key]
    return PROC_VAR_CONTAINER
  end

  l = @executor.unit.loader
  vdomain = @node['vdomain']
    #
  if l && vdomain != false
    vars = l.variables(vdomain || domain)
    return vars if vars.has_key?(key)
  end

  if mod != 'd' && @executor.unit.has_tasker?(@executor.exid, key)
    return TASKER_VAR_CONTAINER
  end

  {}
end
lookup_field(mod, key_and_path) click to toggle source
# File lib/flor/core/node.rb, line 511
def lookup_field(mod, key_and_path)

  Dense.fetch(payload.current, key_and_path)
end
lookup_in_execution(path) click to toggle source
# File lib/flor/core/node.rb, line 353
def lookup_in_execution(path)

  if path == %w[ domain ]
    Flor.domain(@execution['exid'])
  else
    Dense.fetch(@execution, path)
  end
end
lookup_in_node(path) click to toggle source

def closure_node(node=@node)

@execution['nodes'][node['cnid']]

end

# File lib/flor/core/node.rb, line 348
def lookup_in_node(path)

  Dense.fetch(@node, path)
end
lookup_tag(mod, key) click to toggle source
# File lib/flor/core/node.rb, line 500
def lookup_tag(mod, key)

  nids =
    @execution['nodes'].inject([]) do |a, (nid, n)|
      a << nid if n['tags'] && n['tags'].include?(key)
      a
    end

  nids.any? ? nids : nil
end
lookup_var(node, mod, key, pth) click to toggle source
# File lib/flor/core/node.rb, line 382
def lookup_var(node, mod, key, pth)

  c = lookup_var_container(node, mod, key)

  kp = [ key, pth ].reject { |x| x == nil || x.size < 1 }.join('.')
  kp = escape(kp)

  Dense.fetch(c, kp)

rescue KeyError => ke

  m = "variable #{ke.miss[3].inspect} not found"
  m += " at #{Dense::Path.make(ke.miss[1]).to_s.inspect}" if ke.miss[1].any?

  raise ke.relabel(m)

rescue IndexError => ie

  m =
    if ie.miss[1] == [ ie.miss[2] ]
       "variable #{ie.miss[2].inspect} not found"
    else
      pa = Dense::Path.make(ie.miss[1]).to_s.inspect
      ty = Flor.type(ie.miss[2])
      ke = ie.miss[3].inspect
      "variable at #{pa} is a #{ty}, it has no key #{ke}"
    end

  raise ie.relabel(m)

#rescue TypeError => te # leave as is
end
lookup_var_container(node, mod, key) click to toggle source
# File lib/flor/core/node.rb, line 426
def lookup_var_container(node, mod, key)

  return lookup_dvar_container(mod, key) \
    if node == nil || mod == 'd'

  return lookup_arg_container(key) \
    if mod == '' && %w[ arga args argv argh argd ].include?(key)

  if vwl = node['vwlist'] # variable white list
    return lookup_dvar_container(mod, key) unless var_match?(vwl, key)
  end
  if vbl = node['vblist'] # variable black list
    return lookup_dvar_container(mod, key) if var_match?(vbl, key)
  end

  pnode = parent_node(node)
  vars = node['vars']

  if mod == 'g'
    return lookup_var_container(pnode, mod, key) if pnode
    return vars if vars
    fail "node #{node['nid']} has no vars and no parent"
  end

  return vars if vars && vars.has_key?(key)

  if cnid = node['cnid']
    cvars = (@execution['nodes'][cnid] || {})['vars']
    return cvars if cvars && cvars.has_key?(key)
  end
    #
    # look into closure, just one level deep...

  lookup_var_container(pnode, mod, key)
end
match_on?(criteria) click to toggle source

Return true if the current @message matches on the given array of criteria.

# File lib/flor/core/node.rb, line 519
def match_on?(criteria)

  # AND, not OR, hence the true at the bottom

  criteria
    .each { |c|
      next if c == '*'
      return false unless send("match_on_#{c[0]}?", c) }

  true
end
match_on_class?(criterion) click to toggle source
# File lib/flor/core/node.rb, line 540
def match_on_class?(criterion)

  c1 = criterion[1]
  kla, la, _ = extract_on_info

  kla == c1 || la == c1
end
match_on_regex?(criterion) click to toggle source
# File lib/flor/core/node.rb, line 556
def match_on_regex?(criterion)

  c1 = Flor.to_regex(criterion)
  kla, _, msg = extract_on_info

  msg =~ c1 || kla =~ c1
end
match_on_string?(criterion) click to toggle source
# File lib/flor/core/node.rb, line 548
def match_on_string?(criterion)

  c1 = criterion[1]
  kla, la, msg = extract_on_info

  msg == c1 || kla == c1 || la == c1
end
parent_node(node=@node) click to toggle source
# File lib/flor/core/node.rb, line 312
def parent_node(node=@node)

  @execution['nodes'][node['parent']]
end
parent_node_procedure(node=@node) click to toggle source
# File lib/flor/core/node.rb, line 322
def parent_node_procedure(node=@node)

  Flor::Procedure.make(@executor, parent_node(node), @message)
end
parent_node_tree(node=@node) click to toggle source
# File lib/flor/core/node.rb, line 317
def parent_node_tree(node=@node)

  lookup_tree(node['parent'])
end
subtree(tree, pnid, nid) click to toggle source
# File lib/flor/core/node.rb, line 294
def subtree(tree, pnid, nid)

  pnid = Flor.master_nid(pnid)
  nid = Flor.master_nid(nid)

  return nil unless nid[0, pnid.length] == pnid
    # maybe failing would be better

  cid = nid[pnid.length + 1..-1]

  return nil unless cid
    # maybe failing would be better

  cid.split('_').each { |id| tree = tree[1][id.to_i] }

  tree
end
var_match?(vs, key) click to toggle source
# File lib/flor/core/node.rb, line 415
def var_match?(vs, key)

  vs.each do |v|
    return true if v == key
    return true if v.is_a?(Regexp) && v =~ key
    # TODO fun call
  end

  false
end