Skip to content

Instantly share code, notes, and snippets.

@basgys
Created October 22, 2013 11:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save basgys/7098697 to your computer and use it in GitHub Desktop.
Save basgys/7098697 to your computer and use it in GitHub Desktop.
class UberRelation
include Enumerable
def initialize(scopes)
scopes.kind_of?(Array) or raise ArgumentError.new("Argument scopes is not an array!")
@scopes = scopes
end
def each(&block)
block_given? ? load.each{|scope| block.call(scope)} : load
end
def load
scopes.inject([]) {|result, scope| result += scope.load }
end
private
attr_reader :scopes
def method_missing(message, *args, &block)
dispatch(message, *args, &block)
self
end
def dispatch(message, *args, &block)
@scopes = scopes.map {|scope| scope.public_send(message, *args, &block)}
end
end
## ==== Specs ##
require "spec_helper"
require 'uber_relation'
describe UberRelation do
subject { described_class }
let(:scope) { double("scope") }
let(:scopes) { [scope, scope] }
let(:relation) { described_class.new(scopes) }
before(:each) do
allow(scope).to receive(:my_message)
allow(scope).to receive(:unknown_message).and_raise(NoMethodError)
allow(scope).to receive(:load).and_return(["record A", "record B"], ["record C"])
end
describe "#initialize" do
it "initializes object successfuly" do
expect { described_class.new([]) }.to_not raise_error
end
it "raises an ArgumentError if scopes is not an array" do
expect { described_class.new(nil) }.to raise_error(ArgumentError)
end
end
describe "message distribution" do
it "send the message to all scopes successfuly" do
expect(scope).to receive(:my_message).twice
relation.my_message
end
it "raises an undefined method if a scope does not respond to the given message" do
expect { relation.unknown_message }.to raise_error(NoMethodError)
end
end
describe "chaining" do
it "chains a message successfuly" do
expect(relation.my_message).to be(relation)
end
end
describe "Enumerable" do
it "responds to #each" do
expect(relation.each).to be_kind_of(Enumerable)
end
it "responds to #map" do
expect(relation.map {|record| record}).to eq(["record A", "record B", "record C"])
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment