Skip to content

Commit

Permalink
Documented most the code [ci skip]
Browse files Browse the repository at this point in the history
  • Loading branch information
fredwu committed Apr 12, 2013
1 parent e03f73e commit 89a7fd8
Show file tree
Hide file tree
Showing 20 changed files with 157 additions and 7 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
Gemfile.lock
pkg
coverage
.yardoc
doc
1 change: 1 addition & 0 deletions .yardopts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--protected --private
2 changes: 2 additions & 0 deletions datamappify.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Gem::Specification.new do |spec|

spec.add_development_dependency "bundler", "~> 1.3"
spec.add_development_dependency "rake"
spec.add_development_dependency "redcarpet"
spec.add_development_dependency "yard"
spec.add_development_dependency "rspec"
spec.add_development_dependency "pry"
spec.add_development_dependency "simplecov"
Expand Down
1 change: 1 addition & 0 deletions lib/datamappify.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'datamappify/version'

module Datamappify
# @return [Pathname]
def self.root
Pathname.new("#{File.dirname(__FILE__)}/datamappify")
end
Expand Down
34 changes: 33 additions & 1 deletion lib/datamappify/data/criteria/common.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
module Datamappify
module Data
module Criteria
# Provides a set of useful methods for common criteria tasks, all +Criteria+ objects inherit from +Common+
class Common
attr_reader :source_class, :entity, :criteria, :attributes
# @return [Class]
attr_reader :source_class
# @return [Entity]
attr_reader :entity
# @return [void]
attr_reader :criteria
# @return [Set]
attr_reader :attributes

# @param source_class [Class]
# @param args [any]
# @yield an optional block
def initialize(source_class, *args, &block)
@source_class = source_class
@entity, @criteria, @attributes = *args
Expand All @@ -12,26 +23,44 @@ def initialize(source_class, *args, &block)

protected

# Key name of either the primary key (e.g. +id+) or foreign key (e.g. +user_id+)
#
# @return [Symbol]
def key_name
primary_record? ? :id : "#{entity.class.name.demodulize.underscore}_id".to_sym
end

# The value of {#key_name}
#
# @return [void]
def key_value
criteria.with_indifferent_access[key_name]
end

# Determines whether or not it's going to be a new record by looking at the {#key_value}
#
# @return [Boolean]
def new_record?
key_value.nil?
end

# Determines whether or not it's a primary record by comparing the source class and the entity class
#
# @return [Boolean]
def primary_record?
source_class.name.demodulize == entity.class.name.demodulize
end

# Ignores the current Criteria's operation if there is no dirty attributes
#
# @return [Boolean]
def ignore?
attributes_and_values.empty?
end

# Attributes with their corresponding values
#
# @return [Hash]
def attributes_and_values
hash = {}

Expand All @@ -46,6 +75,9 @@ def attributes_and_values

private

# Ignores the attribute if it isn't dirty or if it's a primary key
#
# @return [Boolean]
def ignore_attribute?(attribute)
entity.send(attribute.name).nil? || attribute.primary_key?
end
Expand Down
1 change: 1 addition & 0 deletions lib/datamappify/data/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class MethodNotImplemented < NoMethodError
end

class EntityInvalid < Error
# @param entity [Entity]
def initialize(entity)
super entity.errors.full_messages.join(', ')
end
Expand Down
22 changes: 19 additions & 3 deletions lib/datamappify/data/mapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,82 @@
module Datamappify
module Data
class Mapper
# @return [Class]
attr_accessor :entity_class
# @return [String]
attr_accessor :default_provider_name
# @return [Hash] attribute name to source mapping as specified in {Repository::MappingDSL#map_attribute}
attr_accessor :custom_mapping

def initialize
@custom_mapping = {}
@custom_attribute_names = []
end

# @return [Module]
def default_provider
@default_provider ||= Provider.const_get(default_provider_name)
end

# @return [Module]
def provider(provider_name)
Provider.const_get(provider_name)
end

