Skip to content

Commit

Permalink
Add more YARD docs including Cypher/Rules closes #181
Browse files Browse the repository at this point in the history
  • Loading branch information
andreasronge committed Apr 19, 2012
1 parent f0f4023 commit d321a27
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 30 deletions.
2 changes: 2 additions & 0 deletions .yardopts
@@ -0,0 +1,2 @@
--title 'Neo4j.rb API Documentation'
--no-private
12 changes: 10 additions & 2 deletions lib/neo4j/rails/attributes.rb
Expand Up @@ -4,10 +4,13 @@ module Rails
# in a Railsy way. This typically means not writing anything to the DB until the
# object is saved (after validation).
#
# Externally, when we talk about properties (e.g. #property?, #property_names, #properties),
# Externally, when we talk about properties (e.g. {#property?}, {#property_names}),
# we mean all of the stored properties for this object include the 'hidden' props
# with underscores at the beginning such as _neo_id and _classname. When we talk
# about attributes, we mean all the properties apart from those hidden ones.
#
# This mixin defines a number of class methods, see #{ClassMethods}.
#
module Attributes
extend ActiveSupport::Concern
extend TxMethods
Expand Down Expand Up @@ -47,13 +50,17 @@ def self.inherited(sub_klass)
end
end

# Is called when a node neo4j entity is created and we need to save attributes
# @private
def init_on_create(*)
self._classname = self.class.to_s
write_default_attributes
write_changed_attributes
clear_changes
end

# Setup this mixins instance variables
# @private
def initialize_attributes(attributes)
@_properties = {}
@_properties_before_type_cast={}
Expand Down Expand Up @@ -88,13 +95,14 @@ def update_attributes(attributes)
end
tx_methods :update_attributes

# Same as #update_attributes, but raises an exception if saving fails.
# Same as {#update_attributes}, but raises an exception if saving fails.
def update_attributes!(attributes)
self.attributes = attributes
save!
end
tx_methods :update_attributes!

# @private
def reset_attributes
@_properties = {}
end
Expand Down
24 changes: 24 additions & 0 deletions lib/neo4j/rails/finders.rb
Expand Up @@ -3,10 +3,12 @@ module Rails
class RecordNotFoundError < StandardError
end

# Defines {ClassMethods}
module Finders
extend ActiveSupport::Concern


# @private
def reachable_from_ref_node?
# All relationships are reachable
respond_to?(:_java_rel) || Neo4j::Algo.all_path(self.class.ref_node_for_class, self).outgoing(self.class).outgoing(:_all).first != nil
Expand All @@ -16,8 +18,29 @@ def reachable_from_ref_node?
rule(:_all, :functions => Neo4j::Wrapper::Rule::Functions::Size.new) if respond_to?(:rule)
end

# Defines the #{#find} method. When declaring properties with index a number of finder methods will be generated,
# similar to active record, example +find_by_<property_name>+, +find_or_create_by_<property_name>. +all_by_<property_name>+
#
# @example find_or_create_by
# class Person < Neo4j::Rails::Model
# property :age, :type => Fixnum
# end
#
# Person.find_by_age(42)
# Person.find_or_create_by
# Person.find_or_create_by!(:age => 'bla')
#
# @example find all
# Person.all_by_age
# Person.all(:name => 'bla')
# Person.all('name: "bla"') # lucene query syntax
#
# @see Neo4j::Rails::Attributes::ClassMethods#property
# @see #find
#
module ClassMethods

# @private
def index_prefix
return "" unless Neo4j.running?
return "" unless respond_to?(:ref_node_for_class)
Expand All @@ -26,6 +49,7 @@ def index_prefix
prefix ? prefix + "_" : ""
end

# @private
# overwrite the index method to add find_by_xxx class methods
def index(*args)
field = args.first
Expand Down
5 changes: 3 additions & 2 deletions lib/neo4j/rails/has_n.rb
@@ -1,14 +1,15 @@
module Neo4j
module Rails
# Defines class methods, see {ClassMethods}
module HasN
extend ActiveSupport::Concern

module ClassMethods

