Permalink
Browse files

Docs

  • Loading branch information...
1 parent 4d81c43 commit b1c3fb599f840b6d2b97820b0bf3330ceea4611a @solnic committed Jun 1, 2011
Showing with 264 additions and 33 deletions.
  1. +37 −5 lib/virtus.rb
  2. +73 −5 lib/virtus/attributes.rb
  3. +61 −1 lib/virtus/attributes/attribute.rb
  4. +55 −16 lib/virtus/dirty_tracking.rb
  5. +38 −6 lib/virtus/dirty_tracking/session.rb
View
42 lib/virtus.rb
@@ -8,27 +8,55 @@
module Virtus
module Undefined; end
+ # Extends base class with Attributes and Chainable modules
+ #
+ # @param [Object] base
+ #
# @api private
- # TODO: document
def self.included(base)
base.extend(Attributes)
base.extend(Support::Chainable)
end
+ # Returns a value of the attribute with the given name
+ #
+ # @param [Symbol] name
+ # a name of an attribute
+ #
+ # @return [Object]
+ # a value of an attribute
+ #
# @api public
- # TODO: document
def attribute_get(name)
__send__(name)
end
+
+ # Sets a value of the attribute with the given name
+ #
+ # @param [Symbol] name
+ # a name of an attribute
+ #
+ # @param [Object] value
+ # a value to be set
+ #
+ # @return [Object]
+ # the value set on an object
+ #
# @api public
- # TODO: document
def attribute_set(name, value)
__send__("#{name}=", value)
end
+ # Mass-assign of attribute values
+ #
+ # @param [Hash] attributes
+ # a hash of attribute values to be set on an object
+ #
+ # @return [Hash]
+ # the attributes
+ #
# @api public
- # TODO: document
def attributes=(attributes)
attributes.each do |name, value|
if self.class.public_method_defined?(writer_name = "#{name}=")
@@ -37,8 +65,12 @@ def attributes=(attributes)
end
end
+ # Returns a hash of all publicly accessible attributes
+ #
+ # @return [Hash]
+ # the attributes
+ #
# @api public
- # TODO: document
def attributes
attributes = {}
View
78 lib/virtus/attributes.rb
@@ -1,8 +1,15 @@
module Virtus
module Attributes
class << self
+ # Returns a Virtus::Attributes::Object sub-class based on a name or class.
+ #
+ # @param [Class,String] class_or_name
+ # name of a class or a class itself
+ #
+ # @return [Class]
+ # one of the Virtus::Attributes::Object sub-class
+ #
# @api semipublic
- # TODO: document
def determine_type(class_or_name)
if class_or_name.is_a?(Class) && class_or_name < Attributes::Object
class_or_name
@@ -12,16 +19,46 @@ def determine_type(class_or_name)
end
end
+ # Chains Class.new to be able to set attributes during initialization of
+ # an object.
+ #
+ # @param [Hash] attributes
+ # the attributes hash to be set
+ #
+ # @return [Object]
+ #
# @api private
- # TODO: document
def new(attributes = {})
model = super
model.attributes = attributes
model
end
+ # Defines an attribute on an object's class.
+ #
+ # Usage:
+ #
+ # class Book
+ # include Virtus
+ #
+ # attribute :title, String
+ # attribute :author, String
+ # attribute :published_at, DateTime
+ # attribute :page_count, Integer
+ # end
+ #
+ # @param [Symbol] name
+ # the name of an attribute
+ #
+ # @param [Class] type
+ # the type class of an attribute
+ #
+ # @param [Hash] options
+ # the extra options hash
+ #
+ # @return [Virtus::Attributes::Object]
+ #
# @api public
- # TODO: document
def attribute(name, type, options = {})
attribute_klass = Attributes.determine_type(type)
attributes[name] = attribute = attribute_klass.new(name, self, options)
@@ -32,14 +69,27 @@ def attribute(name, type, options = {})
attribute
end
+ # Returns all the attributes defined on a Class.
+ #
+ # @return [Hash]
+ # an attributes hash indexed by attribute names
+ #
# @api public
- # TODO: document
def attributes
@attributes ||= {}
end
private
+ # Creates an attribute reader method
+ #
+ # @param [Symbol] name
+ # the name of an attribute
+ #
+ # @param [Virtus::Attributes::Object] attribute
+ # an attribute instance
+ #
+ # @api private
def _create_reader(name, attribute)
instance_variable_name = attribute.instance_variable_name
@@ -56,6 +106,15 @@ def #{name}
RUBY
end
+ # Creates an attribute writer method
+ #
+ # @param [Symbol] name
+ # the name of an attribute
+ #
+ # @param [Virtus::Attributes::Object] attribute
+ # an attribute instance
+ #
+ # @api private
def _create_writer(name, attribute)
class_eval <<-RUBY, __FILE__, __LINE__ + 1
chainable(:attributes) do
@@ -68,8 +127,17 @@ def #{name}=(value)
RUBY
end
+ # Hooks into const missing process to determine types of attributes.
+ #
+ # It is used when an attribute is defined and a global class like String
+ # or Integer is provided as the type which needs to be mapped to
+ # Virtus::Attributes::String and Virtus::Attributes::Integer.
+ #
+ # @param [String] name
+ #
+ # @return [Class]
+ #
# @api private
- # TODO: document
def const_missing(name)
Attributes.determine_type(name) || super
end
View
62 lib/virtus/attributes/attribute.rb
@@ -9,11 +9,24 @@ class Attribute
DEFAULT_ACCESSOR = :public.freeze
class << self
+ # Returns an array of valid options
+ #
+ # @return [Array]
+ # the array of valid option names
+ #
# @api public
def accepted_options
@accepted_options ||= []
end
+ # Defines which options are valid for a given attribute class.
+ #
+ # Example:
+ #
+ # class MyAttribute < Virtus::Attributes::Object
+ # accept_options :foo, :bar
+ # end
+ #
# @api public
def accept_options(*args)
accepted_options.concat(args)
@@ -31,11 +44,21 @@ def self.#{attribute_option}(value = Undefined) # def self.unique(value
descendants.each { |descendant| descendant.accepted_options.concat(args) }
end
+ # Returns all the descendant classes
+ #
+ # @return [Array]
+ # the array of descendants
+ #
# @api public
def descendants
@descendants ||= []
end
+ # Returns default options hash for a give attribute class.
+ #
+ # @return [Hash]
+ # a hash of default option values
+ #
# @api public
def options
options = {}
@@ -46,6 +69,8 @@ def options
options
end
+ # Adds descendant to descendants array and inherits default options
+ #
# @api private
def inherited(descendant)
descendants << descendant
@@ -56,12 +81,27 @@ def inherited(descendant)
accept_options *OPTIONS
+ # Returns if an attribute is a complex one.
+ #
+ # @return [TrueClass, FalseClass]
+ #
# @api semipublic
- # TODO: document
def complex?
options[:complex]
end
+ # Initializes an attribute instance
+ #
+ # @param [Symbol] name
+ # the name of an attribute
+ #
+ # @param [Class] model
+ # the object's class
+ #
+ # @param [Hash] options
+ # hash of extra options which overrides defaults set on an attribute class
+ #
+ # @api private
def initialize(name, model, options = {})
@name = name
@model = model
@@ -74,11 +114,21 @@ def initialize(name, model, options = {})
@writer_visibility = @options.fetch(:writer, default_accessor)
end
+ # Returns if the given value's class is an attribute's primitive
+ #
+ # @return [TrueClass, FalseClass]
+ #
# @api private
def primitive?(value)
value.kind_of?(self.class.primitive)
end
+ # Converts the given value to the primitive type unless it's already
+ # the primitive or nil
+ #
+ # @param [Object] value
+ # the value
+ #
# @api private
def typecast(value, model = nil)
if value.nil? || primitive?(value)
@@ -88,27 +138,37 @@ def typecast(value, model = nil)
end
end
+ # Converts the given value to the primitive type
+ #
# @api private
def typecast_to_primitive(value, model)
value
end
+ # Returns value of an attribute for the given model
+ #
# @api private
def get(model)
get!(model)
end
+ # Returns the instance variable of the attribute
+ #
# @api private
def get!(model)
model.instance_variable_get(instance_variable_name)
end
+ # Sets the value on the model
+ #
# @api private
def set(model, value)
return if value.nil?
set!(model, primitive?(value) ? value : typecast(value, model))
end
+ # Sets instance variable of the attribute
+ #
# @api private
def set!(model, value)
model.instance_variable_set(instance_variable_name, value)
View
71 lib/virtus/dirty_tracking.rb
@@ -1,64 +1,103 @@
module Virtus
+ # == Dirty Tracking
+ #
+ # Dirty Tracking is an optional module that you include only if you need it.
module DirtyTracking
+ # Extends a class with DirtyTracking::Attributes module
+ #
+ # @param [Class] base
+ #
# @api private
- # TODO: document
def self.included(base)
base.extend(DirtyTracking::Attributes)
end
+ # Returns if an object is dirty
+ #
+ # @return [TrueClass, FalseClass]
+ #
# @api public
- # TODO: document
def dirty?
dirty_session.dirty?
end
+ # Returns if an attribute with the given name is dirty.
+ #
+ # @param [Symbol] name
+ #
+ # @return [TrueClass, FalseClass]
+ #
# @api public
- # TODO: document
def attribute_dirty?(name)
dirty_session.dirty?(name)
end
+ # Explicitly sets an attribute as dirty.
+ #
+ # @param [Symbol] name
+ # the name of an attribute
+ #
+ # @param [Object] value
+ # a value of an attribute
+ #
# @api public
- # TODO: document
def attribute_dirty!(name, value)
dirty_session.dirty!(name, value)
end
+ # Returns all dirty attributes
+ #
+ # @return [Hash]
+ # a hash indexed with attribute names
+ #
# @api public
- # TODO: document
def dirty_attributes
dirty_session.dirty_attributes
end
+ # Returns original attributes
+ #
+ # @return [Hash]
+ # a hash indexed with attribute names
+ #
# @api public
- # TODO: document
def original_attributes
dirty_session.original_attributes
end
+ # Returns the current dirty tracking session
+ #
+ # @return [Virtus::DirtyTracking::Session]
+ #
# @api private
- # TODO: document
def dirty_session
@_dirty_session ||= Session.new(self)
end
module Attributes
+ # Creates an attribute writer with dirty tracking
+ #
+ # @see Virtus::Attributes.attribute
+ #
+ # @return [Virtus::Attributes::Object]
+ #
# @api public
- # TODO: document
def attribute(name, type, options = {})
- _create_writer_with_dirty_tracking(name, super)
- end
-
- # @api private
- def new(attributes = {})
- model = super
- model
+ _create_writer_with_dirty_tracking(name, attribute = super)
+ attribute
end
private
+ # Creates an attribute writer method with dirty tracking
+ #
+ # @param [Symbol] name
+ # the name of an attribute
+ #
+ # @param [Virtus::Attributes::Object] attribute
+ # an attribute instance
+ #
# @api private
- # TODO: document
def _create_writer_with_dirty_tracking(name, attribute)
class_eval <<-RUBY, __FILE__, __LINE__ + 1
chainable(:dirty_tracking) do
View
44 lib/virtus/dirty_tracking/session.rb
@@ -4,39 +4,65 @@ class Session
attr_reader :subject
# @api semipublic
- # TODO: document
def initialize(subject)
@subject = subject
end
+ # Returns original attributes of the subject
+ #
+ # @return [Hash]
+ # a hash of attributes indexed by attribute names
+ #
# @api semipublic
- # TODO: document
def original_attributes
@_original_attributes ||= subject.attributes.dup
end
+ # Returns dirty attributes of the subject
+ #
+ # @return [Hash]
+ # a hash of attributes indexed by attribute names
+ #
# @api semipublic
- # TODO: document
def dirty_attributes
(@_dirty_attributes ||= {}).update(complex_attributes)
end
+ # Sets an attribute as dirty
+ #
+ # @param [Symbol] name
+ # the name of an attribute
+ #
+ # @param [Object] value
+ # the value of an attribute
+ #
# @api semipublic
- # TODO: document
def dirty!(name, value)
dirty_attributes[name] = value
end
+ # Returns if an object is dirty or if an attribute with the given name is
+ # dirty.
+ #
+ # @param [Symbol] name
+ # the name of an attribute
+ #
+ # @return [TrueClass, FalseClass]
+ #
# @api semipublic
- # TODO: document
def dirty?(name = nil)
name ? dirty_attributes.key?(name) : dirty_attributes.any?
end
private
+ # Returns a values of complex dirty attributes that can be modified via
+ # their own APIs like Hash[] or Array<<
+ #
+ # @return [Hash]
+ # an attributes hash indexed by attribute names
+ #
# @api private
- # TODO: document
def complex_attributes
values = {}
@@ -51,6 +77,12 @@ def complex_attributes
values
end
+ # Returns a hash of complex attribute instances defined on
+ # the subject's class.
+ #
+ # @return [Hash]
+ # the attribute instances hash indexed by attribute names
+ #
# @api private
def complex_attributes_set
@_complex_attributes_set ||= subject.class.attributes.select do |name, attribute|

0 comments on commit b1c3fb5

Please sign in to comment.