Module: Spira::Persistence::ClassMethods

Defined in:
lib/spira/persistence.rb

Instance Method Summary collapse

Instance Method Details

#all(*args) ⇒ Object



36
37
38
# File 'lib/spira/persistence.rb', line 36

def all(*args)
  find(:all, *args)
end

#countInteger

The number of URIs projectable as a given class in the repository. This method is only valid for classes which declare a ‘type` with the `type` method in the Resource.

Returns:

  • (Integer)

    the count

Raises:



100
101
102
# File 'lib/spira/persistence.rb', line 100

def count
  each.count
end

#create(attributes = nil, options = {}, &block) ⇒ Object

Creates an object (or multiple objects) and saves it to the database, if validations pass. The resulting object is returned whether the object was saved successfully to the database or not.

The attributes parameter can be either be a Hash or an Array of Hashes. These Hashes describe the attributes on the objects that are to be created.

create respects mass-assignment security and accepts either :as or :without_protection options in the options parameter.

Examples

# Create a single new object
User.create(first_name: 'Jamie')

# Create a single new object using the :admin mass-assignment security role
User.create({ first_name: 'Jamie', is_admin: true }, as: :admin)

# Create a single new object bypassing mass-assignment security
User.create({ first_name: 'Jamie', is_admin: true }, without_protection: true)

# Create an Array of new objects
User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])

# Create a single object and pass it into a block to set other attributes.
User.create(first_name: 'Jamie') do |u|
  u.is_admin = false
end

# Creating an Array of new objects using a block, where the block is executed for each object:
User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
  u.is_admin = false
end


135
136
137
138
139
140
141
142
143
# File 'lib/spira/persistence.rb', line 135

def create(attributes = nil, options = {}, &block)
  if attributes.is_a?(Array)
    attributes.collect { |attr| create(attr, options, &block) }
  else
    object = new(attributes, options, &block)
    object.save
    object
  end
end

#each {|instance| ... } ⇒ Void #eachEnumerator Also known as: find_each

Enumerate over all resources projectable as this class. This method is only valid for classes which declare a ‘type` with the `type` method in the Resource.

Note that the instantiated records are “promises” not real instances.

Overloads:

  • #each {|instance| ... } ⇒ Void

    Yields:

    • (instance)

      A block to perform for each available projection of this class

    Yield Parameters:

    • instance (self)

    Yield Returns:

    • (Void)

    Returns:

    • (Void)
  • #eachEnumerator

    Returns:

    • (Enumerator)

Raises:



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/spira/persistence.rb', line 60

def each(*args)
  raise Spira::NoTypeError, "Cannot count a #{self} without a reference type URI" unless type

  options = args.extract_options!
  conditions = options.delete(:conditions) || {}

  raise Spira::SpiraError, "Cannot accept :type in query conditions" if conditions.delete(:type) || conditions.delete("type")

  if block_given?
    limit = options[:limit] || -1
    offset = options[:offset] || 0
    # TODO: ideally, all types should be joined in a conjunction
    #       within "conditions_to_query", but since RDF::Query
    #       cannot handle such patterns, we iterate across types "manually"
    types.each do |tp|
      break if limit.zero?
      q = conditions_to_query(conditions.merge(type: tp))
      repository.query(q) do |solution|
        break if limit.zero?
        if offset.zero?
          yield unserialize(solution[:subject])
          limit -= 1
        else
          offset -= 1
        end
      end
    end
  else
    enum_for(:each, *args)
  end
end

#find(scope, *args) ⇒ Spira::Base, Array

Simple finder method.

Parameters:

  • scope (Symbol, ID)

    scope can be :all, :first or an ID

  • args (Hash)

    args can contain:

    :conditions - Hash of properties and values
    :limit      - Integer, limiting the amount of returned records
    

Returns:



25
26
27
28
29
30
31
32
33
34
# File 'lib/spira/persistence.rb', line 25

def find(scope, *args)
  case scope
  when :first
    find_each(*args).first
  when :all
    find_all(*args)
  else
    instantiate_record(scope)
  end
end

#first(*args) ⇒ Object



40
41
42
# File 'lib/spira/persistence.rb', line 40

def first(*args)
  find(:first, *args)
end

#for(uri, attributes = {}) ⇒ Spira::Base #for(identifier, attributes = {}) ⇒ Spira::Base Also known as: []