# Create a number of methods similar to active record has_many.
# The first one returns an Neo4j::Rails::Relationships::NodesDSL
# The first one returns an {Neo4j::Rails::Relationships::NodesDSL}
# the second generate method (with the _rels postfix) returns a
# Neo4j::Rails::Relationships::RelsDSL
# {Neo4j::Rails::Relationships::RelsDSL}
#
# See also Neo4j::NodeMixin#has_n which only work with persisted relationships.
#
Expand Down
62 changes: 53 additions & 9 deletions lib/neo4j/rails/model.rb
@@ -1,20 +1,39 @@
module Neo4j
module Rails
# Makes Neo4j nodes and relationships behave like active record objects.
# That means for example that you don't have to care about transactions since they will be
# automatically be created when needed. Validation, Callbacks etc. are also supported.
# That means for example that you don't (normally) have to care about transactions since they will be
# automatically be created when needed. {Neo4j::Rails::Validation}, {Neo4j::Rails::Callbacks} etc. are also supported.
#
# @example Traverse
# @example Create a node (learn more - see {Neo4j::Rails::Persistence})
# class Company < Neo4j::Rails::Model
# end
# Company.new.save
# Company.save
# Company.save(:name => 'Foo Ab')
#
# @example Declare properties (learn more - see {Neo4j::Rails::Attributes})
#
# class Company < Neo4j::Rails::Model
# property :data
# property :revenue, :type => :Float
# end
#
# c = Company.new(:data => false, :type => '2123123.23')
# c.data = "changed type"
# c.revenue = 123124 # will always be converted
#
# @example Creating and Navigating Relationships (learn more - see {Neo4j::Rails::Relationships})
# class Person < Neo4j::Rails::Model
# end
#
# person = Person.find(...)
# person.outgoing(:foo) << Person.create
# person = Person.new
# person.outgoing(:foo) << Person.new
# person.save!
# person.outgoing(:foo).depth(:all)...
# person.outgoing(:friends).map{|f| f.outgoing(:knows).to_a}.flatten
# person.rels(:outgoing, :foo).first.end_node #=> the other node
#
# @example Declared Relationships: has_n and has_one
# @example Declared Relationships (learn more - see {Neo4j::Rails::HasN::ClassMethods})
#
# class Person < Neo4j::Rails::Model
# end
Expand All @@ -25,9 +44,9 @@ module Rails
# end
#
# Person.new.foo << other_node
# Person.friends.build(:name => 'kalle')
# Person.friends.build(:name => 'kalle').save
#
# @example Declared Properties and Index
# @example Searching with Lucene Index (learn more - see {Neo4j::Rails::Finders::ClassMethods})
#
# class Person < Neo4j::Rails::Model
# property :name
Expand All @@ -37,7 +56,32 @@ module Rails
# Person.create(:name => 'kalle', :age => 42, :undeclared_prop => 3.14)
# Person.find_by_age(42)
#
# @example Callbacks
# @example Searching with Cypher (learn more - {Neo4j-core}[http://rdoc.info/github/andreasronge/neo4j-core/file/README.rdoc])
#
# Monster.all.query(:strength => 17).first #=> a node/Neo4j::Rails::Model
# Monster.all.query(:strength => 17).to_s #=> "START n0=node(42) MATCH ..."
# Neo4j.query{Neo4j.rb cypher DSL}
# dungeon.monsters.query(:name => 'Ghost', :strength => 10) # all monsters with those properties
# dungeon.monsters(:name => 'Ghost', :strength => 10) # same as above
# dungeon.monsters { |m| m[:name] == 'Ghost'] & m[:strength] == 16} # same as above
#
# @example Rules and Cypher (learn more {Neoj::Wrapper::Rule::ClassMethods}[http://rdoc.info/github/andreasronge/neo4j-wrapper/Neo4j/Wrapper/Rule/ClassMethods] )
# class Dungeon < Neo4j::Rails::Model
# has_n(:monsters).to(Monster)
# end
#
# class Monster < Neo4j::Rails::Model
# rule(:dangerous) { |m| m[:strength] > 15 }
# end
#
# class Room < Neo4j::Rails::Model
# has_n(:monsters).to(Monster)
# end
#
# @dungeon.monsters.dangerous { |m| rooms = m.incoming(Room.monsters); rooms } # returns rooms we should avoid
# @dungeon.monsters{|m| ret(m).asc(m[:strength])} # return the monsters nodes sorted by strength
#
# @example Callbacks (learn more - see #{Neo4j::Rails::Callbacks})
#
# class Person < Neo4j::Rails::Model
# before_save :do_something
Expand Down
42 changes: 26 additions & 16 deletions lib/neo4j/rails/persistence.rb
@@ -1,62 +1,65 @@
module Neo4j
module Rails
# Defines the create, delete and update methods.
# @see ClassMethods class methods when including this module
module Persistence
extend ActiveSupport::Concern
extend TxMethods


