Class: ActiveFacts::CQL::Compiler::Reference

Inherits:
Object
  • Object
show all
Defined in:
lib/activefacts/cql/compiler/clause.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(term, leading_adjective = nil, trailing_adjective = nil, quantifier = nil, function_call = nil, role_name = nil, value_constraint = nil, literal = nil, nested_clauses = nil) ⇒ Reference

Returns a new instance of Reference.



842
843
844
845
846
847
848
849
850
851
852
# File 'lib/activefacts/cql/compiler/clause.rb', line 842

def initialize term, leading_adjective = nil, trailing_adjective = nil, quantifier = nil, function_call = nil, role_name = nil, value_constraint = nil, literal = nil, nested_clauses = nil
  @term = term
  @leading_adjective = leading_adjective
  @trailing_adjective = trailing_adjective
  @quantifier = quantifier
  # @function_call = function_call # Not used or implemented
  @role_name = role_name
  @value_constraint = value_constraint
  @literal = literal
  @nested_clauses = nested_clauses
end

Instance Attribute Details

#bindingObject

What Binding for that ObjectType



835
836
837
# File 'lib/activefacts/cql/compiler/clause.rb', line 835

def binding
  @binding
end

#clauseObject

The clause that this Reference is part of



838
839
840
# File 'lib/activefacts/cql/compiler/clause.rb', line 838

def clause
  @clause
end

#embedded_presence_constraintObject (readonly)

This refers to the ActiveFacts::Metamodel::PresenceConstraint



840
841
842
# File 'lib/activefacts/cql/compiler/clause.rb', line 840

def embedded_presence_constraint
  @embedded_presence_constraint
end

#function_callObject (readonly)

Returns the value of attribute function_call.



832
833
834
# File 'lib/activefacts/cql/compiler/clause.rb', line 832

def function_call
  @function_call
end

#leading_adjectiveObject

Returns the value of attribute leading_adjective.



833
834
835
# File 'lib/activefacts/cql/compiler/clause.rb', line 833

def leading_adjective
  @leading_adjective
end

#literalObject (readonly)

Returns the value of attribute literal.



832
833
834
# File 'lib/activefacts/cql/compiler/clause.rb', line 832

def literal
  @literal
end

#nested_clausesObject (readonly)

Returns the value of attribute nested_clauses.



832
833
834
# File 'lib/activefacts/cql/compiler/clause.rb', line 832

def nested_clauses
  @nested_clauses
end

#objectification_ofObject

If nested_clauses is set, this is the fact type it objectifies



839
840
841
# File 'lib/activefacts/cql/compiler/clause.rb', line 839

def objectification_of
  @objectification_of
end

#playerObject

What ObjectType does the Binding denote



834
835
836
# File 'lib/activefacts/cql/compiler/clause.rb', line 834

def player
  @player
end

#quantifierObject (readonly)

Returns the value of attribute quantifier.



832
833
834
# File 'lib/activefacts/cql/compiler/clause.rb', line 832

def quantifier
  @quantifier
end

#roleObject

Which Role of this ObjectType



836
837
838
# File 'lib/activefacts/cql/compiler/clause.rb', line 836

def role
  @role
end

#role_nameObject

Returns the value of attribute role_name.



833
834
835
# File 'lib/activefacts/cql/compiler/clause.rb', line 833

def role_name
  @role_name
end

#role_refObject

Which RoleRef to that Role



837
838
839
# File 'lib/activefacts/cql/compiler/clause.rb', line 837

def role_ref
  @role_ref
end

#termObject (readonly)

Returns the value of attribute term.



832
833
834
# File 'lib/activefacts/cql/compiler/clause.rb', line 832

def term
  @term
end

#trailing_adjectiveObject

Returns the value of attribute trailing_adjective.



833
834
835
# File 'lib/activefacts/cql/compiler/clause.rb', line 833

def trailing_adjective
  @trailing_adjective
end

#value_constraintObject (readonly)

Returns the value of attribute value_constraint.



832
833
834
# File 'lib/activefacts/cql/compiler/clause.rb', line 832

def value_constraint
  @value_constraint
end

Instance Method Details

#<=>(other) ⇒ Object



876
877
878
879
880
881
# File 'lib/activefacts/cql/compiler/clause.rb', line 876

