Class: RuleBase::Rule

Inherits:
Object
  • Object
show all
Defined in:
lib/activerdf_rules/rule_base.rb

Overview

A rule for adding information to an ActiveRDF store. A rule consists of a set of conditions and a single conclusion. Each condition consists of a triple (with variables) that is matched against the database. When all of the conditions are satisfied, then the conclusion is introduced into the database substituting for any variables that may appear in the conclusion.

Variables are simply ruby symbols and they can be used within both the conditions and the conclusion with the following caveat: any variable that appears in the conclusion must also appear in at least one condition.

Example:

r = RuleBase::Rule.new
r.condition :x, :y, :z
r.conclusion :z, :y, :x

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ Rule

Returns a new instance of Rule.



99
100
101
102
103
# File 'lib/activerdf_rules/rule_base.rb', line 99

def initialize(name)
  @name = name
  @conditions = []
  @conclusion = nil
end

Instance Attribute Details

#conditionsObject (readonly)

Returns the value of attribute conditions.



97
98
99
# File 'lib/activerdf_rules/rule_base.rb', line 97

def conditions
  @conditions
end

#nameObject (readonly)

Returns the value of attribute name.



97
98
99
# File 'lib/activerdf_rules/rule_base.rb', line 97

def name
  @name
end

Instance Method Details

#conclusion(s, p, o) ⇒ Object

Sets the conclusion of the rule where s, p, and o are the subject, predicate, and object (respectively).



117
118
119
120
121
122
123
124
# File 'lib/activerdf_rules/rule_base.rb', line 117

def conclusion(s, p, o)
  raise "Conclusion already set" unless @conclusion.nil?
  raise "Conclusion subject #{s} must be a Symbol or an RDFS::Resource" unless [Symbol, RDFS::Resource].include?(s.class)
  raise "Conclusion subject #{p} must be a Symbol or an RDFS::Resource" unless [Symbol, RDFS::Resource].include?(p.class)
  c = [s, p, o]
  @conclusion = c
  $activerdflog.debug("Setting conclusion #{c.inspect} for '#{self}'")
end

#condition(s, p, o) ⇒ Object

Adds a condition to the rule where s, p, and o are the subject, predicate, and object (respectively).



107
108
109
110
111
112
113
# File 'lib/activerdf_rules/rule_base.rb', line 107

def condition(s, p, o)
  raise "Condition subject #{s} must be a Symbol or an RDFS::Resource" unless [Symbol, RDFS::Resource].include?(s.class)
  raise "Condition subject #{p} must be a Symbol or an RDFS::Resource" unless [Symbol, RDFS::Resource].include?(p.class)
  c = [s, p, o]
  @conditions << c
  $activerdflog.debug("Adding condition #{c.inspect} to '#{self}'")
end

#instantiate(var, row, lookup) ⇒ Object

Returns either the value for var by using lookup, the value of row, if the query resulted in a single value, or the value of var since in this case it must be either an RDFS::Resource or a literal.



183
184
185
186
187
188
189
190
191
192
193
# File 'lib/activerdf_rules/rule_base.rb', line 183

def instantiate(var, row, lookup)
  if var.is_a?(Symbol)
    if lookup.size == 1 && !row.is_a?(Array)
      row
    else
      row[lookup.index(var)]
    end
  else
    var
  end
end

#processObject

Processes this rule by converting it to a query, if the query is successful, then the conclusion is introduced into the data store after substituting for any variables.



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/activerdf_rules/rule_base.rb', line 146

def process
  $activerdflog.debug("processing '#{self}'")
  q = Query.new
  lookup = @conclusion.select{|c| c.is_a?(Symbol)}.uniq
  q.select(*lookup)
  @conditions.each do |c|
    q.where(*c)
  end
  
  change = false
  q.execute.each do |row|
    triple = nil
    begin
      triple = @conclusion.collect {|t|
        instantiate(t, row, lookup)
      }
      old = ConnectionPool.write_adapter.size
      $activerdflog.debug("concluding #{triple.inspect}")
      ConnectionPool.write_adapter.add(*triple)
      # TODO HACK This should be changed
      # What I should be able to do is something like below, but the below is
      # broken for redland, and the above condition query is broken in
      # rdflite (because of ambiguous column names).  For now this works.
      # Query.new.ask.where(*triple).execute
      if old < ConnectionPool.write_adapter.size
        change = true
      end
    rescue => e
      $activerdflog.debug("could not add #{triple.inspect} because of #{e}")
    end
  end
  change
end

#to_sObject

Returns the name of this rule



196
197
198
# File 'lib/activerdf_rules/rule_base.rb', line 196

def to_s
  @name
end

#validateObject

Checks that every variable in the conclusion also appears in at least on condition. If this condition is not satisfied, then an exception is thrown.



129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/activerdf_rules/rule_base.rb', line 129

def validate
  # for each conclusion variable verify that it appears in one of the conditions
  @conclusion.each do |x|
    if x.is_a?(Symbol)
      catch(:done) do
        @conditions.each do |c|
          throw :done if c.include?(x)
        end
        raise "Unbound variable :#{x} in conclusion"
      end
    end
  end
end