Create a new projection instance of this class for the given URI. If a class has a base_uri given, and the argument is not an ‘RDF::URI`, the given identifier will be appended to the base URI.

Spira does not have ‘find’ or ‘create’ functions. As RDF identifiers are globally unique, they all simply ‘are’.

On calling ‘for`, a new projection is created for the given URI. The first time access is attempted on a field, the repository will be queried for existing attributes, which will be used for the given URI. Underlying repositories are not accessed at the time of calling `for`.

A class with a base URI may still be projected for any URI, whether or not it uses the given resource class’ base URI.

given in the attributes. have a base URI.

Overloads:

  • #for(uri, attributes = {}) ⇒ Spira::Base

    Parameters:

    • uri (RDF::URI)

      The URI to create an instance for

    • attributes (Hash{Symbol => Any}) (defaults to: {})

      Initial attributes

  • #for(identifier, attributes = {}) ⇒ Spira::Base

    Parameters:

    • uri (Any)

      The identifier to append to the base URI for this class

    • attributes (Hash{Symbol => Any}) (defaults to: {})

      Initial attributes

Yields:

  • (self)

    Executes a given block and calls ‘#save!`

Yield Parameters:

  • self (self)

    The newly created instance

Returns:

Raises:

  • (TypeError)

    if an RDF type is given in the attributes and one is

  • (ArgumentError)

    if a non-URI is given and the class does not

See Also:



175
176
177
# File 'lib/spira/persistence.rb', line 175

def for(identifier, attributes = {}, &block)
  self.project(id_for(identifier), attributes, &block)
end

#id_for(identifier) ⇒ RDF::URI, RDF::Node

Creates a URI or RDF::Node based on a potential base_uri and string, URI, or Node, or Addressable::URI. If not a URI or Node, the given identifier should be a string representing an absolute URI, or something responding to to_s which can be appended to a base URI, which this class must have.

Parameters:

  • identifier (Any)

Returns:

Raises:

  • (ArgumentError)

    If this class cannot create an identifier from the given argument

See Also:



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/spira/persistence.rb', line 211

def id_for(identifier)
  case
    # Absolute URI's go through unchanged
  when identifier.is_a?(RDF::URI) && identifier.absolute?
    identifier
    # We don't have a base URI to join this fragment with, so go ahead and instantiate it as-is.
  when identifier.is_a?(RDF::URI) && self.base_uri.nil?
    identifier
    # Blank nodes go through unchanged
  when identifier.respond_to?(:node?) && identifier.node?
    identifier
    # Anything that can be an RDF::URI, we re-run this case statement
    # on it for the fragment logic above.
  when identifier.respond_to?(:to_uri) && !identifier.is_a?(RDF::URI)
    id_for(identifier.to_uri)
    # see comment with #to_uri above, this might be a fragment
  else
    uri = identifier.is_a?(RDF::URI) ? identifier : RDF::URI.intern(identifier.to_s)
    case
    when uri.absolute?
      uri
    when self.base_uri.nil?
      raise ArgumentError, "Cannot create identifier for #{self} by String without base_uri; an RDF::URI is required"
    else
      separator = self.base_uri.to_s[-1,1] =~ /(\/|#)/ ? '' : '/'
      RDF::URI.intern(self.base_uri.to_s + separator + identifier.to_s)
    end
  end
end

#project(subject, attributes = {}, &block) ⇒ Spira::Base

Create a new instance with the given subject without any modification to the given subject at all. This method exists to provide an entry point for implementing classes that want to create a more intelligent .for and/or .id_for for their given use cases, such as simple string appending to base URIs or calculated URIs from other representations.

Examples:

Using simple string concatentation with base_uri in .for instead of joining delimiters

def for(identifier, attributes = {}, &block)
  self.project(RDF::URI(self.base_uri.to_s + identifier.to_s), attributes, &block)
end

Parameters:

  • subject (RDF::URI, RDF::Node)
  • attributes (Hash{Symbol => Any}) (defaults to: {})

    Initial attributes

Returns:



194
195
196
# File 'lib/spira/persistence.rb', line 194

def project(subject, attributes = {}, &block)
  new(attributes.merge(_subject: subject), &block)
end

#repositoryRDF::Repository?

The current repository for this class

Returns:



11
12
13
# File 'lib/spira/persistence.rb', line 11

def repository
  Spira.repository || raise(NoRepositoryError)
end