def <=>(other)
  ( 4*(@term <=> other.term) +
    2*((@leading_adjective||'') <=> (other.leading_adjective||'')) +
    1*((@trailing_adjective||'') <=> (other.trailing_adjective||''))
  ) <=> 0
end

#bind(context) ⇒ Object



928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
# File 'lib/activefacts/cql/compiler/clause.rb', line 928

def bind context
  @nested_clauses.each{|c| c.bind context} if @nested_clauses
  if role_name = @role_name
    # Omit these tests to see if anything evil eventuates:
    #if @leading_adjective || @trailing_adjective
    #  raise "Role reference may not have adjectives if it defines a role name or uses a subscript: #{inspect}"
    #end
  else
    if uses_role_name?
      if @leading_adjective || @trailing_adjective
        raise "Role reference may not have adjectives if it uses a role name: #{inspect}"
      end
      role_name = @term
    end
  end
  @binding = (context.bindings[key] ||= Binding.new(@player, role_name))
  @binding.refs << self
  @binding
end

#find_pc_over_roles(roles) ⇒ Object



986
987
988
989
990
991
992
993
994
995
# File 'lib/activefacts/cql/compiler/clause.rb', line 986

def find_pc_over_roles(roles)
  return nil if roles.size == 0 # Safeguard; this would chuck an exception otherwise
  roles[0].all_role_ref.each do |role_ref|
    next if role_ref.role_sequence.all_role_ref.map(&:role) != roles
    pc = role_ref.role_sequence.all_presence_constraint.single  # Will return nil if there's more than one.
    #puts "Existing PresenceConstraint matches those roles!" if pc
    return pc if pc
  end
  nil
end

#identify_other_players(context) ⇒ Object



898
899
900
# File 'lib/activefacts/cql/compiler/clause.rb', line 898

def identify_other_players context
  identify_player context
end

#identify_player(context) ⇒ Object



902
903
904
905
906
907
908
909
# File 'lib/activefacts/cql/compiler/clause.rb', line 902

def identify_player context
  @player || begin
    @player = context.object_type @term
    raise "ObjectType #{@term} unrecognised" unless @player
    context.player_by_role_name[@role_name] = player if @role_name
    @player
  end
end

#identify_players_with_role_name(context) ⇒ Object



892
893
894
895
896
# File 'lib/activefacts/cql/compiler/clause.rb', line 892

def identify_players_with_role_name(context)
  identify_player(context) if role_name
  # Include players in nested clauses, if any
  nested_clauses.each{|clause| clause.identify_players_with_role_name(context)} if nested_clauses
end

#includes_literalsObject



883
884
885
# File 'lib/activefacts/cql/compiler/clause.rb', line 883

def includes_literals
  @nested_clauses && @nested_clauses.detect{|oj| oj.includes_literals}
end

#inspectObject



854
855
856
# File 'lib/activefacts/cql/compiler/clause.rb', line 854

def inspect
  to_s
end

#keyObject



915
916
917
918
919
920
921
922
923
924
925
926
# File 'lib/activefacts/cql/compiler/clause.rb', line 915

def key
  if @role_name
    key = [@term, @role_name]         # Defines a role name
  elsif uses_role_name?
    key = [@player.name, @term]       # Uses a role name
  else
    l = @leading_adjective
    t = @trailing_adjective
    key = [!l || l.empty? ? nil : l, @term, !t || t.empty? ? nil : t]
    key
  end
end

#make_embedded_presence_constraint(vocabulary) ⇒ Object



997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
# File 'lib/activefacts/cql/compiler/clause.rb', line 997

