Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 3 commits
  • 5 files changed
  • 0 commit comments
  • 1 contributor
View
63 lib/dm-core/model/property.rb
@@ -1,3 +1,8 @@
+require 'dm-core/property'
+require 'dm-core/property/lookup'
+require 'dm-core/model/repository_property_set'
+require 'dm-core/model/property_accessor_module'
+
# TODO: update Model#respond_to? to return true if method_method missing
# would handle the message
@@ -8,12 +13,14 @@ module Property
def self.extended(model)
model.instance_variable_set(:@properties, {})
+ # model.instance_variable_set(:@properties, RepositoryPropertySet.new(model))
model.instance_variable_set(:@field_naming_conventions, {})
end
def inherited(model)
model.instance_variable_set(:@properties, {})
+ # model.instance_variable_set(:@properties, RepositoryPropertySet.new(model))
model.instance_variable_set(:@field_naming_conventions, @field_naming_conventions.dup)
@properties.each do |repository_name, properties|
@@ -95,8 +102,7 @@ def property(name, type, options = {})
descendant.properties(repository_name) << property
end
- create_reader_for(property)
- create_writer_for(property)
+ property_module.define_property_accessors_for(property)
# FIXME: explicit return needed for YARD to parse this properly
return property
@@ -183,63 +189,16 @@ def key_conditions(repository, key)
# Defines the anonymous module that is used to add properties.
# Using a single module here prevents having a very large number
# of anonymous modules, where each property has their own module.
+ #
# @api private
def property_module
@property_module ||= begin
- mod = Module.new
- class_eval do
- include mod
- end
+ mod = PropertyAccessorModule.new(self.name)
+ include mod
mod
end
end
- # defines the reader method for the property
- #
- # @api private
- def create_reader_for(property)
- name = property.name.to_s
- reader_visibility = property.reader_visibility
- instance_variable_name = property.instance_variable_name
- property_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
- #{reader_visibility}
- def #{name}
- return #{instance_variable_name} if defined?(#{instance_variable_name})
- property = properties[#{name.inspect}]
- #{instance_variable_name} = property ? persistence_state.get(property) : nil
- end
- RUBY
-
- boolean_reader_name = "#{name}?"
-
- if property.kind_of?(DataMapper::Property::Boolean)
- property_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
- #{reader_visibility}
- def #{boolean_reader_name}
- #{name}
- end
- RUBY
- end
- end
-
- # defines the setter for the property
- #
- # @api private
- def create_writer_for(property)
- name = property.name
- writer_visibility = property.writer_visibility
-
- writer_name = "#{name}="
- property_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
- #{writer_visibility}
- def #{writer_name}(value)
- property = properties[#{name.inspect}]
- self.persistence_state = persistence_state.set(property, value)
- persistence_state.get(property)
- end
- RUBY
- end
-
# @api public
def method_missing(method, *args, &block)
if property = properties(repository_name)[method]
View
65 lib/dm-core/model/property_accessor_module.rb
@@ -0,0 +1,65 @@
+module DataMapper
+ module Model
+ class PropertyAccessorModule < Module
+ attr_reader :inspect
+
+ def initialize(model_name)
+ @inspect = "#{model_name}::PropertyAccessorModule"
+ end
+
+ # defines the reader method for the property
+ #
+ # @api private
+ def define_property_accessors_for(property)
+ name = property.name
+ reader_visibility = property.reader_visibility
+ writer_visibility = property.writer_visibility
+ instance_variable_name = property.instance_variable_name
+
+ define_property_reader(name, reader_visibility, instance_variable_name)
+ define_property_writer(name, writer_visibility)
+
+ if property.kind_of?(DataMapper::Property::Boolean)
+ define_property_boolean_query(name, reader_visibility)
+ end
+ end
+
+ def define_property_reader(name, visibility, instance_variable_name)
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ #{visibility}
+
+ def #{name}
+ return #{instance_variable_name} if defined?(#{instance_variable_name})
+ property = properties[:#{name}]
+ #{instance_variable_name} = property ? persistence_state.get(property) : nil
+ end
+ RUBY
+ end
+
+ def define_property_boolean_query(name, visibility)
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ #{visibility}
+
+ def #{name}?
+ #{name}
+ end
+ RUBY
+ end
+
+ # defines the setter for the property
+ #
+ # @api private
+ def define_property_writer(name, visibility)
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ #{visibility}
+ def #{name}=(value)
+ property = properties[:#{name}]
+ self.persistence_state = persistence_state.set(property, value)
+ persistence_state.get(property)
+ end
+ RUBY
+ end
+
+ end # class PropertyAccessorModule
+ end # module Model
+end # module DataMapper
View
61 lib/dm-core/model/relationship.rb
@@ -1,3 +1,6 @@
+require 'dm-core/associations/relationship'
+require 'dm-core/model/relationship_accessor_module'
+
# TODO: update Model#respond_to? to return true if method_method missing
# would handle the message
@@ -129,8 +132,7 @@ def has(cardinality, name, *args)
descendant.relationships(repository_name) << relationship
end
- create_relationship_reader(relationship)
- create_relationship_writer(relationship)
+ relationship_module.define_relationship_accessors_for(relationship)
relationship
end
@@ -183,8 +185,7 @@ def belongs_to(name, *args)
descendant.relationships(repository_name) << relationship
end
- create_relationship_reader(relationship)
- create_relationship_writer(relationship)
+ relationship_module.define_relationship_accessors_for(relationship)
relationship
end
@@ -309,60 +310,12 @@ def assert_valid_options(options)
# @api private
def relationship_module
@relationship_module ||= begin
- mod = Module.new
- class_eval do
- include mod
- end
+ mod = RelationshipAccessorModule.new(self.name)
+ include mod
mod
end
end
- # Dynamically defines reader method
- #
- # @api private
- def create_relationship_reader(relationship)
- name = relationship.name
- reader_name = name.to_s
-
- return if method_defined?(reader_name)
-
- reader_visibility = relationship.reader_visibility
-
- relationship_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
- #{reader_visibility}
- def #{reader_name}(query = nil)
- # TODO: when no query is passed in, return the results from
- # the ivar directly. This will require that the ivar
- # actually hold the resource/collection, and in the case
- # of 1:1, the underlying collection is hidden in a
- # private ivar, and the resource is in a known ivar
-
- persistence_state.get(relationships[#{name.inspect}], query)
- end
- RUBY
- end
-
- # Dynamically defines writer method
- #
- # @api private
- def create_relationship_writer(relationship)
- name = relationship.name
- writer_name = "#{name}="
-
- return if method_defined?(writer_name)
-
- writer_visibility = relationship.writer_visibility
-
- relationship_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
- #{writer_visibility}
- def #{writer_name}(target)
- relationship = relationships[#{name.inspect}]
- self.persistence_state = persistence_state.set(relationship, target)
- persistence_state.get(relationship)
- end
- RUBY
- end
-
# @api public
def method_missing(method, *args, &block)
if relationship = relationships(repository_name)[method]
View
56 lib/dm-core/model/relationship_accessor_module.rb
@@ -0,0 +1,56 @@
+module DataMapper
+ module Model
+ class RelationshipAccessorModule < Module
+ attr_reader :inspect
+
+ def initialize(model_name)
+ @inspect = "#{model_name}::RelationshipAccessorModule"
+ end
+
+ # Dynamically defines reader method
+ #
+ # @api private
+ def define_relationship_accessors_for(relationship)
+ name = relationship.name
+
+ define_relationship_reader(name, relationship.reader_visibility)
+ define_relationship_writer(name, relationship.writer_visibility)
+ end
+
+ # Dynamically defines reader method
+ #
+ # @api private
+ def define_relationship_reader(name, visibility)
+ # TODO: when no query is passed in, return the results from
+ # the ivar directly. This will require that the ivar
+ # actually hold the resource/collection, and in the case
+ # of 1:1, the underlying collection is hidden in a
+ # private ivar, and the resource is in a known ivar
+
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ #{visibility}
+
+ def #{name}(query = nil)
+ persistence_state.get(relationships[:#{name}], query)
+ end
+ RUBY
+ end
+
+ # Dynamically defines writer method
+ #
+ # @api private
+ def define_relationship_writer(name, visibility)
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
+ #{visibility}
+
+ def #{name}=(target)
+ relationship = relationships[:#{name}]
+ self.persistence_state = persistence_state.set(relationship, target)
+ persistence_state.get(relationship)
+ end
+ RUBY
+ end
+
+ end # class RelationshipAccessorModule
+ end # module Model
+end # module DataMapper
View
155 lib/dm-core/model/repository_property_set.rb
@@ -0,0 +1,155 @@
+require 'dm-core/property'
+
+module DataMapper
+ class Property::DeprecatedTypeError < ArgumentError
+ def initialize(deprecated_type, replacement_type)
+ @deprecated_type = deprecated_type
+ @replacement_type = replacement_type
+ end
+
+ def message
+ "#{deprecated_type} is deprecated, use #{replacement_type} instead"
+ end
+ end
+
+ class Property::UnsupportedTypeError < ArgumentError
+ def initialize(type)
+ @type = type
+ end
+
+ def message
+ "#{type.inspect} is not a supported type"
+ end
+ end
+
+ module Model
+ module Property
+ class RepositoryPropertySet
+ attr_reader :model
+ attr_reader :property_sets
+
+ def initialize(model)
+ @model = model
+ @property_sets = {}
+ end
+
+ def add_property(name, raw_type, options = {})
+ assert_supported_type(raw_type)
+
+ # if the type can be found within Property then
+ # use that class rather than the primitive
+ property_factory = DataMapper::Property.determine_class(raw_type)
+ raise Property::UnsupportedTypeError(raw_type) unless property_factory
+
+ property = property_factory.new(model, name, options)
+ current_repository_property_set << property
+
+ # Add property to the other mappings as well if current repository
+ # is the default repository
+ if current_repository_name == default_repository_name
+ add_to_non_default_repositories(property)
+ end
+
+ # Add the property to the lazy_loads set for this resources repository
+ # only.
+ # TODO Is this right or should we add the property to the lazy contexts
+ # of all repositories?
+ if property.lazy?
+ add_to_lazy_contexts(current_repository_property_set, property, options)
+ end
+
+ end
+
+ def [](repository_name)
+ # TODO: create PropertySet#copy that will copy the property_set, but assign the
+ # new Relationship objects to a supplied repository and model. dup does not really
+ # do what is needed
+
+ # TODO: stop using #to_sym on uncontrolled input
+ repository_name = repository_name.to_sym
+
+ @property_sets.fetch(repository_name) do
+ @property_sets[repository_name] = new_property_set_for(repository_name)
+ end
+ end
+
+ def with_descendants(repository_name = default_repository_name)
+ properties = properties(repository_name).dup
+
+ descendants.each do |model|
+ model.properties(repository_name).each do |property|
+ properties << property
+ end
+ end
+
+ properties
+ end
+
+ def concat(other)
+ other.property_sets.each do |repository_name, other_property_set|
+ # TODO: add PropertySet#concat and do this:
+ # self[repository_name].concat(property_set)
+ property_set = self[repository_name]
+ other_property_set.each { |property| property_set << property }
+ end
+ end
+
+ def add_to_non_default_repositories(property_factory, name, options)
+ non_default_property_sets.each do |other_repository_name, property_set|
+ next if property_set.named?(name)
+
+ # make sure the property is created within the correct repository scope
+ DataMapper.repository(other_repository_name) do
+ property_set << property_factory.new(model, name, options)
+ end
+ end
+ end
+
+ # TODO: move to PropertySet#add_to_lazy_contexts
+ def add_to_lazy_contexts(property_set, property, options)
+ # TODO: move to Property#lazy_contexts
+ context = options.fetch(:lazy, :default)
+ context = :default if context == true
+
+ Array(context).each do |context|
+ property_set.lazy_context(context) << property
+ end
+ end
+
+ def new_property_set_for(repository_name)
+ if repository_name == default_repository_name
+ property_set_factory.new
+ else
+ @property_sets[default_repository_name].dup
+ end
+ end
+
+ def current_repository_property_set
+ self[current_repository_name]
+ end
+
+ def non_default_property_sets
+ DataMapper::Ext::Hash.except(@property_sets, default_repository_name)
+ end
+
+ def property_set_factory
+ PropertySet
+ end
+
+ def current_repository_name
+ model.repository_name
+ end
+
+ def default_repository_name
+ model.default_repository_name
+ end
+
+ def assert_supported_type(type)
+ raise Property::DeprecatedTypeError.new(type, Boolean) if TrueClass == type
+ raise Property::DeprecatedTypeError.new(type, Decimal) if BigDecimal == type
+ end
+
+ end # class RepositoryPropertySet
+ end # module Property
+ end # module Model
+end # module DataMapper

No commit comments for this range

Something went wrong with that request. Please try again.