Module: Neo4j::Wrapper::Rule::ClassMethods
- Defined in:
- lib/neo4j-wrapper/rule/class_methods.rb
Overview
Allows you to group nodes by providing a rule.
Example, finding all nodes of a certain class
Just add a rule without a code block, then all nodes of that class will be grouped under the given key (all
for the example below).
class Person
include Neo4j::NodeMixin
rule :all
end
Then you can get all the nodes of type Person (and siblings) by
Person.all.each {|x| ...}
Example, finding all nodes with a given condition on a property
class Person
include Neo4j::NodeMixin
property :age
rule(:old) { age > 10 }
end
Now we can find all nodes with a property <tt>age</tt> above 10.
Chain Rules
class NewsStory
include Neo4j::NodeMixin
has_n :readers
rule(:featured) { |node| node[:featured] == true }
rule(:young_readers) { !readers.find{|user| !user.young?}}
end
You can combine two rules. Let say you want to find all stories which are featured and has young readers:
NewsStory.featured.young_readers.each {...}
Trigger Other Rules
You can let one rule trigger another rule. Let say you have readers of some magazine and want to know if the magazine has old or young readers. So when a reader change from young to old you want to trigger all the magazine that he reads (a but stupid example)
Example
class Reader
include Neo4j::NodeMixin
property :age
rule(:young, :triggers => :readers) { age < 15 }
end
class NewsStory
include Neo4j::NodeMixin
has_n :readers
rule(:young_readers) { !readers.find{|user| !user.young?}}
end
Performance Considerations
If you have many rules and many updates this can be a bit slow. In order to speed it up somewhat you can use the raw java node object instead by providing an argument in your block.
Example:
class Person
include Neo4j::NodeMixin
property :age
rule(:old) {|node| node[:age] > 10 }
end
Thread Safe ?
Yes, since operations are performed in an transaction. However you may get a deadlock exception:
Instance Method Summary collapse
-
#add_function_for(rule_name, function_name_or_class, function_id = '_classname') ⇒ Object
Returns a proc that will call add method on the given function Can be used in migration to trigger rules on already existing nodes.
-
#delete_function_for(rule_name, function_name_or_class, function_id = '_classname') ⇒ Object
See #add_function_for Calls the delete method on the function.
-
#delete_rules ⇒ Object
This is typically used for RSpecs to clean up rule nodes created by the #rule method.
-
#function_for(method, rule_name, function_name_or_class, function_id = '_classname') ⇒ Object
Returns a proc that calls the given method on the given function.
- #inherit_rules_from(clazz) ⇒ Object
-
#ref_node(&block) ⇒ Object
Assigns the reference node for a class via a supplied block.
- #ref_node_for_class ⇒ Object
-
#rule(rule_name, props = {}, &block) ⇒ Object
Creates an rule node attached to the Neo4j.ref_node Can be used to rule all instances of a specific Ruby class.
-
#trigger_rules(node, *changes) ⇒ Object
Force to trigger the rules.
Instance Method Details
#add_function_for(rule_name, function_name_or_class, function_id = '_classname') ⇒ Object
Returns a proc that will call add method on the given function Can be used in migration to trigger rules on already existing nodes. Parameter function_id is default to ‘_classname’ which means that the function ‘reacts’ on changes on the property ‘_classname’. That property changes only when a node is created or deleted. Function using function_id ‘_classname’ is typically used for counting number of nodes of a class.
176 177 178 |
# File 'lib/neo4j-wrapper/rule/class_methods.rb', line 176 def add_function_for(rule_name, function_name_or_class, function_id = '_classname') function_for(:add, rule_name, function_name_or_class, function_id) end |
#delete_function_for(rule_name, function_name_or_class, function_id = '_classname') ⇒ Object
See #add_function_for Calls the delete method on the function.
182 183 184 |
# File 'lib/neo4j-wrapper/rule/class_methods.rb', line 182 def delete_function_for(rule_name, function_name_or_class, function_id = '_classname') function_for(:delete, rule_name, function_name_or_class, function_id) end |
#delete_rules ⇒ Object
This is typically used for RSpecs to clean up rule nodes created by the #rule method. It also remove all the rule class methods.
151 152 153 154 155 156 157 158 159 |
# File 'lib/neo4j-wrapper/rule/class_methods.rb', line 151 def delete_rules singelton = class << self; self; end rule_node = Rule.rule_node_for(self) rule_node.rule_names.each { |rule_name| singelton.send(:remove_method, rule_name) } rule_node.rules.clear end |
#function_for(method, rule_name, function_name_or_class, function_id = '_classname') ⇒ Object
Returns a proc that calls the given method on the given function.
187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/neo4j-wrapper/rule/class_methods.rb', line 187 def function_for(method, rule_name, function_name_or_class, function_id = '_classname') function_name = function_name_or_class.is_a?(Symbol) ? function_name_or_class : function_name_or_class.function_name rule_node = Rule.rule_node_for(self) rule = rule_node.find_rule(rule_name) rule_node_raw = rule_node.rule_node function = rule_node.find_function(rule_name, function_name, function_id) lambda do |node| new_value = node[function_id] function.send(method, rule.rule_name, rule_node_raw, new_value) end end |
#inherit_rules_from(clazz) ⇒ Object
145 146 147 |
# File 'lib/neo4j-wrapper/rule/class_methods.rb', line 145 def inherit_rules_from(clazz) Rule.inherit(clazz, self) end |
#ref_node(&block) ⇒ Object
138 139 140 141 142 143 |
# File 'lib/neo4j-wrapper/rule/class_methods.rb', line 138 def ref_node(&block) singleton = class << self; self; end singleton.send(:define_method, :ref_node_for_class) { block.call } end |
#ref_node_for_class ⇒ Object
127 128 129 |
# File 'lib/neo4j-wrapper/rule/class_methods.rb', line 127 def ref_node_for_class Neo4j.ref_node #The reference node for a type falls back to the threadlocal ref node by default. end |
#rule(rule_name, props = {}, &block) ⇒ Object
Creates an rule node attached to the Neo4j.ref_node Can be used to rule all instances of a specific Ruby class.
Example of usage:
class Person
include Neo4j::NodeMixin
property :age
rule :all
rule :young { self[:age] < 10 }
rule(:old, :functions => [Sum.new[:age]) { age > 20 }
end
p1 = Person.new :age => 5
p2 = Person.new :age => 7
p3 = Person.new :age => 12
Neo4j::Transaction.finish
Person.all # => [p1,p2,p3]
Person.young # => [p1,p2]
p1.young? # => true
p1.sum(old, :age) # the some of the old people's age
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/neo4j-wrapper/rule/class_methods.rb', line 99 def rule(rule_name, props = {}, &block) singleton = class << self; self; end # define class methods singleton.send(:define_method, rule_name) do rule_node = Rule.rule_node_for(self) rule_node.traversal(rule_name) end unless respond_to?(rule_name) # define instance methods self.send(:define_method, "#{rule_name}?") do instance_eval &block end rule = Rule.add(self, rule_name, props, &block) rule.functions && rule.functions.each do |func| singleton.send(:define_method, func.class.function_name) do |r_name, *args| rule_node = Rule.rule_node_for(self) function_id = args.empty? ? "_classname" : args[0] function = rule_node.find_function(r_name, func.class.function_name, function_id) function.value(rule_node.rule_node, r_name) end unless respond_to?(func.class.function_name) end end |
#trigger_rules(node, *changes) ⇒ Object
Force to trigger the rules. You don’t normally need that since it will be done automatically. This can be useful if you need to trigger rules on already existing nodes in the database. Can also be called from an migration.
166 167 168 |
# File 'lib/neo4j-wrapper/rule/class_methods.rb', line 166 def trigger_rules(node, *changes) Rule.trigger_rules(node, *changes) end |