Skip to content

Commit

Permalink
Fixed bug where sti finder names would not be generated correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
aiwilliams committed Dec 29, 2009
1 parent 488874c commit 47691cc
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 79 deletions.
2 changes: 1 addition & 1 deletion VERSION.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
:patch: 1
:patch: 2
:major: 1
:minor: 3
7 changes: 4 additions & 3 deletions dataset.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

Gem::Specification.new do |s|
s.name = %q{dataset}
s.version = "1.3.1"
s.version = "1.3.2"

s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Adam Williams"]
s.date = %q{2009-12-22}
s.date = %q{2009-12-29}
s.description = %q{A simple API for creating and finding sets of data in your database, built on ActiveRecord.}
s.email = %q{[email protected]}
s.extra_rdoc_files = [
Expand Down Expand Up @@ -37,6 +37,7 @@ Gem::Specification.new do |s|
"lib/dataset/instance_methods.rb",
"lib/dataset/load.rb",
"lib/dataset/record/fixture.rb",
"lib/dataset/record/heirarchy.rb",
"lib/dataset/record/meta.rb",
"lib/dataset/record/model.rb",
"lib/dataset/resolver.rb",
Expand All @@ -54,7 +55,7 @@ Gem::Specification.new do |s|
s.test_files = [
"spec/dataset/cucumber_spec.rb",
"spec/dataset/database/base_spec.rb",
"spec/dataset/record/meta_spec.rb",
"spec/dataset/record/heirarchy_spec.rb",
"spec/dataset/resolver_spec.rb",
"spec/dataset/rspec_spec.rb",
"spec/dataset/session_binding_spec.rb",
Expand Down
1 change: 1 addition & 0 deletions lib/dataset.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
require 'dataset/resolver'
require 'dataset/session'
require 'dataset/session_binding'
require 'dataset/record/heirarchy'
require 'dataset/record/meta'
require 'dataset/record/fixture'
require 'dataset/record/model'
Expand Down
15 changes: 14 additions & 1 deletion lib/dataset/database/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,27 @@ def clear
end
end

def record_heirarchy(record_class)
base_class = record_class.base_class
record_heirarchies[base_class] ||= Dataset::Record::Heirarchy.new(base_class)
end

def record_meta(record_class)
record_metas[record_class] ||= Dataset::Record::Meta.new(record_class)
record_metas[record_class] ||= begin
heirarchy = record_heirarchy(record_class)
heirarchy.update(record_class)
Dataset::Record::Meta.new(heirarchy, record_class)
end
end

protected
def record_metas
@record_metas ||= Hash.new
end

def record_heirarchies
@record_heirarchies ||= Hash.new
end
end
end
end
65 changes: 65 additions & 0 deletions lib/dataset/record/heirarchy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
module Dataset
module Record # :nodoc:

class Heirarchy # :nodoc:
attr_reader :base_class, :class_name, :columns, :table_name

delegate :inheritance_column, :to => :base_class

def initialize(base_class)
@base_class = base_class
@class_name = base_class.name
@table_name = base_class.table_name
@columns = base_class.columns
end

def id_cache_key
@id_cache_key ||= table_name
end

def id_finder_names
@id_finder_names ||= [id_finder_name(base_class)]
end

def model_finder_names
@model_finder_names ||= [model_finder_name(base_class)]
end

def to_s
"#<Heirarchy: #{table_name}>"
end

def update(record_class)
record_class.ancestors.each do |c|
finder_name = model_finder_name(c)
unless model_finder_names.include?(finder_name)
model_finder_names << finder_name
id_finder_names << id_finder_name(c)
end
end
end

def finder_name(klass)
klass.name.underscore.gsub('/', '_').sub(/^(\w)_/, '\1').gsub(/_(\w)_/, '_\1')
end

def id_finder_name(klass)
"#{finder_name(klass)}_id".to_sym
end

def model_finder_name(klass)
finder_name(klass).pluralize.to_sym
end

def timestamp_columns
@timestamp_columns ||= begin
timestamps = %w(created_at created_on updated_at updated_on)
columns.select do |column|
timestamps.include?(column.name)
end
end
end
end

end
end
50 changes: 7 additions & 43 deletions lib/dataset/record/meta.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,26 @@ module Record # :nodoc:
# A mechanism to cache information about an ActiveRecord class to speed
# things up a bit for insertions, finds, and method generation.
class Meta # :nodoc:
attr_reader :class_name, :columns, :record_class, :table_name
attr_reader :heirarchy, :class_name, :record_class

# Provides information necessary to insert STI classes correctly for
# later reading.
delegate :name, :inheritance_column, :sti_name, :to => :record_class
delegate :name, :sti_name, :to => :record_class
delegate :inheritance_column, :table_name, :timestamp_columns, :to => :heirarchy

def initialize(record_class)
@record_class = record_class
@class_name = record_class.name
@table_name = record_class.table_name
@columns = record_class.columns
end

def id_cache_key
@id_cache_key ||= table_name
def initialize(heirarchy, record_class)
@heirarchy = heirarchy
@record_class = record_class
@class_name = record_class.name
end

def inheriting_record?
!record_class.descends_from_active_record?
end

def timestamp_columns
@timestamp_columns ||= begin
timestamps = %w(created_at created_on updated_at updated_on)
columns.select do |column|
timestamps.include?(column.name)
end
end
end

def id_finder_names
@id_finder_names ||= begin
names = descendants.collect {|c| finder_name c}
names.uniq.collect {|n| "#{n}_id".to_sym}
end
end

def model_finder_names
@record_finder_names ||= descendants.collect {|c| finder_name(c).pluralize.to_sym}.uniq
end

def to_s
"#<RecordMeta: #{table_name}>"
end

def descendants
if record_class.respond_to?(:self_and_descendents_from_active_record)
record_class.self_and_descendents_from_active_record
else
record_class.self_and_descendants_from_active_record
end
end

def finder_name(klass)
klass.name.underscore.gsub('/', '_').sub(/^(\w)_/, '\1').gsub(/_(\w)_/, '_\1')
end
end

end
Expand Down
36 changes: 19 additions & 17 deletions lib/dataset/session_binding.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ module Dataset
# raised.
#
class RecordNotFound < StandardError
def initialize(record_type, symbolic_name)
super "There is no '#{record_type.name}' found for the symbolic name ':#{symbolic_name}'."
def initialize(record_heirarchy, symbolic_name)
super "There is no '#{record_heirarchy.base_class.name}' found for the symbolic name ':#{symbolic_name}'."
end
end

Expand Down Expand Up @@ -41,12 +41,12 @@ def initialize(record_type, symbolic_name)
# people(:bobby) OR users(:bobby)
#
module ModelFinders
def create_finder(record_meta) # :nodoc:
def create_finders(record_meta) # :nodoc:
@finders_generated ||= []
heirarchy_finders_hash = record_meta.heirarchy.model_finder_names.join('').hash
return if @finders_generated.include?(heirarchy_finders_hash)

return if @finders_generated.include?(record_meta)

record_meta.model_finder_names.each do |finder_name|
record_meta.heirarchy.model_finder_names.each do |finder_name|
unless instance_methods.include?(finder_name)
define_method finder_name do |*symbolic_names|
names = Array(symbolic_names)
Expand All @@ -58,7 +58,7 @@ def create_finder(record_meta) # :nodoc:
end
end

record_meta.id_finder_names.each do |finder_name|
record_meta.heirarchy.id_finder_names.each do |finder_name|
unless instance_methods.include?(finder_name)
define_method finder_name do |*symbolic_names|
names = Array(symbolic_names)
Expand All @@ -70,7 +70,7 @@ def create_finder(record_meta) # :nodoc:
end
end

@finders_generated << record_meta
@finders_generated << heirarchy_finders_hash
end
end

Expand Down Expand Up @@ -207,23 +207,25 @@ def create_record(record_type, *args)

def find_id(record_type_or_meta, symbolic_name)
record_meta = record_meta_for_type(record_type_or_meta)
if local_id = @id_cache[record_meta.id_cache_key][symbolic_name]
heirarchy = record_meta.heirarchy
if local_id = @id_cache[heirarchy.id_cache_key][symbolic_name]
local_id
elsif !parent_binding.nil?
parent_binding.find_id record_meta, symbolic_name
else
raise RecordNotFound.new(record_meta, symbolic_name)
raise RecordNotFound.new(heirarchy, symbolic_name)
end
end

def find_model(record_type_or_meta, symbolic_name)
record_meta = record_meta_for_type(record_type_or_meta)
if local_id = @id_cache[record_meta.id_cache_key][symbolic_name]
record_meta.record_class.find local_id
heirarchy = record_meta.heirarchy
if local_id = @id_cache[heirarchy.id_cache_key][symbolic_name]
heirarchy.base_class.find local_id
elsif !parent_binding.nil?
parent_binding.find_model record_meta, symbolic_name
else
raise RecordNotFound.new(record_meta, symbolic_name)
raise RecordNotFound.new(heirarchy, symbolic_name)
end
end

Expand All @@ -235,8 +237,8 @@ def install_block_variables(target)

def name_model(record, symbolic_name)
record_meta = database.record_meta(record.class)
@model_finders.create_finder(record_meta)
@id_cache[record_meta.id_cache_key][symbolic_name] = record.id
@model_finders.create_finders(record_meta)
@id_cache[record_meta.heirarchy.id_cache_key][symbolic_name] = record.id
record
end

Expand All @@ -258,10 +260,10 @@ def insert(dataset_record_class, record_type, *args)
record = dataset_record_class.new(record_meta, attributes, symbolic_name, self)
return_value = nil

@model_finders.create_finder(record_meta)
@model_finders.create_finders(record_meta)
ActiveRecord::Base.silence do
return_value = record.create
@id_cache[record_meta.id_cache_key][symbolic_name] = record.id
@id_cache[record_meta.heirarchy.id_cache_key][symbolic_name] = record.id
end
return_value
end
Expand Down
14 changes: 14 additions & 0 deletions spec/dataset/record/heirarchy_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')

class MThingy
class NThingy
end
end

describe Dataset::Record::Heirarchy, 'finder name' do
it 'should collapse single character followed by underscore to just the single character' do
@heirarchy = Dataset::Record::Heirarchy.new(Place)
@heirarchy.finder_name(MThingy).should == 'mthingy'
@heirarchy.finder_name(MThingy::NThingy).should == 'mthingy_nthingy'
end
end
14 changes: 0 additions & 14 deletions spec/dataset/record/meta_spec.rb

This file was deleted.

5 changes: 5 additions & 0 deletions spec/dataset/session_binding_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,18 +142,23 @@

describe 'name_model' do
before do
@place = Place.create!
@binding.name_model(@place, :myplace)
@state = State.create!(:name => 'NC')
@binding.name_model(@state, :mystate)
end

it 'should allow assigning a name to a model for later lookup' do
@binding.find_model(Place, :myplace).should == @place
@binding.find_model(State, :mystate).should == @state
end

it 'should allow finding STI' do
@context = Object.new
@context.extend @binding.model_finders
@context.places(:myplace).should == @place
@context.places(:mystate).should == @state
@context.states(:mystate).should == @state
end
end

Expand Down

0 comments on commit 47691cc

Please sign in to comment.