# Persist the object to the database. Validations and Callbacks are included
# by default but validation can be disabled by passing :validate => false
# to #save.
# by default but validation can be disabled by passing <tt>:validate => false</tt>
# to <tt>save</tt>. Creates a new transaction.
# @param (see Neo4j::Rails::Validations#save)
# @return [Boolean] true if it was persisted
# @see Neo4j::Rails::Validations Neo4j::Rails::Validations - for the :validate parameter
# @see Neo4j::Rails::Callbacks Neo4j::Rails::Callbacks - for callbacks
def save(*)
create_or_update
end
tx_methods :save

# Persist the object to the database. Validations and Callbacks are included
# by default but validation can be disabled by passing :validate => false
# to #save!.
# to #save! Creates a new transaction.
#
# Raises a RecordInvalidError if there is a problem during save.
# @raise a RecordInvalidError if there is a problem during save.
# @param (see Neo4j::Rails::Validations#save)
# @return nil
# @see #save
# @see Neo4j::Rails::Validations Neo4j::Rails::Validations - for the :validate parameter
# @see Neo4j::Rails::Callbacks Neo4j::Rails::Callbacks - for callbacks
def save!(*args)
unless save(*args)
raise RecordInvalidError.new(self)
end
end

def update
write_changed_attributes
clear_changes
true
end



# Removes the node from Neo4j and freezes the object.
def destroy
delete
freeze
end

# Same as #destroy but doesn't run destroy callbacks and doesn't freeze
# the object
# the object. Creates a new transaction
def delete
del unless new_record? || destroyed?
set_deleted_properties
end
tx_methods :delete

# Returns true if the object was destroyed.
# Returns +true+ if the object was destroyed.
def destroyed?
@_deleted || (!new_record? && !self.class.load_entity(neo_id))
end

# Returns if the record is persisted, i.e. it’s not a new record and it was not destroyed
# Returns +true+ if the record is persisted, i.e. it’s not a new record and it was not destroyed
def persisted?
!new_record? && !destroyed?
end

# Returns true if the record hasn't been saved to Neo4j yet.
# Returns +true+ if the record hasn't been saved to Neo4j yet.
def new_record?
_java_entity.nil?
end
Expand Down Expand Up @@ -117,6 +120,13 @@ def destroy_all
end

protected

def update
write_changed_attributes
clear_changes
true
end

def create_or_update
result = persisted? ? update : create
unless result != false
Expand Down
3 changes: 2 additions & 1 deletion lib/neo4j/rails/relationships/relationships.rb
@@ -1,7 +1,8 @@
module Neo4j
module Rails

# This module overrides the Neo4j::Core::Rels module so that it can handle unpersisted relationships.
# This module overrides the {Neo4j::Core::Rels}[http://rdoc.info/github/andreasronge/neo4j-core/Neo4j/Core/Rels] and {Neo4j::Core::Traversal}[http://rdoc.info/github/andreasronge/neo4j-core/Neo4j/Core/Traversal]
# modules so that it can handle unpersisted relationships of depth one.
#
module Relationships
extend ActiveSupport::Concern
Expand Down
7 changes: 7 additions & 0 deletions lib/neo4j/rails/validations.rb
@@ -1,14 +1,20 @@
module Neo4j
module Rails
# This mixin replace the original save method and performs validation before the save.
module Validations
include ActiveModel::Validations

# Implements the ActiveModel::Validation hook method.
# @see http://rubydoc.info/docs/rails/ActiveModel/Validations:read_attribute_for_validation
def read_attribute_for_validation(key)
respond_to?(key) ? send(key) : self[key]
end

# The validation process on save can be skipped by passing false. The regular Model#save method is
# replaced with this when the validations module is mixed in, which it is by default.
# @param [Hash] options the options to create a message with.
# @option options [true, false] :validate if false no validation will take place
# @return [Boolean] true if it saved it successfully
def save(options={})
result = perform_validations(options) ? super : false
if !result
Expand All @@ -17,6 +23,7 @@ def save(options={})
result
end

# @return [Boolean] true if valid
def valid?(context = nil)
context ||= (new_record? ? :create : :update)
super(context)
Expand Down

0 comments on commit d321a27

Please sign in to comment.