welcome_cycle 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
6
+ *.tmproj
7
+ nbproject
8
+ .DS_Store
9
+ log/*.log
10
+ tmp/**/*
11
+ bin
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in welcome_cycle.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # welcome_cycle
2
+
3
+ `welcome_cycle` is a ruby gem to help you send out a cycle of emails. Specifically when new users sign up to your app.
4
+
5
+ ## Gemfile
6
+ gem 'welcome_cycle'
7
+ bundle install
8
+
9
+ ## Install
10
+ rails generate welcome_cycle:install
11
+
12
+ **Creates:**
13
+
14
+ `config/initializers/welcome_cycle.rb` - Defines config and your emails.
15
+
16
+ `app/mailers/welcome_cycle_mailer.rb` - Mailer methods for each email, each one is passed the recipient object.
17
+
18
+ ## Config
19
+
20
+ The configure block should be specified at the top of `welcome_cycle.rb`
21
+
22
+ WelcomeCycle.configure do |c|
23
+ c.base_class = Subscription
24
+ c.welcome_cycle_start_date = :trial_started_at
25
+ c.welcome_cycle_end_date = :trial_ends_at
26
+ c.before { run_something_special }
27
+ c.after { run_something_special }
28
+ end
29
+
30
+ **base_class** - The base model in your app to query for email recipients. (E.g Organisation, Subscription, User, Account, etc.)
31
+
32
+ **welcome_cycle_start_date** - The date/datetime field that determines the start of your welcome cycle. (If you want to send email 'n' days after the start.)
33
+
34
+ **welcome_cycle_end_date** - The date/datetime field that determines the end of the welcome cycle. (If you want to send emails 'n' days around the end.)
35
+
36
+ **before** - An optional callback to run before all emails are sent.
37
+
38
+ **after** - An optional callback to run after all emails are sent.
39
+
40
+
41
+ ## Defining new emails
42
+
43
+ rails generate welcome_cycle:email name_for_your_email_here
44
+
45
+ The above generator will add an email definition to `welcome_cycle.rb`, add the mailer method to `welcome_cycle_mailer.rb` and create the corresponding text and html erb templates.
46
+
47
+ ### Options for each email
48
+
49
+ **days_into_cycle** – The days on which you would like the email to be sent after signing up. E.g.: 3 = Three days after the sign up.
50
+
51
+ **days_offset_from_cycle_end** - The days on which you like the email to go out around the cycle/trial end.
52
+
53
+ * positive numbers: Number of days *before* the welcome cycle ends.
54
+ * negative number: Number of days *after* the welcome cycle ends.
55
+
56
+ **scope** - An optional arel chain that allows you restrict the recipients to any conditions you like.
57
+
58
+ * With some simple conditions you can easily set up email variations. E.g. have they performed a certain task? Have they subscribed? Etc.
59
+
60
+ You **must** specify days_into_cycle or days_offset_from_cycle_end.
61
+
62
+ ### Example email definitions:
63
+
64
+ WelcomeCycle::Email.new("We miss you") do
65
+ days 7, 14, 21
66
+ scope do
67
+ where('last_login = ?', nil)
68
+ end
69
+ end
70
+
71
+ WelcomeCycle::Email.new("Trial ends soon!") do
72
+ days -5
73
+ scope do
74
+ where(:subscribed_at => false)
75
+ end
76
+ end
77
+
78
+ ##
79
+
80
+ ## Sending the emails
81
+ Set your favourite scheduler to run the WelcomeCycle::Driver.run daily. E.g. using CRON to send them everyday at 6am:
82
+
83
+ 0 6 * * * cd /path/to/you/app && rails runner -e production 'WelcomeCycle::Driver.run'
84
+
85
+ ## Notes
86
+ 1. The email templates and corresponding methods live inside your app.
87
+ 2. Ironically welcome_cycle is not designed to send an actual welcome_email! You probably want do that immediately when people sign-up. Feel free to use the provided mailer class.
88
+ 3. We'll try our best to stick to semantic versioning (http://semver.org/)
89
+
90
+ ## TODO
91
+ * Work out a clean way of ignoring the initializer unless rails runner is being used.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,41 @@
1
+ module WelcomeCycle
2
+ module Generators
3
+ class EmailGenerator < Rails::Generators::NamedBase
4
+
5
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
6
+
7
+ def register_new_mail
8
+ append_to_file 'config/initializers/welcome_cycle.rb' do
9
+ <<-EOS
10
+
11
+
12
+ WelcomeCycle::Email.new("#{file_name.gsub(/_/, ' ').capitalize}") do
13
+ days_into_cycle 5, 10 # Send on 5 and 10 days into trial
14
+ days_offset_from_cycle_end -5, 5 # Send 5 days before and 5 days after the cycle ends
15
+ scope do
16
+ # send if these Arel conditions are met
17
+ end
18
+ end
19
+ EOS
20
+ end
21
+ end
22
+
23
+ def add_new_mailer_action
24
+ gsub_file 'app/mailers/welcome_cycle_mailer.rb', '# your actions here', ''
25
+ inject_into_class 'app/mailers/welcome_cycle_mailer.rb', WelcomeCycleMailer do
26
+ <<-EOS
27
+
28
+ def #{file_name}(recipient)
29
+ mail(:to => recipient.email, :subject => 'Your subject here')
30
+ end
31
+ EOS
32
+ end
33
+ end
34
+
35
+ def add_new_mailer_templates
36
+ create_file "app/views/welcome_cycle_mailer/#{file_name}.text.erb"
37
+ create_file "app/views/welcome_cycle_mailer/#{file_name}.html.erb"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ module WelcomeCycle
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+
5
+ source_root File.expand_path(File.join(File.dirname(__FILE__), 'templates'))
6
+
7
+ def copy_welcome_cycle_mailer
8
+ copy_file 'welcome_cycle_mailer.rb', File.join('app','mailers','welcome_cycle_mailer.rb')
9
+ end
10
+
11
+ def copy_email_list
12
+ copy_file 'welcome_cycle.rb', File.join('config','initializers','welcome_cycle.rb')
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ WelcomeCycle.configure do |c|
2
+ c.base_class = Subscription
3
+ c.welcome_cycle_start_date = :trial_started_at
4
+ c.welcome_cycle_end_date = :trial_ends_at
5
+ end
6
+
7
+ # run 'rails generate welcome_cycle:email name_for_your_email_here' to add new welcome cycle emails
@@ -0,0 +1,3 @@
1
+ class WelcomeCycleMailer < ActionMailer::Base
2
+ # your actions here
3
+ end
@@ -0,0 +1,20 @@
1
+ require 'singleton'
2
+
3
+ require "welcome_cycle/version"
4
+ require "welcome_cycle/driver"
5
+ require "welcome_cycle/email"
6
+ require "welcome_cycle/email_register"
7
+ require "welcome_cycle/config"
8
+
9
+ module WelcomeCycle
10
+
11
+ class << self
12
+ attr_accessor :config
13
+ end
14
+
15
+ def self.configure
16
+ self.config ||= WelcomeCycle::Config.new
17
+ yield(config)
18
+ end
19
+
20
+ end
@@ -0,0 +1,22 @@
1
+ module WelcomeCycle
2
+
3
+ class Config
4
+ attr_accessor :base_class, :welcome_cycle_start_date, :welcome_cycle_end_date
5
+ attr_reader :before_run, :after_run
6
+
7
+ def initialize
8
+ @welcome_cycle_start_date = :trial_stared_at
9
+ @welcome_cycle_end_date = :trial_ends_at
10
+ end
11
+
12
+ def before(&block)
13
+ @before_run = block
14
+ end
15
+
16
+ def after(&block)
17
+ @after_run = block
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,11 @@
1
+ module WelcomeCycle
2
+ class Driver
3
+ def self.run
4
+ raise 'WelcomeCycle is not configured! See the README config section for help.' if WelcomeCycle.config.nil?
5
+ raise "You must set the 'base_class' option. See README config section." if WelcomeCycle.config.base_class.nil?
6
+ WelcomeCycle.config.before_run.call if WelcomeCycle.config.before_run
7
+ WelcomeCycle::EmailRegister.instance.emails.each { |e| e.send_to_recipients! }
8
+ WelcomeCycle.config.after_run.call if WelcomeCycle.config.after_run
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,78 @@
1
+ module WelcomeCycle
2
+
3
+ class Email
4
+
5
+ def initialize(name, &block)
6
+ @name = name
7
+ instance_eval &block
8
+ raise "You must specify at least one day to send this email by specifying 'days_into_cycle' and/or 'days_offset_from_cycle_end'" if @days_into_cycle.nil? && @days_offset_from_cycle_end.nil?
9
+ WelcomeCycle::EmailRegister.instance << self
10
+ end
11
+
12
+ def days_into_cycle(*days)
13
+ raise ArgumentError, "'days_into_cycle' can only contain positive numbers" if days.detect { |d| d <= 0 }
14
+ raise "When specifying 'days_into_cycle' you must set the 'welcome_cycle_start_date'. See README config section" if WelcomeCycle.config.welcome_cycle_start_date.nil?
15
+ @days_into_cycle = days
16
+ end
17
+
18
+ def days_offset_from_cycle_end(*days)
19
+ raise "When specifying 'days_offset_from_cycle_end' you must set the 'welcome_cycle_end_date' config section" if WelcomeCycle.config.welcome_cycle_end_date.nil?
20
+ @days_offset_from_cycle_end = days
21
+ end
22
+
23
+ def scope(&block)
24
+ @scope_chain = block
25
+ end
26
+
27
+ def send_to_recipients!
28
+ recipients.each { |r| deliver(r) }
29
+ end
30
+
31
+ def recipients
32
+ recipients = WelcomeCycle.config.base_class
33
+ recipients = recipients.where(date_conditions)
34
+ @scope_chain.nil? ? recipients.all : recipients.instance_eval(&@scope_chain)
35
+ end
36
+
37
+ def deliver(r)
38
+ if defined?(Delayed) && (defined?(Delayed::Job) || defined?(Delayed::Worker))
39
+ deliver_via_delayed_job(r)
40
+ else
41
+ deliver_directly(r)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def deliver_via_delayed_job(r)
48
+ WelcomeCycleMailer.delay.send(template_name, r)
49
+ end
50
+
51
+ def deliver_directly(r)
52
+ if mail_message_obj = WelcomeCycleMailer.send(template_name, r)
53
+ mail_message_obj.deliver
54
+ else
55
+ raise "Failed to create Mail::Message object from the current template name '#{template_name}'. Check it is specified in your WelcomeCycleMailer."
56
+ end
57
+ end
58
+
59
+ def template_name
60
+ @name.downcase.gsub(/\s/, '_')
61
+ end
62
+
63
+ def date_conditions
64
+ conditions = ['']
65
+ [[WelcomeCycle.config.welcome_cycle_start_date, @days_into_cycle], [WelcomeCycle.config.welcome_cycle_end_date, @days_offset_from_cycle_end]].each do |field_name, cycle_days|
66
+ next if cycle_days.nil?
67
+ cycle_days.each do |day_in_cycle|
68
+ conditions[0] << " OR " unless conditions[0].empty?
69
+ conditions[0] << "date(`#{WelcomeCycle.config.base_class.table_name}`.`#{field_name}`) = ?"
70
+ conditions << Time.now.utc.to_date - day_in_cycle # Positive: 6th-5.days = 1st / Negative: 25th--5.days = 30th
71
+ end
72
+ end
73
+ conditions
74
+ end
75
+
76
+ end
77
+
78
+ end
@@ -0,0 +1,21 @@
1
+ module WelcomeCycle
2
+ class EmailRegister
3
+
4
+ include Singleton
5
+
6
+ attr_accessor :emails
7
+
8
+ def initialize
9
+ @emails = []
10
+ end
11
+
12
+ def <<(email)
13
+ @emails << email
14
+ end
15
+
16
+ def each
17
+ @emails.each { |email| yield(email) }
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module WelcomeCycle
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+ require 'welcome_cycle'
3
+
4
+ RSpec.configure do |config|
5
+ config.color_enabled = true
6
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe WelcomeCycle::Config do
4
+
5
+ subject { WelcomeCycle::Config.new }
6
+
7
+ describe "new config object" do
8
+ it 'has sensible defaults for the welcome cycle start and end dates' do
9
+ subject.welcome_cycle_start_date.should eq(:trial_stared_at)
10
+ subject.welcome_cycle_end_date.should eq(:trial_ends_at)
11
+ end
12
+ end
13
+
14
+ describe "attributes" do
15
+ it 'allows you to set :base_class' do
16
+ subject.base_class = 'SomeClass'
17
+ subject.base_class.should eq('SomeClass')
18
+ end
19
+ it 'allows you to set :welcome_cycle_start_date' do
20
+ subject.welcome_cycle_start_date = :signed_up_at
21
+ subject.welcome_cycle_start_date.should eq(:signed_up_at)
22
+ end
23
+ it 'allows you to set :welcome_cycle_end_date' do
24
+ subject.welcome_cycle_end_date = :close_at
25
+ subject.welcome_cycle_end_date.should eq(:close_at)
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe WelcomeCycle::Driver do
4
+
5
+ describe "::run" do
6
+ let(:email1) { mock('email 1').as_null_object }
7
+ let(:email2) { mock('email 1').as_null_object }
8
+
9
+ context "when WelcomeCycle has not been configured" do
10
+ it 'raises an error telling you to configure it' do
11
+ lambda { WelcomeCycle::Driver.run }.should raise_error('WelcomeCycle is not configured! See the README config section for help.')
12
+ end
13
+ end
14
+
15
+ context "when no base_class is configured" do
16
+ before { WelcomeCycle.configure {} }
17
+ it 'raises an error telling you to set the base class' do
18
+ lambda { WelcomeCycle::Driver.run }.should raise_error("You must set the 'base_class' option. See README config section.")
19
+ end
20
+ end
21
+
22
+ context "when configured with a base class" do
23
+ before do
24
+ WelcomeCycle.configure { |c| c.base_class = mock('class') }
25
+ WelcomeCycle::EmailRegister.instance << email1
26
+ WelcomeCycle::EmailRegister.instance << email2
27
+ end
28
+
29
+ it 'calls #send_to_recipients! on each email in the register' do
30
+ email1.should_receive(:send_to_recipients!)
31
+ email2.should_receive(:send_to_recipients!)
32
+ WelcomeCycle::Driver.run
33
+ end
34
+ end
35
+
36
+ describe 'callbacks' do
37
+ it 'calls the before_run callback if one is set' do
38
+ WelcomeCycle.configure { |c| c.before {} }
39
+ WelcomeCycle.config.before_run.should_receive(:call)
40
+ WelcomeCycle::Driver.run
41
+ end
42
+
43
+ it 'calls the after_run callback if one is set' do
44
+ WelcomeCycle.configure { |c| c.after {} }
45
+ WelcomeCycle.config.after_run.should_receive(:call)
46
+ WelcomeCycle::Driver.run
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe WelcomeCycle::EmailRegister do
4
+
5
+ subject { WelcomeCycle::EmailRegister.instance }
6
+
7
+ after(:each) { WelcomeCycle::EmailRegister.instance.emails = [] }
8
+
9
+ describe "attributes" do
10
+ it 'allows setting/getting :emails' do
11
+ subject.emails = [1, 2, 3]
12
+ subject.emails.should eq([1, 2, 3])
13
+ end
14
+ end
15
+
16
+ describe "adding emails into the register" do
17
+ let(:email_register) { WelcomeCycle::EmailRegister.instance }
18
+ it 'stores them in an array' do
19
+ subject << "email1"
20
+ subject << "email2"
21
+ subject << "email3"
22
+ subject.emails.should eq(['email1', 'email2', 'email3'])
23
+ end
24
+ end
25
+
26
+ describe "each" do
27
+ let(:email1) { mock('email1') }
28
+ let(:email2) { mock('email2') }
29
+ let(:email3) { mock('email2') }
30
+
31
+ it 'yields the given block for each email in the register' do
32
+ subject << email1
33
+ subject << email2
34
+ subject << email3
35
+ email1.should_receive(:some_method)
36
+ email2.should_receive(:some_method)
37
+ email3.should_receive(:some_method)
38
+ subject.emails.each { |e| e.some_method }
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,180 @@
1
+ require 'spec_helper'
2
+
3
+ describe WelcomeCycle::Email do
4
+
5
+ let(:today) { Time.now.utc.to_date }
6
+
7
+ class WelcomeCycleMailer
8
+ end
9
+
10
+ class Subscription
11
+ def self.table_name
12
+ 'organisations'
13
+ end
14
+ end
15
+
16
+ before(:each) do
17
+ WelcomeCycle.configure do |c|
18
+ c.base_class = Subscription
19
+ c.welcome_cycle_start_date = :trial_started_at
20
+ c.welcome_cycle_end_date = :trial_ends_at
21
+ end
22
+ end
23
+
24
+ subject do
25
+ WelcomeCycle::Email.new("Test email") do
26
+ days_into_cycle 1, 10, 25
27
+ scope do
28
+ where('created_at < ?', today)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "#initialize" do
34
+ it 'raises an error if you do not specify any days' do
35
+ lambda { WelcomeCycle::Email.new("Test email") {} }.should raise_error("You must specify at least one day to send this email by specifying 'days_into_cycle' and/or 'days_offset_from_cycle_end'")
36
+ end
37
+ it 'adds itself into the register' do
38
+ lambda {
39
+ WelcomeCycle::Email.new("Test email") { days_into_cycle 1 }
40
+ }.should change(WelcomeCycle::EmailRegister.instance.emails, :size).by(1)
41
+ end
42
+ end
43
+
44
+ describe "#days_into_cycle" do
45
+ it 'allows you to set the days the email should be sent after the cycle begins' do
46
+ subject.days_into_cycle(1,2,3,4,5).should eq([1,2,3,4,5])
47
+ subject.days_into_cycle(1,2,3).should eq([1,2,3])
48
+ end
49
+ it 'raises an ArgumentError if passed day 0' do
50
+ lambda { subject.days_into_cycle(1, 10, 0, 25) }.should raise_error(ArgumentError, "'days_into_cycle' can only contain positive numbers")
51
+ end
52
+ it 'raises an ArgumentError if passed day a negative day' do
53
+ lambda { subject.days_into_cycle(1, -4, 25) }.should raise_error(ArgumentError, "'days_into_cycle' can only contain positive numbers")
54
+ end
55
+ context 'with no welcome_start_date set' do
56
+ before { WelcomeCycle.config.welcome_cycle_start_date = nil }
57
+ it 'raises an error' do
58
+ lambda { subject.days_into_cycle(1) }.should raise_error("When specifying 'days_into_cycle' you must set the 'welcome_cycle_start_date'. See README config section")
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "#days_offset_from_cycle_end" do
64
+ it 'allows you to set the days the email should be sent, offset from the cycle beginning' do
65
+ subject.days_offset_from_cycle_end(-1,0,1).should eq([-1,0,1])
66
+ end
67
+ context 'with no welcome_cycle_end_date set' do
68
+ before { WelcomeCycle.config.welcome_cycle_end_date = nil }
69
+ it 'raises an error' do
70
+ lambda { subject.days_offset_from_cycle_end(1, -4, 25)}.should raise_error("When specifying 'days_offset_from_cycle_end' you must set the 'welcome_cycle_end_date' config section")
71
+ end
72
+ end
73
+ end
74
+
75
+ describe '#scope' do
76
+ it 'allows you to set a further scope for the email recipients' do
77
+ subject.scope do
78
+ where('1=1')
79
+ end.should be_a(Proc)
80
+ end
81
+ end
82
+
83
+ describe '#send_to_recipients!' do
84
+ let(:r1) { mock 'mock recipient 1' }
85
+ let(:r2) { mock 'mock recipient 2' }
86
+ let(:r3) { mock 'mock recipient 3' }
87
+
88
+ before { subject.stub(:recipients).and_return([r1, r2, r3]) }
89
+
90
+ it 'delivers the email to each recipient' do
91
+ subject.should_receive(:deliver).with(r1)
92
+ subject.should_receive(:deliver).with(r2)
93
+ subject.should_receive(:deliver).with(r3)
94
+ subject.send_to_recipients!
95
+ end
96
+ end
97
+
98
+ describe "#recipients" do
99
+ let(:mock_orgs) { mock "Orgs" }
100
+ context "with the email set to go out on day 5 and 10 of the welcome cycle" do
101
+ let(:email) { WelcomeCycle::Email.new("Test email") { days_into_cycle(5, 10) } }
102
+ it 'queries the base class for all the records that started the welcome cycle 5 or 10 days ago' do
103
+ Subscription.should_receive(:where).with(["date(`organisations`.`trial_started_at`) = ? OR date(`organisations`.`trial_started_at`) = ?", today - 5, today - 10]).and_return(mock_orgs)
104
+ mock_orgs.should_receive(:all)
105
+ email.recipients
106
+ end
107
+ end
108
+ context "with the email set to go out 9 and 3 days before the welcome cycle ends" do
109
+ let(:email) { WelcomeCycle::Email.new("Test email") { days_offset_from_cycle_end(-9, -3) } }
110
+ it 'queries the base class for all the records that are 5/3 days away from ending the welcome cycle' do
111
+ Subscription.should_receive(:where).with(["date(`organisations`.`trial_ends_at`) = ? OR date(`organisations`.`trial_ends_at`) = ?", today + 9, today + 3]).and_return(mock_orgs)
112
+ mock_orgs.should_receive(:all)
113
+ email.recipients
114
+ end
115
+ end
116
+ context "with an extra Arel scope set" do
117
+ let(:email) do
118
+ WelcomeCycle::Email.new("Test email") do
119
+ days_into_cycle(3)
120
+ days_offset_from_cycle_end(-5)
121
+ scope do
122
+ active.where('1=1')
123
+ end
124
+ end
125
+ end
126
+ it "adds the extra scope to the date based query on the base_class" do
127
+ mock_active_orgs = mock 'mock active orgs'
128
+ Subscription.should_receive(:where).with(["date(`organisations`.`trial_started_at`) = ? OR date(`organisations`.`trial_ends_at`) = ?", today - 3, today + 5]).and_return(mock_orgs)
129
+ mock_orgs.should_receive(:active).and_return(mock_active_orgs)
130
+ mock_active_orgs.should_receive(:where).with('1=1')
131
+ email.recipients
132
+ end
133
+ context 'with a non-default configuration for the date fields' do
134
+ before do
135
+ WelcomeCycle.configure do |c|
136
+ c.welcome_cycle_start_date = :my_test_start_date
137
+ c.welcome_cycle_end_date = :my_test_end_date
138
+ end
139
+ end
140
+ it "queries based on the configured field names" do
141
+ mock_active_orgs = mock 'mock active orgs'
142
+ Subscription.should_receive(:where).with(["date(`organisations`.`my_test_start_date`) = ? OR date(`organisations`.`my_test_end_date`) = ?", today - 3, today + 5]).and_return(mock_orgs)
143
+ mock_orgs.should_receive(:active).and_return(mock_active_orgs)
144
+ mock_active_orgs.should_receive(:where).with('1=1')
145
+ email.recipients
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ describe "#deliver" do
152
+ let(:mock_email) { mock 'email' }
153
+ let(:mock_recipient) { mock 'recipient' }
154
+ let(:mock_dj) { mock 'delayed job' }
155
+
156
+ context 'without DelayedJob in the project' do
157
+ it 'calls deliver on the mailer template for this email passing in the recipient' do
158
+ WelcomeCycleMailer.should_receive(:test_email).with(mock_recipient).and_return(mock_email)
159
+ mock_email.should_receive(:deliver)
160
+ subject.deliver(mock_recipient)
161
+ end
162
+ end
163
+
164
+ context 'with DelayedJob in place' do
165
+ before do
166
+ module Delayed
167
+ class Job
168
+ end
169
+ end
170
+ end
171
+
172
+ it 'queues the email for delivery' do
173
+ WelcomeCycleMailer.should_receive(:delay).and_return(mock_dj)
174
+ mock_dj.should_receive(:test_email).with(mock_recipient).and_return(true)
175
+ subject.deliver(mock_recipient)
176
+ end
177
+ end
178
+ end
179
+
180
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe WelcomeCycle do
4
+
5
+ describe "::configure" do
6
+ before do
7
+ WelcomeCycle.configure do |c|
8
+ c.base_class = String
9
+ end
10
+ end
11
+
12
+ it 'sets a module attribute :config to a new WelcomeCycle::Config object and sets the attributes specified in the block given' do
13
+ WelcomeCycle.config.should be_a(WelcomeCycle::Config)
14
+ WelcomeCycle.config.base_class.should eq(String)
15
+ end
16
+
17
+ describe 'calling config more than once' do
18
+ before do
19
+ WelcomeCycle.configure do |c|
20
+ c.base_class = String
21
+ end
22
+ end
23
+ it 'does not create a new WelcomeCycle::Config object' do
24
+ WelcomeCycle::Config.should_receive(:new).never
25
+ WelcomeCycle.configure do |c|
26
+ c.base_class = Fixnum
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "welcome_cycle/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "welcome_cycle"
7
+ s.version = WelcomeCycle::VERSION
8
+ s.authors = ["Luke Brown", "Chris Stainthorpe"]
9
+ s.email = ["tsdbrown@gmail.com", "chris@randomcat.co.uk"]
10
+ s.homepage = ""
11
+ s.summary = %q{Welcome cycle code for SAAS apps}
12
+ s.description = %q{The idea behind this gem is to abstract out the logic of sending out welcome emails during a free trial.}
13
+
14
+ s.rubyforge_project = "welcome_cycle"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency(%q<rails>, [">= 3.0.10"])
22
+
23
+ s.add_development_dependency "rspec"
24
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: welcome_cycle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Luke Brown
9
+ - Chris Stainthorpe
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-02-17 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: &2156475920 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 3.0.10
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *2156475920
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: &2156475500 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *2156475500
37
+ description: The idea behind this gem is to abstract out the logic of sending out
38
+ welcome emails during a free trial.
39
+ email:
40
+ - tsdbrown@gmail.com
41
+ - chris@randomcat.co.uk
42
+ executables: []
43
+ extensions: []
44
+ extra_rdoc_files: []
45
+ files:
46
+ - .gitignore
47
+ - Gemfile
48
+ - README.md
49
+ - Rakefile
50
+ - lib/generators/welcome_cycle/email/email_generator.rb
51
+ - lib/generators/welcome_cycle/install/install_generator.rb
52
+ - lib/generators/welcome_cycle/install/templates/welcome_cycle.rb
53
+ - lib/generators/welcome_cycle/install/templates/welcome_cycle_mailer.rb
54
+ - lib/welcome_cycle.rb
55
+ - lib/welcome_cycle/config.rb
56
+ - lib/welcome_cycle/driver.rb
57
+ - lib/welcome_cycle/email.rb
58
+ - lib/welcome_cycle/email_register.rb
59
+ - lib/welcome_cycle/version.rb
60
+ - spec/spec_helper.rb
61
+ - spec/welcome_cycle/config_spec.rb
62
+ - spec/welcome_cycle/driver_spec.rb
63
+ - spec/welcome_cycle/email_register_spec.rb
64
+ - spec/welcome_cycle/email_spec.rb
65
+ - spec/welcome_cycle_spec.rb
66
+ - welcome_cycle.gemspec
67
+ homepage: ''
68
+ licenses: []
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubyforge_project: welcome_cycle
87
+ rubygems_version: 1.8.6
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Welcome cycle code for SAAS apps
91
+ test_files:
92
+ - spec/spec_helper.rb
93
+ - spec/welcome_cycle/config_spec.rb
94
+ - spec/welcome_cycle/driver_spec.rb
95
+ - spec/welcome_cycle/email_register_spec.rb
96
+ - spec/welcome_cycle/email_spec.rb
97
+ - spec/welcome_cycle_spec.rb