def make_embedded_presence_constraint vocabulary
  raise "No Role for embedded_presence_constraint" unless @role_ref
  fact_type = @role_ref.role.fact_type
  constellation = vocabulary.constellation

  debug :constraint, "Processing embedded constraint #{@quantifier.inspect} on #{@role_ref.role.object_type.name} in #{fact_type.describe}" do
    # Preserve the role order of the clause, excluding this role:
    constrained_roles = (@clause.refs-[self]).map{|vr| vr.role_ref.role}
    if constrained_roles.empty?
      debug :constraint, "Quantifier over unary role has no effect"
      return
    end
    constraint = find_pc_over_roles(constrained_roles)
    if constraint
      raise "Conflicting maximum frequency for constraint" if constraint.max_frequency && constraint.max_frequency != @quantifier.max
      debug :constraint, "Setting max frequency to #{@quantifier.max} for existing constraint #{constraint.object_id} over #{constraint.role_sequence.describe} in #{fact_type.describe}" unless constraint.max_frequency
      constraint.max_frequency = @quantifier.max
      raise "Conflicting minimum frequency for constraint" if constraint.min_frequency && constraint.min_frequency != @quantifier.min
      debug :constraint, "Setting min frequency to #{@quantifier.min} for existing constraint #{constraint.object_id} over #{constraint.role_sequence.describe} in #{fact_type.describe}" unless constraint.min_frequency
      constraint.min_frequency = @quantifier.min
    else
      role_sequence = constellation.RoleSequence(:new)
      constrained_roles.each_with_index do |constrained_role, i|
        role_ref = constellation.RoleRef(role_sequence, i, :role => constrained_role)
      end
      constraint = constellation.PresenceConstraint(
          :new,
          :vocabulary => vocabulary,
          :role_sequence => role_sequence,
          :is_mandatory => @quantifier.min && @quantifier.min > 0,  # REVISIT: Check "maybe" qualifier?
          :max_frequency => @quantifier.max,
          :min_frequency => @quantifier.min
        )
      debug :constraint, "Made new embedded PC GUID=#{constraint.concept.guid} min=#{@quantifier.min.inspect} max=#{@quantifier.max.inspect} over #{(e = fact_type.entity_type) ? e.name : role_sequence.describe} in #{fact_type.describe}"
      @quantifier.enforcement.compile(constellation, constraint) if @quantifier.enforcement
      @embedded_presence_constraint = constraint
    end
    constraint
  end

end

#rebind(context) ⇒ Object



958
959
960
961
# File 'lib/activefacts/cql/compiler/clause.rb', line 958

def rebind(context)
  unbind context
  bind context
end

#rebind_to(context, other_ref) ⇒ Object



963
964
965
966
967
968
969
970
971
972
973
974
975
# File 'lib/activefacts/cql/compiler/clause.rb', line 963

def rebind_to(context, other_ref)
  debug :binding, "Rebinding #{inspect} to #{other_ref.inspect}"

  old_binding = binding   # Remember to move all refs across
  unbind(context)

  new_binding = other_ref.binding
  [self, *old_binding.refs].each do |ref|
    ref.binding = new_binding
    new_binding.refs << ref
  end
  old_binding.rebound_to = new_binding
end

#result(context = nil) ⇒ Object



1039
1040
1041
# File 'lib/activefacts/cql/compiler/clause.rb', line 1039

def result(context = nil)
  self
end

#to_sObject



858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
# File 'lib/activefacts/cql/compiler/clause.rb', line 858

def to_s
  "{#{
    @quantifier && @quantifier.inspect+' '
  }#{
    @leading_adjective && @leading_adjective.sub(/ |$/,'- ').sub(/ *$/,' ')
  }#{
    @term
  }#{
    @trailing_adjective && ' '+@trailing_adjective.sub(/(.* |^)/, '\1-')
  }#{
    @role_name and @role_name.is_a?(Integer) ? "(#{@role_name})" : " (as #{@role_name})"
  }#{
    @literal && ' '+@literal.inspect
  }#{
    @value_constraint && ' '+@value_constraint.to_s
  }}"
end

#unbind(context) ⇒ Object



948
949
950
951
952
953
954
955
956
# File 'lib/activefacts/cql/compiler/clause.rb', line 948

def unbind context
  # The key has changed.
  @binding.refs.delete(self)
  if @binding.refs.empty?
    # Remove the binding from the context if this was the last reference
    context.bindings.delete_if {|k,v| v == @binding }
  end
  @binding = nil
end

#uses_role_name?Boolean

Returns:

  • (Boolean)


911
912
913
# File 'lib/activefacts/cql/compiler/clause.rb', line 911

def uses_role_name?
  @term != @player.name
end

#wipe_leading_adjectiveObject

These are called when we successfully match a fact type reading that has relevant adjectives:



978
979
980
# File 'lib/activefacts/cql/compiler/clause.rb', line 978

def wipe_leading_adjective
  @leading_adjective = nil
end

#wipe_trailing_adjectiveObject



982
983
984
# File 'lib/activefacts/cql/compiler/clause.rb', line 982

def wipe_trailing_adjective
  @trailing_adjective = nil
end