# @return [Class]
def default_source_class
@default_source_class ||= default_provider.find_or_build_record_class(entity_class.name)
end

# @return [Hash] attribute sets classified by the names of their data provider
def classified_attributes
@classified_attributes ||= Set.new(custom_attributes + default_attributes).classify(&:provider_name)
end

private

# @return [Array<Symbol>]
def all_attribute_names
entity_class.attribute_set.entries.collect(&:name)
end

# @return [Array<Symbol>]
def default_attribute_names
all_attribute_names - custom_attribute_names
end

# @return [Array<Symbol>]
def custom_attribute_names
# make sure custom attributes are always processed
custom_attributes

@custom_attribute_names
end

# @return [Array<Attribute>]
def default_attributes
@default_attributes ||= default_attribute_names.collect do |attribute|
Attribute.new(attribute, default_source_for(attribute))
end
end

# @return [Array<Attribute>]
def custom_attributes
@custom_attributes ||= custom_mapping.collect do |attribute, source|
map_attribute(attribute, source)
end
end

def map_attribute(attribute, source)
@custom_attribute_names << attribute
# @param (see Data::Mapper::Attribute#initialize)
# @return [Attribute]
def map_attribute(name, source)
@custom_attribute_names << name

Attribute.new(attribute, source)
Attribute.new(name, source)
end

# @param attribute [Symbol] name of the attribute
# @return [String]
def default_source_for(attribute)
"#{default_provider_name}::#{entity_class.name}##{attribute}"
end
Expand Down
15 changes: 14 additions & 1 deletion lib/datamappify/data/mapper/attribute.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
module Datamappify
module Data
class Mapper
# Represents an entity attribute and its associated data source
class Attribute
attr_reader :name, :provider_name, :source_class_name, :source_attribute_name
# @return [String]
attr_reader :name
# @return [String]
attr_reader :provider_name
# @return [String]
attr_reader :source_class_name
# @return [String]
attr_reader :source_attribute_name

# @param name [Symbol] name of the attribute
# @param source [String] data provider, class and attribute, e.g. "ActiveRecord::User#surname"
def initialize(name, source)
@name = name.to_s

@provider_name, @source_class_name, @source_attribute_name = parse_source(source)
end

# @return [Class]
def source_class
@source_class ||= Record.find_or_build(provider_name, source_class_name)
end

# @return [Boolean]
def primary_key?
source_attribute_name == 'id'
end

private

# @return [Array<String>] an array with provider name, source class name and source attribute name
def parse_source(source)
provider_name, source_class_and_attribute = source.split('::')

Expand Down
1 change: 1 addition & 0 deletions lib/datamappify/data/provider/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Provider
module ActiveRecord
extend CommonProvider

