Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

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.
base fork: moonmaster9000/frill
base: master
...
head fork: moonmaster9000/frill
compare: frill_associations
Checking mergeability… Don't worry, you can still create the pull request.
  • 1 commit
  • 7 files changed
  • 0 commit comments
  • 1 contributor
Commits on Aug 01, 2012
@moonmaster9000 WIP f163ed1
View
65 ar.rb
@@ -0,0 +1,65 @@
+require 'active_record'
+require 'sqlite3'
+
+ActiveRecord::Base.establish_connection(
+ adapter: 'sqlite3',
+ database: 'db/test.db'
+)
+
+%w(posts blogs comments).each do |table|
+ ActiveRecord::Base.connection.execute(
+ %(
+ DROP TABLE
+ IF EXISTS
+ #{table}
+ )
+ )
+end
+
+ActiveRecord::Base.connection.execute(
+ %(
+ CREATE TABLE
+ posts(
+ id INTEGER,
+ blog_id INTEGER,
+ PRIMARY KEY(id ASC)
+ )
+ )
+)
+
+ActiveRecord::Base.connection.execute(
+ %(
+ CREATE TABLE
+ blogs(
+ id INTEGER,
+ name VARCHAR,
+ PRIMARY KEY(id ASC)
+ )
+ )
+)
+
+ActiveRecord::Base.connection.execute(
+ %(
+ CREATE TABLE
+ comments(
+ id INTEGER,
+ post_id INTEGER,
+ PRIMARY KEY(id ASC)
+ )
+ )
+)
+
+
+class Post < ActiveRecord::Base
+ belongs_to :blog
+ has_many :comments
+end
+
+class Blog < ActiveRecord::Base
+ has_many :posts
+end
+
+class Comment < ActiveRecord::Base
+ belongs_to :post
+end
+
View
BIN  db/test.db
Binary file not shown
View
63 lib/frill/active_record/association_decorator.rb
@@ -0,0 +1,63 @@
+module Frill
+ module ActiveRecord
+ class AssociationDecorator
+ def self.decorate(object, context)
+ new(object, context).decorate
+ end
+
+ def initialize(object, context)
+ @object = object
+ @context = context
+ end
+
+ def decorate
+ embed_context_in_object
+ decorate_associations
+ end
+
+ private
+ def embed_context_in_object
+ frill_context = @context
+
+ object.extend(
+ Module.new do
+ private
+ define_method(:__frill_context) do
+ frill_context
+ end
+ end
+ )
+ end
+
+ def decorate_associations
+ object.class.reflect_on_all_associations.each do |association|
+ if association.collection?
+ object.extend(
+ Module.new.tap do |mod|
+ mod.class_eval <<-EVAL
+ def #{association.name}
+ Frill::ActiveRecord::CollectionProxy.new(super, __frill_context)
+ end
+ EVAL
+ end
+ )
+ else
+ object.extend(
+ Module.new.tap do |mod|
+ mod.class_eval <<-EVAL
+ def #{association.name}
+ association = super
+ return nil unless association
+ Frill.decorate association, __frill_context
+ end
+ EVAL
+ end
+ )
+ end
+ end
+ end
+
+ attr_reader :object, :context
+ end
+ end
+end
View
9 lib/frill/active_record/association_proxy.rb
@@ -0,0 +1,9 @@
+module Frill
+ module ActiveRecord
+ class CollectionProxy
+ def initialize(collection, context)
+ end
+ end
+ end
+end
+
View
8 lib/frill/frill.rb
@@ -13,11 +13,11 @@ def self.reset!
end
def self.decorate object, context
- decorators.each do |d|
- object.extend d if d.frill? object, context
- end
+ decorators.each do |d|
+ object.extend d if d.frill? object, context
+ end
- object
+ object
end
module ClassMethods
View
113 spec/frill_active_relation_spec.rb
@@ -0,0 +1,113 @@
+require 'active_record'
+require 'sqlite3'
+
+ActiveRecord::Base.establish_connection(
+ adapter: 'sqlite3',
+ database: 'db/test.db'
+)
+
+%w(posts blogs comments).each do |table|
+ ActiveRecord::Base.connection.execute(
+ %(
+ DROP TABLE
+ IF EXISTS
+ #{table}
+ )
+ )
+end
+
+ActiveRecord::Base.connection.execute(
+ %(
+ CREATE TABLE
+ posts(
+ id INTEGER,
+ blog_id INTEGER,
+ PRIMARY KEY(id ASC)
+ )
+ )
+)
+
+ActiveRecord::Base.connection.execute(
+ %(
+ CREATE TABLE
+ blogs(
+ id INTEGER,
+ name VARCHAR,
+ PRIMARY KEY(id ASC)
+ )
+ )
+)
+
+ActiveRecord::Base.connection.execute(
+ %(
+ CREATE TABLE
+ comments(
+ id INTEGER,
+ post_id INTEGER,
+ PRIMARY KEY(id ASC)
+ )
+ )
+)
+
+require_relative '../lib/frill/active_record/association_decorator'
+
+class Post < ActiveRecord::Base
+ belongs_to :blog
+ has_many :comments
+end
+
+class Blog < ActiveRecord::Base
+ has_many :posts
+end
+
+class Comment < ActiveRecord::Base
+ belongs_to :post
+end
+
+describe Frill::ActiveRecord::AssociationDecorator do
+ before { Post.destroy_all; Blog.destroy_all; Comment.destroy_all }
+ before { Frill.reset! }
+
+ let!(:post) do
+ Post.create.tap do |p|
+ p.blog = Blog.create
+ p.save
+ end
+ end
+
+ let!(:decorated_module) do
+ Module.new do
+ include Frill
+
+ def self.frill?(*)
+ true
+ end
+ end
+ end
+
+ describe ".decorate(object, context)" do
+ context "given an ActiveRecord object" do
+ it "should decorate associated objects" do
+ Frill::ActiveRecord::AssociationDecorator.decorate post, double(:context)
+ blog_eigenclass = class << post.blog; self; end
+ blog_eigenclass.included_modules.should include decorated_module
+ end
+
+ it "should not attempt to decorate nil associations" do
+ comment = Comment.create
+ Frill::ActiveRecord::AssociationDecorator.decorate comment, double(:context)
+ post_eigenclass = class << comment.post; self; end
+ post_eigenclass.included_modules.should_not include decorated_module
+ end
+
+ it "should lazily decorate collection associations" do
+ post.comments << Comment.create << Comment.create
+ Frill::ActiveRecord::AssociationDecorator.decorate post, double(:context)
+ comments = post.comments
+ comment = comments.first
+ comment_eigenclass = class << comment; self; end
+ comment_eigenclass.included_modules.should include decorated_module
+ end
+ end
+ end
+end
View
9 spec/lib/frill/active_record/association_proxy_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../../lib/frill/active_record/association_proxy'
+
+module Frill
+ module ActiveRecord
+ describe CollectionProxy do
+
+ end
+ end
+end

No commit comments for this range

Something went wrong with that request. Please try again.