Skip to content
Browse files

Some documentation, type import from Spira

  • Loading branch information...
1 parent e7cf7b8 commit 36412d353fae260b5d3aaf0d8044e07de7d16cd2 @davidrichards committed Mar 2, 2012
View
14 Rakefile
@@ -32,13 +32,13 @@ Rake::TestTask.new(:test) do |test|
test.verbose = true
end
-require 'rcov/rcovtask'
-Rcov::RcovTask.new do |test|
- test.libs << 'test'
- test.pattern = 'test/**/test_*.rb'
- test.verbose = true
- test.rcov_opts << '--exclude "gems/*"'
-end
+# require 'rcov/rcovtask'
+# Rcov::RcovTask.new do |test|
+# test.libs << 'test'
+# test.pattern = 'test/**/test_*.rb'
+# test.verbose = true
+# test.rcov_opts << '--exclude "gems/*"'
+# end
task :default => :test
View
1 lib/gearbox.rb
@@ -10,6 +10,7 @@ module Gearbox
# ========================
# = Helper Utility: path =
# ========================
+ # @private
def path(path)
File.expand_path("../gearbox/#{path}", __FILE__)
end
View
18 lib/gearbox/attribute_collection.rb
@@ -1,21 +1,39 @@
module Gearbox
+
+ ##
+ # Collects attributes in a hash-like format. Serializes the attributes in an OpenStruct.
+ ##
class AttributeCollection
+
+ # Build a new AttributeCollection with an optional Hash.
+ # Note: this class normalizes the keys and creates OpenStructs for values.
+ # @param [Hash] default A hash with normalized keys and OpenStruct values
def initialize(default={})
raise ArgumentError, "Must provide a hash for the defaults" unless default.is_a?(Hash)
@default = default
@source = {}
end
+ # Set one attribute in the collection.
+ # @param [String, Symbol] key
+ # @param [Hash] hash
+ # @return [OpenStruct] The hash, converted into an OpenStruct
def []=(key, hash)
raise ArgumentError, "Must provide a hash for the value" unless hash.is_a?(Hash)
@source[normalize_key(key)] = OpenStruct.new(@default.merge(hash))
end
+ # Get one attribute from the collection.
+ # @param [String, Symbol] key
+ # @return [OpenStruct, nil] Returns the attribute OpenStruct, if found.
def [](key)
@source[normalize_key(key)]
end
private
+ # Normalizes the key. Converts to a lower case symbol with non-alpha-numerics
+ # replaced by underscores, removing trailing and preceding underscores.
+ # @private
def normalize_key(obj)
obj.to_s.downcase.gsub(/[^A-Za-z0-9_]+/, '_').gsub(/(_$)|(^_)/, '').to_sym
end
View
18 lib/gearbox/mixins/ad_hoc_properties.rb
@@ -1,19 +1,37 @@
module Gearbox
+ ##
+ # Allows a model instance to add a new property at runtime.
+ # This is a (small) tip of the hat towards the flexibility
+ # offered by using a graph instead of a schema to govern
+ # the data store.
+ ##
module AdHocProperties
+ # Getter and setter for an id property.
+ # Will be adjusted when I decide whether to mixin ActiveModel
attr_accessor :id
+ # Stored attributes
+ # @return [RDFCollection]
def attributes_list
@attributes_list ||= RDFCollection.new
end
+ # Generates or gets a blank node, based on the id.
+ # Will be replaced by subject.
+ # @return [RDF::Node]
def bnode
return @bnode if @bnode
self.id ||= UUID.generate
safe_id = "#{self.class.name}_#{id}".gsub(/[^A-Za-z0-9\-_]/, '_')
@bnode = RDF::Node(safe_id)
end
+ # Add a property without defining it on the class.
+ # This will stay, will use the subject, and the regular infrastructure.
+ # @param [Symbol] accessor, the new field being created.
+ # @param [RDF::Statement] predicate, the predicate for the new field.
+ # @param [Any] The value to store
def add_property(accessor, predicate, object)
new_property = RDF::Statement.new(bnode, predicate, object)
attributes_list[accessor] = new_property
View
4 lib/gearbox/mixins/resource.rb
@@ -1,4 +1,8 @@
module Gearbox
+ ##
+ # The main mixin for any model.
+ # TODO: include an example file.
+ ##
module Resource
# ============
View
20 lib/gearbox/mixins/semantic_accessors.rb
@@ -1,15 +1,31 @@
module Gearbox
+
+ ##
+ # The attributes to add to a model.
+ # TODO: Add example from file.
+ ##
module SemanticAccessors
# Treat this as a bundle of class methods and instance methods.
+ # @private
def self.included(base)
base.extend ClassMethods
base.send :include, InstanceMethods
end
-
+ ##
+ # Class methods for the model.
+ ##
module ClassMethods
+ # Add an attribute or a field to a model. Takes a field name.
+ # Defines both a getter and a setter on the object.
+ # Requires a predicate option. Options are:
+ # * :predicate => RDF::URI
+ # * :reverse => Boolean store as value, predicate, subject
+ # * :index => Boolean maintain a full-text search index on this attribute
+ # @param [String, Symbol] getter_name, the field that is being created.
+ # @param [Hash] options
def attribute(getter_name, options={})
raise ArgumentError, "A predicate must be defined" unless options[:predicate]
@@ -29,8 +45,10 @@ def attribute(getter_name, options={})
end
+ # Sets the attributes_source, where to store the attributes
attr_writer :attributes_source
+ # Gets the attributes_source...
def attributes_source
@attributes_source ||= :attribute_collection
end
View
31 lib/gearbox/rdf_collection.rb
@@ -1,11 +1,25 @@
module Gearbox
+
+ ##
+ # Collects model values as RDF. This is a key part of making SPARQL our primary
+ # filtering, finding, and extension language.
+ ##
class RDFCollection
+
+ # ============
+ # = Behavior =
+ # ============
include RDF::Enumerable
def initialize
@source = {}
end
+ # Enumerates on the RDF Statements. Necessary for RDF::Enumerable to
+ # add all of the internal and external iterator goodies available there
+ # (like each_subject and has_subject?).
+ # @param [Block] block Optional block. Creates an external iterator if omitted.
+ # @return [nil, Enumerator] Returns either nil, or an external iterator.
def each(&block)
if block_given?
@source.each(&block)
@@ -14,25 +28,42 @@ def each(&block)
end
end
+ # Set RDF::Statements to the underlying collection. Normalizes the keys.
+ # @param [String, Symbol] key
+ # @param [RDF::Statement] obj. RDF::Statement that will be added.
def add_statement(key, obj)
@source[normalize_key(key)] = obj if obj.is_a?(RDF::Statement)
end
alias :[]= :add_statement
+ # Get RDF::Statement from the underlying collection. Normalizes the key.
+ # @param [String, Symbol] key. Normalized.
+ # @return [RDF::Statement, nil] Found statement, if it exists.
def [](key)
@source[normalize_key(key)]
end
+ # Lookup whether the key exists.
+ # @param [String, Symbol] key
+ # @param [Hash, nil] opts. :normalize => false will lookup the key as provided.
+ # @return [Boolean]
def has_key?(key, opts={})
key = normalize_key(key) if opts.fetch(:normalize, true)
@source.has_key?(key)
end
+ # Merges a hash of RDF::Statements into the underlying collection.
+ # Uses the add_statement to filter the values of the hash.
+ # @param [Hash] hash. Collection of statements.
+ # @return [nil]
def merge!(hash)
hash.each {|key, obj| add_statement(key, obj)}
end
private
+ # Normalizes the key. Converts to a lower case symbol with non-alpha-numerics
+ # replaced by underscores, removing trailing and preceding underscores.
+ # @private
def normalize_key(obj)
obj.to_s.downcase.gsub(/[^A-Za-z0-9_]+/, '_').gsub(/(_$)|(^_)/, '').to_sym
end
View
85 lib/gearbox/type.rb
@@ -0,0 +1,85 @@
+module Gearbox
+
+ ##
+ # This was taken wholesale from Spira. I think Ben did a great job with that.
+ # I have nothing to add or detract from his good work.
+ #
+ # Gearbox::Type can be included by classes to create new property types for
+ # Gearbox. These types are responsible for serialization a Ruby value into an
+ # `RDF::Value`, and deserialization of an `RDF::Value` into a Ruby value.
+ #
+ # A simple example:
+ #
+ # class Integer
+ #
+ # include Gearbox::Type
+ #
+ # def self.unserialize(value)
+ # value.object
+ # end
+ #
+ # def self.serialize(value)
+ # RDF::Literal.new(value)
+ # end
+ #
+ # register_alias XSD.integer
+ # end
+ #
+ # This example will serialize and deserialize integers. It's included with
+ # Gearbox by default. It allows either of the following forms to declare an
+ # integer property on a Gearbox resource:
+ #
+ # property :age, :predicate => FOAF.age, :type => Integer
+ # property :age, :predicate => FOAF.age, :type => XSD.integer
+ #
+ # `Gearbox::Type`s include the RDF namespace and thus have all of the base RDF
+ # vocabularies available to them without the `RDF::` prefix.
+ #
+ # @see http://rdf.rubyforge.org/RDF/Value.html
+ # @see Gearbox::Resource
+ module Type
+
+ ##
+ # Make the DSL available to a child class.
+ #
+ # @private
+ def self.included(child)
+ child.extend(ClassMethods)
+ Gearbox.type_alias(child,child)
+ end
+
+ include RDF
+
+ module ClassMethods
+
+ ##
+ # Register an alias that this type can be referred to as, such as an RDF
+ # URI. The alias can be any object, symbol, or constant.
+ #
+ # @param [Any] identifier The new alias in property declarations for this class
+ # @return [Void]
+ def register_alias(any)
+ Gearbox.type_alias(any, self)
+ end
+
+ ##
+ # Serialize a given value to RDF.
+ #
+ # @param [Any] value The Ruby value to be serialized
+ # @return [RDF::Value] The RDF form of this value
+ def serialize(value)
+ value
+ end
+
+ ##
+ # Unserialize a given RDF value to Ruby
+ #
+ # @param [RDF::Value] value The RDF form of this value
+ # @return [Any] The Ruby form of this value
+ def unserialize(value)
+ value
+ end
+ end
+
+ end
+end
View
28 lib/gearbox/types.rb
@@ -0,0 +1,28 @@
+module Gearbox
+
+ ##
+ # Gearbox::Types is a set of default Gearbox::Type classes.
+ #
+ # @see Gearbox::Type
+ # @see Gearbox::Types::Integer
+ # @see Gearbox::Types::Boolean
+ # @see Gearbox::Types::String
+ # @see Gearbox::Types::Float
+ # @see Gearbox::Types::Any
+ module Types
+
+ # No autoloading here--the associations to XSD types are made by the
+ # classes themselves, so we need to explicitly require them or XSD types
+ # will show up as not found.
+ require 'gearbox/types/integer'
+ require 'gearbox/types/boolean'
+ require 'gearbox/types/any'
+ require 'gearbox/types/string'
+ require 'gearbox/types/float'
+ require 'gearbox/types/uri'
+ require 'gearbox/types/decimal'
+ require 'gearbox/types/native'
+
+
+ end
+end
View
24 lib/gearbox/types/any.rb
@@ -0,0 +1,24 @@
+module Gearbox::Types
+
+ ##
+ # This class does its best to serialize or unserialize RDF values into Ruby
+ # values and vice versa using RDF.rb's built-in helpers for `RDF::Literal`s.
+ # Its behavior is defined as 'What `RDF::Literal` does' for a given value.
+ #
+ # @see Gearbox::Type
+ # @see http://rdf.rubyforge.org/RDF/Literal.html
+ class Any
+
+ include Gearbox::Type
+
+ def self.unserialize(value)
+ value.respond_to?(:object) ? value.object : value
+ end
+
+ def self.serialize(value)
+ raise TypeError, "Gearbox::Types::Any cannot serialize collections" if value.is_a?(Array)
+ value.is_a?(RDF::Value) ? value : RDF::Literal.new(value)
+ end
+
+ end
+end
View
31 lib/gearbox/types/boolean.rb
@@ -0,0 +1,31 @@
+module Gearbox::Types
+
+ ##
+ # A {Gearbox::Type} for Boolean values. Values will be expressed as booleans
+ # and packaged as `XSD.boolean` `RDF::Literal`s.
+ #
+ # A {Gearbox::Resource} property can reference this type as
+ # `Gearbox::Types::Boolean`, `Boolean`, or `XSD.boolean`.
+ #
+ # @see Gearbox::Type
+ # @see http://rdf.rubyforge.org/RDF/Literal.html
+ class Boolean
+
+ include Gearbox::Type
+
+ def self.unserialize(value)
+ value.object == true
+ end
+
+ def self.serialize(value)
+ if value
+ RDF::Literal.new(true, :datatype => XSD.boolean)
+ else
+ RDF::Literal.new(false, :datatype => XSD.boolean)
+ end
+ end
+
+ register_alias XSD.boolean
+
+ end
+end
View
27 lib/gearbox/types/date.rb
@@ -0,0 +1,27 @@
+module Gearbox::Types
+
+ ##
+ # A {Gearbox::Type} for Date values. Values will be associated with the
+ # `XSD.date` type.
+ #
+ # A {Gearbox::Resource} property can reference this type as
+ # `Gearbox::Types::Date`, `Date`, or `XSD.Date`.
+ #
+ # @see Gearbox::Type
+ # @see http://rdf.rubyforge.org/RDF/Literal.html
+ class Date
+
+ include Gearbox::Type
+
+ def self.unserialize(value)
+ value.object
+ end
+
+ def self.serialize(value)
+ RDF::Literal::Date.new(value)
+ end
+
+ register_alias XSD.date
+
+ end
+end
View
29 lib/gearbox/types/decimal.rb
@@ -0,0 +1,29 @@
+require 'bigdecimal'
+
+module Gearbox::Types
+
+ ##
+ # A {Gearbox::Type} for integer values. Values will be associated with the
+ # `XSD.integer` type.
+ #
+ # A {Gearbox::Resource} property can reference this type as
+ # `Gearbox::Types::Integer`, `Integer`, or `XSD.integer`.
+ #
+ # @see Gearbox::Type
+ # @see http://rdf.rubyforge.org/RDF/Literal.html
+ class Decimal
+ include Gearbox::Type
+
+ def self.unserialize(value)
+ object = value.object
+ object.is_a?(BigDecimal) ? object : BigDecimal.new(object.to_s)
+ end
+
+ def self.serialize(value)
+ RDF::Literal.new(value.is_a?(BigDecimal) ? value.to_s('F') : value.to_s, :datatype => XSD.decimal)
+ end
+
+ register_alias XSD.decimal
+
+ end
+end
View
28 lib/gearbox/types/float.rb
@@ -0,0 +1,28 @@
+module Gearbox::Types
+
+ ##
+ # A {Gearbox::Type} for Float values. Values will be associated with the
+ # `XSD.double` type.
+ #
+ # A {Gearbox::Resource} property can reference this type as
+ # `Gearbox::Types::Float`, `Float`, `XSD.double`, or `XSD.float`.
+ #
+ # @see Gearbox::Type
+ # @see http://rdf.rubyforge.org/RDF/Literal.html
+ class Float
+
+ include Gearbox::Type
+
+ def self.unserialize(value)
+ value.object.to_f
+ end
+
+ def self.serialize(value)
+ RDF::Literal.new(value.to_f, :datatype => XSD.double)
+ end
+
+ register_alias XSD.float
+ register_alias XSD.double
+
+ end
+end
View
27 lib/gearbox/types/integer.rb
@@ -0,0 +1,27 @@
+module Gearbox::Types
+
+ ##
+ # A {Gearbox::Type} for integer values. Values will be associated with the
+ # `XSD.integer` type.
+ #
+ # A {Gearbox::Resource} property can reference this type as
+ # `Gearbox::Types::Integer`, `Integer`, or `XSD.integer`.
+ #
+ # @see Gearbox::Type
+ # @see http://rdf.rubyforge.org/RDF/Literal.html
+ class Integer
+
+ include Gearbox::Type
+
+ def self.unserialize(value)
+ value.object
+ end
+
+ def self.serialize(value)
+ RDF::Literal.new(value)
+ end
+
+ register_alias XSD.integer
+
+ end
+end
View
22 lib/gearbox/types/native.rb
@@ -0,0 +1,22 @@
+module Gearbox::Types
+
+ ##
+ # This type is a native type, doing no conversion to Ruby types. The naked
+ # RDF::Value (URI, Node, Literal, etc) will be used, and no deserialization
+ # is done.
+ #
+ # @see Gearbox::Type
+ class Native
+
+ include Gearbox::Type
+
+ def self.unserialize(value)
+ value
+ end
+
+ def self.serialize(value)
+ value
+ end
+
+ end
+end
View
27 lib/gearbox/types/string.rb
@@ -0,0 +1,27 @@
+module Gearbox::Types
+
+ ##
+ # A {Gearbox::Type} for string values. Values will be associated with the
+ # `XSD.string` type with no language code.
+ #
+ # A {Gearbox::Resource} property can reference this type as
+ # `Gearbox::Types::String`, `String`, or `XSD.string`.
+ #
+ # @see Gearbox::Type
+ # @see http://rdf.rubyforge.org/RDF/Literal.html
+ class String
+
+ include Gearbox::Type
+
+ def self.unserialize(value)
+ value.object.to_s
+ end
+
+ def self.serialize(value)
+ RDF::Literal.new(value.to_s)
+ end
+
+ register_alias XSD.string
+
+ end
+end
View
25 lib/gearbox/types/uri.rb
@@ -0,0 +1,25 @@
+module Gearbox::Types
+
+ ##
+ # This type takes RDF Resource objects and provides RDF::URI objects for the
+ # ruby representation.
+ #
+ # @see Gearbox::Type
+ # @see http://rdf.rubyforge.org/RDF/URI.html
+ class URI
+
+ include Gearbox::Type
+
+ def self.unserialize(value)
+ RDF::URI(value)
+ end
+
+ def self.serialize(value)
+ RDF::URI(value)
+ end
+
+ register_alias :uri
+ register_alias RDF::URI
+
+ end
+end

0 comments on commit 36412d3

Please sign in to comment.
Something went wrong with that request. Please try again.