# @return [ActiveRecord::Base]
def self.build_record_class(source_class_name)
Datamappify::Data::Record::ActiveRecord.const_set(
source_class_name, Class.new(::ActiveRecord::Base)
Expand Down
18 changes: 18 additions & 0 deletions lib/datamappify/data/provider/common_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,28 @@ def self.extended(klass)
end

module ModuleMethods
# Loads all the criteria files from the data provider
#
# @return [void]
def load_criterias
Dir[Datamappify.root.join("data/criteria/#{path_name}/*.rb")].each { |file| require file }
end

# Non-namespaced class name
#
# @return [String]
def class_name
@class_name ||= name.demodulize
end

# @return [String]
def path_name
@path_name ||= class_name.underscore
end

# Finds or builds a data record class from the data provider
#
# @return [Class] the data record class
def find_or_build_record_class(source_class_name)
if records_namespace.const_defined?(source_class_name, false)
records_namespace.const_get(source_class_name)
Expand All @@ -31,11 +41,19 @@ def find_or_build_record_class(source_class_name)

private

# The namespace for the data records, e.g. +Datamappify::Data::Record::ActiveRecord+
#
# @return [Module]
def records_namespace
@records_namespace ||= Data::Record.const_set(class_name, Module.new)
end
end

# Builds a {Criteria}
#
# @param name [Symbol]
# @param args [any]
# @yield an optional block passed to the +Criteria+ {Criteria::Common#initialize initialiser}
def build_criteria(name, *args, &block)
Data::Criteria.const_get(class_name).const_get(name).new(*args, &block).result
end
Expand Down
1 change: 1 addition & 0 deletions lib/datamappify/data/provider/sequel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Provider
module Sequel
extend CommonProvider

# @return [Sequel::Model]
def self.build_record_class(source_class_name)
Record::Sequel.const_set(
source_class_name, Class.new(::Sequel::Model(source_class_name.pluralize.underscore.to_sym))
Expand Down
3 changes: 3 additions & 0 deletions lib/datamappify/data/record.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
module Datamappify
module Data
# A convenient class for finding or building a data record
module Record
# @param provider_name [String]
# @param source_class_name [String]
def self.find_or_build(provider_name, source_class_name)
Provider.const_get(provider_name).find_or_build_record_class(source_class_name)
end
Expand Down
19 changes: 19 additions & 0 deletions lib/datamappify/repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,50 @@ def self.included(klass)
end

module InstanceMethods
# @param id_or_ids [Integer, Array<Integer>] an entity id or a collection of entity ids
# @return [Entity, Array<Entity>, nil]
def find(id_or_ids)
QueryMethod::Find.new(data_mapper, id_or_ids).result
end

# @param entity_or_entities [Entity, Array<Entity>] an entity or a collection of entities
# @return [Entity, Array<Entity>, false]
def save(entity_or_entities)
QueryMethod::Save.new(data_mapper, entity_or_entities).result
end

# @param (see #save)
# @raise [Data::EntityNotSaved]
# @return [Entity, Array<Entity>]
def save!(entity_or_entities)
save(entity_or_entities) || raise(Data::EntityNotSaved)
end

# @param id_or_ids_or_entity_or_entities [Entity, Array<Entity>] an entity or a collection of ids or entities
# @return [void, false]
def destroy(id_or_ids_or_entity_or_entities)
QueryMethod::Destroy.new(data_mapper, id_or_ids_or_entity_or_entities).result
end

# @param (see #destroy)
# @raise [Data::EntityNotDestroyed]
# @return [void]
def destroy!(id_or_ids_or_entity_or_entities)
destroy(id_or_ids_or_entity_or_entities) || raise(Data::EntityNotDestroyed)
end

# @return [Integer]
def count
QueryMethod::Count.new(data_mapper).result
end
end

# Wraps a ruby Singleton class so that calling `instance` is no longer necessary.
#
# @example With `instance`
# UserRepository.instance.count
# @example Without `instance`
# UserRepository.count
module SingletonWrapper
def self.extended(klass)
class << klass
Expand Down
10 changes: 8 additions & 2 deletions lib/datamappify/repository/mapping_dsl.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
module Datamappify
module Repository
module MappingDSL
# @param entity_class [Class] entity class
# @return [void]
def for_entity(entity_class)
data_mapper.entity_class = entity_class
end

# @param provider_name [String] name of data provider
# @return [void]
def default_provider(provider_name)
data_mapper.default_provider_name = provider_name.to_s
end

def map_attribute(attribute, source)
data_mapper.custom_mapping[attribute] = source
# @param (see Data::Mapper::Attribute#initialize)
# @return [void]
def map_attribute(name, source)
data_mapper.custom_mapping[name] = source
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/datamappify/repository/query_method/count.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ module Datamappify
module Repository
module QueryMethod
class Count
# @param mapper [Data::Mapper]
def initialize(mapper)
@mapper = mapper
end

# @return [Integer]
def result
@mapper.default_provider.build_criteria(:Count, @mapper.default_source_class)
end
Expand Down
Loading

0 comments on commit 89a7fd8

Please sign in to comment.