Permalink
Browse files

Added Rails integration macro and spec framework

  • Loading branch information...
1 parent 8b8ded0 commit 3e3ecf826b3053e1d250fa01829c677ebc647106 @SFEley committed Jul 26, 2009
View
@@ -0,0 +1 @@
+require File.dirname(__FILE__) + "/rails/init.rb"
@@ -0,0 +1,21 @@
+# Load all of our Rails files
+Dir[File.join(File.dirname(__FILE__), 'rails', '*.rb')].sort.each do |path|
+ filename = File.basename(path, '.rb')
+ require "acts_as_icontact/rails/#{filename}"
+end
+
+module ActsAsIcontact
+ module Rails
+ module ClassMethods
+ include Macro
+ end
+ end
+end
+
+if defined?(::ActiveRecord)
+ module ::ActiveRecord
+ class Base
+ extend ActsAsIcontact::Rails::ClassMethods
+ end
+ end
+end
@@ -0,0 +1,15 @@
+module ActsAsIcontact
+ module Rails
+ module ClassMethods
+ module Macro
+
+ # The core macro for ActsAsIcontact's Rails integration. Establishes callbacks to keep Rails models in
+ # sync with iContact. See the README for more on what it does.
+ def acts_as_icontact(options = {})
+ true
+ end
+
+ end
+ end
+ end
+end
View
@@ -0,0 +1,3 @@
+# Load our Rails integration code
+require 'acts_as_icontact'
+require 'acts_as_icontact/rails'
@@ -0,0 +1,15 @@
+ActiveRecord::Schema.define do
+ create_table "people", :force => true do |t|
+ t.string "firstName"
+ t.string "surname"
+ t.string "email", :null => false
+ t.string "icontact_status"
+ t.string "status"
+ t.string "icontact_id"
+ t.datetime "icontact_created"
+ t.string "bounces"
+ t.string "custom_field"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+end
View
@@ -0,0 +1,36 @@
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+require 'activerecord'
+require 'rails/init'
+
+# Dummy model
+class Person < ActiveRecord::Base
+ # create_table "people", :force => true do |t|
+ # t.string "firstName"
+ # t.string "surname"
+ # t.string "email", :null => false
+ # t.string "icontact_status"
+ # t.string "status"
+ # t.string "icontact_id"
+ # t.datetime "icontact_created"
+ # t.string "bounces"
+ # t.string "custom_field"
+ # t.datetime "created_at"
+ # t.datetime "updated_at"
+ # end
+
+ acts_as_icontact
+end
+
+describe "Rails integration" do
+ before(:all) do
+ ActiveRecord::Base.establish_connection :adapter => :nulldb,
+ :schema => File.dirname(__FILE__) + '/examples/schema.rb'
+ end
+
+ it "relies on a model with an email address" do
+ @person = Person.new(:email => "john@example.org")
+ @person.email.should == "john@example.org"
+ end
+
+end
View
@@ -1,10 +1,13 @@
require 'spec'
$LOAD_PATH.unshift(File.dirname(__FILE__))
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'support'))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require 'acts_as_icontact'
-require 'spec_fakeweb'
+# Requires supporting files with custom matchers and macros, etc,
+# in ./support/ and its subdirectories.
+Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
Spec::Runner.configure do |config|
# config.after(:each) do
@@ -0,0 +1,217 @@
+require 'logger'
+require 'stringio'
+require 'singleton'
+require 'activerecord'
+require 'active_record/connection_adapters/abstract_adapter'
+
+class ActiveRecord::Base
+ # Instantiate a new NullDB connection. Used by ActiveRecord internally.
+ def self.nulldb_connection(config)
+ ActiveRecord::ConnectionAdapters::NullDBAdapter.new(config)
+ end
+end
+
+class ActiveRecord::ConnectionAdapters::NullDBAdapter <
+ ActiveRecord::ConnectionAdapters::AbstractAdapter
+
+ class Statement
+ attr_reader :entry_point, :content
+
+ def initialize(entry_point, content = "")
+ @entry_point, @content = entry_point, content
+ end
+
+ def ==(other)
+ self.entry_point == other.entry_point
+ end
+ end
+
+ class Checkpoint < Statement
+ def initialize
+ super(:checkpoint, "")
+ end
+
+ def ==(other)
+ self.class == other.class
+ end
+ end
+
+ TableDefinition = ActiveRecord::ConnectionAdapters::TableDefinition
+
+ class NullObject
+ def method_missing(*args, &block)
+ nil
+ end
+ end
+
+ # A convenience method for integratinginto RSpec. See README for example of
+ # use.
+ def self.insinuate_into_spec(config)
+ config.before :all do
+ ActiveRecord::Base.establish_connection(:adapter => :nulldb)
+ end
+
+ config.after :all do
+ ActiveRecord::Base.establish_connection(:test)
+ end
+ end
+
+ # Recognized options:
+ #
+ # [+:schema+] path to the schema file, relative to RAILS_ROOT
+ def initialize(config={})
+ @log = StringIO.new
+ @logger = Logger.new(@log)
+ @last_unique_id = 0
+ @tables = {'schema_info' => TableDefinition.new(nil)}
+ @schema_path = config.fetch(:schema){ "db/schema.rb" }
+ super(nil, @logger)
+ end
+
+ # A log of every statement that has been "executed" by this connection adapter
+ # instance.
+ def execution_log
+ (@execution_log ||= [])
+ end
+
+ # A log of every statement that has been "executed" since the last time
+ # #checkpoint! was called, or since the connection was created.
+ def execution_log_since_checkpoint
+ checkpoint_index = @execution_log.rindex(Checkpoint.new)
+ checkpoint_index = checkpoint_index ? checkpoint_index + 1 : 0
+ @execution_log[(checkpoint_index..-1)]
+ end
+
+ # Inserts a checkpoint in the log. See also #execution_log_since_checkpoint.
+ def checkpoint!
+ self.execution_log << Checkpoint.new
+ end
+
+ def adapter_name
+ "NullDB"
+ end
+
+ def supports_migrations?
+ true
+ end
+
+ def create_table(table_name, options = {})
+ table_definition = ActiveRecord::ConnectionAdapters::TableDefinition.new(self)
+ unless options[:id] == false
+ table_definition.primary_key(options[:primary_key] || "id")
+ end
+
+ yield table_definition
+
+ @tables[table_name] = table_definition
+ end
+
+ def add_fk_constraint(*args)
+ # NOOP
+ end
+
+ def add_pk_constraint(*args)
+ # NOOP
+ end
+
+ # Retrieve the table names defined by the schema
+ def tables
+ @tables.keys.map(&:to_s)
+ end
+
+ # Retrieve table columns as defined by the schema
+ def columns(table_name, name = nil)
+ if @tables.size <= 1
+ ActiveRecord::Migration.verbose = false
+ Kernel.load(File.join(@schema_path))
+ end
+ table = @tables[table_name]
+ table.columns.map do |col_def|
+ ActiveRecord::ConnectionAdapters::Column.new(col_def.name.to_s,
+ col_def.default,
+ col_def.type,
+ col_def.null)
+ end
+ end
+
+ def execute(statement, name = nil)
+ self.execution_log << Statement.new(entry_point, statement)
+ NullObject.new
+ end
+
+ def insert(statement, name, primary_key, object_id, sequence_name)
+ returning(object_id || next_unique_id) do
+ with_entry_point(:insert) do
+ super(statement, name, primary_key, object_id, sequence_name)
+ end
+ end
+ end
+
+ def update(statement, name=nil)
+ with_entry_point(:update) do
+ super(statement, name)
+ end
+ end
+
+ def delete(statement, name=nil)
+ with_entry_point(:delete) do
+ super(statement, name)
+ end
+ end
+
+ def select_all(statement, name=nil)
+ with_entry_point(:select_all) do
+ super(statement, name)
+ end
+ end
+
+ def select_one(statement, name=nil)
+ with_entry_point(:select_one) do
+ super(statement, name)
+ end
+ end
+
+ def select_value(statement, name=nil)
+ with_entry_point(:select_value) do
+ super(statement, name)
+ end
+ end
+
+ protected
+
+ def select(statement, name)
+ returning([]) do
+ self.execution_log << Statement.new(entry_point, statement)
+ end
+ end
+
+ private
+
+ def next_unique_id
+ @last_unique_id += 1
+ end
+
+ def with_entry_point(method)
+ if entry_point.nil?
+ with_thread_local_variable(:entry_point, method) do
+ yield
+ end
+ else
+ yield
+ end
+ end
+
+ def entry_point
+ Thread.current[:entry_point]
+ end
+
+ def with_thread_local_variable(name, value)
+ old_value = Thread.current[name]
+ Thread.current[name] = value
+ begin
+ yield
+ ensure
+ Thread.current[name] = old_value
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit 3e3ecf8

Please sign in to comment.